Merge pull request #1679 from amarjeetkapoor1/parameterASTmaster

Parameter now added in AST
This commit is contained in:
Torsten Paul 2016-06-24 19:26:38 +02:00 committed by GitHub
commit 7adb56affe
103 changed files with 1726 additions and 1650 deletions

View file

@ -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
}
FLEX = src/comment_lexer.l
BISON = src/comment_parser.y
@ -262,8 +254,32 @@ 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/Package.h \
src/Assignment.h \
src/expression.h \
src/function.h \
src/module.h \
src/UserModule.h
SOURCES += src/AST.cc \
src/ModuleInstantiation.cc \
src/expr.cc \
src/function.cc \
src/module.cc \
src/UserModule.cc
HEADERS += src/version_check.h \
src/ProgressWidget.h \
src/parsersettings.h \
src/renderer.h \
@ -284,6 +300,8 @@ HEADERS += src/typedefs.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 \
@ -295,15 +313,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 \
@ -330,9 +345,8 @@ HEADERS += src/typedefs.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 \
src/nodedumper.h \
src/ModuleCache.h \
@ -381,13 +395,11 @@ SOURCES += src/version_check.cc \
src/Camera.cc \
src/handle_dep.cc \
src/value.cc \
src/expr.cc \
src/stackcheck.cc \
src/assignment.cc \
src/annotation.cc \
src/func.cc \
src/localscope.cc \
src/module.cc \
src/feature.cc \
src/node.cc \
src/context.cc \
@ -428,7 +440,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 \
@ -449,6 +461,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 \

3
src/AST.cc Normal file
View file

@ -0,0 +1,3 @@
#include "AST.h"
Location Location::NONE(0, 0, 0, 0);

33
src/AST.h Normal file
View file

@ -0,0 +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(const Location &loc) : loc(loc) {}
virtual ~ASTNode() {}
Location location() const { return loc; }
protected:
Location loc;
};

70
src/Assignment.h Normal file
View file

@ -0,0 +1,70 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include <utility>
#include "value.h"
#include "AST.h"
#include "memory.h"
class Annotation;
typedef std::map<const std::string, Annotation *> AnnotationMap;
typedef std::vector<Annotation> AnnotationList;
class Assignment : public ASTNode
{
public:
Assignment(std::string name, const Location &loc)
: ASTNode(loc), name(name) { }
Assignment(std::string name,
shared_ptr<class Expression> expr = shared_ptr<class Expression>(),
const Location &loc = Location::NONE)
: ASTNode(loc), name(name), expr(expr) { }
std::string name;
shared_ptr<class Expression> expr;
typedef std::vector<Assignment> AssignmentList;
virtual void add_annotations(AnnotationList *annotations);
virtual void add_annotation(Annotation *annotations);
virtual bool has_annotations() const;
virtual const Annotation * annotation(const std::string &name) const;
protected:
AnnotationMap annotations;
};
typedef std::vector<Assignment> AssignmentList;
class Annotation
{
protected:
Annotation(const std::string name, const AssignmentList assignments, const AssignmentList args);
public:
virtual ~Annotation();
void dump();
const std::string & get_name();
virtual ValuePtr evaluate(class Context *ctx, const std::string& var) const;
Annotation& operator=(const Annotation&);
static const Annotation * create(const std::string name, const AssignmentList assignments);
//private:
std::string name;
/** Defines the names and values parsed from the script */
AssignmentList assignments;
private:
/** Defines the names of the positional parameters */
AssignmentList args;
};

42
src/BaseVisitable.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
#include <iostream>
// FIXME: Default constructor Response()
enum Response {ContinueTraversal, AbortTraversal, PruneTraversal};
class BaseVisitor
{
public:
virtual ~BaseVisitor() {}
};
template <class T>
class Visitor
{
public:
virtual Response visit(class State &state, const T&) = 0;
};
class BaseVisitable
{
public:
virtual ~BaseVisitable() {}
virtual Response accept(class State&, BaseVisitor&) const = 0;
protected:
template <class T>
static Response acceptImpl(class State &state, const T &node, BaseVisitor &visitor) {
if (Visitor<T> *p = dynamic_cast<Visitor<T>*>(&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, BaseVisitor &visitor) const { \
return acceptImpl(state, *this, visitor); \
}

View file

@ -1,8 +1,8 @@
#include "CSGTreeEvaluator.h"
#include "visitor.h"
#include "state.h"
#include "csgops.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "csgnode.h"
#include "transformnode.h"
#include "colornode.h"
@ -30,8 +30,7 @@
shared_ptr<CSGNode> CSGTreeEvaluator::buildCSGTree(const AbstractNode &node)
{
Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX);
evaluate.execute();
this->traverse(node);
shared_ptr<CSGNode> t(this->stored_term[node.index()]);
if (t) {

View file

@ -4,11 +4,11 @@
#include <list>
#include <vector>
#include <cstddef>
#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)

185
src/FileModule.cc Normal file
View file

@ -0,0 +1,185 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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 <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include "boosty.h"
#include "FontCache.h"
#include <sys/stat.h>
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<std::pair<std::string,std::string>> 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<std::string,std::string> 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<AbstractNode *> 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);
}

49
src/FileModule.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <time.h>
#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<std::string> 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<std::string, struct IncludeFile> IncludeContainer;
IncludeContainer includes;
bool is_handling_dependencies;
std::string path;
};

View file

@ -1,10 +1,10 @@
#include "GeometryEvaluator.h"
#include "traverser.h"
#include "Tree.h"
#include "GeometryCache.h"
#include "CGALCache.h"
#include "Polygon2d.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "state.h"
#include "offsetnode.h"
#include "transformnode.h"
@ -54,8 +54,7 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
this->root = N;
}
else {
Traverser trav(*this, node, Traverser::PRE_AND_POSTFIX);
trav.execute();
this->traverse(node);
}
if (!allownef) {

View file

@ -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 <vector>
#include <map>
class GeometryEvaluator : public Visitor
class GeometryEvaluator : public NodeVisitor
{
public:
GeometryEvaluator(const class Tree &tree);

47
src/GroupModule.cc Normal file
View file

@ -0,0 +1,47 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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());
}

11
src/GroupModule.h Normal file
View file

@ -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;
};

View file

