From fb18ec935b300203e1b41fe8a9fcbe3b1a329c29 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Tue, 26 Jan 2016 01:37:49 -0500 Subject: [PATCH 01/11] AST refactoring: New ASTNode supertype, refactored Expression, Module and Function class hierarchies --- openscad.pro | 37 +- src/AST.h | 8 + src/Assignment.h | 22 + src/CSGTreeEvaluator.cc | 1 + src/GeometryEvaluator.cc | 1 + src/MainWindow.h | 1 + src/ModuleInstantiation.cc | 96 +++ src/ModuleInstantiation.h | 49 ++ src/builtin.cc | 14 +- src/cgaladv.cc | 1 + src/color.cc | 1 + src/context.cc | 9 +- src/context.h | 2 +- src/control.cc | 3 +- src/csgops.cc | 1 + src/evalcontext.cc | 21 +- src/evalcontext.h | 1 + src/expr.cc | 573 ++++++++---------- src/expression.h | 313 ++++------ src/func.cc | 136 +---- src/function.cc | 140 +++++ src/function.h | 21 +- src/import.cc | 1 + src/lexer.l | 2 +- src/linearextrude.cc | 1 + src/localscope.cc | 6 +- src/localscope.h | 6 +- src/modcontext.cc | 22 +- src/modcontext.h | 5 +- src/module.cc | 123 +--- src/module.h | 69 +-- src/node.cc | 1 + src/nodedumper.cc | 1 + src/offset.cc | 1 + src/openscad.cc | 1 + src/parser.y | 113 ++-- src/projection.cc | 1 + src/render.cc | 1 + src/rotateextrude.cc | 1 + src/surface.cc | 1 + src/transform.cc | 2 +- src/typedefs.h | 18 - tests/CMakeLists.txt | 2 + tests/CSGTextRenderer.cc | 2 +- tests/cgalcachetest.cc | 1 + tests/csgtexttest.cc | 1 + tests/modulecachetest.cc | 1 + .../xcschemes/OpenSCAD.app.xcscheme | 13 +- 48 files changed, 898 insertions(+), 949 deletions(-) create mode 100644 src/AST.h create mode 100644 src/Assignment.h create mode 100644 src/ModuleInstantiation.cc create mode 100644 src/ModuleInstantiation.h create mode 100644 src/function.cc delete mode 100644 src/typedefs.h diff --git a/openscad.pro b/openscad.pro index 23f840e8..74dde499 100644 --- a/openscad.pro +++ b/openscad.pro @@ -205,14 +205,6 @@ CONFIG(mingw-cross-env)|CONFIG(mingw-cross-env-shared) { include(mingw-cross-env.pri) } -win* { - FLEXSOURCES = src/lexer.l - BISONSOURCES = src/parser.y -} else { - LEXSOURCES += src/lexer.l - YACCSOURCES += src/parser.y -} - RESOURCES = openscad.qrc # Qt5 removed access to the QMAKE_UIC variable, the following @@ -229,8 +221,28 @@ FORMS += src/MainWindow.ui \ src/launchingscreen.ui \ src/LibraryInfoDialog.ui -HEADERS += src/typedefs.h \ - src/version_check.h \ +# AST nodes +win* { + FLEXSOURCES = src/lexer.l + BISONSOURCES = src/parser.y +} else { + LEXSOURCES += src/lexer.l + YACCSOURCES += src/parser.y +} + +HEADERS += src/AST.h \ + src/ModuleInstantiation.h \ + src/Assignment.h \ + src/expression.h \ + src/function.h \ + src/module.h + +SOURCES += src/ModuleInstantiation.cc \ + src/expr.cc \ + src/function.cc \ + src/module.cc + +HEADERS += src/version_check.h \ src/ProgressWidget.h \ src/parsersettings.h \ src/renderer.h \ @@ -261,15 +273,12 @@ HEADERS += src/typedefs.h \ src/dxfdata.h \ src/dxfdim.h \ src/export.h \ - src/expression.h \ src/stackcheck.h \ - src/function.h \ src/exceptions.h \ src/grid.h \ src/hash.h \ src/highlighter.h \ src/localscope.h \ - src/module.h \ src/feature.h \ src/node.h \ src/csgnode.h \ @@ -338,11 +347,9 @@ SOURCES += src/version_check.cc \ src/Camera.cc \ src/handle_dep.cc \ src/value.cc \ - src/expr.cc \ src/stackcheck.cc \ src/func.cc \ src/localscope.cc \ - src/module.cc \ src/feature.cc \ src/node.cc \ src/context.cc \ diff --git a/src/AST.h b/src/AST.h new file mode 100644 index 00000000..997ee1cb --- /dev/null +++ b/src/AST.h @@ -0,0 +1,8 @@ +#pragma once + +class ASTNode +{ +public: + ASTNode(/* srcref */) {} + virtual ~ASTNode() {} +}; diff --git a/src/Assignment.h b/src/Assignment.h new file mode 100644 index 00000000..27253321 --- /dev/null +++ b/src/Assignment.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "AST.h" +#include "memory.h" + +class Assignment : public ASTNode +{ +public: + Assignment(std::string name, + shared_ptr expr = shared_ptr()) + : name(name), expr(expr) { + } + + std::string name; + shared_ptr expr; +}; + +typedef std::vector AssignmentList; diff --git a/src/CSGTreeEvaluator.cc b/src/CSGTreeEvaluator.cc index 705a4fa9..a1719795 100644 --- a/src/CSGTreeEvaluator.cc +++ b/src/CSGTreeEvaluator.cc @@ -3,6 +3,7 @@ #include "state.h" #include "csgops.h" #include "module.h" +#include "ModuleInstantiation.h" #include "csgnode.h" #include "transformnode.h" #include "colornode.h" diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 5c61819d..2e45a475 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -5,6 +5,7 @@ #include "CGALCache.h" #include "Polygon2d.h" #include "module.h" +#include "ModuleInstantiation.h" #include "state.h" #include "offsetnode.h" #include "transformnode.h" diff --git a/src/MainWindow.h b/src/MainWindow.h index 3294815b..d0cc9677 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -8,6 +8,7 @@ #include "openscad.h" #include "modcontext.h" #include "module.h" +#include "ModuleInstantiation.h" #include "Tree.h" #include "memory.h" #include "editor.h" diff --git a/src/ModuleInstantiation.cc b/src/ModuleInstantiation.cc new file mode 100644 index 00000000..c4317fae --- /dev/null +++ b/src/ModuleInstantiation.cc @@ -0,0 +1,96 @@ +#include "ModuleInstantiation.h" +#include "evalcontext.h" +#include "expression.h" + +#include "boosty.h" + +ModuleInstantiation::~ModuleInstantiation() +{ +} + +IfElseModuleInstantiation::~IfElseModuleInstantiation() +{ +} + +/*! + Returns the absolute path to the given filename, unless it's empty. + + NB! This will actually search for the file, to be backwards compatible with <= 2013.01 + (see issue #217) +*/ +std::string ModuleInstantiation::getAbsolutePath(const std::string &filename) const +{ + if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) { + return boosty::absolute(fs::path(this->modpath) / filename).string(); + } + else { + return filename; + } +} + +std::string ModuleInstantiation::dump(const std::string &indent) const +{ + std::stringstream dump; + dump << indent; + dump << modname + "("; + for (size_t i=0; i < this->arguments.size(); i++) { + const Assignment &arg = this->arguments[i]; + if (i > 0) dump << ", "; + if (!arg.name.empty()) dump << arg.name << " = "; + dump << *arg.expr; + } + if (scope.numElements() == 0) { + dump << ");\n"; + } else if (scope.numElements() == 1) { + dump << ") "; + dump << scope.dump(""); + } else { + dump << ") {\n"; + dump << scope.dump(indent + "\t"); + dump << indent << "}\n"; + } + return dump.str(); +} + +std::string IfElseModuleInstantiation::dump(const std::string &indent) const +{ + std::stringstream dump; + dump << ModuleInstantiation::dump(indent); + dump << indent; + if (else_scope.numElements() > 0) { + dump << indent << "else "; + if (else_scope.numElements() == 1) { + dump << else_scope.dump(""); + } + else { + dump << "{\n"; + dump << else_scope.dump(indent + "\t"); + dump << indent << "}\n"; + } + } + return dump.str(); +} + +AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const +{ + EvalContext c(ctx, this->arguments, &this->scope); + +#if 0 && DEBUG + PRINT("New eval ctx:"); + c.dump(NULL, this); +#endif + + AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx + return node; +} + +std::vector ModuleInstantiation::instantiateChildren(const Context *evalctx) const +{ + return this->scope.instantiateChildren(evalctx); +} + +std::vector IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const +{ + return this->else_scope.instantiateChildren(evalctx); +} + diff --git a/src/ModuleInstantiation.h b/src/ModuleInstantiation.h new file mode 100644 index 00000000..f31cbe6a --- /dev/null +++ b/src/ModuleInstantiation.h @@ -0,0 +1,49 @@ +#pragma once + +#include "AST.h" +#include "localscope.h" +#include + +typedef std::vector ModuleInstantiationList; + +class ModuleInstantiation : public ASTNode +{ +public: + ModuleInstantiation(const std::string &name = "") + : tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } + virtual ~ModuleInstantiation(); + + virtual std::string dump(const std::string &indent) const; + class AbstractNode *evaluate(const class Context *ctx) const; + std::vector instantiateChildren(const Context *evalctx) const; + + void setPath(const std::string &path) { this->modpath = path; } + const std::string &path() const { return this->modpath; } + std::string getAbsolutePath(const std::string &filename) const; + + const std::string &name() const { return this->modname; } + bool isBackground() const { return this->tag_background; } + bool isHighlight() const { return this->tag_highlight; } + bool isRoot() const { return this->tag_root; } + + AssignmentList arguments; + LocalScope scope; + + bool tag_root; + bool tag_highlight; + bool tag_background; +protected: + std::string modname; + std::string modpath; +}; + +class IfElseModuleInstantiation : public ModuleInstantiation { +public: + IfElseModuleInstantiation() : ModuleInstantiation("if") { } + virtual ~IfElseModuleInstantiation(); + std::vector instantiateElseChildren(const Context *evalctx) const; + virtual std::string dump(const std::string &indent) const; + + LocalScope else_scope; +}; + diff --git a/src/builtin.cc b/src/builtin.cc index 98a81187..1d4dc969 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", shared_ptr(new ExpressionConst(ValuePtr(0.0))))); - this->globalscope.assignments.push_back(Assignment("$fs", shared_ptr(new ExpressionConst(ValuePtr(2.0))))); - this->globalscope.assignments.push_back(Assignment("$fa", shared_ptr(new ExpressionConst(ValuePtr(12.0))))); - this->globalscope.assignments.push_back(Assignment("$t", shared_ptr(new ExpressionConst(ValuePtr(0.0))))); + this->globalscope.assignments.push_back(Assignment("$fn", shared_ptr(new Literal(ValuePtr(0.0))))); + this->globalscope.assignments.push_back(Assignment("$fs", shared_ptr(new Literal(ValuePtr(2.0))))); + this->globalscope.assignments.push_back(Assignment("$fa", shared_ptr(new Literal(ValuePtr(12.0))))); + this->globalscope.assignments.push_back(Assignment("$t", shared_ptr(new Literal(ValuePtr(0.0))))); Value::VectorType zero3; zero3.push_back(ValuePtr(0.0)); zero3.push_back(ValuePtr(0.0)); zero3.push_back(ValuePtr(0.0)); ValuePtr zero3val(zero3); - this->globalscope.assignments.push_back(Assignment("$vpt", shared_ptr(new ExpressionConst(zero3val)))); - this->globalscope.assignments.push_back(Assignment("$vpr", shared_ptr(new ExpressionConst(zero3val)))); - this->globalscope.assignments.push_back(Assignment("$vpd", shared_ptr(new ExpressionConst(ValuePtr(500))))); + this->globalscope.assignments.push_back(Assignment("$vpt", shared_ptr(new Literal(zero3val)))); + this->globalscope.assignments.push_back(Assignment("$vpr", shared_ptr(new Literal(zero3val)))); + this->globalscope.assignments.push_back(Assignment("$vpd", shared_ptr(new Literal(ValuePtr(500))))); } Builtins::~Builtins() diff --git a/src/cgaladv.cc b/src/cgaladv.cc index a69a7a48..8b0d5ee7 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -26,6 +26,7 @@ #include "cgaladvnode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "builtin.h" #include "polyset.h" diff --git a/src/color.cc b/src/color.cc index 9a501e89..e421eb10 100644 --- a/src/color.cc +++ b/src/color.cc @@ -26,6 +26,7 @@ #include "colornode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "builtin.h" #include "printutils.h" diff --git a/src/context.cc b/src/context.cc index fa0df62b..e7a6a10b 100644 --- a/src/context.cc +++ b/src/context.cc @@ -29,6 +29,7 @@ #include "expression.h" #include "function.h" #include "module.h" +#include "ModuleInstantiation.h" #include "builtin.h" #include "printutils.h" #include @@ -77,7 +78,7 @@ void Context::setVariables(const AssignmentList &args, const EvalContext *evalctx) { for(const auto &arg : args) { - set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : ValuePtr::undefined); + set_variable(arg.name, arg.expr ? arg.expr->evaluate(this->parent) : ValuePtr::undefined); } if (evalctx) { @@ -86,7 +87,7 @@ void Context::setVariables(const AssignmentList &args, const std::string &name = evalctx->getArgName(i); ValuePtr val = evalctx->getArgValue(i); if (name.empty()) { - if (posarg < args.size()) this->set_variable(args[posarg++].first, val); + if (posarg < args.size()) this->set_variable(args[posarg++].name, val); } else { this->set_variable(name, val); } @@ -211,11 +212,11 @@ std::string Context::dump(const AbstractModule *mod, const ModuleInstantiation * s << boost::format("Context: %p (%p)") % this % this->parent; s << boost::format(" document path: %s") % this->document_path; if (mod) { - const Module *m = dynamic_cast(mod); + const UserModule *m = dynamic_cast(mod); if (m) { s << " module args:"; for(const auto &arg : m->definition_arguments) { - s << boost::format(" %s = %s") % arg.first % variables[arg.first]; + s << boost::format(" %s = %s") % arg.name % variables[arg.name]; } } } diff --git a/src/context.h b/src/context.h index 9105008c..f9783409 100644 --- a/src/context.h +++ b/src/context.h @@ -4,7 +4,7 @@ #include #include #include "value.h" -#include "typedefs.h" +#include "Assignment.h" #include "memory.h" class Context diff --git a/src/control.cc b/src/control.cc index 40cd3899..6fcb2680 100644 --- a/src/control.cc +++ b/src/control.cc @@ -25,6 +25,7 @@ */ #include "module.h" +#include "ModuleInstantiation.h" #include "node.h" #include "evalcontext.h" #include "modcontext.h" @@ -100,7 +101,7 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst // the local scope (as they may depend on the for loop variables Context c(ctx); for(const auto &ass : inst.scope.assignments) { - c.set_variable(ass.first, ass.second->evaluate(&c)); + c.set_variable(ass.name, ass.expr->evaluate(&c)); } std::vector instantiatednodes = inst.instantiateChildren(&c); diff --git a/src/csgops.cc b/src/csgops.cc index b6304c7e..23b47e9b 100644 --- a/src/csgops.cc +++ b/src/csgops.cc @@ -28,6 +28,7 @@ #include "evalcontext.h" #include "module.h" +#include "ModuleInstantiation.h" #include "csgnode.h" #include "builtin.h" #include diff --git a/src/evalcontext.cc b/src/evalcontext.cc index c8195cac..75470206 100644 --- a/src/evalcontext.cc +++ b/src/evalcontext.cc @@ -1,5 +1,6 @@ #include "evalcontext.h" #include "module.h" +#include "ModuleInstantiation.h" #include "expression.h" #include "function.h" #include "printutils.h" @@ -16,7 +17,7 @@ EvalContext::EvalContext(const Context *parent, const std::string &EvalContext::getArgName(size_t i) const { assert(i < this->eval_arguments.size()); - return this->eval_arguments[i].first; + return this->eval_arguments[i].name; } ValuePtr EvalContext::getArgValue(size_t i, const Context *ctx) const @@ -24,8 +25,8 @@ ValuePtr EvalContext::getArgValue(size_t i, const Context *ctx) const assert(i < this->eval_arguments.size()); const Assignment &arg = this->eval_arguments[i]; ValuePtr v; - if (arg.second) { - v = arg.second->evaluate(ctx ? ctx : this); + if (arg.expr) { + v = arg.expr->evaluate(ctx ? ctx : this); } return v; } @@ -44,11 +45,11 @@ void EvalContext::assignTo(Context &target) const { for(const auto &assignment : this->eval_arguments) { ValuePtr v; - if (assignment.second) v = assignment.second->evaluate(&target); - if (target.has_local_variable(assignment.first)) { - PRINTB("WARNING: Ignoring duplicate variable assignment %s = %s", assignment.first % v->toString()); + if (assignment.expr) v = assignment.expr->evaluate(&target); + if (target.has_local_variable(assignment.name)) { + PRINTB("WARNING: Ignoring duplicate variable assignment %s = %s", assignment.name % v->toString()); } else { - target.set_variable(assignment.first, v); + target.set_variable(assignment.name, v); } } } @@ -65,7 +66,7 @@ std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiati s << boost::format(" eval args:"); for (size_t i=0;ieval_arguments.size();i++) { - s << boost::format(" %s = %s") % this->eval_arguments[i].first % this->eval_arguments[i].second; + s << boost::format(" %s = %s") % this->eval_arguments[i].name % this->eval_arguments[i].expr; } if (this->scope && this->scope->children.size() > 0) { s << boost::format(" children:"); @@ -74,11 +75,11 @@ std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiati } } if (mod) { - const Module *m = dynamic_cast(mod); + const UserModule *m = dynamic_cast(mod); if (m) { s << boost::format(" module args:"); for(const auto &arg : m->definition_arguments) { - s << boost::format(" %s = %s") % arg.first % *(variables[arg.first]); + s << boost::format(" %s = %s") % arg.name % *(variables[arg.name]); } } } diff --git a/src/evalcontext.h b/src/evalcontext.h index bf319c23..08b499df 100644 --- a/src/evalcontext.h +++ b/src/evalcontext.h @@ -1,6 +1,7 @@ #pragma once #include "context.h" +#include "Assignment.h" /*! This hold the evaluation context (the parameters actually sent diff --git a/src/expr.cc b/src/expr.cc index 87261643..43dc5234 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -58,32 +58,12 @@ namespace { } } -Expression::Expression() : first(NULL), second(NULL), third(NULL) +Expression::Expression() { } -Expression::Expression(Expression *expr) : first(expr), second(NULL), third(NULL) -{ - children.push_back(expr); -} - -Expression::Expression(Expression *left, Expression *right) : first(left), second(right), third(NULL) -{ - children.push_back(left); - children.push_back(right); -} - -Expression::Expression(Expression *expr1, Expression *expr2, Expression *expr3) - : first(expr1), second(expr2), third(expr3) -{ - children.push_back(expr1); - children.push_back(expr2); - children.push_back(expr3); -} - Expression::~Expression() { - std::for_each(this->children.begin(), this->children.end(), del_fun()); } namespace /* anonymous*/ { @@ -92,8 +72,8 @@ namespace /* anonymous*/ { for (size_t i=0; i < l.size(); i++) { const Assignment &arg = l[i]; if (i > 0) o << ", "; - if (!arg.first.empty()) o << arg.first << " = "; - o << *arg.second; + if (!arg.name.empty()) o << arg.name << " = "; + o << *arg.expr; } return o; } @@ -105,278 +85,215 @@ bool Expression::isListComprehension() const return false; } -ExpressionNot::ExpressionNot(Expression *expr) : Expression(expr) +UnaryOp::UnaryOp(UnaryOp::Op op, Expression *expr) : op(op), expr(expr) { } -ValuePtr ExpressionNot::evaluate(const Context *context) const +ValuePtr UnaryOp::evaluate(const Context *context) const { - return !first->evaluate(context); + switch (this->op) { + case (Op::Not): + return !this->expr->evaluate(context); + case (Op::Negate): + return -this->expr->evaluate(context); + default: + break; + // FIXME: error: + } } -void ExpressionNot::print(std::ostream &stream) const +const char *UnaryOp::opString() const { - stream << "!" << *first; + switch (this->op) { + case Op::Not: + return "!"; + break; + case Op::Negate: + return "-"; + break; + default: + break; + // FIXME: Error: unknown op + } } -ExpressionLogicalAnd::ExpressionLogicalAnd(Expression *left, Expression *right) : Expression(left, right) +void UnaryOp::print(std::ostream &stream) const +{ + stream << opString() << *this->expr; +} + +BinaryOp::BinaryOp(Expression *left, BinaryOp::Op op, Expression *right) : + op(op), left(left), right(right) { } -ValuePtr ExpressionLogicalAnd::evaluate(const Context *context) const +ValuePtr BinaryOp::evaluate(const Context *context) const { - return this->first->evaluate(context) && this->second->evaluate(context); + switch (this->op) { + case Op::LogicalAnd: + return this->left->evaluate(context) && this->right->evaluate(context); + break; + case Op::LogicalOr: + return this->left->evaluate(context) || this->right->evaluate(context); + break; + case Op::Multiply: + return this->left->evaluate(context) * this->right->evaluate(context); + break; + case Op::Divide: + return this->left->evaluate(context) / this->right->evaluate(context); + break; + case Op::Modulo: + return this->left->evaluate(context) % this->right->evaluate(context); + break; + case Op::Plus: + return this->left->evaluate(context) + this->right->evaluate(context); + break; + case Op::Minus: + return this->left->evaluate(context) - this->right->evaluate(context); + break; + case Op::Less: + return this->left->evaluate(context) < this->right->evaluate(context); + break; + case Op::LessEqual: + return this->left->evaluate(context) <= this->right->evaluate(context); + break; + case Op::Greater: + return this->left->evaluate(context) > this->right->evaluate(context); + break; + case Op::GreaterEqual: + return this->left->evaluate(context) >= this->right->evaluate(context); + break; + case Op::Equal: + return this->left->evaluate(context) == this->right->evaluate(context); + break; + case Op::NotEqual: + return this->left->evaluate(context) != this->right->evaluate(context); + break; + default: + break; + // FIXME: Error: unknown op + } } -void ExpressionLogicalAnd::print(std::ostream &stream) const +const char *BinaryOp::opString() const { - stream << "(" << *first << " && " << *second << ")"; + switch (this->op) { + case Op::LogicalAnd: + return "&&"; + break; + case Op::LogicalOr: + return "||"; + break; + case Op::Multiply: + return "*"; + break; + case Op::Divide: + return "/"; + break; + case Op::Modulo: + return "%"; + break; + case Op::Plus: + return "+"; + break; + case Op::Minus: + return "-"; + break; + case Op::Less: + return "<"; + break; + case Op::LessEqual: + return "<="; + break; + case Op::Greater: + return ">"; + break; + case Op::GreaterEqual: + return ">="; + break; + case Op::Equal: + return "=="; + break; + case Op::NotEqual: + return "!="; + break; + default: + break; + // FIXME: Error: unknown op + } } -ExpressionLogicalOr::ExpressionLogicalOr(Expression *left, Expression *right) : Expression(left, right) +void BinaryOp::print(std::ostream &stream) const +{ + stream << "(" << *this->left << " " << opString() << " " << *this->right << ")"; +} + +TernaryOp::TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr) + : cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) { } -ValuePtr ExpressionLogicalOr::evaluate(const Context *context) const +ValuePtr TernaryOp::evaluate(const Context *context) const { - return this->first->evaluate(context) || this->second->evaluate(context); + return (this->cond->evaluate(context) ? this->ifexpr : this->elseexpr)->evaluate(context); } -void ExpressionLogicalOr::print(std::ostream &stream) const +void TernaryOp::print(std::ostream &stream) const { - stream << "(" << *first << " || " << *second << ")"; + stream << "(" << *this->cond << " ? " << *this->ifexpr << " : " << *this->elseexpr << ")"; } -ExpressionMultiply::ExpressionMultiply(Expression *left, Expression *right) : Expression(left, right) +ArrayLookup::ArrayLookup(Expression *array, Expression *index) + : array(array), index(index) { } -ValuePtr ExpressionMultiply::evaluate(const Context *context) const -{ - return this->first->evaluate(context) * this->second->evaluate(context); +ValuePtr ArrayLookup::evaluate(const Context *context) const { + return this->array->evaluate(context)[this->index->evaluate(context)]; } -void ExpressionMultiply::print(std::ostream &stream) const +void ArrayLookup::print(std::ostream &stream) const { - stream << "(" << *first << " * " << *second << ")"; + stream << *array << "[" << *index << "]"; } -ExpressionDivision::ExpressionDivision(Expression *left, Expression *right) : Expression(left, right) +Literal::Literal(const ValuePtr &val) : value(val) { } -ValuePtr ExpressionDivision::evaluate(const Context *context) const +ValuePtr Literal::evaluate(const class Context *) const { - return this->first->evaluate(context) / this->second->evaluate(context); + return this->value; } -void ExpressionDivision::print(std::ostream &stream) const +void Literal::print(std::ostream &stream) const { - stream << "(" << *first << " / " << *second << ")"; + stream << *this->value; } -ExpressionModulo::ExpressionModulo(Expression *left, Expression *right) : Expression(left, right) +Range::Range(Expression *begin, Expression *end) + : begin(begin), end(end) { } -ValuePtr ExpressionModulo::evaluate(const Context *context) const -{ - return this->first->evaluate(context) % this->second->evaluate(context); -} - -void ExpressionModulo::print(std::ostream &stream) const -{ - stream << "(" << *first << " % " << *second << ")"; -} - -ExpressionPlus::ExpressionPlus(Expression *left, Expression *right) : Expression(left, right) +Range::Range(Expression *begin, Expression *step, Expression *end) + : begin(begin), step(step), end(end) { } -ValuePtr ExpressionPlus::evaluate(const Context *context) const +ValuePtr Range::evaluate(const Context *context) const { - return this->first->evaluate(context) + this->second->evaluate(context); -} - -void ExpressionPlus::print(std::ostream &stream) const -{ - stream << "(" << *first << " + " << *second << ")"; -} - -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); -} - -void ExpressionMinus::print(std::ostream &stream) const -{ - stream << "(" << *first << " - " << *second << ")"; -} - -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); -} - -void ExpressionLess::print(std::ostream &stream) const -{ - stream << "(" << *first << " < " << *second << ")"; -} - -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); -} - -void ExpressionLessOrEqual::print(std::ostream &stream) const -{ - stream << "(" << *first << " <= " << *second << ")"; -} - -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); -} - -void ExpressionEqual::print(std::ostream &stream) const -{ - stream << "(" << *first << " == " << *second << ")"; -} - -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); -} - -void ExpressionNotEqual::print(std::ostream &stream) const -{ - stream << "(" << *first << " != " << *second << ")"; -} - -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); -} - -void ExpressionGreaterOrEqual::print(std::ostream &stream) const -{ - stream << "(" << *first << " >= " << *second << ")"; -} - -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); -} - -void ExpressionGreater::print(std::ostream &stream) const -{ - stream << "(" << *first << " > " << *second << ")"; -} - -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); -} - -void ExpressionTernary::print(std::ostream &stream) const -{ - stream << "(" << *first << " ? " << *second << " : " << *third << ")"; -} - -ExpressionArrayLookup::ExpressionArrayLookup(Expression *left, Expression *right) : Expression(left, right) -{ -} - -ValuePtr ExpressionArrayLookup::evaluate(const Context *context) const { - return this->first->evaluate(context)[this->second->evaluate(context)]; -} - -void ExpressionArrayLookup::print(std::ostream &stream) const -{ - stream << *first << "[" << *second << "]"; -} - -ExpressionInvert::ExpressionInvert(Expression *expr) : Expression(expr) -{ -} - -ValuePtr ExpressionInvert::evaluate(const Context *context) const -{ - return -this->first->evaluate(context); -} - -void ExpressionInvert::print(std::ostream &stream) const -{ - stream << "-" << *first; -} - -ExpressionConst::ExpressionConst(const ValuePtr &val) : const_value(val) -{ -} - -ValuePtr ExpressionConst::evaluate(const class Context *) const -{ - return this->const_value; -} - -void ExpressionConst::print(std::ostream &stream) const -{ - stream << *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) { - RangeType range(v1->toDouble(), v2->toDouble()); + ValuePtr beginValue = this->begin->evaluate(context); + if (beginValue->type() == Value::NUMBER) { + ValuePtr endValue = this->end->evaluate(context); + if (endValue->type() == Value::NUMBER) { + if (!this->step) { + RangeType range(beginValue->toDouble(), endValue->toDouble()); return ValuePtr(range); } else { - ValuePtr v3 = this->third->evaluate(context); - if (v3->type() == Value::NUMBER) { - RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble()); + ValuePtr stepValue = this->step->evaluate(context); + if (stepValue->type() == Value::NUMBER) { + RangeType range(beginValue->toDouble(), stepValue->toDouble(), endValue->toDouble()); return ValuePtr(range); } } @@ -385,18 +302,24 @@ ValuePtr ExpressionRange::evaluate(const Context *context) const return ValuePtr::undefined; } -void ExpressionRange::print(std::ostream &stream) const +void Range::print(std::ostream &stream) const { - stream << "[" << *first << " : " << *second; - if (this->children.size() > 2) stream << " : " << *third; + stream << "[" << *this->begin; + if (this->step) stream << " : " << *this->step; + stream << " : " << *this->end; stream << "]"; } -ExpressionVector::ExpressionVector(Expression *expr) : Expression(expr) +Vector::Vector() { } -ValuePtr ExpressionVector::evaluate(const Context *context) const +void Vector::push_back(Expression *expr) +{ + this->children.push_back(shared_ptr(expr)); +} + +ValuePtr Vector::evaluate(const Context *context) const { Value::VectorType vec; for(const auto &e : this->children) { @@ -413,7 +336,7 @@ ValuePtr ExpressionVector::evaluate(const Context *context) const return ValuePtr(vec); } -void ExpressionVector::print(std::ostream &stream) const +void Vector::print(std::ostream &stream) const { stream << "["; for (size_t i=0; i < this->children.size(); i++) { @@ -423,28 +346,28 @@ void ExpressionVector::print(std::ostream &stream) const stream << "]"; } -ExpressionLookup::ExpressionLookup(const std::string &var_name) : var_name(var_name) +Lookup::Lookup(const std::string &name) : name(name) { } -ValuePtr ExpressionLookup::evaluate(const Context *context) const +ValuePtr Lookup::evaluate(const Context *context) const { - return context->lookup_variable(this->var_name); + return context->lookup_variable(this->name); } -void ExpressionLookup::print(std::ostream &stream) const +void Lookup::print(std::ostream &stream) const { - stream << this->var_name; + stream << this->name; } -ExpressionMember::ExpressionMember(Expression *expr, const std::string &member) - : Expression(expr), member(member) +MemberLookup::MemberLookup(Expression *expr, const std::string &member) + : expr(expr), member(member) { } -ValuePtr ExpressionMember::evaluate(const Context *context) const +ValuePtr MemberLookup::evaluate(const Context *context) const { - ValuePtr v = this->first->evaluate(context); + ValuePtr v = this->expr->evaluate(context); if (v->type() == Value::VECTOR) { if (this->member == "x") return v[0]; @@ -458,80 +381,75 @@ ValuePtr ExpressionMember::evaluate(const Context *context) const return ValuePtr::undefined; } -void ExpressionMember::print(std::ostream &stream) const +void MemberLookup::print(std::ostream &stream) const { - stream << *first << "." << this->member; + stream << *this->expr << "." << this->member; } -ExpressionFunctionCall::ExpressionFunctionCall(const std::string &funcname, - const AssignmentList &arglist) - : funcname(funcname), call_arguments(arglist) +FunctionCall::FunctionCall(const std::string &name, + const AssignmentList &args) + : name(name), arguments(args) { } -ValuePtr ExpressionFunctionCall::evaluate(const Context *context) const +ValuePtr FunctionCall::evaluate(const Context *context) const { if (StackCheck::inst()->check()) { - throw RecursionException::create("function", funcname); + throw RecursionException::create("function", this->name); } - EvalContext c(context, this->call_arguments); - ValuePtr result = context->evaluate_function(this->funcname, &c); + EvalContext c(context, this->arguments); + ValuePtr result = context->evaluate_function(this->name, &c); return result; } -void ExpressionFunctionCall::print(std::ostream &stream) const +void FunctionCall::print(std::ostream &stream) const { - stream << this->funcname << "(" << this->call_arguments << ")"; + stream << this->name << "(" << this->arguments << ")"; } -ExpressionLet::ExpressionLet(const AssignmentList &arglist, Expression *expr) - : Expression(expr), call_arguments(arglist) +Let::Let(const AssignmentList &args, Expression *expr) + : arguments(args), expr(expr) { } -ValuePtr ExpressionLet::evaluate(const Context *context) const +ValuePtr Let::evaluate(const Context *context) const { Context c(context); - evaluate_sequential_assignment(this->call_arguments, &c); + evaluate_sequential_assignment(this->arguments, &c); - return this->first->evaluate(&c); + return this->expr->evaluate(&c); } -void ExpressionLet::print(std::ostream &stream) const +void Let::print(std::ostream &stream) const { - stream << "let(" << this->call_arguments << ") " << *first; + stream << "let(" << this->arguments << ") " << *expr; } -ExpressionLc::ExpressionLc(Expression *expr) : Expression(expr) +ListComprehension::ListComprehension() { } -ExpressionLc::ExpressionLc(Expression *expr1, Expression *expr2) - : Expression(expr1, expr2) -{ -} - -bool ExpressionLc::isListComprehension() const +bool ListComprehension::isListComprehension() const { return true; } -ExpressionLcIf::ExpressionLcIf(Expression *cond, Expression *exprIf, Expression *exprElse) - : ExpressionLc(exprIf, exprElse), cond(cond) +LcIf::LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr) + : cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) { } -ValuePtr ExpressionLcIf::evaluate(const Context *context) const +ValuePtr LcIf::evaluate(const Context *context) const { - if (this->second) { + if (this->elseexpr) { ExperimentalFeatureException::check(Feature::ExperimentalElseExpression); } - const Expression *expr = this->cond->evaluate(context) ? this->first : this->second; - - Value::VectorType vec; + const shared_ptr &expr = this->cond->evaluate(context) ? this->ifexpr : this->elseexpr; + + Value::VectorType vec; if (expr) { if (expr->isListComprehension()) { return expr->evaluate(context); @@ -543,26 +461,25 @@ ValuePtr ExpressionLcIf::evaluate(const Context *context) const return ValuePtr(vec); } -void ExpressionLcIf::print(std::ostream &stream) const +void LcIf::print(std::ostream &stream) const { - stream << "if(" << *this->cond << ") (" << *this->first << ")"; - if (this->second) { - stream << " else (" << *this->second << ")"; + stream << "if(" << *this->cond << ") (" << *this->ifexpr << ")"; + if (this->elseexpr) { + stream << " else (" << *this->elseexpr << ")"; } } -ExpressionLcEach::ExpressionLcEach(Expression *expr) - : ExpressionLc(expr) +LcEach::LcEach(Expression *expr) : expr(expr) { } -ValuePtr ExpressionLcEach::evaluate(const Context *context) const +ValuePtr LcEach::evaluate(const Context *context) const { ExperimentalFeatureException::check(Feature::ExperimentalEachExpression); Value::VectorType vec; - ValuePtr v = this->first->evaluate(context); + ValuePtr v = this->expr->evaluate(context); if (v->type() == Value::RANGE) { RangeType range = v->toRange(); @@ -583,28 +500,28 @@ ValuePtr ExpressionLcEach::evaluate(const Context *context) const vec.push_back(v); } - if (this->first->isListComprehension()) { + if (this->expr->isListComprehension()) { return ValuePtr(flatten(vec)); } else { return ValuePtr(vec); } } -void ExpressionLcEach::print(std::ostream &stream) const +void LcEach::print(std::ostream &stream) const { - stream << "each (" << *this->first << ")"; + stream << "each (" << *this->expr << ")"; } -ExpressionLcFor::ExpressionLcFor(const AssignmentList &arglist, Expression *expr) - : ExpressionLc(expr), call_arguments(arglist) +LcFor::LcFor(const AssignmentList &args, Expression *expr) + : arguments(args), expr(expr) { } -ValuePtr ExpressionLcFor::evaluate(const Context *context) const +ValuePtr LcFor::evaluate(const Context *context) const { Value::VectorType vec; - EvalContext for_context(context, this->call_arguments); + EvalContext for_context(context, this->arguments); Context assign_context(context); @@ -622,48 +539,48 @@ ValuePtr ExpressionLcFor::evaluate(const Context *context) const } else { for (RangeType::iterator it = range.begin();it != range.end();it++) { c.set_variable(it_name, ValuePtr(*it)); - vec.push_back(this->first->evaluate(&c)); + vec.push_back(this->expr->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->first->evaluate(&c)); + vec.push_back(this->expr->evaluate(&c)); } } else if (it_values->type() != Value::UNDEFINED) { c.set_variable(it_name, it_values); - vec.push_back(this->first->evaluate(&c)); + vec.push_back(this->expr->evaluate(&c)); } - if (this->first->isListComprehension()) { + if (this->expr->isListComprehension()) { return ValuePtr(flatten(vec)); } else { return ValuePtr(vec); } } -void ExpressionLcFor::print(std::ostream &stream) const +void LcFor::print(std::ostream &stream) const { - stream << "for(" << this->call_arguments << ") (" << *this->first << ")"; + stream << "for(" << this->arguments << ") (" << *this->expr << ")"; } -ExpressionLcForC::ExpressionLcForC(const AssignmentList &arglist, const AssignmentList &incrargs, Expression *cond, Expression *expr) - : ExpressionLc(cond, expr), call_arguments(arglist), incr_arguments(incrargs) +LcForC::LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr) + : arguments(args), incr_arguments(incrargs), cond(cond), expr(expr) { } -ValuePtr ExpressionLcForC::evaluate(const Context *context) const +ValuePtr LcForC::evaluate(const Context *context) const { ExperimentalFeatureException::check(Feature::ExperimentalForCExpression); Value::VectorType vec; Context c(context); - evaluate_sequential_assignment(this->call_arguments, &c); + evaluate_sequential_assignment(this->arguments, &c); unsigned int counter = 0; - while (this->first->evaluate(&c)) { - vec.push_back(this->second->evaluate(&c)); + while (this->cond->evaluate(&c)) { + vec.push_back(this->expr->evaluate(&c)); if (counter++ == 1000000) throw RecursionException::create("for loop", ""); @@ -672,37 +589,37 @@ ValuePtr ExpressionLcForC::evaluate(const Context *context) const c.apply_variables(tmp); } - if (this->second->isListComprehension()) { + if (this->expr->isListComprehension()) { return ValuePtr(flatten(vec)); } else { return ValuePtr(vec); } } -void ExpressionLcForC::print(std::ostream &stream) const +void LcForC::print(std::ostream &stream) const { stream - << "for(" << this->call_arguments - << ";" << *this->first + << "for(" << this->arguments + << ";" << *this->cond << ";" << this->incr_arguments - << ") " << *this->second; + << ") " << *this->expr; } -ExpressionLcLet::ExpressionLcLet(const AssignmentList &arglist, Expression *expr) - : ExpressionLc(expr), call_arguments(arglist) +LcLet::LcLet(const AssignmentList &args, Expression *expr) + : arguments(args), expr(expr) { } -ValuePtr ExpressionLcLet::evaluate(const Context *context) const +ValuePtr LcLet::evaluate(const Context *context) const { Context c(context); - evaluate_sequential_assignment(this->call_arguments, &c); - return this->first->evaluate(&c); + evaluate_sequential_assignment(this->arguments, &c); + return this->expr->evaluate(&c); } -void ExpressionLcLet::print(std::ostream &stream) const +void LcLet::print(std::ostream &stream) const { - stream << "let(" << this->call_arguments << ") (" << *this->first << ")"; + stream << "let(" << this->arguments << ") (" << *this->expr << ")"; } std::ostream &operator<<(std::ostream &stream, const Expression &expr) diff --git a/src/expression.h b/src/expression.h index f9e0ac25..b6e6826d 100644 --- a/src/expression.h +++ b/src/expression.h @@ -1,22 +1,17 @@ #pragma once +#include "AST.h" + #include #include #include "value.h" -#include "typedefs.h" +#include "memory.h" +#include "Assignment.h" -class Expression +class Expression : public ASTNode { public: - std::vector children; - Expression *first; - Expression *second; - Expression *third; - Expression(); - Expression(Expression *expr); - Expression(Expression *left, Expression *right); - Expression(Expression *expr1, Expression *expr2, Expression *expr3); virtual ~Expression(); virtual bool isListComprehension() const; @@ -26,264 +21,216 @@ public: std::ostream &operator<<(std::ostream &stream, const Expression &expr); -class ExpressionNot : public Expression +class UnaryOp : public Expression { public: - ExpressionNot(Expression *expr); + enum class Op { + Not, + Negate + }; + + UnaryOp(Op op, Expression *expr); virtual ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; + +private: + const char *opString() const; + + Op op; + shared_ptr expr; }; -class ExpressionLogicalAnd : public Expression +class BinaryOp : public Expression { public: - ExpressionLogicalAnd(Expression *left, Expression *right); + enum class Op { + LogicalAnd, + LogicalOr, + Multiply, + Divide, + Modulo, + Plus, + Minus, + Less, + LessEqual, + Greater, + GreaterEqual, + Equal, + NotEqual + }; + + BinaryOp(Expression *left, Op op, Expression *right); + virtual ValuePtr evaluate(const class Context *context) const; + virtual void print(std::ostream &stream) const; + +private: + const char *opString() const; + + Op op; + shared_ptr left; + shared_ptr right; +}; + +class TernaryOp : public Expression +{ +public: + TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; + + shared_ptr cond; + shared_ptr ifexpr; + shared_ptr elseexpr; }; -class ExpressionLogicalOr : public Expression +class ArrayLookup : public Expression { public: - ExpressionLogicalOr(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionMultiply : public Expression -{ -public: - ExpressionMultiply(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionDivision : public Expression -{ -public: - ExpressionDivision(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionModulo : public Expression -{ -public: - ExpressionModulo(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionPlus : public Expression -{ -public: - ExpressionPlus(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionMinus : public Expression -{ -public: - ExpressionMinus(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionLess : public Expression -{ -public: - ExpressionLess(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionLessOrEqual : public Expression -{ -public: - ExpressionLessOrEqual(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionEqual : public Expression -{ -public: - ExpressionEqual(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionNotEqual : public Expression -{ -public: - ExpressionNotEqual(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionGreaterOrEqual : public Expression -{ -public: - ExpressionGreaterOrEqual(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionGreater : public Expression -{ -public: - ExpressionGreater(Expression *left, Expression *right); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionTernary : public Expression -{ -public: - ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionArrayLookup : public Expression -{ -public: - ExpressionArrayLookup(Expression *left, Expression *right); + ArrayLookup(Expression *array, Expression *index); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: + shared_ptr array; + shared_ptr index; }; -class ExpressionInvert : public Expression +class Literal : public Expression { public: - ExpressionInvert(Expression *expr); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionConst : public Expression -{ -public: - ExpressionConst(const ValuePtr &val); + Literal(const ValuePtr &val); ValuePtr evaluate(const class Context *) const; virtual void print(std::ostream &stream) const; private: - ValuePtr const_value; + ValuePtr value; }; -class ExpressionRange : public Expression +class Range : public Expression { public: - ExpressionRange(Expression *expr1, Expression *expr2); - ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionVector : public Expression -{ -public: - ExpressionVector(Expression *expr); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionLookup : public Expression -{ -public: - ExpressionLookup(const std::string &var_name); + Range(Expression *begin, Expression *end); + Range(Expression *begin, Expression *step, Expression *end); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - std::string var_name; + shared_ptr begin; + shared_ptr step; + shared_ptr end; }; -class ExpressionMember : public Expression +class Vector : public Expression { public: - ExpressionMember(Expression *expr, const std::string &member); + Vector(); + ValuePtr evaluate(const class Context *context) const; + virtual void print(std::ostream &stream) const; + void push_back(Expression *expr); +private: + std::vector> children; +}; + +class Lookup : public Expression +{ +public: + Lookup(const std::string &name); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: + std::string name; +}; + +class MemberLookup : public Expression +{ +public: + MemberLookup(Expression *expr, const std::string &member); + ValuePtr evaluate(const class Context *context) const; + virtual void print(std::ostream &stream) const; +private: + shared_ptr expr; std::string member; }; -class ExpressionFunctionCall : public Expression +class FunctionCall : public Expression { public: - ExpressionFunctionCall(const std::string &funcname, const AssignmentList &arglist); + FunctionCall(const std::string &funcname, const AssignmentList &arglist); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; public: - std::string funcname; - AssignmentList call_arguments; + std::string name; + AssignmentList arguments; }; -class ExpressionLet : public Expression +class Let : public Expression { public: - ExpressionLet(const AssignmentList &arglist, Expression *expr); + Let(const AssignmentList &args, Expression *expr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - AssignmentList call_arguments; + AssignmentList arguments; + shared_ptr expr; }; -class ExpressionLc : public Expression +class ListComprehension : public Expression { virtual bool isListComprehension() const; public: - ExpressionLc(Expression *expr); - ExpressionLc(Expression *expr1, Expression *expr2); + ListComprehension(); }; -class ExpressionLcIf : public ExpressionLc +class LcIf : public ListComprehension { public: - ExpressionLcIf(Expression *cond, Expression *exprIf, Expression *exprElse); + LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - Expression *cond; + shared_ptr cond; + shared_ptr ifexpr; + shared_ptr elseexpr; }; -class ExpressionLcFor : public ExpressionLc +class LcFor : public ListComprehension { public: - ExpressionLcFor(const AssignmentList &arglist, Expression *expr); + LcFor(const AssignmentList &args, Expression *expr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - AssignmentList call_arguments; + AssignmentList arguments; + shared_ptr expr; }; -class ExpressionLcForC : public ExpressionLc +class LcForC : public ListComprehension { public: - ExpressionLcForC(const AssignmentList &arglist, const AssignmentList &incrargs, Expression *cond, Expression *expr); + LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - AssignmentList call_arguments; + AssignmentList arguments; AssignmentList incr_arguments; + shared_ptr cond; + shared_ptr expr; }; -class ExpressionLcEach : public ExpressionLc +class LcEach : public ListComprehension { public: - ExpressionLcEach(Expression *expr); - ValuePtr evaluate(const class Context *context) const; - virtual void print(std::ostream &stream) const; -}; - -class ExpressionLcLet : public ExpressionLc -{ -public: - ExpressionLcLet(const AssignmentList &arglist, Expression *expr); + LcEach(Expression *expr); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: - AssignmentList call_arguments; + shared_ptr expr; +}; + +class LcLet : public ListComprehension +{ +public: + LcLet(const AssignmentList &args, Expression *expr); + ValuePtr evaluate(const class Context *context) const; + virtual void print(std::ostream &stream) const; +private: + AssignmentList arguments; + shared_ptr expr; }; diff --git a/src/func.cc b/src/func.cc index 8412972a..cc924a23 100644 --- a/src/func.cc +++ b/src/func.cc @@ -35,6 +35,7 @@ #include "printutils.h" #include "stackcheck.h" #include "exceptions.h" +#include "memory.h" #include #include @@ -70,137 +71,6 @@ int process_id = getpid(); boost::mt19937 deterministic_rng; boost::mt19937 lessdeterministic_rng( std::time(0) + process_id ); -AbstractFunction::~AbstractFunction() -{ -} - -// FIXME: Is this needed? -ValuePtr AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const -{ - (void)evalctx; // unusued parameter - return ValuePtr::undefined; -} - -std::string AbstractFunction::dump(const std::string &indent, const std::string &name) const -{ - std::stringstream dump; - dump << indent << "abstract function " << name << "();\n"; - 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; -} - -ValuePtr Function::evaluate(const Context *ctx, const EvalContext *evalctx) const -{ - if (!expr) return ValuePtr::undefined; - Context c(ctx); - c.setVariables(definition_arguments, evalctx); - ValuePtr result = expr->evaluate(&c); - - return result; -} - -std::string Function::dump(const std::string &indent, const std::string &name) const -{ - std::stringstream dump; - dump << indent << "function " << name << "("; - for (size_t i=0; i < definition_arguments.size(); i++) { - const Assignment &arg = definition_arguments[i]; - if (i > 0) dump << ", "; - dump << arg.first; - if (arg.second) dump << " = " << *arg.second; - } - dump << ") = " << *expr << ";\n"; - 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); - Context tmp(&c); - unsigned int counter = 0; - while (invert ^ expr->first->evaluate(&c)) { - tmp.setVariables(definition_arguments, &ec); - c.apply_variables(tmp); - - if (counter++ == 1000000) throw RecursionException::create("function", this->name); - } - - 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() -{ -} - -ValuePtr BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const -{ - return eval_func(ctx, evalctx); -} - -std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const -{ - std::stringstream dump; - dump << indent << "builtin function " << name << "();\n"; - return dump.str(); -} - static inline double deg2rad(double x) { return x * M_PI / 180.0; @@ -912,7 +782,7 @@ ValuePtr builtin_parent_module(const Context *, const EvalContext *evalctx) { int n; double d; - int s = Module::stack_size(); + int s = UserModule::stack_size(); if (evalctx->numArgs() == 0) d=1; // parent module else if (evalctx->numArgs() == 1) { @@ -930,7 +800,7 @@ ValuePtr builtin_parent_module(const Context *, const EvalContext *evalctx) PRINTB("WARNING: Parent module index (%d) greater than the number of modules on the stack", n); return ValuePtr::undefined; } - return ValuePtr(Module::stack_element(s - 1 - n)); + return ValuePtr(UserModule::stack_element(s - 1 - n)); } ValuePtr builtin_norm(const Context *, const EvalContext *evalctx) diff --git a/src/function.cc b/src/function.cc new file mode 100644 index 00000000..80726080 --- /dev/null +++ b/src/function.cc @@ -0,0 +1,140 @@ +/* + * OpenSCAD (www.openscad.org) + * Copyright (C) 2009-2011 Clifford Wolf and + * Marius Kintel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * As a special exception, you have permission to link this program + * with the CGAL library and distribute executables, as long as you + * follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from CGAL. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "function.h" +#include "evalcontext.h" +#include "expression.h" + +AbstractFunction::~AbstractFunction() +{ +} + +UserFunction::UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr) + : name(name), definition_arguments(definition_arguments), expr(expr) +{ +} + +UserFunction::~UserFunction() +{ +} + +ValuePtr UserFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const +{ + if (!expr) return ValuePtr::undefined; + Context c(ctx); + c.setVariables(definition_arguments, evalctx); + ValuePtr result = expr->evaluate(&c); + + return result; +} + +std::string UserFunction::dump(const std::string &indent, const std::string &name) const +{ + std::stringstream dump; + dump << indent << "function " << name << "("; + for (size_t i=0; i < definition_arguments.size(); i++) { + const Assignment &arg = definition_arguments[i]; + if (i > 0) dump << ", "; + dump << arg.name; + if (arg.expr) dump << " = " << *arg.expr; + } + dump << ") = " << *expr << ";\n"; + return dump.str(); +} + +class FunctionTailRecursion : public UserFunction +{ +private: + bool invert; + shared_ptr op; + shared_ptr call; + shared_ptr endexpr; + +public: + FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, + shared_ptr expr, shared_ptr call, + shared_ptr endexpr, bool invert) + : UserFunction(name, definition_arguments, expr), + invert(invert), op(expr), call(call), endexpr(endexpr) { + } + + virtual ~FunctionTailRecursion() { } + + virtual ValuePtr 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->arguments); + Context tmp(&c); + unsigned int counter = 0; + while (invert ^ this->op->cond->evaluate(&c)) { + tmp.setVariables(definition_arguments, &ec); + c.apply_variables(tmp); + + if (counter++ == 1000000) throw RecursionException::create("function", this->name); + } + + ValuePtr result = endexpr->evaluate(&c); + + return result; + } +}; + +UserFunction *UserFunction::create(const char *name, AssignmentList &definition_arguments, shared_ptr expr) +{ + if (shared_ptr ternary = dynamic_pointer_cast(expr)) { + shared_ptr ifcall = dynamic_pointer_cast(ternary->ifexpr); + shared_ptr elsecall = dynamic_pointer_cast(ternary->elseexpr); + if (ifcall && !elsecall) { + if (name == ifcall->name) { + return new FunctionTailRecursion(name, definition_arguments, ternary, ifcall, ternary->elseexpr, false); + } + } else if (elsecall && !ifcall) { + if (name == elsecall->name) { + return new FunctionTailRecursion(name, definition_arguments, ternary, elsecall, ternary->ifexpr, true); + } + } + } + return new UserFunction(name, definition_arguments, expr); +} + +BuiltinFunction::~BuiltinFunction() +{ +} + +ValuePtr BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const +{ + return eval_func(ctx, evalctx); +} + +std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const +{ + std::stringstream dump; + dump << indent << "builtin function " << name << "();\n"; + return dump.str(); +} diff --git a/src/function.h b/src/function.h index c9449c74..42360646 100644 --- a/src/function.h +++ b/src/function.h @@ -1,13 +1,14 @@ #pragma once +#include "AST.h" #include "value.h" -#include "typedefs.h" +#include "Assignment.h" #include "feature.h" #include #include -class AbstractFunction +class AbstractFunction : public ASTNode { private: const Feature *feature; @@ -17,8 +18,8 @@ public: virtual ~AbstractFunction(); virtual bool is_experimental() const { return feature != NULL; } virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } - virtual ValuePtr evaluate(const class Context *ctx, const class EvalContext *evalctx) const; - virtual std::string dump(const std::string &indent, const std::string &name) const; + virtual ValuePtr evaluate(const class Context *ctx, const class EvalContext *evalctx) const = 0; + virtual std::string dump(const std::string &indent, const std::string &name) const = 0; }; class BuiltinFunction : public AbstractFunction @@ -35,19 +36,19 @@ public: virtual std::string dump(const std::string &indent, const std::string &name) const; }; -class Function : public AbstractFunction +class UserFunction : public AbstractFunction { public: - std::string name; + std::string name; AssignmentList definition_arguments; - Expression *expr; + shared_ptr expr; - Function(const char *name, AssignmentList &definition_arguments, Expression *expr); - virtual ~Function(); + UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr); + virtual ~UserFunction(); 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); + static UserFunction *create(const char *name, AssignmentList &definition_arguments, shared_ptr expr); }; diff --git a/src/import.cc b/src/import.cc index 36fdfb21..b75297f7 100644 --- a/src/import.cc +++ b/src/import.cc @@ -27,6 +27,7 @@ #include "importnode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "polyset.h" #include "Polygon2d.h" #include "evalcontext.h" diff --git a/src/lexer.l b/src/lexer.l index 9c74982a..e9bfa6ec 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -27,10 +27,10 @@ %{ #include -#include "typedefs.h" #include "handle_dep.h" #include "printutils.h" #include "parsersettings.h" +#include "Assignment.h" #include "parser_yacc.h" #include "module.h" #include diff --git a/src/linearextrude.cc b/src/linearextrude.cc index ff428f0e..ea70adee 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -27,6 +27,7 @@ #include "linearextrudenode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "printutils.h" #include "fileutils.h" diff --git a/src/localscope.cc b/src/localscope.cc index fc9b12fa..9556abbb 100644 --- a/src/localscope.cc +++ b/src/localscope.cc @@ -1,7 +1,7 @@ #include "localscope.h" #include "modcontext.h" #include "module.h" -#include "typedefs.h" +#include "ModuleInstantiation.h" #include "expression.h" #include "function.h" @@ -32,7 +32,7 @@ std::string LocalScope::dump(const std::string &indent) const dump << m.second->dump(indent, m.first); } for(const auto &ass : this->assignments) { - dump << indent << ass.first << " = " << *ass.second << ";\n"; + dump << indent << ass.name << " = " << *ass.expr << ";\n"; } for(const auto &inst : this->children) { dump << inst->dump(indent); @@ -61,6 +61,6 @@ std::vector LocalScope::instantiateChildren(const Context *evalct void LocalScope::apply(Context &ctx) const { for(const auto &ass : this->assignments) { - ctx.set_variable(ass.first, ass.second->evaluate(&ctx)); + ctx.set_variable(ass.name, ass.expr->evaluate(&ctx)); } } diff --git a/src/localscope.h b/src/localscope.h index b7e1f23e..ea246ef8 100644 --- a/src/localscope.h +++ b/src/localscope.h @@ -1,6 +1,6 @@ #pragma once -#include "typedefs.h" +#include "Assignment.h" #include class LocalScope @@ -12,11 +12,11 @@ public: size_t numElements() const { return assignments.size() + children.size(); } std::string dump(const std::string &indent) const; std::vector instantiateChildren(const class Context *evalctx) const; - void addChild(ModuleInstantiation *ch); + void addChild(class ModuleInstantiation *ch); void apply(Context &ctx) const; AssignmentList assignments; - ModuleInstantiationList children; + std::vector children; typedef std::unordered_map FunctionContainer; FunctionContainer functions; typedef std::unordered_map AbstractModuleContainer; diff --git a/src/modcontext.cc b/src/modcontext.cc index 390bf029..4ae824a3 100644 --- a/src/modcontext.cc +++ b/src/modcontext.cc @@ -3,6 +3,7 @@ #include "modcontext.h" #include "module.h" +#include "ModuleInstantiation.h" #include "expression.h" #include "function.h" #include "printutils.h" @@ -64,14 +65,14 @@ void ModuleContext::evaluateAssignments(const AssignmentList &assignments) } #endif -void ModuleContext::initializeModule(const class Module &module) +void ModuleContext::initializeModule(const class UserModule &module) { this->setVariables(module.definition_arguments, evalctx); // FIXME: Don't access module members directly this->functions_p = &module.scope.functions; this->modules_p = &module.scope.modules; for(const auto &ass : module.scope.assignments) { - this->set_variable(ass.first, ass.second->evaluate(this)); + this->set_variable(ass.name, ass.expr->evaluate(this)); } // Experimental code. See issue #399 @@ -89,7 +90,7 @@ void ModuleContext::registerBuiltin() this->functions_p = &scope.functions; this->modules_p = &scope.modules; for(const auto &ass : scope.assignments) { - this->set_variable(ass.first, ass.second->evaluate(this)); + this->set_variable(ass.name, ass.expr->evaluate(this)); } this->set_constant("PI", ValuePtr(M_PI)); @@ -152,11 +153,11 @@ std::string ModuleContext::dump(const AbstractModule *mod, const ModuleInstantia s << boost::format("ModuleContext: %p (%p)") % this % this->parent; s << boost::format(" document path: %s") % this->document_path; if (mod) { - const Module *m = dynamic_cast(mod); + const UserModule *m = dynamic_cast(mod); if (m) { s << " module args:"; for(const auto &arg : m->definition_arguments) { - s << boost::format(" %s = %s") % arg.first % variables[arg.first]; + s << boost::format(" %s = %s") % arg.name % variables[arg.name]; } } } @@ -184,7 +185,6 @@ FileContext::FileContext(const class FileModule &module, const Context *parent) ValuePtr FileContext::sub_evaluate_function(const std::string &name, const EvalContext *evalctx, FileModule *usedmod) const - { FileContext ctx(*usedmod, this->parent); ctx.initializeModule(*usedmod); @@ -235,3 +235,13 @@ AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, E return ModuleContext::instantiate_module(inst, evalctx); } + +void FileContext::initializeModule(const class FileModule &module) +{ + // FIXME: Don't access module members directly + this->functions_p = &module.scope.functions; + this->modules_p = &module.scope.modules; + for(const auto &ass : module.scope.assignments) { + this->set_variable(ass.name, ass.expr->evaluate(this)); + } +} diff --git a/src/modcontext.h b/src/modcontext.h index b0999bab..27d5c8c6 100644 --- a/src/modcontext.h +++ b/src/modcontext.h @@ -4,7 +4,7 @@ #include "module.h" /*! - This holds the context for a Module definition; keeps track of + This holds the context for a UserModule definition; keeps track of global variables, submodules and functions defined inside a module. NB! every .scad file defines a FileModule holding the contents of the file. @@ -15,7 +15,7 @@ public: ModuleContext(const Context *parent = NULL, const EvalContext *evalctx = NULL); virtual ~ModuleContext(); - void initializeModule(const Module &m); + void initializeModule(const UserModule &m); void registerBuiltin(); virtual ValuePtr evaluate_function(const std::string &name, const EvalContext *evalctx) const; @@ -44,6 +44,7 @@ class FileContext : public ModuleContext public: FileContext(const class FileModule &module, const Context *parent); virtual ~FileContext() {} + void initializeModule(const class FileModule &module); virtual ValuePtr evaluate_function(const std::string &name, const EvalContext *evalctx) const; virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst, diff --git a/src/module.cc b/src/module.cc index f22585bb..c5e6f65a 100644 --- a/src/module.cc +++ b/src/module.cc @@ -25,6 +25,7 @@ */ #include "module.h" +#include "ModuleInstantiation.h" #include "ModuleCache.h" #include "node.h" #include "builtin.h" @@ -78,103 +79,9 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n return dump.str(); } -ModuleInstantiation::~ModuleInstantiation() -{ -} +std::deque UserModule::module_stack; -IfElseModuleInstantiation::~IfElseModuleInstantiation() -{ -} - -/*! - Returns the absolute path to the given filename, unless it's empty. - - NB! This will actually search for the file, to be backwards compatible with <= 2013.01 - (see issue #217) -*/ -std::string ModuleInstantiation::getAbsolutePath(const std::string &filename) const -{ - if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) { - return boosty::absolute(fs::path(this->modpath) / filename).string(); - } - else { - return filename; - } -} - -std::string ModuleInstantiation::dump(const std::string &indent) const -{ - std::stringstream dump; - dump << indent; - dump << modname + "("; - for (size_t i=0; i < this->arguments.size(); i++) { - const Assignment &arg = this->arguments[i]; - if (i > 0) dump << ", "; - if (!arg.first.empty()) dump << arg.first << " = "; - dump << *arg.second; - } - if (scope.numElements() == 0) { - dump << ");\n"; - } else if (scope.numElements() == 1) { - dump << ") "; - dump << scope.dump(""); - } else { - dump << ") {\n"; - dump << scope.dump(indent + "\t"); - dump << indent << "}\n"; - } - return dump.str(); -} - -std::string IfElseModuleInstantiation::dump(const std::string &indent) const -{ - std::stringstream dump; - dump << ModuleInstantiation::dump(indent); - dump << indent; - if (else_scope.numElements() > 0) { - dump << indent << "else "; - if (else_scope.numElements() == 1) { - dump << else_scope.dump(""); - } - else { - dump << "{\n"; - dump << else_scope.dump(indent + "\t"); - dump << indent << "}\n"; - } - } - return dump.str(); -} - -AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const -{ - EvalContext c(ctx, this->arguments, &this->scope); - -#if 0 && DEBUG - PRINT("New eval ctx:"); - c.dump(NULL, this); -#endif - - AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx - return node; -} - -std::vector ModuleInstantiation::instantiateChildren(const Context *evalctx) const -{ - return this->scope.instantiateChildren(evalctx); -} - -std::vector IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const -{ - return this->else_scope.instantiateChildren(evalctx); -} - -std::deque Module::module_stack; - -Module::~Module() -{ -} - -AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const +AbstractNode *UserModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const { if (StackCheck::inst()->check()) { throw RecursionException::create("module", inst->name()); @@ -204,7 +111,7 @@ AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation return node; } -std::string Module::dump(const std::string &indent, const std::string &name) const +std::string UserModule::dump(const std::string &indent, const std::string &name) const { std::stringstream dump; std::string tab; @@ -213,8 +120,8 @@ std::string Module::dump(const std::string &indent, const std::string &name) con for (size_t i=0; i < this->definition_arguments.size(); i++) { const Assignment &arg = this->definition_arguments[i]; if (i > 0) dump << ", "; - dump << arg.first; - if (arg.second) dump << " = " << *arg.second; + dump << arg.name; + if (arg.expr) dump << " = " << *arg.expr; } dump << ") {\n"; tab = "\t"; @@ -231,6 +138,11 @@ FileModule::~FileModule() delete context; } +std::string FileModule::dump(const std::string &indent, const std::string &name) const +{ + return scope.dump(indent); +} + void FileModule::registerUse(const std::string path) { std::string extraw = boosty::extension_str(fs::path(path)); std::string ext = boost::algorithm::to_lower_copy(extraw); @@ -339,12 +251,12 @@ bool FileModule::handleDependencies() return somethingchanged; } -AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) +AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const { assert(evalctx == NULL); - delete context; - context = new FileContext(*this, ctx); + delete this->context; + this->context = new FileContext(*this, ctx); AbstractNode *node = new RootNode(inst); try { @@ -363,11 +275,8 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat ValuePtr FileModule::lookup_variable(const std::string &name) const { - if (!context) { - return ValuePtr::undefined; - } - - return context->lookup_variable(name, true); + if (!this->context) return ValuePtr::undefined; + return this->context->lookup_variable(name, true); } void register_builtin_group() diff --git a/src/module.h b/src/module.h index 3ac331eb..a95647f0 100644 --- a/src/module.h +++ b/src/module.h @@ -9,55 +9,12 @@ #include #include +#include "AST.h" #include "value.h" -#include "typedefs.h" #include "localscope.h" #include "feature.h" -class ModuleInstantiation -{ -public: - ModuleInstantiation(const std::string &name = "") - : tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } - virtual ~ModuleInstantiation(); - - virtual std::string dump(const std::string &indent) const; - class AbstractNode *evaluate(const class Context *ctx) const; - std::vector instantiateChildren(const Context *evalctx) const; - - void setPath(const std::string &path) { this->modpath = path; } - const std::string &path() const { return this->modpath; } - std::string getAbsolutePath(const std::string &filename) const; - - const std::string &name() const { return this->modname; } - bool isBackground() const { return this->tag_background; } - bool isHighlight() const { return this->tag_highlight; } - bool isRoot() const { return this->tag_root; } - - AssignmentList arguments; - LocalScope scope; - - bool tag_root; - bool tag_highlight; - bool tag_background; -protected: - std::string modname; - std::string modpath; - - friend class Module; -}; - -class IfElseModuleInstantiation : public ModuleInstantiation { -public: - IfElseModuleInstantiation() : ModuleInstantiation("if") { } - virtual ~IfElseModuleInstantiation(); - std::vector instantiateElseChildren(const Context *evalctx) const; - virtual std::string dump(const std::string &indent) const; - - LocalScope else_scope; -}; - -class AbstractModule +class AbstractModule : public ASTNode { private: const Feature *feature; @@ -81,12 +38,12 @@ public: virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const; }; -class Module : public AbstractModule +class UserModule : public AbstractModule { public: - Module() { } - Module(const Feature& feature) : AbstractModule(feature) { } - virtual ~Module(); + UserModule() { } + UserModule(const Feature& feature) : AbstractModule(feature) { } + virtual ~UserModule() {} virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; virtual std::string dump(const std::string &indent, const std::string &name) const; @@ -101,31 +58,31 @@ private: static std::deque module_stack; }; -// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really -// inherit from a Module -class FileModule : public Module +class FileModule : public AbstractModule { public: FileModule() : context(NULL), is_handling_dependencies(false) {} virtual ~FileModule(); + virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; + virtual std::string dump(const std::string &indent, const std::string &name) const; void setModulePath(const std::string &path) { this->path = path; } const std::string &modulePath() const { return this->path; } void registerUse(const std::string path); void registerInclude(const std::string &localpath, const std::string &fullpath); bool includesChanged() const; bool handleDependencies(); - virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL); bool hasIncludes() const { return !this->includes.empty(); } bool usesLibraries() const { return !this->usedlibs.empty(); } bool isHandlingDependencies() const { return this->is_handling_dependencies; } - ValuePtr lookup_variable(const std::string &name) const; + ValuePtr lookup_variable(const std::string &name) const; + LocalScope scope; typedef std::unordered_set ModuleContainer; ModuleContainer usedlibs; private: - /** Reference to retain the context that was used in the last evaluation */ - class FileContext *context; + // Reference to retain the context that was used in the last evaluation + mutable class FileContext *context = nullptr; struct IncludeFile { std::string filename; bool valid; diff --git a/src/node.cc b/src/node.cc index 23f1a4ad..b95746eb 100644 --- a/src/node.cc +++ b/src/node.cc @@ -26,6 +26,7 @@ #include "node.h" #include "module.h" +#include "ModuleInstantiation.h" #include "progress.h" #include "visitor.h" #include "stl-utils.h" diff --git a/src/nodedumper.cc b/src/nodedumper.cc index 15d80b72..43ada8c7 100644 --- a/src/nodedumper.cc +++ b/src/nodedumper.cc @@ -1,6 +1,7 @@ #include "nodedumper.h" #include "state.h" #include "module.h" +#include "ModuleInstantiation.h" #include #include diff --git a/src/offset.cc b/src/offset.cc index 0064c9a7..3a71c7f9 100644 --- a/src/offset.cc +++ b/src/offset.cc @@ -27,6 +27,7 @@ #include "offsetnode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "printutils.h" #include "fileutils.h" diff --git a/src/openscad.cc b/src/openscad.cc index f886ba57..5f7fc94a 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -27,6 +27,7 @@ #include "openscad.h" #include "node.h" #include "module.h" +#include "ModuleInstantiation.h" #include "modcontext.h" #include "value.h" #include "export.h" diff --git a/src/parser.y b/src/parser.y index 86bc742d..7a09083e 100644 --- a/src/parser.y +++ b/src/parser.y @@ -34,8 +34,9 @@ #include #endif -#include "typedefs.h" #include "module.h" +#include "ModuleInstantiation.h" +#include "Assignment.h" #include "expression.h" #include "value.h" #include "function.h" @@ -76,9 +77,10 @@ fs::path parser_sourcefile; double number; class Value *value; class Expression *expr; + class Vector *vec; class ModuleInstantiation *inst; class IfElseModuleInstantiation *ifelse; - Assignment *arg; + class Assignment *arg; AssignmentList *args; } @@ -119,7 +121,7 @@ fs::path parser_sourcefile; %left '.' %type expr -%type vector_expr +%type vector_expr %type list_comprehension_elements %type list_comprehension_elements_p %type list_comprehension_elements_or_expr @@ -160,7 +162,8 @@ statement: | assignment | TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { - Module *newmodule = new Module(); + UserModule *newmodule = new UserModule(); + printf("Loc: %d\n", @$.first_line); newmodule->definition_arguments = *$4; scope_stack.top()->modules[$2] = newmodule; scope_stack.push(&newmodule->scope); @@ -173,7 +176,7 @@ statement: } | TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { - Function *func = Function::create($2, *$4, $8); + UserFunction *func = UserFunction::create($2, *$4, shared_ptr($8)); scope_stack.top()->functions[$2] = func; free($2); delete $4; @@ -191,8 +194,8 @@ assignment: { bool found = false; for (auto& iter : scope_stack.top()->assignments) { - if (iter.first == $1) { - iter.second = shared_ptr($3); + if (iter.name == $1) { + iter.expr = shared_ptr($3); found = true; break; } @@ -309,107 +312,107 @@ single_module_instantiation: expr: TOK_TRUE { - $$ = new ExpressionConst(ValuePtr(true)); + $$ = new Literal(ValuePtr(true)); } | TOK_FALSE { - $$ = new ExpressionConst(ValuePtr(false)); + $$ = new Literal(ValuePtr(false)); } | TOK_UNDEF { - $$ = new ExpressionConst(ValuePtr::undefined); + $$ = new Literal(ValuePtr::undefined); } | TOK_ID { - $$ = new ExpressionLookup($1); + $$ = new Lookup($1); free($1); } | expr '.' TOK_ID { - $$ = new ExpressionMember($1, $3); - free($3); + $$ = new MemberLookup($1, $3); + free($3); } | TOK_STRING { - $$ = new ExpressionConst(ValuePtr(std::string($1))); - free($1); + $$ = new Literal(ValuePtr(std::string($1))); + free($1); } | TOK_NUMBER { - $$ = new ExpressionConst(ValuePtr($1)); + $$ = new Literal(ValuePtr($1)); } | TOK_LET '(' arguments_call ')' expr %prec LET { - $$ = new ExpressionLet(*$3, $5); - delete $3; + $$ = new Let(*$3, $5); + delete $3; } | '[' expr ':' expr ']' { - $$ = new ExpressionRange($2, $4); + $$ = new Range($2, $4); } | '[' expr ':' expr ':' expr ']' { - $$ = new ExpressionRange($2, $4, $6); + $$ = new Range($2, $4, $6); } | '[' optional_commas ']' { - $$ = new ExpressionConst(ValuePtr(Value::VectorType())); + $$ = new Literal(ValuePtr(Value::VectorType())); } | '[' vector_expr optional_commas ']' { - $$ = $2; + $$ = $2; } | expr '*' expr { - $$ = new ExpressionMultiply($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Multiply, $3); } | expr '/' expr { - $$ = new ExpressionDivision($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Divide, $3); } | expr '%' expr { - $$ = new ExpressionModulo($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Modulo, $3); } | expr '+' expr { - $$ = new ExpressionPlus($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Plus, $3); } | expr '-' expr { - $$ = new ExpressionMinus($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Minus, $3); } | expr '<' expr { - $$ = new ExpressionLess($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Less, $3); } | expr LE expr { - $$ = new ExpressionLessOrEqual($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LessEqual, $3); } | expr EQ expr { - $$ = new ExpressionEqual($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Equal, $3); } | expr NE expr { - $$ = new ExpressionNotEqual($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::NotEqual, $3); } | expr GE expr { - $$ = new ExpressionGreaterOrEqual($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::GreaterEqual, $3); } | expr '>' expr { - $$ = new ExpressionGreater($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Greater, $3); } | expr AND expr { - $$ = new ExpressionLogicalAnd($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LogicalAnd, $3); } | expr OR expr { - $$ = new ExpressionLogicalOr($1, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LogicalOr, $3); } | '+' expr { @@ -417,29 +420,29 @@ expr: } | '-' expr { - $$ = new ExpressionInvert($2); + $$ = new UnaryOp(UnaryOp::Op::Negate, $2); } | '!' expr { - $$ = new ExpressionNot($2); + $$ = new UnaryOp(UnaryOp::Op::Not, $2); } | '(' expr ')' { - $$ = $2; + $$ = $2; } | expr '?' expr ':' expr { - $$ = new ExpressionTernary($1, $3, $5); + $$ = new TernaryOp($1, $3, $5); } | expr '[' expr ']' { - $$ = new ExpressionArrayLookup($1, $3); + $$ = new ArrayLookup($1, $3); } | TOK_ID '(' arguments_call ')' { - $$ = new ExpressionFunctionCall($1, *$3); - free($1); - delete $3; + $$ = new FunctionCall($1, *$3); + free($1); + delete $3; } ; @@ -448,12 +451,12 @@ list_comprehension_elements: be parsed as an expression) */ TOK_LET '(' arguments_call ')' list_comprehension_elements_p { - $$ = new ExpressionLcLet(*$3, $5); - delete $3; + $$ = new LcLet(*$3, $5); + delete $3; } | TOK_EACH list_comprehension_elements_or_expr { - $$ = new ExpressionLcEach($2); + $$ = new LcEach($2); } | TOK_FOR '(' arguments_call ')' list_comprehension_elements_or_expr { @@ -463,24 +466,24 @@ list_comprehension_elements: for (int i = $3->size()-1; i >= 0; i--) { AssignmentList arglist; arglist.push_back((*$3)[i]); - Expression *e = new ExpressionLcFor(arglist, $$); + Expression *e = new LcFor(arglist, $$); $$ = e; } delete $3; } | TOK_FOR '(' arguments_call ';' expr ';' arguments_call ')' list_comprehension_elements_or_expr { - $$ = new ExpressionLcForC(*$3, *$7, $5, $9); + $$ = new LcForC(*$3, *$7, $5, $9); delete $3; delete $7; } | TOK_IF '(' expr ')' list_comprehension_elements_or_expr { - $$ = new ExpressionLcIf($3, $5, 0); + $$ = new LcIf($3, $5, 0); } | TOK_IF '(' expr ')' list_comprehension_elements_or_expr TOK_ELSE list_comprehension_elements_or_expr { - $$ = new ExpressionLcIf($3, $5, $7); + $$ = new LcIf($3, $5, $7); } ; @@ -506,16 +509,18 @@ optional_commas: vector_expr: expr { - $$ = new ExpressionVector($1); + $$ = new Vector(); + $$->push_back($1); } | list_comprehension_elements { - $$ = new ExpressionVector($1); + $$ = new Vector(); + $$->push_back($1); } | vector_expr ',' optional_commas list_comprehension_elements_or_expr { - $$ = $1; - $$->children.push_back($4); + $$ = $1; + $$->push_back($4); } ; diff --git a/src/projection.cc b/src/projection.cc index 8929c07a..f3beb4c9 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -26,6 +26,7 @@ #include "projectionnode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "printutils.h" #include "builtin.h" diff --git a/src/render.cc b/src/render.cc index 12c5a567..df6e2be9 100644 --- a/src/render.cc +++ b/src/render.cc @@ -26,6 +26,7 @@ #include "rendernode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "builtin.h" #include "polyset.h" diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index 926067a7..606f0fcc 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -26,6 +26,7 @@ #include "rotateextrudenode.h" #include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "printutils.h" #include "fileutils.h" diff --git a/src/surface.cc b/src/surface.cc index 0067112c..2df4596b 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -25,6 +25,7 @@ */ #include "module.h" +#include "ModuleInstantiation.h" #include "node.h" #include "polyset.h" #include "evalcontext.h" diff --git a/src/transform.cc b/src/transform.cc index 05def34e..c963f7f3 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -25,7 +25,7 @@ */ #include "transformnode.h" -#include "module.h" +#include "ModuleInstantiation.h" #include "evalcontext.h" #include "polyset.h" #include "builtin.h" diff --git a/src/typedefs.h b/src/typedefs.h deleted file mode 100644 index a0c5ecbc..00000000 --- a/src/typedefs.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include -#include "memory.h" - -class Assignment : public std::pair> -{ -public: - Assignment(std::string name, - shared_ptr expr = shared_ptr()) { - first = name; second = expr; - } -}; - -typedef std::vector AssignmentList; -typedef std::vector ModuleInstantiationList; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e3f30c82..75dc1282 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -675,9 +675,11 @@ set(CORE_SOURCES ../src/hash.cc ../src/expr.cc ../src/func.cc + ../src/function.cc ../src/stackcheck.cc ../src/localscope.cc ../src/module.cc + ../src/ModuleInstantiation.cc ../src/ModuleCache.cc ../src/node.cc ../src/context.cc diff --git a/tests/CSGTextRenderer.cc b/tests/CSGTextRenderer.cc index f5ab999c..e21dd792 100644 --- a/tests/CSGTextRenderer.cc +++ b/tests/CSGTextRenderer.cc @@ -5,7 +5,7 @@ #include #include "visitor.h" #include "state.h" -#include "module.h" // FIXME: Temporarily for ModuleInstantiation +#include "ModuleInstantiation.h" #include "csgops.h" #include "transformnode.h" diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index 61a9d3e4..58259467 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -30,6 +30,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" +#include "ModuleInstantiation.h" #include "modcontext.h" #include "value.h" #include "export.h" diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 11e687d9..66796d9f 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -31,6 +31,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" +#include "ModuleInstantiation.h" #include "modcontext.h" #include "value.h" #include "export.h" diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc index 78398241..1e81759e 100644 --- a/tests/modulecachetest.cc +++ b/tests/modulecachetest.cc @@ -29,6 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" +#include "ModuleInstantiation.h" #include "modcontext.h" #include "value.h" #include "export.h" diff --git a/xcode/OpenSCAD.xcodeproj/xcshareddata/xcschemes/OpenSCAD.app.xcscheme b/xcode/OpenSCAD.xcodeproj/xcshareddata/xcschemes/OpenSCAD.app.xcscheme index e09efcbb..9d9c2e6a 100644 --- a/xcode/OpenSCAD.xcodeproj/xcshareddata/xcschemes/OpenSCAD.app.xcscheme +++ b/xcode/OpenSCAD.xcodeproj/xcshareddata/xcschemes/OpenSCAD.app.xcscheme @@ -23,10 +23,10 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -38,16 +38,19 @@ ReferencedContainer = "container:OpenSCAD.xcodeproj"> + + @@ -77,7 +80,7 @@ isEnabled = "NO"> From 7800683cf1fd563668d813b808ed49cc611cd6f9 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 8 May 2016 22:15:57 -0400 Subject: [PATCH 02/11] AST refacroting: Green refactoring preparing for a more general visitor system: Made accept() a macro and use a common supertype BaseVisitable. --- src/BaseVisitable.h | 15 +++++++++++++++ src/cgaladvnode.h | 4 +--- src/colornode.h | 4 +--- src/csgops.h | 4 +--- src/importnode.h | 4 +--- src/linearextrudenode.h | 4 +--- src/node.cc | 31 ------------------------------- src/node.h | 19 ++++++++++--------- src/offsetnode.h | 4 +--- src/primitives.cc | 4 +--- src/projectionnode.h | 4 +--- src/rendernode.h | 4 +--- src/rotateextrudenode.h | 4 +--- src/surface.cc | 4 +--- src/textnode.h | 5 +---- src/transformnode.h | 4 +--- 16 files changed, 38 insertions(+), 80 deletions(-) create mode 100644 src/BaseVisitable.h diff --git a/src/BaseVisitable.h b/src/BaseVisitable.h new file mode 100644 index 00000000..ecc1fc85 --- /dev/null +++ b/src/BaseVisitable.h @@ -0,0 +1,15 @@ +#pragma once + +#include "visitor.h" + +class BaseVisitable +{ +public: + virtual ~BaseVisitable() {} + virtual Response accept(class State&, Visitor&) const = 0; +}; + +#define VISITABLE() \ + virtual Response accept(class State &state, Visitor &visitor) const { \ + return visitor.visit(state, *this); \ + } diff --git a/src/cgaladvnode.h b/src/cgaladvnode.h index a2f81fe7..b9ca654d 100644 --- a/src/cgaladvnode.h +++ b/src/cgaladvnode.h @@ -16,13 +16,11 @@ enum cgaladv_type_e { class CgaladvNode : public AbstractNode { public: + VISITABLE(); CgaladvNode(const ModuleInstantiation *mi, cgaladv_type_e type) : AbstractNode(mi), type(type) { convexity = 1; } virtual ~CgaladvNode() { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const; diff --git a/src/colornode.h b/src/colornode.h index b1c73eff..2a5329ca 100644 --- a/src/colornode.h +++ b/src/colornode.h @@ -7,10 +7,8 @@ class ColorNode : public AbstractNode { public: + VISITABLE(); ColorNode(const ModuleInstantiation *mi) : AbstractNode(mi) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const; diff --git a/src/csgops.h b/src/csgops.h index f01cbce5..a1b55e0d 100644 --- a/src/csgops.h +++ b/src/csgops.h @@ -7,11 +7,9 @@ class CsgOpNode : public AbstractNode { public: + VISITABLE(); OpenSCADOperator type; CsgOpNode(const ModuleInstantiation *mi, OpenSCADOperator type) : AbstractNode(mi), type(type) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const; }; diff --git a/src/importnode.h b/src/importnode.h index c8303c70..1544cd71 100644 --- a/src/importnode.h +++ b/src/importnode.h @@ -14,10 +14,8 @@ enum import_type_e { class ImportNode : public LeafNode { public: + VISITABLE(); ImportNode(const ModuleInstantiation *mi, import_type_e type) : LeafNode(mi), type(type) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const; diff --git a/src/linearextrudenode.h b/src/linearextrudenode.h index 27ab0a17..717eb4bf 100644 --- a/src/linearextrudenode.h +++ b/src/linearextrudenode.h @@ -7,6 +7,7 @@ class LinearExtrudeNode : public AbstractPolyNode { public: + VISITABLE(); LinearExtrudeNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) { convexity = slices = 0; fn = fs = fa = height = twist = 0; @@ -14,9 +15,6 @@ public: scale_x = scale_y = 1; center = has_twist = false; } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { return "linear_extrude"; } diff --git a/src/node.cc b/src/node.cc index b95746eb..f83c4cd1 100644 --- a/src/node.cc +++ b/src/node.cc @@ -47,37 +47,6 @@ AbstractNode::~AbstractNode() std::for_each(this->children.begin(), this->children.end(), del_fun()); } -Response AbstractNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - -Response AbstractIntersectionNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - -Response AbstractPolyNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - -Response GroupNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - -Response RootNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - - -Response LeafNode::accept(class State &state, Visitor &visitor) const -{ - return visitor.visit(state, *this); -} - std::string AbstractNode::toString() const { return this->name() + "()"; diff --git a/src/node.h b/src/node.h index bf2c3bb2..31cd11be 100644 --- a/src/node.h +++ b/src/node.h @@ -2,13 +2,13 @@ #include #include -#include "traverser.h" +#include "BaseVisitable.h" extern int progress_report_count; extern void (*progress_report_f)(const class AbstractNode*, void*, int); extern void *progress_report_vp; -void progress_report_prep(AbstractNode *root, void (*f)(const class AbstractNode *node, void *vp, int mark), void *vp); +void progress_report_prep(class AbstractNode *root, void (*f)(const class AbstractNode *node, void *vp, int mark), void *vp); void progress_report_fin(); /*! @@ -18,7 +18,7 @@ void progress_report_fin(); scratch for each compile. */ -class AbstractNode +class AbstractNode : public BaseVisitable { // FIXME: the idx_counter/idx is mostly (only?) for debugging. // We can hash on pointer value or smth. else. @@ -26,9 +26,9 @@ class AbstractNode // use smth. else to display node identifier in CSG tree output? static size_t idx_counter; // Node instantiation index public: + VISITABLE(); AbstractNode(const class ModuleInstantiation *mi); virtual ~AbstractNode(); - virtual Response accept(class State &state, class Visitor &visitor) const; virtual std::string toString() const; /*! The 'OpenSCAD name' of this node, defaults to classname, but can be overloaded to provide specialization for e.g. CSG nodes, primitive nodes etc. @@ -58,9 +58,9 @@ public: class AbstractIntersectionNode : public AbstractNode { public: + VISITABLE(); AbstractIntersectionNode(const ModuleInstantiation *mi) : AbstractNode(mi) { }; virtual ~AbstractIntersectionNode() { }; - virtual Response accept(class State &state, class Visitor &visitor) const; virtual std::string toString() const; virtual std::string name() const; }; @@ -68,9 +68,9 @@ public: class AbstractPolyNode : public AbstractNode { public: + VISITABLE(); AbstractPolyNode(const ModuleInstantiation *mi) : AbstractNode(mi) { }; virtual ~AbstractPolyNode() { }; - virtual Response accept(class State &state, class Visitor &visitor) const; enum render_mode_e { RENDER_CGAL, @@ -85,9 +85,9 @@ public: class GroupNode : public AbstractNode { public: + VISITABLE(); GroupNode(const class ModuleInstantiation *mi) : AbstractNode(mi) { } virtual ~GroupNode() { } - virtual Response accept(class State &state, class Visitor &visitor) const; virtual std::string name() const; }; @@ -97,18 +97,19 @@ public: class RootNode : public GroupNode { public: + VISITABLE(); + RootNode(const class ModuleInstantiation *mi) : GroupNode(mi) { } virtual ~RootNode() { } - virtual Response accept(class State &state, class Visitor &visitor) const; virtual std::string name() const; }; class LeafNode : public AbstractPolyNode { public: + VISITABLE(); LeafNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) { }; virtual ~LeafNode() { }; - virtual Response accept(class State &state, class Visitor &visitor) const; virtual const class Geometry *createGeometry() const = 0; }; diff --git a/src/offsetnode.h b/src/offsetnode.h index d8981fd4..cb0388b5 100644 --- a/src/offsetnode.h +++ b/src/offsetnode.h @@ -8,10 +8,8 @@ class OffsetNode : public AbstractPolyNode { public: + VISITABLE(); OffsetNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi), fn(0), fs(0), fa(0), delta(1), miter_limit(1000000.0), join_type(ClipperLib::jtRound) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { return "offset"; } diff --git a/src/primitives.cc b/src/primitives.cc index c0a55c30..d146f9d3 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -65,10 +65,8 @@ private: class PrimitiveNode : public LeafNode { public: + VISITABLE(); PrimitiveNode(const ModuleInstantiation *mi, primitive_type_e type) : LeafNode(mi), type(type) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { switch (this->type) { diff --git a/src/projectionnode.h b/src/projectionnode.h index 9ad1acd7..feb1b9a5 100644 --- a/src/projectionnode.h +++ b/src/projectionnode.h @@ -7,12 +7,10 @@ class ProjectionNode : public AbstractPolyNode { public: + VISITABLE(); ProjectionNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) { cut_mode = false; } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { return "projection"; } diff --git a/src/rendernode.h b/src/rendernode.h index 3ef59577..36f8ddbf 100644 --- a/src/rendernode.h +++ b/src/rendernode.h @@ -7,10 +7,8 @@ class RenderNode : public AbstractNode { public: + VISITABLE(); RenderNode(const ModuleInstantiation *mi) : AbstractNode(mi), convexity(1) { } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { return "render"; } diff --git a/src/rotateextrudenode.h b/src/rotateextrudenode.h index 728526ae..f9aa62bc 100644 --- a/src/rotateextrudenode.h +++ b/src/rotateextrudenode.h @@ -7,15 +7,13 @@ class RotateExtrudeNode : public AbstractPolyNode { public: + VISITABLE(); RotateExtrudeNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) { convexity = 0; fn = fs = fa = 0; origin_x = origin_y = scale = 0; angle = 360; } - virtual Response accept(class State &state, Visitor &visitor) const { - return visitor.visit(state, *this); - } virtual std::string toString() const; virtual std::string name() const { return "rotate_extrude"; } diff --git a/src/surface.cc b/src/surface.cc index 2df4596b..33300423 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -61,10 +61,8 @@ typedef std::unordered_map, double, boost::hash Date: Sun, 8 May 2016 22:16:59 -0400 Subject: [PATCH 03/11] Renamed Visitor to SettingsVisitor to avoid naming confusion --- src/Preferences.cc | 4 ++-- src/settings.cc | 6 +++--- src/settings.h | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Preferences.cc b/src/Preferences.cc index 0caf3ff8..869ffd2a 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -46,7 +46,7 @@ Preferences *Preferences::instance = NULL; const char * Preferences::featurePropertyName = "FeatureProperty"; Q_DECLARE_METATYPE(Feature *); -class SettingsReader : public Settings::Visitor +class SettingsReader : public Settings::SettingsVisitor { QSettings settings; Value getValue(const Settings::SettingsEntry& entry, const std::string& value) const { @@ -90,7 +90,7 @@ class SettingsReader : public Settings::Visitor } }; -class SettingsWriter : public Settings::Visitor +class SettingsWriter : public Settings::SettingsVisitor { virtual void handle(Settings::SettingsEntry& entry) const { Settings::Settings *s = Settings::Settings::inst(); diff --git a/src/settings.cc b/src/settings.cc index 818756bb..85093288 100644 --- a/src/settings.cc +++ b/src/settings.cc @@ -87,7 +87,7 @@ Settings::~Settings() { } -void Settings::visit(Visitor& visitor) +void Settings::visit(SettingsVisitor& visitor) { for (std::list::iterator it = entries.begin();it != entries.end();it++) { visitor.handle(*(*it)); @@ -109,11 +109,11 @@ void Settings::set(SettingsEntry& entry, const Value &val) entry._value = val; } -Visitor::Visitor() +SettingsVisitor::SettingsVisitor() { } -Visitor::~Visitor() +SettingsVisitor::~SettingsVisitor() { } diff --git a/src/settings.h b/src/settings.h index 2d08aafb..289114b9 100644 --- a/src/settings.h +++ b/src/settings.h @@ -55,7 +55,7 @@ public: static Settings *inst(bool erase = false); - void visit(class Visitor& visitor); + void visit(class SettingsVisitor& visitor); const Value &defaultValue(const SettingsEntry& entry); const Value &get(const SettingsEntry& entry); @@ -66,11 +66,11 @@ private: virtual ~Settings(); }; -class Visitor +class SettingsVisitor { public: - Visitor(); - virtual ~Visitor(); + SettingsVisitor(); + virtual ~SettingsVisitor(); virtual void handle(SettingsEntry& entry) const = 0; }; From d8523ae6be6036b173b28fd315b0ffc7ee8f3e5e Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 8 May 2016 22:44:15 -0400 Subject: [PATCH 04/11] AST refactor: Refactored the visitor system to a more general purpose visitor --- openscad.pro | 2 +- src/BaseVisitable.h | 37 +++++++++++++++++++++++++++----- src/CSGTreeEvaluator.cc | 2 +- src/CSGTreeEvaluator.h | 4 ++-- src/GeometryEvaluator.h | 4 ++-- src/{visitor.h => NodeVisitor.h} | 31 +++++++++++++++++++++----- src/Tree.cc | 1 + src/cgaladvnode.h | 1 - src/colornode.h | 1 - src/csgops.h | 1 - src/importnode.h | 1 - src/linearextrudenode.h | 1 - src/node.cc | 1 - src/nodedumper.h | 5 +++-- src/offsetnode.h | 1 - src/primitives.cc | 1 - src/projection.cc | 1 - src/projectionnode.h | 1 - src/rendernode.h | 1 - src/rotateextrude.cc | 1 - src/rotateextrudenode.h | 1 - src/surface.cc | 1 - src/textnode.h | 1 - src/transformnode.h | 1 - src/traverser.cc | 1 - src/traverser.h | 6 +++--- tests/CSGTextRenderer.cc | 1 - tests/CSGTextRenderer.h | 4 ++-- tests/csgtexttest.cc | 1 + 29 files changed, 74 insertions(+), 41 deletions(-) rename src/{visitor.h => NodeVisitor.h} (74%) diff --git a/openscad.pro b/openscad.pro index 74dde499..bc5dfe17 100644 --- a/openscad.pro +++ b/openscad.pro @@ -305,7 +305,7 @@ HEADERS += src/version_check.h \ src/value.h \ src/progress.h \ src/editor.h \ - src/visitor.h \ + src/NodeVisitor.h \ src/state.h \ src/traverser.h \ src/nodecache.h \ diff --git a/src/BaseVisitable.h b/src/BaseVisitable.h index ecc1fc85..da71da65 100644 --- a/src/BaseVisitable.h +++ b/src/BaseVisitable.h @@ -1,15 +1,42 @@ #pragma once -#include "visitor.h" +#include + +// FIXME: Default constructor Response() +enum Response {ContinueTraversal, AbortTraversal, PruneTraversal}; + +class BaseVisitor +{ +public: + virtual ~BaseVisitor() {} +}; + +template +class Visitor +{ +public: + virtual Response visit(class State &state, const T&) = 0; +}; class BaseVisitable { public: virtual ~BaseVisitable() {} - virtual Response accept(class State&, Visitor&) const = 0; + virtual Response accept(class State&, BaseVisitor&) const = 0; +protected: + template + static Response acceptImpl(class State &state, const T &node, BaseVisitor &visitor) { + if (Visitor *p = dynamic_cast*>(&visitor)) { + return p->visit(state, node); + } + // FIXME: If we want to allow for missing nodes in visitors, we need + // to handle it here, e.g. by calling some handler. + // See e.g. page 225 of Alexandrescu's "Modern C++ Design" + return AbortTraversal; + } }; #define VISITABLE() \ - virtual Response accept(class State &state, Visitor &visitor) const { \ - return visitor.visit(state, *this); \ - } + virtual Response accept(class State &state, BaseVisitor &visitor) const { \ + return acceptImpl(state, *this, visitor); \ + } diff --git a/src/CSGTreeEvaluator.cc b/src/CSGTreeEvaluator.cc index a1719795..080f4422 100644 --- a/src/CSGTreeEvaluator.cc +++ b/src/CSGTreeEvaluator.cc @@ -1,5 +1,5 @@ #include "CSGTreeEvaluator.h" -#include "visitor.h" +#include "traverser.h" #include "state.h" #include "csgops.h" #include "module.h" diff --git a/src/CSGTreeEvaluator.h b/src/CSGTreeEvaluator.h index d90483f7..b94a706d 100644 --- a/src/CSGTreeEvaluator.h +++ b/src/CSGTreeEvaluator.h @@ -4,11 +4,11 @@ #include #include #include -#include "visitor.h" +#include "NodeVisitor.h" #include "memory.h" #include "csgnode.h" -class CSGTreeEvaluator : public Visitor +class CSGTreeEvaluator : public NodeVisitor { public: CSGTreeEvaluator(const class Tree &tree, class GeometryEvaluator *geomevaluator = NULL) diff --git a/src/GeometryEvaluator.h b/src/GeometryEvaluator.h index 2a178138..3a11214b 100644 --- a/src/GeometryEvaluator.h +++ b/src/GeometryEvaluator.h @@ -1,6 +1,6 @@ #pragma once -#include "visitor.h" +#include "NodeVisitor.h" #include "enums.h" #include "memory.h" #include "Geometry.h" @@ -10,7 +10,7 @@ #include #include -class GeometryEvaluator : public Visitor +class GeometryEvaluator : public NodeVisitor { public: GeometryEvaluator(const class Tree &tree); diff --git a/src/visitor.h b/src/NodeVisitor.h similarity index 74% rename from src/visitor.h rename to src/NodeVisitor.h index 144d29bf..b637ad8d 100644 --- a/src/visitor.h +++ b/src/NodeVisitor.h @@ -1,12 +1,33 @@ #pragma once -#include "traverser.h" +#include "BaseVisitable.h" +#include "node.h" -class Visitor +class NodeVisitor : + public BaseVisitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor, + public Visitor { public: - Visitor() {} - virtual ~Visitor() {} + NodeVisitor() {} + virtual ~NodeVisitor() {} virtual Response visit(class State &state, const class AbstractNode &node) = 0; virtual Response visit(class State &state, const class AbstractIntersectionNode &node) { @@ -18,7 +39,7 @@ public: virtual Response visit(class State &state, const class GroupNode &node) { return visit(state, (const class AbstractNode &)node); } - virtual Response visit(class State &state, const class RootNode &node) { + virtual Response visit(class State &state, const RootNode &node) { return visit(state, (const class GroupNode &)node); } virtual Response visit(class State &state, const class LeafNode &node) { diff --git a/src/Tree.cc b/src/Tree.cc index 7264d89d..555d83f3 100644 --- a/src/Tree.cc +++ b/src/Tree.cc @@ -1,5 +1,6 @@ #include "Tree.h" #include "nodedumper.h" +#include "traverser.h" #include "printutils.h" #include diff --git a/src/cgaladvnode.h b/src/cgaladvnode.h index b9ca654d..beb94136 100644 --- a/src/cgaladvnode.h +++ b/src/cgaladvnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" #include "linalg.h" diff --git a/src/colornode.h b/src/colornode.h index 2a5329ca..d66f8cb2 100644 --- a/src/colornode.h +++ b/src/colornode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "linalg.h" class ColorNode : public AbstractNode diff --git a/src/csgops.h b/src/csgops.h index a1b55e0d..5d7543c5 100644 --- a/src/csgops.h +++ b/src/csgops.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "enums.h" class CsgOpNode : public AbstractNode diff --git a/src/importnode.h b/src/importnode.h index 1544cd71..95c27c5e 100644 --- a/src/importnode.h +++ b/src/importnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" enum import_type_e { diff --git a/src/linearextrudenode.h b/src/linearextrudenode.h index 717eb4bf..60ae45c3 100644 --- a/src/linearextrudenode.h +++ b/src/linearextrudenode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" class LinearExtrudeNode : public AbstractPolyNode diff --git a/src/node.cc b/src/node.cc index f83c4cd1..7feab01c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -28,7 +28,6 @@ #include "module.h" #include "ModuleInstantiation.h" #include "progress.h" -#include "visitor.h" #include "stl-utils.h" #include diff --git a/src/nodedumper.h b/src/nodedumper.h index 282dd803..2fb1c941 100644 --- a/src/nodedumper.h +++ b/src/nodedumper.h @@ -3,10 +3,11 @@ #include #include #include -#include "visitor.h" +#include "NodeVisitor.h" +#include "node.h" #include "nodecache.h" -class NodeDumper : public Visitor +class NodeDumper : public NodeVisitor { public: /*! If idPrefix is true, we will output "n:" in front of each node, diff --git a/src/offsetnode.h b/src/offsetnode.h index cb0388b5..8f45b681 100644 --- a/src/offsetnode.h +++ b/src/offsetnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" #include "clipper-utils.h" diff --git a/src/primitives.cc b/src/primitives.cc index d146f9d3..3eaba07f 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -31,7 +31,6 @@ #include "Polygon2d.h" #include "builtin.h" #include "printutils.h" -#include "visitor.h" #include "context.h" #include "calc.h" #include diff --git a/src/projection.cc b/src/projection.cc index f3beb4c9..6391b02d 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -30,7 +30,6 @@ #include "evalcontext.h" #include "printutils.h" #include "builtin.h" -#include "visitor.h" #include "polyset.h" #include diff --git a/src/projectionnode.h b/src/projectionnode.h index feb1b9a5..6e6fb2f6 100644 --- a/src/projectionnode.h +++ b/src/projectionnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include class ProjectionNode : public AbstractPolyNode diff --git a/src/rendernode.h b/src/rendernode.h index 36f8ddbf..59ec46b0 100644 --- a/src/rendernode.h +++ b/src/rendernode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include class RenderNode : public AbstractNode diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index 606f0fcc..34d7c38e 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -32,7 +32,6 @@ #include "fileutils.h" #include "builtin.h" #include "polyset.h" -#include "visitor.h" #include #include diff --git a/src/rotateextrudenode.h b/src/rotateextrudenode.h index f9aa62bc..9df2e402 100644 --- a/src/rotateextrudenode.h +++ b/src/rotateextrudenode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" class RotateExtrudeNode : public AbstractPolyNode diff --git a/src/surface.cc b/src/surface.cc index 33300423..24d0b740 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -33,7 +33,6 @@ #include "printutils.h" #include "fileutils.h" #include "handle_dep.h" // handle_dep() -#include "visitor.h" #include "lodepng.h" #include diff --git a/src/textnode.h b/src/textnode.h index b1de32e1..633a764c 100644 --- a/src/textnode.h +++ b/src/textnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "value.h" #include "FreetypeRenderer.h" diff --git a/src/transformnode.h b/src/transformnode.h index fa5eb012..1135ec4c 100644 --- a/src/transformnode.h +++ b/src/transformnode.h @@ -1,7 +1,6 @@ #pragma once #include "node.h" -#include "visitor.h" #include "linalg.h" class TransformNode : public AbstractNode diff --git a/src/traverser.cc b/src/traverser.cc index 780ab2b6..9355ba95 100644 --- a/src/traverser.cc +++ b/src/traverser.cc @@ -1,5 +1,4 @@ #include "traverser.h" -#include "visitor.h" #include "node.h" #include "state.h" #include diff --git a/src/traverser.h b/src/traverser.h index 2235075a..560a9a38 100644 --- a/src/traverser.h +++ b/src/traverser.h @@ -1,13 +1,13 @@ #pragma once -enum Response {ContinueTraversal, AbortTraversal, PruneTraversal}; +#include "node.h" class Traverser { public: enum TraversalType {PREFIX, POSTFIX, PRE_AND_POSTFIX}; - Traverser(class Visitor &visitor, const class AbstractNode &root, TraversalType travtype) + Traverser(BaseVisitor &visitor, const AbstractNode &root, TraversalType travtype) : visitor(visitor), root(root), traversaltype(travtype) { } virtual ~Traverser() { } @@ -17,7 +17,7 @@ public: Response traverse(const AbstractNode &node, const class State &state); private: - Visitor &visitor; + BaseVisitor &visitor; const AbstractNode &root; TraversalType traversaltype; }; diff --git a/tests/CSGTextRenderer.cc b/tests/CSGTextRenderer.cc index e21dd792..43bff72e 100644 --- a/tests/CSGTextRenderer.cc +++ b/tests/CSGTextRenderer.cc @@ -3,7 +3,6 @@ #include #include #include -#include "visitor.h" #include "state.h" #include "ModuleInstantiation.h" diff --git a/tests/CSGTextRenderer.h b/tests/CSGTextRenderer.h index e96bb1fb..607bbd62 100644 --- a/tests/CSGTextRenderer.h +++ b/tests/CSGTextRenderer.h @@ -1,7 +1,7 @@ #ifndef CSGTEXTRENDERER_H_ #define CSGTEXTRENDERER_H_ -#include "visitor.h" +#include "NodeVisitor.h" #include "CSGTextCache.h" #include "enums.h" @@ -12,7 +12,7 @@ using std::string; using std::map; using std::list; -class CSGTextRenderer : public Visitor +class CSGTextRenderer : public NodeVisitor { public: CSGTextRenderer(CSGTextCache &cache) : cache(cache) {} diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 66796d9f..5ce08399 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -39,6 +39,7 @@ #include "Tree.h" #include "PlatformUtils.h" #include "stackcheck.h" +#include "traverser.h" #ifndef _MSC_VER #include From 33e49a84a121ed4274e93f064f3884a1f9829ba5 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 9 May 2016 13:14:39 -0400 Subject: [PATCH 05/11] C++11: gcc-4.6.3 (Ubuntu 12.04) doesn't support non-static member initializers --- src/module.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/module.h b/src/module.h index a95647f0..0f96563f 100644 --- a/src/module.h +++ b/src/module.h @@ -61,7 +61,7 @@ private: class FileModule : public AbstractModule { public: - FileModule() : context(NULL), is_handling_dependencies(false) {} + FileModule() : context(nullptr), is_handling_dependencies(false) {} virtual ~FileModule(); virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; @@ -82,7 +82,7 @@ public: ModuleContainer usedlibs; private: // Reference to retain the context that was used in the last evaluation - mutable class FileContext *context = nullptr; + mutable class FileContext *context; struct IncludeFile { std::string filename; bool valid; From ae60056968ba827610ee7c913b517e0ae7c406c4 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 15 May 2016 22:18:31 -0400 Subject: [PATCH 06/11] Split the module file into module, FileModule, UserModule and GroupModule to better manage dependencies --- openscad.pro | 10 +- src/FileModule.cc | 185 +++++++++++++++++++++++++++++++++ src/FileModule.h | 49 +++++++++ src/GroupModule.cc | 47 +++++++++ src/GroupModule.h | 11 ++ src/ModuleCache.cc | 2 +- src/UserModule.cc | 90 ++++++++++++++++ src/UserModule.h | 27 +++++ src/context.cc | 2 +- src/evalcontext.cc | 2 +- src/exceptions.h | 1 + src/func.cc | 1 + src/lexer.l | 2 +- src/modcontext.cc | 4 +- src/modcontext.h | 8 +- src/module.cc | 236 +----------------------------------------- src/module.h | 95 ++--------------- src/parser.y | 3 +- tests/CMakeLists.txt | 3 + tests/tests-common.cc | 2 +- 20 files changed, 446 insertions(+), 334 deletions(-) create mode 100644 src/FileModule.cc create mode 100644 src/FileModule.h create mode 100644 src/GroupModule.cc create mode 100644 src/GroupModule.h create mode 100644 src/UserModule.cc create mode 100644 src/UserModule.h diff --git a/openscad.pro b/openscad.pro index bc5dfe17..e16f1034 100644 --- a/openscad.pro +++ b/openscad.pro @@ -235,12 +235,14 @@ HEADERS += src/AST.h \ src/Assignment.h \ src/expression.h \ src/function.h \ - src/module.h + src/module.h \ + src/UserModule.h SOURCES += src/ModuleInstantiation.cc \ src/expr.cc \ src/function.cc \ - src/module.cc + src/module.cc \ + src/UserModule.cc HEADERS += src/version_check.h \ src/ProgressWidget.h \ @@ -262,6 +264,8 @@ HEADERS += src/version_check.h \ src/AboutDialog.h \ src/FontListDialog.h \ src/FontListTableView.h \ + src/GroupModule.h \ + src/FileModule.h \ src/builtin.h \ src/calc.h \ src/context.h \ @@ -411,6 +415,8 @@ SOURCES += src/version_check.cc \ \ src/grid.cc \ src/hash.cc \ + src/GroupModule.cc \ + src/FileModule.cc \ src/builtin.cc \ src/calc.cc \ src/export.cc \ diff --git a/src/FileModule.cc b/src/FileModule.cc new file mode 100644 index 00000000..02aa6286 --- /dev/null +++ b/src/FileModule.cc @@ -0,0 +1,185 @@ +/* + * OpenSCAD (www.openscad.org) + * Copyright (C) 2009-2011 Clifford Wolf and + * Marius Kintel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * As a special exception, you have permission to link this program + * with the CGAL library and distribute executables, as long as you + * follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from CGAL. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "FileModule.h" +#include "ModuleCache.h" +#include "node.h" +#include "printutils.h" +#include "exceptions.h" +#include "modcontext.h" +#include "parsersettings.h" + +#include +namespace fs = boost::filesystem; +#include "boosty.h" +#include "FontCache.h" +#include + +FileModule::~FileModule() +{ + delete context; +} + +std::string FileModule::dump(const std::string &indent, const std::string &name) const +{ + return scope.dump(indent); +} + +void FileModule::registerUse(const std::string path) { + std::string extraw = boosty::extension_str(fs::path(path)); + std::string ext = boost::algorithm::to_lower_copy(extraw); + + if ((ext == ".otf") || (ext == ".ttf")) { + if (fs::is_regular(path)) { + FontCache::instance()->register_font_file(path); + } else { + PRINTB("ERROR: Can't read font with path '%s'", path); + } + } else { + usedlibs.insert(path); + } +} + +void FileModule::registerInclude(const std::string &localpath, + const std::string &fullpath) +{ + struct stat st; + memset(&st, 0, sizeof(struct stat)); + bool valid = stat(fullpath.c_str(), &st) == 0; + IncludeFile inc = {fullpath, valid, st.st_mtime}; + this->includes[localpath] = inc; +} + +bool FileModule::includesChanged() const +{ + for(const auto &item : this->includes) { + if (include_modified(item.second)) return true; + } + return false; +} + +bool FileModule::include_modified(const IncludeFile &inc) const +{ + struct stat st; + memset(&st, 0, sizeof(struct stat)); + + fs::path fullpath = find_valid_path(this->path, inc.filename); + bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false; + + if (valid && !inc.valid) return true; // Detect appearance of file but not removal + if (valid && st.st_mtime > inc.mtime) return true; + + return false; +} + +/*! + Check if any dependencies have been modified and recompile them. + Returns true if anything was recompiled. +*/ +bool FileModule::handleDependencies() +{ + if (this->is_handling_dependencies) return false; + this->is_handling_dependencies = true; + + bool somethingchanged = false; + std::vector> updates; + + // If a lib in usedlibs was previously missing, we need to relocate it + // by searching the applicable paths. We can identify a previously missing module + // as it will have a relative path. + for(auto filename : this->usedlibs) { + + bool wasmissing = false; + bool found = true; + + // Get an absolute filename for the module + if (!boosty::is_absolute(filename)) { + wasmissing = true; + fs::path fullpath = find_valid_path(this->path, filename); + if (!fullpath.empty()) { + updates.push_back(std::make_pair(filename, boosty::stringy(fullpath))); + filename = boosty::stringy(fullpath); + } + else { + found = false; + } + } + + if (found) { + bool wascached = ModuleCache::instance()->isCached(filename); + FileModule *oldmodule = ModuleCache::instance()->lookup(filename); + FileModule *newmodule; + bool changed = ModuleCache::instance()->evaluate(filename, newmodule); + // Detect appearance but not removal of files, and keep old module + // on compile errors (FIXME: Is this correct behavior?) + if (changed) { + PRINTDB(" %s: %p -> %p", filename % oldmodule % newmodule); + } + somethingchanged |= changed; + // Only print warning if we're not part of an automatic reload + if (!newmodule && !wascached && !wasmissing) { + PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename); + } + } + } + + // Relative filenames which were located is reinserted as absolute filenames + typedef std::pair stringpair; + for(const auto &files : updates) { + this->usedlibs.erase(files.first); + this->usedlibs.insert(files.second); + } + this->is_handling_dependencies = false; + return somethingchanged; +} + +AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const +{ + assert(evalctx == NULL); + + delete this->context; + this->context = new FileContext(*this, ctx); + AbstractNode *node = new RootNode(inst); + + try { + context->initializeModule(*this); + + // FIXME: Set document path to the path of the module + std::vector instantiatednodes = this->scope.instantiateChildren(context); + node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); + } + catch (EvaluationException &e) { + PRINT(e.what()); + } + + return node; +} + +ValuePtr FileModule::lookup_variable(const std::string &name) const +{ + if (!this->context) return ValuePtr::undefined; + return this->context->lookup_variable(name, true); +} diff --git a/src/FileModule.h b/src/FileModule.h new file mode 100644 index 00000000..5aacd230 --- /dev/null +++ b/src/FileModule.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include + +#include "module.h" +#include "value.h" +#include "localscope.h" + +class FileModule : public AbstractModule +{ +public: + FileModule() : context(nullptr), is_handling_dependencies(false) {} + virtual ~FileModule(); + + virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; + virtual std::string dump(const std::string &indent, const std::string &name) const; + void setModulePath(const std::string &path) { this->path = path; } + const std::string &modulePath() const { return this->path; } + void registerUse(const std::string path); + void registerInclude(const std::string &localpath, const std::string &fullpath); + bool includesChanged() const; + bool handleDependencies(); + bool hasIncludes() const { return !this->includes.empty(); } + bool usesLibraries() const { return !this->usedlibs.empty(); } + bool isHandlingDependencies() const { return this->is_handling_dependencies; } + ValuePtr lookup_variable(const std::string &name) const; + + LocalScope scope; + typedef std::unordered_set ModuleContainer; + ModuleContainer usedlibs; +private: + // Reference to retain the context that was used in the last evaluation + mutable class FileContext *context; + struct IncludeFile { + std::string filename; + bool valid; + time_t mtime; + }; + + bool include_modified(const IncludeFile &inc) const; + + typedef std::unordered_map IncludeContainer; + IncludeContainer includes; + bool is_handling_dependencies; + std::string path; +}; diff --git a/src/GroupModule.cc b/src/GroupModule.cc new file mode 100644 index 00000000..49928f69 --- /dev/null +++ b/src/GroupModule.cc @@ -0,0 +1,47 @@ +/* + * OpenSCAD (www.openscad.org) + * Copyright (C) 2009-2011 Clifford Wolf and + * Marius Kintel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * As a special exception, you have permission to link this program + * with the CGAL library and distribute executables, as long as you + * follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from CGAL. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "GroupModule.h" +#include "ModuleInstantiation.h" +#include "node.h" +#include "builtin.h" +#include "evalcontext.h" + +AbstractNode *GroupModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const +{ + (void)ctx; // avoid unusued parameter warning + + AbstractNode *node = new GroupNode(inst); + + node->children = inst->instantiateChildren(evalctx); + + return node; +} + +void register_builtin_group() +{ + Builtins::init("group", new GroupModule()); +} diff --git a/src/GroupModule.h b/src/GroupModule.h new file mode 100644 index 00000000..06f0fe8f --- /dev/null +++ b/src/GroupModule.h @@ -0,0 +1,11 @@ +#pragma once + +#include "module.h" + +class GroupModule : public AbstractModule +{ +public: + GroupModule() { } + virtual ~GroupModule() { } + virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const; +}; diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc index 8f27e4bc..cbfbd1c9 100644 --- a/src/ModuleCache.cc +++ b/src/ModuleCache.cc @@ -1,5 +1,5 @@ #include "ModuleCache.h" -#include "module.h" +#include "FileModule.h" #include "printutils.h" #include "openscad.h" diff --git a/src/UserModule.cc b/src/UserModule.cc new file mode 100644 index 00000000..af4d961a --- /dev/null +++ b/src/UserModule.cc @@ -0,0 +1,90 @@ +/* + * OpenSCAD (www.openscad.org) + * Copyright (C) 2009-2011 Clifford Wolf and + * Marius Kintel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * As a special exception, you have permission to link this program + * with the CGAL library and distribute executables, as long as you + * follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from CGAL. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "UserModule.h" +#include "ModuleInstantiation.h" +#include "node.h" +#include "evalcontext.h" +#include "exceptions.h" +#include "stackcheck.h" +#include "modcontext.h" +#include "expression.h" + +#include + +std::deque UserModule::module_stack; + +AbstractNode *UserModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const +{ + if (StackCheck::inst()->check()) { + throw RecursionException::create("module", inst->name()); + return NULL; + } + + // At this point we know that nobody will modify the dependencies of the local scope + // passed to this instance, so we can populate the context + inst->scope.apply(*evalctx); + + ModuleContext c(ctx, evalctx); + // set $children first since we might have variables depending on it + c.set_variable("$children", ValuePtr(double(inst->scope.children.size()))); + module_stack.push_back(inst->name()); + c.set_variable("$parent_modules", ValuePtr(double(module_stack.size()))); + c.initializeModule(*this); + // FIXME: Set document path to the path of the module +#if 0 && DEBUG + c.dump(this, inst); +#endif + + AbstractNode *node = new GroupNode(inst); + std::vector instantiatednodes = this->scope.instantiateChildren(&c); + node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); + module_stack.pop_back(); + + return node; +} + +std::string UserModule::dump(const std::string &indent, const std::string &name) const +{ + std::stringstream dump; + std::string tab; + if (!name.empty()) { + dump << indent << "module " << name << "("; + for (size_t i=0; i < this->definition_arguments.size(); i++) { + const Assignment &arg = this->definition_arguments[i]; + if (i > 0) dump << ", "; + dump << arg.name; + if (arg.expr) dump << " = " << *arg.expr; + } + dump << ") {\n"; + tab = "\t"; + } + dump << scope.dump(indent + tab); + if (!name.empty()) { + dump << indent << "}\n"; + } + return dump.str(); +} diff --git a/src/UserModule.h b/src/UserModule.h new file mode 100644 index 00000000..ab78801b --- /dev/null +++ b/src/UserModule.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "module.h" +#include "localscope.h" + +class UserModule : public AbstractModule, public ASTNode +{ +public: + UserModule() { } + UserModule(const class Feature& feature) : AbstractModule(feature) { } + virtual ~UserModule() {} + + virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; + virtual std::string dump(const std::string &indent, const std::string &name) const; + static const std::string& stack_element(int n) { return module_stack[n]; }; + static int stack_size() { return module_stack.size(); }; + + AssignmentList definition_arguments; + + LocalScope scope; + +private: + static std::deque module_stack; +}; diff --git a/src/context.cc b/src/context.cc index e7a6a10b..e6fd6245 100644 --- a/src/context.cc +++ b/src/context.cc @@ -28,7 +28,7 @@ #include "evalcontext.h" #include "expression.h" #include "function.h" -#include "module.h" +#include "UserModule.h" #include "ModuleInstantiation.h" #include "builtin.h" #include "printutils.h" diff --git a/src/evalcontext.cc b/src/evalcontext.cc index 75470206..3acc7a1a 100644 --- a/src/evalcontext.cc +++ b/src/evalcontext.cc @@ -1,5 +1,5 @@ #include "evalcontext.h" -#include "module.h" +#include "UserModule.h" #include "ModuleInstantiation.h" #include "expression.h" #include "function.h" diff --git a/src/exceptions.h b/src/exceptions.h index 851726eb..8cf58f41 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -1,6 +1,7 @@ #pragma once #include +#include class EvaluationException : public std::runtime_error { public: diff --git a/src/func.cc b/src/func.cc index cc924a23..97d0110b 100644 --- a/src/func.cc +++ b/src/func.cc @@ -36,6 +36,7 @@ #include "stackcheck.h" #include "exceptions.h" #include "memory.h" +#include "UserModule.h" #include #include diff --git a/src/lexer.l b/src/lexer.l index e9bfa6ec..35076f8e 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -32,7 +32,7 @@ #include "parsersettings.h" #include "Assignment.h" #include "parser_yacc.h" -#include "module.h" +#include "FileModule.h" #include #include #include diff --git a/src/modcontext.cc b/src/modcontext.cc index 4ae824a3..9e82675b 100644 --- a/src/modcontext.cc +++ b/src/modcontext.cc @@ -2,7 +2,7 @@ #include "math.h" #include "modcontext.h" -#include "module.h" +#include "UserModule.h" #include "ModuleInstantiation.h" #include "expression.h" #include "function.h" @@ -65,7 +65,7 @@ void ModuleContext::evaluateAssignments(const AssignmentList &assignments) } #endif -void ModuleContext::initializeModule(const class UserModule &module) +void ModuleContext::initializeModule(const UserModule &module) { this->setVariables(module.definition_arguments, evalctx); // FIXME: Don't access module members directly diff --git a/src/modcontext.h b/src/modcontext.h index 27d5c8c6..cb90e61c 100644 --- a/src/modcontext.h +++ b/src/modcontext.h @@ -1,7 +1,7 @@ #pragma once #include "context.h" -#include "module.h" +#include "FileModule.h" /*! This holds the context for a UserModule definition; keeps track of @@ -15,7 +15,7 @@ public: ModuleContext(const Context *parent = NULL, const EvalContext *evalctx = NULL); virtual ~ModuleContext(); - void initializeModule(const UserModule &m); + void initializeModule(const class UserModule &m); void registerBuiltin(); virtual ValuePtr evaluate_function(const std::string &name, const EvalContext *evalctx) const; @@ -42,9 +42,9 @@ private: class FileContext : public ModuleContext { public: - FileContext(const class FileModule &module, const Context *parent); + FileContext(const FileModule &module, const Context *parent); virtual ~FileContext() {} - void initializeModule(const class FileModule &module); + void initializeModule(const FileModule &module); virtual ValuePtr evaluate_function(const std::string &name, const EvalContext *evalctx) const; virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst, diff --git a/src/module.cc b/src/module.cc index c5e6f65a..5e7c0a4d 100644 --- a/src/module.cc +++ b/src/module.cc @@ -25,41 +25,14 @@ */ #include "module.h" -#include "ModuleInstantiation.h" -#include "ModuleCache.h" -#include "node.h" -#include "builtin.h" -#include "modcontext.h" -#include "evalcontext.h" -#include "expression.h" -#include "function.h" -#include "printutils.h" -#include "parsersettings.h" -#include "exceptions.h" -#include "stackcheck.h" - -#include -namespace fs = boost::filesystem; -#include "boosty.h" -#include "FontCache.h" +#include "context.h" +#include "value.h" #include -#include AbstractModule::~AbstractModule() { } -AbstractNode *GroupModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const -{ - (void)ctx; // avoid unusued parameter warning - - AbstractNode *node = new GroupNode(inst); - - node->children = inst->instantiateChildren(evalctx); - - return node; -} - double AbstractModule::lookup_double_variable_with_default(Context &c, std::string variable, double def) const { ValuePtr v = c.lookup_variable(variable, true); @@ -78,208 +51,3 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n dump << indent << "abstract module " << name << "();\n"; return dump.str(); } - -std::deque UserModule::module_stack; - -AbstractNode *UserModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const -{ - if (StackCheck::inst()->check()) { - throw RecursionException::create("module", inst->name()); - return NULL; - } - - // At this point we know that nobody will modify the dependencies of the local scope - // passed to this instance, so we can populate the context - inst->scope.apply(*evalctx); - - ModuleContext c(ctx, evalctx); - // set $children first since we might have variables depending on it - c.set_variable("$children", ValuePtr(double(inst->scope.children.size()))); - module_stack.push_back(inst->name()); - c.set_variable("$parent_modules", ValuePtr(double(module_stack.size()))); - c.initializeModule(*this); - // FIXME: Set document path to the path of the module -#if 0 && DEBUG - c.dump(this, inst); -#endif - - AbstractNode *node = new GroupNode(inst); - std::vector instantiatednodes = this->scope.instantiateChildren(&c); - node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); - module_stack.pop_back(); - - return node; -} - -std::string UserModule::dump(const std::string &indent, const std::string &name) const -{ - std::stringstream dump; - std::string tab; - if (!name.empty()) { - dump << indent << "module " << name << "("; - for (size_t i=0; i < this->definition_arguments.size(); i++) { - const Assignment &arg = this->definition_arguments[i]; - if (i > 0) dump << ", "; - dump << arg.name; - if (arg.expr) dump << " = " << *arg.expr; - } - dump << ") {\n"; - tab = "\t"; - } - dump << scope.dump(indent + tab); - if (!name.empty()) { - dump << indent << "}\n"; - } - return dump.str(); -} - -FileModule::~FileModule() -{ - delete context; -} - -std::string FileModule::dump(const std::string &indent, const std::string &name) const -{ - return scope.dump(indent); -} - -void FileModule::registerUse(const std::string path) { - std::string extraw = boosty::extension_str(fs::path(path)); - std::string ext = boost::algorithm::to_lower_copy(extraw); - - if ((ext == ".otf") || (ext == ".ttf")) { - if (fs::is_regular(path)) { - FontCache::instance()->register_font_file(path); - } else { - PRINTB("ERROR: Can't read font with path '%s'", path); - } - } else { - usedlibs.insert(path); - } -} - -void FileModule::registerInclude(const std::string &localpath, - const std::string &fullpath) -{ - struct stat st; - memset(&st, 0, sizeof(struct stat)); - bool valid = stat(fullpath.c_str(), &st) == 0; - IncludeFile inc = {fullpath, valid, st.st_mtime}; - this->includes[localpath] = inc; -} - -bool FileModule::includesChanged() const -{ - for(const auto &item : this->includes) { - if (include_modified(item.second)) return true; - } - return false; -} - -bool FileModule::include_modified(const IncludeFile &inc) const -{ - struct stat st; - memset(&st, 0, sizeof(struct stat)); - - fs::path fullpath = find_valid_path(this->path, inc.filename); - bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false; - - if (valid && !inc.valid) return true; // Detect appearance of file but not removal - if (valid && st.st_mtime > inc.mtime) return true; - - return false; -} - -/*! - Check if any dependencies have been modified and recompile them. - Returns true if anything was recompiled. -*/ -bool FileModule::handleDependencies() -{ - if (this->is_handling_dependencies) return false; - this->is_handling_dependencies = true; - - bool somethingchanged = false; - std::vector> updates; - - // If a lib in usedlibs was previously missing, we need to relocate it - // by searching the applicable paths. We can identify a previously missing module - // as it will have a relative path. - for(auto filename : this->usedlibs) { - - bool wasmissing = false; - bool found = true; - - // Get an absolute filename for the module - if (!boosty::is_absolute(filename)) { - wasmissing = true; - fs::path fullpath = find_valid_path(this->path, filename); - if (!fullpath.empty()) { - updates.push_back(std::make_pair(filename, boosty::stringy(fullpath))); - filename = boosty::stringy(fullpath); - } - else { - found = false; - } - } - - if (found) { - bool wascached = ModuleCache::instance()->isCached(filename); - FileModule *oldmodule = ModuleCache::instance()->lookup(filename); - FileModule *newmodule; - bool changed = ModuleCache::instance()->evaluate(filename, newmodule); - // Detect appearance but not removal of files, and keep old module - // on compile errors (FIXME: Is this correct behavior?) - if (changed) { - PRINTDB(" %s: %p -> %p", filename % oldmodule % newmodule); - } - somethingchanged |= changed; - // Only print warning if we're not part of an automatic reload - if (!newmodule && !wascached && !wasmissing) { - PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename); - } - } - } - - // Relative filenames which were located is reinserted as absolute filenames - typedef std::pair stringpair; - for(const auto &files : updates) { - this->usedlibs.erase(files.first); - this->usedlibs.insert(files.second); - } - this->is_handling_dependencies = false; - return somethingchanged; -} - -AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const -{ - assert(evalctx == NULL); - - delete this->context; - this->context = new FileContext(*this, ctx); - AbstractNode *node = new RootNode(inst); - - try { - context->initializeModule(*this); - - // FIXME: Set document path to the path of the module - std::vector instantiatednodes = this->scope.instantiateChildren(context); - node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); - } - catch (EvaluationException &e) { - PRINT(e.what()); - } - - return node; -} - -ValuePtr FileModule::lookup_variable(const std::string &name) const -{ - if (!this->context) return ValuePtr::undefined; - return this->context->lookup_variable(name, true); -} - -void register_builtin_group() -{ - Builtins::init("group", new GroupModule()); -} diff --git a/src/module.h b/src/module.h index 0f96563f..8ac55fa3 100644 --- a/src/module.h +++ b/src/module.h @@ -1,98 +1,21 @@ #pragma once #include -#include -#include -#include -#include -#include -#include -#include - #include "AST.h" -#include "value.h" -#include "localscope.h" #include "feature.h" -class AbstractModule : public ASTNode +class AbstractModule { private: - const Feature *feature; + const Feature *feature; public: - AbstractModule() : feature(NULL) {} - AbstractModule(const Feature& feature) : feature(&feature) {} + AbstractModule() : feature(NULL) {} + AbstractModule(const Feature& feature) : feature(&feature) {} virtual ~AbstractModule(); - virtual bool is_experimental() const { return feature != NULL; } - virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } - virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const = 0; + virtual bool is_experimental() const { return feature != NULL; } + virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } + virtual class AbstractNode *instantiate(const class Context *ctx, const class ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const = 0; virtual std::string dump(const std::string &indent, const std::string &name) const; - virtual double lookup_double_variable_with_default(Context &c, std::string variable, double def) const; - virtual std::string lookup_string_variable_with_default(Context &c, std::string variable, std::string def) const; -}; - -class GroupModule : public AbstractModule -{ -public: - GroupModule() { } - virtual ~GroupModule() { } - virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const; -}; - -class UserModule : public AbstractModule -{ -public: - UserModule() { } - UserModule(const Feature& feature) : AbstractModule(feature) { } - virtual ~UserModule() {} - - virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; - virtual std::string dump(const std::string &indent, const std::string &name) const; - static const std::string& stack_element(int n) { return module_stack[n]; }; - static int stack_size() { return module_stack.size(); }; - - AssignmentList definition_arguments; - - LocalScope scope; - -private: - static std::deque module_stack; -}; - -class FileModule : public AbstractModule -{ -public: - FileModule() : context(nullptr), is_handling_dependencies(false) {} - virtual ~FileModule(); - - virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; - virtual std::string dump(const std::string &indent, const std::string &name) const; - void setModulePath(const std::string &path) { this->path = path; } - const std::string &modulePath() const { return this->path; } - void registerUse(const std::string path); - void registerInclude(const std::string &localpath, const std::string &fullpath); - bool includesChanged() const; - bool handleDependencies(); - bool hasIncludes() const { return !this->includes.empty(); } - bool usesLibraries() const { return !this->usedlibs.empty(); } - bool isHandlingDependencies() const { return this->is_handling_dependencies; } - ValuePtr lookup_variable(const std::string &name) const; - - LocalScope scope; - typedef std::unordered_set ModuleContainer; - ModuleContainer usedlibs; -private: - // Reference to retain the context that was used in the last evaluation - mutable class FileContext *context; - struct IncludeFile { - std::string filename; - bool valid; - time_t mtime; - }; - - bool include_modified(const IncludeFile &inc) const; - - typedef std::unordered_map IncludeContainer; - IncludeContainer includes; - bool is_handling_dependencies; - std::string path; + virtual double lookup_double_variable_with_default(Context &c, std::string variable, double def) const; + virtual std::string lookup_string_variable_with_default(Context &c, std::string variable, std::string def) const; }; diff --git a/src/parser.y b/src/parser.y index 7a09083e..28e9448a 100644 --- a/src/parser.y +++ b/src/parser.y @@ -34,7 +34,8 @@ #include #endif -#include "module.h" +#include "FileModule.h" +#include "UserModule.h" #include "ModuleInstantiation.h" #include "Assignment.h" #include "expression.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 75dc1282..adfae6c9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -679,6 +679,9 @@ set(CORE_SOURCES ../src/stackcheck.cc ../src/localscope.cc ../src/module.cc + ../src/FileModule.cc + ../src/UserModule.cc + ../src/GroupModule.cc ../src/ModuleInstantiation.cc ../src/ModuleCache.cc ../src/node.cc diff --git a/tests/tests-common.cc b/tests/tests-common.cc index 3c66e1b8..021b91ff 100644 --- a/tests/tests-common.cc +++ b/tests/tests-common.cc @@ -1,6 +1,6 @@ #include "tests-common.h" #include "openscad.h" -#include "module.h" +#include "FileModule.h" #include "handle_dep.h" #include "boosty.h" From 95b5306495a4a86a43b7b5c7e5db98c1713d068f Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 16 May 2016 00:54:16 -0400 Subject: [PATCH 07/11] ast refactoring: Made the traverser part of NodeVisitor as it was dependent on the node tree --- src/CSGTreeEvaluator.cc | 4 +--- src/GeometryEvaluator.cc | 4 +--- src/{traverser.cc => NodeVisitor.cc} | 30 ++++++++++------------------ src/NodeVisitor.h | 6 ++++++ src/Package.h | 20 +++++++++++++++++++ src/Tree.cc | 4 +--- src/traverser.h | 23 --------------------- tests/CMakeLists.txt | 2 +- tests/csgtexttest.cc | 4 +--- 9 files changed, 41 insertions(+), 56 deletions(-) rename src/{traverser.cc => NodeVisitor.cc} (52%) create mode 100644 src/Package.h delete mode 100644 src/traverser.h diff --git a/src/CSGTreeEvaluator.cc b/src/CSGTreeEvaluator.cc index 080f4422..29623bca 100644 --- a/src/CSGTreeEvaluator.cc +++ b/src/CSGTreeEvaluator.cc @@ -1,5 +1,4 @@ #include "CSGTreeEvaluator.h" -#include "traverser.h" #include "state.h" #include "csgops.h" #include "module.h" @@ -31,8 +30,7 @@ shared_ptr CSGTreeEvaluator::buildCSGTree(const AbstractNode &node) { - Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX); - evaluate.execute(); + this->traverse(node); shared_ptr t(this->stored_term[node.index()]); if (t) { diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 2e45a475..84c0e97a 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -1,5 +1,4 @@ #include "GeometryEvaluator.h" -#include "traverser.h" #include "Tree.h" #include "GeometryCache.h" #include "CGALCache.h" @@ -55,8 +54,7 @@ shared_ptr GeometryEvaluator::evaluateGeometry(const AbstractNod this->root = N; } else { - Traverser trav(*this, node, Traverser::PRE_AND_POSTFIX); - trav.execute(); + this->traverse(node); } if (!allownef) { diff --git a/src/traverser.cc b/src/NodeVisitor.cc similarity index 52% rename from src/traverser.cc rename to src/NodeVisitor.cc index 9355ba95..36ed630b 100644 --- a/src/traverser.cc +++ b/src/NodeVisitor.cc @@ -1,25 +1,17 @@ -#include "traverser.h" -#include "node.h" +#include "NodeVisitor.h" #include "state.h" -#include -void Traverser::execute() -{ - State state(NULL); - traverse(this->root, state); -} +State NodeVisitor::nullstate(nullptr); -Response Traverser::traverse(const AbstractNode &node, const State &state) +Response NodeVisitor::traverse(const AbstractNode &node, const State &state) { State newstate = state; newstate.setNumChildren(node.getChildren().size()); Response response = ContinueTraversal; - if (traversaltype == PREFIX || traversaltype == PRE_AND_POSTFIX) { - newstate.setPrefix(true); - newstate.setParent(state.parent()); - response = node.accept(newstate, this->visitor); - } + newstate.setPrefix(true); + newstate.setParent(state.parent()); + response = node.accept(newstate, *this); // Pruned traversals mean don't traverse children if (response == ContinueTraversal) { @@ -32,12 +24,10 @@ Response Traverser::traverse(const AbstractNode &node, const State &state) // Postfix is executed for all non-aborted traversals if (response != AbortTraversal) { - if (traversaltype == POSTFIX || traversaltype == PRE_AND_POSTFIX) { - newstate.setParent(state.parent()); - newstate.setPrefix(false); - newstate.setPostfix(true); - response = node.accept(newstate, this->visitor); - } + newstate.setParent(state.parent()); + newstate.setPrefix(false); + newstate.setPostfix(true); + response = node.accept(newstate, *this); } if (response != AbortTraversal) response = ContinueTraversal; diff --git a/src/NodeVisitor.h b/src/NodeVisitor.h index b637ad8d..d1b89af2 100644 --- a/src/NodeVisitor.h +++ b/src/NodeVisitor.h @@ -2,6 +2,7 @@ #include "BaseVisitable.h" #include "node.h" +#include "state.h" class NodeVisitor : public BaseVisitor, @@ -29,6 +30,8 @@ public: NodeVisitor() {} virtual ~NodeVisitor() {} + Response traverse(const AbstractNode &node, const class State &state = NodeVisitor::nullstate); + virtual Response visit(class State &state, const class AbstractNode &node) = 0; virtual Response visit(class State &state, const class AbstractIntersectionNode &node) { return visit(state, (const class AbstractNode &)node); @@ -85,4 +88,7 @@ public: return visit(state, (const class AbstractPolyNode &)node); } // Add visit() methods for new visitable subtypes of AbstractNode here + +private: + static State nullstate; }; diff --git a/src/Package.h b/src/Package.h new file mode 100644 index 00000000..bfa3b245 --- /dev/null +++ b/src/Package.h @@ -0,0 +1,20 @@ +#pragma once + +#include "AST.h" +#include + +class Package : public ASTNode +{ +public: + Package() {} + virtual ~Package() {} + + void setPath(const std::string &path) { this->_path = path; } + const std::string &path() const { return this->_path; } + + LocalScope scope; + typedef std::unordered_set ModuleContainer; + ModuleContainer usedlibs; +private: + std::string _path; +}; diff --git a/src/Tree.cc b/src/Tree.cc index 555d83f3..2e6de039 100644 --- a/src/Tree.cc +++ b/src/Tree.cc @@ -1,6 +1,5 @@ #include "Tree.h" #include "nodedumper.h" -#include "traverser.h" #include "printutils.h" #include @@ -25,8 +24,7 @@ const std::string &Tree::getString(const AbstractNode &node) const this->nodecache.clear(); this->nodeidcache.clear(); NodeDumper dumper(this->nodecache, false); - Traverser trav(dumper, *this->root_node, Traverser::PRE_AND_POSTFIX); - trav.execute(); + dumper.traverse(*this->root_node); assert(this->nodecache.contains(*this->root_node) && "NodeDumper failed to create a cache"); } diff --git a/src/traverser.h b/src/traverser.h deleted file mode 100644 index 560a9a38..00000000 --- a/src/traverser.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "node.h" - -class Traverser -{ -public: - enum TraversalType {PREFIX, POSTFIX, PRE_AND_POSTFIX}; - - Traverser(BaseVisitor &visitor, const AbstractNode &root, TraversalType travtype) - : visitor(visitor), root(root), traversaltype(travtype) { - } - virtual ~Traverser() { } - - void execute(); - // FIXME: reverse parameters - Response traverse(const AbstractNode &node, const class State &state); -private: - - BaseVisitor &visitor; - const AbstractNode &root; - TraversalType traversaltype; -}; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index adfae6c9..981e6d63 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -685,6 +685,7 @@ set(CORE_SOURCES ../src/ModuleInstantiation.cc ../src/ModuleCache.cc ../src/node.cc + ../src/NodeVisitor.cc ../src/context.cc ../src/modcontext.cc ../src/evalcontext.cc @@ -755,7 +756,6 @@ set(CGAL_SOURCES set(COMMON_SOURCES ../src/nodedumper.cc - ../src/traverser.cc ../src/GeometryCache.cc ../src/clipper-utils.cc ../src/Tree.cc diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 5ce08399..8c9c6c16 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -39,7 +39,6 @@ #include "Tree.h" #include "PlatformUtils.h" #include "stackcheck.h" -#include "traverser.h" #ifndef _MSC_VER #include @@ -60,8 +59,7 @@ std::string currentdir; void csgTree(CSGTextCache &cache, const AbstractNode &root) { CSGTextRenderer renderer(cache); - Traverser render(renderer, root, Traverser::PRE_AND_POSTFIX); - render.execute(); + renderer.traverse(root); } int main(int argc, char **argv) From 0eadffea33d7a44c04c17f3d83e4385c84f47427 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Tue, 7 Jun 2016 01:32:27 -0400 Subject: [PATCH 08/11] ast refactoring: added recently changed files --- openscad.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openscad.pro b/openscad.pro index e16f1034..b0715fec 100644 --- a/openscad.pro +++ b/openscad.pro @@ -232,6 +232,7 @@ win* { HEADERS += src/AST.h \ src/ModuleInstantiation.h \ + src/Package.h \ src/Assignment.h \ src/expression.h \ src/function.h \ @@ -311,7 +312,6 @@ HEADERS += src/version_check.h \ src/editor.h \ src/NodeVisitor.h \ src/state.h \ - src/traverser.h \ src/nodecache.h \ src/nodedumper.h \ src/ModuleCache.h \ @@ -394,7 +394,7 @@ SOURCES += src/version_check.cc \ src/LibraryInfo.cc \ \ src/nodedumper.cc \ - src/traverser.cc \ + src/NodeVisitor.cc \ src/GeometryEvaluator.cc \ src/ModuleCache.cc \ src/GeometryCache.cc \ From b509afd4ed9cd005e9a818b29ce9e8cebc8c46ed Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 13 Jun 2016 20:20:04 -0400 Subject: [PATCH 09/11] Added a Location object to ASTNode, to track source code locations --- openscad.pro | 3 +- src/AST.cc | 3 ++ src/AST.h | 27 +++++++++- src/Assignment.h | 7 +-- src/ModuleInstantiation.h | 6 +-- src/UserModule.h | 4 +- src/expr.cc | 69 ++++++++++++-------------- src/expression.h | 41 ++++++++-------- src/function.cc | 17 ++++--- src/function.h | 12 ++--- src/parser.y | 100 +++++++++++++++++++------------------- tests/CMakeLists.txt | 1 + 12 files changed, 157 insertions(+), 133 deletions(-) create mode 100644 src/AST.cc diff --git a/openscad.pro b/openscad.pro index b0715fec..de30f97c 100644 --- a/openscad.pro +++ b/openscad.pro @@ -239,7 +239,8 @@ HEADERS += src/AST.h \ src/module.h \ src/UserModule.h -SOURCES += src/ModuleInstantiation.cc \ +SOURCES += src/AST.cc \ + src/ModuleInstantiation.cc \ src/expr.cc \ src/function.cc \ src/module.cc \ diff --git a/src/AST.cc b/src/AST.cc new file mode 100644 index 00000000..10196d88 --- /dev/null +++ b/src/AST.cc @@ -0,0 +1,3 @@ +#include "AST.h" + +Location Location::NONE(0, 0, 0, 0); diff --git a/src/AST.h b/src/AST.h index 997ee1cb..c3de9553 100644 --- a/src/AST.h +++ b/src/AST.h @@ -1,8 +1,33 @@ #pragma once +class Location { +public: + Location(int firstLine, int firstCol, int lastLine, int lastCol) + : first_line(firstLine), first_col(firstCol), last_line(lastLine), last_col(lastCol) { + } + + int firstLine() const { return first_line; } + int firstColumn() const { return first_col; } + int lastLine() const { return last_line; } + int lastColumn() const { return last_col; } + + + static Location NONE; +private: + int first_line; + int first_col; + int last_line; + int last_col; +}; + class ASTNode { public: - ASTNode(/* srcref */) {} + ASTNode(const Location &loc) : loc(loc) {} virtual ~ASTNode() {} + + Location location() const { return loc; } + +protected: + Location loc; }; diff --git a/src/Assignment.h b/src/Assignment.h index 27253321..7bdecc36 100644 --- a/src/Assignment.h +++ b/src/Assignment.h @@ -10,10 +10,11 @@ class Assignment : public ASTNode { public: + Assignment(std::string name, const Location &loc) : Assignment(name, shared_ptr(), loc) { } Assignment(std::string name, - shared_ptr expr = shared_ptr()) - : name(name), expr(expr) { - } + shared_ptr expr = shared_ptr(), + const Location &loc = Location::NONE) + : ASTNode(loc), name(name), expr(expr) { } std::string name; shared_ptr expr; diff --git a/src/ModuleInstantiation.h b/src/ModuleInstantiation.h index f31cbe6a..f205a3b7 100644 --- a/src/ModuleInstantiation.h +++ b/src/ModuleInstantiation.h @@ -9,8 +9,8 @@ typedef std::vector ModuleInstantiationList; class ModuleInstantiation : public ASTNode { public: - ModuleInstantiation(const std::string &name = "") - : tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } + ModuleInstantiation(const std::string &name = "", const Location &loc = Location::NONE) + : ASTNode(loc), tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } virtual ~ModuleInstantiation(); virtual std::string dump(const std::string &indent) const; @@ -39,7 +39,7 @@ protected: class IfElseModuleInstantiation : public ModuleInstantiation { public: - IfElseModuleInstantiation() : ModuleInstantiation("if") { } + IfElseModuleInstantiation(const Location &loc) : ModuleInstantiation("if", loc) { } virtual ~IfElseModuleInstantiation(); std::vector instantiateElseChildren(const Context *evalctx) const; virtual std::string dump(const std::string &indent) const; diff --git a/src/UserModule.h b/src/UserModule.h index ab78801b..a6d3e9b1 100644 --- a/src/UserModule.h +++ b/src/UserModule.h @@ -9,8 +9,8 @@ class UserModule : public AbstractModule, public ASTNode { public: - UserModule() { } - UserModule(const class Feature& feature) : AbstractModule(feature) { } + UserModule(const Location &loc) : ASTNode(loc) { } + UserModule(const class Feature& feature, const Location &loc) : AbstractModule(feature), ASTNode(loc) { } virtual ~UserModule() {} virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const; diff --git a/src/expr.cc b/src/expr.cc index 43dc5234..fe1de74f 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -30,7 +30,6 @@ #include #include #include -#include "stl-utils.h" #include "printutils.h" #include "stackcheck.h" #include "exceptions.h" @@ -58,14 +57,6 @@ namespace { } } -Expression::Expression() -{ -} - -Expression::~Expression() -{ -} - namespace /* anonymous*/ { std::ostream &operator << (std::ostream &o, AssignmentList const& l) { @@ -85,7 +76,7 @@ bool Expression::isListComprehension() const return false; } -UnaryOp::UnaryOp(UnaryOp::Op op, Expression *expr) : op(op), expr(expr) +UnaryOp::UnaryOp(UnaryOp::Op op, Expression *expr, const Location &loc) : Expression(loc), op(op), expr(expr) { } @@ -122,8 +113,8 @@ void UnaryOp::print(std::ostream &stream) const stream << opString() << *this->expr; } -BinaryOp::BinaryOp(Expression *left, BinaryOp::Op op, Expression *right) : - op(op), left(left), right(right) +BinaryOp::BinaryOp(Expression *left, BinaryOp::Op op, Expression *right, const Location &loc) : + Expression(loc), op(op), left(left), right(right) { } @@ -228,8 +219,8 @@ void BinaryOp::print(std::ostream &stream) const stream << "(" << *this->left << " " << opString() << " " << *this->right << ")"; } -TernaryOp::TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr) - : cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) +TernaryOp::TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr, const Location &loc) + : Expression(loc), cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) { } @@ -243,8 +234,8 @@ void TernaryOp::print(std::ostream &stream) const stream << "(" << *this->cond << " ? " << *this->ifexpr << " : " << *this->elseexpr << ")"; } -ArrayLookup::ArrayLookup(Expression *array, Expression *index) - : array(array), index(index) +ArrayLookup::ArrayLookup(Expression *array, Expression *index, const Location &loc) + : Expression(loc), array(array), index(index) { } @@ -257,7 +248,7 @@ void ArrayLookup::print(std::ostream &stream) const stream << *array << "[" << *index << "]"; } -Literal::Literal(const ValuePtr &val) : value(val) +Literal::Literal(const ValuePtr &val, const Location &loc) : Expression(loc), value(val) { } @@ -271,13 +262,13 @@ void Literal::print(std::ostream &stream) const stream << *this->value; } -Range::Range(Expression *begin, Expression *end) - : begin(begin), end(end) +Range::Range(Expression *begin, Expression *end, const Location &loc) + : Expression(loc), begin(begin), end(end) { } -Range::Range(Expression *begin, Expression *step, Expression *end) - : begin(begin), step(step), end(end) +Range::Range(Expression *begin, Expression *step, Expression *end, const Location &loc) + : Expression(loc), begin(begin), step(step), end(end) { } @@ -310,7 +301,7 @@ void Range::print(std::ostream &stream) const stream << "]"; } -Vector::Vector() +Vector::Vector(const Location &loc) : Expression(loc) { } @@ -346,7 +337,7 @@ void Vector::print(std::ostream &stream) const stream << "]"; } -Lookup::Lookup(const std::string &name) : name(name) +Lookup::Lookup(const std::string &name, const Location &loc) : Expression(loc), name(name) { } @@ -360,8 +351,8 @@ void Lookup::print(std::ostream &stream) const stream << this->name; } -MemberLookup::MemberLookup(Expression *expr, const std::string &member) - : expr(expr), member(member) +MemberLookup::MemberLookup(Expression *expr, const std::string &member, const Location &loc) + : Expression(loc), expr(expr), member(member) { } @@ -387,8 +378,8 @@ void MemberLookup::print(std::ostream &stream) const } FunctionCall::FunctionCall(const std::string &name, - const AssignmentList &args) - : name(name), arguments(args) + const AssignmentList &args, const Location &loc) + : Expression(loc), name(name), arguments(args) { } @@ -409,8 +400,8 @@ void FunctionCall::print(std::ostream &stream) const stream << this->name << "(" << this->arguments << ")"; } -Let::Let(const AssignmentList &args, Expression *expr) - : arguments(args), expr(expr) +Let::Let(const AssignmentList &args, Expression *expr, const Location &loc) + : Expression(loc), arguments(args), expr(expr) { } @@ -427,7 +418,7 @@ void Let::print(std::ostream &stream) const stream << "let(" << this->arguments << ") " << *expr; } -ListComprehension::ListComprehension() +ListComprehension::ListComprehension(const Location &loc) : Expression(loc) { } @@ -436,8 +427,8 @@ bool ListComprehension::isListComprehension() const return true; } -LcIf::LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr) - : cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) +LcIf::LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr, const Location &loc) + : ListComprehension(loc), cond(cond), ifexpr(ifexpr), elseexpr(elseexpr) { } @@ -469,7 +460,7 @@ void LcIf::print(std::ostream &stream) const } } -LcEach::LcEach(Expression *expr) : expr(expr) +LcEach::LcEach(Expression *expr, const Location &loc) : ListComprehension(loc), expr(expr) { } @@ -512,8 +503,8 @@ void LcEach::print(std::ostream &stream) const stream << "each (" << *this->expr << ")"; } -LcFor::LcFor(const AssignmentList &args, Expression *expr) - : arguments(args), expr(expr) +LcFor::LcFor(const AssignmentList &args, Expression *expr, const Location &loc) + : ListComprehension(loc), arguments(args), expr(expr) { } @@ -564,8 +555,8 @@ void LcFor::print(std::ostream &stream) const stream << "for(" << this->arguments << ") (" << *this->expr << ")"; } -LcForC::LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr) - : arguments(args), incr_arguments(incrargs), cond(cond), expr(expr) +LcForC::LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr, const Location &loc) + : ListComprehension(loc), arguments(args), incr_arguments(incrargs), cond(cond), expr(expr) { } @@ -605,8 +596,8 @@ void LcForC::print(std::ostream &stream) const << ") " << *this->expr; } -LcLet::LcLet(const AssignmentList &args, Expression *expr) - : arguments(args), expr(expr) +LcLet::LcLet(const AssignmentList &args, Expression *expr, const Location &loc) + : ListComprehension(loc), arguments(args), expr(expr) { } diff --git a/src/expression.h b/src/expression.h index b6e6826d..d517a4e4 100644 --- a/src/expression.h +++ b/src/expression.h @@ -11,8 +11,8 @@ class Expression : public ASTNode { public: - Expression(); - virtual ~Expression(); + Expression(const Location &loc) : ASTNode(loc) {} + virtual ~Expression() {} virtual bool isListComprehension() const; virtual ValuePtr evaluate(const class Context *context) const = 0; @@ -29,7 +29,7 @@ public: Negate }; - UnaryOp(Op op, Expression *expr); + UnaryOp(Op op, Expression *expr, const Location &loc); virtual ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; @@ -59,7 +59,7 @@ public: NotEqual }; - BinaryOp(Expression *left, Op op, Expression *right); + BinaryOp(Expression *left, Op op, Expression *right, const Location &loc); virtual ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; @@ -74,7 +74,7 @@ private: class TernaryOp : public Expression { public: - TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr); + TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; @@ -86,7 +86,7 @@ public: class ArrayLookup : public Expression { public: - ArrayLookup(Expression *array, Expression *index); + ArrayLookup(Expression *array, Expression *index, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -97,7 +97,7 @@ private: class Literal : public Expression { public: - Literal(const ValuePtr &val); + Literal(const ValuePtr &val, const Location &loc = Location::NONE); ValuePtr evaluate(const class Context *) const; virtual void print(std::ostream &stream) const; private: @@ -107,8 +107,8 @@ private: class Range : public Expression { public: - Range(Expression *begin, Expression *end); - Range(Expression *begin, Expression *step, Expression *end); + Range(Expression *begin, Expression *end, const Location &loc); + Range(Expression *begin, Expression *step, Expression *end, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -120,7 +120,7 @@ private: class Vector : public Expression { public: - Vector(); + Vector(const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; void push_back(Expression *expr); @@ -131,7 +131,7 @@ private: class Lookup : public Expression { public: - Lookup(const std::string &name); + Lookup(const std::string &name, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -141,7 +141,7 @@ private: class MemberLookup : public Expression { public: - MemberLookup(Expression *expr, const std::string &member); + MemberLookup(Expression *expr, const std::string &member, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -152,7 +152,7 @@ private: class FunctionCall : public Expression { public: - FunctionCall(const std::string &funcname, const AssignmentList &arglist); + FunctionCall(const std::string &funcname, const AssignmentList &arglist, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; public: @@ -163,7 +163,7 @@ public: class Let : public Expression { public: - Let(const AssignmentList &args, Expression *expr); + Let(const AssignmentList &args, Expression *expr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -175,13 +175,14 @@ class ListComprehension : public Expression { virtual bool isListComprehension() const; public: - ListComprehension(); + ListComprehension(const Location &loc); + ~ListComprehension() = default; }; class LcIf : public ListComprehension { public: - LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr); + LcIf(Expression *cond, Expression *ifexpr, Expression *elseexpr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -193,7 +194,7 @@ private: class LcFor : public ListComprehension { public: - LcFor(const AssignmentList &args, Expression *expr); + LcFor(const AssignmentList &args, Expression *expr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -204,7 +205,7 @@ private: class LcForC : public ListComprehension { public: - LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr); + LcForC(const AssignmentList &args, const AssignmentList &incrargs, Expression *cond, Expression *expr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -217,7 +218,7 @@ private: class LcEach : public ListComprehension { public: - LcEach(Expression *expr); + LcEach(Expression *expr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: @@ -227,7 +228,7 @@ private: class LcLet : public ListComprehension { public: - LcLet(const AssignmentList &args, Expression *expr); + LcLet(const AssignmentList &args, Expression *expr, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; private: diff --git a/src/function.cc b/src/function.cc index 80726080..6105bdd3 100644 --- a/src/function.cc +++ b/src/function.cc @@ -32,8 +32,8 @@ AbstractFunction::~AbstractFunction() { } -UserFunction::UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr) - : name(name), definition_arguments(definition_arguments), expr(expr) +UserFunction::UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr, const Location &loc) + : ASTNode(loc), name(name), definition_arguments(definition_arguments), expr(expr) { } @@ -76,8 +76,9 @@ private: public: FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, shared_ptr expr, shared_ptr call, - shared_ptr endexpr, bool invert) - : UserFunction(name, definition_arguments, expr), + shared_ptr endexpr, bool invert, + const Location &loc) + : UserFunction(name, definition_arguments, expr, loc), invert(invert), op(expr), call(call), endexpr(endexpr) { } @@ -105,22 +106,22 @@ public: } }; -UserFunction *UserFunction::create(const char *name, AssignmentList &definition_arguments, shared_ptr expr) +UserFunction *UserFunction::create(const char *name, AssignmentList &definition_arguments, shared_ptr expr, const Location &loc) { if (shared_ptr ternary = dynamic_pointer_cast(expr)) { shared_ptr ifcall = dynamic_pointer_cast(ternary->ifexpr); shared_ptr elsecall = dynamic_pointer_cast(ternary->elseexpr); if (ifcall && !elsecall) { if (name == ifcall->name) { - return new FunctionTailRecursion(name, definition_arguments, ternary, ifcall, ternary->elseexpr, false); + return new FunctionTailRecursion(name, definition_arguments, ternary, ifcall, ternary->elseexpr, false, loc); } } else if (elsecall && !ifcall) { if (name == elsecall->name) { - return new FunctionTailRecursion(name, definition_arguments, ternary, elsecall, ternary->ifexpr, true); + return new FunctionTailRecursion(name, definition_arguments, ternary, elsecall, ternary->ifexpr, true, loc); } } } - return new UserFunction(name, definition_arguments, expr); + return new UserFunction(name, definition_arguments, expr, loc); } BuiltinFunction::~BuiltinFunction() diff --git a/src/function.h b/src/function.h index 42360646..a16b559b 100644 --- a/src/function.h +++ b/src/function.h @@ -8,13 +8,13 @@ #include #include -class AbstractFunction : public ASTNode +class AbstractFunction { private: const Feature *feature; public: - AbstractFunction() : feature(NULL) {} - AbstractFunction(const Feature& feature) : feature(&feature) {} + AbstractFunction(const Feature& feature) : AbstractFunction(&feature) {} + AbstractFunction(const Feature *feature = NULL) : feature(feature) {} virtual ~AbstractFunction(); virtual bool is_experimental() const { return feature != NULL; } virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } @@ -36,7 +36,7 @@ public: virtual std::string dump(const std::string &indent, const std::string &name) const; }; -class UserFunction : public AbstractFunction +class UserFunction : public AbstractFunction, public ASTNode { public: std::string name; @@ -44,11 +44,11 @@ public: shared_ptr expr; - UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr); + UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr expr, const Location &loc); virtual ~UserFunction(); virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; - static UserFunction *create(const char *name, AssignmentList &definition_arguments, shared_ptr expr); + static UserFunction *create(const char *name, AssignmentList &definition_arguments, shared_ptr expr, const Location &loc); }; diff --git a/src/parser.y b/src/parser.y index 28e9448a..981a9ab2 100644 --- a/src/parser.y +++ b/src/parser.y @@ -51,7 +51,8 @@ namespace fs = boost::filesystem; #include "boosty.h" #define YYMAXDEPTH 20000 - +#define LOC(loc) Location(loc.first_line, loc.first_column, loc.last_line, loc.last_column) + int parser_error_pos = -1; int parserlex(void); @@ -163,8 +164,7 @@ statement: | assignment | TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { - UserModule *newmodule = new UserModule(); - printf("Loc: %d\n", @$.first_line); + UserModule *newmodule = new UserModule(LOC(@$)); newmodule->definition_arguments = *$4; scope_stack.top()->modules[$2] = newmodule; scope_stack.push(&newmodule->scope); @@ -177,7 +177,7 @@ statement: } | TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { - UserFunction *func = UserFunction::create($2, *$4, shared_ptr($8)); + UserFunction *func = UserFunction::create($2, *$4, shared_ptr($8), LOC(@$)); scope_stack.top()->functions[$2] = func; free($2); delete $4; @@ -264,7 +264,7 @@ ifelse_statement: if_statement: TOK_IF '(' expr ')' { - $$ = new IfElseModuleInstantiation(); + $$ = new IfElseModuleInstantiation(LOC(@$)); $$->arguments.push_back(Assignment("", shared_ptr($3))); $$->setPath(boosty::stringy(parser_sourcefile.parent_path())); scope_stack.push(&$$->scope); @@ -302,7 +302,7 @@ module_id: single_module_instantiation: module_id '(' arguments_call ')' { - $$ = new ModuleInstantiation($1); + $$ = new ModuleInstantiation($1, LOC(@$)); $$->arguments = *$3; $$->setPath(boosty::stringy(parser_sourcefile.parent_path())); free($1); @@ -313,51 +313,51 @@ single_module_instantiation: expr: TOK_TRUE { - $$ = new Literal(ValuePtr(true)); + $$ = new Literal(ValuePtr(true), LOC(@$)); } | TOK_FALSE { - $$ = new Literal(ValuePtr(false)); + $$ = new Literal(ValuePtr(false), LOC(@$)); } | TOK_UNDEF { - $$ = new Literal(ValuePtr::undefined); + $$ = new Literal(ValuePtr::undefined, LOC(@$)); } | TOK_ID { - $$ = new Lookup($1); + $$ = new Lookup($1, LOC(@$)); free($1); } | expr '.' TOK_ID { - $$ = new MemberLookup($1, $3); + $$ = new MemberLookup($1, $3, LOC(@$)); free($3); } | TOK_STRING { - $$ = new Literal(ValuePtr(std::string($1))); + $$ = new Literal(ValuePtr(std::string($1)), LOC(@$)); free($1); } | TOK_NUMBER { - $$ = new Literal(ValuePtr($1)); + $$ = new Literal(ValuePtr($1), LOC(@$)); } | TOK_LET '(' arguments_call ')' expr %prec LET { - $$ = new Let(*$3, $5); + $$ = new Let(*$3, $5, LOC(@$)); delete $3; } | '[' expr ':' expr ']' { - $$ = new Range($2, $4); + $$ = new Range($2, $4, LOC(@$)); } | '[' expr ':' expr ':' expr ']' { - $$ = new Range($2, $4, $6); + $$ = new Range($2, $4, $6, LOC(@$)); } | '[' optional_commas ']' { - $$ = new Literal(ValuePtr(Value::VectorType())); + $$ = new Literal(ValuePtr(Value::VectorType()), LOC(@$)); } | '[' vector_expr optional_commas ']' { @@ -365,55 +365,55 @@ expr: } | expr '*' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Multiply, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Multiply, $3, LOC(@$)); } | expr '/' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Divide, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Divide, $3, LOC(@$)); } | expr '%' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Modulo, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Modulo, $3, LOC(@$)); } | expr '+' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Plus, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Plus, $3, LOC(@$)); } | expr '-' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Minus, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Minus, $3, LOC(@$)); } | expr '<' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Less, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Less, $3, LOC(@$)); } | expr LE expr { - $$ = new BinaryOp($1, BinaryOp::Op::LessEqual, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LessEqual, $3, LOC(@$)); } | expr EQ expr { - $$ = new BinaryOp($1, BinaryOp::Op::Equal, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Equal, $3, LOC(@$)); } | expr NE expr { - $$ = new BinaryOp($1, BinaryOp::Op::NotEqual, $3); + $$ = new BinaryOp($1, BinaryOp::Op::NotEqual, $3, LOC(@$)); } | expr GE expr { - $$ = new BinaryOp($1, BinaryOp::Op::GreaterEqual, $3); + $$ = new BinaryOp($1, BinaryOp::Op::GreaterEqual, $3, LOC(@$)); } | expr '>' expr { - $$ = new BinaryOp($1, BinaryOp::Op::Greater, $3); + $$ = new BinaryOp($1, BinaryOp::Op::Greater, $3, LOC(@$)); } | expr AND expr { - $$ = new BinaryOp($1, BinaryOp::Op::LogicalAnd, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LogicalAnd, $3, LOC(@$)); } | expr OR expr { - $$ = new BinaryOp($1, BinaryOp::Op::LogicalOr, $3); + $$ = new BinaryOp($1, BinaryOp::Op::LogicalOr, $3, LOC(@$)); } | '+' expr { @@ -421,11 +421,11 @@ expr: } | '-' expr { - $$ = new UnaryOp(UnaryOp::Op::Negate, $2); + $$ = new UnaryOp(UnaryOp::Op::Negate, $2, LOC(@$)); } | '!' expr { - $$ = new UnaryOp(UnaryOp::Op::Not, $2); + $$ = new UnaryOp(UnaryOp::Op::Not, $2, LOC(@$)); } | '(' expr ')' { @@ -433,15 +433,15 @@ expr: } | expr '?' expr ':' expr { - $$ = new TernaryOp($1, $3, $5); + $$ = new TernaryOp($1, $3, $5, LOC(@$)); } | expr '[' expr ']' { - $$ = new ArrayLookup($1, $3); + $$ = new ArrayLookup($1, $3, LOC(@$)); } | TOK_ID '(' arguments_call ')' { - $$ = new FunctionCall($1, *$3); + $$ = new FunctionCall($1, *$3, LOC(@$)); free($1); delete $3; } @@ -452,12 +452,12 @@ list_comprehension_elements: be parsed as an expression) */ TOK_LET '(' arguments_call ')' list_comprehension_elements_p { - $$ = new LcLet(*$3, $5); + $$ = new LcLet(*$3, $5, LOC(@$)); delete $3; } | TOK_EACH list_comprehension_elements_or_expr { - $$ = new LcEach($2); + $$ = new LcEach($2, LOC(@$)); } | TOK_FOR '(' arguments_call ')' list_comprehension_elements_or_expr { @@ -467,24 +467,24 @@ list_comprehension_elements: for (int i = $3->size()-1; i >= 0; i--) { AssignmentList arglist; arglist.push_back((*$3)[i]); - Expression *e = new LcFor(arglist, $$); + Expression *e = new LcFor(arglist, $$, LOC(@$)); $$ = e; } delete $3; } | TOK_FOR '(' arguments_call ';' expr ';' arguments_call ')' list_comprehension_elements_or_expr { - $$ = new LcForC(*$3, *$7, $5, $9); + $$ = new LcForC(*$3, *$7, $5, $9, LOC(@$)); delete $3; delete $7; } | TOK_IF '(' expr ')' list_comprehension_elements_or_expr { - $$ = new LcIf($3, $5, 0); + $$ = new LcIf($3, $5, 0, LOC(@$)); } | TOK_IF '(' expr ')' list_comprehension_elements_or_expr TOK_ELSE list_comprehension_elements_or_expr { - $$ = new LcIf($3, $5, $7); + $$ = new LcIf($3, $5, $7, LOC(@$)); } ; @@ -510,12 +510,12 @@ optional_commas: vector_expr: expr { - $$ = new Vector(); + $$ = new Vector(LOC(@$)); $$->push_back($1); } | list_comprehension_elements { - $$ = new Vector(); + $$ = new Vector(LOC(@$)); $$->push_back($1); } | vector_expr ',' optional_commas list_comprehension_elements_or_expr @@ -547,12 +547,12 @@ arguments_decl: argument_decl: TOK_ID { - $$ = new Assignment($1); + $$ = new Assignment($1, LOC(@$)); free($1); } | TOK_ID '=' expr { - $$ = new Assignment($1, shared_ptr($3)); + $$ = new Assignment($1, shared_ptr($3), LOC(@$)); free($1); } ; @@ -579,11 +579,11 @@ arguments_call: argument_call: expr { - $$ = new Assignment("", shared_ptr($1)); + $$ = new Assignment("", shared_ptr($1), LOC(@$)); } | TOK_ID '=' expr { - $$ = new Assignment($1, shared_ptr($3)); + $$ = new Assignment($1, shared_ptr($3), LOC(@$)); free($1); } ; @@ -597,9 +597,9 @@ int parserlex(void) void yyerror (char const *s) { - // FIXME: We leak memory on parser errors... - PRINTB("ERROR: Parser error in file %s, line %d: %s\n", - sourcefile() % lexerget_lineno() % s); + // FIXME: We leak memory on parser errors... + PRINTB("ERROR: Parser error in file %s, line %d: %s\n", + sourcefile() % lexerget_lineno() % s); } FileModule *parse(const char *text, const fs::path &filename, int debug) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 981e6d63..c7dd8835 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -682,6 +682,7 @@ set(CORE_SOURCES ../src/FileModule.cc ../src/UserModule.cc ../src/GroupModule.cc + ../src/AST.cc ../src/ModuleInstantiation.cc ../src/ModuleCache.cc ../src/node.cc From f4ddead656d7fa5fb02178054e957e2deaaf8870 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 13 Jun 2016 21:38:21 -0400 Subject: [PATCH 10/11] C++11: gcc-4.6.1 doesn't support delegating constructors --- src/Assignment.h | 3 ++- src/function.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Assignment.h b/src/Assignment.h index 7bdecc36..a9089060 100644 --- a/src/Assignment.h +++ b/src/Assignment.h @@ -10,7 +10,8 @@ class Assignment : public ASTNode { public: - Assignment(std::string name, const Location &loc) : Assignment(name, shared_ptr(), loc) { } + Assignment(std::string name, const Location &loc) + : ASTNode(loc), name(name) { } Assignment(std::string name, shared_ptr expr = shared_ptr(), const Location &loc = Location::NONE) diff --git a/src/function.h b/src/function.h index a16b559b..eaf72db7 100644 --- a/src/function.h +++ b/src/function.h @@ -13,8 +13,8 @@ class AbstractFunction private: const Feature *feature; public: - AbstractFunction(const Feature& feature) : AbstractFunction(&feature) {} - AbstractFunction(const Feature *feature = NULL) : feature(feature) {} + AbstractFunction(const Feature& feature) : feature(&feature) {} + AbstractFunction() : feature(NULL) {} virtual ~AbstractFunction(); virtual bool is_experimental() const { return feature != NULL; } virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } From 68316c443e176124bbbf792fef0062e53d22e482 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Tue, 14 Jun 2016 19:20:17 -0400 Subject: [PATCH 11/11] Moved arguments that should be available at construction-time into the constructor --- src/ModuleInstantiation.h | 8 ++++---- src/parser.y | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ModuleInstantiation.h b/src/ModuleInstantiation.h index f205a3b7..0852e754 100644 --- a/src/ModuleInstantiation.h +++ b/src/ModuleInstantiation.h @@ -9,15 +9,15 @@ typedef std::vector ModuleInstantiationList; class ModuleInstantiation : public ASTNode { public: - ModuleInstantiation(const std::string &name = "", const Location &loc = Location::NONE) - : ASTNode(loc), tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } + ModuleInstantiation(const std::string &name, const AssignmentList &args = AssignmentList(), const std::string &source_path = std::string(), const Location &loc = Location::NONE) + : ASTNode(loc), arguments(args), tag_root(false), tag_highlight(false), tag_background(false), modname(name), modpath(source_path) { } virtual ~ModuleInstantiation(); virtual std::string dump(const std::string &indent) const; class AbstractNode *evaluate(const class Context *ctx) const; std::vector instantiateChildren(const Context *evalctx) const; - void setPath(const std::string &path) { this->modpath = path; } + // This is only needed for import() and the deprecated *_extrude() modules const std::string &path() const { return this->modpath; } std::string getAbsolutePath(const std::string &filename) const; @@ -39,7 +39,7 @@ protected: class IfElseModuleInstantiation : public ModuleInstantiation { public: - IfElseModuleInstantiation(const Location &loc) : ModuleInstantiation("if", loc) { } + IfElseModuleInstantiation(shared_ptr expr, const std::string &source_path, const Location &loc) : ModuleInstantiation("if", AssignmentList{Assignment("", expr)}, source_path, loc) { } virtual ~IfElseModuleInstantiation(); std::vector instantiateElseChildren(const Context *evalctx) const; virtual std::string dump(const std::string &indent) const; diff --git a/src/parser.y b/src/parser.y index 981a9ab2..ad5b86a7 100644 --- a/src/parser.y +++ b/src/parser.y @@ -264,9 +264,7 @@ ifelse_statement: if_statement: TOK_IF '(' expr ')' { - $$ = new IfElseModuleInstantiation(LOC(@$)); - $$->arguments.push_back(Assignment("", shared_ptr($3))); - $$->setPath(boosty::stringy(parser_sourcefile.parent_path())); + $$ = new IfElseModuleInstantiation(shared_ptr($3), boosty::stringy(parser_sourcefile.parent_path()), LOC(@$)); scope_stack.push(&$$->scope); } child_statement @@ -302,9 +300,7 @@ module_id: single_module_instantiation: module_id '(' arguments_call ')' { - $$ = new ModuleInstantiation($1, LOC(@$)); - $$->arguments = *$3; - $$->setPath(boosty::stringy(parser_sourcefile.parent_path())); + $$ = new ModuleInstantiation($1, *$3, boosty::stringy(parser_sourcefile.parent_path()), LOC(@$)); free($1); delete $3; }