diff --git a/chaiscript/chaiscript.hpp b/chaiscript/chaiscript.hpp index f76b15f..a3de3b0 100644 --- a/chaiscript/chaiscript.hpp +++ b/chaiscript/chaiscript.hpp @@ -8,13 +8,19 @@ #include #include +#include +#include #include #include #include +#include "dispatchkit.hpp" +#include "bootstrap.hpp" +#include "bootstrap_stl.hpp" + 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, @@ -30,15 +36,101 @@ namespace chaiscript return token_types[tokentype]; } + */ + 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 }; }; + + 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", + "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File" }; + + return token_types[tokentype]; + } + + 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) { } + + File_Position() : line(0), column(0) { } + }; + + typedef std::tr1::shared_ptr TokenPtr; + + struct Token { + std::string text; + int identifier; + const char *filename; + File_Position start, end; + + std::vector children; + + Token(const std::string &token_text, int id, const char *fname) : text(token_text), identifier(id), filename(fname) { } + + Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + text(token_text), identifier(id), filename(fname) { + + start.line = start_line; + start.column = start_col; + end.line = end_line; + end.column = end_col; + } + }; + + struct Parse_Error { + std::string reason; + File_Position position; + const char *filename; + + Parse_Error(const std::string &why, const File_Position &where, const char *fname) : + reason(why), position(where), filename(fname) { } + + Parse_Error(const std::string &why, const TokenPtr &where) : reason(why) { + filename = where->filename; + position = where->start; + } + + virtual ~Parse_Error() throw() {} + }; + + struct ParserError { + 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) + : std::runtime_error("Eval error: \"" + why + "\" in '" + + where->filename + "' line: " + boost::lexical_cast(where->start.line+1)), + reason(why), location(where) { } + + virtual ~EvalError() throw() {} + }; + + struct ReturnValue { + dispatchkit::Boxed_Value retval; + TokenPtr location; + + ReturnValue(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { } + }; + + struct BreakLoop { + TokenPtr location; + + BreakLoop(const TokenPtr where) : location(where) { } + }; } -#include "dispatchkit.hpp" -#include "bootstrap.hpp" -#include "bootstrap_stl.hpp" - -#include "langkit_lexer.hpp" -#include "langkit_parser.hpp" - #include "chaiscript_eval.hpp" #include "chaiscript_engine.hpp" diff --git a/chaiscript/chaiscript_engine.hpp b/chaiscript/chaiscript_engine.hpp index 4b0bc3a..d363254 100644 --- a/chaiscript/chaiscript_engine.hpp +++ b/chaiscript/chaiscript_engine.hpp @@ -5,6 +5,8 @@ #define CHAISCRIPT_ENGINE_HPP_ #include +#include + #include "chaiscript_prelude.hpp" @@ -12,12 +14,17 @@ namespace chaiscript { template class ChaiScript_System { - langkit::Lexer lexer; - langkit::Rule parser; Eval_Engine engine; + std::string::iterator input_pos, input_end; + int line, col; + std::string multiline_comment_begin, multiline_comment_end; + std::string singleline_comment; + const char *filename; + std::vector match_stack; + public: - ChaiScript_System() : lexer(build_lexer()), parser(build_parser_rules()), engine(build_eval_system(lexer, parser)) { + ChaiScript_System() { } @@ -25,6 +32,13 @@ namespace chaiscript return engine; } + 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) { + debug_print(t->children[j], prepend + " "); + } + } + const dispatchkit::Boxed_Value eval(const std::vector &vals) { std::string val; @@ -32,10 +46,10 @@ namespace chaiscript val = dispatchkit::boxed_cast(vals[0]); } catch (EvalError &ee) { - throw EvalError("Can not evaluate string: " + val + " reason: " + ee.reason, langkit::TokenPtr()); + throw EvalError("Can not evaluate string: " + val + " reason: " + ee.reason, TokenPtr()); } catch (std::exception &e) { - throw EvalError("Can not evaluate string: " + val, langkit::TokenPtr()); + throw EvalError("Can not evaluate string: " + val, TokenPtr()); } return evaluate_string(val); } @@ -59,208 +73,40 @@ namespace chaiscript return ret_val; } - void debug_print(langkit::TokenPtr token, std::string prepend) { - using namespace langkit; - std::cout << prepend << "Token: " << token->text << "(" << tokentype_to_string(token->identifier) << ") @ " << token->filename - << ": (" << token->start.line << ", " << token->start.column << ") to (" - << token->end.line << ", " << token->end.column << ") " << std::endl; + void build_eval_system() { + multiline_comment_begin = "/*"; + multiline_comment_end = "*/"; + singleline_comment = "//"; - for (unsigned int i = 0; i < token->children.size(); ++i) { - debug_print(token->children[i], prepend + " "); - } - } + dispatchkit::Bootstrap::bootstrap(engine); + dispatchkit::bootstrap_vector >(engine, "Vector"); + dispatchkit::bootstrap_map >(engine, "Map"); + dispatchkit::bootstrap_pair >(engine, "Pair"); - void debug_print(std::vector &tokens) { - using namespace langkit; - for (unsigned int i = 0; i < tokens.size(); ++i) { - debug_print(tokens[i], ""); - } - } - - langkit::Lexer build_lexer() { - using namespace langkit; - Lexer lexer; - lexer.set_skip(Pattern("[ \\t]+", TokenType::Whitespace)); - lexer.set_line_sep(Pattern("\\n|\\r\\n", TokenType::Carriage_Return)); - lexer.set_command_sep(Pattern(";|\\r\\n|\\n", TokenType::Semicolon)); - lexer.set_multiline_comment(Pattern("/\\*", TokenType::Comment), Pattern("\\*/", TokenType::Comment)); - lexer.set_singleline_comment(Pattern("//", TokenType::Comment)); - - lexer << Pattern("[A-Za-z_][A-Za-z_0-9]*", TokenType::Identifier); - lexer << Pattern("[0-9]+\\.[0-9]+", TokenType::Real_Number); - lexer << Pattern("[0-9]+", TokenType::Integer); - lexer << Pattern("[!@#$%^&*|\\-+=<>.:]+|/[!@#$%^&|\\-+=<>]*", TokenType::Operator); - lexer << Pattern("\\(", TokenType::Parens_Open); - lexer << Pattern("\\)", TokenType::Parens_Close); - lexer << Pattern("\\[", TokenType::Square_Open); - lexer << Pattern("\\]", TokenType::Square_Close); - lexer << Pattern("\\{", TokenType::Curly_Open); - lexer << Pattern("\\}", TokenType::Curly_Close); - lexer << Pattern(",", TokenType::Comma); - lexer << Pattern("\"(?:[^\"\\\\]|\\\\.)*\"", TokenType::Quoted_String); - lexer << Pattern("'(?:[^'\\\\]|\\\\.)*'", TokenType::Single_Quoted_String); - - return lexer; - } - - langkit::Rule build_parser_rules() { - using namespace langkit; - Rule params; - Rule block(TokenType::Scoped_Block); - Rule fundef(TokenType::Function_Def); - Rule lambda_def(TokenType::Lambda_Def); - Rule statement; - Rule equation(TokenType::Equation); - Rule boolean(TokenType::Boolean); - Rule comparison(TokenType::Comparison); - Rule expression(TokenType::Expression); - Rule term(TokenType::Term); - Rule factor(TokenType::Factor); - Rule negate(TokenType::Negate); - Rule boolean_not(TokenType::Not); - Rule prefix(TokenType::Prefix); - - Rule funcall(TokenType::Fun_Call); - Rule methodcall(TokenType::Method_Call); - Rule if_block(TokenType::If_Block); - Rule while_block(TokenType::While_Block); - Rule for_block(TokenType::For_Block); - Rule arraycall(TokenType::Array_Call); - Rule vardecl(TokenType::Variable_Decl); - Rule arrayinit(TokenType::Array_Init); - Rule mapinit(TokenType::Map_Init); - Rule mappair(TokenType::Map_Pair); - - Rule return_statement(TokenType::Return); - Rule break_statement(TokenType::Break); - - Rule value; - Rule statements; - Rule for_conditions; - Rule source_elem; - Rule source_elems; - Rule statement_list; - Rule paren_block; - - Rule rule = *(Ign(Id(TokenType::Semicolon))) >> source_elems >> *(Ign(Id(TokenType::Semicolon))); - - source_elems = source_elem >> *(+Ign(Id(TokenType::Semicolon)) >> source_elem); - source_elem = fundef | statement; - statement_list = statement >> *(+Ign(Id(TokenType::Semicolon)) >> statement); - statement = if_block | while_block | for_block | equation; - - if_block = Ign(Str("if")) >> boolean >> block >> *(*Ign(Id(TokenType::Semicolon)) >> Str("elseif") >> boolean >> block) >> ~(*Ign(Id(TokenType::Semicolon)) >> Str("else") >> block); - while_block = Ign(Str("while")) >> boolean >> block; - for_block = Ign(Str("for")) >> for_conditions >> block; - for_conditions = Ign(Id(TokenType::Parens_Open)) >> ~equation >> Ign(Str(";")) >> boolean >> Ign(Str(";")) >> equation >> Ign(Id(TokenType::Parens_Close)); - - fundef = Ign(Str("def")) >> Id(TokenType::Identifier) >> ~(Ign(Id(TokenType::Parens_Open)) >> ~params >> Ign(Id(TokenType::Parens_Close))) >> - block; - params = Id(TokenType::Identifier) >> *(Ign(Str(",")) >> Id(TokenType::Identifier)); - block = *(Ign(Id(TokenType::Semicolon))) >> Ign(Id(TokenType::Curly_Open)) >> *(Ign(Id(TokenType::Semicolon))) >> ~statement_list >> *(Ign(Id(TokenType::Semicolon))) >> Ign(Id(TokenType::Curly_Close)); - - equation = *(((vardecl | arraycall | funcall | methodcall | Id(TokenType::Identifier)) >> Str("=")) | - ((vardecl | arraycall | funcall | methodcall | Id(TokenType::Identifier)) >> Str("+=")) | - ((vardecl | arraycall | funcall | methodcall | Id(TokenType::Identifier)) >> Str("-=")) | - ((vardecl | arraycall | funcall | methodcall | Id(TokenType::Identifier)) >> Str("*=")) | - ((vardecl | arraycall | funcall | methodcall | Id(TokenType::Identifier)) >> Str("/="))) >> boolean; - boolean = comparison >> *((Str("&&") >> comparison) | (Str("||") >> comparison)); - comparison = expression >> *((Str("==") >> expression) | (Str("!=") >> expression) | (Str("<") >> expression) | - (Str("<=") >> expression) |(Str(">") >> expression) | (Str(">=") >> expression)); - expression = term >> *((Str("+") >> term) | (Str("-") >> term)); - term = factor >> *((Str("*") >> factor) | (Str("/") >> factor)); - factor = methodcall | arraycall | value | negate | boolean_not | prefix | (Ign(Str("+")) >> value); - value = vardecl | mapinit | arrayinit | block | lambda_def | paren_block | return_statement | break_statement | - funcall | Id(TokenType::Identifier) | Id(TokenType::Real_Number) | Id(TokenType::Integer) | Id(TokenType::Quoted_String) | - Id(TokenType::Single_Quoted_String) ; - - funcall = Id(TokenType::Identifier) >> Ign(Id(TokenType::Parens_Open)) >> ~(boolean >> *(Ign(Str("," )) >> boolean)) >> Ign(Id(TokenType::Parens_Close)); - methodcall = value >> +(Ign(Str(".")) >> (funcall | Id(TokenType::Identifier))); - negate = (Str("-") >> (boolean | arraycall)); - boolean_not = (Str("!") >> (boolean | arraycall)); - prefix = (Str("++") >> (boolean | arraycall)) | (Str("--") >> (boolean | arraycall)); - arraycall = value >> +((Ign(Id(TokenType::Square_Open)) >> boolean >> Ign(Id(TokenType::Square_Close)))); - - arrayinit = Ign(Id(TokenType::Square_Open)) >> ~(boolean >> *(Ign(Str(",")) >> boolean)) >> Ign(Id(TokenType::Square_Close)); - mapinit = Ign(Id(TokenType::Square_Open)) >> mappair >> *(Ign(Str(",")) >> mappair) >> Ign(Id(TokenType::Square_Close)); - mappair = Id(TokenType::Quoted_String) >> Ign(Str(":")) >> boolean; - - vardecl = Ign(Str("var")) >> Id(TokenType::Identifier); - return_statement = Ign(Str("return")) >> ~boolean; - break_statement = Wrap(Ign(Str("break"))); - paren_block = (Ign(Id(TokenType::Parens_Open)) >> equation >> Ign(Id(TokenType::Parens_Close))); - lambda_def = (Ign(Str("function")) >> ~(Ign(Id(TokenType::Parens_Open)) >> ~params >> Ign(Id(TokenType::Parens_Close))) >> block) | - (Ign(Id(TokenType::Parens_Open)) >> ~params >> Ign(Id(TokenType::Parens_Close)) >> Ign(Str(":")) >> block); - - return rule; - } - - - Eval_Engine build_eval_system(langkit::Lexer &lexer, langkit::Rule &parser) { - using namespace langkit; - Eval_Engine ss; - dispatchkit::Bootstrap::bootstrap(ss); - dispatchkit::bootstrap_vector >(ss, "Vector"); - dispatchkit::bootstrap_map >(ss, "Map"); - dispatchkit::bootstrap_pair >(ss, "Pair"); - - ss.register_function(boost::shared_ptr( + engine.register_function(boost::shared_ptr( new dispatchkit::Dynamic_Proxy_Function(boost::bind(&ChaiScript_System::eval, boost::ref(*this), _1), 1)), "eval"); evaluate_string(chaiscript_prelude); - - return ss; - } - - langkit::TokenPtr parse(langkit::Rule &rule, std::vector &tokens, const char *filename) { - using namespace langkit; - - Token_Iterator iter = tokens.begin(), end = tokens.end(); - TokenPtr parent(new Token("Root", TokenType::File, filename)); - - std::pair results = rule(iter, end, parent); - - if ((results.second) && (results.first == end)) { - //debug_print(parent, ""); - return parent; - } - else { - throw ParserError("Parse failed to complete", *(results.first)); - //throw ParserError("Parse failed to complete at: " + (*(results.first))->text , *(results.first)); - } } dispatchkit::Boxed_Value evaluate_string(const std::string &input, const char *filename = "__EVAL__") { - using namespace langkit; - std::vector tokens = lexer.lex(input, filename); + //debug_print(tokens); dispatchkit::Boxed_Value value; - for (unsigned int i = 0; i < tokens.size(); ++i) { - if ((tokens[i]->identifier == TokenType::Quoted_String) || (tokens[i]->identifier == TokenType::Single_Quoted_String)) { - tokens[i]->text = tokens[i]->text.substr(1, tokens[i]->text.size()-2); - for (unsigned int j = 0; j < tokens[i]->text.size(); ++j) { - if (tokens[i]->text[j] == '\\') { - tokens[i]->text.erase(tokens[i]->text.begin() + j, tokens[i]->text.begin() + j + 1); - } - } - } - } - - //debug_print(tokens); try { - TokenPtr parent = parse(parser, tokens, filename); - value = eval_token(engine, parent); + clear_match_stack(); + if (parse(input, filename)) { + //show_match_stack(); + value = eval_token(engine, match_stack.front()); + //clear_match_stack(); + } } catch (const ReturnValue &rv) { value = rv.retval; } - catch (ParserError &pe) { - if (filename != std::string("__EVAL__")) { - std::cout << "Parsing error: \"" << pe.reason << "\" in '" << pe.location->filename << "' line: " << pe.location->start.line+1 << std::endl; - } - else { - std::cout << "Parsing error: \"" << pe.reason << "\"" << std::endl; - } + catch (Parse_Error &pe) { + std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl; + clear_match_stack(); } catch (EvalError &ee) { if (filename != std::string("__EVAL__")) { @@ -280,6 +126,1128 @@ namespace chaiscript dispatchkit::Boxed_Value evaluate_file(const char *filename) { return evaluate_string(load_file(filename), filename); } + + void show_match_stack() { + for (unsigned int i = 0; i < match_stack.size(); ++i) { + debug_print(match_stack[i]); + } + } + + void clear_match_stack() { + match_stack.clear(); + } + + 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()) { + TokenPtr t(new Token("", match_type, filename, match_stack[match_start]->start.line, match_stack[match_start]->start.column, line, col)); + t->children.assign(match_stack.begin() + (match_start), match_stack.end()); + match_stack.erase(match_stack.begin() + (match_start), match_stack.end()); + match_stack.push_back(t); + } + else { + //todo: fix the fact that a successful match that captured no tokens does't have any real start position + TokenPtr t(new Token("", match_type, filename, line, col, line, col)); + match_stack.push_back(t); + } + } + + bool SkipComment() { + bool retval = false; + + if (Symbol_(multiline_comment_begin.c_str())) { + while (input_pos != input_end) { + if (Symbol_(multiline_comment_end.c_str())) { + break; + } + else if (!Eol_()) { + ++col; + ++input_pos; + } + } + retval = true; + } + else if (Symbol_(singleline_comment.c_str())) { + while (input_pos != input_end) { + if (Eol_()) { + break; + } + else { + ++col; + ++input_pos; + } + } + retval = true; + } + return retval; + } + + bool SkipWS() { + bool retval = false; + while (input_pos != input_end) { + if ((*input_pos == ' ') || (*input_pos == '\t')) { + ++input_pos; + ++col; + retval = true; + } + else if (SkipComment()) { + retval = true; + } + else { + break; + } + } + 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; + } + + bool Float_() { + bool retval = false; + if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { + while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { + ++input_pos; + ++col; + } + if (*input_pos == '.') { + ++input_pos; + ++col; + 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; + } + } + else { + --input_pos; + --col; + } + } + } + + return retval; + } + + bool Num(bool capture = false) { + SkipWS(); + + if (!capture) { + return Float_(); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { + if (Float_()) { + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + } + else { + return false; + } + } + } + + bool Id_() { + bool retval = false; + if ((input_pos != input_end) && (((*input_pos >= 'A') && (*input_pos <= 'Z')) || (*input_pos == '_') || ((*input_pos >= 'a') && (*input_pos <= 'z')))) { + retval = true; + while ((input_pos != input_end) && (((*input_pos >= 'A') && (*input_pos <= 'Z')) || (*input_pos == '_') || ((*input_pos >= 'a') && (*input_pos <= 'z')) + || ((*input_pos >= '0') && (*input_pos <= '9')))) { + ++input_pos; + ++col; + } + } + + return retval; + } + + bool Id(bool capture = false) { + SkipWS(); + + if (!capture) { + return Id_(); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Id_()) { + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Quoted_String_() { + bool retval = false; + char prev_char = 0; + if ((input_pos != input_end) && (*input_pos == '\"')) { + retval = true; + prev_char = *input_pos; + ++input_pos; + ++col; + + while ((input_pos != input_end) && ((*input_pos != '\"') || ((*input_pos == '\"') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *input_pos; + } + ++input_pos; + ++col; + } + } + + if (input_pos != input_end) { + ++input_pos; + ++col; + } + else { + throw Parse_Error("Unclosed quoted string", File_Position(line, col), filename); + } + } + return retval; + } + + bool Quoted_String(bool capture = false) { + SkipWS(); + + if (!capture) { + return Quoted_String_(); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + 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 Parse_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); + } + } + else { + match.push_back(*s); + } + is_escaped = false; + } + } + TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Single_Quoted_String_() { + bool retval = false; + char prev_char = 0; + if ((input_pos != input_end) && (*input_pos == '\'')) { + retval = true; + prev_char = *input_pos; + ++input_pos; + ++col; + + while ((input_pos != input_end) && ((*input_pos != '\'') || ((*input_pos == '\'') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *input_pos; + } + ++input_pos; + ++col; + } + } + + if (input_pos != input_end) { + ++input_pos; + ++col; + } + else { + throw Parse_Error("Unclosed single-quoted string", File_Position(line, col), filename); + } + } + return retval; + } + + bool Single_Quoted_String(bool capture = false) { + SkipWS(); + + if (!capture) { + return Single_Quoted_String_(); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Single_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 Parse_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); + } + } + else { + match.push_back(*s); + } + is_escaped = false; + } + } + TokenPtr t(new Token(match, Token_Type::Single_Quoted_String, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + + bool Char_(char c) { + bool retval = false; + if ((input_pos != input_end) && (*input_pos == c)) { + ++input_pos; + ++col; + retval = true; + } + + return retval; + } + + bool Char(char c, bool capture = false) { + SkipWS(); + + if (!capture) { + return Char_(c); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Char_(c)) { + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Char, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Keyword_(const char *s) { + bool retval = false; + int len = strlen(s); + + if ((input_end - input_pos) >= len) { + std::string::iterator tmp = input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != s[i]) { + return false; + } + ++tmp; + } + retval = true; + input_pos = tmp; + col += len; + } + + return retval; + } + + bool Keyword(const char *s, bool capture = false) { + SkipWS(); + + if (!capture) { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + bool retval = Keyword_(s); + if (retval) { + //todo: fix this. Hacky workaround for preventing substring matches + if ((input_pos != input_end) && (((*input_pos >= 'A') && (*input_pos <= 'Z')) || (*input_pos == '_') || ((*input_pos >= 'a') && (*input_pos <= 'z')) + || ((*input_pos >= '0') && (*input_pos <= '9')))) { + input_pos = start; + col = prev_col; + line = prev_line; + return false; + } + return true; + } + else { + return retval; + } + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Keyword_(s)) { + //todo: fix this. Hacky workaround for preventing substring matches + if ((input_pos != input_end) && (((*input_pos >= 'A') && (*input_pos <= 'Z')) || (*input_pos == '_') || ((*input_pos >= 'a') && (*input_pos <= 'z')) + || ((*input_pos >= '0') && (*input_pos <= '9')))) { + input_pos = start; + col = prev_col; + line = prev_line; + return false; + } + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Symbol_(const char *s) { + bool retval = false; + int len = strlen(s); + + if ((input_end - input_pos) >= len) { + std::string::iterator tmp = input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != s[i]) { + return false; + } + ++tmp; + } + retval = true; + input_pos = tmp; + col += len; + } + + return retval; + } + + bool Symbol(const char *s, bool capture = false) { + SkipWS(); + + if (!capture) { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + bool retval = Symbol_(s); + if (retval) { + //todo: fix this. Hacky workaround for preventing substring matches + if ((input_pos != input_end) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '='))) { + input_pos = start; + col = prev_col; + line = prev_line; + return false; + } + return true; + } + else { + return retval; + } + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Symbol_(s)) { + //todo: fix this. Hacky workaround for preventing substring matches + if ((input_pos != input_end) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '='))) { + input_pos = start; + col = prev_col; + line = prev_line; + return false; + } + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Eol_() { + bool retval = false; + + if ((input_pos != input_end) && (Symbol_("\r\n") || Char_('\n'))) { + retval = true; + ++line; + col = 1; + } + else if ((input_pos != input_end) && Char_(';')) { + retval = true; + } + + return retval; + } + + bool Eol(bool capture = false) { + SkipWS(); + + if (!capture) { + return Eol_(); + } + else { + std::string::iterator start = input_pos; + int prev_col = col; + int prev_line = line; + if (Eol_()) { + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Eol, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + bool Arg_List() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Expression()) { + retval = true; + if (Char(',')) { + do { + if (!Expression()) { + throw Parse_Error("Unexpected value in parameter list", match_stack.back()); + } + } while (retval && Char(',')); + } + build_match(Token_Type::Arg_List, prev_stack_top); + } + + return retval; + + } + + bool Lambda() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("fun")) { + retval = true; + + if (Char('(')) { + if (!(Arg_List() && Char(')'))) { + throw Parse_Error("Incomplete anonymous function", File_Position(line, col), filename); + } + } + + while (Eol()); + + if (!Block()) { + throw Parse_Error("Incomplete anonymous function", File_Position(line, col), filename); + } + + build_match(Token_Type::Lambda, prev_stack_top); + } + + return retval; + } + + bool Def() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("def")) { + retval = true; + + if (!Id(true)) { + throw Parse_Error("Missing function name in definition", File_Position(line, col), filename); + } + + if (Char('(')) { + if (!(Arg_List() && Char(')'))) { + throw Parse_Error("Incomplete function definition", File_Position(line, col), filename); + } + } + + while (Eol()); + + if (!Block()) { + throw Parse_Error("Incomplete function definition", File_Position(line, col), filename); + } + + build_match(Token_Type::Def, prev_stack_top); + } + + return retval; + } + + bool If() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("if")) { + retval = true; + + if (!Char('(')) { + throw Parse_Error("Incomplete if expression", File_Position(line, col), filename); + } + + if (!(Expression() && Char(')'))) { + throw Parse_Error("Incomplete if expression", File_Position(line, col), filename); + } + + while (Eol()); + + if (!Block()) { + throw Parse_Error("Incomplete if block", File_Position(line, col), filename); + } + + build_match(Token_Type::If, prev_stack_top); + } + + return retval; + } + + bool While() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("while")) { + retval = true; + + if (!Char('(')) { + throw Parse_Error("Incomplete while expression", File_Position(line, col), filename); + } + + if (!(Expression() && Char(')'))) { + throw Parse_Error("Incomplete while expression", File_Position(line, col), filename); + } + + while (Eol()); + + if (!Block()) { + throw Parse_Error("Incomplete while block", File_Position(line, col), filename); + } + + build_match(Token_Type::While, prev_stack_top); + } + + return retval; + } + + bool Block() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Char('{')) { + retval = true; + + Statements(); + if (!Char('}')) { + throw Parse_Error("Incomplete block", File_Position(line, col), filename); + } + + build_match(Token_Type::Block, prev_stack_top); + } + + return retval; + + } + + bool Return() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("return")) { + retval = true; + + Expression(); + build_match(Token_Type::Return, prev_stack_top); + } + + return retval; + } + + bool Id_Fun_Array() { + bool retval = false; + std::string::iterator prev_pos = input_pos; + + unsigned int prev_stack_top = match_stack.size(); + if (Id(true)) { + retval = true; + bool has_more = true; + + while (has_more) { + has_more = false; + + if (Char('(')) { + has_more = true; + + Arg_List(); + if (!Char(')')) { + throw Parse_Error("Incomplete function call", File_Position(line, col), filename); + } + + build_match(Token_Type::Fun_Call, prev_stack_top); + } + else if (Char('[')) { + has_more = true; + + if (!(Expression() && Char(']'))) { + throw Parse_Error("Incomplete array access", File_Position(line, col), filename); + } + + build_match(Token_Type::Array_Call, prev_stack_top); + } + } + } + + return retval; + } + + /* + * TODO: Look into if we need an explicit LHS for equations + bool LHS() { + if (Var_Decl() || Id()) { + return true; + } + else { + return false; + } + } + */ + + bool Var_Decl() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Keyword("var")) { + retval = true; + + if (!Id(true)) { + throw Parse_Error("Incomplete variable declaration", File_Position(line, col), filename); + } + + build_match(Token_Type::Var_Decl, prev_stack_top); + } + + return retval; + + } + + bool Paren_Expression() { + bool retval = false; + + if (Char('(')) { + retval = true; + if (!Expression()) { + throw Parse_Error("Incomplete expression", File_Position(line, col), filename); + } + if (!Char(')')) { + throw Parse_Error("Missing closing parenthesis", File_Position(line, col), filename); + } + } + return retval; + } + + bool Inline_Container() { + bool retval = false; + + unsigned int prev_stack_top = match_stack.size(); + + if (Char('[')) { + retval = true; + Arg_List(); + if (!Char(']')) { + throw Parse_Error("Missing closing square bracket", File_Position(line, col), filename); + } + build_match(Token_Type::Inline_Array, prev_stack_top); + } + + return retval; + } + + bool Id_Literal() { + bool retval = false; + + SkipWS(); + + if ((input_pos != input_end) && (*input_pos == '`')) { + retval = true; + + int prev_col = col; + int prev_line = line; + + ++col; + ++input_pos; + + std::string::iterator start = input_pos; + + while ((input_pos != input_end) && (*input_pos != '`')) { + if (Eol()) { + throw Parse_Error("Carriage return in identifier literal", File_Position(line, col), filename); + } + else { + ++input_pos; + ++col; + } + } + + if (start == input_pos) { + throw Parse_Error("Missing contents of identifier literal", File_Position(line, col), filename); + } + else if (input_pos == input_end) { + throw Parse_Error("Incomplete identifier literal", File_Position(line, col), filename); + } + + ++col; + std::string match(start, input_pos); + TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); + match_stack.push_back(t); + ++input_pos; + + } + + return retval; + } + + bool Value() { + if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Negate() || Not() || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container() || Id_Literal()) { + return true; + } + else { + return false; + } + } + + bool Negate() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Symbol("-")) { + retval = true; + + if (!Additive()) { + throw Parse_Error("Incomplete negation expression", File_Position(line, col), filename); + } + + build_match(Token_Type::Negate, prev_stack_top); + } + + return retval; + + } + + bool Not() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Symbol("!")) { + retval = true; + + if (!Expression()) { + throw Parse_Error("Incomplete '!' expression", File_Position(line, col), filename); + } + + build_match(Token_Type::Not, prev_stack_top); + } + + return retval; + + } + + bool Comparison() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Additive()) { + retval = true; + if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) { + do { + if (!Additive()) { + throw Parse_Error("Incomplete comparison expression", File_Position(line, col), filename); + } + } while (retval && (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true))); + + build_match(Token_Type::Comparison, prev_stack_top); + } + } + + return retval; + + } + + bool Additive() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Multiplicative()) { + retval = true; + if (Symbol("+", true) || Symbol("-", true)) { + do { + if (!Multiplicative()) { + throw Parse_Error("Incomplete math expression", File_Position(line, col), filename); + } + } while (retval && (Symbol("+", true) || Symbol("-", true))); + + build_match(Token_Type::Additive, prev_stack_top); + } + } + + return retval; + } + + bool Multiplicative() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Dot_Access()) { + retval = true; + if (Symbol("*", true) || Symbol("/", true)) { + do { + if (!Dot_Access()) { + throw Parse_Error("Incomplete math expression", File_Position(line, col), filename); + } + } while (retval && (Symbol("*", true) || Symbol("/", true))); + + build_match(Token_Type::Multiplicative, prev_stack_top); + } + } + + return retval; + + } + + bool Dot_Access() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Value()) { + retval = true; + if (Symbol(".")) { + do { + if (!Value()) { + throw Parse_Error("Incomplete dot notation", File_Position(line, col), filename); + } + } while (retval && Symbol(".")); + + build_match(Token_Type::Dot_Access, prev_stack_top); + } + } + + return retval; + } + + bool Expression() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Comparison()) { + retval = true; + if (Symbol("&&", true) || Symbol("||", true)) { + do { + if (!Comparison()) { + throw Parse_Error("Incomplete expression", File_Position(line, col), filename); + } + } while (retval && (Symbol("&&", true) || Symbol("||", true))); + + build_match(Token_Type::Expression, prev_stack_top); + } + } + + return retval; + } + + bool Equation() { + bool retval = false; + + int prev_stack_top = match_stack.size(); + + if (Expression()) { + retval = true; + if (Symbol("=", true) || Symbol("+=", true) || Symbol("-=", true) || Symbol("*=", true) || Symbol("/=", true)) { + if (!Equation()) { + throw Parse_Error("Incomplete equation", match_stack.back()); + } + + build_match(Token_Type::Equation, prev_stack_top); + } + } + + return retval; + + } + + bool Statement() { + if (Return() || Equation()) { + return true; + } + else { + return false; + } + } + + bool Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + has_more = false; + if (Def()) { + if (!saw_eol) { + throw Parse_Error("Two function definitions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (If()) { + if (!saw_eol) { + throw Parse_Error("Two function definitions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (While()) { + if (!saw_eol) { + throw Parse_Error("Two function definitions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Statement()) { + if (!saw_eol) { + throw Parse_Error("Two expressions missing line separator", match_stack.back()); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } + else { + has_more = false; + } + } + + return retval; + } + + bool parse(std::string input, const char *fname) { + input_pos = input.begin(); + input_end = input.end(); + line = 1; col = 1; + filename = fname; + + if (Statements()) { + if (input_pos != input_end) { + throw Parse_Error("Unparsed input", File_Position(line, col), fname); + } + else { + build_match(Token_Type::File, 0); + return true; + } + } + else { + return false; + } + } + }; typedef ChaiScript_System ChaiScript_Engine; diff --git a/chaiscript/chaiscript_eval.hpp b/chaiscript/chaiscript_eval.hpp index 697c074..8a3881d 100644 --- a/chaiscript/chaiscript_eval.hpp +++ b/chaiscript/chaiscript_eval.hpp @@ -8,40 +8,8 @@ namespace chaiscript { - struct ParserError { - std::string reason; - langkit::TokenPtr location; - - ParserError(const std::string &why, const langkit::TokenPtr where) : reason(why), location(where){ } - }; - - struct EvalError : public std::runtime_error { - std::string reason; - langkit::TokenPtr location; - - EvalError(const std::string &why, const langkit::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() {} - }; - - struct ReturnValue { - dispatchkit::Boxed_Value retval; - langkit::TokenPtr location; - - ReturnValue(const dispatchkit::Boxed_Value &return_value, const langkit::TokenPtr where) : retval(return_value), location(where) { } - }; - - struct BreakLoop { - langkit::TokenPtr location; - - BreakLoop(const langkit::TokenPtr where) : location(where) { } - }; - template - const dispatchkit::Boxed_Value eval_function (Eval_System &ss, langkit::TokenPtr node, const std::vector ¶m_names, const std::vector &vals) { + const dispatchkit::Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector ¶m_names, const std::vector &vals) { ss.new_scope(); for (unsigned int i = 0; i < param_names.size(); ++i) { @@ -61,18 +29,17 @@ namespace chaiscript } template - dispatchkit::Boxed_Value eval_token(Eval_System &ss, langkit::TokenPtr node) { + dispatchkit::Boxed_Value eval_token(Eval_System &ss, TokenPtr node) { dispatchkit::Boxed_Value retval; unsigned int i, j; switch (node->identifier) { - case (TokenType::Value) : - case (TokenType::File) : + case (Token_Type::File) : for (i = 0; i < node->children.size(); ++i) { retval = eval_token(ss, node->children[i]); } break; - case (TokenType::Identifier) : + case (Token_Type::Id) : if (node->text == "true") { retval = dispatchkit::Boxed_Value(true); } @@ -88,19 +55,19 @@ namespace chaiscript } } break; - case (TokenType::Real_Number) : + case (Token_Type::Float) : retval = dispatchkit::Boxed_Value(double(atof(node->text.c_str()))); break; - case (TokenType::Integer) : + case (Token_Type::Int) : retval = dispatchkit::Boxed_Value(atoi(node->text.c_str())); break; - case (TokenType::Quoted_String) : + case (Token_Type::Quoted_String) : retval = dispatchkit::Boxed_Value(node->text); break; - case (TokenType::Single_Quoted_String) : + case (Token_Type::Single_Quoted_String) : retval = dispatchkit::Boxed_Value(node->text); break; - case (TokenType::Equation) : + case (Token_Type::Equation) : retval = eval_token(ss, node->children.back()); if (node->children.size() > 1) { for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) { @@ -116,16 +83,15 @@ namespace chaiscript } } break; - case (TokenType::Variable_Decl): { + case (Token_Type::Var_Decl): { ss.add_object(node->children[0]->text, dispatchkit::Boxed_Value()); retval = ss.get_object(node->children[0]->text); } break; - case (TokenType::Factor) : - case (TokenType::Expression) : - case (TokenType::Term) : - case (TokenType::Boolean) : - case (TokenType::Comparison) : { + case (Token_Type::Comparison) : + case (Token_Type::Expression) : + case (Token_Type::Additive) : + case (Token_Type::Multiplicative) : { retval = eval_token(ss, node->children[0]); if (node->children.size() > 1) { for (i = 1; i < node->children.size(); i += 2) { @@ -143,7 +109,7 @@ namespace chaiscript } } break; - case (TokenType::Array_Call) : { + case (Token_Type::Array_Call) : { retval = eval_token(ss, node->children[0]); for (i = 1; i < node->children.size(); ++i) { dispatchkit::Param_List_Builder plb; @@ -161,8 +127,8 @@ namespace chaiscript } } break; - case (TokenType::Negate) : { - retval = eval_token(ss, node->children[1]); + case (Token_Type::Negate) : { + retval = eval_token(ss, node->children[0]); dispatchkit::Param_List_Builder plb; plb << retval; plb << dispatchkit::Boxed_Value(-1); @@ -175,10 +141,10 @@ namespace chaiscript } } break; - case (TokenType::Not) : { + case (Token_Type::Not) : { bool cond; try { - retval = eval_token(ss, node->children[1]); + retval = eval_token(ss, node->children[0]); cond = dispatchkit::boxed_cast(retval); } catch (std::exception) { @@ -187,7 +153,8 @@ namespace chaiscript retval = dispatchkit::Boxed_Value(!cond); } break; - case (TokenType::Prefix) : { + /* + case (Token_Type::Prefix) : { retval = eval_token(ss, node->children[1]); dispatchkit::Param_List_Builder plb; plb << retval; @@ -200,16 +167,19 @@ namespace chaiscript } } break; - case (TokenType::Array_Init) : { + */ + case (Token_Type::Inline_Array) : { try { retval = dispatch(ss.get_function("Vector"), dispatchkit::Param_List_Builder()); - for (i = 0; i < node->children.size(); ++i) { - try { - dispatchkit::Boxed_Value tmp = eval_token(ss, node->children[i]); - 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[i]); + if (node->children.size() > 0) { + for (i = 0; i < node->children[0]->children.size(); ++i) { + try { + dispatchkit::Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]); + 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]); + } } } } @@ -218,6 +188,7 @@ namespace chaiscript } } break; + /* case (TokenType::Map_Init) : { try { retval = dispatch(ss.get_function("Map"), dispatchkit::Param_List_Builder()); @@ -237,7 +208,9 @@ namespace chaiscript } } break; - case (TokenType::Fun_Call) : { + */ + case (Token_Type::Fun_Call) : { + dispatchkit::Param_List_Builder plb; std::vector > fn; dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack(); @@ -245,9 +218,10 @@ namespace chaiscript dispatchkit::Dispatch_Engine::Stack new_stack; new_stack.push_back(dispatchkit::Dispatch_Engine::Scope()); - dispatchkit::Param_List_Builder plb; - for (i = 1; i < node->children.size(); ++i) { - plb << eval_token(ss, node->children[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 { fn = ss.get_function(node->children[0]->text); @@ -269,7 +243,8 @@ namespace chaiscript } } break; - case (TokenType::Method_Call) : { + + case (Token_Type::Dot_Access) : { std::vector > fn; dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack(); @@ -282,12 +257,15 @@ namespace chaiscript dispatchkit::Param_List_Builder plb; plb << retval; - for (j = 1; j < node->children[i]->children.size(); ++j) { - plb << eval_token(ss, node->children[i]->children[j]); + if (node->children[i]->children.size() > 1) { + //std::cout << "size: " << node->children[i]->children.size() << std::endl; + for (j = 0; j < node->children[i]->children[1]->children.size(); ++j) { + plb << eval_token(ss, node->children[i]->children[1]->children[j]); + } } std::string fun_name; - if (node->children[i]->identifier == TokenType::Fun_Call) { + if (node->children[i]->identifier == Token_Type::Fun_Call) { fun_name = node->children[i]->children[0]->text; } else { @@ -316,7 +294,8 @@ namespace chaiscript } } break; - case(TokenType::If_Block) : { + + case(Token_Type::If) : { retval = eval_token(ss, node->children[0]); bool cond; try { @@ -354,7 +333,7 @@ namespace chaiscript } } break; - case(TokenType::While_Block) : { + case(Token_Type::While) : { retval = eval_token(ss, node->children[0]); bool cond; try { @@ -381,6 +360,7 @@ namespace chaiscript retval = dispatchkit::Boxed_Value(); } break; + /* case(TokenType::For_Block) : { dispatchkit::Boxed_Value condition; bool cond; @@ -423,31 +403,37 @@ namespace chaiscript retval = dispatchkit::Boxed_Value(); } break; - case (TokenType::Function_Def) : { - unsigned int num_args = node->children.size() - 2; + */ + case (Token_Type::Def) : { std::vector param_names; - for (i = 0; i < num_args; ++i) { - param_names.push_back(node->children[i+1]->text); + + if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < node->children[1]->children.size(); ++i) { + param_names.push_back(node->children[1]->children[i]->text); + } } ss.register_function(boost::shared_ptr( - new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), num_args)), node->children[0]->text); + new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), node->children[1]->children.size())), node->children[0]->text); } break; - case (TokenType::Lambda_Def) : { - unsigned int num_args = node->children.size() - 1; + case (Token_Type::Lambda) : { std::vector param_names; - for (i = 0; i < num_args; ++i) { - param_names.push_back(node->children[i]->text); + + if ((node->children.size() > 0) && (node->children[0]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < node->children[0]->children.size(); ++i) { + param_names.push_back(node->children[0]->children[i]->text); + } } //retval = boost::shared_ptr(new dispatchkit::Proxy_Function_Impl >(&test)); retval = dispatchkit::Boxed_Value(boost::shared_ptr( new dispatchkit::Dynamic_Proxy_Function( - boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), num_args))); + boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), node->children[0]->children.size()))); } break; - case (TokenType::Scoped_Block) : { + + case (Token_Type::Block) : { ss.new_scope(); for (i = 0; i < node->children.size(); ++i) { retval = eval_token(ss, node->children[i]); @@ -455,7 +441,8 @@ namespace chaiscript ss.pop_scope(); } break; - case (TokenType::Return) : { + + case (Token_Type::Return) : { if (node->children.size() > 0) { retval = eval_token(ss, node->children[0]); } @@ -465,6 +452,7 @@ namespace chaiscript throw ReturnValue(retval, node); } break; + /* case (TokenType::Break) : { throw BreakLoop(node); } @@ -483,6 +471,7 @@ namespace chaiscript case (TokenType::Curly_Close) : case (TokenType::Comma) : break; + */ } return retval; diff --git a/chaiscript/main.cpp b/chaiscript/main.cpp index e08c065..3a3a085 100644 --- a/chaiscript/main.cpp +++ b/chaiscript/main.cpp @@ -7,12 +7,13 @@ int main(int argc, char *argv[]) { std::string input; chaiscript::ChaiScript_Engine chai; + chai.build_eval_system(); if (argc < 2) { std::cout << "eval> "; std::getline(std::cin, input); while (input != "quit") { - dispatchkit::Boxed_Value val; + dispatchkit::Boxed_Value val; val = chai.evaluate_string(input); @@ -25,7 +26,7 @@ int main(int argc, char *argv[]) { dispatchkit::dispatch(chai.get_eval_engine().get_function("print"), dispatchkit::Param_List_Builder() << printeval); } catch (const std::runtime_error &e) { - std::cout << "result: object #" << &val << std::endl; + std::cout << "result: object #" << &val << " Error: " << e.what() << std::endl; } } std::cout << "eval> "; diff --git a/chaiscript/sensors.cpp b/chaiscript/sensors.cpp index 14a71dd..44320d4 100644 --- a/chaiscript/sensors.cpp +++ b/chaiscript/sensors.cpp @@ -4,6 +4,7 @@ #include "function_call.hpp" #include #include +#include std::string load_text_file(const std::string &filename)