@ -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"
@ -16,6 +17,9 @@
#include <QMutex>
#include <QTime>
#include <QIODevice>
#include"Assignment.h"
extern AssignmentList * parser(const char *text);
class MainWindow : public QMainWindow, public Ui::MainWindow
{
@ -94,6 +98,8 @@ private slots:
void consoleOutput(const QString &msg);
private:
void addparameter(const char *fulltext);
string getParameter(string fulltext, int loc);
void initActionIcon(QAction *action, const char *darkResource, const char *lightResource);
void handleFileDrop(const QString &filename);
void refreshDocument();

View file

@ -1,5 +1,5 @@
#include "ModuleCache.h"
#include "module.h"
#include "FileModule.h"
#include "printutils.h"
#include "openscad.h"

View file

@ -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<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
{
return this->scope.instantiateChildren(evalctx);
}
std::vector<AbstractNode*> IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const
{
return this->else_scope.instantiateChildren(evalctx);
}

49
src/ModuleInstantiation.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
#include "AST.h"
#include "localscope.h"
#include <vector>
typedef std::vector<class ModuleInstantiation*> ModuleInstantiationList;
class ModuleInstantiation : public ASTNode
{
public:
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<AbstractNode*> instantiateChildren(const Context *evalctx) const;
// 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;
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(shared_ptr<class Expression> expr, const std::string &source_path, const Location &loc) : ModuleInstantiation("if", AssignmentList{Assignment("", expr)}, source_path, loc) { }
virtual ~IfElseModuleInstantiation();
std::vector<AbstractNode*> instantiateElseChildren(const Context *evalctx) const;
virtual std::string dump(const std::string &indent) const;
LocalScope else_scope;
};

View file

@ -1,26 +1,17 @@
#include "traverser.h"
#include "visitor.h"
#include "node.h"
#include "NodeVisitor.h"
#include "state.h"
#include <algorithm>
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) {
@ -33,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;

View file

@ -1,13 +1,37 @@
#pragma once
#include "traverser.h"
#include "BaseVisitable.h"
#include "node.h"
#include "state.h"
class Visitor
class NodeVisitor :
public BaseVisitor,
public Visitor<class AbstractNode>,
public Visitor<class AbstractIntersectionNode>,
public Visitor<class AbstractPolyNode>,
public Visitor<class GroupNode>,
public Visitor<class RootNode>,
public Visitor<class LeafNode>,
public Visitor<class CgaladvNode>,
public Visitor<class CsgOpNode>,
public Visitor<class LinearExtrudeNode>,
public Visitor<class RotateExtrudeNode>,
public Visitor<class ImportNode>,
public Visitor<class PrimitiveNode>,
public Visitor<class TextNode>,
public Visitor<class ProjectionNode>,
public Visitor<class RenderNode>,
public Visitor<class SurfaceNode>,
public Visitor<class TransformNode>,
public Visitor<class ColorNode>,
public Visitor<class OffsetNode>
{
public:
Visitor() {}
virtual ~Visitor() {}
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);
@ -18,7 +42,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) {
@ -64,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;
};

20
src/Package.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include "AST.h"
#include <string>
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<std::string> ModuleContainer;
ModuleContainer usedlibs;
private:
std::string _path;
};

View file

