From dc8f559b85c022d1b6db05c93510e4faef0af7a3 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Mon, 24 Nov 2014 23:37:42 +0100 Subject: [PATCH] Use class hierarchy for the different types of expressions. --- src/builtin.cc | 14 +- src/expr.cc | 743 ++++++++++++++++++++++++----------------------- src/expression.h | 271 ++++++++++++----- src/func.cc | 8 +- src/openscad.cc | 3 + src/parser.y | 79 +++-- 6 files changed, 628 insertions(+), 490 deletions(-) diff --git a/src/builtin.cc b/src/builtin.cc index b04d2b53..76b76b90 100644 --- a/src/builtin.cc +++ b/src/builtin.cc @@ -94,19 +94,19 @@ std::string Builtins::isDeprecated(const std::string &name) Builtins::Builtins() { - this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr(new Expression(ValuePtr(0.0))))); - this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr(new Expression(ValuePtr(2.0))))); - this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr(new Expression(ValuePtr(12.0))))); - this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr(new Expression(ValuePtr(0.0))))); + this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr(new ExpressionConst(ValuePtr(0.0))))); + this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr(new ExpressionConst(ValuePtr(2.0))))); + this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr(new ExpressionConst(ValuePtr(12.0))))); + this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr(new ExpressionConst(ValuePtr(0.0))))); Value::VectorType zero3; zero3.push_back(Value(0.0)); zero3.push_back(Value(0.0)); zero3.push_back(Value(0.0)); ValuePtr zero3val(zero3); - this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr(new Expression(zero3val)))); - this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr(new Expression(zero3val)))); - this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr(new Expression(ValuePtr(500))))); + this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr(new ExpressionConst(zero3val)))); + this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr(new ExpressionConst(zero3val)))); + this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr(new ExpressionConst(ValuePtr(500))))); } Builtins::~Builtins() diff --git a/src/expr.cc b/src/expr.cc index eb0c27d2..2be6e6cb 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -23,7 +23,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - #include "expression.h" #include "value.h" #include "evalcontext.h" @@ -32,14 +31,10 @@ #include #include "stl-utils.h" #include "printutils.h" +#include "stackcheck.h" #include #include -ExpressionEvaluator * Expression::evaluators[256]; - -// static initializer for the expression evaluator lookup table -ExpressionEvaluatorInit Expression::evaluatorInit; - // unnamed namespace namespace { Value::VectorType flatten(Value::VectorType const& vec) { @@ -71,358 +66,49 @@ namespace { } } -class ExpressionEvaluatorAbort : public ExpressionEvaluator +Expression::Expression() { - ValuePtr evaluate(const class Expression *, const class Context *) const { - abort(); - } -}; - -class ExpressionEvaluatorNot : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return ! expr->children[0]->evaluate(context); - } -}; - -class ExpressionEvaluatorLogicalAnd : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) && expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorLogicalOr : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) || expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorMultiply : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) * expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorDivision : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) / expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorModulo : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) % expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorPlus : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) + expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorMinus : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) - expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorLess : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) < expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorLessOrEqual : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) <= expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorEqual : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) == expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorNotEqual : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children.at(0)->evaluate(context) != expr->children.at(1)->evaluate(context); - } -}; - -class ExpressionEvaluatorGreaterOrEqual : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) >= expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorGreater : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context) > expr->children[1]->evaluate(context); - } -}; - -class ExpressionEvaluatorTernary : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[expr->children[0]->evaluate(context) ? 1 : 2]->evaluate(context); - } -}; - -class ExpressionEvaluatorArray : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context)[expr->children[1]->evaluate(context)]; - } -}; - -class ExpressionEvaluatorInvert : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return -expr->children[0]->evaluate(context); - } -}; - -class ExpressionEvaluatorConst : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *) const { - return ValuePtr(expr->const_value); - } -}; - -class ExpressionEvaluatorRange : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - ValuePtr v1 = expr->children[0]->evaluate(context); - if (v1->type() == Value::NUMBER) { - ValuePtr v2 = expr->children[1]->evaluate(context); - if (v2->type() == Value::NUMBER) { - if (expr->children.size() == 2) { - Value::RangeType range(v1->toDouble(), v2->toDouble()); - return ValuePtr(range); - } else { - ValuePtr v3 = expr->children[2]->evaluate(context); - if (v3->type() == Value::NUMBER) { - Value::RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble()); - return ValuePtr(range); - } - } - } - } - return ValuePtr::undefined; - } -}; - -class ExpressionEvaluatorVector : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - Value::VectorType vec; - BOOST_FOREACH(const Expression *e, expr->children) { - vec.push_back(*(e->evaluate(context))); - } - return ValuePtr(vec); - } -}; - -class ExpressionEvaluatorLookup : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return context->lookup_variable(expr->var_name); - } -}; - -class ExpressionEvaluatorMember : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - ValuePtr v = expr->children[0]->evaluate(context); - - if (v->type() == Value::VECTOR) { - if (expr->var_name == "x") return v[0]; - if (expr->var_name == "y") return v[1]; - if (expr->var_name == "z") return v[2]; - } else if (v->type() == Value::RANGE) { - if (expr->var_name == "begin") return v[0]; - if (expr->var_name == "step") return v[1]; - if (expr->var_name == "end") return v[2]; - } - return ValuePtr::undefined; - } -}; - -static void function_recursion_detected(const char *func) -{ - PRINTB("ERROR: Recursion detected calling function '%s'", func); } -class ExpressionEvaluatorFunction : public ExpressionEvaluator +Expression::Expression(const ValuePtr &val) { - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - if (expr->recursioncount >= 1000) { - function_recursion_detected(expr->call_funcname.c_str()); - // TO DO: throw function_recursion_detected(); - return ValuePtr::undefined; - } - expr->recursioncount += 1; - EvalContext *c = new EvalContext(context, expr->call_arguments); - ValuePtr result = context->evaluate_function(expr->call_funcname, c); - delete c; - expr->recursioncount -= 1; - return result; - } -}; - -class ExpressionEvaluatorLet : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - Context c(context); - evaluate_sequential_assignment(expr->call_arguments, &c); - - return expr->children[0]->evaluate(&c); - } -}; - -class ExpressionEvaluatorLcExpression : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - return expr->children[0]->evaluate(context); - } -}; - -class ExpressionEvaluatorLc : public ExpressionEvaluator -{ - ValuePtr evaluate(const class Expression *expr, const class Context *context) const { - Value::VectorType vec; - - if (expr->call_funcname == "if") { - if (expr->children[0]->evaluate(context)) { - if (expr->children[1]->type == EXPRESSION_TYPE_LC) { - return expr->children[1]->evaluate(context); - } else { - vec.push_back((*expr->children[1]->evaluate(context))); - } - } - return ValuePtr(vec); - } else if (expr->call_funcname == "for") { - EvalContext for_context(context, expr->call_arguments); - - Context assign_context(context); - - // comprehension for statements are by the parser reduced to only contain one single element - const std::string &it_name = for_context.getArgName(0); - ValuePtr it_values = for_context.getArgValue(0, &assign_context); - - Context c(context); - - if (it_values->type() == Value::RANGE) { - Value::RangeType range = it_values->toRange(); - boost::uint32_t steps = range.nbsteps(); - if (steps >= 1000000) { - PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps); - } else { - for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { - c.set_variable(it_name, ValuePtr(*it)); - vec.push_back((*expr->children[0]->evaluate(&c))); - } - } - } - else if (it_values->type() == Value::VECTOR) { - for (size_t i = 0; i < it_values->toVector().size(); i++) { - c.set_variable(it_name, it_values->toVector()[i]); - vec.push_back((*expr->children[0]->evaluate(&c))); - } - } - else if (it_values->type() != Value::UNDEFINED) { - c.set_variable(it_name, it_values); - vec.push_back((*expr->children[0]->evaluate(&c))); - } - if (expr->children[0]->type == EXPRESSION_TYPE_LC) { - return ValuePtr(flatten(vec)); - } else { - return ValuePtr(vec); - } - } else if (expr->call_funcname == "let") { - Context c(context); - evaluate_sequential_assignment(expr->call_arguments, &c); - - return expr->children[0]->evaluate(&c); - } else { - abort(); - } - } -}; - -ExpressionEvaluatorInit::ExpressionEvaluatorInit() -{ - ExpressionEvaluator *abort = new ExpressionEvaluatorAbort(); - for (int a = 0;a < 256;a++) { - Expression::evaluators[a] = abort; - } - - Expression::evaluators[EXPRESSION_TYPE_NOT] = new ExpressionEvaluatorNot(); - Expression::evaluators[EXPRESSION_TYPE_LOGICAL_AND] = new ExpressionEvaluatorLogicalAnd(); - Expression::evaluators[EXPRESSION_TYPE_LOGICAL_OR] = new ExpressionEvaluatorLogicalOr(); - Expression::evaluators[EXPRESSION_TYPE_MULTIPLY] = new ExpressionEvaluatorMultiply(); - Expression::evaluators[EXPRESSION_TYPE_DIVISION] = new ExpressionEvaluatorDivision(); - Expression::evaluators[EXPRESSION_TYPE_MODULO] = new ExpressionEvaluatorModulo(); - Expression::evaluators[EXPRESSION_TYPE_PLUS] = new ExpressionEvaluatorPlus(); - Expression::evaluators[EXPRESSION_TYPE_MINUS] = new ExpressionEvaluatorMinus(); - Expression::evaluators[EXPRESSION_TYPE_LESS] = new ExpressionEvaluatorLess(); - Expression::evaluators[EXPRESSION_TYPE_LESS_OR_EQUAL] = new ExpressionEvaluatorLessOrEqual(); - Expression::evaluators[EXPRESSION_TYPE_EQUAL] = new ExpressionEvaluatorEqual(); - Expression::evaluators[EXPRESSION_TYPE_NOT_EQUAL] = new ExpressionEvaluatorNotEqual(); - Expression::evaluators[EXPRESSION_TYPE_GREATER_OR_EQUAL] = new ExpressionEvaluatorGreaterOrEqual(); - Expression::evaluators[EXPRESSION_TYPE_GREATER] = new ExpressionEvaluatorGreater(); - Expression::evaluators[EXPRESSION_TYPE_TERNARY] = new ExpressionEvaluatorTernary(); - Expression::evaluators[EXPRESSION_TYPE_ARRAY_ACCESS] = new ExpressionEvaluatorArray(); - Expression::evaluators[EXPRESSION_TYPE_INVERT] = new ExpressionEvaluatorInvert(); - Expression::evaluators[EXPRESSION_TYPE_CONST] = new ExpressionEvaluatorConst(); - Expression::evaluators[EXPRESSION_TYPE_RANGE] = new ExpressionEvaluatorRange(); - Expression::evaluators[EXPRESSION_TYPE_VECTOR] = new ExpressionEvaluatorVector(); - Expression::evaluators[EXPRESSION_TYPE_LOOKUP] = new ExpressionEvaluatorLookup(); - Expression::evaluators[EXPRESSION_TYPE_MEMBER] = new ExpressionEvaluatorMember(); - Expression::evaluators[EXPRESSION_TYPE_FUNCTION] = new ExpressionEvaluatorFunction(); - Expression::evaluators[EXPRESSION_TYPE_LET] = new ExpressionEvaluatorLet(); - Expression::evaluators[EXPRESSION_TYPE_LC_EXPRESSION] = new ExpressionEvaluatorLcExpression(); - Expression::evaluators[EXPRESSION_TYPE_LC] = new ExpressionEvaluatorLc(); + const_value = val; } -Expression::Expression(const unsigned char type) : recursioncount(0) +Expression::Expression(const std::string &val) { - setType(type); + var_name = val; } -Expression::Expression(const unsigned char type, Expression *left, Expression *right) - : recursioncount(0) +Expression::Expression(const std::string &val, Expression *expr) { - setType(type); - this->children.push_back(left); - this->children.push_back(right); + var_name = val; + children.push_back(expr); + first = expr; } -Expression::Expression(const unsigned char type, Expression *expr) - : recursioncount(0) +Expression::Expression(Expression *expr) { - setType(type); - this->children.push_back(expr); + children.push_back(expr); + first = expr; } -Expression::Expression(const ValuePtr &val) : const_value(val), recursioncount(0) +Expression::Expression(Expression *left, Expression *right) { - setType(EXPRESSION_TYPE_CONST); + children.push_back(left); + children.push_back(right); + first = left; + second = right; +} + +Expression::Expression(Expression *expr1, Expression *expr2, Expression *expr3) +{ + children.push_back(expr1); + children.push_back(expr2); + children.push_back(expr3); + first = expr1; + second = expr2; + third = expr3; } Expression::~Expression() @@ -430,20 +116,6 @@ Expression::~Expression() std::for_each(this->children.begin(), this->children.end(), del_fun()); } -void Expression::setType(const unsigned char type) -{ - this->type = type; - this->evaluator = evaluators[type]; -} - -ValuePtr Expression::evaluate(const Context *context) const -{ - char _c; - context->checkStack(&_c); - - return evaluator->evaluate(this, context); -} - namespace /* anonymous*/ { std::ostream &operator << (std::ostream &o, AssignmentList const& l) { @@ -458,10 +130,15 @@ namespace /* anonymous*/ { } +bool Expression::isListComprehension() +{ + return false; +} + std::string Expression::toString() const { std::stringstream stream; - +/* switch (this->type) { case EXPRESSION_TYPE_MULTIPLY: case EXPRESSION_TYPE_DIVISION: @@ -561,9 +238,361 @@ std::string Expression::toString() const assert(false && "Illegal expression type"); break; } + */ return stream.str(); } +ExpressionNot::ExpressionNot(Expression *expr) : Expression(expr) +{ +} + +ValuePtr ExpressionNot::evaluate(const Context *context) const +{ + return !first->evaluate(context); +} + +ExpressionLogicalAnd::ExpressionLogicalAnd(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionLogicalAnd::evaluate(const Context *context) const +{ + return this->first->evaluate(context) && this->second->evaluate(context); +} + +ExpressionLogicalOr::ExpressionLogicalOr(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionLogicalOr::evaluate(const Context *context) const +{ + return this->first->evaluate(context) || this->second->evaluate(context); +} + +ExpressionMultiply::ExpressionMultiply(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionMultiply::evaluate(const Context *context) const +{ + return this->first->evaluate(context) * this->second->evaluate(context); +} + +ExpressionDivision::ExpressionDivision(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionDivision::evaluate(const Context *context) const +{ + return this->first->evaluate(context) / this->second->evaluate(context); +} + +ExpressionModulo::ExpressionModulo(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionModulo::evaluate(const Context *context) const +{ + return this->first->evaluate(context) % this->second->evaluate(context); +} + +ExpressionPlus::ExpressionPlus(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionPlus::evaluate(const Context *context) const +{ + return this->first->evaluate(context) + this->second->evaluate(context); +} + +ExpressionMinus::ExpressionMinus(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionMinus::evaluate(const Context *context) const +{ + return this->first->evaluate(context) - this->second->evaluate(context); +} + +ExpressionLess::ExpressionLess(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionLess::evaluate(const Context *context) const +{ + return this->first->evaluate(context) < this->second->evaluate(context); +} + +ExpressionLessOrEqual::ExpressionLessOrEqual(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionLessOrEqual::evaluate(const Context *context) const +{ + return this->first->evaluate(context) <= this->second->evaluate(context); +} + +ExpressionEqual::ExpressionEqual(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionEqual::evaluate(const Context *context) const +{ + return this->first->evaluate(context) == this->second->evaluate(context); +} + +ExpressionNotEqual::ExpressionNotEqual(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionNotEqual::evaluate(const Context *context) const +{ + return this->first->evaluate(context) != this->second->evaluate(context); +} + +ExpressionGreaterOrEqual::ExpressionGreaterOrEqual(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionGreaterOrEqual::evaluate(const Context *context) const +{ + return this->first->evaluate(context) >= this->second->evaluate(context); +} + +ExpressionGreater::ExpressionGreater(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionGreater::evaluate(const Context *context) const +{ + return this->first->evaluate(context) > this->second->evaluate(context); +} + +ExpressionTernary::ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3) : Expression(expr1, expr2, expr3) +{ +} + +ValuePtr ExpressionTernary::evaluate(const Context *context) const +{ + return (this->first->evaluate(context) ? this->second : this->third)->evaluate(context); +} + +ExpressionArray::ExpressionArray(Expression *left, Expression *right) : Expression(left, right) +{ +} + +ValuePtr ExpressionArray::evaluate(const Context *context) const { + return this->first->evaluate(context)[this->second->evaluate(context)]; +} + +ExpressionInvert::ExpressionInvert(Expression *expr) : Expression(expr) +{ +} + +ValuePtr ExpressionInvert::evaluate(const Context *context) const +{ + return -this->first->evaluate(context); +} + +ExpressionConst::ExpressionConst(const ValuePtr &val) : Expression(val) +{ +} + +ValuePtr ExpressionConst::evaluate(const class Context *) const +{ + return ValuePtr(this->const_value); +} + +ExpressionRange::ExpressionRange(Expression *expr1, Expression *expr2) : Expression(expr1, expr2) +{ +} + +ExpressionRange::ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3) : Expression(expr1, expr2, expr3) +{ +} + +ValuePtr ExpressionRange::evaluate(const Context *context) const +{ + ValuePtr v1 = this->first->evaluate(context); + if (v1->type() == Value::NUMBER) { + ValuePtr v2 = this->second->evaluate(context); + if (v2->type() == Value::NUMBER) { + if (this->children.size() == 2) { + Value::RangeType range(v1->toDouble(), v2->toDouble()); + return ValuePtr(range); + } else { + ValuePtr v3 = this->third->evaluate(context); + if (v3->type() == Value::NUMBER) { + Value::RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble()); + return ValuePtr(range); + } + } + } + } + return ValuePtr::undefined; +} + +ExpressionVector::ExpressionVector(Expression *expr) : Expression(expr) +{ +} + +ValuePtr ExpressionVector::evaluate(const Context *context) const +{ + Value::VectorType vec; + BOOST_FOREACH(const Expression *e, this->children) { + vec.push_back(*(e->evaluate(context))); + } + return ValuePtr(vec); +} + +ExpressionLookup::ExpressionLookup(const std::string &val) : Expression(val) +{ +} + +ValuePtr ExpressionLookup::evaluate(const Context *context) const +{ + return context->lookup_variable(this->var_name); +} + +ExpressionMember::ExpressionMember(const std::string &val, Expression *expr) : Expression(val, expr) +{ +} + +ValuePtr ExpressionMember::evaluate(const Context *context) const +{ + ValuePtr v = this->first->evaluate(context); + + if (v->type() == Value::VECTOR) { + if (this->var_name == "x") return v[0]; + if (this->var_name == "y") return v[1]; + if (this->var_name == "z") return v[2]; + } else if (v->type() == Value::RANGE) { + if (this->var_name == "begin") return v[0]; + if (this->var_name == "step") return v[1]; + if (this->var_name == "end") return v[2]; + } + return ValuePtr::undefined; +} + +static void function_recursion_detected(const char *func) +{ + PRINTB("ERROR: Recursion detected calling function '%s'", func); +} + +ExpressionFunction::ExpressionFunction() +{ +} + +ValuePtr ExpressionFunction::evaluate(const Context *context) const +{ + if (StackCheck::inst()->check()) { + function_recursion_detected(this->call_funcname.c_str()); + // TO DO: throw function_recursion_detected(); + return ValuePtr::undefined; + } + + EvalContext *c = new EvalContext(context, this->call_arguments); + ValuePtr result = context->evaluate_function(this->call_funcname, c); + delete c; + + return result; +} + +ExpressionLet::ExpressionLet() +{ +} + +ValuePtr ExpressionLet::evaluate(const Context *context) const +{ + Context c(context); + evaluate_sequential_assignment(this->call_arguments, &c); + + return this->children[0]->evaluate(&c); +} + +ExpressionLcExpression::ExpressionLcExpression(Expression *expr) : Expression(expr) +{ +} + +ValuePtr ExpressionLcExpression::evaluate(const Context *context) const +{ + return this->children[0]->evaluate(context); +} + +ExpressionLc::ExpressionLc(Expression *expr) : Expression(expr) +{ +} + +ExpressionLc::ExpressionLc(Expression *expr1, Expression *expr2) : Expression(expr1, expr2) +{ +} + +bool ExpressionLc::isListComprehension() +{ + return true; +} + +ValuePtr ExpressionLc::evaluate(const Context *context) const +{ + Value::VectorType vec; + + if (this->call_funcname == "if") { + if (this->children[0]->evaluate(context)) { + if (this->children[1]->isListComprehension()) { + return this->children[1]->evaluate(context); + } else { + vec.push_back((*this->children[1]->evaluate(context))); + } + } + return ValuePtr(vec); + } else if (this->call_funcname == "for") { + EvalContext for_context(context, this->call_arguments); + + Context assign_context(context); + + // comprehension for statements are by the parser reduced to only contain one single element + const std::string &it_name = for_context.getArgName(0); + ValuePtr it_values = for_context.getArgValue(0, &assign_context); + + Context c(context); + + if (it_values->type() == Value::RANGE) { + Value::RangeType range = it_values->toRange(); + boost::uint32_t steps = range.nbsteps(); + if (steps >= 1000000) { + PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps); + } else { + for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { + c.set_variable(it_name, ValuePtr(*it)); + vec.push_back((*this->children[0]->evaluate(&c))); + } + } + } + else if (it_values->type() == Value::VECTOR) { + for (size_t i = 0; i < it_values->toVector().size(); i++) { + c.set_variable(it_name, it_values->toVector()[i]); + vec.push_back((*this->children[0]->evaluate(&c))); + } + } + else if (it_values->type() != Value::UNDEFINED) { + c.set_variable(it_name, it_values); + vec.push_back((*this->children[0]->evaluate(&c))); + } + if (this->children[0]->isListComprehension()) { + return ValuePtr(flatten(vec)); + } else { + return ValuePtr(vec); + } + } else if (this->call_funcname == "let") { + Context c(context); + evaluate_sequential_assignment(this->call_arguments, &c); + + return this->children[0]->evaluate(&c); + } else { + abort(); + } +} + std::ostream &operator<<(std::ostream &stream, const Expression &expr) { stream << expr.toString(); diff --git a/src/expression.h b/src/expression.h index a83a75ef..28ba0378 100644 --- a/src/expression.h +++ b/src/expression.h @@ -5,49 +5,13 @@ #include "value.h" #include "typedefs.h" -#define EXPRESSION_TYPE_NOT ('!') -#define EXPRESSION_TYPE_LOGICAL_AND ('&') -#define EXPRESSION_TYPE_LOGICAL_OR ('|') -#define EXPRESSION_TYPE_MULTIPLY ('*') -#define EXPRESSION_TYPE_DIVISION ('/') -#define EXPRESSION_TYPE_MODULO ('%') -#define EXPRESSION_TYPE_PLUS ('+') -#define EXPRESSION_TYPE_MINUS ('-') -#define EXPRESSION_TYPE_LESS ('<') -#define EXPRESSION_TYPE_LESS_OR_EQUAL ('0') -#define EXPRESSION_TYPE_EQUAL ('=') -#define EXPRESSION_TYPE_NOT_EQUAL ('1') -#define EXPRESSION_TYPE_GREATER_OR_EQUAL ('2') -#define EXPRESSION_TYPE_GREATER ('>') -#define EXPRESSION_TYPE_TERNARY ('?') -#define EXPRESSION_TYPE_ARRAY_ACCESS ('[') -#define EXPRESSION_TYPE_INVERT ('I') -#define EXPRESSION_TYPE_CONST ('C') -#define EXPRESSION_TYPE_RANGE ('R') -#define EXPRESSION_TYPE_VECTOR ('V') -#define EXPRESSION_TYPE_LOOKUP ('L') -#define EXPRESSION_TYPE_MEMBER ('N') -#define EXPRESSION_TYPE_FUNCTION ('F') -#define EXPRESSION_TYPE_LET ('l') -#define EXPRESSION_TYPE_LC_EXPRESSION ('i') -#define EXPRESSION_TYPE_LC ('c') - -class ExpressionEvaluator -{ -public: - virtual ValuePtr evaluate(const class Expression *expr, const class Context *context) const = 0; -}; - -class ExpressionEvaluatorInit -{ -public: - ExpressionEvaluatorInit(); -}; - class Expression { public: std::vector children; + Expression *first; + Expression *second; + Expression *third; ValuePtr const_value; std::string var_name; @@ -55,45 +19,204 @@ public: std::string call_funcname; AssignmentList call_arguments; + Expression(); Expression(const ValuePtr &val); - Expression(const unsigned char type); - Expression(const unsigned char type, Expression *left, Expression *right); - Expression(const unsigned char type, Expression *expr); - ~Expression(); + Expression(const std::string &val); + Expression(const std::string &val, Expression *expr); + Expression(Expression *expr); + Expression(Expression *left, Expression *right); + Expression(Expression *expr1, Expression *expr2, Expression *expr3); + virtual ~Expression(); - void setType(const unsigned char type); - ValuePtr evaluate(const class Context *context) const; + virtual bool isListComprehension(); + virtual ValuePtr evaluate(const class Context *context) const = 0; std::string toString() const; - -private: - // Boolean: ! && || - // Operators: * / % + - - // Relations: < <= == != >= > - // Vector element: [] - // Condition operator: ?: - // Invert (prefix '-'): I - // Constant value: C - // Create Range: R - // Create Vector: V - // Create Matrix: M - // Lookup Variable: L - // Lookup member per name: N - // Function call: F - // Let expression: l - // List comprehension expression: i - // List comprehension: c - unsigned char type; - ExpressionEvaluator *evaluator; - - mutable int recursioncount; - - static ExpressionEvaluator *evaluators[256]; - static ExpressionEvaluatorInit evaluatorInit; - - friend class ExpressionEvaluatorInit; - friend class ExpressionEvaluatorLc; // for type - friend class ExpressionEvaluatorFunction; // for recursioncount }; std::ostream &operator<<(std::ostream &stream, const Expression &expr); + +class ExpressionNot : public Expression +{ +public: + ExpressionNot(Expression *expr); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLogicalAnd : public Expression +{ +public: + ExpressionLogicalAnd(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLogicalOr : public Expression +{ +public: + ExpressionLogicalOr(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionMultiply : public Expression +{ +public: + ExpressionMultiply(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionDivision : public Expression +{ +public: + ExpressionDivision(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionModulo : public Expression +{ +public: + ExpressionModulo(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionPlus : public Expression +{ +public: + ExpressionPlus(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionMinus : public Expression +{ +public: + ExpressionMinus(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLess : public Expression +{ +public: + ExpressionLess(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLessOrEqual : public Expression +{ +public: + ExpressionLessOrEqual(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionEqual : public Expression +{ +public: + ExpressionEqual(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionNotEqual : public Expression +{ +public: + ExpressionNotEqual(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionGreaterOrEqual : public Expression +{ +public: + ExpressionGreaterOrEqual(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionGreater : public Expression +{ +public: + ExpressionGreater(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionTernary : public Expression +{ +public: + ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionArray : public Expression +{ +public: + ExpressionArray(Expression *left, Expression *right); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionInvert : public Expression +{ +public: + ExpressionInvert(Expression *expr); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionConst : public Expression +{ +public: + ExpressionConst(const ValuePtr &val); + ValuePtr evaluate(const class Context *) const; +}; + +class ExpressionRange : public Expression +{ +public: + ExpressionRange(Expression *expr1, Expression *expr2); + ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionVector : public Expression +{ +public: + ExpressionVector(Expression *expr); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLookup : public Expression +{ +public: + ExpressionLookup(const std::string &val); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionMember : public Expression +{ +public: + ExpressionMember(const std::string &val, Expression *expr); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionFunction : public Expression +{ +public: + ExpressionFunction(); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLet : public Expression +{ +public: + ExpressionLet(); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLcExpression : public Expression +{ +public: + ExpressionLcExpression(Expression *expr); + ValuePtr evaluate(const class Context *context) const; +}; + +class ExpressionLc : public Expression +{ + bool isListComprehension(); +public: + ExpressionLc(Expression *expr); + ExpressionLc(Expression *expr1, Expression *expr2); + ValuePtr evaluate(const class Context *context) const; +}; diff --git a/src/func.cc b/src/func.cc index 168499cf..11faa327 100644 --- a/src/func.cc +++ b/src/func.cc @@ -35,6 +35,7 @@ #include #include "stl-utils.h" #include "printutils.h" +#include "stackcheck.h" #include #include @@ -88,21 +89,14 @@ Function::~Function() delete expr; } -static const char *txt = "stack usage: "; ValuePtr Function::evaluate(const Context *ctx, const EvalContext *evalctx) const { - char _c; - bool set = ctx->setStack(&_c); - if (!expr) return ValuePtr::undefined; Context *c = new Context(ctx); c->setVariables(definition_arguments, evalctx); ValuePtr result = expr->evaluate(c); delete c; - if (set) { - std::cout << txt << ctx->stackUsage() << std::endl; - } return result; } diff --git a/src/openscad.cc b/src/openscad.cc index bbd6c265..5b1c7c8a 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -39,6 +39,7 @@ #include "PlatformUtils.h" #include "LibraryInfo.h" #include "nodedumper.h" +#include "stackcheck.h" #include "CocoaUtils.h" #include @@ -655,6 +656,8 @@ int main(int argc, char **argv) { int rc = 0; bool isGuiLaunched = getenv("GUI_LAUNCHED") != 0; + StackCheck::inst()->init(); + #ifdef Q_OS_MAC if (isGuiLaunched) set_output_handler(CocoaUtils::nslog, NULL); #else diff --git a/src/parser.y b/src/parser.y index 9456f662..8ed27b85 100644 --- a/src/parser.y +++ b/src/parser.y @@ -308,65 +308,57 @@ single_module_instantiation: expr: TOK_TRUE { - $$ = new Expression(ValuePtr(true)); + $$ = new ExpressionConst(ValuePtr(true)); } | TOK_FALSE { - $$ = new Expression(ValuePtr(false)); + $$ = new ExpressionConst(ValuePtr(false)); } | TOK_UNDEF { - $$ = new Expression(ValuePtr::undefined); + $$ = new ExpressionConst(ValuePtr::undefined); } | TOK_ID { - $$ = new Expression(EXPRESSION_TYPE_LOOKUP); - $$->var_name = $1; + $$ = new ExpressionLookup($1); free($1); } | expr '.' TOK_ID { - $$ = new Expression(EXPRESSION_TYPE_MEMBER, $1); - $$->var_name = $3; + $$ = new ExpressionMember($3, $1); free($3); } | TOK_STRING { - $$ = new Expression(ValuePtr(std::string($1))); + $$ = new ExpressionConst(ValuePtr(std::string($1))); free($1); } | TOK_NUMBER { - $$ = new Expression(ValuePtr($1)); + $$ = new ExpressionConst(ValuePtr($1)); } | TOK_LET '(' arguments_call ')' expr %prec LET { - $$ = new Expression(EXPRESSION_TYPE_LET); + $$ = new ExpressionLet(); $$->call_arguments = *$3; delete $3; $$->children.push_back($5); } | '[' expr ':' expr ']' { - $$ = new Expression(EXPRESSION_TYPE_RANGE); - $$->children.push_back($2); - $$->children.push_back($4); + $$ = new ExpressionRange($2, $4); } | '[' expr ':' expr ':' expr ']' { - $$ = new Expression(EXPRESSION_TYPE_RANGE); - $$->children.push_back($2); - $$->children.push_back($4); - $$->children.push_back($6); + $$ = new ExpressionRange($2, $4, $6); } | '[' list_comprehension_elements ']' { - $$ = new Expression(EXPRESSION_TYPE_LC_EXPRESSION); - $$->children.push_back($2); + $$ = new ExpressionLcExpression($2); } | '[' optional_commas ']' { - $$ = new Expression(ValuePtr(Value::VectorType())); + $$ = new ExpressionConst(ValuePtr(Value::VectorType())); } | '[' vector_expr optional_commas ']' { @@ -374,55 +366,55 @@ expr: } | expr '*' expr { - $$ = new Expression(EXPRESSION_TYPE_MULTIPLY, $1, $3); + $$ = new ExpressionMultiply($1, $3); } | expr '/' expr { - $$ = new Expression(EXPRESSION_TYPE_DIVISION, $1, $3); + $$ = new ExpressionDivision($1, $3); } | expr '%' expr { - $$ = new Expression(EXPRESSION_TYPE_MODULO, $1, $3); + $$ = new ExpressionModulo($1, $3); } | expr '+' expr { - $$ = new Expression(EXPRESSION_TYPE_PLUS, $1, $3); + $$ = new ExpressionPlus($1, $3); } | expr '-' expr { - $$ = new Expression(EXPRESSION_TYPE_MINUS, $1, $3); + $$ = new ExpressionMinus($1, $3); } | expr '<' expr { - $$ = new Expression(EXPRESSION_TYPE_LESS, $1, $3); + $$ = new ExpressionLess($1, $3); } | expr LE expr { - $$ = new Expression(EXPRESSION_TYPE_LESS_OR_EQUAL, $1, $3); + $$ = new ExpressionLessOrEqual($1, $3); } | expr EQ expr { - $$ = new Expression(EXPRESSION_TYPE_EQUAL, $1, $3); + $$ = new ExpressionEqual($1, $3); } | expr NE expr { - $$ = new Expression(EXPRESSION_TYPE_NOT_EQUAL, $1, $3); + $$ = new ExpressionNotEqual($1, $3); } | expr GE expr { - $$ = new Expression(EXPRESSION_TYPE_GREATER_OR_EQUAL, $1, $3); + $$ = new ExpressionGreaterOrEqual($1, $3); } | expr '>' expr { - $$ = new Expression(EXPRESSION_TYPE_GREATER, $1, $3); + $$ = new ExpressionGreater($1, $3); } | expr AND expr { - $$ = new Expression(EXPRESSION_TYPE_LOGICAL_AND, $1, $3); + $$ = new ExpressionLogicalAnd($1, $3); } | expr OR expr { - $$ = new Expression(EXPRESSION_TYPE_LOGICAL_OR, $1, $3); + $$ = new ExpressionLogicalOr($1, $3); } | '+' expr { @@ -430,11 +422,11 @@ expr: } | '-' expr { - $$ = new Expression(EXPRESSION_TYPE_INVERT, $2); + $$ = new ExpressionInvert($2); } | '!' expr { - $$ = new Expression(EXPRESSION_TYPE_NOT, $2); + $$ = new ExpressionNot($2); } | '(' expr ')' { @@ -442,18 +434,15 @@ expr: } | expr '?' expr ':' expr { - $$ = new Expression(EXPRESSION_TYPE_TERNARY); - $$->children.push_back($1); - $$->children.push_back($3); - $$->children.push_back($5); + $$ = new ExpressionTernary($1, $3, $5); } | expr '[' expr ']' { - $$ = new Expression(EXPRESSION_TYPE_ARRAY_ACCESS, $1, $3); + $$ = new ExpressionArray($1, $3); } | TOK_ID '(' arguments_call ')' { - $$ = new Expression(EXPRESSION_TYPE_FUNCTION); + $$ = new ExpressionFunction(); $$->call_funcname = $1; $$->call_arguments = *$3; free($1); @@ -466,7 +455,7 @@ list_comprehension_elements: be parsed as an expression) */ TOK_LET '(' arguments_call ')' list_comprehension_elements { - $$ = new Expression(EXPRESSION_TYPE_LC, $5); + $$ = new ExpressionLc($5); $$->call_funcname = "let"; $$->call_arguments = *$3; delete $3; @@ -477,7 +466,7 @@ list_comprehension_elements: /* transform for(i=...,j=...) -> for(i=...) for(j=...) */ for (int i = $3->size()-1; i >= 0; i--) { - Expression *e = new Expression(EXPRESSION_TYPE_LC, $$); + Expression *e = new ExpressionLc($$); e->call_funcname = "for"; e->call_arguments.push_back((*$3)[i]); $$ = e; @@ -486,7 +475,7 @@ list_comprehension_elements: } | TOK_IF '(' expr ')' list_comprehension_elements_or_expr { - $$ = new Expression(EXPRESSION_TYPE_LC, $3, $5); + $$ = new ExpressionLc($3, $5); $$->call_funcname = "if"; } ; @@ -504,7 +493,7 @@ optional_commas: vector_expr: expr { - $$ = new Expression(EXPRESSION_TYPE_VECTOR, $1); + $$ = new ExpressionVector($1); } | vector_expr ',' optional_commas expr {