diff --git a/chaiscript/chaiscript.hpp b/chaiscript/chaiscript.hpp index afcb32b..9d88a58 100644 --- a/chaiscript/chaiscript.hpp +++ b/chaiscript/chaiscript.hpp @@ -20,28 +20,17 @@ namespace chaiscript { - /* - class TokenType { public: enum Type { File, Whitespace, Identifier, Integer, Operator, Parens_Open, Parens_Close, - Square_Open, Square_Close, Curly_Open, Curly_Close, Comma, Quoted_String, Single_Quoted_String, Carriage_Return, Semicolon, - Function_Def, Lambda_Def, Scoped_Block, Statement, Equation, Return, Expression, Term, Factor, Negate, Not, Comment, - Value, Fun_Call, Method_Call, Comparison, If_Block, While_Block, Boolean, Real_Number, Array_Call, Variable_Decl, Array_Init, Map_Init, - For_Block, Prefix, Break, Map_Pair}; }; - - const char *tokentype_to_string(int tokentype) { - const char *token_types[] = {"File", "Whitespace", "Identifier", "Integer", "Operator", "Parens_Open", "Parens_Close", - "Square_Open", "Square_Close", "Curly_Open", "Curly_Close", "Comma", "Quoted_String", "Single_Quoted_String", "Carriage_Return", "Semicolon", - "Function_Def", "Lambda_Def", "Scoped_Block", "Statement", "Equation", "Return", "Expression", "Term", "Factor", "Negate", "Not", "Comment", - "Value", "Fun_Call", "Method_Call", "Comparison", "If_Block", "While_Block", "Boolean", "Real Number", "Array_Call", "Variable_Decl", "Array_Init", "Map_Init", - "For_Block", "Prefix", "Break", "Map_Pair"}; - - return token_types[tokentype]; - } - */ + /** + * 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, 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 }; }; + /** + * 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", "Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", @@ -51,10 +40,12 @@ namespace chaiscript return token_types[tokentype]; } + /** + * Convenience type for file positions + */ struct File_Position { int line; int column; - // std::string::iterator text_pos; File_Position(int file_line, int file_column) : line(file_line), column(file_column) { } @@ -64,6 +55,9 @@ namespace chaiscript typedef std::tr1::shared_ptr TokenPtr; + /** + * The struct that doubles as both a parser token and an AST node + */ struct Token { std::string text; int identifier; @@ -85,6 +79,9 @@ namespace chaiscript } }; + /** + * Errors generated inside the parser + */ struct Parse_Error { std::string reason; File_Position position; @@ -101,36 +98,38 @@ namespace chaiscript virtual ~Parse_Error() throw() {} }; - struct ParserError { + /** + * Errors generated inside the evaluator + */ + struct Eval_Error : public std::runtime_error { std::string reason; TokenPtr location; - ParserError(const std::string &why, const TokenPtr where) : reason(why), location(where){ } - }; - - struct EvalError : public std::runtime_error { - std::string reason; - TokenPtr location; - - EvalError(const std::string &why, const TokenPtr where) + Eval_Error(const std::string &why, const TokenPtr where) : std::runtime_error("Eval error: \"" + why + "\" in '" + where->filename + "' line: " + boost::lexical_cast(where->start.line+1)), reason(why), location(where) { } - virtual ~EvalError() throw() {} + virtual ~Eval_Error() throw() {} }; - struct ReturnValue { + /** + * Special type for returned values + */ + struct Return_Value { dispatchkit::Boxed_Value retval; TokenPtr location; - ReturnValue(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { } + Return_Value(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { } }; - struct BreakLoop { + /** + * Special type indicating a call to 'break' + */ + struct Break_Loop { TokenPtr location; - BreakLoop(const TokenPtr where) : location(where) { } + Break_Loop(const TokenPtr where) : location(where) { } }; } diff --git a/chaiscript/chaiscript_engine.hpp b/chaiscript/chaiscript_engine.hpp index 7772d00..fd8e881 100644 --- a/chaiscript/chaiscript_engine.hpp +++ b/chaiscript/chaiscript_engine.hpp @@ -48,11 +48,11 @@ namespace chaiscript try { val = dispatchkit::boxed_cast(vals[0]); } - catch (EvalError &ee) { - throw EvalError("Can not evaluate string: " + val + " reason: " + ee.reason, TokenPtr()); + catch (Eval_Error &ee) { + throw Eval_Error("Can not evaluate string: " + val + " reason: " + ee.reason, TokenPtr()); } catch (std::exception &e) { - throw EvalError("Can not evaluate string: " + val, TokenPtr()); + throw Eval_Error("Can not evaluate string: " + val, TokenPtr()); } return evaluate_string(val); } @@ -109,13 +109,13 @@ namespace chaiscript value = eval_token(engine, parser.ast()); } } - catch (const ReturnValue &rv) { + catch (const Return_Value &rv) { value = rv.retval; } catch (Parse_Error &pe) { std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl; } - catch (EvalError &ee) { + catch (Eval_Error &ee) { if (filename != std::string("__EVAL__")) { std::cout << "Eval error: \"" << ee.reason << "\" in '" << ee.location->filename << "' line: " << ee.location->start.line << std::endl; } diff --git a/chaiscript/chaiscript_eval.hpp b/chaiscript/chaiscript_eval.hpp index 4d2ad9a..bb1b4b4 100644 --- a/chaiscript/chaiscript_eval.hpp +++ b/chaiscript/chaiscript_eval.hpp @@ -8,6 +8,9 @@ namespace chaiscript { + /** + * Helper function that will set up the scope around a function call, including handling the named function parameters + */ template const dispatchkit::Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector ¶m_names, const std::vector &vals) { ss.new_scope(); @@ -21,7 +24,7 @@ namespace chaiscript try { retval = eval_token(ss, node); ss.pop_scope(); - } catch (const ReturnValue &rv) { + } catch (const Return_Value &rv) { retval = rv.retval; ss.pop_scope(); } catch (...) { @@ -29,10 +32,12 @@ namespace chaiscript throw; } - return retval; } + /** + * Evaluates the top-level file node + */ template dispatchkit::Boxed_Value eval_file(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -43,6 +48,9 @@ namespace chaiscript return retval; } + /** + * Evaluates a variable or function name identifier + */ template dispatchkit::Boxed_Value eval_id(Eval_System &ss, TokenPtr node) { @@ -57,31 +65,46 @@ namespace chaiscript return ss.get_object(node->text); } catch (std::exception &e) { - throw EvalError("Can not find object: " + node->text, node); + throw Eval_Error("Can not find object: " + node->text, node); } } } + /** + * Evaluates a floating point number + */ template dispatchkit::Boxed_Value eval_float(Eval_System &ss, TokenPtr node) { return dispatchkit::Boxed_Value(double(atof(node->text.c_str()))); } + /** + * Evaluates an integer + */ template dispatchkit::Boxed_Value eval_int(Eval_System &ss, TokenPtr node) { return dispatchkit::Boxed_Value(atoi(node->text.c_str())); } + /** + * Evaluates a quoted string + */ template dispatchkit::Boxed_Value eval_quoted_string(Eval_System &ss, TokenPtr node) { return dispatchkit::Boxed_Value(node->text); } + /** + * Evaluates a char group + */ template dispatchkit::Boxed_Value eval_single_quoted_string(Eval_System &ss, TokenPtr node) { return dispatchkit::Boxed_Value(node->text); } + /** + * Evaluates a string of equations in reverse order so that the right-most side has precedence + */ template dispatchkit::Boxed_Value eval_equation(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -103,11 +126,11 @@ namespace chaiscript retval = dispatch(ss.get_function(node->children[i+1]->text), plb); } catch(const dispatchkit::dispatch_error &e){ - throw EvalError("Mismatched types in equation", node->children[i+1]); + throw Eval_Error("Mismatched types in equation", node->children[i+1]); } } catch(const dispatchkit::dispatch_error &e){ - throw EvalError("Can not clone right hand side of equation", node->children[i+1]); + throw Eval_Error("Can not clone right hand side of equation", node->children[i+1]); } } else if (node->children[i+1]->text == ":=") { @@ -116,7 +139,7 @@ namespace chaiscript lhs.assign(retval); } else { - throw EvalError("Mismatched types in equation", node->children[i+1]); + throw Eval_Error("Mismatched types in equation", node->children[i+1]); } } else { @@ -127,7 +150,7 @@ namespace chaiscript retval = dispatch(ss.get_function(node->children[i+1]->text), plb); } catch(const dispatchkit::dispatch_error &e){ - throw EvalError("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]); + throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]); } } } @@ -135,12 +158,18 @@ namespace chaiscript return retval; } + /** + * Evaluates a variable declaration + */ template dispatchkit::Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) { ss.add_object(node->children[0]->text, dispatchkit::Boxed_Value()); return ss.get_object(node->children[0]->text); } + /** + * Evaluates binary boolean operators. Respects short-circuiting rules. + */ template dispatchkit::Boxed_Value eval_expression(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -154,7 +183,7 @@ namespace chaiscript lhs = dispatchkit::boxed_cast(retval); } catch (std::exception &e) { - throw EvalError("Condition not boolean", node); + throw Eval_Error("Condition not boolean", node); } if (node->children[i]->text == "&&") { if (lhs) { @@ -177,6 +206,9 @@ namespace chaiscript return retval; } + /** + * Evaluates comparison, additions, and multiplications and their relatives + */ template dispatchkit::Boxed_Value eval_comp_add_mul(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -193,7 +225,7 @@ namespace chaiscript retval = dispatch(ss.get_function(node->children[i]->text), plb); } catch(const dispatchkit::dispatch_error &e){ - throw EvalError("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]); + throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]); } } } @@ -201,6 +233,9 @@ namespace chaiscript return retval; } + /** + * Evaluates an array lookup + */ template dispatchkit::Boxed_Value eval_array_call(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -215,16 +250,19 @@ namespace chaiscript retval = dispatch(ss.get_function("[]"), plb); } catch(std::out_of_range &oor) { - throw EvalError("Out of bounds exception", node); + throw Eval_Error("Out of bounds exception", node); } catch(const dispatchkit::dispatch_error &e){ - throw EvalError("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]); + throw Eval_Error("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]); } } return retval; } + /** + * Evaluates a unary negation + */ template dispatchkit::Boxed_Value eval_negate(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -232,16 +270,19 @@ namespace chaiscript retval = eval_token(ss, node->children[0]); dispatchkit::Param_List_Builder plb; plb << retval; - plb << dispatchkit::Boxed_Value(-1); + plb << dispatchkit::Boxed_Value(-1.0); try { return dispatch(ss.get_function("*"), plb); } catch(std::exception &e){ - throw EvalError("Can not find appropriate negation", node->children[0]); + throw Eval_Error("Can not find appropriate negation", node->children[0]); } } + /** + * Evaluates a unary boolean not + */ template dispatchkit::Boxed_Value eval_not(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -252,11 +293,14 @@ namespace chaiscript cond = dispatchkit::boxed_cast(retval); } catch (std::exception) { - throw EvalError("Boolean not('!') condition not boolean", node->children[0]); + throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]); } return dispatchkit::Boxed_Value(!cond); } + /** + * Evaluates any unary prefix + */ template dispatchkit::Boxed_Value eval_prefix(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -269,10 +313,13 @@ namespace chaiscript return dispatch(ss.get_function(node->children[0]->text), plb); } catch(std::exception &e){ - throw EvalError("Can not find appropriate prefix", node->children[0]); + throw Eval_Error("Can not find appropriate prefix", node->children[0]); } } + /** + * Evaluates (and generates) an inline array initialization + */ template dispatchkit::Boxed_Value eval_inline_array(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -287,18 +334,21 @@ namespace chaiscript dispatch(ss.get_function("push_back"), dispatchkit::Param_List_Builder() << retval << tmp); } catch (const dispatchkit::dispatch_error &inner_e) { - throw EvalError("Can not find appropriate 'push_back'", node->children[0]->children[i]); + throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]); } } } } catch (const dispatchkit::dispatch_error &e) { - throw EvalError("Can not find appropriate 'Vector()'", node); + throw Eval_Error("Can not find appropriate 'Vector()'", node); } return retval; } + /** + * Evaluates (and generates) an inline range initialization + */ template dispatchkit::Boxed_Value eval_inline_range(Eval_System &ss, TokenPtr node) { try { @@ -307,10 +357,13 @@ namespace chaiscript << eval_token(ss, node->children[0]->children[0]->children[1])); } catch (const dispatchkit::dispatch_error &e) { - throw EvalError("Unable to generate range vector", node); + throw Eval_Error("Unable to generate range vector", node); } } + /** + * Evaluates (and generates) an inline map initialization + */ template dispatchkit::Boxed_Value eval_inline_map(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -325,17 +378,20 @@ namespace chaiscript dispatch(ss.get_function("="), dispatchkit::Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1])); } catch (const dispatchkit::dispatch_error &inner_e) { - throw EvalError("Can not find appropriate '=' for map init", node->children[0]->children[i]); + throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]); } } } catch (const dispatchkit::dispatch_error &e) { - throw EvalError("Can not find appropriate 'Map()'", node); + throw Eval_Error("Can not find appropriate 'Map()'", node); } return retval; } + /** + * Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call. + */ template dispatchkit::Boxed_Value eval_fun_call(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -355,9 +411,9 @@ namespace chaiscript try { fn = eval_token(ss, node->children[0]); } - catch(EvalError &ee) { + catch(Eval_Error &ee) { ss.set_stack(prev_stack); - throw EvalError(ee.reason, node->children[0]); + throw Eval_Error(ee.reason, node->children[0]); } try { ss.set_stack(new_stack); @@ -366,9 +422,9 @@ namespace chaiscript } catch(const dispatchkit::dispatch_error &e){ ss.set_stack(prev_stack); - throw EvalError("Engine error: " + std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); + throw Eval_Error("Engine error: " + std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); } - catch(ReturnValue &rv) { + catch(Return_Value &rv) { ss.set_stack(prev_stack); retval = rv.retval; } @@ -380,6 +436,9 @@ namespace chaiscript return retval; } + /** + * Evaluates a method/attributes invocation + */ template dispatchkit::Boxed_Value eval_dot_access(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -420,9 +479,9 @@ namespace chaiscript } catch(const dispatchkit::dispatch_error &e){ ss.set_stack(prev_stack); - throw EvalError("Can not find appropriate '" + fun_name + "'", node); + throw Eval_Error("Can not find appropriate '" + fun_name + "'", node); } - catch(ReturnValue &rv) { + catch(Return_Value &rv) { ss.set_stack(prev_stack); retval = rv.retval; } @@ -436,6 +495,9 @@ namespace chaiscript return retval; } + /** + * Evaluates an if/elseif/else block + */ template dispatchkit::Boxed_Value eval_if(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -447,7 +509,7 @@ namespace chaiscript cond = dispatchkit::boxed_cast(retval); } catch (std::exception &e) { - throw EvalError("If condition not boolean", node->children[0]); + throw Eval_Error("If condition not boolean", node->children[0]); } if (cond) { retval = eval_token(ss, node->children[1]); @@ -466,7 +528,7 @@ namespace chaiscript cond = dispatchkit::boxed_cast(retval); } catch (std::exception &e) { - throw EvalError("Elseif condition not boolean", node->children[i+1]); + throw Eval_Error("Elseif condition not boolean", node->children[i+1]); } if (cond) { retval = eval_token(ss, node->children[i+2]); @@ -480,6 +542,9 @@ namespace chaiscript return retval; } + /** + * Evaluates a while block + */ template dispatchkit::Boxed_Value eval_while(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -490,7 +555,7 @@ namespace chaiscript cond = dispatchkit::boxed_cast(retval); } catch (std::exception) { - throw EvalError("While condition not boolean", node->children[0]); + throw Eval_Error("While condition not boolean", node->children[0]); } while (cond) { try { @@ -500,16 +565,19 @@ namespace chaiscript cond = dispatchkit::boxed_cast(retval); } catch (std::exception) { - throw EvalError("While condition not boolean", node->children[0]); + throw Eval_Error("While condition not boolean", node->children[0]); } } - catch (BreakLoop &bl) { + catch (Break_Loop &bl) { cond = false; } } return dispatchkit::Boxed_Value(); } + /** + * Evaluates a for block, including the for's conditions, from left to right + */ template dispatchkit::Boxed_Value eval_for(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -528,7 +596,7 @@ namespace chaiscript cond = dispatchkit::boxed_cast(condition); } catch (std::exception &e) { - throw EvalError("For condition not boolean", node); + throw Eval_Error("For condition not boolean", node); } while (cond) { try { @@ -546,15 +614,18 @@ namespace chaiscript } catch (std::exception &e) { - throw EvalError("For condition not boolean", node); + throw Eval_Error("For condition not boolean", node); } - catch (BreakLoop &bl) { + catch (Break_Loop &bl) { cond = false; } } return dispatchkit::Boxed_Value(); } + /** + * Evaluates a function definition + */ template dispatchkit::Boxed_Value eval_def(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -602,6 +673,9 @@ namespace chaiscript return retval; } + /** + * Evaluates a lambda (anonymous function) + */ template dispatchkit::Boxed_Value eval_lambda(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -627,6 +701,9 @@ namespace chaiscript boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), numparams))); } + /** + * Evaluates a scoped block. Handles resetting the scope after the block has completed. + */ template dispatchkit::Boxed_Value eval_block(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -637,7 +714,7 @@ namespace chaiscript try { retval = eval_token(ss, node->children[i]); } - catch (const chaiscript::ReturnValue &rv) { + catch (const chaiscript::Return_Value &rv) { ss.pop_scope(); retval = rv.retval; throw; @@ -652,6 +729,9 @@ namespace chaiscript return retval; } + /** + * Evaluates a return statement + */ template dispatchkit::Boxed_Value eval_return(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; @@ -661,14 +741,20 @@ namespace chaiscript else { retval = dispatchkit::Boxed_Value(); } - throw ReturnValue(retval, node); + throw Return_Value(retval, node); } + /** + * Evaluates a break statement + */ template dispatchkit::Boxed_Value eval_break(Eval_System &ss, TokenPtr node) { - throw BreakLoop(node); + throw Break_Loop(node); } + /** + * Top-level evaluation dispatch for all AST node types + */ template dispatchkit::Boxed_Value eval_token(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; diff --git a/chaiscript/chaiscript_parser.hpp b/chaiscript/chaiscript_parser.hpp index 5a79839..8dee612 100644 --- a/chaiscript/chaiscript_parser.hpp +++ b/chaiscript/chaiscript_parser.hpp @@ -27,6 +27,9 @@ namespace chaiscript singleline_comment = "//"; } + /** + * Prints the parsed tokens as a tree + */ void debug_print(TokenPtr t, std::string prepend = "") { std::cout << prepend << "(" << token_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; for (unsigned int j = 0; j < t->children.size(); ++j) { @@ -34,20 +37,32 @@ namespace chaiscript } } + /** + * Shows the current stack of matched tokens + */ void show_match_stack() { for (unsigned int i = 0; i < match_stack.size(); ++i) { debug_print(match_stack[i]); } } + /** + * Clears the stack of matched tokens + */ void clear_match_stack() { match_stack.clear(); } + /** + * Returns the front-most AST node + */ TokenPtr ast() { return match_stack.front(); } + /** + * Helper function that collects tokens from a starting position to the top of the stack into a new AST node + */ void build_match(Token_Type::Type match_type, int match_start) { //so we want to take everything to the right of this and make them children if (match_start != (int)match_stack.size()) { @@ -63,6 +78,9 @@ namespace chaiscript } } + /** + * Skips any multi-line or single-line comment + */ bool SkipComment() { bool retval = false; @@ -93,6 +111,9 @@ namespace chaiscript return retval; } + /** + * Skips ChaiScript whitespace, which means space and tab, but not cr/lf + */ bool SkipWS() { bool retval = false; while (input_pos != input_end) { @@ -111,19 +132,9 @@ namespace chaiscript return retval; } - bool Int_() { - bool retval = false; - if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { - retval = true; - while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { - ++input_pos; - ++col; - } - } - - return retval; - } - + /** + * Reads a floating point value from input, without skipping initial whitespace + */ bool Float_() { bool retval = false; if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { @@ -151,6 +162,9 @@ namespace chaiscript return retval; } + /** + * Reads a number from the input, detecting if it's an integer or floating point + */ bool Num(bool capture = false) { SkipWS(); @@ -181,6 +195,9 @@ namespace chaiscript } } + /** + * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace + */ bool Id_() { bool retval = false; if ((input_pos != input_end) && (((*input_pos >= 'A') && (*input_pos <= 'Z')) || (*input_pos == '_') || ((*input_pos >= 'a') && (*input_pos <= 'z')))) { @@ -195,6 +212,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) an identifier from input + */ bool Id(bool capture = false) { SkipWS(); @@ -217,6 +237,9 @@ namespace chaiscript } } + /** + * Checks for a node annotation of the form "#" + */ bool Annotation() { SkipWS(); std::string::iterator start = input_pos; @@ -245,6 +268,9 @@ namespace chaiscript } } + /** + * Reads a quoted string from input, without skipping initial whitespace + */ bool Quoted_String_() { bool retval = false; char prev_char = 0; @@ -278,6 +304,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. + */ bool Quoted_String(bool capture = false) { SkipWS(); @@ -330,6 +359,9 @@ namespace chaiscript } } + /** + * Reads a character group from input, without skipping initial whitespace + */ bool Single_Quoted_String_() { bool retval = false; char prev_char = 0; @@ -363,6 +395,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) a char group from input. Translates escaped sequences. + */ bool Single_Quoted_String(bool capture = false) { SkipWS(); @@ -415,7 +450,9 @@ namespace chaiscript } } - + /** + * Reads a char from input if it matches the parameter, without skipping initial whitespace + */ bool Char_(char c) { bool retval = false; if ((input_pos != input_end) && (*input_pos == c)) { @@ -427,6 +464,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) a char from input if it matches the parameter + */ bool Char(char c, bool capture = false) { SkipWS(); @@ -449,6 +489,9 @@ namespace chaiscript } } + /** + * Reads a string from input if it matches the parameter, without skipping initial whitespace + */ bool Keyword_(const char *s) { bool retval = false; int len = strlen(s); @@ -469,6 +512,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) a string from input if it matches the parameter + */ bool Keyword(const char *s, bool capture = false) { SkipWS(); @@ -516,6 +562,9 @@ namespace chaiscript } } + /** + * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + */ bool Symbol_(const char *s) { bool retval = false; int len = strlen(s); @@ -536,6 +585,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) a symbol group from input if it matches the parameter + */ bool Symbol(const char *s, bool capture = false) { SkipWS(); @@ -583,6 +635,9 @@ namespace chaiscript } } + /** + * Reads an end-of-line group from input, without skipping initial whitespace + */ bool Eol_() { bool retval = false; @@ -598,6 +653,9 @@ namespace chaiscript return retval; } + /** + * Reads (and potentially captures) an end-of-line group from input + */ bool Eol(bool capture = false) { SkipWS(); @@ -620,6 +678,9 @@ namespace chaiscript } } + /** + * Reads a comma-separated list of values from input + */ bool Arg_List() { bool retval = false; @@ -638,9 +699,11 @@ namespace chaiscript } return retval; - } + /** + * Reads possible special container values, including ranges and map_pairs + */ bool Container_Arg_List() { bool retval = false; @@ -666,6 +729,9 @@ namespace chaiscript } + /** + * Reads a lambda (anonymous function) from input + */ bool Lambda() { bool retval = false; @@ -693,6 +759,9 @@ namespace chaiscript return retval; } + /** + * Reads a function definition from input + */ bool Def() { bool retval = false; bool is_annotated = false; @@ -745,6 +814,9 @@ namespace chaiscript return retval; } + /** + * Reads an if/elseif/else block from input + */ bool If() { bool retval = false; @@ -803,6 +875,9 @@ namespace chaiscript return retval; } + /** + * Reads a while block from input + */ bool While() { bool retval = false; @@ -831,6 +906,9 @@ namespace chaiscript return retval; } + /** + * Reads the C-style for conditions from input + */ bool For_Guards() { Equation(); @@ -841,6 +919,10 @@ namespace chaiscript throw Parse_Error("Incomplete conditions in 'for' loop", File_Position(line, col), filename); } } + + /** + * Reads a for block from input + */ bool For() { bool retval = false; @@ -869,6 +951,9 @@ namespace chaiscript return retval; } + /** + * Reads a curly-brace C-style block from input + */ bool Block() { bool retval = false; @@ -886,9 +971,11 @@ namespace chaiscript } return retval; - } + /** + * Reads a return statement from input + */ bool Return() { bool retval = false; @@ -904,6 +991,9 @@ namespace chaiscript return retval; } + /** + * Reads a break statement from input + */ bool Break() { bool retval = false; @@ -918,6 +1008,9 @@ namespace chaiscript return retval; } + /** + * Reads an identifier, then proceeds to check if it's a function or array call + */ bool Id_Fun_Array() { bool retval = false; std::string::iterator prev_pos = input_pos; @@ -955,6 +1048,9 @@ namespace chaiscript return retval; } + /** + * Reads a variable declaration from input + */ bool Var_Decl() { bool retval = false; @@ -971,9 +1067,11 @@ namespace chaiscript } return retval; - } + /** + * Reads an expression surrounded by parentheses from input + */ bool Paren_Expression() { bool retval = false; @@ -989,6 +1087,9 @@ namespace chaiscript return retval; } + /** + * Reads, and identifies, a short-form container initialization from input + */ bool Inline_Container() { bool retval = false; @@ -1019,6 +1120,9 @@ namespace chaiscript return retval; } + /** + * Reads an identifier literal of the special form `` from input + */ bool Id_Literal() { bool retval = false; @@ -1063,16 +1167,9 @@ namespace chaiscript return retval; } - bool Value() { - if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container()) { - return true; - } - else { - return false; - } - } - + /** + * Reads a unary prefixed expression from input + */ bool Prefix() { bool retval = false; @@ -1116,9 +1213,24 @@ namespace chaiscript } return retval; - } + /** + * Parses any of a group of 'value' style token groups from input + */ + bool Value() { + if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container()) { + return true; + } + else { + return false; + } + } + + /** + * Reads a string of binary comparisons from input + */ bool Comparison() { bool retval = false; @@ -1138,9 +1250,11 @@ namespace chaiscript } return retval; - } + /** + * Reads a string of binary additions/subtractions from input + */ bool Additive() { bool retval = false; @@ -1162,6 +1276,9 @@ namespace chaiscript return retval; } + /** + * Reads a string of multiplication/division/modulus from input + */ bool Multiplicative() { bool retval = false; @@ -1181,9 +1298,11 @@ namespace chaiscript } return retval; - } + /** + * Reads a string of dot-notation accesses from input + */ bool Dot_Access() { bool retval = false; @@ -1205,6 +1324,9 @@ namespace chaiscript return retval; } + /** + * Top-level expression, parses a string of binary boolean operators from input + */ bool Expression() { bool retval = false; @@ -1226,6 +1348,9 @@ namespace chaiscript return retval; } + /** + * Reads a pair of values used to create a map initialization from input + */ bool Map_Pair() { bool retval = false; @@ -1247,6 +1372,9 @@ namespace chaiscript return retval; } + /** + * Reads a pair of values used to create a range initialization from input + */ bool Value_Range() { bool retval = false; @@ -1274,6 +1402,10 @@ namespace chaiscript return retval; } + + /** + * Parses a string of binary equation operators + */ bool Equation() { bool retval = false; @@ -1291,18 +1423,11 @@ namespace chaiscript } return retval; - - } - - bool Statement() { - if (Return() || Break() || Equation()) { - return true; - } - else { - return false; - } } + /** + * Top level parser, starts parsing of all known parses + */ bool Statements() { bool retval = false; @@ -1343,7 +1468,23 @@ namespace chaiscript retval = true; saw_eol = true; } - else if (Statement()) { + else if (Return()) { + if (!saw_eol) { + throw Parse_Error("Two expressions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Break()) { + if (!saw_eol) { + throw Parse_Error("Two expressions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Equation()) { if (!saw_eol) { throw Parse_Error("Two expressions missing line separator", match_stack.back()); } @@ -1364,6 +1505,9 @@ namespace chaiscript return retval; } + /** + * Parses the given input string, tagging parsed tokens with the given filename. + */ bool parse(std::string input, const char *fname) { input_pos = input.begin(); input_end = input.end();