@ -1,6 +1,6 @@
#include "parameterextractor.h"
#include "module.h"
#include "FileModule.h"
#include "modcontext.h"
ParameterExtractor::ParameterExtractor()
@ -18,7 +18,7 @@ void ParameterExtractor::applyParameters(FileModule *fileModule)
}
for (AssignmentList::iterator it = fileModule->scope.assignments.begin();it != fileModule->scope.assignments.end();it++) {
entry_map_t::iterator entry = entries.find((*it).first);
entry_map_t::iterator entry = entries.find((*it).name);
if (entry == entries.end()) {
continue;
}
@ -28,7 +28,7 @@ void ParameterExtractor::applyParameters(FileModule *fileModule)
}
}
void ParameterExtractor::setParameters(const Module *module)
void ParameterExtractor::setParameters(const FileModule* module)
{
if (module == NULL) {
return;
@ -43,7 +43,7 @@ void ParameterExtractor::setParameters(const Module *module)
continue;
}
const ValuePtr defaultValue = assignment.second.get()->evaluate(&ctx);
const ValuePtr defaultValue = assignment.expr.get()->evaluate(&ctx);
if (defaultValue->type() == Value::UNDEFINED) {
continue;
}
@ -52,13 +52,13 @@ void ParameterExtractor::setParameters(const Module *module)
entryObject->setAssignment(&ctx, &assignment, defaultValue);
//need to improve structure
if(entries.find(assignment.first) == entries.end()){
entries[assignment.first] = entryObject;
if(entries.find(assignment.name) == entries.end()){
entries[assignment.name] = entryObject;
}else{
if(*entryObject==*entries[assignment.first]){
entryObject=entries[assignment.first];
if(*entryObject==*entries[assignment.name]){
entryObject=entries[assignment.name];
}else{
entries[assignment.first] = entryObject;
entries[assignment.name] = entryObject;
}
}

View file

@ -1,6 +1,7 @@
#ifndef PARAMETEREXTRACTOR_H
#define PARAMETEREXTRACTOR_H
#include "FileModule.h"
#include "parametervirtualwidget.h"
class ParameterExtractor
@ -14,7 +15,7 @@ protected:
public:
ParameterExtractor();
virtual ~ParameterExtractor();
void setParameters(const Module *module);
void setParameters(const FileModule* module);
void applyParameters(class FileModule *fileModule);

View file

@ -11,10 +11,10 @@ ParameterObject::ParameterObject()
void ParameterObject::applyParameter(class Assignment *assignment){
ModuleContext ctx;
const ValuePtr defaultValue =assignment->second.get()->evaluate(&ctx);
const ValuePtr defaultValue =assignment->expr.get()->evaluate(&ctx);
if( defaultValue->type() == dvt ){
assignment->second = shared_ptr<Expression>(new ExpressionConst(value));
assignment->expr = shared_ptr<Expression>(new Literal(value));
}
}
@ -44,7 +44,7 @@ int ParameterObject::setValue(const class ValuePtr defaultValue, const class Val
}
void ParameterObject::setAssignment(class Context *ctx, const class Assignment *assignment, const ValuePtr defaultValue){
name = assignment->first;
name = assignment->name;
const Annotation *param = assignment->annotation("Parameter");
const ValuePtr values = param->evaluate(ctx, "values");
setValue(defaultValue, values);

View file

@ -5,7 +5,7 @@
#include "value.h"
#include "qtgettext.h"
#include "typedefs.h"
#include "Assignment.h"
#include "expression.h"
#include<QString>

View file

@ -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();

View file

@ -24,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");
}

90
src/UserModule.cc Normal file
View file

@ -0,0 +1,90 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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 <sstream>
std::deque<std::string> 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<AbstractNode *> 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();
}

27
src/UserModule.h Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <string>
#include <deque>
#include "module.h"
#include "localscope.h"
class UserModule : public AbstractModule, public ASTNode
{
public:
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;
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<std::string> module_stack;
};

View file

@ -25,12 +25,13 @@
*/
#include <stdio.h>
#include "typedefs.h"
#include"Assignment.h"
#include "expression.h"
#include "context.h"
#include "evalcontext.h"
#include <iostream>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
Annotation::Annotation(const std::string name, const AssignmentList assignments, const AssignmentList args)
@ -82,6 +83,6 @@ void Annotation::dump()
std::cout << " ANNOTATION: '" << name << "'" << std::endl;
for (AssignmentList::const_iterator it = assignments.begin();it != assignments.end();it++) {
const Assignment &assignment = (*it);
std::cout << (*it).first << assignment.second << std::endl;
std::cout << (*it).name << assignment.expr << std::endl;
}
}

View file

@ -24,23 +24,9 @@
*
*/
#include "typedefs.h"
#include "Assignment.h"
Assignment::Assignment(std::string name)
{
first = name;
second = shared_ptr<class Expression>();
}
Assignment::Assignment(std::string name, shared_ptr<class Expression> expr)
{
first = name;
second = expr;
}
Assignment::~Assignment()
{
}
void Assignment::add_annotations(AnnotationList *annotations)
{

View file

@ -94,19 +94,19 @@ std::string Builtins::isDeprecated(const std::string &name)
Builtins::Builtins()
{
this->globalscope.assignments.push_back(Assignment("$fn", shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fs", shared_ptr<Expression>(new ExpressionConst(ValuePtr(2.0)))));
this->globalscope.assignments.push_back(Assignment("$fa", shared_ptr<Expression>(new ExpressionConst(ValuePtr(12.0)))));
this->globalscope.assignments.push_back(Assignment("$t", shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fn", shared_ptr<Expression>(new Literal(ValuePtr(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fs", shared_ptr<Expression>(new Literal(ValuePtr(2.0)))));
this->globalscope.assignments.push_back(Assignment("$fa", shared_ptr<Expression>(new Literal(ValuePtr(12.0)))));
this->globalscope.assignments.push_back(Assignment("$t", shared_ptr<Expression>(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<Expression>(new ExpressionConst(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpr", shared_ptr<Expression>(new ExpressionConst(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpd", shared_ptr<Expression>(new ExpressionConst(ValuePtr(500)))));
this->globalscope.assignments.push_back(Assignment("$vpt", shared_ptr<Expression>(new Literal(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpr", shared_ptr<Expression>(new Literal(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpd", shared_ptr<Expression>(new Literal(ValuePtr(500)))));
}
Builtins::~Builtins()

View file

@ -26,6 +26,7 @@
#include "cgaladvnode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "builtin.h"
#include "polyset.h"

View file

@ -1,7 +1,6 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
#include "linalg.h"
@ -16,13 +15,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;

View file

@ -193,7 +193,7 @@ namespace CGALUtils {
PRINTDB("After hull valid: %d", r.is_valid());
success = !createPolySetFromPolyhedron(r, result);
}
catch (const CGAL::Assertion_exception &e) {
catch (const CGAL::Failure_exception &e) {
PRINTB("ERROR: CGAL error in applyHull(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
@ -207,6 +207,7 @@ namespace CGALUtils {
*/
Geometry const * applyMinkowski(const Geometry::Geometries &children)
{
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
CGAL::Timer t,t_tot;
assert(children.size() >= 2);
Geometry::Geometries::const_iterator it = children.begin();
@ -397,6 +398,7 @@ namespace CGALUtils {
t_tot.stop();
PRINTDB("Minkowski: Total execution time %f s", t_tot.time());
t_tot.reset();
CGAL::set_error_behaviour(old_behaviour);
return operands[0];
}
catch (...) {
@ -404,6 +406,7 @@ namespace CGALUtils {
PRINTD("Minkowski: Falling back to Nef Minkowski");
CGAL_Nef_polyhedron *N = applyOperator(children, OPENSCAD_MINKOWSKI);
CGAL::set_error_behaviour(old_behaviour);
return N;
}
}

View file

@ -26,6 +26,7 @@
#include "colornode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "builtin.h"
#include "printutils.h"

View file

@ -1,16 +1,13 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "linalg.h"
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;

View file

@ -1,5 +1,5 @@
%{
#include "typedefs.h"
#include "Assignment.h"
#include "expression.h"
#include "value.h"
#include "comment_parser.h"
@ -29,10 +29,12 @@ H [0-9a-fA-F]
"]" { return yytext[0];}
"," { return yytext[0];}
":" { return yytext[0];}
[ \t]
[^(\[ \] \, \:)]* { yylval.text=strdup(yytext); return WORD;}
[\n\r ]
[ \n\r ]
. { }

View file

@ -2,8 +2,7 @@
#include<iostream>
#include<string.h>
using namespace std;
#include "typedefs.h"
#include "module.h"
#include "Assignment.h"
#include "expression.h"
#include "value.h"
void yyerror(char *);
@ -16,6 +15,7 @@
char ch;
double num;
class Expression *expr;
class Vector *vec;
Assignment *arg;
AssignmentList *args;
@ -29,7 +29,8 @@
%type <expr> expr
%type <args> arguments_call
%type <arg> argument_call
%type <expr> vector_expr
%type <vec> vector_expr
%type <vec> labled_vector
%%
@ -59,17 +60,17 @@ argument_call:
expr :
NUM
{
$$ = new ExpressionConst(ValuePtr($1));
$$ = new Literal(ValuePtr($1));
}
| word
{
$$ = new ExpressionConst(ValuePtr(std::string($1)));
$$ = new Literal(ValuePtr(std::string($1)));
free($1);
}
| '[' optional_commas ']'
{
$$ = new ExpressionConst(ValuePtr(Value::VectorType()));
$$ = new Literal(ValuePtr(Value::VectorType()));
}
| '[' vector_expr optional_commas ']'
{
@ -77,17 +78,21 @@ expr :
}
| '[' expr ':' expr ']'
{
$$ = new ExpressionRange($2, $4);
$$ = new Range($2, $4,Location::NONE);
}
| '[' expr ':' expr ':' expr ']'
{
$$ = new ExpressionRange($2, $4, $6);
}
| expr ':' expr
{
$$ = new ExpressionVector($1);
$$->children.push_back($3);
$$ = new Range($2, $4, $6,Location::NONE);
}
| labled_vector { $$=$1;}
;
labled_vector:
expr ':' expr {
$$ = new Vector(Location::NONE);
$$->push_back($1);
$$->push_back($3);
}
;
optional_commas:
@ -98,12 +103,13 @@ optional_commas:
vector_expr:
expr
{
$$ = new ExpressionVector($1);
$$ = new Vector(Location::NONE);
$$->push_back($1);
}
| vector_expr ',' optional_commas expr
{
$$ = $1;
$$->children.push_back($4);
$$->push_back($4);
}
;
@ -124,12 +130,14 @@ word:
void yyerror(char *msg) {
cout<<msg<<endl;
argument=NULL;
}
AssignmentList * parser(const char *text) {
yy_scan_string(text);
int parserretval = yyparse();
if (parserretval != 0) return NULL;
return argument;
}

View file

@ -28,7 +28,8 @@
#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "module.h"
#include "UserModule.h"
#include "ModuleInstantiation.h"
#include "builtin.h"
#include "printutils.h"
#include <boost/filesystem.hpp>
@ -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<const Module*>(mod);
const UserModule *m = dynamic_cast<const UserModule*>(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];
}
}
}

View file

@ -4,7 +4,7 @@
#include <vector>
#include <unordered_map>
#include "value.h"
#include "typedefs.h"
#include "Assignment.h"
#include "memory.h"
class Context

View file

@ -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<AbstractNode *> instantiatednodes = inst.instantiateChildren(&c);

View file

@ -28,6 +28,7 @@
#include "evalcontext.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "csgnode.h"
#include "builtin.h"
#include <sstream>

View file

@ -1,17 +1,14 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "enums.h"
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;
};

View file

@ -1,5 +1,6 @@
#include "evalcontext.h"
#include "module.h"
#include "UserModule.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;i<this->eval_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<const Module*>(mod);
const UserModule *m = dynamic_cast<const UserModule*>(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]);
}
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "context.h"
#include "Assignment.h"
/*!
This hold the evaluation context (the parameters actually sent

View file

@ -1,6 +1,7 @@
#pragma once
#include <stdexcept>
#include <sstream>
class EvaluationException : public std::runtime_error {
public:

View file

@ -34,8 +34,6 @@ void export_png(const shared_ptr<const class CGAL_Nef_polyhedron> &root_N, Camer
void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output);
void export_png_with_throwntogether(Tree &tree, Camera &c, std::ostream &output);
void export_parameter(std::ostream &output, FileModule *fileModule);
#ifdef DEBUG
void export_stl(const class PolySet &ps, std::ostream &output);

View file

@ -30,7 +30,6 @@
#include <assert.h>
#include <sstream>
#include <algorithm>
#include "stl-utils.h"
#include "printutils.h"
#include "stackcheck.h"
#include "exceptions.h"
@ -58,42 +57,14 @@ namespace {
}
}
Expression::Expression() : first(NULL), second(NULL), third(NULL)
{
}
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<Expression>());
}
namespace /* anonymous*/ {
std::ostream &operator << (std::ostream &o, AssignmentList const& l) {
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 +76,215 @@ bool Expression::isListComprehension() const
return false;
}
ExpressionNot::ExpressionNot(Expression *expr) : Expression(expr)
UnaryOp::UnaryOp(UnaryOp::Op op, Expression *expr, const Location &loc) : Expression(loc), 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, const Location &loc) :
Expression(loc), 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, const Location &loc)
: Expression(loc), 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, const Location &loc)
: Expression(loc), 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, const Location &loc) : Expression(loc), 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, const Location &loc)
: Expression(loc), 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, const Location &loc)
: Expression(loc), 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 +293,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(const Location &loc) : Expression(loc)
{
}
ValuePtr ExpressionVector::evaluate(const Context *context) const
void Vector::push_back(Expression *expr)
{
this->children.push_back(shared_ptr<Expression>(expr));
}
ValuePtr Vector::evaluate(const Context *context) const
{
Value::VectorType vec;
for(const auto &e : this->children) {
@ -413,7 +327,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 +337,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, const Location &loc) : Expression(loc), 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, const Location &loc)
: Expression(loc), 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 +372,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, const Location &loc)
: Expression(loc), 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, const Location &loc)
: Expression(loc), 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(const Location &loc) : Expression(loc)
{
}
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, const Location &loc)
: ListComprehension(loc), 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<Expression> &expr = this->cond->evaluate(context) ? this->ifexpr : this->elseexpr;
Value::VectorType vec;
if (expr) {
if (expr->isListComprehension()) {
return expr->evaluate(context);
@ -543,26 +452,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, const Location &loc) : ListComprehension(loc), 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 +491,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, const Location &loc)
: ListComprehension(loc), 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 +530,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, const Location &loc)
: ListComprehension(loc), 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 +580,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, const Location &loc)
: ListComprehension(loc), 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)

