diff --git a/src/context.cc b/src/context.cc index 74dfc3cd..567cdbca 100644 --- a/src/context.cc +++ b/src/context.cc @@ -121,6 +121,13 @@ void Context::set_constant(const std::string &name, const Value &value) set_constant(name, ValuePtr(value)); } +void Context::apply_variables(const Context &other) +{ + for (ValueMap::const_iterator it = other.variables.begin();it != other.variables.end();it++) { + set_variable((*it).first, (*it).second); + } +} + ValuePtr Context::lookup_variable(const std::string &name, bool silent) const { if (!this->ctx_stack) { diff --git a/src/context.h b/src/context.h index 696eaa85..f3b1bcc0 100644 --- a/src/context.h +++ b/src/context.h @@ -26,6 +26,7 @@ public: void set_constant(const std::string &name, const ValuePtr &value); void set_constant(const std::string &name, const Value &value); + void apply_variables(const Context &other); ValuePtr lookup_variable(const std::string &name, bool silent = false) const; bool has_local_variable(const std::string &name) const; diff --git a/src/func.cc b/src/func.cc index ed03fac8..96a7b887 100644 --- a/src/func.cc +++ b/src/func.cc @@ -84,6 +84,11 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string return dump.str(); } +Function::Function(const char *name, AssignmentList &definition_arguments, Expression *expr) + : name(name), definition_arguments(definition_arguments), expr(expr) +{ +} + Function::~Function() { delete expr; @@ -113,6 +118,66 @@ std::string Function::dump(const std::string &indent, const std::string &name) c return dump.str(); } +class FunctionTailRecursion : public Function +{ +private: + bool invert; + ExpressionFunctionCall *call; // memory owned by the main expression + Expression *endexpr; // memory owned by the main expression + +public: + FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert); + virtual ~FunctionTailRecursion(); + + virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const; +}; + +FunctionTailRecursion::FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert) + : Function(name, definition_arguments, expr), invert(invert), call(call), endexpr(endexpr) +{ +} + +FunctionTailRecursion::~FunctionTailRecursion() +{ +} + +ValuePtr FunctionTailRecursion::evaluate(const Context *ctx, const EvalContext *evalctx) const +{ + if (!expr) return ValuePtr::undefined; + + Context c(ctx); + c.setVariables(definition_arguments, evalctx); + + EvalContext ec(&c, call->call_arguments); + while (invert ^ expr->first->evaluate(&c)) { + Context tmp; + tmp.setVariables(definition_arguments, &ec); + c.apply_variables(tmp); + } + + ValuePtr result = endexpr->evaluate(&c); + + return result; +} + +Function * Function::create(const char *name, AssignmentList &definition_arguments, Expression *expr) +{ + if (dynamic_cast(expr)) { + ExpressionFunctionCall *f1 = dynamic_cast(expr->second); + ExpressionFunctionCall *f2 = dynamic_cast(expr->third); + if (f1 && !f2) { + if (name == f1->funcname) { + return new FunctionTailRecursion(name, definition_arguments, expr, f1, expr->third, false); + } + } else if (f2 && !f1) { + if (name == f2->funcname) { + return new FunctionTailRecursion(name, definition_arguments, expr, f2, expr->second, true); + } + } + } + return new Function(name, definition_arguments, expr); +} + BuiltinFunction::~BuiltinFunction() { } diff --git a/src/function.h b/src/function.h index 48496518..c9449c74 100644 --- a/src/function.h +++ b/src/function.h @@ -38,13 +38,16 @@ public: class Function : public AbstractFunction { public: + std::string name; AssignmentList definition_arguments; Expression *expr; - Function() { } + Function(const char *name, AssignmentList &definition_arguments, Expression *expr); virtual ~Function(); virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; + + static Function * create(const char *name, AssignmentList &definition_arguments, Expression *expr); }; diff --git a/src/parser.y b/src/parser.y index dfa1ab2e..73c07504 100644 --- a/src/parser.y +++ b/src/parser.y @@ -166,9 +166,7 @@ statement: } | TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { - Function *func = new Function(); - func->definition_arguments = *$4; - func->expr = $8; + Function *func = Function::create($2, *$4, $8); scope_stack.top()->functions[$2] = func; free($2); delete $4;