From 620c775eee2b3494a048f02cc1ac0c3b31814626 Mon Sep 17 00:00:00 2001 From: yhirose Date: Fri, 24 Jul 2015 22:18:03 -0400 Subject: [PATCH] Made header-only file. --- language/CMakeLists.txt | 2 +- language/interpreter.cc | 361 --------------------------- language/interpreter.hpp | 443 +++++++++++++++++++++++++++++++++- language/main.cc | 27 ++- language/parser.cc | 92 ------- language/parser.hpp | 5 - language/repl.cc | 31 --- language/repl.hpp | 5 - language/vc12/culebra.sln | 26 -- language/vc12/culebra.vcxproj | 98 -------- language/vc14/culebra.vcxproj | 5 - 11 files changed, 468 insertions(+), 627 deletions(-) delete mode 100644 language/interpreter.cc delete mode 100644 language/parser.cc delete mode 100644 language/parser.hpp delete mode 100644 language/repl.cc delete mode 100644 language/repl.hpp delete mode 100644 language/vc12/culebra.sln delete mode 100644 language/vc12/culebra.vcxproj diff --git a/language/CMakeLists.txt b/language/CMakeLists.txt index 5ac8a13..ae57321 100644 --- a/language/CMakeLists.txt +++ b/language/CMakeLists.txt @@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 3.0) include_directories(..) 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) diff --git a/language/interpreter.cc b/language/interpreter.cc deleted file mode 100644 index 47a7abf..0000000 --- a/language/interpreter.cc +++ /dev/null @@ -1,361 +0,0 @@ -#include "interpreter.hpp" -#include "parser.hpp" -#include - -using namespace peglib; -using namespace std; - -struct Eval -{ - static Value eval(const Ast& ast, shared_ptr 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 "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) { - return Value(string(ast.token)); - } - - // NOTREACHED - throw logic_error("invalid Ast type"); - } - -private: - static Value eval_statements(const Ast& ast, shared_ptr env) { - if (ast.is_token) { - return eval(ast, env); - } else if (ast.nodes.empty()) { - return Value(); - } - auto it = ast.nodes.begin(); - while (it != ast.nodes.end() - 1) { - eval(**it, env); - ++it; - } - return eval(**it, env); - } - - static Value eval_while(const Ast& ast, shared_ptr env) { - for (;;) { - auto cond = eval(*ast.nodes[0], env); - if (!cond.to_bool()) { - break; - } - eval(*ast.nodes[1], env); - } - return Value(); - } - - static Value eval_if(const Ast& ast, shared_ptr env) { - const auto& nodes = ast.nodes; - - for (auto i = 0u; i < nodes.size(); i += 2) { - if (i + 1 == nodes.size()) { - return eval(*nodes[i], env); - } else { - auto cond = eval(*nodes[i], env); - if (cond.to_bool()) { - return eval(*nodes[i + 1], env); - } - } - } - - return Value(); - } - - static Value eval_function(const Ast& ast, shared_ptr env) { - std::vector params; - for (auto node: ast.nodes[0]->nodes) { - auto mut = node->nodes[0]->token == "mut"; - const auto& name = node->nodes[1]->token; - params.push_back({ name, mut }); - } - - auto body = ast.nodes[1]; - - auto f = FunctionValue( - params, - [=](shared_ptr callEnv) { - callEnv->append_outer(env); - return eval(*body, callEnv); - } - ); - - return Value(std::move(f)); - }; - - static Value eval_call(const Ast& ast, shared_ptr env) { - Value val = eval(*ast.nodes[0], env); - - for (auto i = 1u; i < ast.nodes.size(); i++) { - const auto& n = *ast.nodes[i]; - if (n.original_tag == "ARGUMENTS"_) { - // Function call - const auto& f = val.to_function(); - const auto& params = f.data->params; - const auto& args = n.nodes; - if (params.size() <= args.size()) { - auto callEnv = make_shared(); - - callEnv->initialize("self", val, false); - - for (auto iprm = 0u; iprm < params.size(); iprm++) { - auto param = params[iprm]; - auto arg = args[iprm]; - auto val = eval(*arg, env); - callEnv->initialize(param.name, val, param.mut); - } - - callEnv->initialize("__LINE__", Value((long)ast.line), false); - callEnv->initialize("__COLUMN__", Value((long)ast.column), false); - - val = f.data->eval(callEnv); - } else { - string msg = "arguments error..."; - throw runtime_error(msg); - } - } 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(arr.values->size())) { - val = arr.values->at(idx); - } - } else if (n.original_tag == "DOT"_) { - // Property - auto name = n.token; - auto prop = val.get_property(name); - - if (prop.get_type() == Value::Function) { - const auto& pf = prop.to_function(); - - auto f = FunctionValue( - pf.data->params, - [=](shared_ptr callEnv) { - callEnv->initialize("this", val, false); - if (val.get_type() == Value::Object) { - callEnv->set_object(val.to_object()); - } - return pf.data->eval(callEnv); - } - ); - - val = Value(std::move(f)); - } else { - val = prop; - } - } else { - throw std::logic_error("invalid internal condition."); - } - } - - return val; - } - - static Value eval_logical_or(const Ast& ast, shared_ptr env) { - if (ast.nodes.size() == 1) { - return eval(*ast.nodes[0], env); - } else { - Value ret; - for (auto node: ast.nodes) { - ret = eval(*node, env); - if (ret.to_bool()) { - return ret; - } - } - return ret; - } - } - - static Value eval_logical_and(const Ast& ast, shared_ptr env) { - Value ret; - for (auto node: ast.nodes) { - ret = eval(*node, env); - if (!ret.to_bool()) { - return ret; - } - } - return ret; - } - - static Value eval_condition(const Ast& ast, shared_ptr env) { - if (ast.nodes.size() == 1) { - return eval(*ast.nodes[0], env); - } else { - auto lhs = eval(*ast.nodes[0], env); - auto ope = eval(*ast.nodes[1], env).to_string(); - auto rhs = eval(*ast.nodes[2], env); - - if (ope == "==") { - return Value(lhs == rhs); - } else if (ope == "!=") { - return Value(lhs != rhs); - } else if (ope == "<=") { - return Value(lhs <= rhs); - } else if (ope == "<") { - return Value(lhs < rhs); - } else if (ope == ">=") { - return Value(lhs >= rhs); - } else if (ope == ">") { - return Value(lhs > rhs); - } else { - throw std::logic_error("invalid internal condition."); - } - } - } - - static Value eval_unary_plus(const Ast& ast, shared_ptr env) { - if (ast.nodes.size() == 1) { - return eval(*ast.nodes[0], env); - } else { - return eval(*ast.nodes[1], env); - } - } - - static Value eval_unary_minus(const Ast& ast, shared_ptr env) { - if (ast.nodes.size() == 1) { - return eval(*ast.nodes[0], env); - } else { - return Value(eval(*ast.nodes[1], env).to_long() * -1); - } - } - - static Value eval_unary_not(const Ast& ast, shared_ptr env) { - if (ast.nodes.size() == 1) { - return eval(*ast.nodes[0], env); - } else { - return Value(!eval(*ast.nodes[1], env).to_bool()); - } - } - - static Value eval_bin_expression(const Ast& ast, shared_ptr env) { - auto ret = eval(*ast.nodes[0], env).to_long(); - for (auto i = 1u; i < ast.nodes.size(); i += 2) { - auto val = eval(*ast.nodes[i + 1], env).to_long(); - auto ope = eval(*ast.nodes[i], env).to_string()[0]; - switch (ope) { - case '+': ret += val; break; - case '-': ret -= val; break; - case '*': ret *= val; break; - case '/': ret /= val; break; - case '%': ret %= val; break; - } - } - return Value(ret); - } - - static Value eval_assignment(const Ast& ast, shared_ptr env) { - const auto& mut = ast.nodes[0]->token; - const auto& var = ast.nodes[1]->token; - auto val = eval(*ast.nodes[2], env); - if (env->has(var)) { - env->assign(var, val); - } else { - env->initialize(var, val, mut == "mut"); - } - return val; - }; - - static Value eval_identifier(const Ast& ast, shared_ptr env) { - const auto& var = ast.token; - return env->get(var); - }; - - static Value eval_object(const Ast& ast, shared_ptr env) { - ObjectValue obj; - - for (auto i = 0u; i < ast.nodes.size(); i++) { - const auto& prop = *ast.nodes[i]; - const auto& name = prop.nodes[0]->token; - auto val = eval(*prop.nodes[1], env); - obj.properties->emplace(name, val); - } - - return Value(std::move(obj)); - } - - static Value eval_array(const Ast& ast, shared_ptr env) { - ArrayValue arr; - - for (auto i = 0u; i < ast.nodes.size(); i++) { - auto expr = ast.nodes[i]; - auto val = eval(*expr, env); - arr.values->push_back(val); - } - - return Value(std::move(arr)); - } - - static Value eval_number(const Ast& ast, shared_ptr env) { - return Value(stol(ast.token)); - }; - - static Value eval_bool(const Ast& ast, shared_ptr env) { - return Value(ast.token == "true"); - }; - - static Value eval_interpolated_string(const Ast& ast, shared_ptr env) { - string s; - for (auto node: ast.nodes) { - const auto& val = eval(*node, env); - s += val.str(); - } - return Value(std::move(s)); - }; -}; - -bool run( - const string& path, - shared_ptr env, - const char* expr, - size_t len, - Value& val, - string& msg, - bool print_ast) -{ - try { - shared_ptr ast; - - auto& parser = get_parser(); - - parser.log = [&](size_t ln, size_t col, const string& err_msg) { - stringstream ss; - ss << path << ":" << ln << ":" << col << ": " << err_msg << endl; - msg = ss.str(); - }; - - if (parser.parse_n(expr, len, ast)) { - if (print_ast) { - ast->print(); - } - - val = Eval::eval(*ast, env); - return true; - } - } catch (runtime_error& e) { - msg = e.what(); - } - - return false; -} - -// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/interpreter.hpp b/language/interpreter.hpp index 950a7b1..2ecdf18 100644 --- a/language/interpreter.hpp +++ b/language/interpreter.hpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -443,11 +444,449 @@ inline void setup_built_in_functions(Environment& env) { } } -bool run( +struct Eval +{ + static Value eval(const peglib::Ast& ast, std::shared_ptr env) { + using peglib::operator"" _; + + 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 "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) { + return Value(std::string(ast.token)); + } + + // NOTREACHED + throw std::logic_error("invalid Ast type"); + } + +private: + static Value eval_statements(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.is_token) { + return eval(ast, env); + } else if (ast.nodes.empty()) { + return Value(); + } + auto it = ast.nodes.begin(); + while (it != ast.nodes.end() - 1) { + eval(**it, env); + ++it; + } + return eval(**it, env); + } + + static Value eval_while(const peglib::Ast& ast, std::shared_ptr env) { + for (;;) { + auto cond = eval(*ast.nodes[0], env); + if (!cond.to_bool()) { + break; + } + eval(*ast.nodes[1], env); + } + return Value(); + } + + static Value eval_if(const peglib::Ast& ast, std::shared_ptr env) { + const auto& nodes = ast.nodes; + + for (auto i = 0u; i < nodes.size(); i += 2) { + if (i + 1 == nodes.size()) { + return eval(*nodes[i], env); + } else { + auto cond = eval(*nodes[i], env); + if (cond.to_bool()) { + return eval(*nodes[i + 1], env); + } + } + } + + return Value(); + } + + static Value eval_function(const peglib::Ast& ast, std::shared_ptr env) { + std::vector params; + for (auto node: ast.nodes[0]->nodes) { + auto mut = node->nodes[0]->token == "mut"; + const auto& name = node->nodes[1]->token; + params.push_back({ name, mut }); + } + + auto body = ast.nodes[1]; + + auto f = FunctionValue( + params, + [=](std::shared_ptr callEnv) { + callEnv->append_outer(env); + return eval(*body, callEnv); + } + ); + + return Value(std::move(f)); + }; + + static Value eval_call(const peglib::Ast& ast, std::shared_ptr env) { + using peglib::operator"" _; + + Value val = eval(*ast.nodes[0], env); + + for (auto i = 1u; i < ast.nodes.size(); i++) { + const auto& n = *ast.nodes[i]; + if (n.original_tag == "ARGUMENTS"_) { + // Function call + const auto& f = val.to_function(); + const auto& params = f.data->params; + const auto& args = n.nodes; + if (params.size() <= args.size()) { + auto callEnv = std::make_shared(); + + callEnv->initialize("self", val, false); + + for (auto iprm = 0u; iprm < params.size(); iprm++) { + auto param = params[iprm]; + auto arg = args[iprm]; + auto val = eval(*arg, env); + callEnv->initialize(param.name, val, param.mut); + } + + callEnv->initialize("__LINE__", Value((long)ast.line), false); + callEnv->initialize("__COLUMN__", Value((long)ast.column), false); + + val = f.data->eval(callEnv); + } else { + std::string msg = "arguments error..."; + throw std::runtime_error(msg); + } + } 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(arr.values->size())) { + val = arr.values->at(idx); + } + } else if (n.original_tag == "DOT"_) { + // Property + auto name = n.token; + auto prop = val.get_property(name); + + if (prop.get_type() == Value::Function) { + const auto& pf = prop.to_function(); + + auto f = FunctionValue( + pf.data->params, + [=](std::shared_ptr callEnv) { + callEnv->initialize("this", val, false); + if (val.get_type() == Value::Object) { + callEnv->set_object(val.to_object()); + } + return pf.data->eval(callEnv); + } + ); + + val = Value(std::move(f)); + } else { + val = prop; + } + } else { + throw std::logic_error("invalid internal condition."); + } + } + + return val; + } + + static Value eval_logical_or(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.size() == 1) { + return eval(*ast.nodes[0], env); + } else { + Value ret; + for (auto node: ast.nodes) { + ret = eval(*node, env); + if (ret.to_bool()) { + return ret; + } + } + return ret; + } + } + + static Value eval_logical_and(const peglib::Ast& ast, std::shared_ptr env) { + Value ret; + for (auto node: ast.nodes) { + ret = eval(*node, env); + if (!ret.to_bool()) { + return ret; + } + } + return ret; + } + + static Value eval_condition(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.size() == 1) { + return eval(*ast.nodes[0], env); + } else { + auto lhs = eval(*ast.nodes[0], env); + auto ope = eval(*ast.nodes[1], env).to_string(); + auto rhs = eval(*ast.nodes[2], env); + + if (ope == "==") { + return Value(lhs == rhs); + } else if (ope == "!=") { + return Value(lhs != rhs); + } else if (ope == "<=") { + return Value(lhs <= rhs); + } else if (ope == "<") { + return Value(lhs < rhs); + } else if (ope == ">=") { + return Value(lhs >= rhs); + } else if (ope == ">") { + return Value(lhs > rhs); + } else { + throw std::logic_error("invalid internal condition."); + } + } + } + + static Value eval_unary_plus(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.size() == 1) { + return eval(*ast.nodes[0], env); + } else { + return eval(*ast.nodes[1], env); + } + } + + static Value eval_unary_minus(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.size() == 1) { + return eval(*ast.nodes[0], env); + } else { + return Value(eval(*ast.nodes[1], env).to_long() * -1); + } + } + + static Value eval_unary_not(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.size() == 1) { + return eval(*ast.nodes[0], env); + } else { + return Value(!eval(*ast.nodes[1], env).to_bool()); + } + } + + static Value eval_bin_expression(const peglib::Ast& ast, std::shared_ptr env) { + auto ret = eval(*ast.nodes[0], env).to_long(); + for (auto i = 1u; i < ast.nodes.size(); i += 2) { + auto val = eval(*ast.nodes[i + 1], env).to_long(); + auto ope = eval(*ast.nodes[i], env).to_string()[0]; + switch (ope) { + case '+': ret += val; break; + case '-': ret -= val; break; + case '*': ret *= val; break; + case '/': ret /= val; break; + case '%': ret %= val; break; + } + } + return Value(ret); + } + + static Value eval_assignment(const peglib::Ast& ast, std::shared_ptr env) { + const auto& mut = ast.nodes[0]->token; + const auto& var = ast.nodes[1]->token; + auto val = eval(*ast.nodes[2], env); + if (env->has(var)) { + env->assign(var, val); + } else { + env->initialize(var, val, mut == "mut"); + } + return val; + }; + + static Value eval_identifier(const peglib::Ast& ast, std::shared_ptr env) { + const auto& var = ast.token; + return env->get(var); + }; + + static Value eval_object(const peglib::Ast& ast, std::shared_ptr env) { + ObjectValue obj; + + for (auto i = 0u; i < ast.nodes.size(); i++) { + const auto& prop = *ast.nodes[i]; + const auto& name = prop.nodes[0]->token; + auto val = eval(*prop.nodes[1], env); + obj.properties->emplace(name, val); + } + + return Value(std::move(obj)); + } + + static Value eval_array(const peglib::Ast& ast, std::shared_ptr env) { + ArrayValue arr; + + for (auto i = 0u; i < ast.nodes.size(); i++) { + auto expr = ast.nodes[i]; + auto val = eval(*expr, env); + arr.values->push_back(val); + } + + return Value(std::move(arr)); + } + + static Value eval_number(const peglib::Ast& ast, std::shared_ptr env) { + return Value(stol(ast.token)); + }; + + static Value eval_bool(const peglib::Ast& ast, std::shared_ptr env) { + return Value(ast.token == "true"); + }; + + static Value eval_interpolated_string(const peglib::Ast& ast, std::shared_ptr env) { + std::string s; + for (auto node: ast.nodes) { + const auto& val = eval(*node, env); + s += val.str(); + } + return Value(std::move(s)); + }; +}; + +inline peglib::peg& get_parser() +{ + using namespace peglib; + using namespace std; + + static auto grammar_ = R"( + + PROGRAM <- _ STATEMENTS + + STATEMENTS <- (EXPRESSION (';' _)?)* + + EXPRESSION <- ASSIGNMENT / LOGICAL_OR + ASSIGNMENT <- MUTABLE IDENTIFIER '=' _ EXPRESSION + WHILE <- 'while' _ EXPRESSION BLOCK + IF <- 'if' _ EXPRESSION BLOCK ('else' _ 'if' _ EXPRESSION BLOCK)* ('else' _ BLOCK)? + + LOGICAL_OR <- LOGICAL_AND ('||' _ LOGICAL_AND)* + LOGICAL_AND <- CONDITION ('&&' _ CONDITION)* + CONDITION <- ADDITIVE (CONDITION_OPERATOR ADDITIVE)* + ADDITIVE <- UNARY_PLUS (ADDITIVE_OPERATOR UNARY_PLUS)* + UNARY_PLUS <- UNARY_PLUS_OPERATOR? UNARY_MINUS + UNARY_MINUS <- UNARY_MINUS_OPERATOR? UNARY_NOT + UNARY_NOT <- UNARY_NOT_OPERATOR? MULTIPLICATIVE + MULTIPLICATIVE <- CALL (MULTIPLICATIVE_OPERATOR CALL)* + + CALL <- PRIMARY (ARGUMENTS / INDEX / DOT)* + ARGUMENTS <- '(' _ (EXPRESSION (',' _ EXPRESSION)*)? ')' _ + INDEX <- '[' _ EXPRESSION ']' _ + DOT <- '.' _ IDENTIFIER + + PRIMARY <- WHILE / IF / FUNCTION / IDENTIFIER / OBJECT / ARRAY / NUMBER / BOOLEAN / STRING / INTERPOLATED_STRING / '(' _ EXPRESSION ')' _ + + FUNCTION <- 'fn' _ PARAMETERS BLOCK + PARAMETERS <- '(' _ (PARAMETER (',' _ PARAMETER)*)? ')' _ + PARAMETER <- MUTABLE IDENTIFIER + + BLOCK <- '{' _ STATEMENTS '}' _ + + CONDITION_OPERATOR <- < ('==' / '!=' / '<=' / '<' / '>=' / '>') > _ + ADDITIVE_OPERATOR <- < [-+] > _ + UNARY_PLUS_OPERATOR <- < '+' > _ + UNARY_MINUS_OPERATOR <- < '-' > _ + UNARY_NOT_OPERATOR <- < '!' > _ + MULTIPLICATIVE_OPERATOR <- < [*/%] > _ + + IDENTIFIER <- < [a-zA-Z_][a-zA-Z0-9_]* > _ + + OBJECT <- '{' _ (OBJECT_PROPERTY (',' _ OBJECT_PROPERTY)*)? '}' _ + OBJECT_PROPERTY <- IDENTIFIER ':' _ EXPRESSION + + ARRAY <- '[' _ (EXPRESSION (',' _ EXPRESSION)*)? ']' _ + + NUMBER <- < [0-9]+ > _ + BOOLEAN <- < ('true' / 'false') > _ + STRING <- ['] < (!['] .)* > ['] _ + + INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _ + INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)* + + MUTABLE <- < 'mut'? > _ + + ~_ <- (Space / EndOfLine / Comment)* + Space <- ' ' / '\t' + EndOfLine <- '\r\n' / '\n' / '\r' + EndOfFile <- !. + Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile) + + )"; + + static peg parser; + static bool initialized = false; + + if (!initialized) { + initialized = true; + + parser.log = [&](size_t ln, size_t col, const string& msg) { + cerr << ln << ":" << col << ": " << msg << endl; + }; + + if (!parser.load_grammar(grammar_)) { + throw logic_error("invalid peg grammar"); + } + + parser.enable_ast(true, { "PARAMETERS", "ARGUMENTS" }); + } + + return parser; +} + +inline bool run( const std::string& path, std::shared_ptr env, const char* expr, size_t len, Value& val, std::string& msg, - bool print_ast); + bool print_ast) +{ + try { + std::shared_ptr ast; + + auto& parser = get_parser(); + + parser.log = [&](size_t ln, size_t col, const std::string& err_msg) { + std::stringstream ss; + ss << path << ":" << ln << ":" << col << ": " << err_msg << std::endl; + msg = ss.str(); + }; + + if (parser.parse_n(expr, len, ast)) { + if (print_ast) { + ast->print(); + } + + val = Eval::eval(*ast, env); + return true; + } + } catch (std::runtime_error& e) { + msg = e.what(); + } + + return false; +} + diff --git a/language/main.cc b/language/main.cc index b661ec4..44fd0ec 100644 --- a/language/main.cc +++ b/language/main.cc @@ -1,4 +1,5 @@ -#include "repl.hpp" +#include "interpreter.hpp" +#include "linenoise.hpp" #include #include #include @@ -22,6 +23,30 @@ bool read_file(const char* path, vector& buff) return true; } +int repl(shared_ptr env, bool print_ast) +{ + for (;;) { + auto line = linenoise::Readline("cul> "); + + if (line == "exit" || line == "quit") { + break; + } + + if (!line.empty()) { + Value val; + string msg; + if (run("(repl)", env, line.c_str(), line.size(), val, msg, print_ast)) { + cout << val << endl; + linenoise::AddHistory(line.c_str()); + } else if (!msg.empty()) { + cout << msg; + } + } + } + + return 0; +} + int main(int argc, const char** argv) { auto print_ast = false; diff --git a/language/parser.cc b/language/parser.cc deleted file mode 100644 index 5fd9a56..0000000 --- a/language/parser.cc +++ /dev/null @@ -1,92 +0,0 @@ -#include "parser.hpp" - -using namespace peglib; -using namespace std; - -const auto g_grammar = R"( - - PROGRAM <- _ STATEMENTS - - STATEMENTS <- (EXPRESSION (';' _)?)* - - EXPRESSION <- ASSIGNMENT / LOGICAL_OR - ASSIGNMENT <- MUTABLE IDENTIFIER '=' _ EXPRESSION - WHILE <- 'while' _ EXPRESSION BLOCK - IF <- 'if' _ EXPRESSION BLOCK ('else' _ 'if' _ EXPRESSION BLOCK)* ('else' _ BLOCK)? - - LOGICAL_OR <- LOGICAL_AND ('||' _ LOGICAL_AND)* - LOGICAL_AND <- CONDITION ('&&' _ CONDITION)* - CONDITION <- ADDITIVE (CONDITION_OPERATOR ADDITIVE)* - ADDITIVE <- UNARY_PLUS (ADDITIVE_OPERATOR UNARY_PLUS)* - UNARY_PLUS <- UNARY_PLUS_OPERATOR? UNARY_MINUS - UNARY_MINUS <- UNARY_MINUS_OPERATOR? UNARY_NOT - UNARY_NOT <- UNARY_NOT_OPERATOR? MULTIPLICATIVE - MULTIPLICATIVE <- CALL (MULTIPLICATIVE_OPERATOR CALL)* - - CALL <- PRIMARY (ARGUMENTS / INDEX / DOT)* - ARGUMENTS <- '(' _ (EXPRESSION (',' _ EXPRESSION)*)? ')' _ - INDEX <- '[' _ EXPRESSION ']' _ - DOT <- '.' _ IDENTIFIER - - PRIMARY <- WHILE / IF / FUNCTION / IDENTIFIER / OBJECT / ARRAY / NUMBER / BOOLEAN / STRING / INTERPOLATED_STRING / '(' _ EXPRESSION ')' _ - - FUNCTION <- 'fn' _ PARAMETERS BLOCK - PARAMETERS <- '(' _ (PARAMETER (',' _ PARAMETER)*)? ')' _ - PARAMETER <- MUTABLE IDENTIFIER - - BLOCK <- '{' _ STATEMENTS '}' _ - - CONDITION_OPERATOR <- < ('==' / '!=' / '<=' / '<' / '>=' / '>') > _ - ADDITIVE_OPERATOR <- < [-+] > _ - UNARY_PLUS_OPERATOR <- < '+' > _ - UNARY_MINUS_OPERATOR <- < '-' > _ - UNARY_NOT_OPERATOR <- < '!' > _ - MULTIPLICATIVE_OPERATOR <- < [*/%] > _ - - IDENTIFIER <- < [a-zA-Z_][a-zA-Z0-9_]* > _ - - OBJECT <- '{' _ (OBJECT_PROPERTY (',' _ OBJECT_PROPERTY)*)? '}' _ - OBJECT_PROPERTY <- IDENTIFIER ':' _ EXPRESSION - - ARRAY <- '[' _ (EXPRESSION (',' _ EXPRESSION)*)? ']' _ - - NUMBER <- < [0-9]+ > _ - BOOLEAN <- < ('true' / 'false') > _ - STRING <- ['] < (!['] .)* > ['] _ - - INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _ - INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)* - - MUTABLE <- < 'mut'? > _ - - ~_ <- (Space / EndOfLine / Comment)* - Space <- ' ' / '\t' - EndOfLine <- '\r\n' / '\n' / '\r' - EndOfFile <- !. - Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile) - -)"; - -peg& get_parser() -{ - static peg parser; - static bool initialized = false; - - if (!initialized) { - initialized = true; - - parser.log = [&](size_t ln, size_t col, const string& msg) { - cerr << ln << ":" << col << ": " << msg << endl; - }; - - if (!parser.load_grammar(g_grammar)) { - throw logic_error("invalid peg grammar"); - } - - parser.enable_ast(true, { "PARAMETERS", "ARGUMENTS" }); - } - - return parser; -} - -// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/parser.hpp b/language/parser.hpp deleted file mode 100644 index 2a60e51..0000000 --- a/language/parser.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -peglib::peg& get_parser(); - -// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/repl.cc b/language/repl.cc deleted file mode 100644 index 29835ba..0000000 --- a/language/repl.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include "linenoise.hpp" -#include "repl.hpp" -#include - -using namespace std; - -int repl(shared_ptr env, bool print_ast) -{ - for (;;) { - auto line = linenoise::Readline("cul> "); - - if (line == "exit" || line == "quit") { - break; - } - - if (!line.empty()) { - Value val; - string msg; - if (run("(repl)", env, line.c_str(), line.size(), val, msg, print_ast)) { - cout << val << endl; - linenoise::AddHistory(line.c_str()); - } else if (!msg.empty()) { - cout << msg; - } - } - } - - return 0; -} - -// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/repl.hpp b/language/repl.hpp deleted file mode 100644 index d1a5ad4..0000000 --- a/language/repl.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "interpreter.hpp" - -int repl(std::shared_ptr env, bool print_ast); - -// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/language/vc12/culebra.sln b/language/vc12/culebra.sln deleted file mode 100644 index cf12fcc..0000000 --- a/language/vc12/culebra.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "culebra", "culebra.vcxproj", "{F85B641A-7538-4809-8175-C528FF632CF6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F85B641A-7538-4809-8175-C528FF632CF6}.Debug|Win32.ActiveCfg = Debug|Win32 - {F85B641A-7538-4809-8175-C528FF632CF6}.Debug|Win32.Build.0 = Debug|Win32 - {F85B641A-7538-4809-8175-C528FF632CF6}.Release|Win32.ActiveCfg = Release|Win32 - {F85B641A-7538-4809-8175-C528FF632CF6}.Release|Win32.Build.0 = Release|Win32 - {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Debug|Win32.ActiveCfg = Debug|Win32 - {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Debug|Win32.Build.0 = Debug|Win32 - {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.ActiveCfg = Release|Win32 - {1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/language/vc12/culebra.vcxproj b/language/vc12/culebra.vcxproj deleted file mode 100644 index 4fcd297..0000000 --- a/language/vc12/culebra.vcxproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - {F85B641A-7538-4809-8175-C528FF632CF6} - Win32Proj - culebra - - - - Application - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - - - - - - - - - - - true - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../.. - - - Console - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../.. - - - Console - true - true - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - diff --git a/language/vc14/culebra.vcxproj b/language/vc14/culebra.vcxproj index c0e3d6a..191a845 100644 --- a/language/vc14/culebra.vcxproj +++ b/language/vc14/culebra.vcxproj @@ -14,14 +14,9 @@ - - - - - {F85B641A-7538-4809-8175-C528FF632CF6}