View file

@ -1,23 +1,18 @@
#pragma once
#include "AST.h"
#include <string>
#include <vector>
#include "value.h"
#include "typedefs.h"
#include "memory.h"
#include "Assignment.h"
class Expression
class Expression : public ASTNode
{
public:
std::vector<Expression*> 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();
Expression(const Location &loc) : ASTNode(loc) {}
virtual ~Expression() {}
virtual bool isListComprehension() const;
virtual ValuePtr evaluate(const class Context *context) const = 0;
@ -26,264 +21,217 @@ 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, const Location &loc);
virtual ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
const char *opString() const;
Op op;
shared_ptr<Expression> 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, const Location &loc);
virtual ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
const char *opString() const;
Op op;
shared_ptr<Expression> left;
shared_ptr<Expression> right;
};
class TernaryOp : public Expression
{
public:
TernaryOp(Expression *cond, Expression *ifexpr, Expression *elseexpr, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
shared_ptr<Expression> cond;
shared_ptr<Expression> ifexpr;
shared_ptr<Expression> 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, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
shared_ptr<Expression> array;
shared_ptr<Expression> 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, const Location &loc = Location::NONE);
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, 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:
std::string var_name;
shared_ptr<Expression> begin;
shared_ptr<Expression> step;
shared_ptr<Expression> end;
};
class ExpressionMember : public Expression
class Vector : public Expression
{
public:
ExpressionMember(Expression *expr, const std::string &member);
Vector(const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
void push_back(Expression *expr);
private:
std::vector<shared_ptr<Expression>> children;
};
class Lookup : public Expression
{
public:
Lookup(const std::string &name, const Location &loc);
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, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
shared_ptr<Expression> 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, const Location &loc);
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, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
AssignmentList call_arguments;
AssignmentList arguments;
shared_ptr<Expression> expr;
};
class ExpressionLc : public Expression
class ListComprehension : public Expression
{
virtual bool isListComprehension() const;
public:
ExpressionLc(Expression *expr);
ExpressionLc(Expression *expr1, Expression *expr2);
ListComprehension(const Location &loc);
~ListComprehension() = default;
};
class ExpressionLcIf : public ExpressionLc
class LcIf : public ListComprehension
{
public:
ExpressionLcIf(Expression *cond, Expression *exprIf, Expression *exprElse);
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:
Expression *cond;
shared_ptr<Expression> cond;
shared_ptr<Expression> ifexpr;
shared_ptr<Expression> elseexpr;
};
class ExpressionLcFor : public ExpressionLc
class LcFor : public ListComprehension
{
public:
ExpressionLcFor(const AssignmentList &arglist, 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:
AssignmentList call_arguments;
AssignmentList arguments;
shared_ptr<Expression> 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, const Location &loc);
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<Expression> cond;
shared_ptr<Expression> 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, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
AssignmentList call_arguments;
shared_ptr<Expression> expr;
};
class LcLet : public ListComprehension
{
public:
LcLet(const AssignmentList &args, Expression *expr, const Location &loc);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
AssignmentList arguments;
shared_ptr<Expression> expr;
};

View file

@ -35,6 +35,8 @@
#include "printutils.h"
#include "stackcheck.h"
#include "exceptions.h"
#include "memory.h"
#include "UserModule.h"
#include <cmath>
#include <sstream>
@ -70,137 +72,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<ExpressionTernary *>(expr)) {
ExpressionFunctionCall *f1 = dynamic_cast<ExpressionFunctionCall *>(expr->second);
ExpressionFunctionCall *f2 = dynamic_cast<ExpressionFunctionCall *>(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 +783,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 +801,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)

141
src/function.cc Normal file
View file

@ -0,0 +1,141 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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<Expression> expr, const Location &loc)
: ASTNode(loc), 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<TernaryOp> op;
shared_ptr<FunctionCall> call;
shared_ptr<Expression> endexpr;
public:
FunctionTailRecursion(const char *name, AssignmentList &definition_arguments,
shared_ptr<TernaryOp> expr, shared_ptr<FunctionCall> call,
shared_ptr<Expression> endexpr, bool invert,
const Location &loc)
: UserFunction(name, definition_arguments, expr, loc),
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<Expression> expr, const Location &loc)
{
if (shared_ptr<TernaryOp> ternary = dynamic_pointer_cast<TernaryOp>(expr)) {
shared_ptr<FunctionCall> ifcall = dynamic_pointer_cast<FunctionCall>(ternary->ifexpr);
shared_ptr<FunctionCall> elsecall = dynamic_pointer_cast<FunctionCall>(ternary->elseexpr);
if (ifcall && !elsecall) {
if (name == ifcall->name) {
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, loc);
}
}
}
return new UserFunction(name, definition_arguments, expr, loc);
}
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();
}

View file

