From 50927138765ad31a8c2b96e24a9344a14b8b73b1 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 12 Sep 2009 14:52:46 +0000 Subject: [PATCH] Add in-string eval --- include/chaiscript/chaiscript.hpp | 4 +- .../chaiscript/language/chaiscript_eval.hpp | 50 ++++++ .../chaiscript/language/chaiscript_parser.hpp | 145 +++++++++++++++--- 3 files changed, 172 insertions(+), 27 deletions(-) diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 5c3d838..c5a6ba0 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -28,7 +28,7 @@ namespace chaiscript /** * Types of AST nodes available to the parser and eval */ - class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl, + class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, Expression, Comparison, Additive, Multiplicative, Negate, Not, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range, Inline_Range, Annotation }; }; @@ -37,7 +37,7 @@ namespace chaiscript * Helper lookup to get the name of each node type */ const char *token_type_to_string(int tokentype) { - const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", + const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", "Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range", "Inline_Range", "Annotation"}; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index a48ed4a..bde105b 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -116,6 +116,15 @@ namespace chaiscript Boxed_Value eval_quoted_string(Eval_System &ss, const TokenPtr &node) { //return const_var(node->text); + /* + if ((node->text.size() > 0) && (node->text[0] == '$')) { + node->text.erase(0, 1); + Param_List_Builder plb; + plb << node->text; + + return ss.call_function("eval", plb); + } + */ if (!node->is_cached) { cache_const(ss, node, const_var(node->text)); } @@ -468,6 +477,43 @@ namespace chaiscript } + /** + * Evaluates a function call, starting with its arguments. Does NOT change scope. + */ + template + Boxed_Value eval_inplace_fun_call(Eval_System &ss, const TokenPtr &node) { + Param_List_Builder plb; + unsigned int i; + + if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < node->children[1]->children.size(); ++i) { + plb << eval_token(ss, node->children[1]->children[i]); + } + } + + try { + Boxed_Value fn = eval_token(ss, node->children[0]); + + try { + Boxed_Value retval = (*boxed_cast(fn))(plb); + return retval; + } + catch(const dispatch_error &e){ + throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); + } + catch(Return_Value &rv) { + return rv.retval; + } + catch(...) { + throw; + } + } + catch(Eval_Error &ee) { + throw Eval_Error(ee.reason, node->children[0]); + } + + } + /** * Evaluates a method/attributes invocation */ @@ -870,6 +916,10 @@ namespace chaiscript return eval_fun_call(ss, node); break; + case (Token_Type::Inplace_Fun_Call) : + return eval_inplace_fun_call(ss, node); + break; + case (Token_Type::Dot_Access) : return eval_dot_access(ss, node); break; diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 40b881b..4528a41 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -323,37 +323,132 @@ namespace chaiscript if (Quoted_String_()) { std::string match; bool is_escaped = false; - for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); + bool is_interpolated = false; + bool saw_interpolation_marker = false; + int prev_stack_top = match_stack.size(); + + //for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) { + std::string::iterator s = start + 1, end = input_pos - 1; + + while (s != end) { + if (saw_interpolation_marker) { + if (*s == '{') { + //We've found an interpolation point + + if (is_interpolated) { + //If we've seen previous interpolation, add on instead of making a new one + TokenPtr plus(new Token("+", Token_Type::Str, filename, -1, -1, -1, -1)); + match_stack.push_back(plus); + + TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + + build_match(Token_Type::Additive, prev_stack_top); + } + else { + TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + } + + //We've finished with the part of the string up to this point, so clear it + match = ""; + + TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); + match_stack.push_back(plus); + + std::string eval_match; + + ++s; + while ((*s != '}') && (s != end)) { + eval_match.push_back(*s); + ++s; + } + if (*s == '}') { + is_interpolated = true; + ++s; + + int tostr_stack_top = match_stack.size(); + + TokenPtr tostr(new Token("to_string", Token_Type::Id, filename, prev_line, prev_col, line, col)); + match_stack.push_back(tostr); + + int ev_stack_top = match_stack.size(); + + TokenPtr ev(new Token("eval", Token_Type::Id, filename, prev_line, prev_col, line, col)); + match_stack.push_back(ev); + + int arg_stack_top = match_stack.size(); + + TokenPtr t(new Token(eval_match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + + build_match(Token_Type::Arg_List, arg_stack_top); + + build_match(Token_Type::Inplace_Fun_Call, ev_stack_top); + + build_match(Token_Type::Arg_List, ev_stack_top); + + build_match(Token_Type::Fun_Call, tostr_stack_top); + + build_match(Token_Type::Additive, prev_stack_top); + } + else { + throw Eval_Error("Unclosed in-string eval", File_Position(prev_line, prev_col), filename); } } else { - match.push_back(*s); + match.push_back('$'); } - is_escaped = false; + saw_interpolation_marker = false; + } + else { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } + else { + is_escaped = true; + } + } + else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + case ('$') : match.push_back('$'); break; + default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); + } + } + else if (*s == '$') { + saw_interpolation_marker = true; + } + else { + match.push_back(*s); + } + is_escaped = false; + } + ++s; } } - TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); - match_stack.push_back(t); + if (is_interpolated) { + TokenPtr plus(new Token("+", Token_Type::Str, filename, -1, -1, -1, -1)); + match_stack.push_back(plus); + + TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + + build_match(Token_Type::Additive, prev_stack_top); + } + else { + TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + } return true; } else {