summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AboutDialog.html8
-rw-r--r--src/CGALEvaluator.cc13
-rw-r--r--src/CGALRenderer.cc2
-rw-r--r--src/CGAL_Nef_polyhedron.cc2
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc2
-rw-r--r--src/MainWindow.h6
-rw-r--r--src/ModuleCache.cc10
-rw-r--r--src/ModuleCache.h7
-rw-r--r--src/PolySetCGALEvaluator.cc137
-rw-r--r--src/boost-utils.cc168
-rw-r--r--src/boost-utils.h13
-rw-r--r--src/boosty.h68
-rw-r--r--src/builtin.cc25
-rw-r--r--src/builtin.h12
-rw-r--r--src/cgaladv.cc23
-rw-r--r--src/color.cc17
-rw-r--r--src/context.cc150
-rw-r--r--src/context.h36
-rw-r--r--src/control.cc103
-rw-r--r--src/csgops.cc9
-rw-r--r--src/dxfdata.cc7
-rw-r--r--src/dxfdim.cc65
-rw-r--r--src/dxftess-cgal.cc6
-rw-r--r--src/dxftess-glu.cc79
-rw-r--r--src/dxftess.h4
-rw-r--r--src/evalcontext.cc64
-rw-r--r--src/evalcontext.h37
-rw-r--r--src/expr.cc55
-rw-r--r--src/expression.h7
-rw-r--r--src/fileutils.cc35
-rw-r--r--src/fileutils.h9
-rw-r--r--src/func.cc241
-rw-r--r--src/function.h12
-rw-r--r--src/highlighter.cc2
-rw-r--r--src/import.cc55
-rw-r--r--src/lexer.l5
-rw-r--r--src/linearextrude.cc41
-rw-r--r--src/linearextrudenode.h5
-rw-r--r--src/localscope.cc73
-rw-r--r--src/localscope.h26
-rw-r--r--src/mainwin.cc38
-rw-r--r--src/modcontext.cc163
-rw-r--r--src/modcontext.h54
-rw-r--r--src/module.cc189
-rw-r--r--src/module.h75
-rw-r--r--src/openscad.cc23
-rw-r--r--src/openscad.h2
-rw-r--r--src/parser.y746
-rw-r--r--src/parsersettings.cc3
-rw-r--r--src/primitives.cc30
-rw-r--r--src/printutils.cc2
-rw-r--r--src/printutils.h3
-rw-r--r--src/projection.cc17
-rw-r--r--src/render.cc17
-rw-r--r--src/rotateextrude.cc20
-rw-r--r--src/surface.cc18
-rw-r--r--src/transform.cc25
-rw-r--r--src/typedefs.h11
-rw-r--r--src/value.cc8
59 files changed, 1913 insertions, 1170 deletions
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
index 6203e83..005f61f 100644
--- a/src/AboutDialog.html
+++ b/src/AboutDialog.html
@@ -67,7 +67,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
</p>
<p>
-<b>Acknowledgements</b>
+<b>OpenSCAD Maintainer:</b> <a href="https://github.com/kintel">Marius Kintel </a>
</p>
<p>
@@ -101,11 +101,13 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
<li><a href="https://github.com/iamwilhelm">iamwilhelm</a>
<li><a href="https://github.com/clothbot">clothbot</a>
<li><a href="https://github.com/colah">colah</a>
+<li><a href="https://github.com/peteruithoven">Peter Uithoven</a>
+
</lu>
<p>
-<b>Mailing list, bug reports, testing, contribs, &c</b>
+<b>Mailing list, bug reports, testing, contribs, help, &c</b>
</p>
nop head, Triffid Hunter, Len Trigg, Kliment Yanev, Christian Siefkes,
@@ -115,7 +117,7 @@ Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop,
uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox,
Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith,
Pasca Andrei, David Goodenough, William A Adams, mrrobinson, 1i7,
-benhowes, 5263, Craig Trader, Miro Hrončok, ... and many others
+benhowes, 5263, Craig Trader, Miro Hrončok, Tony Theodore ... and many others
<p>
<b>Hosting &amp; resources</b>
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index 7c483cb..d0140fa 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -141,6 +141,9 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
continue;
}
+ if (chN.isNull()) { // If one of the children evaluated to a null object
+ continue;
+ }
if (dim == 2) {
CGAL_Nef_polyhedron2::Explorer explorer = chN.p2->explorer();
BOOST_FOREACH(const CGAL_Nef_polyhedron2::Explorer::Vertex &vh,
@@ -206,9 +209,11 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
bb = bounding_box( *N.p3 );
}
- Eigen::Matrix<NT,3,1> scale, bbox_size;
- scale << 1,1,1;
- bbox_size << bb.xmax()-bb.xmin(), bb.ymax()-bb.ymin(), bb.zmax()-bb.zmin();
+ std::vector<NT> scale, bbox_size;
+ for (int i=0;i<3;i++) scale.push_back( NT(1) );
+ bbox_size.push_back( bb.xmax()-bb.xmin() );
+ bbox_size.push_back( bb.ymax()-bb.ymin() );
+ bbox_size.push_back( bb.zmax()-bb.zmin() );
for (int i=0;i<3;i++) {
if (node.newsize[i]) {
if (bbox_size[i]==NT(0)) {
@@ -220,7 +225,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
}
}
}
- NT autoscale = scale.maxCoeff();
+ NT autoscale = std::max( scale[0], std::max( scale[1], scale[2] ));
for (int i=0;i<3;i++) {
if (node.autosize[i]) scale[i] = autoscale;
}
diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc
index 4357e44..0a75266 100644
--- a/src/CGALRenderer.cc
+++ b/src/CGALRenderer.cc
@@ -52,7 +52,7 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
this->polyhedron = NULL;
this->polyset = new PolySet();
this->polyset->is2d = true;
- dxf_tesselate(this->polyset, *dd, 0, true, false, 0);
+ dxf_tesselate(this->polyset, *dd, 0, Vector2d(1,1), true, false, 0);
delete dd;
}
else if (root.dim == 3) {
diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc
index 8906595..440f4ed 100644
--- a/src/CGAL_Nef_polyhedron.cc
+++ b/src/CGAL_Nef_polyhedron.cc
@@ -90,7 +90,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset()
ps = new PolySet();
DxfData *dd = this->convertToDxfData();
ps->is2d = true;
- dxf_tesselate(ps, *dd, 0, true, false, 0);
+ dxf_tesselate(ps, *dd, 0, Vector2d(1,1), true, false, 0);
dxf_border_to_ps(ps, *dd);
delete dd;
}
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 0388fe5..c4347e8 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -123,7 +123,7 @@ void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
PolySet ps;
ps.is2d = true;
- dxf_tesselate(&ps, *dd, 0, true, false, 0);
+ dxf_tesselate(&ps, *dd, 0, Vector2d(1,1), true, false, 0);
Tree nulltree;
CGALEvaluator tmpeval(nulltree);
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 8745b8b..378705e 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -4,7 +4,7 @@
#include <QMainWindow>
#include "ui_MainWindow.h"
#include "openscad.h"
-#include "context.h"
+#include "modcontext.h"
#include "module.h"
#include "Tree.h"
#include "memory.h"
@@ -29,8 +29,8 @@ public:
QTimer *autoReloadTimer;
std::string autoReloadId;
- Context root_ctx;
- Module *root_module; // Result of parsing
+ ModuleContext top_ctx;
+ FileModule *root_module; // Result of parsing
ModuleInstantiation root_inst; // Top level instance
AbstractNode *absolute_root_node; // Result of tree evaluation
AbstractNode *root_node; // Root if the root modifier (!) is used
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index 19a3f84..4944495 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -28,9 +28,9 @@ static bool is_modified(const std::string &filename, const time_t &mtime)
return (st.st_mtime > mtime);
}
-Module *ModuleCache::evaluate(const std::string &filename)
+FileModule *ModuleCache::evaluate(const std::string &filename)
{
- Module *lib_mod = NULL;
+ FileModule *lib_mod = NULL;
// Create cache ID
struct stat st;
@@ -48,7 +48,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
#endif
lib_mod = &(*this->entries[filename].module);
- BOOST_FOREACH(const Module::IncludeContainer::value_type &item, lib_mod->includes) {
+ BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, lib_mod->includes) {
if (is_modified(item.first, item.second)) {
lib_mod = NULL;
break;
@@ -78,7 +78,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
print_messages_push();
- Module *oldmodule = NULL;
+ FileModule *oldmodule = NULL;
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
oldmodule = this->entries[filename].module;
@@ -86,7 +86,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
- lib_mod = dynamic_cast<Module*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
+ lib_mod = dynamic_cast<FileModule*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
PRINTB_NOCACHE(" compiled module: %p", lib_mod);
if (lib_mod) {
diff --git a/src/ModuleCache.h b/src/ModuleCache.h
index 1e6373d..b8ded38 100644
--- a/src/ModuleCache.h
+++ b/src/ModuleCache.h
@@ -1,11 +1,14 @@
#include <string>
#include <boost/unordered_map.hpp>
+/*!
+ Caches FileModules based on their filenames
+*/
class ModuleCache
{
public:
static ModuleCache *instance() { if (!inst) inst = new ModuleCache; return inst; }
- class Module *evaluate(const std::string &filename);
+ class FileModule *evaluate(const std::string &filename);
size_t size() { return this->entries.size(); }
void clear();
@@ -16,7 +19,7 @@ private:
static ModuleCache *inst;
struct cache_entry {
- class Module *module;
+ class FileModule *module;
std::string cache_id;
};
boost::unordered_map<std::string, cache_entry> entries;
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 5976daf..f0c274f 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -202,27 +202,38 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
return ps;
}
-static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, double rot1, double rot2, double h1, double h2)
+static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path,
+ double rot1, double rot2,
+ double h1, double h2,
+ double scale1_x, double scale1_y,
+ double scale2_x, double scale2_y)
{
+ // FIXME: If scale2 == 0 we need to handle tessellation separately
bool splitfirst = sin(rot2 - rot1) >= 0.0;
- for (size_t j = 1; j < path.indices.size(); j++)
- {
+ for (size_t j = 1; j < path.indices.size(); j++) {
int k = j - 1;
- double jx1 = dxf.points[path.indices[j]][0] * cos(rot1*M_PI/180) + dxf.points[path.indices[j]][1] * sin(rot1*M_PI/180);
- double jy1 = dxf.points[path.indices[j]][0] * -sin(rot1*M_PI/180) + dxf.points[path.indices[j]][1] * cos(rot1*M_PI/180);
+ double jx1 = scale1_x * (dxf.points[path.indices[j]][0] * cos(rot1*M_PI/180) +
+ dxf.points[path.indices[j]][1] * sin(rot1*M_PI/180));
+ double jy1 = scale1_y * (dxf.points[path.indices[j]][0] * -sin(rot1*M_PI/180) +
+ dxf.points[path.indices[j]][1] * cos(rot1*M_PI/180));
- double jx2 = dxf.points[path.indices[j]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[j]][1] * sin(rot2*M_PI/180);
- double jy2 = dxf.points[path.indices[j]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[j]][1] * cos(rot2*M_PI/180);
+ double jx2 = scale2_x * (dxf.points[path.indices[j]][0] * cos(rot2*M_PI/180) +
+ dxf.points[path.indices[j]][1] * sin(rot2*M_PI/180));
+ double jy2 = scale2_y * (dxf.points[path.indices[j]][0] * -sin(rot2*M_PI/180) +
+ dxf.points[path.indices[j]][1] * cos(rot2*M_PI/180));
- double kx1 = dxf.points[path.indices[k]][0] * cos(rot1*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot1*M_PI/180);
- double ky1 = dxf.points[path.indices[k]][0] * -sin(rot1*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot1*M_PI/180);
+ double kx1 = scale1_x * (dxf.points[path.indices[k]][0] * cos(rot1*M_PI/180) +
+ dxf.points[path.indices[k]][1] * sin(rot1*M_PI/180));
+ double ky1 = scale1_y * (dxf.points[path.indices[k]][0] * -sin(rot1*M_PI/180) +
+ dxf.points[path.indices[k]][1] * cos(rot1*M_PI/180));
- double kx2 = dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180);
- double ky2 = dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180);
+ double kx2 = scale2_x * (dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) +
+ dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180));
+ double ky2 = scale2_y * (dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) +
+ dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180));
- if (splitfirst)
- {
+ if (splitfirst) {
ps->append_poly();
if (path.is_inner) {
ps->append_vertex(kx1, ky1, h1);
@@ -234,19 +245,20 @@ static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, doub
ps->insert_vertex(jx2, jy2, h2);
}
- ps->append_poly();
- if (path.is_inner) {
- ps->append_vertex(kx2, ky2, h2);
- ps->append_vertex(kx1, ky1, h1);
- ps->append_vertex(jx2, jy2, h2);
- } else {
- ps->insert_vertex(kx2, ky2, h2);
- ps->insert_vertex(kx1, ky1, h1);
- ps->insert_vertex(jx2, jy2, h2);
+ if (scale2_x > 0 || scale2_y > 0) {
+ ps->append_poly();
+ if (path.is_inner) {
+ ps->append_vertex(kx2, ky2, h2);
+ ps->append_vertex(kx1, ky1, h1);
+ ps->append_vertex(jx2, jy2, h2);
+ } else {
+ ps->insert_vertex(kx2, ky2, h2);
+ ps->insert_vertex(kx1, ky1, h1);
+ ps->insert_vertex(jx2, jy2, h2);
+ }
}
}
- else
- {
+ else {
ps->append_poly();
if (path.is_inner) {
ps->append_vertex(kx1, ky1, h1);
@@ -258,15 +270,17 @@ static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, doub
ps->insert_vertex(kx2, ky2, h2);
}
- ps->append_poly();
- if (path.is_inner) {
- ps->append_vertex(jx2, jy2, h2);
- ps->append_vertex(kx2, ky2, h2);
- ps->append_vertex(jx1, jy1, h1);
- } else {
- ps->insert_vertex(jx2, jy2, h2);
- ps->insert_vertex(kx2, ky2, h2);
- ps->insert_vertex(jx1, jy1, h1);
+ if (scale2_x > 0 || scale2_y > 0) {
+ ps->append_poly();
+ if (path.is_inner) {
+ ps->append_vertex(jx2, jy2, h2);
+ ps->append_vertex(kx2, ky2, h2);
+ ps->append_vertex(jx1, jy1, h1);
+ } else {
+ ps->insert_vertex(jx2, jy2, h2);
+ ps->insert_vertex(kx2, ky2, h2);
+ ps->insert_vertex(jx1, jy1, h1);
+ }
}
}
}
@@ -298,7 +312,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const LinearExtrudeNode &node)
if (sum.isNull()) return NULL;
dxf = sum.convertToDxfData();;
} else {
- dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
+ dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale_x);
}
PolySet *ps = extrudeDxfData(node, *dxf);
@@ -322,50 +336,49 @@ PolySet *PolySetCGALEvaluator::extrudeDxfData(const LinearExtrudeNode &node, Dxf
}
bool first_open_path = true;
- for (size_t i = 0; i < dxf.paths.size(); i++)
- {
- if (dxf.paths[i].is_closed)
- continue;
+ for (size_t i = 0; i < dxf.paths.size(); i++) {
+ if (dxf.paths[i].is_closed) continue;
if (first_open_path) {
PRINTB("WARNING: Open paths in dxf_linear_extrude(file = \"%s\", layer = \"%s\"):",
node.filename % node.layername);
first_open_path = false;
}
PRINTB(" %9.5f %10.5f ... %10.5f %10.5f",
- (dxf.points[dxf.paths[i].indices.front()][0] / node.scale + node.origin_x) %
- (dxf.points[dxf.paths[i].indices.front()][1] / node.scale + node.origin_y) %
- (dxf.points[dxf.paths[i].indices.back()][0] / node.scale + node.origin_x) %
- (dxf.points[dxf.paths[i].indices.back()][1] / node.scale + node.origin_y));
+ (dxf.points[dxf.paths[i].indices.front()][0] / node.scale_x + node.origin_x) %
+ (dxf.points[dxf.paths[i].indices.front()][1] / node.scale_y + node.origin_y) %
+ (dxf.points[dxf.paths[i].indices.back()][0] / node.scale_x + node.origin_x) %
+ (dxf.points[dxf.paths[i].indices.back()][1] / node.scale_y + node.origin_y));
}
- if (node.has_twist)
- {
- dxf_tesselate(ps, dxf, 0, false, true, h1);
- dxf_tesselate(ps, dxf, node.twist, true, true, h2);
- for (int j = 0; j < node.slices; j++)
- {
+ if (node.has_twist) {
+ dxf_tesselate(ps, dxf, 0, Vector2d(1,1), false, true, h1); // bottom
+ if (node.scale_x > 0 || node.scale_y > 0) {
+ dxf_tesselate(ps, dxf, node.twist, Vector2d(node.scale_x, node.scale_y), true, true, h2); // top
+ }
+ for (int j = 0; j < node.slices; j++) {
double t1 = node.twist*j / node.slices;
double t2 = node.twist*(j+1) / node.slices;
double g1 = h1 + (h2-h1)*j / node.slices;
double g2 = h1 + (h2-h1)*(j+1) / node.slices;
- for (size_t i = 0; i < dxf.paths.size(); i++)
- {
- if (!dxf.paths[i].is_closed)
- continue;
- add_slice(ps, dxf, dxf.paths[i], t1, t2, g1, g2);
+ double s1x = 1 - (1-node.scale_x)*j / node.slices;
+ double s1y = 1 - (1-node.scale_y)*j / node.slices;
+ double s2x = 1 - (1-node.scale_x)*(j+1) / node.slices;
+ double s2y = 1 - (1-node.scale_y)*(j+1) / node.slices;
+ for (size_t i = 0; i < dxf.paths.size(); i++) {
+ if (!dxf.paths[i].is_closed) continue;
+ add_slice(ps, dxf, dxf.paths[i], t1, t2, g1, g2, s1x, s1y, s2x, s2y);
}
}
}
- else
- {
- dxf_tesselate(ps, dxf, 0, false, true, h1);
- dxf_tesselate(ps, dxf, 0, true, true, h2);
- for (size_t i = 0; i < dxf.paths.size(); i++)
- {
- if (!dxf.paths[i].is_closed)
- continue;
- add_slice(ps, dxf, dxf.paths[i], 0, 0, h1, h2);
+ else {
+ dxf_tesselate(ps, dxf, 0, Vector2d(1,1), false, true, h1); //bottom
+ if (node.scale_x > 0 || node.scale_y > 0) {
+ dxf_tesselate(ps, dxf, 0, Vector2d(node.scale_x, node.scale_y), true, true, h2); // top
+ }
+ for (size_t i = 0; i < dxf.paths.size(); i++) {
+ if (!dxf.paths[i].is_closed) continue;
+ add_slice(ps, dxf, dxf.paths[i], 0, 0, h1, h2, 1, 1, node.scale_x, node.scale_y);
}
}
diff --git a/src/boost-utils.cc b/src/boost-utils.cc
new file mode 100644
index 0000000..534cbaa
--- /dev/null
+++ b/src/boost-utils.cc
@@ -0,0 +1,168 @@
+#include "boosty.h"
+#include "boost-utils.h"
+#include <stdio.h>
+#include <iostream>
+
+// If the given (absolute) path is relative to the relative_to path, return a new
+// relative path. Will normalize the given path first
+fs::path boostfs_relative_path(const fs::path &path, const fs::path &relative_to)
+{
+ // create absolute paths
+ fs::path p = boosty::absolute(boostfs_normalize(path));
+ fs::path r = boosty::absolute(relative_to);
+
+ // if root paths are different, return absolute path
+ if (p.root_path() != r.root_path())
+ return p;
+
+ // initialize relative path
+ fs::path result;
+
+ // find out where the two paths diverge
+ fs::path::const_iterator itr_path = p.begin();
+ fs::path::const_iterator itr_relative_to = r.begin();
+ while (*itr_path == *itr_relative_to && itr_path != p.end() && itr_relative_to != r.end()) {
+ ++itr_path;
+ ++itr_relative_to;
+ }
+
+ // add "../" for each remaining token in relative_to
+ if (itr_relative_to != r.end()) {
+ ++itr_relative_to;
+ while (itr_relative_to != r.end()) {
+ result /= "..";
+ ++itr_relative_to;
+ }
+ }
+
+ // add remaining path
+ while (itr_path != p.end()) {
+ result /= *itr_path;
+ ++itr_path;
+ }
+
+ return result;
+}
+
+// Will normalize the given path, i.e. remove any redundant ".." path elements.
+fs::path boostfs_normalize(const fs::path &path)
+{
+ fs::path absPath = boosty::absolute(path);
+ fs::path::iterator it = absPath.begin();
+ fs::path result = *it;
+ if (it!=absPath.end()) it++;
+
+ // Get canonical version of the existing part
+ for(;exists(result) && it != absPath.end(); ++it) {
+ result /= *it;
+ }
+ result = boosty::canonical(result.parent_path());
+ if (it!=absPath.begin()) it--;
+
+ // For the rest remove ".." and "." in a path with no symlinks
+ for (; it != absPath.end(); ++it) {
+ // Just move back on ../
+ if (*it == "..") {
+ result = result.parent_path();
+ }
+ // Ignore "."
+ else if (*it != ".") {
+ // Just cat other path entries
+ result /= *it;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * https://svn.boost.org/trac/boost/ticket/1976#comment:2
+ *
+ * "The idea: uncomplete(/foo/new, /foo/bar) => ../new
+ * The use case for this is any time you get a full path (from an open dialog, perhaps)
+ * and want to store a relative path so that the group of files can be moved to a different
+ * directory without breaking the paths. An IDE would be a simple example, so that the
+ * project file could be safely checked out of subversion."
+ *
+ * ALGORITHM:
+ * iterate path and base
+ * compare all elements so far of path and base
+ * whilst they are the same, no write to output
+x2 * when they change, or one runs out:
+ * write to output, ../ times the number of remaining elements in base
+ * write to output, the remaining elements in path
+ */
+fs::path
+boostfs_uncomplete(fs::path const p, fs::path const base)
+{
+ if (p == base) return "./";
+ /*!! this breaks stuff if path is a filename rather than a directory,
+ which it most likely is... but then base shouldn't be a filename so... */
+
+ // create absolute paths
+ fs::path abs_p = boosty::absolute(boostfs_normalize(p));
+ fs::path abs_base = boosty::absolute(base);
+
+ fs::path from_path, from_base, output;
+
+ fs::path::iterator path_it = abs_p.begin(), path_end = abs_p.end();
+ fs::path::iterator base_it = abs_base.begin(), base_end = abs_base.end();
+
+ // check for emptiness
+ if ((path_it == path_end) || (base_it == base_end)) {
+ throw std::runtime_error("path or base was empty; couldn't generate relative path");
+ }
+
+#ifdef WIN32
+ // drive letters are different; don't generate a relative path
+ if (*path_it != *base_it) return p;
+
+ // now advance past drive letters; relative paths should only go up
+ // to the root of the drive and not past it
+ ++path_it, ++base_it;
+#endif
+
+ // Cache system-dependent dot, double-dot and slash strings
+ const std::string _dot = ".";
+ const std::string _dots = "..";
+ const std::string _sep = "/";
+
+ // iterate over path and base
+ while (true) {
+
+ // compare all elements so far of path and base to find greatest common root;
+ // when elements of path and base differ, or run out:
+ if ((path_it == path_end) || (base_it == base_end) || (*path_it != *base_it)) {
+
+ // write to output, ../ times the number of remaining elements in base;
+ // this is how far we've had to come down the tree from base to get to the common root
+ for (; base_it != base_end; ++base_it) {
+ if (*base_it == _dot)
+ continue;
+ else if (*base_it == _sep)
+ continue;
+
+ output /= "../";
+ }
+
+ // write to output, the remaining elements in path;
+ // this is the path relative from the common root
+ fs::path::iterator path_it_start = path_it;
+ for (; path_it != path_end; ++path_it) {
+ if (path_it != path_it_start) output /= "/";
+ if (*path_it == _dot) continue;
+ if (*path_it == _sep) continue;
+ output /= *path_it;
+ }
+ break;
+ }
+
+ // add directory level to both paths and continue iteration
+ from_path /= fs::path(*path_it);
+ from_base /= fs::path(*base_it);
+
+ ++path_it, ++base_it;
+ }
+
+ return output;
+}
diff --git a/src/boost-utils.h b/src/boost-utils.h
new file mode 100644
index 0000000..3678ecc
--- /dev/null
+++ b/src/boost-utils.h
@@ -0,0 +1,13 @@
+#ifndef BOOST_UTILS_H_
+#define BOOST_UTILS_H_
+
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+
+// FIXME: boostfs_relative_path() has been replaced by
+// boostfs_uncomplete(), but kept around for now.
+fs::path boostfs_relative_path(const fs::path &path, const fs::path &relative_to);
+fs::path boostfs_normalize(const fs::path &path);
+fs::path boostfs_uncomplete(fs::path const p, fs::path const base);
+
+#endif
diff --git a/src/boosty.h b/src/boosty.h
index 6ec417a..82c765b 100644
--- a/src/boosty.h
+++ b/src/boosty.h
@@ -10,9 +10,8 @@
versions of boost found on popular versions of linux, circa early 2012.
design
- hope that the user is compiling with boost>1.46 + filesystem v3
- if not, fall back to older deprecated functions, and rely on
- testing to find bugs. implement the minimum needed by OpenSCAD and no more.
+ the boost filsystem changed around 1.46-1.48. we do a large #ifdef
+ based on boost version that wraps various functions appropriately.
in a few years, this file should be deleted as unnecessary.
see also
@@ -27,7 +26,9 @@
#include <string>
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
namespace fs = boost::filesystem;
+#include "printutils.h"
namespace boosty {
@@ -77,6 +78,67 @@ inline std::string extension_str( fs::path p)
#endif
+
+
+
+
+#if BOOST_VERSION >= 104800
+
+inline fs::path canonical( fs::path p, fs::path p2 )
+{
+ return fs::canonical( p, p2 );
+}
+
+inline fs::path canonical( fs::path p )
+{
+ return fs::canonical( p );
+}
+
+#else
+
+inline fs::path canonical( fs::path p, fs::path p2 )
+{
+#if defined (__WIN32__) || defined(__APPLE__)
+#error you should be using a newer version of boost on win/mac
+#endif
+ // based on the code in boost
+ fs::path result;
+ if (p=="") p=p2;
+ std::string result_s;
+ std::vector<std::string> resultv, pieces;
+ std::vector<std::string>::iterator pi;
+ std::string tmps = boosty::stringy( p );
+ boost::split( pieces, tmps, boost::is_any_of("/") );
+ for ( pi = pieces.begin(); pi != pieces.end(); ++pi )
+ {
+ if (*pi == "..")
+ resultv.erase( resultv.end() );
+ else
+ resultv.push_back( *pi );
+ }
+ for ( pi = resultv.begin(); pi != resultv.end(); ++pi )
+ {
+ if ((*pi).length()>0) result_s = result_s + "/" + *pi;
+ }
+ result = fs::path( result_s );
+ if (fs::is_symlink(result))
+ {
+ PRINT("WARNING: canonical() wrapper can't do symlinks. rebuild openscad with boost >=1.48");
+ PRINT("WARNING: or don't use symbolic links");
+ }
+ return result;
+}
+
+inline fs::path canonical( fs::path p )
+{
+ return canonical( p, fs::current_path() );
+}
+
+#endif
+
+
+
+
} // namespace
#endif
diff --git a/src/builtin.cc b/src/builtin.cc
index 6eb32b6..e116f17 100644
--- a/src/builtin.cc
+++ b/src/builtin.cc
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "function.h"
#include "module.h"
+#include "expression.h"
#include <boost/foreach.hpp>
Builtins *Builtins::instance(bool erase)
@@ -15,12 +16,12 @@ Builtins *Builtins::instance(bool erase)
void Builtins::init(const char *name, class AbstractModule *module)
{
- Builtins::instance()->builtinmodules[name] = module;
+ Builtins::instance()->globalscope.modules[name] = module;
}
void Builtins::init(const char *name, class AbstractFunction *function)
{
- Builtins::instance()->builtinfunctions[name] = function;
+ Builtins::instance()->globalscope.functions[name] = function;
}
extern void register_builtin_functions();
@@ -77,10 +78,22 @@ std::string Builtins::isDeprecated(const std::string &name)
return std::string();
}
+Builtins::Builtins()
+{
+ this->globalscope.assignments.push_back(Assignment("$fn", new Expression(Value(0.0))));
+ this->globalscope.assignments.push_back(Assignment("$fs", new Expression(Value(2.0))));
+ this->globalscope.assignments.push_back(Assignment("$fa", new Expression(Value(12.0))));
+ this->globalscope.assignments.push_back(Assignment("$t", new Expression(Value(0.0))));
+
+ Value::VectorType zero3;
+ zero3.push_back(Value(0.0));
+ zero3.push_back(Value(0.0));
+ zero3.push_back(Value(0.0));
+ Value zero3val(zero3);
+ this->globalscope.assignments.push_back(Assignment("$vpt", new Expression(zero3val)));
+ this->globalscope.assignments.push_back(Assignment("$vpr", new Expression(zero3val)));
+}
+
Builtins::~Builtins()
{
- BOOST_FOREACH(FunctionContainer::value_type &f, this->builtinfunctions) delete f.second;
- this->builtinfunctions.clear();
- BOOST_FOREACH(ModuleContainer::value_type &m, this->builtinmodules) delete m.second;
- this->builtinmodules.clear();
}
diff --git a/src/builtin.h b/src/builtin.h
index bc096e5..9397aa9 100644
--- a/src/builtin.h
+++ b/src/builtin.h
@@ -3,6 +3,8 @@
#include <string>
#include <boost/unordered_map.hpp>
+#include "module.h"
+#include "localscope.h"
class Builtins
{
@@ -16,19 +18,15 @@ public:
void initialize();
std::string isDeprecated(const std::string &name);
- const FunctionContainer &functions() { return this->builtinfunctions; }
- const ModuleContainer &modules() { return this->builtinmodules; }
+ const LocalScope &getGlobalScope() { return this->globalscope; }
private:
- Builtins() { }
+ Builtins();
~Builtins();
- FunctionContainer builtinfunctions;
- ModuleContainer builtinmodules;
+ LocalScope globalscope;
boost::unordered_map<std::string, std::string> deprecations;
};
-extern void register_builtin(class Context &ctx);
-
#endif
diff --git a/src/cgaladv.cc b/src/cgaladv.cc
index a4cb5ec..70590f7 100644
--- a/src/cgaladv.cc
+++ b/src/cgaladv.cc
@@ -26,7 +26,7 @@
#include "cgaladvnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
#include <sstream>
@@ -39,30 +39,29 @@ class CgaladvModule : public AbstractModule
public:
cgaladv_type_e type;
CgaladvModule(cgaladv_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CgaladvNode *node = new CgaladvNode(inst, type);
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
+ AssignmentList args;
if (type == MINKOWSKI)
- argnames += "convexity";
+ args += Assignment("convexity", NULL);
if (type == GLIDE)
- argnames += "path", "convexity";
+ args += Assignment("path", NULL), Assignment("convexity", NULL);
if (type == SUBDIV)
- argnames += "type", "level", "convexity";
+ args += Assignment("type", NULL), Assignment("level", NULL), Assignment("convexity", NULL);
if (type == RESIZE)
- argnames += "newsize", "auto";
+ args += Assignment("newsize", NULL), Assignment("auto", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
Value convexity, path, subdiv_type, level;
@@ -111,8 +110,8 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (node->level <= 1)
node->level = 1;
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/color.cc b/src/color.cc
index acca652..7fef030 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -26,7 +26,7 @@
#include "colornode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
@@ -40,27 +40,26 @@ class ColorModule : public AbstractModule
{
public:
ColorModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
private:
static boost::unordered_map<std::string, Color4f> colormap;
};
#include "colormap.h"
-AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ColorNode *node = new ColorNode(inst);
node->color[0] = node->color[1] = node->color[2] = -1.0;
node->color[3] = 1.0;
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
+ AssignmentList args;
- argnames += "c", "alpha";
+ args += Assignment("c", NULL), Assignment("alpha", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {
@@ -88,8 +87,8 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
node->color[3] = alpha.toDouble();
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/context.cc b/src/context.cc
index 97ea5b9..a7273a4 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -25,6 +25,7 @@
*/
#include "context.h"
+#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "module.h"
@@ -40,26 +41,11 @@ std::vector<const Context*> Context::ctx_stack;
/*!
Initializes this context. Optionally initializes a context for an external library
*/
-Context::Context(const Context *parent, const Module *library)
- : parent(parent), inst_p(NULL)
+Context::Context(const Context *parent)
+ : parent(parent)
{
- if (parent) recursioncount = parent->recursioncount;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
- if (library) {
- // FIXME: Don't access module members directly
- this->functions_p = &library->functions;
- this->modules_p = &library->modules;
- this->usedlibs_p = &library->usedlibs;
- BOOST_FOREACH(const std::string &var, library->assignments_var) {
- this->set_variable(var, library->assignments.at(var)->evaluate(this));
- }
- }
- else {
- functions_p = NULL;
- modules_p = NULL;
- usedlibs_p = NULL;
- }
}
Context::~Context()
@@ -68,25 +54,26 @@ Context::~Context()
}
/*!
- Initialize context from argument lists (function call/module instantiation)
- */
-void Context::args(const std::vector<std::string> &argnames,
- const std::vector<Expression*> &argexpr,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues)
+ Initialize context from a module argument list and a evaluation context
+ which may pass variables which will be preferred over default values.
+*/
+void Context::setVariables(const AssignmentList &args,
+ const EvalContext *evalctx)
{
- for (size_t i=0; i<argnames.size(); i++) {
- set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?
- argexpr[i]->evaluate(this->parent) : Value());
+ BOOST_FOREACH(const Assignment &arg, args) {
+ set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : Value());
}
- size_t posarg = 0;
- for (size_t i=0; i<call_argnames.size(); i++) {
- if (call_argnames[i].empty()) {
- if (posarg < argnames.size())
- set_variable(argnames[posarg++], call_argvalues[i]);
- } else {
- set_variable(call_argnames[i], call_argvalues[i]);
+ if (evalctx) {
+ size_t posarg = 0;
+ for (size_t i=0; i<evalctx->numArgs(); i++) {
+ const std::string &name = evalctx->getArgName(i);
+ const Value &val = evalctx->getArgValue(i);
+ if (name.empty()) {
+ if (posarg < args.size()) this->set_variable(args[posarg++].first, val);
+ } else {
+ this->set_variable(name, val);
+ }
}
}
}
@@ -130,61 +117,16 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
return Value();
}
-class RecursionGuard
-{
-public:
- RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; }
- ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); }
- bool recursion_detected() const { return (c.recursioncount[name] > 100); }
-private:
- const Context &c;
- const std::string &name;
-};
-
-Value Context::evaluate_function(const std::string &name,
- const std::vector<std::string> &argnames,
- const std::vector<Value> &argvalues) const
+Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const
{
- RecursionGuard g(*this, name);
- if (g.recursion_detected()) {
- PRINTB("Recursion detected calling function '%s'", name);
- return Value();
- }
- if (this->functions_p && this->functions_p->find(name) != this->functions_p->end())
- return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues);
- if (this->usedlibs_p) {
- BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
- if (m.second->functions.find(name) != m.second->functions.end()) {
- Context ctx(this->parent, m.second);
- return m.second->functions[name]->evaluate(&ctx, argnames, argvalues);
- }
- }
- }
- if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues);
+ if (this->parent) return this->parent->evaluate_function(name, evalctx);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
-AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const
+AbstractNode *Context::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
{
- if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) {
- AbstractModule *m = this->modules_p->find(inst.name())->second;
- std::string replacement = Builtins::instance()->isDeprecated(inst.name());
- if (!replacement.empty()) {
- PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement);
- }
- return m->evaluate(this, &inst);
- }
- if (this->usedlibs_p) {
- BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
- assert(m.second);
- if (m.second->modules.find(inst.name()) != m.second->modules.end()) {
- Context ctx(this->parent, m.second);
- return m.second->modules[inst.name()]->evaluate(&ctx, &inst);
- }
- }
- }
- if (this->parent) return this->parent->evaluate_module(inst);
+ if (this->parent) return this->parent->instantiate_module(inst, evalctx);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());
return NULL;
}
@@ -202,22 +144,34 @@ std::string Context::getAbsolutePath(const std::string &filename) const
}
}
-void register_builtin(Context &ctx)
+#ifdef DEBUG
+void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
- ctx.functions_p = &Builtins::instance()->functions();
- ctx.modules_p = &Builtins::instance()->modules();
- ctx.set_variable("$fn", Value(0.0));
- ctx.set_variable("$fs", Value(2.0));
- ctx.set_variable("$fa", Value(12.0));
- ctx.set_variable("$t", Value(0.0));
-
- Value::VectorType zero3;
- zero3.push_back(Value(0.0));
- zero3.push_back(Value(0.0));
- zero3.push_back(Value(0.0));
- Value zero3val(zero3);
- ctx.set_variable("$vpt", zero3val);
- ctx.set_variable("$vpr", zero3val);
+ if (inst)
+ PRINTB("ModuleContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst);
+ else
+ PRINTB("Context: %p (%p)", this % this->parent);
+ PRINTB(" document path: %s", this->document_path);
+ if (mod) {
+ const Module *m = dynamic_cast<const Module*>(mod);
+ if (m) {
+ PRINT(" module args:");
+ BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
+ PRINTB(" %s = %s", arg.first % variables[arg.first]);
+ }
+ }
+ }
+ typedef std::pair<std::string, Value> ValueMapType;
+ PRINT(" vars:");
+ BOOST_FOREACH(const ValueMapType &v, constants) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
+ BOOST_FOREACH(const ValueMapType &v, variables) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
+ BOOST_FOREACH(const ValueMapType &v, config_variables) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
- ctx.set_constant("PI",Value(M_PI));
}
+#endif
diff --git a/src/context.h b/src/context.h
index eb9a175..9817df3 100644
--- a/src/context.h
+++ b/src/context.h
@@ -5,48 +5,46 @@
#include <vector>
#include <boost/unordered_map.hpp>
#include "value.h"
+#include "typedefs.h"
class Context
{
public:
- Context(const Context *parent = NULL, const class Module *library = NULL);
- ~Context();
+ Context(const Context *parent = NULL);
+ virtual ~Context();
- void args(const std::vector<std::string> &argnames,
- const std::vector<class Expression*> &argexpr,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues);
+ virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
+ virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const;
+
+ void setVariables(const AssignmentList &args,
+ const class EvalContext *evalctx = NULL);
void set_variable(const std::string &name, const Value &value);
void set_constant(const std::string &name, const Value &value);
Value lookup_variable(const std::string &name, bool silent = false) const;
- Value evaluate_function(const std::string &name,
- const std::vector<std::string> &argnames,
- const std::vector<Value> &argvalues) const;
- class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const;
void setDocumentPath(const std::string &path) { this->document_path = path; }
+ const std::string &documentPath() const { return this->document_path; }
std::string getAbsolutePath(const std::string &filename) const;
public:
const Context *parent;
- const boost::unordered_map<std::string, class AbstractFunction*> *functions_p;
- const boost::unordered_map<std::string, class AbstractModule*> *modules_p;
- typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
- const ModuleContainer *usedlibs_p;
- const ModuleInstantiation *inst_p;
static std::vector<const Context*> ctx_stack;
- mutable boost::unordered_map<std::string, int> recursioncount;
-
-private:
+protected:
typedef boost::unordered_map<std::string, Value> ValueMap;
ValueMap constants;
ValueMap variables;
ValueMap config_variables;
- std::string document_path;
+
+ std::string document_path; // FIXME: This is a remnant only needed by dxfdim
+
+#ifdef DEBUG
+public:
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
};
#endif
diff --git a/src/control.cc b/src/control.cc
index 44847f5..7786e36 100644
--- a/src/control.cc
+++ b/src/control.cc
@@ -26,7 +26,8 @@
#include "module.h"
#include "node.h"
-#include "context.h"
+#include "evalcontext.h"
+#include "modcontext.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
@@ -45,18 +46,16 @@ class ControlModule : public AbstractModule
public:
control_type_e type;
ControlModule(control_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues,
- const Context *arg_context)
+ const Context *ctx, const EvalContext *evalctx)
{
- if (call_argnames.size() > l) {
- const std::string &it_name = call_argnames[l];
- const Value &it_values = call_argvalues[l];
- Context c(arg_context);
+ if (evalctx->numArgs() > l) {
+ const std::string &it_name = evalctx->getArgName(l);
+ const Value &it_values = evalctx->getArgValue(l, ctx);
+ Context c(ctx);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
if (range.end < range.begin) {
@@ -67,55 +66,69 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
if (range.step > 0 && (range.begin-range.end)/range.step < 10000) {
for (double i = range.begin; i <= range.end; i += range.step) {
c.set_variable(it_name, Value(i));
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
}
}
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]);
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
}
else if (it_values.type() != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
} else if (l > 0) {
- std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context);
- node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst.instantiateChildren(ctx);
+ node.children.insert(node.children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
}
-AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = NULL;
if (type == CHILD)
{
- size_t n = 0;
- if (inst->argvalues.size() > 0) {
+ int n = 0;
+ if (evalctx->numArgs() > 0) {
double v;
- if (inst->argvalues[0].getDouble(v)) {
- if (v < 0) return NULL; // Disallow negative child indices
+ if (evalctx->getArgValue(0).getDouble(v)) {
n = trunc(v);
+ if (n < 0) {
+ PRINTB("WARNING: Negative child index (%d) not allowed", n);
+ return NULL; // Disallow negative child indices
+ }
}
}
- for (int i = Context::ctx_stack.size()-1; i >= 0; i--) {
- const Context *c = Context::ctx_stack[i];
- if (c->inst_p) {
- if (n < c->inst_p->children.size()) {
- node = c->inst_p->children[n]->evaluate(c->inst_p->ctx);
- // FIXME: We'd like to inherit any tags from the ModuleInstantiation
- // given as parameter to this method. However, the instantition which belongs
- // to the returned node cannot be changed. This causes the test
- // features/child-background.scad to fail.
+
+ // Find the last custom module invocation, which will contain
+ // an eval context with the children of the module invokation
+ const Context *tmpc = evalctx;
+ while (tmpc->parent) {
+ const ModuleContext *filectx = dynamic_cast<const ModuleContext*>(tmpc->parent);
+ if (filectx) {
+ // This will trigger if trying to invoke child from the root of any file
+ // assert(filectx->evalctx);
+
+ if (filectx->evalctx) {
+ if (n < filectx->evalctx->numChildren()) {
+ node = filectx->evalctx->getChild(n)->evaluate(filectx->evalctx);
+ }
+ else {
+ // How to deal with negative objects in this case?
+ // (e.g. first child of difference is invalid)
+ PRINTB("WARNING: Child index (%d) out of bounds (%d children)",
+ n % filectx->evalctx->numChildren());
+ }
}
return node;
}
- c = c->parent;
+ tmpc = tmpc->parent;
}
- return NULL;
+ return node;
}
if (type == INT_FOR)
@@ -127,40 +140,40 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation
{
std::stringstream msg;
msg << "ECHO: ";
- for (size_t i = 0; i < inst->argnames.size(); i++) {
+ for (size_t i = 0; i < inst->arguments.size(); i++) {
if (i > 0) msg << ", ";
- if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = ";
- msg << inst->argvalues[i];
+ if (!evalctx->getArgName(i).empty()) msg << evalctx->getArgName(i) << " = ";
+ msg << evalctx->getArgValue(i);
}
PRINTB("%s", msg.str());
}
if (type == ASSIGN)
{
- Context c(inst->ctx);
- for (size_t i = 0; i < inst->argnames.size(); i++) {
- if (!inst->argnames[i].empty())
- c.set_variable(inst->argnames[i], inst->argvalues[i]);
+ Context c(evalctx);
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (!evalctx->getArgName(i).empty())
+ c.set_variable(evalctx->getArgName(i), evalctx->getArgValue(i));
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(&c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
if (type == FOR || type == INT_FOR)
{
- for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx);
+ for_eval(*node, *inst, 0, evalctx, evalctx);
}
if (type == IF)
{
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
- if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) {
- std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) {
+ std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
else {
- std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateElseChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
}
diff --git a/src/csgops.cc b/src/csgops.cc
index 7524559..92b97e7 100644
--- a/src/csgops.cc
+++ b/src/csgops.cc
@@ -26,6 +26,7 @@
#include "csgnode.h"
+#include "evalcontext.h"
#include "module.h"
#include "csgterm.h"
#include "builtin.h"
@@ -37,14 +38,14 @@ class CsgModule : public AbstractModule
public:
csg_type_e type;
CsgModule(csg_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *CsgModule::instantiate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CsgNode *node = new CsgNode(inst, type);
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/dxfdata.cc b/src/dxfdata.cc
index f34af51..8415228 100644
--- a/src/dxfdata.cc
+++ b/src/dxfdata.cc
@@ -41,8 +41,9 @@
#include <sstream>
#include <map>
-#include <QDir>
#include "value.h"
+#include "boost-utils.h"
+#include "boosty.h"
/*! \class DxfData
@@ -389,10 +390,10 @@ DxfData::DxfData(double fn, double fs, double fa,
BOOST_FOREACH(const EntityList::value_type &i, unsupported_entities_list) {
if (layername.empty()) {
PRINTB("WARNING: Unsupported DXF Entity '%s' (%x) in %s.",
- i.first % i.second % QuotedString(QDir::current().relativeFilePath(QString::fromLocal8Bit(filename.c_str())).toLocal8Bit().constData()));
+ i.first % i.second % QuotedString(boosty::stringy(boostfs_uncomplete(filename, fs::current_path()))));
} else {
PRINTB("WARNING: Unsupported DXF Entity '%s' (%x) in layer '%s' of %s.",
- i.first % i.second % layername % QuotedString(QDir::current().relativeFilePath(QString::fromLocal8Bit(filename.c_str())).toLocal8Bit().constData()));
+ i.first % i.second % layername % QuotedString(boosty::stringy(boostfs_uncomplete(filename, fs::current_path()))));
}
}
diff --git a/src/dxfdim.cc b/src/dxfdim.cc
index 1ed37fa..66842d2 100644
--- a/src/dxfdim.cc
+++ b/src/dxfdim.cc
@@ -30,7 +30,8 @@
#include "dxfdata.h"
#include "builtin.h"
#include "printutils.h"
-#include "context.h"
+#include "fileutils.h"
+#include "evalcontext.h"
#include "mathc99.h"
#include <sstream>
@@ -40,7 +41,7 @@ boost::unordered_map<std::string,Value> dxf_dim_cache;
boost::unordered_map<std::string,Value> dxf_cross_cache;
namespace fs = boost::filesystem;
-Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
+Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@@ -49,23 +50,34 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
double yorigin = 0;
double scale = 1;
- for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
- if (argnames[i] == "file")
- filename = ctx->getAbsolutePath(args[i].toString());
- if (argnames[i] == "layer")
- layername = args[i].toString();
- if (argnames[i] == "origin")
- args[i].getVec2(xorigin, yorigin);
- if (argnames[i] == "scale")
- args[i].getDouble(scale);
- if (argnames[i] == "name")
- name = args[i].toString();
+ // FIXME: We don't lookup the file relative to where this function was instantiated
+ // since the path is only available for ModuleInstantiations, not function expressions.
+ // See issue #217
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (evalctx->getArgName(i) == "file")
+ filename = lookup_file(evalctx->getArgValue(i).toString(),
+ evalctx->documentPath(), ctx->documentPath());
+ if (evalctx->getArgName(i) == "layer")
+ layername = evalctx->getArgValue(i).toString();
+ if (evalctx->getArgName(i) == "origin")
+ evalctx->getArgValue(i).getVec2(xorigin, yorigin);
+ if (evalctx->getArgName(i) == "scale")
+ evalctx->getArgValue(i).getDouble(scale);
+ if (evalctx->getArgName(i) == "name")
+ name = evalctx->getArgValue(i).toString();
}
std::stringstream keystream;
+ fs::path filepath(filename);
+ uintmax_t filesize = -1;
+ time_t lastwritetime = -1;
+ if (fs::exists(filepath) && fs::is_regular_file(filepath)) {
+ filesize = fs::file_size(filepath);
+ lastwritetime = fs::last_write_time(filepath);
+ }
keystream << filename << "|" << layername << "|" << name << "|" << xorigin
- << "|" << yorigin <<"|" << scale << "|" << fs::last_write_time(filename)
- << "|" << fs::file_size(filename);
+ << "|" << yorigin <<"|" << scale << "|" << lastwritetime
+ << "|" << filesize;
std::string key = keystream.str();
if (dxf_dim_cache.find(key) != dxf_dim_cache.end())
return dxf_dim_cache.find(key)->second;
@@ -125,7 +137,7 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
return Value();
}
-Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
+Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@@ -133,15 +145,18 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn
double yorigin = 0;
double scale = 1;
- for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
- if (argnames[i] == "file")
- filename = ctx->getAbsolutePath(args[i].toString());
- if (argnames[i] == "layer")
- layername = args[i].toString();
- if (argnames[i] == "origin")
- args[i].getVec2(xorigin, yorigin);
- if (argnames[i] == "scale")
- args[i].getDouble(scale);
+ // FIXME: We don't lookup the file relative to where this function was instantiated
+ // since the path is only available for ModuleInstantiations, not function expressions.
+ // See isse #217
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (evalctx->getArgName(i) == "file")
+ filename = ctx->getAbsolutePath(evalctx->getArgValue(i).toString());
+ if (evalctx->getArgName(i) == "layer")
+ layername = evalctx->getArgValue(i).toString();
+ if (evalctx->getArgName(i) == "origin")
+ evalctx->getArgValue(i).getVec2(xorigin, yorigin);
+ if (evalctx->getArgName(i) == "scale")
+ evalctx->getArgValue(i).getDouble(scale);
}
std::stringstream keystream;
diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc
index 0197473..16eaf9f 100644
--- a/src/dxftess-cgal.cc
+++ b/src/dxftess-cgal.cc
@@ -101,7 +101,7 @@ void mark_inner_outer(std::vector<struct triangle> &tri, Grid2d<point_info_t> &p
}
}
-void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_triangle_splitting */, double h)
+void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool /* do_triangle_splitting */, double h)
{
CDT cdt;
@@ -314,8 +314,8 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr
int idx = up ? j : (2-j);
double px = tri[i].p[idx].x;
double py = tri[i].p[idx].y;
- ps->append_vertex(px * cos(rot*M_PI/180) + py * sin(rot*M_PI/180),
- px * -sin(rot*M_PI/180) + py * cos(rot*M_PI/180), h);
+ ps->append_vertex(scale[0] * (px * cos(rot*M_PI/180) + py * sin(rot*M_PI/180)),
+ scale[1] * (px * -sin(rot*M_PI/180) + py * cos(rot*M_PI/180)), h);
path[j] = point_info.data(px, py).pathidx;
point[j] = point_info.data(px, py).pointidx;
}
diff --git a/src/dxftess-glu.cc b/src/dxftess-glu.cc
index 1a8bfa5..89999c3 100644
--- a/src/dxftess-glu.cc
+++ b/src/dxftess-glu.cc
@@ -3,14 +3,11 @@
#include "polyset.h"
#include "grid.h"
#include <stdio.h>
+#include <boost/foreach.hpp>
#include "system-gl.h"
#include "mathc99.h"
-#include <QVector>
-#include <QPair>
-#include <QHash>
-
#ifdef WIN32
# define STDCALL __stdcall
#else
@@ -31,7 +28,7 @@ struct tess_triangle {
static GLenum tess_type;
static int tess_count;
-static QVector<tess_triangle> tess_tri;
+static std::vector<tess_triangle> tess_tri;
static GLdouble *tess_p1, *tess_p2;
static void STDCALL tess_vertex(void *vertex_data)
@@ -48,7 +45,7 @@ static void STDCALL tess_vertex(void *vertex_data)
tess_p2 = p;
}
if (tess_count > 1) {
- tess_tri.append(tess_triangle(tess_p1, tess_p2, p));
+ tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
tess_p2 = p;
}
}
@@ -61,9 +58,9 @@ static void STDCALL tess_vertex(void *vertex_data)
}
if (tess_count > 1) {
if (tess_count % 2 == 1) {
- tess_tri.append(tess_triangle(tess_p2, tess_p1, p));
+ tess_tri.push_back(tess_triangle(tess_p2, tess_p1, p));
} else {
- tess_tri.append(tess_triangle(tess_p1, tess_p2, p));
+ tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
}
tess_p1 = tess_p2;
tess_p2 = p;
@@ -77,7 +74,7 @@ static void STDCALL tess_vertex(void *vertex_data)
tess_p2 = p;
}
if (tess_count == 2) {
- tess_tri.append(tess_triangle(tess_p1, tess_p2, p));
+ tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
tess_count = -1;
}
}
@@ -188,12 +185,23 @@ static bool point_on_line(double *p1, double *p2, double *p3)
return true;
}
+typedef std::pair<int,int> pair_ii;
+inline void do_emplace( boost::unordered_multimap<int, pair_ii> &tri_by_atan2, int ai, const pair_ii &indexes)
+{
+#if BOOST_VERSION >= 104800
+ tri_by_atan2.emplace(ai, indexes);
+#else
+ std::pair< int, pair_ii > tmp( ai, indexes );
+ tri_by_atan2.insert( tmp );
+#endif
+}
+
/*!
up: true if the polygon is facing in the normal direction (i.e. normal = [0,0,1])
rot: CLOCKWISE rotation around positive Z axis
*/
-void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_triangle_splitting, double h)
+void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h)
{
GLUtesselator *tobj = gluNewTess();
@@ -214,7 +222,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
tess_tri.clear();
- QList<tess_vdata> vl;
+ std::list<tess_vdata> vl;
gluTessBeginPolygon(tobj, NULL);
@@ -225,7 +233,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
gluTessNormal(tobj, 0, 0, +1);
}
- Grid3d< QPair<int,int> > point_to_path(GRID_COARSE);
+ Grid3d< std::pair<int,int> > point_to_path(GRID_COARSE);
for (int i = 0; i < dxf.paths.size(); i++) {
if (!dxf.paths[i].is_closed)
@@ -234,12 +242,12 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
for (int j = 1; j < dxf.paths[i].indices.size(); j++) {
point_to_path.data(dxf.points[dxf.paths[i].indices[j]][0],
dxf.points[dxf.paths[i].indices[j]][1],
- h) = QPair<int,int>(i, j);
- vl.append(tess_vdata());
- vl.last().v[0] = dxf.points[dxf.paths[i].indices[j]][0];
- vl.last().v[1] = dxf.points[dxf.paths[i].indices[j]][1];
- vl.last().v[2] = h;
- gluTessVertex(tobj, vl.last().v, vl.last().v);
+ h) = std::pair<int,int>(i, j);
+ vl.push_back(tess_vdata());
+ vl.back().v[0] = scale[0] * dxf.points[dxf.paths[i].indices[j]][0];
+ vl.back().v[1] = scale[1] * dxf.points[dxf.paths[i].indices[j]][1];
+ vl.back().v[2] = h;
+ gluTessVertex(tobj, vl.back().v, vl.back().v);
}
gluTessEndContour(tobj);
}
@@ -263,7 +271,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) ||
point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) {
// printf("DEBUG: Removed triangle\n");
- tess_tri.remove(i--);
+ tess_tri.erase(tess_tri.begin() + i--);
}
}
@@ -277,13 +285,13 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
if (do_triangle_splitting)
{
bool added_triangles = true;
- typedef QPair<int,int> QPair_ii;
- QHash<int, QPair_ii> tri_by_atan2;
+ typedef std::pair<int,int> pair_ii;
+ boost::unordered_multimap<int, pair_ii> tri_by_atan2;
for (int i = 0; i < tess_tri.size(); i++)
for (int j = 0; j < 3; j++) {
int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]),
fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001);
- tri_by_atan2.insertMulti(ai, QPair<int,int>(i, j));
+ do_emplace( tri_by_atan2, ai, std::pair<int,int>(i, j) );
}
while (added_triangles)
{
@@ -294,20 +302,23 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
for (int i = 0; i < tess_tri.size(); i++)
for (int k = 0; k < 3; k++)
{
- QHash<QPair_ii, QPair_ii> possible_neigh;
+ boost::unordered_map<pair_ii, pair_ii> possible_neigh;
int ai = (int)floor(atan2(fabs(tess_tri[i].p[(k+1)%3][0] - tess_tri[i].p[k][0]),
fabs(tess_tri[i].p[(k+1)%3][1] - tess_tri[i].p[k][1])) / 0.001 - 0.5);
for (int j = 0; j < 2; j++) {
- foreach (const QPair_ii &jl, tri_by_atan2.values(ai+j))
- if (i != jl.first)
- possible_neigh[jl] = jl;
+ for (boost::unordered_multimap<int, pair_ii>::iterator it = tri_by_atan2.find(ai+j);
+ it != tri_by_atan2.end();
+ it++) {
+ if (i != it->first) possible_neigh[it->second] = it->second;
+ }
}
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("%d/%d: %d\n", i, k, possible_neigh.size());
#endif
- foreach (const QPair_ii &jl, possible_neigh) {
- int j = jl.first;
- for (int l = jl.second; l != (jl.second + 2) % 3; l = (l + 1) % 3)
+ typedef std::pair<pair_ii,pair_ii> ElemPair;
+ BOOST_FOREACH (const ElemPair &elem, possible_neigh) {
+ int j = elem.first.first;
+ for (int l = elem.first.second; l != (elem.first.second + 2) % 3; l = (l + 1) % 3)
if (point_on_line(tess_tri[i].p[k], tess_tri[j].p[l], tess_tri[i].p[(k+1)%3])) {
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("%% %f %f %f %f %f %f [%d %d]\n",
@@ -316,18 +327,18 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_trian
tess_tri[i].p[(k+1)%3][0], tess_tri[i].p[(k+1)%3][1],
i, j);
#endif
- tess_tri.append(tess_triangle(tess_tri[j].p[l],
+ tess_tri.push_back(tess_triangle(tess_tri[j].p[l],
tess_tri[i].p[(k+1)%3], tess_tri[i].p[(k+2)%3]));
for (int m = 0; m < 2; m++) {
- int ai = (int)round(atan2(fabs(tess_tri.last().p[(m+1)%3][0] - tess_tri.last().p[m][0]),
- fabs(tess_tri.last().p[(m+1)%3][1] - tess_tri.last().p[m][1])) / 0.001 );
- tri_by_atan2.insertMulti(ai, QPair<int,int>(tess_tri.size()-1, m));
+ int ai = (int)round(atan2(fabs(tess_tri.back().p[(m+1)%3][0] - tess_tri.back().p[m][0]),
+ fabs(tess_tri.back().p[(m+1)%3][1] - tess_tri.back().p[m][1])) / 0.001 );
+ do_emplace(tri_by_atan2, ai, std::pair<int,int>(tess_tri.size()-1, m));
}
tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l];
for (int m = 0; m < 2; m++) {
int ai = (int)round(atan2(fabs(tess_tri[i].p[(m+1)%3][0] - tess_tri[i].p[m][0]),
fabs(tess_tri[i].p[(m+1)%3][1] - tess_tri[i].p[m][1])) / 0.001 );
- tri_by_atan2.insertMulti(ai, QPair<int,int>(i, m));
+ do_emplace(tri_by_atan2, ai, std::pair<int,int>(i, m));
}
added_triangles = true;
}
diff --git a/src/dxftess.h b/src/dxftess.h
index d3af36e..f0f27b5 100644
--- a/src/dxftess.h
+++ b/src/dxftess.h
@@ -1,9 +1,11 @@
#ifndef DXFTESS_H_
#define DXFTESS_H_
+#include "linalg.h"
+
class DxfData;
class PolySet;
-void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_triangle_splitting, double h);
+void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h);
void dxf_border_to_ps(PolySet *ps, const DxfData &dxf);
#endif
diff --git a/src/evalcontext.cc b/src/evalcontext.cc
new file mode 100644
index 0000000..57c206f
--- /dev/null
+++ b/src/evalcontext.cc
@@ -0,0 +1,64 @@
+#include "evalcontext.h"
+#include "module.h"
+#include "expression.h"
+#include "function.h"
+#include "printutils.h"
+#include "builtin.h"
+#include "localscope.h"
+
+#include <boost/foreach.hpp>
+
+const std::string &EvalContext::getArgName(size_t i) const
+{
+ assert(i < this->eval_arguments.size());
+ return this->eval_arguments[i].first;
+}
+
+Value EvalContext::getArgValue(size_t i, const Context *ctx) const
+{
+ assert(i < this->eval_arguments.size());
+ const Assignment &arg = this->eval_arguments[i];
+ return arg.second ? arg.second->evaluate(ctx ? ctx : this) : Value();
+}
+
+size_t EvalContext::numChildren() const
+{
+ return this->scope ? this->scope->children.size() : 0;
+}
+
+ModuleInstantiation *EvalContext::getChild(size_t i) const
+{
+ return this->scope ? this->scope->children[i] : NULL;
+}
+
+#ifdef DEBUG
+void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
+{
+ if (inst)
+ PRINTB("EvalContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst);
+ else
+ PRINTB("Context: %p (%p)", this % this->parent);
+ PRINTB(" document path: %s", this->document_path);
+
+ PRINT(" eval args:");
+ for (int i=0;i<this->eval_arguments.size();i++) {
+ PRINTB(" %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second);
+ }
+ if (this->scope && this->scope->children.size() > 0) {
+ PRINT(" children:");
+ BOOST_FOREACH(const ModuleInstantiation *ch, this->scope->children) {
+ PRINTB(" %s", ch->name());
+ }
+ }
+
+ if (mod) {
+ const Module *m = dynamic_cast<const Module*>(mod);
+ if (m) {
+ PRINT(" module args:");
+ BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
+ PRINTB(" %s = %s", arg.first % variables[arg.first]);
+ }
+ }
+ }
+}
+#endif
diff --git a/src/evalcontext.h b/src/evalcontext.h
new file mode 100644
index 0000000..34f339a
--- /dev/null
+++ b/src/evalcontext.h
@@ -0,0 +1,37 @@
+#ifndef EVALCONTEXT_H_
+#define EVALCONTEXT_H_
+
+#include "context.h"
+
+/*!
+ This hold the evaluation context (the parameters actually sent
+ when calling a module or function, including the children).
+*/
+class EvalContext : public Context
+{
+public:
+ typedef std::vector<class ModuleInstantiation *> InstanceList;
+
+ EvalContext(const Context *parent,
+ const AssignmentList &args, const class LocalScope *const scope = NULL)
+ : Context(parent), eval_arguments(args), scope(scope) {}
+ virtual ~EvalContext() {}
+
+ size_t numArgs() const { return this->eval_arguments.size(); }
+ const std::string &getArgName(size_t i) const;
+ Value getArgValue(size_t i, const Context *ctx = NULL) const;
+
+ size_t numChildren() const;
+ ModuleInstantiation *getChild(size_t i) const;
+
+#ifdef DEBUG
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
+
+private:
+ const AssignmentList &eval_arguments;
+ std::vector<std::pair<std::string, Value> > eval_values;
+ const LocalScope *const scope;
+};
+
+#endif
diff --git a/src/expr.cc b/src/expr.cc
index 75fc47a..4355400 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -26,19 +26,34 @@
#include "expression.h"
#include "value.h"
-#include "context.h"
+#include "evalcontext.h"
#include <assert.h>
#include <sstream>
#include <algorithm>
#include "stl-utils.h"
+#include "printutils.h"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
-Expression::Expression()
+Expression::Expression() : recursioncount(0)
{
}
-Expression::Expression(const Value &val) : const_value(val), type("C")
+Expression::Expression(const std::string &type,
+ Expression *left, Expression *right)
+ : type(type), recursioncount(0)
+{
+ this->children.push_back(left);
+ this->children.push_back(right);
+}
+
+Expression::Expression(const std::string &type, Expression *expr)
+ : type(type), recursioncount(0)
+{
+ this->children.push_back(expr);
+}
+
+Expression::Expression(const Value &val) : const_value(val), type("C"), recursioncount(0)
{
}
@@ -47,6 +62,18 @@ Expression::~Expression()
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
}
+class FuncRecursionGuard
+{
+public:
+ FuncRecursionGuard(const Expression &e) : expr(e) {
+ expr.recursioncount++;
+ }
+ ~FuncRecursionGuard() { expr.recursioncount--; }
+ bool recursion_detected() const { return (expr.recursioncount > 100); }
+private:
+ const Expression &expr;
+};
+
Value Expression::evaluate(const Context *context) const
{
if (this->type == "!")
@@ -127,13 +154,14 @@ Value Expression::evaluate(const Context *context) const
return Value();
}
if (this->type == "F") {
- Value::VectorType argvalues;
- std::transform(this->children.begin(), this->children.end(),
- std::back_inserter(argvalues),
- boost::bind(&Expression::evaluate, _1, context));
- // for (size_t i=0; i < this->children.size(); i++)
- // argvalues.push_back(this->children[i]->evaluate(context));
- return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues);
+ FuncRecursionGuard g(*this);
+ if (g.recursion_detected()) {
+ PRINTB("ERROR: Recursion detected calling function '%s'", this->call_funcname);
+ return Value();
+ }
+
+ EvalContext c(context, this->call_arguments);
+ return context->evaluate_function(this->call_funcname, &c);
}
abort();
}
@@ -178,10 +206,11 @@ std::string Expression::toString() const
}
else if (this->type == "F") {
stream << this->call_funcname << "(";
- for (size_t i=0; i < this->children.size(); i++) {
+ for (size_t i=0; i < this->call_arguments.size(); i++) {
+ const Assignment &arg = this->call_arguments[i];
if (i > 0) stream << ", ";
- if (!this->call_argnames[i].empty()) stream << this->call_argnames[i] << " = ";
- stream << *this->children[i];
+ if (!arg.first.empty()) stream << arg.first << " = ";
+ stream << *arg.second;
}
stream << ")";
}
diff --git a/src/expression.h b/src/expression.h
index 2919b78..3629704 100644
--- a/src/expression.h
+++ b/src/expression.h
@@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include "value.h"
+#include "typedefs.h"
class Expression
{
@@ -14,7 +15,7 @@ public:
std::string var_name;
std::string call_funcname;
- std::vector<std::string> call_argnames;
+ AssignmentList call_arguments;
// Boolean: ! && ||
// Operators: * / % + -
@@ -33,10 +34,14 @@ public:
Expression();
Expression(const Value &val);
+ Expression(const std::string &type, Expression *left, Expression *right);
+ Expression(const std::string &type, Expression *expr);
~Expression();
Value evaluate(const class Context *context) const;
std::string toString() const;
+
+ mutable int recursioncount;
};
std::ostream &operator<<(std::ostream &stream, const Expression &expr);
diff --git a/src/fileutils.cc b/src/fileutils.cc
new file mode 100644
index 0000000..b844b4a
--- /dev/null
+++ b/src/fileutils.cc
@@ -0,0 +1,35 @@
+#include "fileutils.h"
+#include "printutils.h"
+
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#include "boosty.h"
+
+/*!
+ Returns the absolute path to the given filename, unless it's empty.
+ If the file isn't found in the given path, the fallback path will be
+ used to be backwards compatible with <= 2013.01 (see issue #217).
+*/
+std::string lookup_file(const std::string &filename,
+ const std::string &path, const std::string &fallbackpath)
+{
+ std::string resultfile;
+ if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) {
+ fs::path absfile;
+ if (!path.empty()) absfile = boosty::absolute(fs::path(path) / filename);
+ fs::path absfile_fallback;
+ if (!fallbackpath.empty()) absfile_fallback = boosty::absolute(fs::path(fallbackpath) / filename);
+
+ if (!fs::exists(absfile) && fs::exists(absfile_fallback)) {
+ resultfile = absfile_fallback.string();
+ PRINTB("WARNING: Imported file (%s) found in document root instead of relative to the importing module. This behavior is deprecated", filename);
+ }
+ else {
+ resultfile = absfile.string();
+ }
+ }
+ else {
+ resultfile = filename;
+ }
+ return resultfile;
+}
diff --git a/src/fileutils.h b/src/fileutils.h
new file mode 100644
index 0000000..1f68cdb
--- /dev/null
+++ b/src/fileutils.h
@@ -0,0 +1,9 @@
+#ifndef FILEUTILS_H_
+#define FILEUTILS_H_
+
+#include <string>
+
+std::string lookup_file(const std::string &filename,
+ const std::string &path, const std::string &fallbackpath);
+
+#endif
diff --git a/src/func.cc b/src/func.cc
index 791e957..18884b8 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -26,7 +26,7 @@
#include "function.h"
#include "expression.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include <sstream>
#include <ctime>
@@ -34,6 +34,7 @@
#include <algorithm>
#include "stl-utils.h"
#include "printutils.h"
+#include <boost/foreach.hpp>
/*
Random numbers
@@ -61,7 +62,7 @@ AbstractFunction::~AbstractFunction()
{
}
-Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const
+Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const
{
return Value();
}
@@ -75,16 +76,14 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string
Function::~Function()
{
- std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>());
+ BOOST_FOREACH(const Assignment &arg, this->definition_arguments) delete arg.second;
delete expr;
}
-Value Function::evaluate(const Context *ctx,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues) const
+Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
Context c(ctx);
- c.args(argnames, argexpr, call_argnames, call_argvalues);
+ c.setVariables(definition_arguments, evalctx);
return expr ? expr->evaluate(&c) : Value();
}
@@ -92,10 +91,11 @@ std::string Function::dump(const std::string &indent, const std::string &name) c
{
std::stringstream dump;
dump << indent << "function " << name << "(";
- for (size_t i=0; i < argnames.size(); i++) {
+ for (size_t i=0; i < definition_arguments.size(); i++) {
+ const Assignment &arg = definition_arguments[i];
if (i > 0) dump << ", ";
- dump << argnames[i];
- if (argexpr[i]) dump << " = " << *argexpr[i];
+ dump << arg.first;
+ if (arg.second) dump << " = " << *arg.second;
}
dump << ") = " << *expr << ";\n";
return dump.str();
@@ -105,9 +105,9 @@ BuiltinFunction::~BuiltinFunction()
{
}
-Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const
+Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
- return eval_func(ctx, call_argnames, call_argvalues);
+ return eval_func(ctx, evalctx);
}
std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const
@@ -127,37 +127,37 @@ static inline double rad2deg(double x)
return x * 180.0 / M_PI;
}
-Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_abs(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(fabs(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(fabs(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sign(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value((evalctx->getArgValue(0).toDouble()<0) ? -1.0 : ((evalctx->getArgValue(0).toDouble()>0) ? 1.0 : 0.0));
return Value();
}
-Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_rands(const Context *, const EvalContext *evalctx)
{
bool deterministic = false;
- if (args.size() == 3 &&
- args[0].type() == Value::NUMBER &&
- args[1].type() == Value::NUMBER &&
- args[2].type() == Value::NUMBER)
+ if (evalctx->numArgs() == 3 &&
+ evalctx->getArgValue(0).type() == Value::NUMBER &&
+ evalctx->getArgValue(1).type() == Value::NUMBER &&
+ evalctx->getArgValue(2).type() == Value::NUMBER)
{
deterministic = false;
}
- else if (args.size() == 4 &&
- args[0].type() == Value::NUMBER &&
- args[1].type() == Value::NUMBER &&
- args[2].type() == Value::NUMBER &&
- args[3].type() == Value::NUMBER)
+ else if (evalctx->numArgs() == 4 &&
+ evalctx->getArgValue(0).type() == Value::NUMBER &&
+ evalctx->getArgValue(1).type() == Value::NUMBER &&
+ evalctx->getArgValue(2).type() == Value::NUMBER &&
+ evalctx->getArgValue(3).type() == Value::NUMBER)
{
- deterministic_rng.seed( (unsigned int) args[3].toDouble() );
+ deterministic_rng.seed( (unsigned int) evalctx->getArgValue(3).toDouble() );
deterministic = true;
}
else
@@ -165,11 +165,11 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
return Value();
}
- double min = std::min( args[0].toDouble(), args[1].toDouble() );
- double max = std::max( args[0].toDouble(), args[1].toDouble() );
+ double min = std::min( evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble() );
+ double max = std::max( evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble() );
boost::uniform_real<> distributor( min, max );
Value::VectorType vec;
- for (int i=0; i<args[2].toDouble(); i++) {
+ for (int i=0; i<evalctx->getArgValue(2).toDouble(); i++) {
if ( deterministic ) {
vec.push_back( Value( distributor( deterministic_rng ) ) );
} else {
@@ -181,169 +181,168 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
}
-Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_min(const Context *, const EvalContext *evalctx)
{
- if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
- double val = args[0].toDouble();
- for (size_t i = 1; i < args.size(); i++)
- if (args[1].type() == Value::NUMBER)
- val = fmin(val, args[i].toDouble());
+ if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
+ double val = evalctx->getArgValue(0).toDouble();
+ for (size_t i = 1; i < evalctx->numArgs(); i++)
+ if (evalctx->getArgValue(1).type() == Value::NUMBER)
+ val = fmin(val, evalctx->getArgValue(i).toDouble());
return Value(val);
}
return Value();
}
-Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_max(const Context *, const EvalContext *evalctx)
{
- if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
- double val = args[0].toDouble();
- for (size_t i = 1; i < args.size(); i++)
- if (args[1].type() == Value::NUMBER)
- val = fmax(val, args[i].toDouble());
+ if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
+ double val = evalctx->getArgValue(0).toDouble();
+ for (size_t i = 1; i < evalctx->numArgs(); i++)
+ if (evalctx->getArgValue(1).type() == Value::NUMBER)
+ val = fmax(val, evalctx->getArgValue(i).toDouble());
return Value(val);
}
return Value();
}
-Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sin(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(sin(deg2rad(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(sin(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_cos(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(cos(deg2rad(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(cos(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_asin(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(asin(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(asin(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_acos(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(acos(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(acos(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_tan(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(tan(deg2rad(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(tan(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_atan(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(atan(args[0].toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(atan(evalctx->getArgValue(0).toDouble())));
return Value();
}
-Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_atan2(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble())));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(rad2deg(atan2(evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble())));
return Value();
}
-Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_pow(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(pow(args[0].toDouble(), args[1].toDouble()));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(pow(evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble()));
return Value();
}
-Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_round(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(round(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(round(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_ceil(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(ceil(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(ceil(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_floor(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(floor(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(floor(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sqrt(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(sqrt(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(sqrt(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_exp(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(exp(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(exp(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_length(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1) {
- if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size()));
- if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size()));
+ if (evalctx->numArgs() == 1) {
+ if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size()));
+ if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size()));
}
return Value();
}
-Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_log(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(log(args[1].toDouble()) / log(args[0].toDouble()));
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(log(args[0].toDouble()) / log(10.0));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(1).toDouble()) / log(evalctx->getArgValue(0).toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(0).toDouble()) / log(10.0));
return Value();
}
-Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_ln(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(log(args[0].toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(0).toDouble()));
return Value();
}
-Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_str(const Context *, const EvalContext *evalctx)
{
std::stringstream stream;
- for (size_t i = 0; i < args.size(); i++) {
- stream << args[i].toString();
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ stream << evalctx->getArgValue(i).toString();
}
return Value(stream.str());
}
-Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_lookup(const Context *, const EvalContext *evalctx)
{
double p, low_p, low_v, high_p, high_v;
- if (args.size() < 2 || // Needs two args
- !args[0].getDouble(p) || // First must be a number
- args[1].toVector().size() < 2 || // Second must be a vector of vectors
- args[1].toVector()[0].toVector().size() < 2)
+ if (evalctx->numArgs() < 2 || // Needs two args
+ !evalctx->getArgValue(0).getDouble(p) || // First must be a number
+ evalctx->getArgValue(1).toVector()[0].toVector().size() < 2) // Second must be a vector of vectors
return Value();
- if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v))
+ if (!evalctx->getArgValue(1).toVector()[0].getVec2(low_p, low_v) || !evalctx->getArgValue(1).toVector()[0].getVec2(high_p, high_v))
return Value();
- for (size_t i = 1; i < args[1].toVector().size(); i++) {
+ for (size_t i = 1; i < evalctx->getArgValue(1).toVector().size(); i++) {
double this_p, this_v;
- if (args[1].toVector()[i].getVec2(this_p, this_v)) {
+ if (evalctx->getArgValue(1).toVector()[i].getVec2(this_p, this_v)) {
if (this_p <= p && (this_p > low_p || low_p > p)) {
low_p = this_p;
low_v = this_v;
@@ -355,9 +354,9 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std
}
}
if (p <= low_p)
- return Value(low_v);
- if (p >= high_p)
return Value(high_v);
+ if (p >= high_p)
+ return Value(low_v);
double f = (p-low_p) / (high_p-low_p);
return Value(high_v * f + low_v * (1-f));
}
@@ -404,14 +403,14 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std
- returns [[0,4],[1,5],[2,6],[8]]
*/
-Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_search(const Context *, const EvalContext *evalctx)
{
- if (args.size() < 2) return Value();
+ if (evalctx->numArgs() < 2) return Value();
- const Value &findThis = args[0];
- const Value &searchTable = args[1];
- unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1;
- unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0;
+ const Value &findThis = evalctx->getArgValue(0);
+ const Value &searchTable = evalctx->getArgValue(1);
+ unsigned int num_returns_per_match = (evalctx->numArgs() > 2) ? evalctx->getArgValue(2).toDouble() : 1;
+ unsigned int index_col_num = (evalctx->numArgs() > 3) ? evalctx->getArgValue(3).toDouble() : 0;
Value::VectorType returnvec;
@@ -449,7 +448,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std
if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;
}
}
- if (matchCount == 0) PRINTB(" search term not found: \"%s\"", findThis.toString()[i]);
+ if (matchCount == 0) PRINTB(" WARNING: search term not found: \"%s\"", findThis.toString()[i]);
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
returnvec.push_back(Value(resultvec));
}
@@ -478,10 +477,10 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std
}
if (num_returns_per_match == 1 && matchCount == 0) {
if (findThis.toVector()[i].type() == Value::NUMBER) {
- PRINTB(" search term not found: %s",findThis.toVector()[i].toDouble());
+ PRINTB(" WARNING: search term not found: %s",findThis.toVector()[i].toDouble());
}
else if (findThis.toVector()[i].type() == Value::STRING) {
- PRINTB(" search term not found: \"%s\"",findThis.toVector()[i].toString());
+ PRINTB(" WARNING: search term not found: \"%s\"",findThis.toVector()[i].toString());
}
returnvec.push_back(Value(resultvec));
}
@@ -490,7 +489,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std
}
}
} else {
- PRINTB(" search: none performed on input %s", findThis);
+ PRINTB(" WARNING: search: none performed on input %s", findThis);
return Value();
}
return Value(returnvec);
@@ -499,7 +498,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std
#define QUOTE(x__) # x__
#define QUOTED(x__) QUOTE(x__)
-Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &)
+Value builtin_version(const Context *, const EvalContext *evalctx)
{
Value::VectorType val;
val.push_back(Value(double(OPENSCAD_YEAR)));
@@ -510,9 +509,9 @@ Value builtin_version(const Context *, const std::vector<std::string>&, const st
return Value(val);
}
-Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args)
+Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)
{
- Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0];
+ Value val = (evalctx->numArgs() == 0) ? builtin_version(ctx, evalctx) : evalctx->getArgValue(0);
double y, m, d = 0;
if (!val.getVec3(y, m, d)) {
if (!val.getVec2(y, m)) {
diff --git a/src/function.h b/src/function.h
index 623ef7e..a1fde3c 100644
--- a/src/function.h
+++ b/src/function.h
@@ -2,6 +2,7 @@
#define FUNCTION_H_
#include "value.h"
+#include "typedefs.h"
#include <string>
#include <vector>
@@ -9,35 +10,34 @@ class AbstractFunction
{
public:
virtual ~AbstractFunction();
- virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class BuiltinFunction : public AbstractFunction
{
public:
- typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args);
+ typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);
eval_func_t eval_func;
BuiltinFunction(eval_func_t f) : eval_func(f) { }
virtual ~BuiltinFunction();
- virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class Function : public AbstractFunction
{
public:
- std::vector<std::string> argnames;
- std::vector<class Expression*> argexpr;
+ AssignmentList definition_arguments;
Expression *expr;
Function() { }
virtual ~Function();
- virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
diff --git a/src/highlighter.cc b/src/highlighter.cc
index 391e3a5..bf80bb4 100644
--- a/src/highlighter.cc
+++ b/src/highlighter.cc
@@ -151,7 +151,7 @@ Highlighter::Highlighter(QTextDocument *parent)
tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross";
typeformats["import"].setForeground(Qt::darkYellow);
- tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb";
+ tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr";
typeformats["special"].setForeground(Qt::darkGreen);
tokentypes["extrude"] << "linear_extrude" << "rotate_extrude";
diff --git a/src/import.cc b/src/import.cc
index 32d4fed..2180684 100644
--- a/src/import.cc
+++ b/src/import.cc
@@ -28,11 +28,12 @@
#include "module.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "printutils.h"
+#include "fileutils.h"
#include "handle_dep.h" // handle_dep()
#ifdef ENABLE_CGAL
@@ -60,27 +61,44 @@ class ImportModule : public AbstractModule
public:
import_type_e type;
ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
- std::vector<std::string> argnames;
- argnames += "file", "layer", "convexity", "origin", "scale";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL);
+ args += Assignment("filename",NULL), Assignment("layername", NULL);
+ // FIXME: This is broken. Tag as deprecated and fix
// Map old argnames to new argnames for compatibility
+ // To fix:
+ // o after c.setVariables()
+ // - if "filename" in evalctx: deprecated-warning && v.set_variable("file", value);
+ // - if "layername" in evalctx: deprecated-warning && v.set_variable("layer", value);
+#if 0
std::vector<std::string> inst_argnames = inst->argnames;
for (size_t i=0; i<inst_argnames.size(); i++) {
if (inst_argnames[i] == "filename") inst_argnames[i] = "file";
if (inst_argnames[i] == "layername") inst_argnames[i] = "layer";
}
+#endif
Context c(ctx);
- c.args(argnames, argexpr, inst_argnames, inst->argvalues);
+ c.setDocumentPath(evalctx->documentPath());
+ c.setVariables(args, evalctx);
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
Value v = c.lookup_variable("file");
- std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString());
+ if (v.isUndefined()) {
+ v = c.lookup_variable("filename");
+ if (!v.isUndefined()) {
+ PRINT("DEPRECATED: filename= is deprecated. Please use file=");
+ }
+ }
+ std::string filename = lookup_file(v.isUndefined() ? "" : v.toString(), inst->path(), ctx->documentPath());
import_type_e actualtype = this->type;
if (actualtype == TYPE_UNKNOWN) {
std::string extraw = boosty::extension_str( fs::path(filename) );
@@ -98,6 +116,12 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
node->filename = filename;
Value layerval = c.lookup_variable("layer", true);
+ if (layerval.isUndefined()) {
+ layerval = c.lookup_variable("layername");
+ if (!layerval.isUndefined()) {
+ PRINT("DEPRECATED: layername= is deprecated. Please use layer=");
+ }
+ }
node->layername = layerval.isUndefined() ? "" : layerval.toString();
node->convexity = c.lookup_variable("convexity", true).toDouble();
@@ -251,10 +275,15 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const
#ifdef ENABLE_CGAL
CGAL_Polyhedron poly;
std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary);
- file >> poly;
- file.close();
-
- p = createPolySetFromPolyhedron(poly);
+ if (!file.good()) {
+ PRINTB("WARNING: Can't open import file '%s'.", this->filename);
+ }
+ else {
+ file >> poly;
+ file.close();
+
+ p = createPolySetFromPolyhedron(poly);
+ }
#else
PRINT("WARNING: OFF import requires CGAL.");
#endif
@@ -265,7 +294,7 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const
p = new PolySet();
DxfData dd(this->fn, this->fs, this->fa, this->filename, this->layername, this->origin_x, this->origin_y, this->scale);
p->is2d = true;
- dxf_tesselate(p, dd, 0, true, false, 0);
+ dxf_tesselate(p, dd, 0, Vector2d(1,1), true, false, 0);
dxf_border_to_ps(p, dd);
}
else
diff --git a/src/lexer.l b/src/lexer.l
index 4dff654..6dfe9bc 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -26,6 +26,7 @@
%{
+#include "typedefs.h"
#include "handle_dep.h"
#include "printutils.h"
#include "parsersettings.h"
@@ -54,7 +55,7 @@ static void yyunput(int, char*) __attribute__((unused));
#endif
extern const char *parser_input_buffer;
extern std::string parser_source_path;
-extern Module *currmodule;
+extern FileModule *rootmodule;
#define YY_INPUT(buf,result,max_size) { \
if (yyin && yyin != stdin) { \
@@ -247,7 +248,7 @@ void includefile()
path_stack.push_back(finfo.parent_path());
handle_dep(fullname);
- currmodule->registerInclude(fullname);
+ rootmodule->registerInclude(fullname);
yyin = fopen(fullname.c_str(), "r");
if (!yyin) {
PRINTB("WARNING: Can't open 'include' file '%s'.", filename);
diff --git a/src/linearextrude.cc b/src/linearextrude.cc
index 43db907..9a7365b 100644
--- a/src/linearextrude.cc
+++ b/src/linearextrude.cc
@@ -27,8 +27,9 @@
#include "linearextrudenode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
+#include "fileutils.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
#include "openscad.h" // get_fragments_from_r()
@@ -45,19 +46,18 @@ class LinearExtrudeModule : public AbstractModule
{
public:
LinearExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
LinearExtrudeNode *node = new LinearExtrudeNode(inst);
- std::vector<std::string> argnames;
- argnames += "file", "layer", "height", "origin", "scale", "center", "twist", "slices";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("height", NULL), Assignment("origin", NULL), Assignment("scale", NULL), Assignment("center", NULL), Assignment("twist", NULL), Assignment("slices", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
@@ -73,25 +73,28 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
Value twist = c.lookup_variable("twist", true);
Value slices = c.lookup_variable("slices", true);
- if (!file.isUndefined()) {
+ if (!file.isUndefined() && file.type() == Value::STRING) {
PRINT("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead.");
- node->filename = c.getAbsolutePath(file.toString());
+ node->filename = lookup_file(file.toString(), inst->path(), c.documentPath());
}
// if height not given, and first argument is a number,
// then assume it should be the height.
if (c.lookup_variable("height").isUndefined() &&
- inst->argnames.size() > 0 &&
- inst->argnames[0] == "" &&
- inst->argvalues[0].type() == Value::NUMBER) {
- height = Value(inst->argvalues[0]);
+ evalctx->numArgs() > 0 &&
+ evalctx->getArgName(0) == "" &&
+ evalctx->getArgValue(0).type() == Value::NUMBER) {
+ height = evalctx->getArgValue(0);
}
node->layername = layer.isUndefined() ? "" : layer.toString();
node->height = height.toDouble();
node->convexity = (int)convexity.toDouble();
origin.getVec2(node->origin_x, node->origin_y);
- node->scale = scale.toDouble();
+ node->scale_x = node->scale_y = 1;
+ scale.getDouble(node->scale_x);
+ scale.getDouble(node->scale_y);
+ scale.getVec2(node->scale_x, node->scale_y);
if (center.type() == Value::BOOL)
node->center = center.toBool();
@@ -102,8 +105,8 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
if (node->convexity <= 0)
node->convexity = 1;
- if (node->scale <= 0)
- node->scale = 1;
+ if (node->scale_x < 0) node->scale_x = 0;
+ if (node->scale_y < 0) node->scale_y = 0;
if (twist.type() == Value::NUMBER) {
node->twist = twist.toDouble();
@@ -117,8 +120,8 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
}
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
return node;
@@ -151,7 +154,6 @@ std::string LinearExtrudeNode::toString() const
"file = " << this->filename << ", "
"layer = " << QuotedString(this->layername) << ", "
"origin = [" << this->origin_x << ", " << this->origin_y << "], "
- "scale = " << this->scale << ", "
#ifndef OPENSCAD_TESTING
// timestamp is needed for caching, but disturbs the test framework
<< "timestamp = " << (fs::exists(path) ? fs::last_write_time(path) : 0) << ", "
@@ -166,6 +168,7 @@ std::string LinearExtrudeNode::toString() const
if (this->has_twist) {
stream << ", twist = " << this->twist << ", slices = " << this->slices;
}
+ stream << ", scale = [" << this->scale_x << ", " << this->scale_y << "]";
stream << ", $fn = " << this->fn << ", $fa = " << this->fa << ", $fs = " << this->fs << ")";
return stream.str();
diff --git a/src/linearextrudenode.h b/src/linearextrudenode.h
index 112eccc..6ff8c56 100644
--- a/src/linearextrudenode.h
+++ b/src/linearextrudenode.h
@@ -11,7 +11,8 @@ public:
LinearExtrudeNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi) {
convexity = slices = 0;
fn = fs = fa = height = twist = 0;
- origin_x = origin_y = scale = 0;
+ origin_x = origin_y = 0;
+ scale_x = scale_y = 1;
center = has_twist = false;
}
virtual Response accept(class State &state, Visitor &visitor) const {
@@ -22,7 +23,7 @@ public:
int convexity, slices;
double fn, fs, fa, height, twist;
- double origin_x, origin_y, scale;
+ double origin_x, origin_y, scale_x, scale_y;
bool center, has_twist;
Filename filename;
std::string layername;
diff --git a/src/localscope.cc b/src/localscope.cc
new file mode 100644
index 0000000..eecff91
--- /dev/null
+++ b/src/localscope.cc
@@ -0,0 +1,73 @@
+#include "localscope.h"
+#include "modcontext.h"
+#include "module.h"
+#include "typedefs.h"
+#include "expression.h"
+#include "function.h"
+
+#include <boost/foreach.hpp>
+
+LocalScope::LocalScope()
+{
+}
+
+LocalScope::~LocalScope()
+{
+ BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
+ BOOST_FOREACH (const Assignment &v, assignments) delete v.second;
+ BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;
+ BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;
+}
+
+void LocalScope::addChild(ModuleInstantiation *ch)
+{
+ assert(ch != NULL);
+ this->children.push_back(ch);
+}
+
+std::string LocalScope::dump(const std::string &indent) const
+{
+ std::stringstream dump;
+ BOOST_FOREACH(const FunctionContainer::value_type &f, this->functions) {
+ dump << f.second->dump(indent, f.first);
+ }
+ BOOST_FOREACH(const AbstractModuleContainer::value_type &m, this->modules) {
+ dump << m.second->dump(indent, m.first);
+ }
+ BOOST_FOREACH(const Assignment &ass, this->assignments) {
+ dump << indent << ass.first << " = " << *ass.second << ";\n";
+ }
+ BOOST_FOREACH(const ModuleInstantiation *inst, this->children) {
+ dump << inst->dump(indent);
+ }
+ return dump.str();
+}
+
+// FIXME: Two parameters here is a hack. Rather have separate types of scopes, or check the type of the first parameter. Note const vs. non-const
+std::vector<AbstractNode*> LocalScope::instantiateChildren(const Context *evalctx, FileContext *filectx) const
+{
+ Context *c = filectx;
+
+ if (!c) {
+ c = new Context(evalctx);
+
+ // FIXME: If we make c a ModuleContext, child() doesn't work anymore
+ // c->functions_p = &this->functions;
+ // c->modules_p = &this->modules;
+
+ BOOST_FOREACH (const Assignment &ass, this->assignments) {
+ c->set_variable(ass.first, ass.second->evaluate(c));
+ }
+ }
+
+ std::vector<AbstractNode*> childnodes;
+ BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
+ AbstractNode *node = modinst->evaluate(c);
+ if (node) childnodes.push_back(node);
+ }
+
+ if (c != filectx) delete c;
+
+ return childnodes;
+}
+
diff --git a/src/localscope.h b/src/localscope.h
new file mode 100644
index 0000000..d81a27c
--- /dev/null
+++ b/src/localscope.h
@@ -0,0 +1,26 @@
+#ifndef LOCALSCOPE_H_
+#define LOCALSCOPE_H_
+
+#include "typedefs.h"
+#include <boost/unordered_map.hpp>
+
+class LocalScope
+{
+public:
+ LocalScope();
+ ~LocalScope();
+
+ 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, class FileContext *filectx = NULL) const;
+ void addChild(ModuleInstantiation *ch);
+
+ AssignmentList assignments;
+ ModuleInstantiationList children;
+ typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
+ FunctionContainer functions;
+ typedef boost::unordered_map<std::string, class AbstractModule*> AbstractModuleContainer;
+ AbstractModuleContainer modules;
+};
+
+#endif
diff --git a/src/mainwin.cc b/src/mainwin.cc
index dd855fb..da3501d 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -158,7 +158,7 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int
}
MainWindow::MainWindow(const QString &filename)
- : progresswidget(NULL)
+ : root_inst("group"), progresswidget(NULL)
{
setupUi(this);
@@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename)
this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *)));
#endif
- register_builtin(root_ctx);
+ top_ctx.registerBuiltin();
this->openglbox = NULL;
root_module = NULL;
@@ -488,17 +488,25 @@ void MainWindow::requestOpenFile(const QString &)
void
MainWindow::openFile(const QString &new_filename)
{
+ QString actual_filename = new_filename;
#ifdef ENABLE_MDI
if (!editor->toPlainText().isEmpty()) {
- new MainWindow(new_filename);
+ QFileInfo fi(new_filename);
+ if (fi.suffix().toLower().contains(QRegExp("^(stl|off|dxf)$"))) {
+ actual_filename = QString();
+ }
+ new MainWindow(actual_filename);
clearCurrentOutput();
return;
}
#endif
- setFileName(new_filename);
+ setFileName(actual_filename);
refreshDocument();
updateRecentFiles();
+ if (actual_filename.isEmpty()) {
+ this->editor->setPlainText(QString("import(\"%1\");\n").arg(new_filename));
+ }
}
void
@@ -506,7 +514,7 @@ MainWindow::setFileName(const QString &filename)
{
if (filename.isEmpty()) {
this->fileName.clear();
- this->root_ctx.setDocumentPath(currentdir);
+ this->top_ctx.setDocumentPath(currentdir);
setWindowTitle("OpenSCAD - New Document[*]");
}
else {
@@ -522,7 +530,7 @@ MainWindow::setFileName(const QString &filename)
this->fileName = fileinfo.fileName();
}
- this->root_ctx.setDocumentPath(fileinfo.dir().absolutePath().toLocal8Bit().constData());
+ this->top_ctx.setDocumentPath(fileinfo.dir().absolutePath().toLocal8Bit().constData());
QDir::setCurrent(fileinfo.dir().absolutePath());
}
@@ -643,8 +651,8 @@ bool MainWindow::compile(bool reload, bool procevents)
if (procevents) QApplication::processEvents();
AbstractNode::resetIndexCounter();
- this->root_inst = ModuleInstantiation();
- this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst);
+ this->root_inst = ModuleInstantiation("group");
+ this->absolute_root_node = this->root_module->instantiate(&top_ctx, &this->root_inst, NULL);
if (this->absolute_root_node) {
// Do we have an explicit root node (! modifier)?
@@ -979,19 +987,19 @@ void MainWindow::pasteViewportRotation()
void MainWindow::updateTemporalVariables()
{
- this->root_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
+ this->top_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
Value::VectorType vpt;
vpt.push_back(Value(-qglview->cam.object_trans.x()));
vpt.push_back(Value(-qglview->cam.object_trans.y()));
vpt.push_back(Value(-qglview->cam.object_trans.z()));
- this->root_ctx.set_variable("$vpt", Value(vpt));
+ this->top_ctx.set_variable("$vpt", Value(vpt));
Value::VectorType vpr;
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.x() + 90, 360)));
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.y(), 360)));
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.z(), 360)));
- root_ctx.set_variable("$vpr", Value(vpr));
+ top_ctx.set_variable("$vpr", Value(vpr));
}
bool MainWindow::fileChangedOnDisk()
@@ -1022,7 +1030,7 @@ static bool is_modified(const std::string &filename, const time_t &mtime)
bool MainWindow::includesChanged()
{
if (this->root_module) {
- BOOST_FOREACH(const Module::IncludeContainer::value_type &item, this->root_module->includes) {
+ BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->root_module->includes) {
if (is_modified(item.first, item.second)) return true;
}
}
@@ -1757,6 +1765,12 @@ void MainWindow::helpLibrary()
OPENCSG_VERSION_STRING,
qVersion());
+#if defined( __MINGW64__ )
+ libinfo += QString("Compiled for MingW64\n\n");
+#elif defined( __MINGW32__ )
+ libinfo += QString("Compiled for MingW32\n\n");
+#endif
+
if (!this->openglbox) {
this->openglbox = new QMessageBox(QMessageBox::Information,
"OpenGL Info", "OpenSCAD Detailed Library Info ",
diff --git a/src/modcontext.cc b/src/modcontext.cc
new file mode 100644
index 0000000..3879811
--- /dev/null
+++ b/src/modcontext.cc
@@ -0,0 +1,163 @@
+#include "modcontext.h"
+#include "module.h"
+#include "expression.h"
+#include "function.h"
+#include "printutils.h"
+#include "builtin.h"
+
+#include <boost/foreach.hpp>
+
+ModuleContext::ModuleContext(const Context *parent, const EvalContext *evalctx)
+ : Context(parent), functions_p(NULL), modules_p(NULL), evalctx(evalctx)
+{
+}
+
+ModuleContext::~ModuleContext()
+{
+}
+
+void ModuleContext::initializeModule(const class Module &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;
+ BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
+ this->set_variable(ass.first, ass.second->evaluate(this));
+ }
+}
+
+/*!
+ Only used to initialize builtins for the top-level root context
+*/
+void ModuleContext::registerBuiltin()
+{
+ const LocalScope &scope = Builtins::instance()->getGlobalScope();
+
+ // FIXME: Don't access module members directly
+ this->functions_p = &scope.functions;
+ this->modules_p = &scope.modules;
+ BOOST_FOREACH(const Assignment &ass, scope.assignments) {
+ this->set_variable(ass.first, ass.second->evaluate(this));
+ }
+
+ this->set_constant("PI",Value(M_PI));
+}
+
+const AbstractFunction *ModuleContext::findLocalFunction(const std::string &name) const
+{
+ if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) {
+ return this->functions_p->find(name)->second;
+ }
+ return NULL;
+}
+
+const AbstractModule *ModuleContext::findLocalModule(const std::string &name) const
+{
+ if (this->modules_p && this->modules_p->find(name) != this->modules_p->end()) {
+ AbstractModule *m = this->modules_p->find(name)->second;
+ std::string replacement = Builtins::instance()->isDeprecated(name);
+ if (!replacement.empty()) {
+ PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
+ }
+ return m;
+ }
+ return NULL;
+}
+
+Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
+{
+ const AbstractFunction *foundf = findLocalFunction(name);
+ if (foundf) return foundf->evaluate(this, evalctx);
+
+ return Context::evaluate_function(name, evalctx);
+}
+
+AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+{
+ const AbstractModule *foundm = this->findLocalModule(inst.name());
+ if (foundm) return foundm->instantiate(this, &inst, evalctx);
+
+ return Context::instantiate_module(inst, evalctx);
+}
+
+#ifdef DEBUG
+void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
+{
+ if (inst)
+ PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst);
+ else
+ PRINTB("ModuleContext: %p (%p)", this % this->parent);
+ PRINTB(" document path: %s", this->document_path);
+ if (mod) {
+ const Module *m = dynamic_cast<const Module*>(mod);
+ if (m) {
+ PRINT(" module args:");
+ BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
+ PRINTB(" %s = %s", arg.first % variables[arg.first]);
+ }
+ }
+ }
+ typedef std::pair<std::string, Value> ValueMapType;
+ PRINT(" vars:");
+ BOOST_FOREACH(const ValueMapType &v, constants) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
+ BOOST_FOREACH(const ValueMapType &v, variables) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
+ BOOST_FOREACH(const ValueMapType &v, config_variables) {
+ PRINTB(" %s = %s", v.first % v.second);
+ }
+
+}
+#endif
+
+FileContext::FileContext(const class FileModule &module, const Context *parent)
+ : usedlibs(module.usedlibs), ModuleContext(parent)
+{
+ if (!module.modulePath().empty()) this->document_path = module.modulePath();
+}
+
+Value FileContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
+{
+ const AbstractFunction *foundf = findLocalFunction(name);
+ if (foundf) return foundf->evaluate(this, evalctx);
+
+ BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
+ if (m.second->scope.functions.find(name) != m.second->scope.functions.end()) {
+ FileContext ctx(*m.second, this->parent);
+ ctx.initializeModule(*m.second);
+ // FIXME: Set document path
+#if 0 && DEBUG
+ PRINTB("New lib Context for %s func:", name);
+ ctx.dump(NULL, NULL);
+#endif
+ return m.second->scope.functions[name]->evaluate(&ctx, evalctx);
+ }
+ }
+
+ return ModuleContext::evaluate_function(name, evalctx);
+}
+
+AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+{
+ const AbstractModule *foundm = this->findLocalModule(inst.name());
+ if (foundm) return foundm->instantiate(this, &inst, evalctx);
+
+ BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
+ assert(m.second);
+ if (m.second->scope.modules.find(inst.name()) != m.second->scope.modules.end()) {
+ FileContext ctx(*m.second, this->parent);
+ ctx.initializeModule(*m.second);
+ // FIXME: Set document path
+#if 0 && DEBUG
+ PRINT("New file Context:");
+ ctx.dump(NULL, &inst);
+#endif
+ return m.second->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
+ }
+ }
+
+ return ModuleContext::instantiate_module(inst, evalctx);
+}
diff --git a/src/modcontext.h b/src/modcontext.h
new file mode 100644
index 0000000..0b3e48c
--- /dev/null
+++ b/src/modcontext.h
@@ -0,0 +1,54 @@
+#ifndef FILECONTEXT_H_
+#define FILECONTEXT_H_
+
+#include "context.h"
+#include "module.h"
+#include <boost/unordered_map.hpp>
+
+/*!
+ This holds the context for a Module 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.
+*/
+class ModuleContext : public Context
+{
+public:
+ ModuleContext(const Context *parent = NULL, const EvalContext *evalctx = NULL);
+ virtual ~ModuleContext();
+
+ void initializeModule(const Module &m);
+ void registerBuiltin();
+ virtual Value evaluate_function(const std::string &name,
+ const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
+ const EvalContext *evalctx) const;
+
+ const AbstractModule *findLocalModule(const std::string &name) const;
+ const AbstractFunction *findLocalFunction(const std::string &name) const;
+
+ const LocalScope::FunctionContainer *functions_p;
+ const LocalScope::AbstractModuleContainer *modules_p;
+
+ // FIXME: Points to the eval context for the call to this module. Not sure where it belongs
+ const class EvalContext *evalctx;
+
+#ifdef DEBUG
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
+};
+
+class FileContext : public ModuleContext
+{
+public:
+ FileContext(const class FileModule &module, const Context *parent);
+ virtual ~FileContext() {}
+ virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
+ const EvalContext *evalctx) const;
+
+private:
+ const FileModule::ModuleContainer &usedlibs;
+};
+
+#endif
diff --git a/src/module.cc b/src/module.cc
index e6dcb57..e853457 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -27,11 +27,15 @@
#include "module.h"
#include "ModuleCache.h"
#include "node.h"
-#include "context.h"
+#include "modcontext.h"
+#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "printutils.h"
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#include "boosty.h"
#include <boost/foreach.hpp>
#include <sstream>
#include <sys/stat.h>
@@ -40,11 +44,11 @@ AbstractModule::~AbstractModule()
{
}
-AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = new AbstractNode(inst);
- node->children = inst->evaluateChildren();
+ node->children = inst->instantiateChildren(evalctx);
return node;
}
@@ -58,13 +62,27 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n
ModuleInstantiation::~ModuleInstantiation()
{
- BOOST_FOREACH (Expression *v, argexpr) delete v;
- BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
+ BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second;
}
IfElseModuleInstantiation::~IfElseModuleInstantiation()
{
- BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v;
+}
+
+/*!
+ 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
@@ -72,21 +90,20 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
std::stringstream dump;
dump << indent;
dump << modname + "(";
- for (size_t i=0; i < argnames.size(); i++) {
+ for (size_t i=0; i < this->arguments.size(); i++) {
+ const Assignment &arg = this->arguments[i];
if (i > 0) dump << ", ";
- if (!argnames[i].empty()) dump << argnames[i] << " = ";
- dump << *argexpr[i];
+ if (!arg.first.empty()) dump << arg.first << " = ";
+ dump << *arg.second;
}
- if (children.size() == 0) {
+ if (scope.numElements() == 0) {
dump << ");\n";
- } else if (children.size() == 1) {
+ } else if (scope.numElements() == 1) {
dump << ")\n";
- dump << children[0]->dump(indent + "\t");
+ dump << scope.dump(indent + "\t");
} else {
dump << ") {\n";
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + "\t");
- }
+ scope.dump(indent + "\t");
dump << indent << "}\n";
}
return dump.str();
@@ -94,80 +111,63 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
{
- AbstractNode *node = NULL;
- if (this->ctx) {
- PRINTB("WARNING: Ignoring recursive module instantiation of '%s'.", modname);
- } else {
- // FIXME: Casting away const..
- ModuleInstantiation *that = (ModuleInstantiation*)this;
- that->argvalues.clear();
- BOOST_FOREACH (Expression *expr, that->argexpr) {
- that->argvalues.push_back(expr->evaluate(ctx));
- }
- that->ctx = ctx;
- node = ctx->evaluate_module(*this);
- that->ctx = NULL;
- that->argvalues.clear();
- }
+ 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::evaluateChildren(const Context *ctx) const
+std::vector<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
{
- if (!ctx) ctx = this->ctx;
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
- AbstractNode *node = modinst->evaluate(ctx);
- if (node) childnodes.push_back(node);
- }
- return childnodes;
+ return this->scope.instantiateChildren(evalctx);
}
-std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const
+std::vector<AbstractNode*> IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const
{
- if (!ctx) ctx = this->ctx;
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) {
- AbstractNode *node = modinst->evaluate(ctx);
- if (node != NULL) childnodes.push_back(node);
- }
- return childnodes;
+ return this->else_scope.instantiateChildren(evalctx);
}
Module::~Module()
{
- BOOST_FOREACH (const AssignmentContainer::value_type &v, assignments) delete v.second;
- BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;
- BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;
- BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
}
-AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+class ModRecursionGuard
{
- Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
-
- c.inst_p = inst;
- c.set_variable("$children", Value(double(inst->children.size())));
-
- c.functions_p = &functions;
- c.modules_p = &modules;
-
- if (!usedlibs.empty())
- c.usedlibs_p = &usedlibs;
- else
- c.usedlibs_p = NULL;
+public:
+ ModRecursionGuard(const ModuleInstantiation &inst) : inst(inst) {
+ inst.recursioncount++;
+ }
+ ~ModRecursionGuard() {
+ inst.recursioncount--;
+ }
+ bool recursion_detected() const { return (inst.recursioncount > 100); }
+private:
+ const ModuleInstantiation &inst;
+};
- BOOST_FOREACH(const std::string &var, assignments_var) {
- c.set_variable(var, assignments.at(var)->evaluate(&c));
+AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+{
+ ModRecursionGuard g(*inst);
+ if (g.recursion_detected()) {
+ PRINTB("ERROR: Recursion detected calling module '%s'", inst->name());
+ return NULL;
}
+ ModuleContext c(ctx, evalctx);
+ c.initializeModule(*this);
+ c.set_variable("$children", Value(double(inst->scope.children.size())));
+ // FIXME: Set document path to the path of the module
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
+
AbstractNode *node = new AbstractNode(inst);
- for (size_t i = 0; i < children.size(); i++) {
- AbstractNode *n = children[i]->evaluate(&c);
- if (n != NULL)
- node->children.push_back(n);
- }
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(&c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
@@ -178,33 +178,23 @@ std::string Module::dump(const std::string &indent, const std::string &name) con
std::string tab;
if (!name.empty()) {
dump << indent << "module " << name << "(";
- for (size_t i=0; i < argnames.size(); i++) {
+ for (size_t i=0; i < this->definition_arguments.size(); i++) {
+ const Assignment &arg = this->definition_arguments[i];
if (i > 0) dump << ", ";
- dump << argnames[i];
- if (argexpr[i]) dump << " = " << *argexpr[i];
+ dump << arg.first;
+ if (arg.second) dump << " = " << *arg.second;
}
dump << ") {\n";
tab = "\t";
}
- BOOST_FOREACH(const FunctionContainer::value_type &f, functions) {
- dump << f.second->dump(indent + tab, f.first);
- }
- BOOST_FOREACH(const AbstractModuleContainer::value_type &m, modules) {
- dump << m.second->dump(indent + tab, m.first);
- }
- BOOST_FOREACH(const std::string &var, assignments_var) {
- dump << indent << tab << var << " = " << *assignments.at(var) << ";\n";
- }
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + tab);
- }
+ dump << scope.dump(indent + tab);
if (!name.empty()) {
dump << indent << "}\n";
}
return dump.str();
}
-void Module::registerInclude(const std::string &filename)
+void FileModule::registerInclude(const std::string &filename)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
@@ -216,17 +206,17 @@ void Module::registerInclude(const std::string &filename)
Check if any dependencies have been modified and recompile them.
Returns true if anything was recompiled.
*/
-bool Module::handleDependencies()
+bool FileModule::handleDependencies()
{
if (this->is_handling_dependencies) return false;
this->is_handling_dependencies = true;
bool changed = false;
// Iterating manually since we want to modify the container while iterating
- Module::ModuleContainer::iterator iter = this->usedlibs.begin();
+ FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
- Module::ModuleContainer::iterator curr = iter++;
- Module *oldmodule = curr->second;
+ FileModule::ModuleContainer::iterator curr = iter++;
+ FileModule *oldmodule = curr->second;
curr->second = ModuleCache::instance()->evaluate(curr->first);
if (curr->second != oldmodule) {
changed = true;
@@ -243,3 +233,20 @@ bool Module::handleDependencies()
this->is_handling_dependencies = false;
return changed;
}
+
+AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+{
+ assert(evalctx == NULL);
+ FileContext c(*this, ctx);
+ c.initializeModule(*this);
+ // FIXME: Set document path to the path of the module
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
+
+ AbstractNode *node = new AbstractNode(inst);
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(ctx, &c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
+
+ return node;
+}
diff --git a/src/module.h b/src/module.h
index cc82f81..9f46d37 100644
--- a/src/module.h
+++ b/src/module.h
@@ -6,35 +6,39 @@
#include <list>
#include <boost/unordered_map.hpp>
#include "value.h"
+#include "typedefs.h"
+#include "localscope.h"
class ModuleInstantiation
{
public:
- ModuleInstantiation(const std::string &name = "")
- : ctx(NULL),
- tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }
+ ModuleInstantiation(const std::string &name = "")
+ : tag_root(false), tag_highlight(false), tag_background(false), recursioncount(0), modname(name) { }
virtual ~ModuleInstantiation();
std::string dump(const std::string &indent) const;
class AbstractNode *evaluate(const class Context *ctx) const;
- std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) 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; }
- std::vector<std::string> argnames;
- std::vector<Value> argvalues;
- std::vector<class Expression*> argexpr;
- std::vector<ModuleInstantiation*> children;
- const Context *ctx;
+ AssignmentList arguments;
+ LocalScope scope;
bool tag_root;
bool tag_highlight;
bool tag_background;
+ mutable int recursioncount;
protected:
std::string modname;
+ std::string modpath;
friend class Module;
};
@@ -43,54 +47,55 @@ class IfElseModuleInstantiation : public ModuleInstantiation {
public:
IfElseModuleInstantiation() : ModuleInstantiation("if") { }
virtual ~IfElseModuleInstantiation();
- std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const;
+ std::vector<AbstractNode*> instantiateElseChildren(const Context *evalctx) const;
- std::vector<ModuleInstantiation*> else_children;
+ LocalScope else_scope;
};
class AbstractModule
{
public:
virtual ~AbstractModule();
- virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class Module : public AbstractModule
{
public:
- Module() : is_handling_dependencies(false) { }
+ Module() { }
virtual ~Module();
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
- virtual std::string dump(const std::string &indent, const std::string &name) const;
-
- void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); }
- typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
- ModuleContainer usedlibs;
- void registerInclude(const std::string &filename);
- typedef boost::unordered_map<std::string, time_t> IncludeContainer;
- IncludeContainer includes;
- bool is_handling_dependencies;
- bool handleDependencies();
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
+ virtual std::string dump(const std::string &indent, const std::string &name) const;
- std::list<std::string> assignments_var;
- typedef boost::unordered_map<std::string, Expression*> AssignmentContainer;
- AssignmentContainer assignments;
+ AssignmentList definition_arguments;
- typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
- FunctionContainer functions;
- typedef boost::unordered_map<std::string, AbstractModule*> AbstractModuleContainer;
- AbstractModuleContainer modules;
+ LocalScope scope;
+};
- std::vector<ModuleInstantiation*> children;
+// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really
+// inherit from a Module
+class FileModule : public Module
+{
+public:
+ FileModule() : is_handling_dependencies(false) {}
+ virtual ~FileModule() {}
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
+ void setModulePath(const std::string &path) { this->path = path; }
+ const std::string &modulePath() const { return this->path; }
+ void registerInclude(const std::string &filename);
+ bool handleDependencies();
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
-protected:
+ typedef boost::unordered_map<std::string, class FileModule*> ModuleContainer;
+ ModuleContainer usedlibs;
+ typedef boost::unordered_map<std::string, time_t> IncludeContainer;
+ IncludeContainer includes;
private:
+ bool is_handling_dependencies;
+ std::string path;
};
#endif
diff --git a/src/openscad.cc b/src/openscad.cc
index f7cc48e..7c54762 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -28,7 +28,7 @@
#include "MainWindow.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -327,11 +327,16 @@ int main(int argc, char **argv)
if (!filename) help(argv[0]);
- Context root_ctx;
- register_builtin(root_ctx);
+ // Top context - this context only holds builtins
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
+ PRINT("Root Context:");
+#if 0 && DEBUG
+ top_ctx.dump(NULL, NULL);
+#endif
- Module *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
AbstractNode *absolute_root_node;
CGAL_Nef_polyhedron root_N;
@@ -354,14 +359,14 @@ int main(int argc, char **argv)
fs::path fpath = boosty::absolute(fs::path(filename));
fs::path fparent = fpath.parent_path();
fs::current_path(fparent);
-
+ top_ctx.setDocumentPath(fparent.string());
+
AbstractNode::resetIndexCounter();
- absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ absolute_root_node = root_module->instantiate(&top_ctx, &root_inst, NULL);
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node)))
- root_node = absolute_root_node;
+ root_node = absolute_root_node;
tree.setRoot(root_node);
diff --git a/src/openscad.h b/src/openscad.h
index 8d9a01e..dd379a9 100644
--- a/src/openscad.h
+++ b/src/openscad.h
@@ -27,7 +27,7 @@
#ifndef OPENSCAD_H
#define OPENSCAD_H
-extern class Module *parse(const char *text, const char *path, int debug);
+extern class FileModule *parse(const char *text, const char *path, int debug);
extern int get_fragments_from_r(double r, double fn, double fs, double fa);
#include <string>
diff --git a/src/parser.y b/src/parser.y
index 536f4ef..2b07f14 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -34,6 +34,7 @@
#include <unistd.h>
#endif
+#include "typedefs.h"
#include "module.h"
#include "expression.h"
#include "value.h"
@@ -43,43 +44,38 @@
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
-namespace fs = boost::filesystem;
+ namespace fs = boost::filesystem;
#include "boosty.h"
-int parser_error_pos = -1;
+ int parser_error_pos = -1;
-int parserlex(void);
-void yyerror(char const *s);
+ int parserlex(void);
+ void yyerror(char const *s);
-int lexerget_lineno(void);
-int lexerlex_destroy(void);
-int lexerlex(void);
+ int lexerget_lineno(void);
+ int lexerlex_destroy(void);
+ int lexerlex(void);
-std::vector<Module*> module_stack;
-Module *currmodule;
+ std::stack<LocalScope *> scope_stack;
+ FileModule *rootmodule;
-class ArgContainer {
-public:
- std::string argname;
- Expression *argexpr;
-};
-class ArgsContainer {
-public:
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
-};
+ extern void lexerdestroy();
+ extern FILE *lexerin;
+ extern const char *parser_input_buffer;
+ const char *parser_input_buffer;
+ std::string parser_source_path;
-%}
+ %}
%union {
- char *text;
- double number;
- class Value *value;
- class Expression *expr;
- class ModuleInstantiation *inst;
- class IfElseModuleInstantiation *ifelse;
- class ArgContainer *arg;
- class ArgsContainer *args;
+ char *text;
+ double number;
+ class Value *value;
+ class Expression *expr;
+ class ModuleInstantiation *inst;
+ class IfElseModuleInstantiation *ifelse;
+ Assignment *arg;
+ AssignmentList *args;
}
%token TOK_MODULE
@@ -117,8 +113,6 @@ public:
%type <inst> module_instantiation
%type <ifelse> if_statement
%type <ifelse> ifelse_statement
-%type <inst> children_instantiation
-%type <inst> module_instantiation_list
%type <inst> single_module_instantiation
%type <args> arguments_call
@@ -132,434 +126,342 @@ public:
%%
input:
- /* empty */ |
- TOK_USE { currmodule->usedlibs[$1] = NULL; } input |
- statement input ;
+/* empty */ |
+TOK_USE { rootmodule->usedlibs[$1] = NULL; } input |
+statement input ;
inner_input:
- /* empty */ |
- statement inner_input ;
+/* empty */ |
+statement inner_input ;
+
+assignment:
+TOK_ID '=' expr ';' {
+ for (AssignmentList::iterator iter = scope_stack.top()->assignments.begin();
+ iter != scope_stack.top()->assignments.end();
+ iter++) {
+ if (iter->first == $1) {
+ scope_stack.top()->assignments.erase(iter);
+ break;
+ }
+ }
+ scope_stack.top()->assignments.push_back(Assignment($1, $3));
+} ;
statement:
- ';' |
- '{' inner_input '}' |
- module_instantiation {
- if ($1) {
- currmodule->addChild($1);
- } else {
- delete $1;
- }
- } |
- TOK_ID '=' expr ';' {
- std::list<std::string>::iterator found = std::find(currmodule->assignments_var.begin(), currmodule->assignments_var.end(),$1);
- if (found != currmodule->assignments_var.end()) currmodule->assignments_var.erase(found);
- currmodule->assignments_var.push_back($1);
- currmodule->assignments[$1] = $3;
- } |
- TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' {
- Module *p = currmodule;
- module_stack.push_back(currmodule);
- currmodule = new Module();
- p->modules[$2] = currmodule;
- currmodule->argnames = $4->argnames;
- currmodule->argexpr = $4->argexpr;
- free($2);
- delete $4;
- } statement {
- currmodule = module_stack.back();
- module_stack.pop_back();
- } |
- TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr {
- Function *func = new Function();
- func->argnames = $4->argnames;
- func->argexpr = $4->argexpr;
- func->expr = $8;
- currmodule->functions[$2] = func;
- free($2);
- delete $4;
- } ';' ;
-
-/* Will return a dummy parent node with zero or more children */
-children_instantiation:
- module_instantiation {
- $$ = new ModuleInstantiation();
- if ($1) {
- $$->children.push_back($1);
- }
- } |
- '{' module_instantiation_list '}' {
- $$ = $2;
- } ;
+';' |
+'{' inner_input '}' |
+module_instantiation {
+ if ($1) scope_stack.top()->addChild($1);
+} |
+assignment |
+TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' {
+ Module *newmodule = new Module();
+ newmodule->definition_arguments = *$4;
+ scope_stack.top()->modules[$2] = newmodule;
+ scope_stack.push(&newmodule->scope);
+ free($2);
+ delete $4;
+} statement {
+ scope_stack.pop();
+ } |
+ TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr {
+ Function *func = new Function();
+ func->definition_arguments = *$4;
+ func->expr = $8;
+ scope_stack.top()->functions[$2] = func;
+ free($2);
+ delete $4;
+ } ';' ;
if_statement:
- TOK_IF '(' expr ')' children_instantiation {
- $$ = new IfElseModuleInstantiation();
- $$->argnames.push_back("");
- $$->argexpr.push_back($3);
-
- if ($$) {
- $$->children = $5->children;
- } else {
- for (size_t i = 0; i < $5->children.size(); i++)
- delete $5->children[i];
- }
- $5->children.clear();
- delete $5;
- } ;
+TOK_IF '(' expr ')' {
+ $<ifelse>$ = new IfElseModuleInstantiation();
+ $<ifelse>$->arguments.push_back(Assignment("", $3));
+ $<ifelse>$->setPath(parser_source_path);
+ scope_stack.push(&$<ifelse>$->scope);
+} child_statement {
+ scope_stack.pop();
+ $$ = $<ifelse>5;
+ } ;
ifelse_statement:
- if_statement {
- $$ = $1;
- } |
- if_statement TOK_ELSE children_instantiation {
- $$ = $1;
- if ($$) {
- $$->else_children = $3->children;
- } else {
- for (size_t i = 0; i < $3->children.size(); i++)
- delete $3->children[i];
- }
- $3->children.clear();
- delete $3;
- } ;
+if_statement {
+ $$ = $1;
+} |
+if_statement TOK_ELSE {
+ scope_stack.push(&$1->else_scope);
+} child_statement {
+ scope_stack.pop();
+ $$ = $1;
+ } ;
module_instantiation:
- '!' module_instantiation {
- $$ = $2;
- if ($$) $$->tag_root = true;
- } |
- '#' module_instantiation {
- $$ = $2;
- if ($$) $$->tag_highlight = true;
- } |
- '%' module_instantiation {
- $$ = $2;
- if ($$) $$->tag_background = true;
- } |
- '*' module_instantiation {
- delete $2;
- $$ = NULL;
- } |
- single_module_instantiation ';' {
- $$ = $1;
- } |
- single_module_instantiation children_instantiation {
- $$ = $1;
- if ($$) {
- $$->children = $2->children;
- } else {
- for (size_t i = 0; i < $2->children.size(); i++)
- delete $2->children[i];
- }
- $2->children.clear();
- delete $2;
- } |
- ifelse_statement {
- $$ = $1;
- } ;
-
-module_instantiation_list:
- /* empty */ {
- $$ = new ModuleInstantiation();
- } |
- module_instantiation_list module_instantiation {
- $$ = $1;
- if ($$) {
- if ($2) $$->children.push_back($2);
- } else {
- delete $2;
- }
- } ;
+'!' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_root = true;
+} |
+'#' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_highlight = true;
+} |
+'%' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_background = true;
+} |
+'*' module_instantiation {
+ delete $2;
+ $$ = NULL;
+} |
+single_module_instantiation {
+ $<inst>$ = $1;
+ scope_stack.push(&$1->scope);
+} child_statement {
+ scope_stack.pop();
+ $$ = $<inst>2;
+ } |
+ ifelse_statement {
+ $$ = $1;
+ } ;
+
+child_statement:
+';' |
+'{' child_statements '}' |
+module_instantiation {
+ if ($1) scope_stack.top()->addChild($1);
+} ;
+
+/*
+ FIXME: This allows for variable declaration in child blocks, not activated yet
+ |
+assignment ;
+*/
+
+child_statements:
+/* empty */ |
+child_statements child_statement ;
single_module_instantiation:
- TOK_ID '(' arguments_call ')' {
- $$ = new ModuleInstantiation($1);
- $$->argnames = $3->argnames;
- $$->argexpr = $3->argexpr;
- free($1);
- delete $3;
- }
+TOK_ID '(' arguments_call ')' {
+ $$ = new ModuleInstantiation($1);
+ $$->arguments = *$3;
+ $$->setPath(parser_source_path);
+ free($1);
+ delete $3;
+}
expr:
- TOK_TRUE {
- $$ = new Expression(Value(true));
- } |
- TOK_FALSE {
- $$ = new Expression(Value(false));
- } |
- TOK_UNDEF {
- $$ = new Expression(Value::undefined);
- } |
- TOK_ID {
- $$ = new Expression();
- $$->type = "L";
- $$->var_name = $1;
- free($1);
- } |
- expr '.' TOK_ID {
- $$ = new Expression();
- $$->type = "N";
- $$->children.push_back($1);
- $$->var_name = $3;
- free($3);
- } |
- TOK_STRING {
- $$ = new Expression(Value(std::string($1)));
- free($1);
- } |
- TOK_NUMBER {
- $$ = new Expression(Value($1));
- } |
- '[' expr ':' expr ']' {
- Expression *e_one = new Expression(Value(1.0));
- $$ = new Expression();
- $$->type = "R";
- $$->children.push_back($2);
- $$->children.push_back(e_one);
- $$->children.push_back($4);
- } |
- '[' expr ':' expr ':' expr ']' {
- $$ = new Expression();
- $$->type = "R";
- $$->children.push_back($2);
- $$->children.push_back($4);
- $$->children.push_back($6);
- } |
- '[' optional_commas ']' {
- $$ = new Expression(Value(Value::VectorType()));
- } |
- '[' vector_expr optional_commas ']' {
- $$ = $2;
- } |
- expr '*' expr {
- $$ = new Expression();
- $$->type = "*";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '/' expr {
- $$ = new Expression();
- $$->type = "/";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '%' expr {
- $$ = new Expression();
- $$->type = "%";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '+' expr {
- $$ = new Expression();
- $$->type = "+";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '-' expr {
- $$ = new Expression();
- $$->type = "-";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '<' expr {
- $$ = new Expression();
- $$->type = "<";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr LE expr {
- $$ = new Expression();
- $$->type = "<=";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr EQ expr {
- $$ = new Expression();
- $$->type = "==";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr NE expr {
- $$ = new Expression();
- $$->type = "!=";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr GE expr {
- $$ = new Expression();
- $$->type = ">=";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr '>' expr {
- $$ = new Expression();
- $$->type = ">";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr AND expr {
- $$ = new Expression();
- $$->type = "&&";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- expr OR expr {
- $$ = new Expression();
- $$->type = "||";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- '+' expr {
- $$ = $2;
- } |
- '-' expr {
- $$ = new Expression();
- $$->type = "I";
- $$->children.push_back($2);
- } |
- '!' expr {
- $$ = new Expression();
- $$->type = "!";
- $$->children.push_back($2);
- } |
- '(' expr ')' {
- $$ = $2;
- } |
- expr '?' expr ':' expr {
- $$ = new Expression();
- $$->type = "?:";
- $$->children.push_back($1);
- $$->children.push_back($3);
- $$->children.push_back($5);
- } |
- expr '[' expr ']' {
- $$ = new Expression();
- $$->type = "[]";
- $$->children.push_back($1);
- $$->children.push_back($3);
- } |
- TOK_ID '(' arguments_call ')' {
- $$ = new Expression();
- $$->type = "F";
- $$->call_funcname = $1;
- $$->call_argnames = $3->argnames;
- $$->children = $3->argexpr;
- free($1);
- delete $3;
- } ;
+TOK_TRUE {
+ $$ = new Expression(Value(true));
+} |
+TOK_FALSE {
+ $$ = new Expression(Value(false));
+} |
+TOK_UNDEF {
+ $$ = new Expression(Value::undefined);
+} |
+TOK_ID {
+ $$ = new Expression();
+ $$->type = "L";
+ $$->var_name = $1;
+ free($1);
+} |
+expr '.' TOK_ID {
+ $$ = new Expression("N", $1);
+ $$->var_name = $3;
+ free($3);
+} |
+TOK_STRING {
+ $$ = new Expression(Value(std::string($1)));
+ free($1);
+} |
+TOK_NUMBER {
+ $$ = new Expression(Value($1));
+} |
+'[' expr ':' expr ']' {
+ Expression *e_one = new Expression(Value(1.0));
+ $$ = new Expression();
+ $$->type = "R";
+ $$->children.push_back($2);
+ $$->children.push_back(e_one);
+ $$->children.push_back($4);
+} |
+'[' expr ':' expr ':' expr ']' {
+ $$ = new Expression();
+ $$->type = "R";
+ $$->children.push_back($2);
+ $$->children.push_back($4);
+ $$->children.push_back($6);
+} |
+'[' optional_commas ']' {
+ $$ = new Expression(Value(Value::VectorType()));
+} |
+'[' vector_expr optional_commas ']' {
+ $$ = $2;
+} |
+expr '*' expr {
+ $$ = new Expression("*", $1, $3);
+} |
+expr '/' expr {
+ $$ = new Expression("/", $1, $3);
+} |
+expr '%' expr {
+ $$ = new Expression("%", $1, $3);
+} |
+expr '+' expr {
+ $$ = new Expression("+", $1, $3);
+} |
+expr '-' expr {
+ $$ = new Expression("-", $1, $3);
+} |
+expr '<' expr {
+ $$ = new Expression("<", $1, $3);
+} |
+expr LE expr {
+ $$ = new Expression("<=", $1, $3);
+} |
+expr EQ expr {
+ $$ = new Expression("==", $1, $3);
+} |
+expr NE expr {
+ $$ = new Expression("!=", $1, $3);
+} |
+expr GE expr {
+ $$ = new Expression(">=", $1, $3);
+} |
+expr '>' expr {
+ $$ = new Expression(">", $1, $3);
+} |
+expr AND expr {
+ $$ = new Expression("&&", $1, $3);
+} |
+expr OR expr {
+ $$ = new Expression("||", $1, $3);
+} |
+'+' expr {
+ $$ = $2;
+} |
+'-' expr {
+ $$ = new Expression("I", $2);
+} |
+'!' expr {
+ $$ = new Expression("!", $2);
+} |
+'(' expr ')' {
+ $$ = $2;
+} |
+expr '?' expr ':' expr {
+ $$ = new Expression();
+ $$->type = "?:";
+ $$->children.push_back($1);
+ $$->children.push_back($3);
+ $$->children.push_back($5);
+} |
+expr '[' expr ']' {
+ $$ = new Expression("[]", $1, $3);
+} |
+TOK_ID '(' arguments_call ')' {
+ $$ = new Expression();
+ $$->type = "F";
+ $$->call_funcname = $1;
+ $$->call_arguments = *$3;
+ free($1);
+ delete $3;
+} ;
optional_commas:
- ',' optional_commas | ;
+',' optional_commas | ;
vector_expr:
- expr {
- $$ = new Expression();
- $$->type = 'V';
- $$->children.push_back($1);
- } |
- vector_expr ',' optional_commas expr {
- $$ = $1;
- $$->children.push_back($4);
- } ;
+expr {
+ $$ = new Expression("V", $1);
+} |
+vector_expr ',' optional_commas expr {
+ $$ = $1;
+ $$->children.push_back($4);
+} ;
arguments_decl:
- /* empty */ {
- $$ = new ArgsContainer();
- } |
- argument_decl {
- $$ = new ArgsContainer();
- $$->argnames.push_back($1->argname);
- $$->argexpr.push_back($1->argexpr);
- delete $1;
- } |
- arguments_decl ',' optional_commas argument_decl {
- $$ = $1;
- $$->argnames.push_back($4->argname);
- $$->argexpr.push_back($4->argexpr);
- delete $4;
- } ;
+/* empty */ {
+ $$ = new AssignmentList();
+} |
+argument_decl {
+ $$ = new AssignmentList();
+ $$->push_back(*$1);
+ delete $1;
+} |
+arguments_decl ',' optional_commas argument_decl {
+ $$ = $1;
+ $$->push_back(*$4);
+ delete $4;
+} ;
argument_decl:
- TOK_ID {
- $$ = new ArgContainer();
- $$->argname = $1;
- $$->argexpr = NULL;
- free($1);
- } |
- TOK_ID '=' expr {
- $$ = new ArgContainer();
- $$->argname = $1;
- $$->argexpr = $3;
- free($1);
- } ;
+TOK_ID {
+ $$ = new Assignment($1, NULL);
+ free($1);
+} |
+TOK_ID '=' expr {
+ $$ = new Assignment($1, $3);
+ free($1);
+} ;
arguments_call:
- /* empty */ {
- $$ = new ArgsContainer();
- } |
- argument_call {
- $$ = new ArgsContainer();
- $$->argnames.push_back($1->argname);
- $$->argexpr.push_back($1->argexpr);
- delete $1;
- } |
- arguments_call ',' optional_commas argument_call {
- $$ = $1;
- $$->argnames.push_back($4->argname);
- $$->argexpr.push_back($4->argexpr);
- delete $4;
- } ;
+/* empty */ {
+ $$ = new AssignmentList();
+} |
+argument_call {
+ $$ = new AssignmentList();
+ $$->push_back(*$1);
+ delete $1;
+} |
+arguments_call ',' optional_commas argument_call {
+ $$ = $1;
+ $$->push_back(*$4);
+ delete $4;
+} ;
argument_call:
- expr {
- $$ = new ArgContainer();
- $$->argexpr = $1;
- } |
- TOK_ID '=' expr {
- $$ = new ArgContainer();
- $$->argname = $1;
- $$->argexpr = $3;
- free($1);
- } ;
+expr {
+ $$ = new Assignment("", $1);
+} |
+TOK_ID '=' expr {
+ $$ = new Assignment($1, $3);
+ free($1);
+} ;
%%
int parserlex(void)
{
- return lexerlex();
+ return lexerlex();
}
void yyerror (char const *s)
{
- // FIXME: We leak memory on parser errors...
- PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s);
- currmodule = NULL;
+ // FIXME: We leak memory on parser errors...
+ PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s);
}
-extern void lexerdestroy();
-extern FILE *lexerin;
-extern const char *parser_input_buffer;
-const char *parser_input_buffer;
-std::string parser_source_path;
-
-Module *parse(const char *text, const char *path, int debug)
+FileModule *parse(const char *text, const char *path, int debug)
{
- lexerin = NULL;
- parser_error_pos = -1;
- parser_input_buffer = text;
- parser_source_path = std::string(path);
-
- module_stack.clear();
- Module *rootmodule = currmodule = new Module();
- // PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
-
- parserdebug = debug;
- int parserretval = parserparse();
- lexerdestroy();
- lexerlex_destroy();
-
- if (parserretval != 0) return NULL;
-
- parser_error_pos = -1;
- return rootmodule;
+ lexerin = NULL;
+ parser_error_pos = -1;
+ parser_input_buffer = text;
+ parser_source_path = boosty::absolute(std::string(path)).string();
+
+ rootmodule = new FileModule();
+ rootmodule->setModulePath(path);
+ scope_stack.push(&rootmodule->scope);
+ // PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
+
+ parserdebug = debug;
+ int parserretval = parserparse();
+ lexerdestroy();
+ lexerlex_destroy();
+
+ if (parserretval != 0) return NULL;
+
+ parser_error_pos = -1;
+ scope_stack.pop();
+ return rootmodule;
}
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index a757ba1..8d82744 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -3,8 +3,9 @@
#include <boost/foreach.hpp>
#include "boosty.h"
#include <boost/algorithm/string.hpp>
-#include <qglobal.h> // Needed for Q_ defines - move the offending code somewhere else
+#ifdef __APPLE__
#include "CocoaUtils.h"
+#endif
namespace fs = boost::filesystem;
diff --git a/src/primitives.cc b/src/primitives.cc
index e02df35..9b755ef 100644
--- a/src/primitives.cc
+++ b/src/primitives.cc
@@ -27,12 +27,13 @@
#include "module.h"
#include "node.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "builtin.h"
#include "printutils.h"
#include "visitor.h"
+#include "context.h"
#include <sstream>
#include <assert.h>
#include <boost/assign/std/vector.hpp>
@@ -55,7 +56,7 @@ class PrimitiveModule : public AbstractModule
public:
primitive_type_e type;
PrimitiveModule(primitive_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class PrimitiveNode : public AbstractPolyNode
@@ -104,44 +105,43 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
PrimitiveNode *node = new PrimitiveNode(inst, this->type);
node->center = false;
node->x = node->y = node->z = node->h = node->r1 = node->r2 = 1;
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
+ AssignmentList args;
switch (this->type) {
case CUBE:
- argnames += "size", "center";
+ args += Assignment("size", NULL), Assignment("center", NULL);
break;
case SPHERE:
- argnames += "r";
+ args += Assignment("r", NULL);
break;
case CYLINDER:
- argnames += "h", "r1", "r2", "center";
+ args += Assignment("h", NULL), Assignment("r1", NULL), Assignment("r2", NULL), Assignment("center", NULL);
break;
case POLYHEDRON:
- argnames += "points", "triangles", "convexity";
+ args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL);
break;
case SQUARE:
- argnames += "size", "center";
+ args += Assignment("size", NULL), Assignment("center", NULL);
break;
case CIRCLE:
- argnames += "r";
+ args += Assignment("r", NULL);
break;
case POLYGON:
- argnames += "points", "paths", "convexity";
+ args += Assignment("points", NULL), Assignment("paths", NULL), Assignment("convexity", NULL);
break;
default:
- assert(false && "PrimitiveModule::evaluate(): Unknown node type");
+ assert(false && "PrimitiveModule::instantiate(): Unknown node type");
}
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
@@ -546,7 +546,7 @@ sphere_next_r2:
p->is2d = true;
p->convexity = convexity;
- dxf_tesselate(p, dd, 0, true, false, 0);
+ dxf_tesselate(p, dd, 0, Vector2d(1,1), true, false, 0);
dxf_border_to_ps(p, dd);
}
diff --git a/src/printutils.cc b/src/printutils.cc
index 698fffb..37092fa 100644
--- a/src/printutils.cc
+++ b/src/printutils.cc
@@ -69,5 +69,3 @@ std::string two_digit_exp_format( double x )
s << x;
return two_digit_exp_format( s.str() );
}
-
-
diff --git a/src/printutils.h b/src/printutils.h
index 439c884..18aadde 100644
--- a/src/printutils.h
+++ b/src/printutils.h
@@ -22,6 +22,9 @@ void PRINT(const std::string &msg);
void PRINT_NOCACHE(const std::string &msg);
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
+
+void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst);
+
std::string two_digit_exp_format( std::string doublestr );
std::string two_digit_exp_format( double x );
diff --git a/src/projection.cc b/src/projection.cc
index 1fcf639..8d8cee6 100644
--- a/src/projection.cc
+++ b/src/projection.cc
@@ -26,7 +26,7 @@
#include "projectionnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
#include "builtin.h"
#include "visitor.h"
@@ -41,19 +41,18 @@ class ProjectionModule : public AbstractModule
{
public:
ProjectionModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ProjectionNode *node = new ProjectionNode(inst);
- std::vector<std::string> argnames;
- argnames += "cut";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("cut", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
Value convexity = c.lookup_variable("convexity", true);
Value cut = c.lookup_variable("cut", true);
@@ -63,8 +62,8 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant
if (cut.type() == Value::BOOL)
node->cut_mode = cut.toBool();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/render.cc b/src/render.cc
index 81c3f7b..5097661 100644
--- a/src/render.cc
+++ b/src/render.cc
@@ -26,7 +26,7 @@
#include "rendernode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
@@ -38,26 +38,25 @@ class RenderModule : public AbstractModule
{
public:
RenderModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RenderNode *node = new RenderNode(inst);
- std::vector<std::string> argnames;
- argnames += "convexity";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("convexity", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
Value v = c.lookup_variable("convexity");
if (v.type() == Value::NUMBER)
node->convexity = (int)v.toDouble();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc
index dc8ea34..e073a69 100644
--- a/src/rotateextrude.cc
+++ b/src/rotateextrude.cc
@@ -26,8 +26,9 @@
#include "rotateextrudenode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
+#include "fileutils.h"
#include "builtin.h"
#include "polyset.h"
#include "visitor.h"
@@ -45,19 +46,18 @@ class RotateExtrudeModule : public AbstractModule
{
public:
RotateExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RotateExtrudeNode *node = new RotateExtrudeNode(inst);
- std::vector<std::string> argnames;
- argnames += "file", "layer", "origin", "scale";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("origin", NULL), Assignment("scale", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
@@ -71,7 +71,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst
if (!file.isUndefined()) {
PRINT("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead.");
- node->filename = c.getAbsolutePath(file.toString());
+ node->filename = lookup_file(file.toString(), inst->path(), c.documentPath());
}
node->layername = layer.isUndefined() ? "" : layer.toString();
@@ -86,8 +86,8 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst
node->scale = 1;
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
return node;
diff --git a/src/surface.cc b/src/surface.cc
index 4339ead..7987b99 100644
--- a/src/surface.cc
+++ b/src/surface.cc
@@ -27,9 +27,10 @@
#include "module.h"
#include "node.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "printutils.h"
+#include "fileutils.h"
#include "handle_dep.h" // handle_dep()
#include "visitor.h"
@@ -50,7 +51,7 @@ class SurfaceModule : public AbstractModule
{
public:
SurfaceModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class SurfaceNode : public AbstractPolyNode
@@ -69,21 +70,20 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *SurfaceModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
SurfaceNode *node = new SurfaceNode(inst);
node->center = false;
node->convexity = 1;
- std::vector<std::string> argnames;
- argnames += "file", "center", "convexity";
- std::vector<Expression*> argexpr;
+ AssignmentList args;
+ args += Assignment("file", NULL), Assignment("center", NULL), Assignment("convexity", NULL);
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
Value fileval = c.lookup_variable("file");
- node->filename = c.getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString());
+ node->filename = lookup_file(fileval.isUndefined() ? "" : fileval.toString(), inst->path(), c.documentPath());
Value center = c.lookup_variable("center", true);
if (center.type() == Value::BOOL) {
@@ -122,7 +122,7 @@ PolySet *SurfaceNode::evaluate_polyset(class PolySetEvaluator *) const
std::getline(stream, line);
boost::trim(line);
}
- if (stream.eof()) break;
+ if (line.size() == 0 && stream.eof()) break;
int col = 0;
tokenizer tokens(line, sep);
diff --git a/src/transform.cc b/src/transform.cc
index b01827f..ddf222a 100644
--- a/src/transform.cc
+++ b/src/transform.cc
@@ -26,7 +26,7 @@
#include "transformnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "polyset.h"
#include "builtin.h"
#include "value.h"
@@ -50,40 +50,39 @@ class TransformModule : public AbstractModule
public:
transform_type_e type;
TransformModule(transform_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
TransformNode *node = new TransformNode(inst);
node->matrix = Transform3d::Identity();
- std::vector<std::string> argnames;
- std::vector<Expression*> argexpr;
+ AssignmentList args;
switch (this->type) {
case SCALE:
- argnames += "v";
+ args += Assignment("v", NULL);
break;
case ROTATE:
- argnames += "a", "v";
+ args += Assignment("a", NULL), Assignment("v", NULL);
break;
case MIRROR:
- argnames += "v";
+ args += Assignment("v", NULL);
break;
case TRANSLATE:
- argnames += "v";
+ args += Assignment("v", NULL);
break;
case MULTMATRIX:
- argnames += "m";
+ args += Assignment("m", NULL);
break;
default:
assert(false);
}
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(args, evalctx);
if (this->type == SCALE)
{
@@ -176,8 +175,8 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
}
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/typedefs.h b/src/typedefs.h
new file mode 100644
index 0000000..fd676e2
--- /dev/null
+++ b/src/typedefs.h
@@ -0,0 +1,11 @@
+#ifndef TYPEDEFS_H_
+#define TYPEDEFS_H_
+
+#include <string>
+#include <vector>
+
+typedef std::pair<std::string, class Expression*> Assignment;
+typedef std::vector<Assignment> AssignmentList;
+typedef std::vector<class ModuleInstantiation*> ModuleInstantiationList;
+
+#endif
diff --git a/src/value.cc b/src/value.cc
index f14f826..ebb825d 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -34,12 +34,14 @@
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/format.hpp>
-
-#include <QtCore/QDir>
+#include "boost-utils.h"
+#include "boosty.h"
std::ostream &operator<<(std::ostream &stream, const Filename &filename)
{
- stream << QuotedString(QDir::current().relativeFilePath(QString::fromLocal8Bit(filename.c_str())).toLocal8Bit().constData());
+ fs::path fnpath = fs::path( (std::string)filename );
+ fs::path fpath = boostfs_uncomplete(fnpath, fs::current_path());
+ stream << QuotedString(boosty::stringy( fpath ));
return stream;
}
contact: Jan Huwald // Impressum