@ -1,7 +1,8 @@
#pragma once
#include "AST.h"
#include "value.h"
#include "typedefs.h"
#include "Assignment.h"
#include "feature.h"
#include <string>
@ -12,13 +13,13 @@ class AbstractFunction
private:
const Feature *feature;
public:
AbstractFunction() : feature(NULL) {}
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(); }
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 ASTNode
{
public:
std::string name;
std::string name;
AssignmentList definition_arguments;
Expression *expr;
shared_ptr<Expression> expr;
Function(const char *name, AssignmentList &definition_arguments, Expression *expr);
virtual ~Function();
UserFunction(const char *name, AssignmentList &definition_arguments, shared_ptr<Expression> 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 Function * create(const char *name, AssignmentList &definition_arguments, Expression *expr);
static UserFunction *create(const char *name, AssignmentList &definition_arguments, shared_ptr<Expression> expr, const Location &loc);
};

View file

@ -27,6 +27,7 @@
#include "importnode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "polyset.h"
#include "Polygon2d.h"
#include "evalcontext.h"

View file

@ -1,7 +1,6 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
enum import_type_e {
@ -14,10 +13,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;

View file

@ -27,13 +27,12 @@
%{
#include <glib.h>
#include "typedefs.h"
#include "handle_dep.h"
#include "printutils.h"
#include "parsersettings.h"
#include "Assignment.h"
#include "parser_yacc.h"
#include "module.h"
#include<iostream>
#include "FileModule.h"
#include <assert.h>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
@ -89,6 +88,15 @@ std::vector<std::string> openfilenames;
std::string filename;
std::string filepath;
extern YYLTYPE parserlloc;
#define yylloc parserlloc
int yycolumn = 1;
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \
yycolumn += yyleng;
%}
%option yylineno
@ -203,18 +211,11 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
[\n\r\t ]
[\n]+"//" { BEGIN(cond_lcomment); stringcontents.clear(); return DCOMMENT;}
\/\/ { BEGIN(cond_lcomment); stringcontents.clear(); return COMMENT;}
\/\/ BEGIN(cond_lcomment);
<cond_lcomment>{
\n { BEGIN(INITIAL);
parserlval.text = strdup(stringcontents.c_str());
return CTOK_STRING; }
{UNICODE} {
parser_error_pos -= strlen(lexertext) - 1;
stringcontents += lexertext; }
[^\n] { stringcontents += lexertext;}
\n { BEGIN(INITIAL); }
{UNICODE} { parser_error_pos -= strlen(lexertext) - 1; }
[^\n]
}

View file

@ -27,6 +27,7 @@
#include "linearextrudenode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "printutils.h"
#include "fileutils.h"

View file

@ -1,12 +1,12 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
class LinearExtrudeNode : public AbstractPolyNode
{
public:
VISITABLE();
LinearExtrudeNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) {
convexity = slices = 0;
fn = fs = fa = height = twist = 0;
@ -14,9 +14,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"; }

View file

@ -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<AbstractNode*> 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));
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "typedefs.h"
#include "Assignment.h"
#include <unordered_map>
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<class AbstractNode*> 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<ModuleInstantiation*> children;
typedef std::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
FunctionContainer functions;
typedef std::unordered_map<std::string, class AbstractModule*> AbstractModuleContainer;

View file

@ -23,6 +23,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <iostream>
#include "openscad.h"
#include "GeometryCache.h"
@ -1715,13 +1716,91 @@ void MainWindow::compileTopLevelDocument()
const char* fname =
this->fileName.isEmpty() ? "" : fnameba;
this->root_module = parse(fulltext.c_str(), fs::path(fname), false);
if(this->root_module!=NULL)
addparameter(fulltext.c_str());
this->parameterWidget->setParameters(this->root_module);
this->parameterWidget->applyParameters(this->root_module);
}
void MainWindow::addparameter(const char *fulltext){
for (AssignmentList::iterator it = this->root_module->scope.assignments.begin();it != this->root_module->scope.assignments.end();it++) {
//get loaction of assignment node
const Location locate=(*it).location();
int loc =locate.firstLine();
// makeing list to add annotations
AnnotationList *annotationList = new AnnotationList();
AssignmentList *assignments;
//extracting the parameter
string name = getParameter(std::string(fulltext),loc);
if(name!= " " ){
//getting the node for parameter annnotataion
assignments=parser(name.c_str());
if(assignments!=NULL){
const Annotation *Parameter;
Parameter=Annotation::create("Parameter",*assignments);
// adding parameter to the list
annotationList->push_back(*Parameter);
}
}
//extracting the description
name = getParameter(std::string(fulltext),loc-1);
if(name!= " "){
//creating node for description
assignments=new AssignmentList();
Expression *expr;
expr=new Literal(ValuePtr(std::string(name.c_str())));
Assignment *assign;
assign=new Assignment("", shared_ptr<Expression>(expr));
assignments->push_back(*assign);
const Annotation * Description;
Description=Annotation::create("Description", *assignments);
annotationList->push_back(*Description);
}
(*it).add_annotations(annotationList);
}
}
string MainWindow::getParameter(string fulltext, int loc){
int chara=0;
for(; chara<fulltext.length() ; chara++){
if(fulltext[chara]=='\n')
loc--;
if(loc==1)
break;
}
int len=chara+1;
while(fulltext[len]!='\n'){
len++;
}
string str2 = fulltext.substr(chara,len-chara);
int start= str2.find("//");
if(start<0 || start+2>str2.length()){
return " ";
}
return str2.substr(start+2);
}
void MainWindow::checkAutoReload()
{
if (!this->fileName.isEmpty()) {

View file

@ -2,7 +2,8 @@
#include "math.h"
#include "modcontext.h"
#include "module.h"
#include "UserModule.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 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<const Module*>(mod);
const UserModule *m = dynamic_cast<const UserModule*>(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));
}
}

View file

@ -1,10 +1,10 @@
#pragma once
#include "context.h"
#include "module.h"
#include "FileModule.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 class UserModule &m);
void registerBuiltin();
virtual ValuePtr evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
@ -42,8 +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 FileModule &module);
virtual ValuePtr evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,

View file

@ -25,40 +25,14 @@
*/
#include "module.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 <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include "boosty.h"
#include "FontCache.h"
#include "context.h"
#include "value.h"
#include <sstream>
#include <sys/stat.h>
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,324 +52,3 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n
return dump.str();
}
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.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<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
{
return this->scope.instantiateChildren(evalctx);
}
std::vector<AbstractNode*> IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const
{
return this->else_scope.instantiateChildren(evalctx);
}
std::deque<std::string> Module::module_stack;
Module::~Module()
{
}
void Module::add_annotations(AnnotationList *annotations)
{
for (AnnotationList::iterator it = annotations->begin();it != annotations->end();it++) {
this->annotations.insert(std::pair<const std::string, Annotation *>((*it).get_name(), &(*it)));
}
}
bool Module::has_annotations() const
{
return !annotations.empty();
}
const Annotation * Module::annotation(const std::string &name) const
{
AnnotationMap::const_iterator it = annotations.find(name);
return it == annotations.end() ? NULL : (*it).second;
}
AbstractNode *Module::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<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(&c);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
module_stack.pop_back();
return node;
}
std::string Module::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.first;
if (arg.second) dump << " = " << *arg.second;
}
dump << ") {\n";
tab = "\t";
}
dump << scope.dump(indent + tab);
if (!name.empty()) {
dump << indent << "}\n";
}
return dump.str();
}
FileModule::~FileModule()
{
delete context;
}
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<std::pair<std::string,std::string>> 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<std::string,std::string> 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)
{
assert(evalctx == NULL);
delete context;
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<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(context);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
catch (EvaluationException &e) {
PRINT(e.what());
}
return node;
}
void FileModule::set_variable(const std::string name, Value value)
{
if (this->context) {
this->context->set_variable(name, value);
}
}
ValuePtr FileModule::lookup_variable(const std::string &name) const
{
if (!context) {
return ValuePtr::undefined;
}
return context->lookup_variable(name, true);
}
void register_builtin_group()
{
Builtins::init("group", new GroupModule());
}

