mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Changed to use constexpr.
This commit is contained in:
parent
9578362416
commit
c0857d19ec
@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
include_directories(..)
|
||||
add_definitions("-std=c++1y")
|
||||
add_definitions("-std=c++1y" -DPEGLIB_HAS_CONSTEXPR_SUPPORT)
|
||||
|
||||
add_executable(culebra main.cc repl.cc interpreter.cc parser.cc)
|
||||
|
@ -9,25 +9,26 @@ struct Eval
|
||||
{
|
||||
static Value eval(const Ast& ast, shared_ptr<Environment> env) {
|
||||
switch (ast.tag) {
|
||||
case Statements: return eval_statements(ast, env);
|
||||
case While: return eval_while(ast, env);
|
||||
case If: return eval_if(ast, env);
|
||||
case Function: return eval_function(ast, env);
|
||||
case Call: return eval_call(ast, env);
|
||||
case Assignment: return eval_assignment(ast, env);
|
||||
case LogicalOr: return eval_logical_or(ast, env);
|
||||
case LogicalAnd: return eval_logical_and(ast, env);
|
||||
case Condition: return eval_condition(ast, env);
|
||||
case UnaryPlus: return eval_unary_plus(ast, env);
|
||||
case UnaryMinus: return eval_unary_minus(ast, env);
|
||||
case UnaryNot: return eval_unary_not(ast, env);
|
||||
case BinExpresion: return eval_bin_expression(ast, env);
|
||||
case Identifier: return eval_identifier(ast, env);
|
||||
case Object: return eval_object(ast, env);
|
||||
case Array: return eval_array(ast, env);
|
||||
case Number: return eval_number(ast, env);
|
||||
case Boolean: return eval_bool(ast, env);
|
||||
case InterpolatedString: return eval_interpolated_string(ast, env);
|
||||
case "STATEMENTS"_: return eval_statements(ast, env);
|
||||
case "WHILE"_: return eval_while(ast, env);
|
||||
case "IF"_: return eval_if(ast, env);
|
||||
case "FUNCTION"_: return eval_function(ast, env);
|
||||
case "CALL"_: return eval_call(ast, env);
|
||||
case "ASSIGNMENT"_: return eval_assignment(ast, env);
|
||||
case "LOGICAL_OR"_: return eval_logical_or(ast, env);
|
||||
case "LOGICAL_AND"_: return eval_logical_and(ast, env);
|
||||
case "CONDITION"_: return eval_condition(ast, env);
|
||||
case "UNARY_PLUS"_: return eval_unary_plus(ast, env);
|
||||
case "UNARY_MINUS"_: return eval_unary_minus(ast, env);
|
||||
case "UNARY_NOT"_: return eval_unary_not(ast, env);
|
||||
case "ADDITIVE"_:
|
||||
case "MULTIPLICATIVE"_: return eval_bin_expression(ast, env);
|
||||
case "IDENTIFIER"_: return eval_identifier(ast, env);
|
||||
case "OBJECT"_: return eval_object(ast, env);
|
||||
case "ARRAY"_: return eval_array(ast, env);
|
||||
case "NUMBER"_: return eval_number(ast, env);
|
||||
case "BOOLEAN"_: return eval_bool(ast, env);
|
||||
case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env);
|
||||
}
|
||||
|
||||
if (ast.is_token) {
|
||||
@ -107,7 +108,7 @@ private:
|
||||
|
||||
for (auto i = 1u; i < ast.nodes.size(); i++) {
|
||||
const auto& n = *ast.nodes[i];
|
||||
if (n.original_tag == AstTag::Arguments) {
|
||||
if (n.original_tag == "ARGUMENTS"_) {
|
||||
// Function call
|
||||
const auto& f = val.to_function();
|
||||
const auto& params = f.data->params;
|
||||
@ -132,14 +133,14 @@ private:
|
||||
string msg = "arguments error...";
|
||||
throw runtime_error(msg);
|
||||
}
|
||||
} else if (n.original_tag == AstTag::Index) {
|
||||
} else if (n.original_tag == "INDEX"_) {
|
||||
// Array reference
|
||||
const auto& arr = val.to_array();
|
||||
auto idx = eval(n, env).to_long();
|
||||
if (0 <= idx && idx < static_cast<long>(arr.values->size())) {
|
||||
val = arr.values->at(idx);
|
||||
}
|
||||
} else if (n.original_tag == AstTag::Dot) {
|
||||
} else if (n.original_tag == "DOT"_) {
|
||||
// Property
|
||||
auto name = n.token;
|
||||
auto prop = val.get_property(name);
|
||||
|
@ -3,7 +3,7 @@
|
||||
using namespace peglib;
|
||||
using namespace std;
|
||||
|
||||
static auto g_grammar = R"(
|
||||
const auto g_grammar = R"(
|
||||
|
||||
PROGRAM <- _ STATEMENTS
|
||||
|
||||
@ -83,36 +83,7 @@ peg& get_parser()
|
||||
throw logic_error("invalid peg grammar");
|
||||
}
|
||||
|
||||
parser.enable_ast(
|
||||
true, // Optimize AST nodes
|
||||
{
|
||||
/* Definition Tag Optimize
|
||||
----------------------- ------------------ ---------- */
|
||||
{ "STATEMENTS", Statements, true },
|
||||
{ "WHILE", While, true },
|
||||
{ "ASSIGNMENT", Assignment, true },
|
||||
{ "IF", If, true },
|
||||
{ "FUNCTION", Function, true },
|
||||
{ "PARAMETERS", Default, false },
|
||||
{ "CALL", Call, true },
|
||||
{ "ARGUMENTS", Arguments, false },
|
||||
{ "INDEX", Index, true },
|
||||
{ "DOT", Dot, true },
|
||||
{ "LOGICAL_OR", LogicalOr, true },
|
||||
{ "LOGICAL_AND", LogicalAnd, true },
|
||||
{ "CONDITION", Condition, true },
|
||||
{ "ADDITIVE", BinExpresion, true },
|
||||
{ "UNARY_PLUS", UnaryPlus, true },
|
||||
{ "UNARY_MINUS", UnaryMinus, true },
|
||||
{ "UNARY_NOT", UnaryNot, true },
|
||||
{ "MULTIPLICATIVE", BinExpresion, true },
|
||||
{ "OBJECT", Object, true },
|
||||
{ "ARRAY", Array, true },
|
||||
{ "NUMBER", Number, true },
|
||||
{ "BOOLEAN", Boolean, true },
|
||||
{ "IDENTIFIER", Identifier, true },
|
||||
{ "INTERPOLATED_STRING", InterpolatedString, true },
|
||||
});
|
||||
parser.enable_ast(true, { "PARAMETERS", "ARGUMENTS" });
|
||||
}
|
||||
|
||||
return parser;
|
||||
|
@ -1,39 +1,5 @@
|
||||
#include <peglib.h>
|
||||
|
||||
enum AstTag
|
||||
{
|
||||
Default = peglib::AstDefaultTag,
|
||||
|
||||
Statements,
|
||||
While,
|
||||
If,
|
||||
Call,
|
||||
Assignment,
|
||||
|
||||
Arguments,
|
||||
Index,
|
||||
Dot,
|
||||
|
||||
LogicalOr,
|
||||
LogicalAnd,
|
||||
Condition,
|
||||
UnaryPlus,
|
||||
UnaryMinus,
|
||||
UnaryNot,
|
||||
BinExpresion,
|
||||
|
||||
Identifier,
|
||||
|
||||
Object,
|
||||
Array,
|
||||
Function,
|
||||
|
||||
InterpolatedString,
|
||||
|
||||
Number,
|
||||
Boolean,
|
||||
};
|
||||
|
||||
peglib::peg& get_parser();
|
||||
|
||||
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
||||
|
@ -64,7 +64,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PEGLIB_HAS_CONSTEXPR_SUPPORT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -81,7 +81,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PEGLIB_HAS_CONSTEXPR_SUPPORT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
117
peglib.h
117
peglib.h
@ -1941,16 +1941,39 @@ private:
|
||||
|
||||
const int AstDefaultTag = -1;
|
||||
|
||||
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
|
||||
inline constexpr unsigned int str2tag(const char* str, int h = 0) {
|
||||
return !str[h] ? 5381 : (str2tag(str, h + 1) * 33) ^ str[h];
|
||||
}
|
||||
|
||||
inline constexpr unsigned int operator "" _(const char* s, size_t) {
|
||||
return str2tag(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Ast
|
||||
{
|
||||
Ast(size_t _line, size_t _column, const char* _name, int _tag, const std::vector<std::shared_ptr<Ast>>& _nodes)
|
||||
: line(_line), column(_column), name(_name), tag(_tag), original_tag(_tag), is_token(false), nodes(_nodes) {}
|
||||
Ast(size_t _line, size_t _column, const char* _name, const std::vector<std::shared_ptr<Ast>>& _nodes)
|
||||
: line(_line), column(_column), name(_name), original_name(name), is_token(false), nodes(_nodes)
|
||||
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
|
||||
, tag(str2tag(_name)), original_tag(tag)
|
||||
#endif
|
||||
{}
|
||||
|
||||
Ast(size_t _line, size_t _column, const char* _name, int _tag, const std::string& _token)
|
||||
: line(_line), column(_column), name(_name), tag(_tag), original_tag(_tag), is_token(true), token(_token) {}
|
||||
Ast(size_t _line, size_t _column, const char* _name, const std::string& _token)
|
||||
: line(_line), column(_column), name(_name), original_name(name), is_token(true), token(_token)
|
||||
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
|
||||
, tag(str2tag(_name)), original_tag(tag)
|
||||
#endif
|
||||
{}
|
||||
|
||||
Ast(const Ast& ast, int original_tag)
|
||||
: line(ast.line), column(ast.column), name(ast.name), tag(ast.tag), original_tag(original_tag), is_token(ast.is_token), token(ast.token), nodes(ast.nodes) {}
|
||||
Ast(const Ast& ast, const char* _original_name)
|
||||
: line(ast.line), column(ast.column), name(ast.name), original_name(_original_name)
|
||||
, is_token(ast.is_token), token(ast.token), nodes(ast.nodes)
|
||||
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
|
||||
, tag(ast.tag), original_tag(str2tag(_original_name))
|
||||
#endif
|
||||
{}
|
||||
|
||||
const Ast& get_smallest_ancestor() const;
|
||||
|
||||
@ -1959,11 +1982,14 @@ struct Ast
|
||||
const size_t line;
|
||||
const size_t column;
|
||||
const std::string name;
|
||||
const int tag;
|
||||
const int original_tag;
|
||||
const std::string original_name;
|
||||
const bool is_token;
|
||||
const std::string token;
|
||||
const std::vector<std::shared_ptr<Ast>> nodes;
|
||||
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
|
||||
const unsigned int tag;
|
||||
const unsigned int original_tag;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct AstPrint
|
||||
@ -2153,22 +2179,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
struct AstNodeInfo {
|
||||
const char* name;
|
||||
int tag; // TODO: It should be calculated at compile-time from 'name' with constexpr hash function.
|
||||
bool optimize_nodes;
|
||||
};
|
||||
peg& enable_ast(bool optimize_nodes, const std::initializer_list<std::string>& filters) {
|
||||
for (auto& x: *grammar_) {
|
||||
const auto& name = x.first;
|
||||
auto& rule = x.second;
|
||||
|
||||
peg& enable_ast(bool optimize_nodes, std::initializer_list<AstNodeInfo> list) {
|
||||
for (const auto& info: list) {
|
||||
ast_node(info);
|
||||
auto found = std::find(filters.begin(), filters.end(), name) != filters.end();
|
||||
bool opt = optimize_nodes ? !found : found;
|
||||
|
||||
if (!rule.action) {
|
||||
auto is_token = rule.is_token;
|
||||
rule.action = [=](const SemanticValues& sv) {
|
||||
if (is_token) {
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, name.c_str(), std::string(sv.s, sv.n));
|
||||
}
|
||||
if (opt && sv.size() == 1) {
|
||||
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
|
||||
return ast;
|
||||
}
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>());
|
||||
};
|
||||
}
|
||||
}
|
||||
ast_end(optimize_nodes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
peg& enable_ast(bool optimize_nodes) {
|
||||
ast_end(optimize_nodes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2188,45 +2222,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void ast_node(const AstNodeInfo& info) {
|
||||
auto& rule = (*this)[info.name];
|
||||
auto is_token = rule.is_token;
|
||||
rule = [info, is_token](const SemanticValues& sv) {
|
||||
if (is_token) {
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, info.name, info.tag, std::string(sv.s, sv.n));
|
||||
}
|
||||
if (info.optimize_nodes && sv.size() == 1) {
|
||||
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), info.tag);
|
||||
return ast;
|
||||
}
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, info.name, info.tag, sv.transform<std::shared_ptr<Ast>>());
|
||||
};
|
||||
}
|
||||
|
||||
void ast_end(bool optimize_nodes) {
|
||||
for (auto& x: *grammar_) {
|
||||
const auto& name = x.first;
|
||||
auto& rule = x.second;
|
||||
if (!rule.action) {
|
||||
auto is_token = rule.is_token;
|
||||
rule.action = [=](const SemanticValues& sv) {
|
||||
if (is_token) {
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, name.c_str(), AstDefaultTag, std::string(sv.s, sv.n));
|
||||
}
|
||||
if (optimize_nodes && sv.size() == 1) {
|
||||
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), AstDefaultTag);
|
||||
return ast;
|
||||
}
|
||||
auto line = line_info(sv.ss, sv.s);
|
||||
return std::make_shared<Ast>(line.first, line.second, name.c_str(), AstDefaultTag, sv.transform<std::shared_ptr<Ast>>());
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Grammar> grammar_;
|
||||
std::string start_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user