From 84f747100645abe6e974b8c48e1426cad67ab55b Mon Sep 17 00:00:00 2001 From: John Doe Date: Fri, 14 Nov 2014 19:06:42 +0100 Subject: [PATCH] first impl of builtin member methods (thus far, string.size implemented. more to come!) --- CMakeLists.txt | 8 +- examples/basics.jtc | 6 +- examples/class.jtc | 6 +- examples/derivatives.jtc | 61 +++++++---- include/jtc.h | 265 +++++++++++++++++++++++---------------------- src/builtin.array.cpp | 0 src/builtin.h | 45 ++++++++ src/builtin.string.cpp | 10 ++ src/builtin.table.cpp | 0 src/ops.cpp | 273 ++--------------------------------------------- src/ops.member.cpp | 69 ++++++++++++ src/ops.statement.cpp | 223 ++++++++++++++++++++++++++++++++++++++ src/parser.h | 2 - src/private.h | 10 -- src/stdlib.file.cpp | 11 +- 15 files changed, 556 insertions(+), 433 deletions(-) create mode 100644 src/builtin.array.cpp create mode 100644 src/builtin.h create mode 100644 src/builtin.string.cpp create mode 100644 src/builtin.table.cpp create mode 100644 src/ops.member.cpp create mode 100644 src/ops.statement.cpp delete mode 100644 src/parser.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 07b7fb8..1f11490 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,14 @@ set(exename ${name}-exe) set(libname ${name}-library) set(libsources + "src/ops.cpp" + "src/ops.statement.cpp" + "src/ops.member.cpp" + "src/builtin.string.cpp" + "src/builtin.table.cpp" + "src/builtin.array.cpp" "src/common.cpp" "src/interp.cpp" - "src/ops.cpp" "src/stdlib.cpp" "src/stdlib.file.cpp" ) @@ -24,6 +29,7 @@ set(binsources include_directories("include") add_definitions( "-std=c++11" + "-Wall" "-Wextra" "-s" "-Wl,-s" "-Os" ) diff --git a/examples/basics.jtc b/examples/basics.jtc index ad30c38..6cf6a07 100644 --- a/examples/basics.jtc +++ b/examples/basics.jtc @@ -4,11 +4,11 @@ pi = 3.14159 // numbers are always doubles greeting = "Hello World!" // string -square = function(x) { // functions are first class citizens +square = func(x) { // functions are first class citizens return x*x } -arr = [pi greeting nil] // array types +arr = [pi, greeting, nil] // array types arr[2] = square //replace the nil element (indices start at 0) arr += [23] // append length = size(arr) // use the size operator to find an arrays length @@ -20,7 +20,7 @@ table = { "bar" = square } table.e = 2.71 // equivalent to table["e"] = 2.71 -table.bar = function() { print(this.e, "\n") } +table.bar = func() { print(this.e, "\n") } table.bar() // flow control uses C style diff --git a/examples/class.jtc b/examples/class.jtc index 7493d69..215410f 100644 --- a/examples/class.jtc +++ b/examples/class.jtc @@ -1,14 +1,14 @@ -local Person = function() +local Person = func() { // code in the mainbody is the 'constructor', so to say print("Person.Person() called!\n") this = {name = "foo"} - this.setName = function(newname) + this.setName = func(newname) { this.name = newname } - this.printName = function() + this.printName = func() { print("this.name = ", this.name, "\n") } diff --git a/examples/derivatives.jtc b/examples/derivatives.jtc index 41a426d..764cd3f 100644 --- a/examples/derivatives.jtc +++ b/examples/derivatives.jtc @@ -1,52 +1,73 @@ // use jtc's introspection abilities to calculate symbolic derivatives // of simple functions. -derive_expr = function(expr var) { +derive_expr = func(expr, var) +{ expansion = expand_node(expr) - - if(size(expansion)==1) { - if(type(expansion[0])=="string") { + if(size(expansion) == 1) + { + if(type(expansion[0]) == "string") + { if(expansion[0] == var) + { return "1" + } else + { return "0" - } else { - return derive(expansion[0] var) + } + } + else + { + return derive(expansion[0], var) } - } else if(expansion[0]=="(") { - return derive_expr(expansion[1] var) - } else { - dleft = derive_expr(expansion[0] var) - dright = derive_expr(expansion[2] var) + } + else if(expansion[0] == "(") + { + return derive_expr(expansion[1], var) + } + else + { + dleft = derive_expr(expansion[0], var) + dright = derive_expr(expansion[2], var) left = tostring(expansion[0]) right = tostring(expansion[2]) - if(expansion[1] == "+") { + if(expansion[1] == "+") + { return "(" + dleft + "+" + dright + ")" - } else if(expansion[1] == "-") { + } + else if(expansion[1] == "-") + { return "(" + dleft + "-" + dright + ")" - } else if(expansion[1] == "*") { + } + else if(expansion[1] == "*") + { return "(" + left + "*" + dright + "+" + dleft + "*" + right + ")" - } else if(expansion[1] == "/") { + } + else if(expansion[1] == "/") + { return "(" + dleft + "*" + right + "-" + dright + "*" + left + ")/(" + right + "*" + right + ")" } } } -derive = function(fun var) { +derive = func(fun, var) +{ expansion = expand_node(fun) vars = tostring(expansion[1]) if(var == nil) + { var = tostring(expand_node(expansion[1])[1]) - + } expr = expand_node(expansion[2])[1] - source = "function"+vars+" return "+derive_expr(expr var)+"" + source = "func"+vars+" return "+derive_expr(expr, var)+"" return eval(parse_expression(source)) } -f = function(x) return x*x +f = func(x) return x*x df = derive(f) -g = function(x y) return x*y +g = func(x, y) return x*y dg = derive(g "y") print(tostring(df) "\n") diff --git a/include/jtc.h b/include/jtc.h index b91d621..504247d 100644 --- a/include/jtc.h +++ b/include/jtc.h @@ -23,72 +23,54 @@ class Interpreter; namespace Internal { - /* - enum TokenType - { - Type::Number, IDENTIFIER, Type::String, - LEFT_PAREN, RIGHT_PAREN, LEFT_BRACKET, - RIGHT_BRACKET, LEFT_BRACE, RIGHT_BRACE, - PLUS, DASH, STAR, - PERCENT, SLASH, PLUS_EQUAL, - DASH_EQUAL, STAR_EQUAL, PERCENT_EQUAL, - SLASH_EQUAL, NOT, COMMA, - SEMICOLON, DOT, COLON, - EQUAL, EQ_OP, NOT_EQUAL, - GREATER, GREATER_EQUAL, LESS, - LESS_EQUAL, LOGICAL_AND, LOGICAL_OR, - IF, ELSE, WHILE, - FOR, Type::Return, Type::Break, - Type::Continue, Type::Function, EXPRESSION, - STATEMENT, ROOT, Type::Nil, - EVAL, PARSE_STATEMENT, PARSE_EXPRESSION, - GLOBAL, LOCAL, PRINT, - TYPE, SIZE - }; - */ enum TokenType { Tok_Number, Tok_Identifier, Tok_String, Tok_LeftParen, Tok_RightParen, Tok_LeftBracket, Tok_RightBracket, Tok_LeftBrace, Tok_RightBrace, Tok_Plus, Tok_Dash, Tok_Star, - Tok_Percent, Tok_Slash, Tok_Plus_Tok_Equal, - Tok_Dash_Equal, Tok_Star_Equal, Tok_Percent_Tok_Equal, - Tok_Slash_Tok_Equal, NOT, Tok_Comma, + Tok_Percent, Tok_Slash, Tok_PlusEqual, + Tok_DashEqual, Tok_StarEqual, Tok_PercentEqual, + Tok_SlashEqual, Tok_Not, Tok_Comma, Tok_Semicolon, Tok_Dot, Tok_Colon, Tok_Equal, Tok_EqOp, Tok_NotEqual, - Tok_Greater, Tok_Greater_Equal, Tok_Less, - Tok_Less_Tok_Equal, Tok_LogicalAnd, Tok_LogicalOr, + Tok_Greater, Tok_GreaterEqual, Tok_Less, + Tok_LessEqual, Tok_LogicalAnd, Tok_LogicalOr, Tok_If, Tok_Else, Tok_While, Tok_For, Tok_Return, Tok_Break, Tok_Continue, Tok_Function, Tok_Expression, Tok_Statement, Tok_Root, Tok_Nil, Tok_Eval, Tok_ParseStatement, Tok_ParseExpression, Tok_Global, Tok_Local, Tok_Print, - Tok_Type, Tok_Size - }; - - const std::unordered_map keywords = - { - {"if", Tok_If}, - {"else", Tok_Else}, - {"while", Tok_While}, - {"for", Tok_For}, - {"return", Tok_Return}, - {"break", Tok_Break}, - {"continue", Tok_Continue}, - {"function", Tok_Function}, - {"nil", Tok_Nil}, - {"expression", Tok_Expression}, - {"statement", Tok_Statement}, - {"eval", Tok_Eval}, - {"parse_statement", Tok_ParseStatement}, + Tok_Type, Tok_Size, Tok_Switch, + Tok_Case, Tok_Import, + }; + + static const std::unordered_map keywords = + { + {"if", Tok_If}, + {"else", Tok_Else}, + {"while", Tok_While}, + {"for", Tok_For}, + {"return", Tok_Return}, + {"break", Tok_Break}, + {"continue", Tok_Continue}, + {"func", Tok_Function}, + {"nil", Tok_Nil}, + {"expression", Tok_Expression}, + {"statement", Tok_Statement}, + {"eval", Tok_Eval}, + {"parse_statement", Tok_ParseStatement}, {"parse_expression", Tok_ParseExpression}, - {"global", Tok_Global}, - {"local", Tok_Local}, - {"root", Tok_Root}, - {"type", Tok_Type}, - {"size", Tok_Size}, + {"global", Tok_Global}, + {"local", Tok_Local}, + {"root", Tok_Root}, + {"type", Tok_Type}, + {"size", Tok_Size}, + // these aren't implemented yet + {"switch", Tok_Switch}, + {"case", Tok_Case}, + {"import", Tok_Import}, }; template @@ -182,7 +164,7 @@ namespace Internal case '+': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Plus_Tok_Equal, i, i+2); + tokens.emplace_back(Tok_PlusEqual, i, i+2); i+=2; } else @@ -194,7 +176,7 @@ namespace Internal case '-': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Dash_Equal, i, i+2); + tokens.emplace_back(Tok_DashEqual, i, i+2); i+=2; } else @@ -206,7 +188,7 @@ namespace Internal case '*': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Star_Equal, i, i+2); + tokens.emplace_back(Tok_StarEqual, i, i+2); i+=2; } else @@ -218,7 +200,7 @@ namespace Internal case '%': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Percent_Tok_Equal, i, i+2); + tokens.emplace_back(Tok_PercentEqual, i, i+2); i+=2; } else @@ -238,7 +220,7 @@ namespace Internal } else if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Slash_Tok_Equal, i, i+2); + tokens.emplace_back(Tok_SlashEqual, i, i+2); i+=2; } else @@ -250,7 +232,7 @@ namespace Internal case '<': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Less_Tok_Equal, i, i+2); + tokens.emplace_back(Tok_LessEqual, i, i+2); i+=2; } else @@ -262,7 +244,7 @@ namespace Internal case '>': if(i+1 != end && *(i+1) == '=') { - tokens.emplace_back(Tok_Greater_Equal, i, i+2); + tokens.emplace_back(Tok_GreaterEqual, i, i+2); i+=2; } else @@ -291,7 +273,7 @@ namespace Internal } else { - tokens.emplace_back(NOT, i, i+1); + tokens.emplace_back(Tok_Not, i, i+1); i+=2; } break; @@ -1620,31 +1602,31 @@ namespace Internal { return_t right = expression(); expect(Tok_RightBracket); - if(peek(Tok_Equal) || peek(Tok_Plus_Tok_Equal) || peek(Tok_Dash_Equal) || - peek(Tok_Star_Equal) || peek(Tok_Slash_Tok_Equal) || peek(Tok_Percent_Tok_Equal)) + if(peek(Tok_Equal) || peek(Tok_PlusEqual) || peek(Tok_DashEqual) || + peek(Tok_StarEqual) || peek(Tok_SlashEqual) || peek(Tok_PercentEqual)) { std::shared_ptr> node; if(accept(Tok_Equal)) { node = std::make_shared>(); } - else if(accept(Tok_Plus_Tok_Equal)) + else if(accept(Tok_PlusEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Dash_Equal)) + else if(accept(Tok_DashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Star_Equal)) + else if(accept(Tok_StarEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Slash_Tok_Equal)) + else if(accept(Tok_SlashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Percent_Tok_Equal)) + else if(accept(Tok_PercentEqual)) { node = std::make_shared>(); } @@ -1668,31 +1650,31 @@ namespace Internal else if(accept(Tok_Dot)) { return_t right = field_name(); - if(peek(Tok_Equal) || peek(Tok_Plus_Tok_Equal) || peek(Tok_Dash_Equal) || - peek(Tok_Star_Equal) || peek(Tok_Slash_Tok_Equal) || peek(Tok_Percent_Tok_Equal)) + if(peek(Tok_Equal) || peek(Tok_PlusEqual) || peek(Tok_DashEqual) || + peek(Tok_StarEqual) || peek(Tok_SlashEqual) || peek(Tok_PercentEqual)) { std::shared_ptr> node; if(accept(Tok_Equal)) { node = std::make_shared>(); } - else if(accept(Tok_Plus_Tok_Equal)) + else if(accept(Tok_PlusEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Dash_Equal)) + else if(accept(Tok_DashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Star_Equal)) + else if(accept(Tok_StarEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Slash_Tok_Equal)) + else if(accept(Tok_SlashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Percent_Tok_Equal)) + else if(accept(Tok_PercentEqual)) { node = std::make_shared>(); } @@ -1755,7 +1737,7 @@ namespace Internal return_t unary_expression() { - if(accept(Tok_Plus) || accept(Tok_Dash) || accept(NOT)) + if(accept(Tok_Plus) || accept(Tok_Dash) || accept(Tok_Not)) { using node_t = std::shared_ptr>; node_t node; @@ -1767,7 +1749,7 @@ namespace Internal case Tok_Dash: node = node_t(new UnaryMinusExpression); break; - case NOT: + case Tok_Not: node = node_t(new UnaryNotExpression); break; default: @@ -1853,7 +1835,7 @@ namespace Internal { Iter from = i; return_t left = additive_expression(); - if(accept(Tok_Less) || accept(Tok_Less_Tok_Equal) || accept(Tok_Greater) || accept(Tok_Greater_Equal)) + if(accept(Tok_Less) || accept(Tok_LessEqual) || accept(Tok_Greater) || accept(Tok_GreaterEqual)) { using node_t = std::shared_ptr>; node_t node; @@ -1862,13 +1844,13 @@ namespace Internal case Tok_Less: node = node_t(new LessExpression); break; - case Tok_Less_Tok_Equal: + case Tok_LessEqual: node = node_t(new LessEqualExpression); break; case Tok_Greater: node = node_t(new GreaterExpression); break; - case Tok_Greater_Equal: + case Tok_GreaterEqual: node = node_t(new GreaterEqualExpression); break; default: @@ -1989,23 +1971,23 @@ namespace Internal { node = std::make_shared>(); } - else if(accept(Tok_Plus_Tok_Equal)) + else if(accept(Tok_PlusEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Dash_Equal)) + else if(accept(Tok_DashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Star_Equal)) + else if(accept(Tok_StarEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Slash_Tok_Equal)) + else if(accept(Tok_SlashEqual)) { node = std::make_shared>(); } - else if(accept(Tok_Percent_Tok_Equal)) + else if(accept(Tok_PercentEqual)) { node = std::make_shared>(); } @@ -2325,6 +2307,40 @@ struct BaseValue return m_type; } + const char* typeName() const + { + switch(type()) + { + case Type::Nil: + return "nil"; + case Type::Number: + return "number"; + case Type::String: + return "string"; + case Type::ProtoString: + return "protostring"; + case Type::Tree: + return "tree"; + case Type::Function: + return "function"; + case Type::Table: + return "table"; + case Type::Array: + return "array"; + case Type::Return: + return "return"; + case Type::Break: + return "break"; + case Type::Continue: + return "continue"; + case Type::UserPtr: + return "userptr"; + default: + ; + } + return "invalid"; + } + Type internal_type() const { return m_type; @@ -2709,15 +2725,15 @@ std::ostream& operator<<(std::ostream &out, const BaseValue &v) case T::Type::String: return out << v.string(); case T::Type::Tree: - return out << "tree: " << v.tree(); + return out << "tree@" << v.tree(); case T::Type::Function: - return out << "function: " << v.function(); + return out << "function@" << v.function(); case T::Type::Table: - return out << "table: " << v.table(); + return out << "table@" << v.table(); case T::Type::Array: - return out << "array: " << v.array(); + return out << "array@" << v.array(); case T::Type::UserPtr: - return out << "userpointer: " << v.userptr(); + return out << "userpointer@" << v.userptr(); default: return out; } @@ -2833,51 +2849,50 @@ class Array class Interpreter { public: - using Iter = std::vector>::iterator; - using FuncType = Interpreter; - using Value = BaseValue; - using env_t = std::shared_ptr>; - using envstack_t = std::vector; - using funstack_t = std::vector; + using Iter = std::vector>::iterator; + using FuncType = Interpreter; + using Value = BaseValue; + using Environment = std::shared_ptr>; + using EnvStack = std::vector; + using FunStack = std::vector; + using ParserInstance = Internal::Parser; struct FunctionScope { - FunctionScope() - { - } + Interpreter* m_self; - FunctionScope(Interpreter* ev_): ev(ev_) + FunctionScope(Interpreter* self): m_self(self) { - ev->beginFunctionScope(); + m_self->beginFunctionScope(); } ~FunctionScope() { - ev->endFunctionScope(); + m_self->endFunctionScope(); } - - Interpreter* ev; }; struct LocalScope { - LocalScope(Interpreter &ev_) : ev(ev_) + Interpreter& m_self; + + LocalScope(Interpreter& self): m_self(self) { - ev.beginLocalScope(); + m_self.beginLocalScope(); } + ~LocalScope() { - ev.endLocalScope(); + m_self.endLocalScope(); } - Interpreter &ev; }; private: - Internal::Parser parser; - std::vector function_stack; - std::vector> scopes; - envstack_t envstack; - funstack_t funstack; + ParserInstance m_parser; + std::vector m_function_stack; + std::vector> m_scopes; + EnvStack m_envstack; + FunStack m_funstack; public: Value operator()(Internal::Variable &node); @@ -3050,54 +3065,54 @@ class Interpreter void beginLocalScope() { - envstack.push_back(std::make_shared>()); + m_envstack.push_back(std::make_shared>()); } void endLocalScope() { - envstack.pop_back(); + m_envstack.pop_back(); } void beginFunctionScope() { - funstack.push_back(envstack.size()); - envstack.push_back(std::make_shared>()); + m_funstack.push_back(m_envstack.size()); + m_envstack.push_back(std::make_shared>()); } void endFunctionScope() { - envstack.pop_back(); - funstack.pop_back(); + m_envstack.pop_back(); + m_funstack.pop_back(); } Value get(Value key) { - int top = envstack.size()-1; - int bottom = funstack.back(); + int top = m_envstack.size()-1; + int bottom = m_funstack.back(); for(int i = top; i>=bottom; --i) { - Value value = envstack[i]->get(key); + Value value = m_envstack[i]->get(key); if(value.type() != Value::Type::Nil) { return value; } } - return envstack[0]->get(key); + return m_envstack[0]->get(key); } void set(Value key, Value value) { - envstack[funstack.back()]->set(key, value); + m_envstack[m_funstack.back()]->set(key, value); } void setLocal(Value key, Value value) { - envstack.back()->set(key, value); + m_envstack.back()->set(key, value); } void setGlobal(Value key, Value value) { - envstack[0]->set(key, value); + m_envstack[0]->set(key, value); } template @@ -3128,7 +3143,7 @@ class Interpreter Value run(const std::string &source) { - auto root = parser(source.begin(), source.end()); + auto root = m_parser(source.begin(), source.end()); Value result = root->accept(*this); return result; } diff --git a/src/builtin.array.cpp b/src/builtin.array.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/builtin.h b/src/builtin.h new file mode 100644 index 0000000..78df19a --- /dev/null +++ b/src/builtin.h @@ -0,0 +1,45 @@ + +#include + +#define BUILTIN_PROTO(funcname, ipname, selfname) \ + Interpreter::Value funcname(Interpreter& ipname, Interpreter::Value& selfname) + +#define BUILTIN_DECLARE(funcname) \ + BUILTIN_PROTO(funcname, _ip, _self) + +#define BUILTIN_EXISTS(shortname, funcname) \ + ( \ + rtbuiltin_##shortname##_methods.find(funcname) != rtbuiltin_##shortname##_methods.end() \ + ) + +#define BUILTIN_GET(shortname, funcname) \ + rtbuiltin_##shortname##_methods[funcname] + +using BuiltinFunction = std::function; + + +//! function protos for string builtins +BUILTIN_DECLARE(rtbuiltin_func_string_length); + +//! function protos for array builtins + + +//! function protos for table builtins + +// builtin functions for strings +static std::map rtbuiltin_string_methods = +{ + {"length", rtbuiltin_func_string_length}, + {"size", rtbuiltin_func_string_length}, +}; + + +// builtin functions for arrays +static std::map rtbuiltin_array_methods = +{ +}; + +// builtin functions for tables +static std::map rtbuiltin_table_methods = +{ +}; diff --git a/src/builtin.string.cpp b/src/builtin.string.cpp new file mode 100644 index 0000000..90b6452 --- /dev/null +++ b/src/builtin.string.cpp @@ -0,0 +1,10 @@ + +#include "private.h" +#include "builtin.h" + +BUILTIN_PROTO(rtbuiltin_func_string_length, ip, self) +{ + (void)ip; + return self.string().size(); +} + diff --git a/src/builtin.table.cpp b/src/builtin.table.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ops.cpp b/src/ops.cpp index f713f93..7bc80af 100644 --- a/src/ops.cpp +++ b/src/ops.cpp @@ -38,10 +38,6 @@ Interpreter::Value Interpreter::operator()(Parensaccept(*this); } -Interpreter::Value Interpreter::operator()(ExpressionStatement &node) -{ - return node.children[0]->accept(*this); -} Interpreter::Value Interpreter::operator()(Type &node) { @@ -866,19 +862,10 @@ Interpreter::Value Interpreter::operator()(Function &node) -{ - if(node.children.size()>0) - { - function_stack.push_back(node.children[0]->accept(*this)); - } - return Interpreter::Value(typename Interpreter::Value::TagReturn()); -} - Interpreter::Value Interpreter::operator()(IdentifierList &node) { - auto i = function_stack.begin(); - auto end = function_stack.end(); + auto i = m_function_stack.begin(); + auto end = m_function_stack.end(); set(Interpreter::Value("this"), *i++); for(auto child : node.children) { @@ -888,14 +875,13 @@ Interpreter::Value Interpreter::operator()(IdentifierListaccept(*this), *i++); } - function_stack.clear(); + m_function_stack.clear(); return Interpreter::Value(); } -//! OP: func_call Interpreter::Value Interpreter::operator()(BuiltinFunction &node) { - node.function(*this, function_stack); + node.function(*this, m_function_stack); return Interpreter::Value(); } @@ -904,7 +890,7 @@ Interpreter::Value Interpreter::operator()(Callaccept(*this); if(fun.type() != Interpreter::Value::Type::Function) { - error("can not call non-function.", node); + error("can not call non-function", node); return Interpreter::Value(); } auto function = fun.function(); @@ -913,59 +899,18 @@ Interpreter::Value Interpreter::operator()(Callaccept(*this)); } - function_stack.push_back(Interpreter::Value()); + m_function_stack.push_back(Interpreter::Value()); for(size_t i = 1; ichildren[0]->accept(*this); - function->children[1]->accept(*this); - if(!function_stack.empty()) - { - Interpreter::Value result = function_stack.back(); - function_stack.clear(); - return result; - } - else - { - return Interpreter::Value(); - } -} - -Interpreter::Value Interpreter::operator()(MemberCall &node) -{ - Interpreter::Value table = node.children[0]->accept(*this); - if(table.type() != Interpreter::Value::Type::Table) - { - error("can only index tables.", node); - return Interpreter::Value(); - } - Interpreter::Value name = node.children[1]->accept(*this); - Interpreter::Value fun = table.table()->get(name); - if(fun.type() != Interpreter::Value::Type::Function) - { - error("can not call non-function.", node); - return Interpreter::Value(); - } - auto function = fun.function(); - std::vector args; - for(size_t i = 2; iaccept(*this)); - } - function_stack.push_back(table); - for(size_t i = 2; ichildren[0]->accept(*this); function->children[1]->accept(*this); - if(!function_stack.empty()) + if(!m_function_stack.empty()) { - Interpreter::Value result = function_stack.back(); - function_stack.clear(); + Interpreter::Value result = m_function_stack.back(); + m_function_stack.clear(); return result; } else @@ -974,27 +919,6 @@ Interpreter::Value Interpreter::operator()(MemberCall &node) -{ - Interpreter::Value treeval = node.children[0]->accept(*this); - if(treeval.type() != Interpreter::Value::Type::Tree) - { - error("cannot eval non-tree.", node); - return Interpreter::Value(); - } - return treeval.tree()->accept(*this); -} - -Interpreter::Value Interpreter::operator()(Eval &node) -{ - Interpreter::Value treeval = node.children[0]->accept(*this); - if(treeval.type() != Interpreter::Value::Type::Tree) - { - error("cannot eval non-tree.", node); - return Interpreter::Value(); - } - return treeval.tree()->accept(*this); -} Interpreter::Value Interpreter::operator()(Tree &node) { @@ -1022,180 +946,3 @@ Interpreter::Value Interpreter::operator()(Root &node) -{ - Interpreter::Value val = node.children[0]->accept(*this); - if(val.type() != Interpreter::Value::Type::String) - { - error("parse argument needs to be string.", node); - return Interpreter::Value(); - } - return Interpreter::Value(Interpreter::Value::Type::Tree, parser(val.string().begin(), val.string().end())); -} - -Interpreter::Value Interpreter::operator()(ParseExpression &node) -{ - Interpreter::Value val = node.children[0]->accept(*this); - if(val.type() != Interpreter::Value::Type::String) - { - error("parse argument needs to be string.", node); - return Interpreter::Value(); - } - return Interpreter::Value(Interpreter::Value::Type::Tree, parser.parse_expression(val.string().begin(), val.string().end())); -} - -Interpreter::Value Interpreter::operator()(StatementList &node) -{ - for(auto child : node.children) - { - Interpreter::Value result = child->accept(*this); - typename Interpreter::Value::Type t = result.internal_type(); - if(t >= Interpreter::Value::Type::Return && t<= Interpreter::Value::Type::Continue) - { - return result; - } - } - return Interpreter::Value(); -} - -Interpreter::Value Interpreter::operator()(IfStatement &node) -{ - Interpreter::Value cond = node.children[0]->accept(*this); - if(cond.type() != Interpreter::Value::Type::Number) - { - error("if condition not a number.", node); - return Interpreter::Value(); - } - if(cond.number() != 0.0) - { - return node.children[1]->accept(*this); - } - else if(node.children.size()>2) - { - return node.children[2]->accept(*this); - } - return Interpreter::Value(); -} - -Interpreter::Value Interpreter::operator()(WhileStatement &node) -{ - while(true) - { - Interpreter::Value cond = node.children[0]->accept(*this); - if(cond.type() != Interpreter::Value::Type::Number) - { - error("while condition not a number.", node); - } - if(cond == 0.0) - { - break; - } - Interpreter::Value result = node.children[1]->accept(*this); - typename Interpreter::Value::Type t = result.internal_type(); - if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) - { - return result; - } - } - return Interpreter::Value(); -} - -Interpreter::Value Interpreter::operator()(ForStatement &node) -{ - LocalScope(*this); - node.children[0]->accept(*this); - while(true) - { - Interpreter::Value cond = node.children[1]->accept(*this); - if(cond.type() != Interpreter::Value::Type::Number) - { - error("while condition not a number.", node); - } - if(cond == 0.0) - { - break; - } - Interpreter::Value result = node.children[3]->accept(*this); - typename Interpreter::Value::Type t = result.internal_type(); - if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) - { - return result; - } - node.children[2]->accept(*this); - } - return Interpreter::Value(); -} - -Interpreter::Value Interpreter::operator()(ForEachStatement &node) -{ - if(node.children.size()==3) - { - Interpreter::Value value = node.children[0]->accept(*this); - Interpreter::Value table = node.children[1]->accept(*this); - Interpreter::Value::Type t = table.type(); - if(t != Interpreter::Value::Type::Table && t != Interpreter::Value::Type::Array) - { - error("for each argument is not a table or array", node); - } - LocalScope local(*this); - if(t == Interpreter::Value::Type::Table) - { - for(auto entry : *table.table()) - { - setLocal(value, entry.second); - Interpreter::Value result = node.children[2]->accept(*this); - typename Interpreter::Value::Type result_t = result.internal_type(); - if(result_t == Interpreter::Value::Type::Break || result_t == Interpreter::Value::Type::Return) - { - return result; - } - } - } - else - { - for(auto entry : *table.array()) - { - setLocal(value, entry); - Interpreter::Value result = node.children[2]->accept(*this); - typename Interpreter::Value::Type result_t = result.type(); - if(result_t == Interpreter::Value::Type::Break || result_t == Interpreter::Value::Type::Return) - { - return result; - } - } - } - } - else - { - Interpreter::Value key = node.children[0]->accept(*this); - Interpreter::Value value = node.children[1]->accept(*this); - Interpreter::Value table = node.children[2]->accept(*this); - if(table.type() != Interpreter::Value::Type::Table) - { - error("for each argument is not a table", node); - } - LocalScope local(*this); - for(auto entry : *table.table()) - { - setLocal(key, entry.first); - setLocal(value, entry.second); - Interpreter::Value result = node.children[3]->accept(*this); - typename Interpreter::Value::Type t = result.type(); - if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) - { - return result; - } - } - } - return Interpreter::Value(); -} - -Interpreter::Value Interpreter::operator()(ContinueStatement &) -{ - return Interpreter::Value(typename Interpreter::Value::TagContinue()); -} - -Interpreter::Value Interpreter::operator()(BreakStatement &) -{ - return Interpreter::Value(typename Interpreter::Value::TagBreak()); -} diff --git a/src/ops.member.cpp b/src/ops.member.cpp new file mode 100644 index 0000000..d023d98 --- /dev/null +++ b/src/ops.member.cpp @@ -0,0 +1,69 @@ + +#include +#include "private.h" +#include "builtin.h" +using namespace Internal; + +// this function is dangerously close to turning really awfully hacky! + +static std::string no_such_index(Interpreter::Value& self, Interpreter::Value& name) +{ + std::stringstream strm; + strm << "cannot find index '" << name << "' for type <" << self.typeName() << ">"; + return strm.str(); +} + +Interpreter::Value Interpreter::operator()(MemberCall &node) +{ + Interpreter::Value table = node.children[0]->accept(*this); + Interpreter::Value name = node.children[1]->accept(*this); + std::cerr << "MemberCall: name = " << name << std::endl; + if(table.type() == Interpreter::Value::Type::Table) + { + // nop + } + else if((table.type() == Interpreter::Value::Type::String) && BUILTIN_EXISTS(string, name.string())) + { + // add string member functions ... + return BUILTIN_GET(string, name.string())(*this, table); + } + else if((table.type() == Interpreter::Value::Type::Array) && BUILTIN_EXISTS(array, name.string())) + { + return BUILTIN_GET(array, name.string())(*this, table); + } + else + { + error(no_such_index(table, name), node); + return Interpreter::Value(); + } + Interpreter::Value fun = table.table()->get(name); + if(fun.type() != Interpreter::Value::Type::Function) + { + error("can not call non-function", node); + return Interpreter::Value(); + } + auto function = fun.function(); + std::vector args; + for(size_t i = 2; iaccept(*this)); + } + m_function_stack.push_back(table); + for(size_t i = 2; ichildren[0]->accept(*this); + function->children[1]->accept(*this); + if(!m_function_stack.empty()) + { + Interpreter::Value result = m_function_stack.back(); + m_function_stack.clear(); + return result; + } + else + { + return Interpreter::Value(); + } +} diff --git a/src/ops.statement.cpp b/src/ops.statement.cpp new file mode 100644 index 0000000..dacfb93 --- /dev/null +++ b/src/ops.statement.cpp @@ -0,0 +1,223 @@ + +#include "private.h" +using namespace Internal; + + +Interpreter::Value Interpreter::operator()(ExpressionStatement &node) +{ + return node.children[0]->accept(*this); +} + +Interpreter::Value Interpreter::operator()(ReturnStatement &node) +{ + if(node.children.size()>0) + { + m_function_stack.push_back(node.children[0]->accept(*this)); + } + return Interpreter::Value(typename Interpreter::Value::TagReturn()); +} + +Interpreter::Value Interpreter::operator()(EvalStatement &node) +{ + Interpreter::Value treeval = node.children[0]->accept(*this); + if(treeval.type() != Interpreter::Value::Type::Tree) + { + error("cannot eval non-tree.", node); + return Interpreter::Value(); + } + return treeval.tree()->accept(*this); +} + +Interpreter::Value Interpreter::operator()(Eval &node) +{ + Interpreter::Value treeval = node.children[0]->accept(*this); + if(treeval.type() != Interpreter::Value::Type::Tree) + { + error("cannot eval non-tree.", node); + return Interpreter::Value(); + } + return treeval.tree()->accept(*this); +} + + +Interpreter::Value Interpreter::operator()(ParseStatement &node) +{ + Interpreter::Value val = node.children[0]->accept(*this); + if(val.type() != Interpreter::Value::Type::String) + { + error("parse argument needs to be string.", node); + return Interpreter::Value(); + } + return Interpreter::Value(Interpreter::Value::Type::Tree, m_parser(val.string().begin(), val.string().end())); +} + +Interpreter::Value Interpreter::operator()(ParseExpression &node) +{ + Interpreter::Value val = node.children[0]->accept(*this); + if(val.type() != Interpreter::Value::Type::String) + { + error("parse argument needs to be string.", node); + return Interpreter::Value(); + } + return Interpreter::Value(Interpreter::Value::Type::Tree, m_parser.parse_expression( + val.string().begin(), val.string().end())); +} + + +Interpreter::Value Interpreter::operator()(StatementList &node) +{ + for(auto child : node.children) + { + Interpreter::Value result = child->accept(*this); + typename Interpreter::Value::Type t = result.internal_type(); + if(t >= Interpreter::Value::Type::Return && t<= Interpreter::Value::Type::Continue) + { + return result; + } + } + return Interpreter::Value(); +} + +Interpreter::Value Interpreter::operator()(IfStatement &node) +{ + Interpreter::Value cond = node.children[0]->accept(*this); + if(cond.type() != Interpreter::Value::Type::Number) + { + error("if condition not a number.", node); + return Interpreter::Value(); + } + if(cond.number() != 0.0) + { + return node.children[1]->accept(*this); + } + else if(node.children.size()>2) + { + return node.children[2]->accept(*this); + } + return Interpreter::Value(); +} + +Interpreter::Value Interpreter::operator()(WhileStatement &node) +{ + while(true) + { + Interpreter::Value cond = node.children[0]->accept(*this); + if(cond.type() != Interpreter::Value::Type::Number) + { + error("while condition not a number.", node); + } + if(cond == 0.0) + { + break; + } + Interpreter::Value result = node.children[1]->accept(*this); + typename Interpreter::Value::Type t = result.internal_type(); + if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) + { + return result; + } + } + return Interpreter::Value(); +} + +Interpreter::Value Interpreter::operator()(ForStatement &node) +{ + LocalScope(*this); + node.children[0]->accept(*this); + while(true) + { + Interpreter::Value cond = node.children[1]->accept(*this); + if(cond.type() != Interpreter::Value::Type::Number) + { + error("while condition not a number.", node); + } + if(cond == 0.0) + { + break; + } + Interpreter::Value result = node.children[3]->accept(*this); + typename Interpreter::Value::Type t = result.internal_type(); + if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) + { + return result; + } + node.children[2]->accept(*this); + } + return Interpreter::Value(); +} + +Interpreter::Value Interpreter::operator()(ForEachStatement &node) +{ + if(node.children.size()==3) + { + Interpreter::Value value = node.children[0]->accept(*this); + Interpreter::Value table = node.children[1]->accept(*this); + Interpreter::Value::Type t = table.type(); + if(t != Interpreter::Value::Type::Table && t != Interpreter::Value::Type::Array) + { + error("for each argument is not a table or array", node); + } + LocalScope local(*this); + if(t == Interpreter::Value::Type::Table) + { + for(auto entry : *table.table()) + { + setLocal(value, entry.second); + Interpreter::Value result = node.children[2]->accept(*this); + typename Interpreter::Value::Type result_t = result.internal_type(); + if(result_t == Interpreter::Value::Type::Break || result_t == Interpreter::Value::Type::Return) + { + return result; + } + } + } + else + { + for(auto entry : *table.array()) + { + setLocal(value, entry); + Interpreter::Value result = node.children[2]->accept(*this); + typename Interpreter::Value::Type result_t = result.type(); + if(result_t == Interpreter::Value::Type::Break || result_t == Interpreter::Value::Type::Return) + { + return result; + } + } + } + } + else + { + Interpreter::Value key = node.children[0]->accept(*this); + Interpreter::Value value = node.children[1]->accept(*this); + Interpreter::Value table = node.children[2]->accept(*this); + if(table.type() != Interpreter::Value::Type::Table) + { + error("for each argument is not a table", node); + } + LocalScope local(*this); + for(auto entry : *table.table()) + { + setLocal(key, entry.first); + setLocal(value, entry.second); + Interpreter::Value result = node.children[3]->accept(*this); + typename Interpreter::Value::Type t = result.type(); + if(t == Interpreter::Value::Type::Break || t == Interpreter::Value::Type::Return) + { + return result; + } + } + } + return Interpreter::Value(); +} + +Interpreter::Value Interpreter::operator()(ContinueStatement &) +{ + return Interpreter::Value(typename Interpreter::Value::TagContinue()); +} + +Interpreter::Value Interpreter::operator()(BreakStatement &) +{ + return Interpreter::Value(typename Interpreter::Value::TagBreak()); +} + + diff --git a/src/parser.h b/src/parser.h deleted file mode 100644 index ce2e7e7..0000000 --- a/src/parser.h +++ /dev/null @@ -1,2 +0,0 @@ - -//! todo: this is where the parser could (should?) go. maybe. diff --git a/src/private.h b/src/private.h index 7a489b9..9f868e1 100644 --- a/src/private.h +++ b/src/private.h @@ -1,15 +1,5 @@ -#pragma once #include "jtc.h" -#include "parser.h" - -/* -template bool isint(T x) -{ - return x == std::trunc(x); -} -*/ - //! todo: create a wrapper method ... //namespace Stdlib diff --git a/src/stdlib.file.cpp b/src/stdlib.file.cpp index e4595cf..76158c2 100644 --- a/src/stdlib.file.cpp +++ b/src/stdlib.file.cpp @@ -5,15 +5,13 @@ #define ID_HANDLE Interpreter::Value(Interpreter::Value::NumberType('h')) -static std::ios_base::openmode make_mode(const std::string& str) +static void make_mode(const std::string& str, std::ios_base::openmode& dest) { // laaaaazy - std::ios_base::openmode mode; if(str == "r") { - mode = mode | std::ios::in; + dest = std::ios::in; } - return mode; } void rt_file_read(Interpreter& ip, std::vector& stack) @@ -33,7 +31,7 @@ void rt_file_read(Interpreter& ip, std::vector& stack) return; } -void rt_file_close(Interpreter& ip, std::vector& stack) +void rt_file_close(Interpreter&, std::vector& stack) { auto self = stack[0].table(); auto fh = (std::fstream*)self->get(ID_HANDLE).userptr(); @@ -46,6 +44,7 @@ void rt_file_constructor(Interpreter& ip, std::vector& stack std::string path; std::string mode; std::ios_base::openmode realmode; + realmode = std::ios::in; Table self; if(stack.empty()) { @@ -54,7 +53,7 @@ void rt_file_constructor(Interpreter& ip, std::vector& stack } path = stack[1].string(); mode = stack[2].string(); - realmode = make_mode(mode); + make_mode(mode, realmode); fh = new std::fstream(path, realmode); if(fh->good()) { -- 2.11.4.GIT