View file

@ -1,150 +1,21 @@
#pragma once
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <time.h>
#include <sys/stat.h>
#include "value.h"
#include "typedefs.h"
#include "localscope.h"
#include "AST.h"
#include "feature.h"
#include "context.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<AbstractNode*> 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<AbstractNode*> instantiateElseChildren(const Context *evalctx) const;
virtual std::string dump(const std::string &indent) const;
LocalScope else_scope;
};
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 Module : public AbstractModule
{
public:
Module() { }
Module(const Feature& feature) : AbstractModule(feature) { }
virtual ~Module();
virtual void add_annotations(AnnotationList *annotations);
virtual bool has_annotations() const;
virtual const Annotation * annotation(const std::string &name) const;
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;
protected:
AnnotationMap annotations;
private:
static std::deque<std::string> module_stack;
};
// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really
// inherit from a Module
class FileModule : public Module
{
public:
FileModule() : context(NULL), is_handling_dependencies(false) {}
virtual ~FileModule();
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; }
void set_variable(const std::string name, Value value);
ValuePtr lookup_variable(const std::string &name) const;
typedef std::unordered_set<std::string> ModuleContainer;
ModuleContainer usedlibs;
private:
/** Reference to retain the context that was used in the last evaluation */
class FileContext *context;
struct IncludeFile {
std::string filename;
bool valid;
time_t mtime;
};
bool include_modified(const IncludeFile &inc) const;
typedef std::unordered_map<std::string, struct IncludeFile> 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;
};

View file

@ -26,8 +26,8 @@
#include "node.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "progress.h"
#include "visitor.h"
#include "stl-utils.h"
#include <iostream>
@ -46,37 +46,6 @@ AbstractNode::~AbstractNode()
std::for_each(this->children.begin(), this->children.end(), del_fun<AbstractNode>());
}
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() + "()";

View file

@ -2,13 +2,13 @@
#include <vector>
#include <string>
#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;
};

View file

@ -1,6 +1,7 @@
#include "nodedumper.h"
#include "state.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include <string>
#include <sstream>

View file

@ -3,10 +3,11 @@
#include <string>
#include <map>
#include <list>
#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<id>:" in front of each node,

View file

@ -27,6 +27,7 @@
#include "offsetnode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "printutils.h"
#include "fileutils.h"

View file

@ -1,17 +1,14 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
#include "clipper-utils.h"
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"; }

View file

@ -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"

View file

