Changed to use constexpr.

This commit is contained in:
yhirose 2015-07-24 21:36:39 -04:00
parent 9578362416
commit c0857d19ec
6 changed files with 84 additions and 151 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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
View File

@ -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_;
};