From ff6deb98e3c1ba9ebfc39a15017d598b499fd650 Mon Sep 17 00:00:00 2001 From: yhirose Date: Tue, 4 Aug 2015 18:03:05 -0400 Subject: [PATCH] Added 'return' statement. --- language/cul.vim | 8 ++++++-- language/culebra.h | 39 +++++++++++++++++++++++++++++++-------- language/samples/test.cul | 29 ++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/language/cul.vim b/language/cul.vim index 52a07ed..3fa37ee 100644 --- a/language/cul.vim +++ b/language/cul.vim @@ -6,10 +6,12 @@ syn match culError ";" syn match culError "\s*$" syn match culLineComment "\(\/\/\|#\).*" contains=@Spell,javaScriptCommentTodo -syn keyword culKeyword fn +syn keyword culFunction fn syn keyword culSelf self syn keyword culConditional if else syn keyword culRepeat while +syn keyword culReturn return +syn keyword culDebugger debugger syn keyword culBoolean true false syn keyword culCommentTodo TODO FIXME XXX TBD contained syn keyword culStorage mut @@ -24,10 +26,12 @@ hi def link culCommentTodo Todo hi def link culConditional Conditional hi def link culDecNumber Number hi def link culFuncCall Function -hi def link culKeyword Keyword +hi def link culFunction Type hi def link culLineComment Comment hi def link culOperator Operator hi def link culRepeat Repeat +hi def link culReturn Statement +hi def link culDebugger Debug hi def link culSelf Constant hi def link culStorage StorageClass hi def link culStringD String diff --git a/language/culebra.h b/language/culebra.h index c43a0fd..803f3bb 100644 --- a/language/culebra.h +++ b/language/culebra.h @@ -9,9 +9,10 @@ const auto grammar_ = R"( PROGRAM <- _ STATEMENTS STATEMENTS <- (STATEMENT (';' _)?)* - STATEMENT <- DEBUGGER / EXPRESSION + STATEMENT <- DEBUGGER / RETURN / EXPRESSION DEBUGGER <- 'debugger' _ + RETURN <- 'return' __ '\n' / 'return' _ EXPRESSION? EXPRESSION <- ASSIGNMENT / LOGICAL_OR @@ -67,10 +68,11 @@ const auto grammar_ = R"( MUTABLE <- < 'mut'? > _ ~_ <- (Space / EndOfLine / Comment)* + ~__ <- (Space / Comment)* Space <- ' ' / '\t' EndOfLine <- '\r\n' / '\n' / '\r' EndOfFile <- !. - Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile) + Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* &(EndOfLine / EndOfFile) )"; @@ -526,12 +528,21 @@ inline void setup_built_in_functions(Environment& env) { false); } -struct Eval +struct Interpreter { - Eval(Debugger debugger = nullptr) + Interpreter(Debugger debugger = nullptr) : debugger_(debugger) { } + Value exec(const peglib::Ast& ast, std::shared_ptr env) { + try { + return eval(ast, env); + } catch (const Value& val) { + return val; + } + } + +private: Value eval(const peglib::Ast& ast, std::shared_ptr env) { using peglib::operator"" _; @@ -566,6 +577,7 @@ struct Eval case "NUMBER"_: return eval_number(ast, env); case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env); case "DEBUGGER"_: return Value(); + case "RETURN"_: eval_return(ast, env); } if (ast.is_token) { @@ -576,7 +588,6 @@ struct Eval throw std::logic_error("invalid Ast type"); } -private: Value eval_statements(const peglib::Ast& ast, std::shared_ptr env) { if (ast.is_token) { return eval(ast, env); @@ -654,7 +665,11 @@ private: } callEnv->initialize("__LINE__", Value((long)ast.line), false); callEnv->initialize("__COLUMN__", Value((long)ast.column), false); - return f.eval(callEnv); + try { + return f.eval(callEnv); + } catch (const Value& val) { + return val; + } } std::string msg = "arguments error..."; @@ -901,6 +916,14 @@ private: return Value(std::move(s)); }; + void eval_return(const peglib::Ast& ast, std::shared_ptr env) { + if (ast.nodes.empty()) { + throw Value(); + } else { + throw eval(*ast.nodes[0], env); + } + } + Debugger debugger_; }; @@ -924,8 +947,8 @@ inline bool run( }; if (parser.parse_n(expr, len, ast, path.c_str())) { - ast = peglib::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY" }).optimize(ast); - val = Eval(debugger).eval(*ast, env); + ast = peglib::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast); + val = Interpreter(debugger).exec(*ast, env); return true; } } catch (std::runtime_error& e) { diff --git a/language/samples/test.cul b/language/samples/test.cul index d4a9894..eee7314 100644 --- a/language/samples/test.cul +++ b/language/samples/test.cul @@ -1,9 +1,32 @@ +/* + * Unit tests + */ test_call = fn () { ret = fn(){[1,fn(){[4,5,6]},3]}()[1]()[1] assert(ret == 5) } +test_return = fn () { + f = fn (x) { + if (x % 2) { + return 'odd' + } + 'even' + } + assert(f(3) == 'odd') + assert(f(4) == 'even') + + mut val = 0 + f2 = fn () { + val = 1 + return // comment + val = 2 + } + f2() + assert(val == 1) +} + test_undefined = fn () { assert(undefined == undefined) assert(!(undefined != undefined)) @@ -162,13 +185,14 @@ test_fib = fn () { test_interpolated_string = fn () { hello = "Hello" - world = "World!" + world = "World!" ret = "{hello} {world}" assert(ret == 'Hello World!') } debugger test_call() +test_return() test_closure() test_undefined() test_array() @@ -176,6 +200,9 @@ test_function() test_object() test_object_factory() test_class() +debugger test_sum() test_fib() test_interpolated_string() + +return // end \ No newline at end of file