@ -24,7 +24,7 @@
*
*/
//%expect 3 /* Expect 2 shift/reduce conflict for ifelse_statement - "dangling else problem" */
%expect 2 /* Expect 2 shift/reduce conflict for ifelse_statement - "dangling else problem" */
%{
@ -34,8 +34,10 @@
#include <unistd.h>
#endif
#include "typedefs.h"
#include "module.h"
#include "FileModule.h"
#include "UserModule.h"
#include "ModuleInstantiation.h"
#include "Assignment.h"
#include "expression.h"
#include "value.h"
#include "function.h"
@ -49,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);
@ -60,7 +63,6 @@ fs::path sourcefile(void);
int lexerlex_destroy(void);
int lexerlex(void);
extern AssignmentList * parser(const char *text);
std::stack<LocalScope *> scope_stack;
FileModule *rootmodule;
@ -77,30 +79,29 @@ 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;
const Annotation *annotation;
AnnotationList *annotations;
}
%locations
%token TOK_ERROR
%token TOK_MODULE
%token TOK_ANNOTATION
%token COMMENT DCOMMENT
%token TOK_FUNCTION
%token TOK_IF
%token TOK_ELSE
%token TOK_FOR
%token TOK_LET
%token TOK_EACH
%token TOK_EACH
%token <text> TOK_ID
%token <text> TOK_STRING
%token <text> CTOK_STRING
%token <text> TOK_USE
%token <number> TOK_NUMBER
@ -126,7 +127,7 @@ fs::path parser_sourcefile;
%left '.'
%type <expr> expr
%type <expr> vector_expr
%type <vec> vector_expr
%type <expr> list_comprehension_elements
%type <expr> list_comprehension_elements_p
%type <expr> list_comprehension_elements_or_expr
@ -139,19 +140,14 @@ fs::path parser_sourcefile;
%type <args> arguments_call
%type <args> arguments_decl
%type <arg> assignment
%type <arg> argument_call
%type <arg> argument_decl
%type <annotation> annotation
%type <annotation> parameter
%type <annotations> parameters
%type <annotation> description
%type <annotations> descriptions
%type <annotations> annotations
%type <text> module_id
%type <arg> assignment
%type <annotation> annotation
%type <annotations> annotations
%debug
%%
@ -188,40 +184,7 @@ annotation:
free($2);
}
;
descriptions:
description
{
$$ = new AnnotationList();
$$->push_back(*$1);
delete $1;
}
;
description:
COMMENT arguments_call
{
$$ = Annotation::create("Description", *$2);
}
;
parameters:
parameter
{
$$ = new AnnotationList();
$$->push_back(*$1);
delete $1;
}
;
parameter:
COMMENT CTOK_STRING
{
AssignmentList *assignments;
assignments=parser($2);
$$ = Annotation::create("Parameter",*assignments);
}
;
statement:
';'
| '{' inner_input '}'
@ -234,24 +197,9 @@ statement:
{
$2->add_annotations($1);
}
| assignment parameters
{
$1->add_annotations($2);
}
| descriptions assignment
{
$2->add_annotations($1);
}
| descriptions assignment parameters
{
$2->add_annotations($1);
$2->add_annotations($3);
}
| COMMENT CTOK_STRING {}
| DCOMMENT CTOK_STRING {}
| TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')'
{
Module *newmodule = new Module();
UserModule *newmodule = new UserModule(LOC(@$));
newmodule->definition_arguments = *$4;
scope_stack.top()->modules[$2] = newmodule;
scope_stack.push(&newmodule->scope);
@ -262,23 +210,9 @@ statement:
{
scope_stack.pop();
}
| annotations TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')'
{
Module *newmodule = new Module();
newmodule->definition_arguments = *$5;
newmodule->add_annotations($1);
scope_stack.top()->modules[$3] = newmodule;
scope_stack.push(&newmodule->scope);
free($3);
delete $5;
}
statement
{
scope_stack.pop();
}
| TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr
{
Function *func = Function::create($2, *$4, $8);
UserFunction *func = UserFunction::create($2, *$4, shared_ptr<Expression>($8), LOC(@$));
scope_stack.top()->functions[$2] = func;
free($2);
delete $4;
@ -296,21 +230,18 @@ assignment:
{
bool found = false;
for (auto& iter : scope_stack.top()->assignments) {
if (iter.first == $1) {
iter.second = shared_ptr<Expression>($3);
if (iter.name == $1) {
iter.expr = shared_ptr<Expression>($3);
found = true;
$$ = &iter;
break;
}
}
if (!found) {
scope_stack.top()->assignments.push_back(Assignment($1, shared_ptr<Expression>($3)));
$$ = &scope_stack.top()->assignments.back();
scope_stack.top()->assignments.push_back(Assignment($1, shared_ptr<Expression>($3),LOC(@$)));
}
free($1);
$$ = &scope_stack.top()->assignments.back();
}
| COMMENT CTOK_STRING {}
| DCOMMENT CTOK_STRING {}
;
module_instantiation:
@ -369,9 +300,7 @@ ifelse_statement:
if_statement:
TOK_IF '(' expr ')'
{
$<ifelse>$ = new IfElseModuleInstantiation();
$<ifelse>$->arguments.push_back(Assignment("", shared_ptr<Expression>($3)));
$<ifelse>$->setPath(boosty::stringy(parser_sourcefile.parent_path()));
$<ifelse>$ = new IfElseModuleInstantiation(shared_ptr<Expression>($3), boosty::stringy(parser_sourcefile.parent_path()), LOC(@$));
scope_stack.push(&$<ifelse>$->scope);
}
child_statement
@ -407,17 +336,7 @@ module_id:
single_module_instantiation:
module_id '(' arguments_call ')'
{
$$ = new ModuleInstantiation($1);
$$->arguments = *$3;
$$->setPath(boosty::stringy(parser_sourcefile.parent_path()));
free($1);
delete $3;
}
|module_id '(' arguments_call ')' COMMENT CTOK_STRING
{
$$ = new ModuleInstantiation($1);
$$->arguments = *$3;
$$->setPath(boosty::stringy(parser_sourcefile.parent_path()));
$$ = new ModuleInstantiation($1, *$3, boosty::stringy(parser_sourcefile.parent_path()), LOC(@$));
free($1);
delete $3;
}
@ -426,120 +345,107 @@ single_module_instantiation:
expr:
TOK_TRUE
{
$$ = new ExpressionConst(ValuePtr(true));
$$ = new Literal(ValuePtr(true), LOC(@$));
}
| TOK_FALSE
{
$$ = new ExpressionConst(ValuePtr(false));
$$ = new Literal(ValuePtr(false), LOC(@$));
}
| TOK_UNDEF
{
$$ = new ExpressionConst(ValuePtr::undefined);
$$ = new Literal(ValuePtr::undefined, LOC(@$));
}
| TOK_ID
{
$$ = new ExpressionLookup($1);
$$ = new Lookup($1, LOC(@$));
free($1);
}
| expr '.' TOK_ID
{
$$ = new ExpressionMember($1, $3);
free($3);
$$ = new MemberLookup($1, $3, LOC(@$));
free($3);
}
| TOK_STRING
{
$$ = new ExpressionConst(ValuePtr(std::string($1)));
free($1);
$$ = new Literal(ValuePtr(std::string($1)), LOC(@$));
free($1);
}
| CTOK_STRING
{
$$ = new ExpressionConst(ValuePtr(std::string($1)));
free($1);
}
| COMMENT CTOK_STRING {}
| COMMENT CTOK_STRING expr {
$$=$3;
}
| TOK_NUMBER
{
$$ = new ExpressionConst(ValuePtr($1));
$$ = new Literal(ValuePtr($1), LOC(@$));
}
| TOK_LET '(' arguments_call ')' expr %prec LET
{
$$ = new ExpressionLet(*$3, $5);
delete $3;
$$ = new Let(*$3, $5, LOC(@$));
delete $3;
}
| '[' expr ':' expr ']'
{
$$ = new ExpressionRange($2, $4);
$$ = new Range($2, $4, LOC(@$));
}
| '[' expr ':' expr ':' expr ']'
{
$$ = new ExpressionRange($2, $4, $6);
$$ = new Range($2, $4, $6, LOC(@$));
}
| '[' optional_commas ']'
{
$$ = new ExpressionConst(ValuePtr(Value::VectorType()));
$$ = new Literal(ValuePtr(Value::VectorType()), LOC(@$));
}
| '[' vector_expr optional_commas expr']'
| '[' vector_expr optional_commas ']'
{
$$ = $2;
}
| '[' vector_expr optional_commas']'
{
$$ = $2;
$$ = $2;
}
| expr '*' expr
{
$$ = new ExpressionMultiply($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Multiply, $3, LOC(@$));
}
| expr '/' expr
{
$$ = new ExpressionDivision($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Divide, $3, LOC(@$));
}
| expr '%' expr
{
$$ = new ExpressionModulo($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Modulo, $3, LOC(@$));
}
| expr '+' expr
{
$$ = new ExpressionPlus($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Plus, $3, LOC(@$));
}
| expr '-' expr
{
$$ = new ExpressionMinus($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Minus, $3, LOC(@$));
}
| expr '<' expr
{
$$ = new ExpressionLess($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Less, $3, LOC(@$));
}
| expr LE expr
{
$$ = new ExpressionLessOrEqual($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::LessEqual, $3, LOC(@$));
}
| expr EQ expr
{
$$ = new ExpressionEqual($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Equal, $3, LOC(@$));
}
| expr NE expr
{
$$ = new ExpressionNotEqual($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::NotEqual, $3, LOC(@$));
}
| expr GE expr
{
$$ = new ExpressionGreaterOrEqual($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::GreaterEqual, $3, LOC(@$));
}
| expr '>' expr
{
$$ = new ExpressionGreater($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::Greater, $3, LOC(@$));
}
| expr AND expr
{
$$ = new ExpressionLogicalAnd($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::LogicalAnd, $3, LOC(@$));
}
| expr OR expr
{
$$ = new ExpressionLogicalOr($1, $3);
$$ = new BinaryOp($1, BinaryOp::Op::LogicalOr, $3, LOC(@$));
}
| '+' expr
{
@ -547,29 +453,29 @@ expr:
}
| '-' expr
{
$$ = new ExpressionInvert($2);
$$ = new UnaryOp(UnaryOp::Op::Negate, $2, LOC(@$));
}
| '!' expr
{
$$ = new ExpressionNot($2);
$$ = new UnaryOp(UnaryOp::Op::Not, $2, LOC(@$));
}
| '(' expr ')'
{
$$ = $2;
$$ = $2;
}
| expr '?' expr ':' expr
{
$$ = new ExpressionTernary($1, $3, $5);
$$ = new TernaryOp($1, $3, $5, LOC(@$));
}
| expr '[' expr ']'
{
$$ = new ExpressionArrayLookup($1, $3);
$$ = new ArrayLookup($1, $3, LOC(@$));
}
| TOK_ID '(' arguments_call ')'
{
$$ = new ExpressionFunctionCall($1, *$3);
free($1);
delete $3;
$$ = new FunctionCall($1, *$3, LOC(@$));
free($1);
delete $3;
}
;
@ -578,12 +484,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, LOC(@$));
delete $3;
}
| TOK_EACH list_comprehension_elements_or_expr
{
$$ = new ExpressionLcEach($2);
$$ = new LcEach($2, LOC(@$));
}
| TOK_FOR '(' arguments_call ')' list_comprehension_elements_or_expr
{
@ -593,24 +499,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, $$, LOC(@$));
$$ = 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, LOC(@$));
delete $3;
delete $7;
}
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr
{
$$ = new ExpressionLcIf($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 ExpressionLcIf($3, $5, $7);
$$ = new LcIf($3, $5, $7, LOC(@$));
}
;
@ -636,16 +542,18 @@ optional_commas:
vector_expr:
expr
{
$$ = new ExpressionVector($1);
$$ = new Vector(LOC(@$));
$$->push_back($1);
}
| list_comprehension_elements
{
$$ = new ExpressionVector($1);
$$ = new Vector(LOC(@$));
$$->push_back($1);
}
| vector_expr ',' optional_commas list_comprehension_elements_or_expr
{
$$ = $1;
$$->children.push_back($4);
$$ = $1;
$$->push_back($4);
}
;
@ -660,37 +568,23 @@ arguments_decl:
$$->push_back(*$1);
delete $1;
}
| annotations argument_decl
{
$$ = new AssignmentList();
$2->add_annotations($1);
$$->push_back(*$2);
delete $2;
}
| arguments_decl ',' optional_commas argument_decl
{
$$ = $1;
$$->push_back(*$4);
delete $4;
}
| arguments_decl ',' optional_commas annotations argument_decl
{
$$ = $1;
$5->add_annotations($4);
$$->push_back(*$5);
delete $5;
}
;
argument_decl:
TOK_ID
{
$$ = new Assignment($1);
$$ = new Assignment($1, LOC(@$));
free($1);
}
| TOK_ID '=' expr
{
$$ = new Assignment($1, shared_ptr<Expression>($3));
$$ = new Assignment($1, shared_ptr<Expression>($3), LOC(@$));
free($1);
}
;
@ -717,11 +611,11 @@ arguments_call:
argument_call:
expr
{
$$ = new Assignment("", shared_ptr<Expression>($1));
$$ = new Assignment("", shared_ptr<Expression>($1), LOC(@$));
}
| TOK_ID '=' expr
{
$$ = new Assignment($1, shared_ptr<Expression>($3));
$$ = new Assignment($1, shared_ptr<Expression>($3), LOC(@$));
free($1);
}
;
@ -735,9 +629,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)
@ -763,3 +657,4 @@ FileModule *parse(const char *text, const fs::path &filename, int debug)
scope_stack.pop();
return rootmodule;
}

