diff --git a/code/sum.vs b/code/sum.vs new file mode 100644 index 0000000..5312cd3 --- /dev/null +++ b/code/sum.vs @@ -0,0 +1,10 @@ +func sum(init, *args) { + var res = init; + for (var i = 0; i < args.len(); i += 1) { + res += args[i]; + } + return res; +} + +print(sum(0)); +print(sum(1, 2, 3)); \ No newline at end of file diff --git a/grm/grammar.txt b/grm/grammar.txt index 839b9ff..a1b4028 100644 --- a/grm/grammar.txt +++ b/grm/grammar.txt @@ -64,6 +64,8 @@ set_declaration:L_CURLY value_list_expression R_CURLY anony_function_declaration:LAMBDA L_PAREN R_PAREN compound_statement anony_function_declaration:LAMBDA L_PAREN parameter_list R_PAREN compound_statement +anony_function_declaration:LAMBDA L_PAREN MUL IDENTIFIER R_PAREN compound_statement +anony_function_declaration:LAMBDA L_PAREN parameter_list COMMA MUL IDENTIFIER R_PAREN compound_statement assignment_operator:ASSIGN assignment_operator:MUL_ASSIGN @@ -97,6 +99,8 @@ parameter_list:parameter_list COMMA IDENTIFIER function_declaration:FUNC IDENTIFIER L_PAREN R_PAREN compound_statement function_declaration:FUNC IDENTIFIER L_PAREN parameter_list R_PAREN compound_statement +function_declaration:FUNC IDENTIFIER L_PAREN MUL IDENTIFIER R_PAREN compound_statement +function_declaration:FUNC IDENTIFIER L_PAREN parameter_list COMMA MUL IDENTIFIER R_PAREN compound_statement elif_statement:ELIF L_PAREN logical_or_expression R_PAREN compound_statement elif_statement:elif_statement ELIF L_PAREN logical_or_expression R_PAREN compound_statement diff --git a/inc/compiler/VSASTNode.hpp b/inc/compiler/VSASTNode.hpp index 75aa6ba..2085590 100644 --- a/inc/compiler/VSASTNode.hpp +++ b/inc/compiler/VSASTNode.hpp @@ -282,11 +282,13 @@ class InitDeclListNode : public VSASTNode { class FuncDeclNode : public VSASTNode { public: + bool va_args; IdentNode *name; std::vector args; VSASTNode *body; FuncDeclNode(IdentNode *name) : name(name) { + this->va_args = false; this->node_type = name != NULL ? AST_FUNC_DECL : AST_LAMBDA_DECL; this->args = std::vector(); this->body = NULL; diff --git a/inc/objects/VSCodeObject.hpp b/inc/objects/VSCodeObject.hpp index 6a729a2..386af20 100644 --- a/inc/objects/VSCodeObject.hpp +++ b/inc/objects/VSCodeObject.hpp @@ -20,11 +20,14 @@ class VSInst { VSInst &operator=(VSInst &inst); }; +#define VS_FUNC_VARARGS 0x1 + class VSCodeObject : public VSObject { private: static const str_func_map vs_code_methods; public: + int flags; vs_size_t ninsts; vs_size_t nconsts; vs_size_t nargs; diff --git a/inc/objects/VSFunctionObject.hpp b/inc/objects/VSFunctionObject.hpp index 650a94a..a3881d0 100644 --- a/inc/objects/VSFunctionObject.hpp +++ b/inc/objects/VSFunctionObject.hpp @@ -35,8 +35,6 @@ class VSNativeFunctionObject : public VSFunctionObject { VSObject *call(VSTupleObject *args) override; }; -#define VS_FUNC_VARARGS 0x1 - class VSDynamicFunctionObject : public VSFunctionObject { private: static const str_func_map vs_dynamic_func_methods; diff --git a/src/compiler/VSCompiler.cpp b/src/compiler/VSCompiler.cpp index e60842a..b305f3f 100644 --- a/src/compiler/VSCompiler.cpp +++ b/src/compiler/VSCompiler.cpp @@ -626,6 +626,9 @@ void VSCompiler::gen_func_decl(VSASTNode *node) { // Add function code to parent code consts. VSCodeObject *code = this->codeobjects.top(); + // Set flags. + code->flags |= func->va_args ? VS_FUNC_VARARGS : 0; + // Add function arg names to function locals. for (auto argnode : func->args) { VSObject *argname; diff --git a/src/compiler/VSParser.cpp b/src/compiler/VSParser.cpp index 3c158f2..08af9fb 100644 --- a/src/compiler/VSParser.cpp +++ b/src/compiler/VSParser.cpp @@ -96,22 +96,33 @@ VSToken *VSParser::expect(int ntypes, ...) { void VSParser::read_func_def(FuncDeclNode *func) { // read func args ENSURE_TOKEN(); + if (PEEKTOKEN()->tk_type != TK_R_PAREN) { - VSToken *token = this->expect(1, TK_IDENTIFIER); - if (token != NULL) { - IdentNode *arg = new IdentNode(token->literal); - func->add_arg(arg); + VSToken *token = NULL; + while (PEEKTOKEN()->tk_type == TK_IDENTIFIER) + { + token = GETTOKEN(); + if (token != NULL) { + IdentNode *arg = new IdentNode(token->literal); + func->add_arg(arg); + } + + ENSURE_TOKEN(); + if (PEEKTOKEN()->tk_type != TK_COMMA) { + break; + } + POPTOKEN(1, TK_COMMA); } ENSURE_TOKEN(); - while (PEEKTOKEN()->tk_type == TK_COMMA) { - POPTOKEN(1, TK_COMMA); + if (PEEKTOKEN()->tk_type == TK_MUL) { + POPTOKEN(1, TK_MUL); token = this->expect(1, TK_IDENTIFIER); if (token != NULL) { + func->va_args = true; IdentNode *arg = new IdentNode(token->literal); func->add_arg(arg); } - ENSURE_TOKEN(); } } POPTOKEN(1, TK_R_PAREN); diff --git a/src/objects/VSCodeObject.cpp b/src/objects/VSCodeObject.cpp index b6b23ff..48afe53 100644 --- a/src/objects/VSCodeObject.cpp +++ b/src/objects/VSCodeObject.cpp @@ -57,6 +57,7 @@ VSCodeObject::VSCodeObject(VSStringObject *name) { this->name = name; INCREF(name); + this->flags = 0; this->ninsts = 0; this->nconsts = 0; this->nargs = 0; diff --git a/src/objects/VSFrameObject.cpp b/src/objects/VSFrameObject.cpp index 46276e1..f24d95d 100644 --- a/src/objects/VSFrameObject.cpp +++ b/src/objects/VSFrameObject.cpp @@ -76,7 +76,15 @@ VSFrameObject::VSFrameObject(VSCodeObject *code, VSTupleObject *args, VSTupleObj this->locals = new VSTupleObject(this->nlocals); for (vs_size_t i = 0; i < this->nlocals; i++) { if (i < code->nargs) { - TUPLE_SET(this->locals, i, new VSCellObject(TUPLE_GET(args, i))); + if (i < code->nargs - 1 || !(code->flags & VS_FUNC_VARARGS)) { + TUPLE_SET(this->locals, i, new VSCellObject(TUPLE_GET(args, i))); + } else { + VSTupleObject *va_args = new VSTupleObject(TUPLE_LEN(args) - code->nargs + 1); + for (vs_size_t j = i; j < TUPLE_LEN(args); j++) { + TUPLE_SET(va_args, j - i, TUPLE_GET(args, j)); + } + TUPLE_SET(this->locals, i, new VSCellObject(va_args)); + } } else { TUPLE_SET(this->locals, i, new VSCellObject(VS_NONE)); } @@ -564,11 +572,12 @@ void VSFrameObject::eval(std::stack &stack) { break; } case OP_BUILD_FUNC: { - VSObject *code = STACK_POP(stack); + VSObject *codeobj = STACK_POP(stack); VSObject *freevars = STACK_POP(stack); + VSCodeObject *code = (VSCodeObject *)codeobj; VSFunctionObject *func = new VSDynamicFunctionObject( - AS_CODE(code)->name, AS_CODE(code), AS_TUPLE(freevars), this->builtins, 0); + code->name, code, AS_TUPLE(freevars), this->builtins, code->flags); STACK_PUSH_INCREF(stack, func); DECREF(freevars); DECREF(code); diff --git a/src/objects/VSFunctionObject.cpp b/src/objects/VSFunctionObject.cpp index 4ed6177..b278e22 100644 --- a/src/objects/VSFunctionObject.cpp +++ b/src/objects/VSFunctionObject.cpp @@ -174,7 +174,12 @@ void VSDynamicFunctionObject::setattr(std::string &, VSObject *) { VSObject *VSDynamicFunctionObject::call(VSTupleObject *args) { assert(args != NULL); vs_size_t nargs = TUPLE_LEN(args); - if (nargs < this->code->nargs || (nargs > this->code->nargs && !(VS_FUNC_VARARGS & this->flags))) { + bool va_args = VS_FUNC_VARARGS & this->flags; + + if (va_args && nargs < this->code->nargs - 1) { + ERR_NARGS(this->name->_value.c_str(), this->code->nargs - 1, nargs); + terminate(TERM_ERROR); + } else if (!va_args && nargs != this->code->nargs) { ERR_NARGS(this->name->_value.c_str(), this->code->nargs, nargs); terminate(TERM_ERROR); }