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