View file

@ -31,7 +31,6 @@
#include "Polygon2d.h"
#include "builtin.h"
#include "printutils.h"
#include "visitor.h"
#include "context.h"
#include "calc.h"
#include <sstream>
@ -65,10 +64,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) {

View file

@ -26,10 +26,10 @@
#include "projectionnode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "printutils.h"
#include "builtin.h"
#include "visitor.h"
#include "polyset.h"
#include <assert.h>

View file

@ -1,18 +1,15 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include <string>
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"; }

View file

@ -26,6 +26,7 @@
#include "rendernode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "builtin.h"
#include "polyset.h"

View file

@ -1,16 +1,13 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include <string>
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"; }

View file

@ -26,12 +26,12 @@
#include "rotateextrudenode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "printutils.h"
#include "fileutils.h"
#include "builtin.h"
#include "polyset.h"
#include "visitor.h"
#include <sstream>
#include <boost/assign/std/vector.hpp>

View file

@ -1,21 +1,18 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
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"; }

View file

@ -87,7 +87,7 @@ Settings::~Settings()
{
}
void Settings::visit(Visitor& visitor)
void Settings::visit(SettingsVisitor& visitor)
{
for (std::list<SettingsEntry *>::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()
{
}

View file

@ -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;
};

View file

@ -25,6 +25,7 @@
*/
#include "module.h"
#include "ModuleInstantiation.h"
#include "node.h"
#include "polyset.h"
#include "evalcontext.h"
@ -32,7 +33,6 @@
#include "printutils.h"
#include "fileutils.h"
#include "handle_dep.h" // handle_dep()
#include "visitor.h"
#include "lodepng.h"
#include <sstream>
@ -60,10 +60,8 @@ typedef std::unordered_map<std::pair<int,int>, double, boost::hash<std::pair<int
class SurfaceNode : public LeafNode
{
public:
VISITABLE();
SurfaceNode(const ModuleInstantiation *mi) : LeafNode(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 { return "surface"; }

View file

@ -1,7 +1,6 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "value.h"
#include "FreetypeRenderer.h"
@ -11,12 +10,9 @@ class TextModule;
class TextNode : public AbstractPolyNode
{
public:
VISITABLE();
TextNode(const ModuleInstantiation *mi) : AbstractPolyNode(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 { return "text"; }

View file

@ -25,7 +25,7 @@
*/
#include "transformnode.h"
#include "module.h"
#include "ModuleInstantiation.h"
#include "evalcontext.h"
#include "polyset.h"
#include "builtin.h"

View file

@ -1,16 +1,13 @@
#pragma once
#include "node.h"
#include "visitor.h"
#include "linalg.h"
class TransformNode : public AbstractNode
{
public:
VISITABLE();
TransformNode(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;

View file

@ -1,23 +0,0 @@
#pragma once
enum Response {ContinueTraversal, AbortTraversal, PruneTraversal};
class Traverser
{
public:
enum TraversalType {PREFIX, POSTFIX, PRE_AND_POSTFIX};
Traverser(class Visitor &visitor, const class 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:
Visitor &visitor;
const AbstractNode &root;
TraversalType traversaltype;
};

View file

@ -0,0 +1,5 @@
minkowski() {
scale([0,0,1]) cube(1);
scale([0,1,0]) cube(1);
scale([1,0,0]) cube(1);
}

View file

@ -0,0 +1,3 @@
hull() {
scale([0,0,1]) cube(1);
}

View file

@ -682,11 +682,18 @@ 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/FileModule.cc
../src/UserModule.cc
../src/GroupModule.cc
../src/AST.cc
../src/ModuleInstantiation.cc
../src/ModuleCache.cc
../src/node.cc
../src/NodeVisitor.cc
../src/context.cc
../src/modcontext.cc
../src/evalcontext.cc
@ -759,7 +766,6 @@ set(CGAL_SOURCES
set(COMMON_SOURCES
../src/nodedumper.cc
../src/traverser.cc
../src/GeometryCache.cc
../src/clipper-utils.cc
../src/Tree.cc
@ -1168,7 +1174,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/issues/issue1472.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/empty-stl.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/issues/issue1516.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/issues/issue1528.scad)
${CMAKE_SOURCE_DIR}/../testdata/scad/issues/issue1528.scad
)
list(APPEND DUMPTEST_FILES ${FEATURES_2D_FILES} ${FEATURES_3D_FILES} ${DEPRECATED_3D_FILES})
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
@ -1380,7 +1387,8 @@ list(APPEND BUGS_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue13.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1580-back-to-back2.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1580-import-back-to-back2.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1580-zero-area-triangle.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1580-import-zero-area-triangle.scad)
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1580-import-zero-area-triangle.scad
)
# We know that we cannot import weakly manifold files into CGAL, so to make tests easier
# to manage, don't try. Once we improve import, we can reenable this

View file

@ -3,9 +3,8 @@
#include <string>
#include <map>
#include <list>
#include "visitor.h"
#include "state.h"
#include "module.h" // FIXME: Temporarily for ModuleInstantiation
#include "ModuleInstantiation.h"
#include "csgops.h"
#include "transformnode.h"

View file

@ -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) {}

View file

@ -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"

View file

@ -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"
@ -58,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)

View file

@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Some files were not shown because too many files have changed in this diff Show more