parent
7ef79b62e2
commit
0168d19a0c
@ -0,0 +1,5 @@ |
|||||||
|
cmake_minimum_required(VERSION 3.0) |
||||||
|
include_directories(..) |
||||||
|
add_definitions("-std=c++1y") |
||||||
|
|
||||||
|
add_executable(culebra main.cc repl.cc interpreter.cc parser.cc) |
@ -0,0 +1,201 @@ |
|||||||
|
#include "interpreter.hpp" |
||||||
|
#include "parser.hpp" |
||||||
|
|
||||||
|
using namespace peglib; |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
struct Eval |
||||||
|
{ |
||||||
|
static Value eval(const Ast& ast, Env& env) { |
||||||
|
switch (ast.type) { |
||||||
|
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 FunctionCall: return eval_function_call(ast, env); |
||||||
|
case Assignment: return eval_assignment(ast, env); |
||||||
|
case Condition: return eval_condition(ast, env); |
||||||
|
case BinExpresion: return eval_bin_expression(ast, env); |
||||||
|
case Identifier: return eval_identifier(ast, env); |
||||||
|
case Number: return eval_number(ast, env); |
||||||
|
case Boolean: return eval_bool(ast, env); |
||||||
|
} |
||||||
|
|
||||||
|
if (ast.is_token) { |
||||||
|
return Value(ast.token); |
||||||
|
} |
||||||
|
|
||||||
|
// NOTREACHED
|
||||||
|
throw logic_error("invalid Ast type"); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
static Value eval_statements(const Ast& ast, Env& 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, Env& 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, Env& env) { |
||||||
|
auto cond = eval(*ast.nodes[0], env); |
||||||
|
if (cond.to_bool()) { |
||||||
|
return eval(*ast.nodes[1], env); |
||||||
|
} else if (ast.nodes.size() > 2) { |
||||||
|
return eval(*ast.nodes[2], env); |
||||||
|
} |
||||||
|
return Value(); |
||||||
|
} |
||||||
|
|
||||||
|
static Value eval_function(const Ast& ast, Env& env) { |
||||||
|
vector<string> params; |
||||||
|
for (auto node: ast.nodes[0]->nodes) { |
||||||
|
params.push_back(node->token); |
||||||
|
} |
||||||
|
|
||||||
|
auto body = ast.nodes[1]; |
||||||
|
|
||||||
|
auto f = Value::FunctionValue { |
||||||
|
params, |
||||||
|
[=](Env& env) { return eval(*body, env); } |
||||||
|
}; |
||||||
|
return Value(f); |
||||||
|
}; |
||||||
|
|
||||||
|
static Value eval_function_call(const Ast& ast, Env& env) { |
||||||
|
const auto& var = ast.nodes[0]->token; |
||||||
|
const auto& args = ast.nodes[1]->nodes; |
||||||
|
|
||||||
|
const auto& f = dereference_identirier(env, var); |
||||||
|
const auto& fv = f.to_function(); |
||||||
|
|
||||||
|
if (fv.params.size() <= args.size()) { |
||||||
|
Env callEnv(env); |
||||||
|
|
||||||
|
callEnv.set("self", f); |
||||||
|
|
||||||
|
for (auto i = 0u; i < fv.params.size(); i++) { |
||||||
|
auto var = fv.params[i]; |
||||||
|
auto arg = args[i]; |
||||||
|
auto val = eval(*arg, env); |
||||||
|
callEnv.set(var, val); |
||||||
|
} |
||||||
|
return fv.eval(callEnv); |
||||||
|
} |
||||||
|
|
||||||
|
string msg = "arguments error in '" + var + "'..."; |
||||||
|
throw runtime_error(msg); |
||||||
|
} |
||||||
|
|
||||||
|
static Value eval_condition(const Ast& ast, Env& env) { |
||||||
|
auto lhs = eval(*ast.nodes[0], env); |
||||||
|
if (ast.nodes.size() > 1) { |
||||||
|
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); |
||||||
|
} |
||||||
|
|
||||||
|
throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
return lhs; // Any
|
||||||
|
} |
||||||
|
|
||||||
|
static Value eval_bin_expression(const Ast& ast, Env& 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; |
||||||
|
} |
||||||
|
} |
||||||
|
return Value(ret); |
||||||
|
} |
||||||
|
|
||||||
|
static Value eval_assignment(const Ast& ast, Env& env) { |
||||||
|
const auto& var = ast.nodes[0]->token; |
||||||
|
auto val = eval(*ast.nodes[1], env); |
||||||
|
env.set(var, val); |
||||||
|
return val; |
||||||
|
}; |
||||||
|
|
||||||
|
static Value eval_identifier(const Ast& ast, Env& env) { |
||||||
|
const auto& var = ast.token; |
||||||
|
return dereference_identirier(env, var); |
||||||
|
}; |
||||||
|
|
||||||
|
static Value eval_number(const Ast& ast, Env& env) { |
||||||
|
return Value(stol(ast.token)); |
||||||
|
}; |
||||||
|
|
||||||
|
static Value eval_bool(const Ast& ast, Env& env) { |
||||||
|
return Value(ast.token == "true"); |
||||||
|
}; |
||||||
|
|
||||||
|
static Value dereference_identirier(Env& env, const string& var) { |
||||||
|
if (!env.has(var)) { |
||||||
|
string msg = "undefined variable '" + var + "'..."; |
||||||
|
throw runtime_error(msg); |
||||||
|
} |
||||||
|
return env.get(var); |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Value& val) |
||||||
|
{ |
||||||
|
return val.out(os); |
||||||
|
} |
||||||
|
|
||||||
|
bool run(Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast) |
||||||
|
{ |
||||||
|
try { |
||||||
|
shared_ptr<Ast> ast;
|
||||||
|
if (get_parser().parse_n(expr, len, ast)) { |
||||||
|
if (print_ast) { |
||||||
|
ast->print(); |
||||||
|
} |
||||||
|
|
||||||
|
val = Eval::eval(*ast, env); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} catch (exception& e) { |
||||||
|
msg = e.what(); |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
@ -0,0 +1,196 @@ |
|||||||
|
#include <map> |
||||||
|
#include <string> |
||||||
|
#include <peglib.h> |
||||||
|
|
||||||
|
struct Env; |
||||||
|
|
||||||
|
struct Value |
||||||
|
{ |
||||||
|
enum Type { Undefined, Bool, Long, String, Array, Function }; |
||||||
|
|
||||||
|
struct ArrayValue { |
||||||
|
std::vector<Value> values; |
||||||
|
}; |
||||||
|
|
||||||
|
struct FunctionValue { |
||||||
|
std::vector<std::string> params; |
||||||
|
std::function<Value (Env& env)> eval; |
||||||
|
}; |
||||||
|
|
||||||
|
explicit Value() : type(Undefined) {} |
||||||
|
explicit Value(bool b) : type(Bool) { v = b; } |
||||||
|
explicit Value(long l) : type(Long) { v = l; } |
||||||
|
explicit Value(const std::string& s) : type(String) { v = s; } |
||||||
|
explicit Value(const ArrayValue& a) : type(Array) { v = a; } |
||||||
|
explicit Value(const FunctionValue& f) : type(Function) { v = f; } |
||||||
|
|
||||||
|
bool to_bool() const { |
||||||
|
switch (type) { |
||||||
|
case Bool: return v.get<bool>(); |
||||||
|
case Long: return v.get<long>() != 0; |
||||||
|
} |
||||||
|
throw std::runtime_error("type error."); |
||||||
|
} |
||||||
|
|
||||||
|
long to_long() const { |
||||||
|
switch (type) { |
||||||
|
case Bool: return v.get<bool>(); |
||||||
|
case Long: return v.get<long>(); |
||||||
|
} |
||||||
|
throw std::runtime_error("type error."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string to_string() const { |
||||||
|
switch (type) { |
||||||
|
case String: return v.get<std::string>(); |
||||||
|
} |
||||||
|
throw std::runtime_error("type error."); |
||||||
|
} |
||||||
|
|
||||||
|
ArrayValue to_array() const { |
||||||
|
switch (type) { |
||||||
|
case Array: return v.get<ArrayValue>(); |
||||||
|
} |
||||||
|
throw std::runtime_error("type error."); |
||||||
|
} |
||||||
|
|
||||||
|
FunctionValue to_function() const { |
||||||
|
switch (type) { |
||||||
|
case Function: return v.get<FunctionValue>(); |
||||||
|
} |
||||||
|
throw std::runtime_error("type error."); |
||||||
|
} |
||||||
|
|
||||||
|
std::ostream& out(std::ostream& os) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: os << "undefined"; break; |
||||||
|
case Bool: os << (to_bool() ? "true" : "false"); break; |
||||||
|
case Long: os << to_long(); break; |
||||||
|
case String: os << "'" << to_string() << "'"; break; |
||||||
|
case Function: os << "[function]"; break; |
||||||
|
case Array: os << "[array]"; break; |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
return os; |
||||||
|
} |
||||||
|
|
||||||
|
bool operator==(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return true;
|
||||||
|
case Bool: return to_bool() == rhs.to_bool(); |
||||||
|
case Long: return to_long() == rhs.to_long(); |
||||||
|
case String: return to_string() == rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
bool operator!=(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return false;
|
||||||
|
case Bool: return to_bool() != rhs.to_bool(); |
||||||
|
case Long: return to_long() != rhs.to_long(); |
||||||
|
case String: return to_string() != rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
bool operator<=(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return false;
|
||||||
|
case Bool: return to_bool() <= rhs.to_bool(); |
||||||
|
case Long: return to_long() <= rhs.to_long(); |
||||||
|
case String: return to_string() <= rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
bool operator<(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return false;
|
||||||
|
case Bool: return to_bool() < rhs.to_bool(); |
||||||
|
case Long: return to_long() < rhs.to_long(); |
||||||
|
case String: return to_string() < rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
bool operator>=(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return false;
|
||||||
|
case Bool: return to_bool() >= rhs.to_bool(); |
||||||
|
case Long: return to_long() >= rhs.to_long(); |
||||||
|
case String: return to_string() >= rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
bool operator>(const Value& rhs) const { |
||||||
|
switch (type) { |
||||||
|
case Undefined: return false;
|
||||||
|
case Bool: return to_bool() > rhs.to_bool(); |
||||||
|
case Long: return to_long() > rhs.to_long(); |
||||||
|
case String: return to_string() > rhs.to_string(); |
||||||
|
default: throw std::logic_error("invalid internal condition."); |
||||||
|
} |
||||||
|
// NOTREACHED
|
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
friend std::ostream& operator<<(std::ostream&, const Value&); |
||||||
|
|
||||||
|
int type; |
||||||
|
peglib::any v; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Value& val); |
||||||
|
|
||||||
|
struct Env |
||||||
|
{ |
||||||
|
Env() : outer_(nullptr) {} |
||||||
|
Env(Env& outer) : outer_(&outer) {} |
||||||
|
|
||||||
|
bool has(const std::string& s) const { |
||||||
|
if (dic_.find(s) != dic_.end()) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
if (outer_) { |
||||||
|
return outer_->has(s); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
Value get(const std::string& s) const { |
||||||
|
assert(has(s)); |
||||||
|
if (dic_.find(s) != dic_.end()) { |
||||||
|
return dic_.at(s); |
||||||
|
} |
||||||
|
return outer_->get(s); |
||||||
|
} |
||||||
|
|
||||||
|
void set(const std::string& s, const Value& val) { |
||||||
|
dic_[s] = val; |
||||||
|
} |
||||||
|
|
||||||
|
void setup_built_in_functions() { |
||||||
|
auto func_print = Value::FunctionValue { |
||||||
|
{ "arg" }, |
||||||
|
[](Env& env) { |
||||||
|
std::cout << env.get("arg") << std::endl; |
||||||
|
return Value(); |
||||||
|
} |
||||||
|
}; |
||||||
|
set("print", Value(func_print)); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
Env* outer_; |
||||||
|
std::map<std::string, Value> dic_; |
||||||
|
}; |
||||||
|
|
||||||
|
bool run(Env& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,73 @@ |
|||||||
|
#include "repl.hpp" |
||||||
|
#include <fstream> |
||||||
|
#include <iostream> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
bool read_file(const char* path, vector<char>& buff) |
||||||
|
{ |
||||||
|
ifstream ifs(path, ios::in|ios::binary); |
||||||
|
if (ifs.fail()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
auto size = static_cast<unsigned int>(ifs.seekg(0, ios::end).tellg()); |
||||||
|
|
||||||
|
if (size > 0) { |
||||||
|
buff.resize(size); |
||||||
|
ifs.seekg(0, ios::beg).read(&buff[0], static_cast<streamsize>(buff.size())); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, const char** argv) |
||||||
|
{ |
||||||
|
auto print_ast = false; |
||||||
|
auto shell = false; |
||||||
|
vector<const char*> path_list; |
||||||
|
|
||||||
|
int argi = 1; |
||||||
|
while (argi < argc) { |
||||||
|
auto arg = argv[argi++]; |
||||||
|
if (string("--shell") == arg) { |
||||||
|
shell = true; |
||||||
|
} else if (string("--ast") == arg) { |
||||||
|
print_ast = true; |
||||||
|
} else { |
||||||
|
path_list.push_back(arg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!shell) { |
||||||
|
shell = path_list.empty(); |
||||||
|
} |
||||||
|
|
||||||
|
Env env; |
||||||
|
env.setup_built_in_functions(); |
||||||
|
|
||||||
|
for (auto path: path_list) { |
||||||
|
vector<char> buff; |
||||||
|
if (!read_file(path, buff)) { |
||||||
|
cerr << "can't open '" << path << "'." << endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
Value val; |
||||||
|
string msg; |
||||||
|
if (!run(env, buff.data(), buff.size(), val, msg, print_ast)) { |
||||||
|
cerr << "error in '" << path << "'." << endl; |
||||||
|
cerr << msg.c_str() << endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (shell) { |
||||||
|
repl(env, print_ast); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
@ -0,0 +1,72 @@ |
|||||||
|
#include "parser.hpp" |
||||||
|
|
||||||
|
using namespace peglib; |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
static auto g_grammar = R"( |
||||||
|
PROGRAM <- _ STATEMENTS |
||||||
|
|
||||||
|
STATEMENTS <- EXPRESSION* |
||||||
|
|
||||||
|
EXPRESSION <- ASSIGNMENT / PRIMARY |
||||||
|
ASSIGNMENT <- IDENTIFIER '=' _ EXPRESSION |
||||||
|
WHILE <- 'while' _ EXPRESSION BLOCK |
||||||
|
IF <- 'if' _ EXPRESSION BLOCK ('else' _ BLOCK)? |
||||||
|
FUNCTION <- 'fn' _ PARAMETERS BLOCK |
||||||
|
PARAMETERS <- '(' _ IDENTIFIER* ')' _
|
||||||
|
FUNCTION_CALL <- IDENTIFIER ARGUMENTS |
||||||
|
ARGUMENTS <- '(' _ EXPRESSION* ')' _
|
||||||
|
|
||||||
|
PRIMARY <- CONDITION (CONDITION_OPERATOR CONDITION)? |
||||||
|
CONDITION <- TERM (TERM_OPERATOR TERM)* |
||||||
|
TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* |
||||||
|
FACTOR <- WHILE / IF / FUNCTION / FUNCTION_CALL / NUMBER / BOOLEAN / STRING / IDENTIFIER / '(' _ EXPRESSION ')' _ |
||||||
|
|
||||||
|
BLOCK <- '{' _ STATEMENTS '}' _ |
||||||
|
|
||||||
|
CONDITION_OPERATOR <- < ('==' / '!=' / '<=' / '<' / '>=' / '>') > _ |
||||||
|
TERM_OPERATOR <- < [-+] > _ |
||||||
|
FACTOR_OPERATOR <- < [*/] > _ |
||||||
|
IDENTIFIER <- < [a-zA-Z_]+ > _ |
||||||
|
|
||||||
|
NUMBER <- < [0-9]+ > _ |
||||||
|
BOOLEAN <- < ('true' / 'false') > _ |
||||||
|
STRING <- ['] < (!['] .)* > ['] _ |
||||||
|
|
||||||
|
~_ <- (Space / EndOfLine / Comment)* |
||||||
|
Space <- ' ' / '\t' |
||||||
|
EndOfLine <- '\r\n' / '\n' / '\r' |
||||||
|
EndOfFile <- !. |
||||||
|
Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile)
|
||||||
|
)"; |
||||||
|
|
||||||
|
static auto g_parser = peg(g_grammar) |
||||||
|
.ast_node_optimizable("STATEMENTS", Statements) |
||||||
|
.ast_node("WHILE", While) |
||||||
|
.ast_node("ASSIGNMENT", Assignment) |
||||||
|
.ast_node("IF", If) |
||||||
|
.ast_node("FUNCTION", Function) |
||||||
|
.ast_node("PARAMETERS") |
||||||
|
.ast_node("FUNCTION_CALL", FunctionCall) |
||||||
|
.ast_node("ARGUMENTS") |
||||||
|
.ast_node_optimizable("PRIMARY", Condition) |
||||||
|
.ast_node_optimizable("CONDITION", BinExpresion) |
||||||
|
.ast_node_optimizable("TERM", BinExpresion) |
||||||
|
.ast_token("CONDITION_OPERATOR") |
||||||
|
.ast_token("TERM_OPERATOR") |
||||||
|
.ast_token("FACTOR_OPERATOR") |
||||||
|
.ast_token("NUMBER", Number) |
||||||
|
.ast_token("BOOLEAN", Boolean) |
||||||
|
.ast_token("STRING") |
||||||
|
.ast_token("IDENTIFIER", Identifier) |
||||||
|
.ast_end() |
||||||
|
.set_logger([&](size_t ln, size_t col, const string& msg) { |
||||||
|
cerr << ln << ":" << col << ": " << msg << endl; |
||||||
|
}); |
||||||
|
|
||||||
|
const peglib::peg& get_parser() |
||||||
|
{ |
||||||
|
return g_parser; |
||||||
|
} |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
@ -0,0 +1,11 @@ |
|||||||
|
#include <peglib.h> |
||||||
|
|
||||||
|
enum AstType |
||||||
|
{ |
||||||
|
Statements, While, If, FunctionCall, Assignment, Condition, BinExpresion, |
||||||
|
Identifier, Number, Boolean, Function |
||||||
|
}; |
||||||
|
|
||||||
|
const peglib::peg& get_parser(); |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
@ -0,0 +1,31 @@ |
|||||||
|
#include "linenoise.hpp" |
||||||
|
#include "repl.hpp" |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
int repl(Env& 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(env, line.c_str(), line.size(), val, msg, print_ast)) { |
||||||
|
cout << val << endl; |
||||||
|
linenoise::AddHistory(line.c_str()); |
||||||
|
} else if (!msg.empty()) { |
||||||
|
cout << msg << endl; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
@ -0,0 +1,5 @@ |
|||||||
|
#include "interpreter.hpp" |
||||||
|
|
||||||
|
int repl(Env& env, bool print_ast); |
||||||
|
|
||||||
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
Loading…
Reference in new issue