summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2013-05-24 14:16:20 (GMT)
committerMarius Kintel <marius@kintel.net>2013-05-24 14:16:20 (GMT)
commit26046f6f0c4a774cbbb2af8ae7dc0e687963440c (patch)
tree38ff04fc460e8aa55134fb1ee6167fafb90a3423
parenteefcd6d0b271642d470cd55bc47d1579d943938e (diff)
parent95e399e06c6522f3fa67679808a1d52815368efa (diff)
Merge branch 'master' into epec-kernel
-rw-r--r--Info.plist30
-rw-r--r--README.md27
-rw-r--r--RELEASE_NOTES6
-rw-r--r--bison.pri2
-rw-r--r--doc/OpenSCAD-polygons.grafflebin4215 -> 4982 bytes
-rw-r--r--eigen.pri9
-rw-r--r--examples/example024.scad32
-rw-r--r--flex.pri2
-rw-r--r--mingw-cross-env.pri8
-rw-r--r--openscad.pro13
-rw-r--r--scripts/LogicLib.nsh792
-rwxr-xr-xscripts/builder.sh231
-rwxr-xr-xscripts/googlecode_upload.py16
-rw-r--r--scripts/installer.nsi5
-rw-r--r--scripts/installer32.nsi3
-rw-r--r--scripts/installer64.nsi8
-rwxr-xr-xscripts/macosx-build-dependencies.sh37
-rwxr-xr-xscripts/mingw-x-build-dependencies.sh28
-rwxr-xr-xscripts/publish-macosx.sh43
-rwxr-xr-xscripts/release-common.sh86
-rw-r--r--scripts/setenv-mingw-xbuild.sh83
-rwxr-xr-xscripts/uni-build-dependencies.sh65
-rwxr-xr-xscripts/uni-get-dependencies.sh13
-rw-r--r--scripts/x64.nsh54
-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
-rw-r--r--testdata/scad/features/child-child-test.scad12
-rw-r--r--testdata/scad/features/child-tests.scad7
-rw-r--r--testdata/scad/features/hull2-tests.scad8
-rw-r--r--testdata/scad/features/hull3-tests.scad9
-rw-r--r--testdata/scad/features/linear_extrude-scale-zero-tests.scad56
-rw-r--r--testdata/scad/features/linear_extrude-tests.scad11
-rw-r--r--testdata/scad/features/module-recursion.scad15
-rw-r--r--testdata/scad/features/modulevariables.scad7
-rw-r--r--testdata/scad/features/surface-simple.dat4
-rw-r--r--testdata/scad/features/surface-simple.scad2
-rw-r--r--testdata/scad/features/surface-simple2.dat3
-rw-r--r--testdata/scad/misc/localfiles-test.scad3
-rw-r--r--testdata/scad/misc/localfiles_dir/localfile.dat2
-rw-r--r--testdata/scad/misc/localfiles_dir/localfile.dxf1968
-rw-r--r--testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad3
-rw-r--r--testdata/scad/misc/localfiles_dir/localfiles_module.scad9
-rw-r--r--testdata/scad/misc/localfiles_dir/localfiles_subdir/localfiles_submodule.scad9
-rw-r--r--testdata/scad/misc/lookup-tests.scad17
-rw-r--r--testdata/scad/misc/variable-scope-sub.scad24
-rw-r--r--testdata/scad/misc/variable-scope-tests.scad53
-rw-r--r--testdata/scad/templates/import_dxf-tests-template.scad2
-rw-r--r--tests/CMakeLists.txt68
-rw-r--r--tests/cgalcachetest.cc21
-rw-r--r--tests/cgalpngtest.cc26
-rw-r--r--tests/cgalstlsanitytest.cc23
-rw-r--r--tests/cgaltest.cc19
-rw-r--r--tests/csgtermtest.cc19
-rw-r--r--tests/csgtestcore.cc28
-rw-r--r--tests/csgtexttest.cc19
-rw-r--r--tests/dumptest.cc44
-rw-r--r--tests/echotest.cc19
-rw-r--r--tests/modulecachetest.cc22
-rw-r--r--tests/regression/cgalpngtest/child-child-test-expected.pngbin0 -> 8017 bytes
-rw-r--r--tests/regression/cgalpngtest/child-tests-expected.pngbin13034 -> 13394 bytes
-rw-r--r--tests/regression/cgalpngtest/linear_extrude-scale-zero-tests-expected.pngbin0 -> 16708 bytes
-rw-r--r--tests/regression/cgalpngtest/linear_extrude-tests-expected.pngbin12351 -> 10804 bytes
-rw-r--r--tests/regression/cgalpngtest/localfiles-compatibility-test-expected.pngbin0 -> 11732 bytes
-rw-r--r--tests/regression/cgalpngtest/localfiles-test-expected.pngbin0 -> 11732 bytes
-rw-r--r--tests/regression/cgalpngtest/module-recursion-expected.pngbin0 -> 9814 bytes
-rw-r--r--tests/regression/cgalpngtest/modulevariables-expected.pngbin0 -> 9534 bytes
-rw-r--r--tests/regression/cgalpngtest/surface-simple-expected.pngbin7157 -> 8022 bytes
-rw-r--r--tests/regression/dumptest/allmodules-expected.txt4
-rw-r--r--tests/regression/dumptest/child-child-test-expected.txt59
-rw-r--r--tests/regression/dumptest/child-tests-expected.txt12
-rw-r--r--tests/regression/dumptest/dxf_linear_extrude-expected.txt2
-rw-r--r--tests/regression/dumptest/example009-expected.txt8
-rw-r--r--tests/regression/dumptest/hull2-tests-expected.txt6
-rw-r--r--tests/regression/dumptest/hull3-tests-expected.txt6
-rw-r--r--tests/regression/dumptest/include-tests-expected.txt2
-rw-r--r--tests/regression/dumptest/linear_extrude-expected.txt2
-rw-r--r--tests/regression/dumptest/linear_extrude-scale-zero-tests-expected.txt253
-rw-r--r--tests/regression/dumptest/linear_extrude-tests-expected.txt35
-rw-r--r--tests/regression/dumptest/localfiles-compatibility-test-expected.txt20
-rw-r--r--tests/regression/dumptest/localfiles-test-expected.txt20
-rw-r--r--tests/regression/dumptest/module-recursion-expected.txt244
-rw-r--r--tests/regression/dumptest/modulevariables-expected.txt4
-rw-r--r--tests/regression/dumptest/projection-tests-expected.txt10
-rw-r--r--tests/regression/dumptest/scale2D-tests-expected.txt4
-rw-r--r--tests/regression/dumptest/scale3D-tests-expected.txt6
-rw-r--r--tests/regression/dumptest/surface-simple-expected.txt3
-rw-r--r--tests/regression/dumptest/use-tests-expected.txt6
-rw-r--r--tests/regression/echotest/lookup-tests-expected.txt15
-rw-r--r--tests/regression/echotest/recursion-tests-expected.txt2
-rw-r--r--tests/regression/echotest/search-tests-expected.txt12
-rw-r--r--tests/regression/echotest/variable-scope-tests-expected.txt16
-rw-r--r--tests/regression/opencsgtest/child-child-test-expected.pngbin0 -> 8105 bytes
-rw-r--r--tests/regression/opencsgtest/child-tests-expected.pngbin13600 -> 14187 bytes
-rw-r--r--tests/regression/opencsgtest/linear_extrude-scale-zero-tests-expected.pngbin0 -> 29795 bytes
-rw-r--r--tests/regression/opencsgtest/linear_extrude-tests-expected.pngbin12785 -> 11331 bytes
-rw-r--r--tests/regression/opencsgtest/localfiles-compatibility-test-expected.pngbin0 -> 12657 bytes
-rw-r--r--tests/regression/opencsgtest/localfiles-test-expected.pngbin0 -> 12657 bytes
-rw-r--r--tests/regression/opencsgtest/module-recursion-expected.pngbin0 -> 10321 bytes
-rw-r--r--tests/regression/opencsgtest/modulevariables-expected.pngbin0 -> 9854 bytes
-rw-r--r--tests/regression/opencsgtest/surface-simple-expected.pngbin7396 -> 8416 bytes
-rw-r--r--tests/regression/throwntogethertest/child-child-test-expected.pngbin0 -> 8105 bytes
-rw-r--r--tests/regression/throwntogethertest/child-tests-expected.pngbin9234 -> 14187 bytes
-rw-r--r--tests/regression/throwntogethertest/linear_extrude-scale-zero-tests-expected.pngbin0 -> 29795 bytes
-rw-r--r--tests/regression/throwntogethertest/linear_extrude-tests-expected.pngbin12023 -> 11331 bytes
-rw-r--r--tests/regression/throwntogethertest/localfiles-compatibility-test-expected.pngbin0 -> 12657 bytes
-rw-r--r--tests/regression/throwntogethertest/localfiles-test-expected.pngbin0 -> 12657 bytes
-rw-r--r--tests/regression/throwntogethertest/module-recursion-expected.pngbin0 -> 10321 bytes
-rw-r--r--tests/regression/throwntogethertest/modulevariables-expected.pngbin0 -> 9854 bytes
-rw-r--r--tests/regression/throwntogethertest/surface-simple-expected.pngbin7396 -> 8416 bytes
-rwxr-xr-xtests/test_cmdline_tool.py3
-rw-r--r--tests/tests-common.cc13
-rw-r--r--tests/tests-common.h4
169 files changed, 6485 insertions, 1494 deletions
diff --git a/Info.plist b/Info.plist
index 506bab7..84b270f 100644
--- a/Info.plist
+++ b/Info.plist
@@ -38,6 +38,36 @@
<key>LSIsAppleDefaultForType</key>
<true/>
</dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>stl</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>STL 3D file</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>off</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>OFF 3D file</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>dxf</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>DXF file</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
</array>
<key>NSAppleScriptEnabled</key>
<true/>
diff --git a/README.md b/README.md
index c2acded..73eea87 100644
--- a/README.md
+++ b/README.md
@@ -84,15 +84,15 @@ libraries from aptitude. If you're using Mac, or an older Linux/BSD, there
are build scripts that download and compile the libraries from source.
Follow the instructions for the platform you're compiling on below.
-* [Qt4 (4.4 - 4.7)](http://www.qt.nokia.com/)
-* [CGAL (3.6 - 4.0.2)](http://www.cgal.org/)
- * [GMP (5.0.x)](http://www.gmplib.org/)
- * [cmake (2.6 - 2.8, required by CGAL and the test framework)](http://www.cmake.org/)
+* [Qt4 (4.4 - 4.8)](http://www.qt.nokia.com/)
+* [CGAL (3.6 - 4.1)](http://www.cgal.org/)
+ * [GMP (5.x)](http://www.gmplib.org/)
+ * [cmake (2.8, required by CGAL and the test framework)](http://www.cmake.org/)
* [MPFR (3.x)](http://www.mpfr.org/)
- * [boost (1.35 - 1.47)](http://www.boost.org/)
+ * [boost (1.35 - 1.53)](http://www.boost.org/)
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
-* [Eigen (2.0.13->3.1.1)](http://eigen.tuxfamily.org/)
+* [Eigen (2.0.x->3.x)](http://eigen.tuxfamily.org/)
* [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)
* [Bison (2.4)](http://www.gnu.org/software/bison/)
* [Flex (2.5.35)](http://flex.sourceforge.net/)
@@ -108,8 +108,7 @@ This will download the latest sources into a directory named 'openscad'.
To pull the MCAD library (http://reprap.org/wiki/MCAD), do the following:
cd openscad
- git submodule init
- git submodule update
+ git submodule update --init
### Building for Mac OS X
@@ -189,14 +188,14 @@ http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_on_Windows
To cross-build, first make sure that you have development tools
installed to get GCC. Then after you've cloned this git repository,
-start a new clean shell and run the script that sets up the environment
+start a new clean bash shell and run the script that sets up the environment
variables.
- source ./scripts/setenv-mingw-xbuild.sh
+ source ./scripts/setenv-mingw-xbuild.sh 32
Then run the script to download & compile all the prerequisite libraries above:
- ./scripts/mingw-x-build-dependencies.sh
+ ./scripts/mingw-x-build-dependencies.sh 32
Note that this process can take several hours, as it uses the
http://mxe.cc system to cross-build many libraries. After it is
@@ -207,9 +206,11 @@ complete, build OpenSCAD and package it to an installer:
If you wish you can only build the openscad.exe binary:
cd mingw32
- i686-pc-mingw32-qmake .. CONFIG+=mingw-cross-env
+ qmake .. CONFIG+=mingw-cross-env
make
-
+
+For a 64-bit Windows cross-build, replace 32 with 64 in the above instructions.
+
### Compilation
First, run 'qmake' from Qt4 to generate a Makefile. On some systems you need to
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index d912be4..56b92d9 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -2,6 +2,8 @@ OpenSCAD 2013.XX
================
Features:
+o Recursive modules and functions is now supported (including cascading child() operations)
+o Parameter list values can now depend on earlier values, e.g. for (i=[0:2], j=[0:i]) ..
o Console output is now enabled on Windows through the openscad.com executable
o Added basic syntax highlighting in the editor
o Mac: Added document icon
@@ -10,8 +12,11 @@ o Commandline output to PNG, with various camera and rendering settings
o resize() command introduced
o Regression test now creates single monolithic .html file for easier uploading
o value reassignment is now less strict
+o value assignments in parameters can now depend on already declared parameters
+o Attempting to open dxf, off or stl files in the GUI will now create an import statement.
Bugfixes:
+o Importing files is now always relative to the importing script, also for libraries
o OpenCSG rendering sometimes crashed when rendering large models
o We didn't always print a warning when CSG normalization created too many elements
o Binary STLs can now be read on big endian architectures
@@ -21,7 +26,6 @@ o Changed multmatrix floating-point output to improve dumptest portability
o Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine
o CGAL triangulation more lenient- enables partial rendering of 'bad' DXF data
o Fixes problem where local changes are overwritten on automatic reload when included files has changed.
-o Non-ascii filenames are now allowed
OpenSCAD 2013.01
================
diff --git a/bison.pri b/bison.pri
index 7a63f0e..d2972d6 100644
--- a/bison.pri
+++ b/bison.pri
@@ -1,4 +1,4 @@
-win32 {
+{
bison.name = Bison ${QMAKE_FILE_IN}
bison.input = BISONSOURCES
bison.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}_yacc.cpp
diff --git a/doc/OpenSCAD-polygons.graffle b/doc/OpenSCAD-polygons.graffle
index 758d575..63985dc 100644
--- a/doc/OpenSCAD-polygons.graffle
+++ b/doc/OpenSCAD-polygons.graffle
Binary files differ
diff --git a/eigen.pri b/eigen.pri
index 5935a47..7b4d46a 100644
--- a/eigen.pri
+++ b/eigen.pri
@@ -15,10 +15,6 @@ OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
EIGEN2_DIR = $$(EIGEN2DIR)
EIGEN_DIR = $$(EIGENDIR)
-CONFIG(mingw-cross-env) {
- EIGEN_INCLUDEPATH = mingw-cross-env/include/eigen2
-}
-
# Optionally specify location of Eigen3 using the
# OPENSCAD_LIBRARIES env. variable
!isEmpty(OPENSCAD_LIBRARIES_DIR) {
@@ -69,11 +65,6 @@ isEmpty(EIGEN_INCLUDEPATH) {
EIGEN_INCLUDEPATH = $$replace(EIGEN_CFLAGS,"-I","")
}
-mingw-cross-env {
- EIGEN_CFLAGS = $$system("i686-pc-mingw32-pkg-config --cflags eigen3")
- EIGEN_INCLUDEPATH = $$replace(EIGEN_CFLAGS,"-I","")
-}
-
# disable Eigen SIMD optimizations for platforms where it breaks compilation
!macx {
!freebsd-g++ {
diff --git a/examples/example024.scad b/examples/example024.scad
new file mode 100644
index 0000000..1502ec7
--- /dev/null
+++ b/examples/example024.scad
@@ -0,0 +1,32 @@
+// Menger Sponge
+// By Nathan Hellweg, Emmett Lalish and Marius Kintel May 13, 2013
+// CC-BY-SA license
+
+// Size of edge of sponge
+D=100;
+// Fractal depth (number of iterations)
+n=3;
+
+module menger() {
+ difference() {
+ cube(D, center=true);
+ for (v=[[0,0,0], [0,0,90], [0,90,0]])
+ rotate(v) menger_negative(side=D, maxside=D, level=n);
+ }
+}
+
+module menger_negative(side=1, maxside=1, level=1) {
+ l=side/3;
+ cube([maxside*1.1, l, l], center=true);
+ if (level > 1) {
+ for (i=[-1:1], j=[-1:1])
+ if (i || j)
+ translate([0, i*l, j*l])
+ menger_negative(side=l, maxside=maxside, level=level-1);
+ }
+}
+
+difference() {
+ rotate([45, atan(1/sqrt(2)), 0]) menger();
+ translate([0,0,-D]) cube(2*D, center=true);
+}
diff --git a/flex.pri b/flex.pri
index 203d90d..0813300 100644
--- a/flex.pri
+++ b/flex.pri
@@ -1,4 +1,4 @@
-win32 {
+{
flex.name = Flex ${QMAKE_FILE_IN}
flex.input = FLEXSOURCES
flex.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp
diff --git a/mingw-cross-env.pri b/mingw-cross-env.pri
index 9b808c0..e696b56 100644
--- a/mingw-cross-env.pri
+++ b/mingw-cross-env.pri
@@ -4,13 +4,15 @@ CONFIG(mingw-cross-env) {
LIBS += mingw-cross-env/lib/libglut.a
LIBS += mingw-cross-env/lib/libopengl32.a
LIBS += mingw-cross-env/lib/libGLEW.a
- LIBS += mingw-cross-env/lib/libglaux.a
+# exists( mingw-cross-env/lib/libglaux.a ) {
+# LIBS += mingw-cross-env/lib/libglaux.a
+# }
LIBS += mingw-cross-env/lib/libglu32.a
LIBS += mingw-cross-env/lib/libopencsg.a
LIBS += mingw-cross-env/lib/libmpfr.a
LIBS += mingw-cross-env/lib/libgmp.a
LIBS += mingw-cross-env/lib/libCGAL.a
QMAKE_CXXFLAGS += -fpermissive
+ QMAKE_DEL_FILE = rm -f
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-local-typedefs #eigen3
}
-
-
diff --git a/openscad.pro b/openscad.pro
index d9442d4..542bcc3 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -187,7 +187,8 @@ FORMS += src/MainWindow.ui \
src/AboutDialog.ui \
src/ProgressWidget.ui
-HEADERS += src/version_check.h \
+HEADERS += src/typedefs.h \
+ src/version_check.h \
src/ProgressWidget.h \
src/parsersettings.h \
src/renderer.h \
@@ -203,6 +204,8 @@ HEADERS += src/version_check.h \
src/AboutDialog.h \
src/builtin.h \
src/context.h \
+ src/modcontext.h \
+ src/evalcontext.h \
src/csgterm.h \
src/csgtermnormalizer.h \
src/dxfdata.h \
@@ -213,6 +216,7 @@ HEADERS += src/version_check.h \
src/function.h \
src/grid.h \
src/highlighter.h \
+ src/localscope.h \
src/module.h \
src/node.h \
src/csgnode.h \
@@ -228,6 +232,7 @@ HEADERS += src/version_check.h \
src/handle_dep.h \
src/polyset.h \
src/printutils.h \
+ src/fileutils.h \
src/value.h \
src/progress.h \
src/editor.h \
@@ -247,6 +252,7 @@ HEADERS += src/version_check.h \
src/Camera.h \
src/system-gl.h \
src/stl-utils.h \
+ src/boost-utils.h \
src/svg.h \
\
src/lodepng.h \
@@ -268,9 +274,12 @@ SOURCES += src/version_check.cc \
src/value.cc \
src/expr.cc \
src/func.cc \
+ src/localscope.cc \
src/module.cc \
src/node.cc \
src/context.cc \
+ src/modcontext.cc \
+ src/evalcontext.cc \
src/csgterm.cc \
src/csgtermnormalizer.cc \
src/polyset.cc \
@@ -288,9 +297,11 @@ SOURCES += src/version_check.cc \
src/linearextrude.cc \
src/rotateextrude.cc \
src/printutils.cc \
+ src/fileutils.cc \
src/progress.cc \
src/parsersettings.cc \
src/stl-utils.cc \
+ src/boost-utils.cc \
\
src/nodedumper.cc \
src/traverser.cc \
diff --git a/scripts/LogicLib.nsh b/scripts/LogicLib.nsh
new file mode 100644
index 0000000..2f8968c
--- /dev/null
+++ b/scripts/LogicLib.nsh
@@ -0,0 +1,792 @@
+; NSIS LOGIC LIBRARY - LogicLib.nsh
+; Version 2.6 - 08/12/2007
+; By dselkirk@hotmail.com
+; and eccles@users.sf.net
+; with IfNot support added by Message
+;
+; Questions/Comments -
+; See http://forums.winamp.com/showthread.php?s=&postid=1116241
+;
+; Description:
+; Provides the use of various logic statements within NSIS.
+;
+; Usage:
+; The following "statements" are available:
+; If|IfNot|Unless..{ElseIf|ElseIfNot|ElseUnless}..[Else]..EndIf|EndUnless
+; - Conditionally executes a block of statements, depending on the value
+; of an expression. IfNot and Unless are equivalent and
+; interchangeable, as are ElseIfNot and ElseUnless.
+; AndIf|AndIfNot|AndUnless|OrIf|OrIfNot|OrUnless
+; - Adds any number of extra conditions to If, IfNot, Unless, ElseIf,
+; ElseIfNot and ElseUnless statements.
+; IfThen|IfNotThen..|..|
+; - Conditionally executes an inline statement, depending on the value
+; of an expression.
+; IfCmd..||..|
+; - Conditionally executes an inline statement, depending on a true
+; value of the provided NSIS function.
+; Select..{Case[2|3|4|5]}..[CaseElse|Default]..EndSelect
+; - Executes one of several blocks of statements, depending on the value
+; of an expression.
+; Switch..{Case|CaseElse|Default}..EndSwitch
+; - Jumps to one of several labels, depending on the value of an
+; expression.
+; Do[While|Until]..{ExitDo|Continue|Break}..Loop[While|Until]
+; - Repeats a block of statements until stopped, or depending on the
+; value of an expression.
+; While..{ExitWhile|Continue|Break}..EndWhile
+; - An alias for DoWhile..Loop (for backwards-compatibility)
+; For[Each]..{ExitFor|Continue|Break}..Next
+; - Repeats a block of statements varying the value of a variable.
+;
+; The following "expressions" are available:
+; Standard (built-in) string tests (which are case-insensitive):
+; a == b; a != b
+; Additional case-insensitive string tests (using System.dll):
+; a S< b; a S>= b; a S> b; a S<= b
+; Case-sensitive string tests:
+; a S== b; a S!= b
+; Standard (built-in) signed integer tests:
+; a = b; a <> b; a < b; a >= b; a > b; a <= b
+; Standard (built-in) unsigned integer tests:
+; a U< b; a U>= b; a U> b; a U<= b
+; 64-bit integer tests (using System.dll):
+; a L= b; a L<> b; a L< b; a L>= b; a L> b; a L<= b
+; Built-in NSIS flag tests:
+; ${Abort}; ${Errors}; ${RebootFlag}; ${Silent}
+; Built-in NSIS other tests:
+; ${FileExists} a
+; Any conditional NSIS instruction test:
+; ${Cmd} a
+; Section flag tests:
+; ${SectionIsSelected} a; ${SectionIsSectionGroup} a;
+; ${SectionIsSectionGroupEnd} a; ${SectionIsBold} a;
+; ${SectionIsReadOnly} a; ${SectionIsExpanded} a;
+; ${SectionIsPartiallySelected} a
+;
+; Examples:
+; See LogicLib.nsi in the Examples folder for lots of example usage.
+
+!verbose push
+!verbose 3
+!ifndef LOGICLIB_VERBOSITY
+ !define LOGICLIB_VERBOSITY 3
+!endif
+!define _LOGICLIB_VERBOSITY ${LOGICLIB_VERBOSITY}
+!undef LOGICLIB_VERBOSITY
+!verbose ${_LOGICLIB_VERBOSITY}
+
+!ifndef LOGICLIB
+ !define LOGICLIB
+ !define | "'"
+ !define || "' '"
+ !define LOGICLIB_COUNTER 0
+
+ !include Sections.nsh
+
+ !macro _LOGICLIB_TEMP
+ !ifndef _LOGICLIB_TEMP
+ !define _LOGICLIB_TEMP
+ Var /GLOBAL _LOGICLIB_TEMP ; Temporary variable to aid the more elaborate logic tests
+ !endif
+ !macroend
+
+ !macro _IncreaseCounter
+ !define _LOGICLIB_COUNTER ${LOGICLIB_COUNTER}
+ !undef LOGICLIB_COUNTER
+ !define /math LOGICLIB_COUNTER ${_LOGICLIB_COUNTER} + 1
+ !undef _LOGICLIB_COUNTER
+ !macroend
+
+ !macro _PushLogic
+ !insertmacro _PushScope Logic _LogicLib_Label_${LOGICLIB_COUNTER}
+ !insertmacro _IncreaseCounter
+ !macroend
+
+ !macro _PopLogic
+ !insertmacro _PopScope Logic
+ !macroend
+
+ !macro _PushScope Type label
+ !ifdef _${Type} ; If we already have a statement
+ !define _Cur${Type} ${_${Type}}
+ !undef _${Type}
+ !define _${Type} ${label}
+ !define ${_${Type}}Prev${Type} ${_Cur${Type}} ; Save the current logic
+ !undef _Cur${Type}
+ !else
+ !define _${Type} ${label} ; Initialise for first statement
+ !endif
+ !macroend
+
+ !macro _PopScope Type
+ !ifndef _${Type}
+ !error "Cannot use _Pop${Type} without a preceding _Push${Type}"
+ !endif
+ !ifdef ${_${Type}}Prev${Type} ; If a previous statment was active then restore it
+ !define _Cur${Type} ${_${Type}}
+ !undef _${Type}
+ !define _${Type} ${${_Cur${Type}}Prev${Type}}
+ !undef ${_Cur${Type}}Prev${Type}
+ !undef _Cur${Type}
+ !else
+ !undef _${Type}
+ !endif
+ !macroend
+
+ ; String tests
+ !macro _== _a _b _t _f
+ StrCmp `${_a}` `${_b}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _!= _a _b _t _f
+ !insertmacro _== `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Case-sensitive string tests
+ !macro _S== _a _b _t _f
+ StrCmpS `${_a}` `${_b}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _S!= _a _b _t _f
+ !insertmacro _S== `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Extra string tests (cannot do these case-sensitively - I tried and lstrcmp still ignored the case)
+ !macro _StrCmpI _a _b _e _l _m
+ !insertmacro _LOGICLIB_TEMP
+ System::Call `kernel32::lstrcmpiA(ts, ts) i.s` `${_a}` `${_b}`
+ Pop $_LOGICLIB_TEMP
+ IntCmp $_LOGICLIB_TEMP 0 `${_e}` `${_l}` `${_m}`
+ !macroend
+
+ !macro _S< _a _b _t _f
+ !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _S>= _a _b _t _f
+ !insertmacro _S< `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _S> _a _b _t _f
+ !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _S<= _a _b _t _f
+ !insertmacro _S> `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Integer tests
+ !macro _= _a _b _t _f
+ IntCmp `${_a}` `${_b}` `${_t}` `${_f}` `${_f}`
+ !macroend
+
+ !macro _<> _a _b _t _f
+ !insertmacro _= `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _< _a _b _t _f
+ IntCmp `${_a}` `${_b}` `${_f}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _>= _a _b _t _f
+ !insertmacro _< `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _> _a _b _t _f
+ IntCmp `${_a}` `${_b}` `${_f}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _<= _a _b _t _f
+ !insertmacro _> `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Unsigned integer tests (NB: no need for extra equality tests)
+ !macro _U< _a _b _t _f
+ IntCmpU `${_a}` `${_b}` `${_f}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _U>= _a _b _t _f
+ !insertmacro _U< `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _U> _a _b _t _f
+ IntCmpU `${_a}` `${_b}` `${_f}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _U<= _a _b _t _f
+ !insertmacro _U> `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Int64 tests
+ !macro _Int64Cmp _a _o _b _t _f
+ !insertmacro _LOGICLIB_TEMP
+ System::Int64Op `${_a}` `${_o}` `${_b}`
+ Pop $_LOGICLIB_TEMP
+ !insertmacro _= $_LOGICLIB_TEMP 0 `${_f}` `${_t}`
+ !macroend
+
+ !macro _L= _a _b _t _f
+ !insertmacro _Int64Cmp `${_a}` = `${_b}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _L<> _a _b _t _f
+ !insertmacro _L= `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _L< _a _b _t _f
+ !insertmacro _Int64Cmp `${_a}` < `${_b}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _L>= _a _b _t _f
+ !insertmacro _L< `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ !macro _L> _a _b _t _f
+ !insertmacro _Int64Cmp `${_a}` > `${_b}` `${_t}` `${_f}`
+ !macroend
+
+ !macro _L<= _a _b _t _f
+ !insertmacro _L> `${_a}` `${_b}` `${_f}` `${_t}`
+ !macroend
+
+ ; Flag tests
+ !macro _Abort _a _b _t _f
+ IfAbort `${_t}` `${_f}`
+ !macroend
+ !define Abort `"" Abort ""`
+
+ !macro _Errors _a _b _t _f
+ IfErrors `${_t}` `${_f}`
+ !macroend
+ !define Errors `"" Errors ""`
+
+ !macro _FileExists _a _b _t _f
+ IfFileExists `${_b}` `${_t}` `${_f}`
+ !macroend
+ !define FileExists `"" FileExists`
+
+ !macro _RebootFlag _a _b _t _f
+ IfRebootFlag `${_t}` `${_f}`
+ !macroend
+ !define RebootFlag `"" RebootFlag ""`
+
+ !macro _Silent _a _b _t _f
+ IfSilent `${_t}` `${_f}`
+ !macroend
+ !define Silent `"" Silent ""`
+
+ ; "Any instruction" test
+ !macro _Cmd _a _b _t _f
+ !define _t=${_t}
+ !ifdef _t= ; If no true label then make one
+ !define __t _LogicLib_Label_${LOGICLIB_COUNTER}
+ !insertmacro _IncreaseCounter
+ !else
+ !define __t ${_t}
+ !endif
+ ${_b} ${__t}
+ !define _f=${_f}
+ !ifndef _f= ; If a false label then go there
+ Goto ${_f}
+ !endif
+ !undef _f=${_f}
+ !ifdef _t= ; If we made our own true label then place it
+ ${__t}:
+ !endif
+ !undef __t
+ !undef _t=${_t}
+ !macroend
+ !define Cmd `"" Cmd`
+
+ ; Section flag test
+ !macro _SectionFlagIsSet _a _b _t _f
+ !insertmacro _LOGICLIB_TEMP
+ SectionGetFlags `${_b}` $_LOGICLIB_TEMP
+ IntOp $_LOGICLIB_TEMP $_LOGICLIB_TEMP & `${_a}`
+ !insertmacro _= $_LOGICLIB_TEMP `${_a}` `${_t}` `${_f}`
+ !macroend
+ !define SectionIsSelected `${SF_SELECTED} SectionFlagIsSet`
+ !define SectionIsSubSection `${SF_SUBSEC} SectionFlagIsSet`
+ !define SectionIsSubSectionEnd `${SF_SUBSECEND} SectionFlagIsSet`
+ !define SectionIsSectionGroup `${SF_SECGRP} SectionFlagIsSet`
+ !define SectionIsSectionGroupEnd `${SF_SECGRPEND} SectionFlagIsSet`
+ !define SectionIsBold `${SF_BOLD} SectionFlagIsSet`
+ !define SectionIsReadOnly `${SF_RO} SectionFlagIsSet`
+ !define SectionIsExpanded `${SF_EXPAND} SectionFlagIsSet`
+ !define SectionIsPartiallySelected `${SF_PSELECTED} SectionFlagIsSet`
+
+ !define IfCmd `!insertmacro _IfThen "" Cmd ${|}`
+
+ !macro _If _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !insertmacro _PushLogic
+ !define ${_Logic}If
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the Else
+ !insertmacro _IncreaseCounter
+ !define _c=${_c}
+ !ifdef _c=true ; If is true
+ !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} ""
+ !endif
+ !undef _c=${_c}
+ !verbose pop
+ !macroend
+ !define If `!insertmacro _If true`
+ !define Unless `!insertmacro _If false`
+ !define IfNot `!insertmacro _If false`
+
+ !macro _And _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}If
+ !error "Cannot use And without a preceding If or IfNot/Unless"
+ !endif
+ !ifndef ${_Logic}Else
+ !error "Cannot use And following an Else"
+ !endif
+ !define _c=${_c}
+ !ifdef _c=true ; If is true
+ !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} ""
+ !endif
+ !undef _c=${_c}
+ !verbose pop
+ !macroend
+ !define AndIf `!insertmacro _And true`
+ !define AndUnless `!insertmacro _And false`
+ !define AndIfNot `!insertmacro _And false`
+
+ !macro _Or _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}If
+ !error "Cannot use Or without a preceding If or IfNot/Unless"
+ !endif
+ !ifndef ${_Logic}Else
+ !error "Cannot use Or following an Else"
+ !endif
+ !define _label _LogicLib_Label_${LOGICLIB_COUNTER} ; Skip this test as we already
+ !insertmacro _IncreaseCounter
+ Goto ${_label} ; have a successful result
+ ${${_Logic}Else}: ; Place the Else label
+ !undef ${_Logic}Else ; and remove it
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new If
+ !insertmacro _IncreaseCounter
+ !define _c=${_c}
+ !ifdef _c=true ; If is true
+ !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} ""
+ !endif
+ !undef _c=${_c}
+ ${_label}:
+ !undef _label
+ !verbose pop
+ !macroend
+ !define OrIf `!insertmacro _Or true`
+ !define OrUnless `!insertmacro _Or false`
+ !define OrIfNot `!insertmacro _Or false`
+
+ !macro _Else
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}If
+ !error "Cannot use Else without a preceding If or IfNot/Unless"
+ !endif
+ !ifndef ${_Logic}Else
+ !error "Cannot use Else following an Else"
+ !endif
+ !ifndef ${_Logic}EndIf ; First Else for this If?
+ !define ${_Logic}EndIf _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the EndIf
+ !insertmacro _IncreaseCounter
+ !endif
+ Goto ${${_Logic}EndIf} ; Go to the EndIf
+ ${${_Logic}Else}: ; Place the Else label
+ !undef ${_Logic}Else ; and remove it
+ !verbose pop
+ !macroend
+ !define Else `!insertmacro _Else`
+
+ !macro _ElseIf _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${Else} ; Perform the Else
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new If
+ !insertmacro _IncreaseCounter
+ !define _c=${_c}
+ !ifdef _c=true ; If is true
+ !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} ""
+ !endif
+ !undef _c=${_c}
+ !verbose pop
+ !macroend
+ !define ElseIf `!insertmacro _ElseIf true`
+ !define ElseUnless `!insertmacro _ElseIf false`
+ !define ElseIfNot `!insertmacro _ElseIf false`
+
+ !macro _EndIf _n
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}If
+ !error "Cannot use End${_n} without a preceding If or IfNot/Unless"
+ !endif
+ !ifdef ${_Logic}Else
+ ${${_Logic}Else}: ; Place the Else label
+ !undef ${_Logic}Else ; and remove it
+ !endif
+ !ifdef ${_Logic}EndIf
+ ${${_Logic}EndIf}: ; Place the EndIf
+ !undef ${_Logic}EndIf ; and remove it
+ !endif
+ !undef ${_Logic}If
+ !insertmacro _PopLogic
+ !verbose pop
+ !macroend
+ !define EndIf `!insertmacro _EndIf If`
+ !define EndUnless `!insertmacro _EndIf Unless`
+
+ !macro _IfThen _a _o _b _t
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${If} `${_a}` `${_o}` `${_b}`
+ ${_t}
+ ${EndIf}
+ !verbose pop
+ !macroend
+ !define IfThen `!insertmacro _IfThen`
+
+ !macro _IfNotThen _a _o _b _t
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${IfNot} `${_a}` `${_o}` `${_b}`
+ ${_t}
+ ${EndIf}
+ !verbose pop
+ !macroend
+ !define IfNotThen `!insertmacro _IfNotThen`
+
+ !macro _ForEach _v _f _t _o _s
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ StrCpy "${_v}" "${_f}" ; Assign the initial value
+ Goto +2 ; Skip the loop expression for the first iteration
+ !define _DoLoopExpression `IntOp "${_v}" "${_v}" "${_o}" "${_s}"` ; Define the loop expression
+ !define _o=${_o}
+ !ifdef _o=+ ; Check the loop expression operator
+ !define __o > ; to determine the correct loop condition
+ !else ifdef _o=-
+ !define __o <
+ !else
+ !error "Unsupported ForEach step operator (must be + or -)"
+ !endif
+ !undef _o=${_o}
+ !insertmacro _Do For false `${_v}` `${__o}` `${_t}` ; Let Do do the rest
+ !undef __o
+ !verbose pop
+ !macroend
+ !define ForEach `!insertmacro _ForEach`
+
+ !macro _For _v _f _t
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${ForEach} `${_v}` `${_f}` `${_t}` + 1 ; Pass on to ForEach
+ !verbose pop
+ !macroend
+ !define For `!insertmacro _For`
+
+ !define ExitFor `!insertmacro _Goto ExitFor For`
+
+ !define Next `!insertmacro _Loop For Next "" "" "" ""`
+
+ !define While `!insertmacro _Do While true`
+
+ !define ExitWhile `!insertmacro _Goto ExitWhile While`
+
+ !define EndWhile `!insertmacro _Loop While EndWhile "" "" "" ""`
+
+ !macro _Do _n _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !insertmacro _PushLogic
+ !define ${_Logic}${_n} _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the start of the loop
+ !insertmacro _IncreaseCounter
+ ${${_Logic}${_n}}:
+ !insertmacro _PushScope Exit${_n} _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the end of the loop
+ !insertmacro _IncreaseCounter
+ !insertmacro _PushScope Break ${_Exit${_n}} ; Break goes to the end of the loop
+ !ifdef _DoLoopExpression
+ ${_DoLoopExpression} ; Special extra parameter for inserting code
+ !undef _DoLoopExpression ; between the Continue label and the loop condition
+ !endif
+ !define _c=${_c}
+ !ifdef _c= ; No starting condition
+ !insertmacro _PushScope Continue _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for Continue at the end of the loop
+ !insertmacro _IncreaseCounter
+ !else
+ !insertmacro _PushScope Continue ${${_Logic}${_n}} ; Continue goes to the start of the loop
+ !ifdef _c=true ; If is true
+ !insertmacro _${_o} `${_a}` `${_b}` "" ${_Exit${_n}}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${_Exit${_n}} ""
+ !endif
+ !endif
+ !undef _c=${_c}
+ !define ${_Logic}Condition ${_c} ; Remember the condition used
+ !verbose pop
+ !macroend
+ !define Do `!insertmacro _Do Do "" "" "" ""`
+ !define DoWhile `!insertmacro _Do Do true`
+ !define DoUntil `!insertmacro _Do Do false`
+
+ !macro _Goto _n _s
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _${_n}
+ !error "Cannot use ${_n} without a preceding ${_s}"
+ !endif
+ Goto ${_${_n}}
+ !verbose pop
+ !macroend
+ !define ExitDo `!insertmacro _Goto ExitDo Do`
+
+ !macro _Loop _n _e _c _a _o _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}${_n}
+ !error "Cannot use ${_e} without a preceding ${_n}"
+ !endif
+ !define _c=${${_Logic}Condition}
+ !ifdef _c= ; If Do had no condition place the Continue label
+ ${_Continue}:
+ !endif
+ !undef _c=${${_Logic}Condition}
+ !define _c=${_c}
+ !ifdef _c= ; No ending condition
+ Goto ${${_Logic}${_n}}
+ !else ifdef _c=true ; If condition is true
+ !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}${_n}} ${_Exit${_n}}
+ !else ; If condition is false
+ !insertmacro _${_o} `${_a}` `${_b}` ${_Exit${_n}} ${${_Logic}${_n}}
+ !endif
+ !undef _c=${_c}
+ Goto ${_Continue} ; Just to ensure it is referenced at least once
+ Goto ${_Exit${_n}} ; Just to ensure it is referenced at least once
+ ${_Exit${_n}}: ; Place the loop exit point
+ !undef ${_Logic}Condition
+ !insertmacro _PopScope Continue
+ !insertmacro _PopScope Break
+ !insertmacro _PopScope Exit${_n}
+ !undef ${_Logic}${_n}
+ !insertmacro _PopLogic
+ !verbose pop
+ !macroend
+ !define Loop `!insertmacro _Loop Do Loop "" "" "" ""`
+ !define LoopWhile `!insertmacro _Loop Do LoopWhile true`
+ !define LoopUntil `!insertmacro _Loop Do LoopUntil false`
+
+ !define Continue `!insertmacro _Goto Continue "For or Do or While"`
+ !define Break `!insertmacro _Goto Break "For or Do or While"`
+
+ !macro _Select _a
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !insertmacro _PushLogic
+ !define ${_Logic}Select `${_a}` ; Remember the left hand side of the comparison
+ !verbose pop
+ !macroend
+ !define Select `!insertmacro _Select`
+
+ !macro _Select_CaseElse
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}Select
+ !error "Cannot use Case without a preceding Select"
+ !endif
+ !ifdef ${_Logic}EndSelect ; This is set only after the first case
+ !ifndef ${_Logic}Else
+ !error "Cannot use Case following a CaseElse"
+ !endif
+ Goto ${${_Logic}EndSelect} ; Go to the EndSelect
+ ${${_Logic}Else}: ; Place the Else label
+ !undef ${_Logic}Else ; and remove it
+ !else
+ !define ${_Logic}EndSelect _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the EndSelect
+ !insertmacro _IncreaseCounter
+ !endif
+ !verbose pop
+ !macroend
+ !define CaseElse `!insertmacro _CaseElse`
+ !define Case_Else `!insertmacro _CaseElse` ; Compatibility with 2.2 and earlier
+ !define Default `!insertmacro _CaseElse` ; For the C-minded
+
+ !macro _Select_Case _a
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${CaseElse} ; Perform the CaseElse
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case
+ !insertmacro _IncreaseCounter
+ !insertmacro _== `${${_Logic}Select}` `${_a}` "" ${${_Logic}Else}
+ !verbose pop
+ !macroend
+ !define Case `!insertmacro _Case`
+
+ !macro _Case2 _a _b
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${CaseElse} ; Perform the CaseElse
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case
+ !insertmacro _IncreaseCounter
+ !insertmacro _== `${${_Logic}Select}` `${_a}` +2 ""
+ !insertmacro _== `${${_Logic}Select}` `${_b}` "" ${${_Logic}Else}
+ !verbose pop
+ !macroend
+ !define Case2 `!insertmacro _Case2`
+
+ !macro _Case3 _a _b _c
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${CaseElse} ; Perform the CaseElse
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case
+ !insertmacro _IncreaseCounter
+ !insertmacro _== `${${_Logic}Select}` `${_a}` +3 ""
+ !insertmacro _== `${${_Logic}Select}` `${_b}` +2 ""
+ !insertmacro _== `${${_Logic}Select}` `${_c}` "" ${${_Logic}Else}
+ !verbose pop
+ !macroend
+ !define Case3 `!insertmacro _Case3`
+
+ !macro _Case4 _a _b _c _d
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${CaseElse} ; Perform the CaseElse
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case
+ !insertmacro _IncreaseCounter
+ !insertmacro _== `${${_Logic}Select}` `${_a}` +4 ""
+ !insertmacro _== `${${_Logic}Select}` `${_b}` +3 ""
+ !insertmacro _== `${${_Logic}Select}` `${_c}` +2 ""
+ !insertmacro _== `${${_Logic}Select}` `${_d}` "" ${${_Logic}Else}
+ !verbose pop
+ !macroend
+ !define Case4 `!insertmacro _Case4`
+
+ !macro _Case5 _a _b _c _d _e
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ ${CaseElse} ; Perform the CaseElse
+ !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case
+ !insertmacro _IncreaseCounter
+ !insertmacro _== `${${_Logic}Select}` `${_a}` +5 ""
+ !insertmacro _== `${${_Logic}Select}` `${_b}` +4 ""
+ !insertmacro _== `${${_Logic}Select}` `${_c}` +3 ""
+ !insertmacro _== `${${_Logic}Select}` `${_d}` +2 ""
+ !insertmacro _== `${${_Logic}Select}` `${_e}` "" ${${_Logic}Else}
+ !verbose pop
+ !macroend
+ !define Case5 `!insertmacro _Case5`
+
+ !macro _EndSelect
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}Select
+ !error "Cannot use EndSelect without a preceding Select"
+ !endif
+ !ifdef ${_Logic}Else
+ ${${_Logic}Else}: ; Place the Else label
+ !undef ${_Logic}Else ; and remove it
+ !endif
+ !ifdef ${_Logic}EndSelect ; This won't be set if there weren't any cases
+ ${${_Logic}EndSelect}: ; Place the EndSelect
+ !undef ${_Logic}EndSelect ; and remove it
+ !endif
+ !undef ${_Logic}Select
+ !insertmacro _PopLogic
+ !verbose pop
+ !macroend
+ !define EndSelect `!insertmacro _EndSelect`
+
+ !macro _Switch _a
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !insertmacro _PushLogic
+ !insertmacro _PushScope Switch ${_Logic} ; Keep a separate stack for switch data
+ !insertmacro _PushScope Break _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a lable for beyond the end of the switch
+ !insertmacro _IncreaseCounter
+ !define ${_Switch}Var `${_a}` ; Remember the left hand side of the comparison
+ !tempfile ${_Switch}Tmp ; Create a temporary file
+ !define ${_Logic}Switch _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the end of the switch
+ !insertmacro _IncreaseCounter
+ Goto ${${_Logic}Switch} ; and go there
+ !verbose pop
+ !macroend
+ !define Switch `!insertmacro _Switch`
+
+ !macro _Case _a
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifdef _Logic & ${_Logic}Select ; Check for an active Select
+ !insertmacro _Select_Case `${_a}`
+ !else ifndef _Switch ; If not then check for an active Switch
+ !error "Cannot use Case without a preceding Select or Switch"
+ !else
+ !define _label _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for this case,
+ !insertmacro _IncreaseCounter
+ ${_label}: ; place it and add it's check to the temp file
+ !appendfile "${${_Switch}Tmp}" `!insertmacro _== $\`${${_Switch}Var}$\` $\`${_a}$\` ${_label} ""$\n`
+ !undef _label
+ !endif
+ !verbose pop
+ !macroend
+
+ !macro _CaseElse
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifdef _Logic & ${_Logic}Select ; Check for an active Select
+ !insertmacro _Select_CaseElse
+ !else ifndef _Switch ; If not then check for an active Switch
+ !error "Cannot use Case without a preceding Select or Switch"
+ !else ifdef ${_Switch}Else ; Already had a default case?
+ !error "Cannot use CaseElse following a CaseElse"
+ !else
+ !define ${_Switch}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the default case,
+ !insertmacro _IncreaseCounter
+ ${${_Switch}Else}: ; and place it
+ !endif
+ !verbose pop
+ !macroend
+
+ !macro _EndSwitch
+ !verbose push
+ !verbose ${LOGICLIB_VERBOSITY}
+ !ifndef _Logic | ${_Logic}Switch
+ !error "Cannot use EndSwitch without a preceding Switch"
+ !endif
+ Goto ${_Break} ; Skip the jump table
+ ${${_Logic}Switch}: ; Place the end of the switch
+ !undef ${_Logic}Switch
+ !include "${${_Switch}Tmp}" ; Include the jump table
+ !delfile "${${_Switch}Tmp}" ; and clear it up
+ !ifdef ${_Switch}Else ; Was there a default case?
+ Goto ${${_Switch}Else} ; then go there if all else fails
+ !undef ${_Switch}Else
+ !endif
+ !undef ${_Switch}Tmp
+ !undef ${_Switch}Var
+ ${_Break}: ; Place the break label
+ !insertmacro _PopScope Break
+ !insertmacro _PopScope Switch
+ !insertmacro _PopLogic
+ !verbose pop
+ !macroend
+ !define EndSwitch `!insertmacro _EndSwitch`
+
+!endif ; LOGICLIB
+!verbose 3
+!define LOGICLIB_VERBOSITY ${_LOGICLIB_VERBOSITY}
+!undef _LOGICLIB_VERBOSITY
+!verbose pop
diff --git a/scripts/builder.sh b/scripts/builder.sh
new file mode 100755
index 0000000..6a143e3
--- /dev/null
+++ b/scripts/builder.sh
@@ -0,0 +1,231 @@
+#!/usr/bin/env bash
+
+# build&upload script for linux & windows snapshot binaries
+# tested under linux
+
+# requirements -
+# see http://mxe.cc for required tools (scons, perl, yasm, etc etc etc)
+
+# todo - can we build 32 bit linux from within 64 bit linux?
+#
+# todo - make linux work
+#
+# todo - detect failure and stop
+
+init_variables()
+{
+ STARTPATH=$PWD
+ export STARTPATH
+ if [ "`echo $* | grep uploadonly`" ]; then
+ UPLOADONLY=1
+ DATECODE=`date +"%Y.%m.%d"`
+ else
+ UPLOADONLY=
+ fi
+ if [ "`echo $* | grep dry`" ]; then
+ DRYRUN=1
+ else
+ DRYRUN=
+ fi
+ export UPLOADONLY
+ export DRYRUN
+ export DATECODE
+}
+
+check_starting_path()
+{
+ if [ -e openscad.pro ]; then
+ echo 'please start from a clean directory outside of openscad'
+ exit
+ fi
+}
+
+get_source_code()
+{
+ git clone http://github.com/openscad/openscad.git
+ cd openscad
+ git submodule update --init # MCAD
+ #git checkout branch ##debugging
+}
+
+build_win32()
+{
+ . ./scripts/setenv-mingw-xbuild.sh clean
+ . ./scripts/setenv-mingw-xbuild.sh
+ ./scripts/mingw-x-build-dependencies.sh
+ ./scripts/release-common.sh mingw32
+ DATECODE=`date +"%Y.%m.%d"`
+ export DATECODE
+}
+
+build_win64()
+{
+ . ./scripts/setenv-mingw-xbuild.sh clean
+ . ./scripts/setenv-mingw-xbuild.sh 64
+ ./scripts/mingw-x-build-dependencies.sh 64
+ ./scripts/release-common.sh mingw64
+ DATECODE=`date +"%Y.%m.%d"`
+ export DATECODE
+}
+
+build_lin32()
+{
+ . ./scripts/setenv-unibuild.sh
+ ./scripts/uni-build-dependencies.sh
+ ./scripts/release-common.sh
+ DATECODE=`date +"%Y.%m.%d"`
+ export DATECODE
+}
+
+upload_win_generic()
+{
+ summary="$1"
+ username=$2
+ filename=$3
+ if [ -f $filename ]; then
+ echo 'file "'$filename'" found'
+ else
+ echo 'file "'$filename'" not found'
+ fi
+ opts=
+ opts="$opts -p openscad"
+ opts="$opts -u $username"
+ opts="$opts $filename"
+ if [ $DRYRUN ]; then
+ echo dry run, not uploading to googlecode
+ echo cmd - python ./scripts/googlecode_upload.py -s '"'$summary'"' $opts
+ else
+ python ./scripts/googlecode_upload.py -s "$summary" $opts
+ fi
+}
+
+upload_win32()
+{
+ SUMMARY1="Windows x86-32 Snapshot Installer"
+ SUMMARY2="Windows x86-32 Snapshot Zipfile"
+ DATECODE=`date +"%Y.%m.%d"`
+ BASEDIR=./mingw32/
+ WIN32_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-32-Installer.exe
+ WIN32_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-32.zip
+ upload_win_generic "$SUMMARY1" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE1
+ upload_win_generic "$SUMMARY2" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE2
+ export WIN32_PACKAGEFILE1
+ export WIN32_PACKAGEFILE2
+ WIN32_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE1 | awk ' {print $1} ';`
+ WIN32_PACKAGEFILE2_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE2 | awk ' {print $1} ';`
+ WIN32_PACKAGEFILE1_SIZE=`echo "$WIN32_PACKAGEFILE1_SIZE""B"`
+ WIN32_PACKAGEFILE2_SIZE=`echo "$WIN32_PACKAGEFILE2_SIZE""B"`
+ export WIN32_PACKAGEFILE1_SIZE
+ export WIN32_PACKAGEFILE2_SIZE
+}
+
+upload_win64()
+{
+ SUMMARY1="Windows x86-64 Snapshot Zipfile"
+ SUMMARY2="Windows x86-64 Snapshot Installer"
+ BASEDIR=./mingw64/
+ WIN64_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-64-Installer.exe
+ WIN64_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-64.zip
+ upload_win_generic "$SUMMARY1" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE1
+ upload_win_generic "$SUMMARY2" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE2
+ export WIN64_PACKAGEFILE1
+ export WIN64_PACKAGEFILE2
+ WIN64_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE1 | awk ' {print $1} ';`
+ WIN64_PACKAGEFILE2_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE2 | awk ' {print $1} ';`
+ WIN64_PACKAGEFILE1_SIZE=`echo "$WIN64_PACKAGEFILE1_SIZE""B"`
+ WIN64_PACKAGEFILE2_SIZE=`echo "$WIN64_PACKAGEFILE2_SIZE""B"`
+ export WIN64_PACKAGEFILE1_SIZE
+ export WIN64_PACKAGEFILE2_SIZE
+}
+
+read_username_from_user()
+{
+ if [ $DRYRUN ]; then USERNAME=none;export USERNAME; return; fi
+ echo 'Please enter your username for https://code.google.com/hosting/settings'
+ echo -n 'Username:'
+ read USERNAME
+ echo 'username is ' $USERNAME
+}
+
+read_password_from_user()
+{
+ if [ $DRYRUN ]; then return; fi
+ echo 'Please enter your password for https://code.google.com/hosting/settings'
+ echo -n 'Password:'
+ read -s PASSWORD1
+ echo
+ echo -n 'Verify :'
+ read -s PASSWORD2
+ echo
+ if [ ! $PASSWORD1 = $PASSWORD2 ]; then
+ echo 'error - passwords dont match'
+ exit
+ fi
+ OSUPL_PASSWORD=$PASSWORD1
+ export OSUPL_PASSWORD
+}
+
+update_win_www_download_links()
+{
+ cd $STARTPATH
+ git clone git@github.com:openscad/openscad.github.com.git
+ cd openscad.github.com
+ cd inc
+ echo `pwd`
+ BASEURL='https://openscad.googlecode.com/files/'
+ DATECODE=`date +"%Y.%m.%d"`
+
+ rm win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT1_URL'] = '$BASEURL$WIN64_PACKAGEFILE1'" >> win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT2_URL'] = '$BASEURL$WIN64_PACKAGEFILE2'" >> win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT1_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT2_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT1_SIZE'] = '$WIN64_PACKAGEFILE1_SIZE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN64_SNAPSHOT2_SIZE'] = '$WIN64_PACKAGEFILE2_SIZE'" >> win_snapshot_links.js
+
+ echo "snapinfo['WIN32_SNAPSHOT1_URL'] = '$BASEURL$WIN32_PACKAGEFILE1'" >> win_snapshot_links.js
+ echo "snapinfo['WIN32_SNAPSHOT2_URL'] = '$BASEURL$WIN32_PACKAGEFILE2'" >> win_snapshot_links.js
+ echo "snapinfo['WIN32_SNAPSHOT1_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN32_SNAPSHOT2_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN32_SNAPSHOT1_SIZE'] = '$WIN32_PACKAGEFILE1_SIZE'" >> win_snapshot_links.js
+ echo "snapinfo['WIN32_SNAPSHOT2_SIZE'] = '$WIN32_PACKAGEFILE2_SIZE'" >> win_snapshot_links.js
+ echo 'modified win_snapshot_links.js'
+
+ PAGER=cat git diff
+ if [ ! $DRYRUN ]; then
+ git commit -a -m 'builder.sh - updated snapshot links'
+ git push origin master
+ else
+ echo dry run, not updating www links
+ fi
+}
+
+check_ssh_agent()
+{
+ if [ $DRYRUN ]; then echo 'skipping ssh, dry run'; return; fi
+ if [ ! $SSH_AUTH_SOCK ]; then
+ echo 'please start an ssh-agent for github.com/openscad/openscad.github.com uploads'
+ echo 'for example:'
+ echo
+ echo ' ssh-agent > .tmp && source .tmp && ssh-add'
+ echo
+ fi
+}
+
+init_variables $*
+check_ssh_agent
+check_starting_path
+read_username_from_user
+read_password_from_user
+get_source_code
+
+if [ ! $UPLOADONLY ]; then
+ build_win32
+ build_win64
+fi
+upload_win32
+upload_win64
+update_win_www_download_links
+
+
+
diff --git a/scripts/googlecode_upload.py b/scripts/googlecode_upload.py
index 188dd6c..c0fe4c9 100755
--- a/scripts/googlecode_upload.py
+++ b/scripts/googlecode_upload.py
@@ -189,7 +189,7 @@ def encode_upload_request(fields, file_path):
def upload_find_auth(file_path, project_name, summary, labels=None,
- user_name=None, password=None, tries=3):
+ user_name=None, password=None, tries=1):
"""Find credentials and upload a file to a Google Code project's file server.
file_path, project_name, summary, and labels are passed as-is to upload.
@@ -203,6 +203,8 @@ def upload_find_auth(file_path, project_name, summary, labels=None,
user_name: Your Google account name.
tries: How many attempts to make.
"""
+ print 'uploading. username: ', user_name
+ print 'password detected:', password!=None
if user_name is None or password is None:
from netrc import netrc
authenticators = None
@@ -255,14 +257,20 @@ def main():
help='Google Code project name')
parser.add_option('-u', '--user', dest='user',
help='Your Google Code username')
- parser.add_option('-w', '--password', dest='password',
- help='Your Google Code password')
+ #this is a massive security hole. anyone using 'ps' could steal p/w
+ #parser.add_option('-w', '--password', dest='password',
+ # help='Your Google Code password')
parser.add_option('-l', '--labels', dest='labels',
help='An optional list of comma-separated labels to attach '
'to the file')
options, args = parser.parse_args()
+ if os.environ.has_key('OSUPL_PASSWORD'):
+ options.password=os.environ['OSUPL_PASSWORD']
+ else:
+ options.password=None
+
if not options.summary:
parser.error('File summary is missing.')
elif not options.project:
@@ -279,6 +287,7 @@ def main():
else:
labels = None
+ print 'read arguments'
status, reason, url = upload_find_auth(file_path, options.project,
options.summary, labels,
options.user, options.password)
@@ -293,4 +302,5 @@ def main():
if __name__ == '__main__':
+ print sys.argv
sys.exit(main())
diff --git a/scripts/installer.nsi b/scripts/installer.nsi
index 1841431..2cbd6d3 100644
--- a/scripts/installer.nsi
+++ b/scripts/installer.nsi
@@ -1,7 +1,10 @@
+InstallDir ""
+!include "LogicLib.nsh"
!include "mingw-file-association.nsh"
+!include "x64.nsh"
Name "OpenSCAD"
OutFile "openscad_setup.exe"
-InstallDir $PROGRAMFILES\OpenSCAD
+!include "installer_arch.nsi"
DirText "This will install OpenSCAD on your computer. Choose a directory"
Section "install"
SetOutPath $INSTDIR
diff --git a/scripts/installer32.nsi b/scripts/installer32.nsi
new file mode 100644
index 0000000..051cb0e
--- /dev/null
+++ b/scripts/installer32.nsi
@@ -0,0 +1,3 @@
+Function .onInit
+ StrCpy $InstDir $PROGRAMFILES\OpenSCAD
+FunctionEnd
diff --git a/scripts/installer64.nsi b/scripts/installer64.nsi
new file mode 100644
index 0000000..1b24c0c
--- /dev/null
+++ b/scripts/installer64.nsi
@@ -0,0 +1,8 @@
+Function .onInit
+${If} ${RunningX64}
+ StrCpy $InstDir $PROGRAMFILES64\OpenSCAD
+ SetRegView 64
+${Else}
+ Messagebox MB_OK "This is 64 bit OpenSCAD, your machine is 32 bits. Error."
+${EndIf}
+FunctionEnd
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index 3687041..088d8b4 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -28,7 +28,7 @@ OPTION_32BIT=true
OPTION_LLVM=false
OPTION_CLANG=false
OPTION_GCC=false
-DETECTED_LION=false
+OPTION_DEPLOY=false
export QMAKESPEC=macx-g++
printUsage()
@@ -370,12 +370,13 @@ do
esac
done
-OSVERSION=`sw_vers -productVersion | cut -d. -f2`
-if [[ $OSVERSION -ge 7 ]]; then
- echo "Detected Lion or later"
- DETECTED_LION=true
+OSX_VERSION=`sw_vers -productVersion | cut -d. -f2`
+if (( $OSX_VERSION >= 8 )); then
+ echo "Detected Mountain Lion (10.8) or later"
+elif (( $OSX_VERSION >= 7 )); then
+ echo "Detected Lion (10.7) or later"
else
- echo "Detected Snow Leopard or earlier"
+ echo "Detected Snow Leopard (10.6) or earlier"
fi
USING_LLVM=false
@@ -387,7 +388,7 @@ elif $OPTION_GCC; then
USING_GCC=true
elif $OPTION_CLANG; then
USING_CLANG=true
-elif $DETECTED_LION; then
+elif (( $OSX_VERSION >= 7 )); then
USING_GCC=true
fi
@@ -411,12 +412,32 @@ elif $USING_CLANG; then
export QMAKESPEC=unsupported/macx-clang
fi
+if (( $OSX_VERSION >= 8 )); then
+ echo "Setting build target to 10.6 or later"
+ MAC_OSX_VERSION_MIN=10.6
+else
+ echo "Setting build target to 10.5 or later"
+ MAC_OSX_VERSION_MIN=10.5
+fi
+
+if $OPTION_DEPLOY; then
+ echo "Building deployment version of libraries"
+else
+ OPTION_32BIT=false
+fi
+
+if $OPTION_32BIT; then
+ echo "Building combined 32/64-bit binaries"
+else
+ echo "Building 64-bit binaries"
+fi
+
echo "Using basedir:" $BASEDIR
mkdir -p $SRCDIR $DEPLOYDIR
build_qt 4.8.4
build_eigen 3.1.2
build_gmp 5.1.1
-build_mpfr 3.1.1
+build_mpfr 3.1.2
build_boost 1.53.0
# NB! For CGAL, also update the actual download URL in the function
build_cgal 4.1
diff --git a/scripts/mingw-x-build-dependencies.sh b/scripts/mingw-x-build-dependencies.sh
index ee51848..e9f124b 100755
--- a/scripts/mingw-x-build-dependencies.sh
+++ b/scripts/mingw-x-build-dependencies.sh
@@ -1,11 +1,13 @@
#!/bin/sh -e
#
# This script builds all library dependencies of OpenSCAD for cross-compilation
-# from linux to mingw32 for windows, using the MXE cross build system.
+# from linux to mingw32/64 for windows, using the MXE cross build system.
#
# This script must be run from the OpenSCAD source root directory
#
-# Usage: ./scripts/mingw-x-build-dependencies.sh
+# Usage:
+# ./scripts/mingw-x-build-dependencies.sh # 32 bit
+# ./scripts/mingw-x-build-dependencies.sh 64 # 64 bit
#
# Prerequisites:
#
@@ -13,6 +15,8 @@
#
# Also see http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Cross-compiling_for_Windows_on_Linux_or_Mac_OS_X
#
+# Also note the 64 bit is built on the branch of mxe by Tony Theodore
+# which hasnt been merged to official mxe as of writing
OPENSCADDIR=$PWD
if [ ! -f $OPENSCADDIR/openscad.pro ]; then
@@ -34,7 +38,7 @@ if [ ! $NUMJOBS ]; then
fi
fi
-. ./scripts/setenv-mingw-xbuild.sh
+. ./scripts/setenv-mingw-xbuild.sh $*
if [ ! -e $BASEDIR ]; then
mkdir -p $BASEDIR
@@ -44,14 +48,24 @@ if [ ! -e $MXEDIR ]; then
mkdir -p $MXEDIR
cd $MXEDIR/..
echo "Downloading MXE into " $PWD
- git clone git://github.com/mxe/mxe.git
+ if [ "`echo $* | grep 64`" ]; then
+ git clone -b multi-rebase git://github.com/tonytheodore/mxe.git $MXEDIR
+ else
+ git clone git://github.com/mxe/mxe.git $MXEDIR
+ fi
fi
echo "entering" $MXEDIR
cd $MXEDIR
-echo "make mpfr eigen opencsg cgal qt -j $NUMCPU JOBS=$NUMJOBS"
-make mpfr eigen opencsg cgal qt nsis -j $NUMCPU JOBS=$NUMJOBS
-#make mpfr -j $NUMCPU JOBS=$NUMJOBS # for testing
+if [ "`echo $* | grep 64`" ]; then
+ MXE_TARGETS='x86_64-w64-mingw32'
+ PACKAGES='mpfr eigen opencsg cgal qt'
+else
+ MXE_TARGETS=
+ PACKAGES='mpfr eigen opencsg cgal qt nsis'
+fi
+echo make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS
+make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS
echo "leaving" $MXEDIR
diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh
index 3aeeaf9..a3b0090 100755
--- a/scripts/publish-macosx.sh
+++ b/scripts/publish-macosx.sh
@@ -3,6 +3,41 @@
# NB! To build a release build, the VERSION and VERSIONDATE environment variables needs to be set.
# See doc/release-checklist.txt
+human_filesize()
+{
+ awk -v sum=$1 'BEGIN {
+ hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB";
+ for (x=1024**3; x>=1024; x/=1024) {
+ if (sum>=x) { printf "%.1f %s\n",sum/x,hum[x]; break }
+ }
+ }'
+}
+
+# Pass version=<version> packagefile=<packagefile> filesize=<bytes>
+update_www_download_links()
+{
+ # Make the passed variables available
+ local $*
+ filesize=$(human_filesize $filesize)
+ webdir=../openscad.github.com
+ incfile=inc/mac_snapshot_links.js
+ BASEURL='https://openscad.googlecode.com/files/'
+ DATECODE=`date +"%Y.%m.%d"`
+
+ if [ -f $webdir/$incfile ]; then
+ cd $webdir
+ echo "snapinfo['MAC_SNAPSHOT_URL'] = '$BASEURL$packagefile'" > $incfile
+ echo "snapinfo['MAC_SNAPSHOT_NAME'] = 'OpenSCAD $version'" >> $incfile
+ echo "snapinfo['MAC_SNAPSHOT_SIZE'] = '$filesize'" >> $incfile
+ echo 'modified mac_snapshot_links.js'
+
+ git --no-pager diff
+ echo "Web page updated. Remember to commit and push openscad.github.com"
+ else
+ echo "Web page not found at $incfile"
+ fi
+}
+
if test -z "$VERSIONDATE"; then
VERSIONDATE=`date "+%Y.%m.%d"`
fi
@@ -40,7 +75,8 @@ else
APPCASTFILE=appcast.xml
fi
echo "Creating appcast $APPCASTFILE..."
-sed -e "s,@VERSION@,$VERSION,g" -e "s,@VERSIONDATE@,$VERSIONDATE,g" -e "s,@DSASIGNATURE@,$SIGNATURE,g" -e "s,@FILESIZE@,$(stat -f "%z" OpenSCAD-$VERSION.dmg),g" $APPCASTFILE.in > $APPCASTFILE
+FILESIZE=$(stat -f "%z" OpenSCAD-$VERSION.dmg)
+sed -e "s,@VERSION@,$VERSION,g" -e "s,@VERSIONDATE@,$VERSIONDATE,g" -e "s,@DSASIGNATURE@,$SIGNATURE,g" -e "s,@FILESIZE@,$FILESIZE,g" $APPCASTFILE.in > $APPCASTFILE
cp $APPCASTFILE ../openscad.github.com
if [[ $VERSION == $VERSIONDATE ]]; then
cp $APPCASTFILE ../openscad.github.com/appcast-snapshots.xml
@@ -50,6 +86,9 @@ echo "Uploading..."
LABELS=OpSys-OSX,Type-Executable
if ! $SNAPSHOT; then LABELS=$LABELS,Featured; fi
`dirname $0`/googlecode_upload.py -s 'Mac OS X Snapshot' -p openscad OpenSCAD-$VERSION.dmg -l $LABELS
+if [[ $? != 0 ]]; then
+ exit 1
+fi
# Update snapshot filename on web page
-`dirname $0`/update-web.sh OpenSCAD-$VERSION.dmg
+update_www_download_links version=$VERSION packagefile=OpenSCAD-$VERSION.dmg filesize=$FILESIZE
diff --git a/scripts/release-common.sh b/scripts/release-common.sh
index 10a1c18..7d36907 100755
--- a/scripts/release-common.sh
+++ b/scripts/release-common.sh
@@ -7,11 +7,12 @@
# The script will create a file called openscad-<versionstring>.<extension> in
# the current directory (or under ./mingw32)
#
-# Usage: release-common.sh [-v <versionstring>] [-c] [-x32]
+# Usage: release-common.sh [-v <versionstring>] [-c] [-mingw[32|64]]
# -v Version string (e.g. -v 2010.01)
# -d Version date (e.g. -d 2010.01.23)
# -c Build with commit info
# -mingw32 Cross-compile for win32 using MXE
+# -mingw64 Cross-compile for win64 using Tony Theodore's MXE fork
#
# If no version string or version date is given, todays date will be used (YYYY-MM-DD)
# If only verion date is given, it will be used also as version string.
@@ -20,7 +21,7 @@
# The commit info will extracted from git and be passed to qmake as OPENSCAD_COMMIT
# to identify a build in the about box.
#
-# The mingw32 cross compile depends on the MXE cross-build tools. Please
+# The mingw cross compile depends on the MXE cross-build tools. Please
# see the README.md file on how to install these dependencies.
printUsage()
@@ -47,11 +48,19 @@ elif [[ $OSTYPE == "linux-gnu" ]]; then
else
ARCH=32
fi
- echo "Detected ARCH: $ARCH"
+ echo "Detected build-machine ARCH: $ARCH"
fi
if [ "`echo $* | grep mingw32`" ]; then
OS=LINXWIN
+ ARCH=32
+ echo Mingw-cross build using ARCH=32
+fi
+
+if [ "`echo $* | grep mingw64`" ]; then
+ OS=LINXWIN
+ ARCH=64
+ echo Mingw-cross build using ARCH=64
fi
if [ $OS ]; then
@@ -83,7 +92,6 @@ echo "Checking pre-requisites..."
case $OS in
LINXWIN)
MAKENSIS=
-
if [ "`command -v makensis`" ]; then
MAKENSIS=makensis
elif [ "`command -v i686-pc-mingw32-makensis`" ]; then
@@ -110,6 +118,13 @@ fi
echo "Building openscad-$VERSION ($VERSIONDATE) $CONFIGURATION..."
+if [ ! $NUMCPU ]; then
+ echo "note: you can 'export NUMCPU=x' for multi-core compiles (x=number)";
+ NUMCPU=2
+else
+ echo "NUMCPU: " $NUMCPU
+fi
+
CONFIG=deploy
case $OS in
LINUX|MACOSX)
@@ -124,17 +139,17 @@ case $OS in
TARGET=release
;;
LINXWIN)
- . ./scripts/setenv-mingw-xbuild.sh
+ . ./scripts/setenv-mingw-xbuild.sh $ARCH
TARGET=release
ZIP="zip"
- ZIPARGS="-r"
+ ZIPARGS="-r -q"
;;
esac
case $OS in
LINXWIN)
- cd $DEPLOYDIR && i686-pc-mingw32-qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+=$CONFIG CONFIG+=mingw-cross-env CONFIG-=debug ../openscad.pro
+ cd $DEPLOYDIR && qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+=$CONFIG CONFIG+=mingw-cross-env CONFIG-=debug ../openscad.pro
cd $OPENSCADDIR
;;
*)
@@ -144,7 +159,8 @@ esac
case $OS in
LINXWIN)
- cd $DEPLOYDIR && make -s clean
+ cd $DEPLOYDIR
+ make clean ## comment out for test-run
cd $OPENSCADDIR
;;
*)
@@ -162,21 +178,22 @@ case $OS in
;;
esac
-if [ ! $NUMCPU ]; then
- echo "note: you can 'export NUMCPU=x' for multi-core compiles (x=number)";
- NUMCPU=2
-fi
-
case $OS in
LINXWIN)
- # dont use paralell builds, it can error-out on parser_yacc.
-
# make main openscad.exe
- cd $DEPLOYDIR && make $TARGET
-
+ cd $DEPLOYDIR
+ make $TARGET -j$NUMCPU ## comment 4 test
+ if [ ! -e $TARGET/openscad.exe ]; then
+ echo "cant find $TARGET/openscad.exe. build failed. stopping."
+ exit
+ fi
# make console pipe-able openscad.com - see winconsole.pri for info
- i686-pc-mingw32-qmake CONFIG+=winconsole ../openscad.pro
+ qmake CONFIG+=winconsole ../openscad.pro
make
+ if [ ! -e $TARGET/openscad.com ]; then
+ echo "cant find $TARGET/openscad.com. build failed. stopping."
+ exit
+ fi
cd $OPENSCADDIR
;;
@@ -245,36 +262,40 @@ case $OS in
cp win32deps/* openscad-$VERSION
cp $TARGET/openscad.exe openscad-$VERSION
cp $TARGET/openscad.com openscad-$VERSION
- rm -f openscad-$VERSION.zip
- "$ZIP" $ZIPARGS openscad-$VERSION.zip openscad-$VERSION
+ rm -f openscad-$VERSION.x86-$ARCH.zip
+ "$ZIP" $ZIPARGS openscad-$VERSION.x86-$ARCH.zip openscad-$VERSION
rm -rf openscad-$VERSION
echo "Binary created: openscad-$VERSION.zip"
;;
LINXWIN)
+ BINFILE=$DEPLOYDIR/OpenSCAD-$VERSION-x86-$ARCH.zip
+ INSTFILE=$DEPLOYDIR/OpenSCAD-$VERSION-x86-$ARCH-Installer.exe
+
#package
- echo "Creating binary package"
+ echo "Creating binary zip package"
cd $DEPLOYDIR
cp $TARGET/openscad.exe openscad-$VERSION
cp $TARGET/openscad.com openscad-$VERSION
- rm -f OpenSCAD-$VERSION.zip
- "$ZIP" $ZIPARGS OpenSCAD-$VERSION.zip openscad-$VERSION
+ rm -f OpenSCAD-$VERSION.x86-$ARCH.zip
+ "$ZIP" $ZIPARGS $BINFILE openscad-$VERSION
cd $OPENSCADDIR
- echo "Binary package created"
+ echo "Binary zip package created"
echo "Creating installer"
echo "Copying NSIS files to $DEPLOYDIR/openscad-$VERSION"
- cp ./scripts/installer.nsi $DEPLOYDIR/openscad-$VERSION
- cp ./scripts/mingw-file-association.nsh $DEPLOYDIR/openscad-$VERSION
+ cp ./scripts/installer$ARCH.nsi $DEPLOYDIR/openscad-$VERSION/installer_arch.nsi
+ cp ./scripts/installer.nsi $DEPLOYDIR/openscad-$VERSION/
+ cp ./scripts/mingw-file-association.nsh $DEPLOYDIR/openscad-$VERSION/
+ cp ./scripts/x64.nsh $DEPLOYDIR/openscad-$VERSION/
+ cp ./scripts/LogicLib.nsh $DEPLOYDIR/openscad-$VERSION/
cd $DEPLOYDIR/openscad-$VERSION
NSISDEBUG=-V2
# NSISDEBUG= # leave blank for full log
echo $MAKENSIS $NSISDEBUG installer.nsi
$MAKENSIS $NSISDEBUG installer.nsi
- cp $DEPLOYDIR/openscad-$VERSION/openscad_setup.exe $DEPLOYDIR/OpenSCAD-$VERSION-Installer.exe
+ cp $DEPLOYDIR/openscad-$VERSION/openscad_setup.exe $INSTFILE
cd $OPENSCADDIR
- BINFILE=$DEPLOYDIR/OpenSCAD-$VERSION.zip
- INSTFILE=$DEPLOYDIR/OpenSCAD-$VERSION-Installer.exe
if [ -e $BINFILE ]; then
if [ -e $INSTFILE ]; then
echo
@@ -282,12 +303,11 @@ case $OS in
echo "Installer created:" $INSTFILE
echo
else
- echo "Build failed. Cannot find" $INSTFILE
- exit 1
+ echo "Build failed. Cannot find" $INSTFILE
fi
else
- echo "Build failed. Cannot find" $BINFILE
- exit 1
+ echo "Build failed. Cannot find" $BINFILE
+ exit 1
fi
;;
LINUX)
diff --git a/scripts/setenv-mingw-xbuild.sh b/scripts/setenv-mingw-xbuild.sh
index e8976b7..d3a014c 100644
--- a/scripts/setenv-mingw-xbuild.sh
+++ b/scripts/setenv-mingw-xbuild.sh
@@ -2,7 +2,10 @@
#
# set environment variables for mingw/mxe cross-build
#
-# Usage: source ./scripts/setenv-mingw-xbuild.sh
+# Usage:
+#
+# source ./scripts/setenv-mingw-xbuild.sh # 32 bit build
+# source ./scripts/setenv-mingw-xbuild.sh 64 # 64 bit build
#
# Prerequisites:
#
@@ -11,33 +14,83 @@
# Also see http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Cross-compiling_for_Windows_on_Linux_or_Mac_OS_X
#
-export OPENSCADDIR=$PWD
+OPENSCADDIR=$PWD
if [ ! $BASEDIR ]; then
- export BASEDIR=$HOME/openscad_deps
+ BASEDIR=$HOME/openscad_deps
fi
+DEPLOYDIR64=$OPENSCADDIR/mingw64
+DEPLOYDIR32=$OPENSCADDIR/mingw32
+
if [ ! $DEPLOYDIR ]; then
- export DEPLOYDIR=$OPENSCADDIR/mingw32
+ if [ "`echo $* | grep 64 `" ]; then
+ DEPLOYDIR=$DEPLOYDIR64
+ else
+ DEPLOYDIR=$DEPLOYDIR32
+ fi
fi
if [ ! $MXEDIR ]; then
- export MXEDIR=$BASEDIR/mxe
+ if [ "`echo $* | grep 64 `" ]; then
+ MXEDIR=$BASEDIR/mxe-w64
+ else
+ MXEDIR=$BASEDIR/mxe
+ fi
fi
-export PATH=$MXEDIR/usr/bin:$PATH
-
-echo BASEDIR: $BASEDIR
-echo MXEDIR: $MXEDIR
-echo DEPLOYDIR: $DEPLOYDIR
-echo PATH modified with $MXEDIR/usr/bin
-
if [ ! -e $DEPLOYDIR ]; then
mkdir -p $DEPLOYDIR
fi
-echo linking $MXEDIR/usr/i686-pc-mingw32/ to $DEPLOYDIR/mingw-cross-env
-rm -f $DEPLOYDIR/mingw-cross-env
-ln -s $MXEDIR/usr/i686-pc-mingw32/ $DEPLOYDIR/mingw-cross-env
+if [ "`echo $* | grep 64 `" ]; then
+ MXETARGETDIR=$MXEDIR/usr/x86_64-w64-mingw32
+else
+ MXETARGETDIR=$MXEDIR/usr/i686-pc-mingw32
+fi
+
+if [ ! $MINGWX_SAVED_ORIGINAL_PATH ]; then
+ MINGWX_SAVED_ORIGINAL_PATH=$PATH
+ echo current path saved
+fi
+PATH=$MXEDIR/usr/bin:$PATH
+PATH=$MXETARGETDIR/qt/bin:$PATH
+
+OPENSCAD_LIBRARIES=$MXETARGETDIR
+
+if [ "`echo $* | grep clean`" ]; then
+ OPENSCAD_LIBRARIES=
+ BASEDIR=
+ MXEDIR=
+ MXETARGETDIR=
+ DEPLOYDIR=
+ PATH=$MINGWX_SAVED_ORIGINAL_PATH
+ MINGWX_SAVED_ORIGINAL_PATH=
+else
+ echo 'linking' $MXETARGETDIR
+ echo ' to' $DEPLOYDIR/mingw-cross-env
+ rm -f $DEPLOYDIR/mingw-cross-env
+ ln -s $MXETARGETDIR $DEPLOYDIR/mingw-cross-env
+fi
+
+export OPENSCAD_LIBRARIES
+export BASEDIR
+export MXEDIR
+export MXETARGETDIR
+export DEPLOYDIR
+export PATH
+export MINGWX_SAVED_ORIGINAL_PATH
+
+echo OPENSCAD_LIBRARIES: $OPENSCAD_LIBRARIES
+echo BASEDIR: $BASEDIR
+echo MXEDIR: $MXEDIR
+echo MXETARGETDIR: $MXETARGETDIR
+echo DEPLOYDIR: $DEPLOYDIR
+if [ "`echo $* | grep clean`" ]; then
+ echo PATH restored to pre-setenv-mingw-x state
+else
+ echo PATH modified: $MXEDIR/usr/bin
+ echo PATH modified: $MXETARGETDIR/qt/bin
+fi
diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh
index dc61f74..60dbb74 100755
--- a/scripts/uni-build-dependencies.sh
+++ b/scripts/uni-build-dependencies.sh
@@ -264,6 +264,12 @@ build_boost()
echo boost build failed
exit 1
fi
+ if [ "`ls $DEPLOYDIR/include/ | grep boost.[0-9]`" ]; then
+ if [ ! -e $DEPLOYDIR/include/boost ]; then
+ echo "boost is old, make a symlink to $DEPLOYDIR/include/boost & rerun"
+ exit 1
+ fi
+ fi
}
build_cgal()
@@ -276,17 +282,26 @@ build_cgal()
echo "Building CGAL" $version "..."
cd $BASEDIR/src
rm -rf CGAL-$version
- if [ ! -f CGAL-$version.tar.* ]; then
- # 4.1
- curl --insecure -O https://gforge.inria.fr/frs/download.php/31640/CGAL-$version.tar.bz2
- # 4.0.2 curl --insecure -O https://gforge.inria.fr/frs/download.php/31174/CGAL-$version.tar.bz2
- # 4.0 curl --insecure -O https://gforge.inria.fr/frs/download.php/30387/CGAL-$version.tar.gz #4.0
- # 3.9 curl --insecure -O https://gforge.inria.fr/frs/download.php/29125/CGAL-$version.tar.gz #3.9
- # 3.8 curl --insecure -O https://gforge.inria.fr/frs/download.php/28500/CGAL-$version.tar.gz
- # 3.7 curl --insecure -O https://gforge.inria.fr/frs/download.php/27641/CGAL-$version.tar.gz
- fi
- tar xf CGAL-$version.tar.bz2
+ ver4_1="curl --insecure -O https://gforge.inria.fr/frs/download.php/31640/CGAL-4.1.tar.bz2"
+ ver4_0_2="curl --insecure -O https://gforge.inria.fr/frs/download.php/31174/CGAL-4.0.2.tar.bz2"
+ ver4_0="curl --insecure -O https://gforge.inria.fr/frs/download.php/30387/CGAL-4.0.tar.gz"
+ ver3_9="curl --insecure -O https://gforge.inria.fr/frs/download.php/29125/CGAL-3.9.tar.gz"
+ ver3_8="curl --insecure -O https://gforge.inria.fr/frs/download.php/28500/CGAL-3.8.tar.gz"
+ ver3_7="curl --insecure -O https://gforge.inria.fr/frs/download.php/27641/CGAL-3.7.tar.gz"
+ vernull="echo already downloaded..skipping"
+ download_cmd=ver`echo $version | sed s/"\."/"_"/`
+ if [ -e CGAL-$version.tar.gz ]; then download_cmd=vernull; fi
+ if [ -e CGAL-$version.tar.bz2 ]; then download_cmd=vernull; fi
+ `eval echo "$"$download_cmd`
+ if [ -e CGAL-$version.tar.gz ]; then tar xf CGAL-$version.tar.gz; fi
+ if [ -e CGAL-$version.tar.bz2 ]; then tar xf CGAL-$version.tar.bz2; fi
cd CGAL-$version
+
+ # older cmakes have buggy FindBoost that can result in
+ # finding the system libraries but OPENSCAD_LIBRARIES include paths
+ FINDBOOST_CMAKE=$OPENSCAD_SCRIPTDIR/../tests/FindBoost.cmake
+ cp $FINDBOOST_CMAKE ./cmake/modules/
+
mkdir bin
cd bin
rm -rf ./*
@@ -295,10 +310,13 @@ build_cgal()
else
CGAL_BUILDTYPE="Debug"
fi
+
+ DEBUGBOOSTFIND=0 # for debugging FindBoost.cmake (not for debugging boost)
+ Boost_NO_SYSTEM_PATHS=1
if [ "`echo $2 | grep use-sys-libs`" ]; then
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DCMAKE_BUILD_TYPE=$CGAL_BUILDTYPE ..
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DCMAKE_BUILD_TYPE=$CGAL_BUILDTYPE -DBoost_DEBUG=$DEBUGBOOSTFIND ..
else
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_ROOT=$DEPLOYDIR -DBoost_USE_MULTITHREADED=false -DCMAKE_BUILD_TYPE=$CGAL_BUILD_TYPE ..
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_LIBRARYDIR=$DEPLOYDIR/lib -DBOOST_INCLUDEDIR=$DEPLOYDIR/include -DCMAKE_BUILD_TYPE=$CGAL_BUILD_TYPE -DBoost_DEBUG=$DEBUGBOOSTFIND -DBoost_NO_SYSTEM_PATHS=1 ..
fi
make -j$NUMCPU
make install
@@ -390,8 +408,21 @@ build_opencsg()
OPENCSG_QMAKE=qmake-qt4
elif [ "`command -v qmake4`" ]; then
OPENCSG_QMAKE=qmake4
- else
+ elif [ "`command -v qmake`" ]; then
OPENCSG_QMAKE=qmake
+ else
+ echo qmake not found... using standard OpenCSG makefiles
+ OPENCSG_QMAKE=make
+ cp Makefile Makefile.bak
+ cp src/Makefile src/Makefile.bak
+
+ cat Makefile.bak | sed s/example// |sed s/glew// > Makefile
+ cat src/Makefile.bak | sed s@^INCPATH.*@INCPATH\ =\ -I$BASEDIR/include\ -I../include\ -I..\ -I.@ > src/Makefile
+ cp src/Makefile src/Makefile.bak2
+ cat src/Makefile.bak2 | sed s@^LIBS.*@LIBS\ =\ -L$BASEDIR/lib\ -L/usr/X11R6/lib\ -lGLU\ -lGL@ > src/Makefile
+ tmp=$version
+ build_glu 9.0.0 # todo - autodetect the need for glu
+ version=$tmp
fi
cd $BASEDIR/src/OpenCSG-$version/src
@@ -459,7 +490,11 @@ build_eigen()
# the 'dirname' command installed
if [ "`command -v dirname`" ]; then
+ RUNDIR=$PWD
OPENSCAD_SCRIPTDIR=`dirname $0`
+ cd $OPENSCAD_SCRIPTDIR
+ OPENSCAD_SCRIPTDIR=$PWD
+ cd $RUNDIR
else
if [ ! -f openscad.pro ]; then
echo "Must be run from the OpenSCAD source root directory (dont have 'dirname')"
@@ -513,7 +548,7 @@ if [ $1 ]; then
exit $?
fi
if [ $1 = "cgal" ]; then
- build_cgal 4.0.2 use-sys-libs
+ build_cgal 4.1 use-sys-libs
exit $?
fi
if [ $1 = "opencsg" ]; then
@@ -540,7 +575,7 @@ fi
build_eigen 3.1.1
build_gmp 5.0.5
build_mpfr 3.1.1
-build_boost 1.49.0
+build_boost 1.53.0
# NB! For CGAL, also update the actual download URL in the function
build_cgal 4.1
build_glew 1.9.0
diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh
index 98170de..e2fdaa7 100755
--- a/scripts/uni-get-dependencies.sh
+++ b/scripts/uni-get-dependencies.sh
@@ -7,7 +7,8 @@
get_fedora_deps()
{
sudo yum install qt-devel bison flex eigen2-devel python-paramiko \
- boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc pkgconfig git libXmu-devel
+ boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc pkgconfig \
+ git libXmu-devel curl imagemagick
}
get_qomo_deps()
@@ -19,7 +20,7 @@ get_altlinux_deps()
{
for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \
boost-thread-devel boost-system-devel boost-regex-devel eigen2 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
- libglew-devel flex bison; do sudo apt-get install $i; done
+ libglew-devel flex bison curl imagemagick; do sudo apt-get install $i; done
}
get_freebsd_deps()
@@ -27,19 +28,19 @@ get_freebsd_deps()
pkg_add -r bison boost-libs cmake git bash eigen2 flex gmake gmp mpfr \
xorg libGLU libXmu libXi xorg-vfbserver glew \
qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \
- opencsg cgal
+ opencsg cgal curl imagemagick
}
get_netbsd_deps()
{
sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
- qt4 glew cgal opencsg modular-xorg python27 py27-paramiko
+ qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl imagemagick
}
get_opensuse_deps()
{
sudo zypper install libeigen2-devel mpfr-devel gmp-devel boost-devel \
- libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel
+ libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl
}
get_mageia_deps()
@@ -56,7 +57,7 @@ get_debian_deps()
libxmu-dev cmake bison flex git-core libboost-all-dev \
libXi-dev libmpfr-dev libboost-dev libglew-dev libeigen2-dev \
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
- python-paramiko ; do
+ python-paramiko curl imagemagick; do
sudo apt-get -y install $pkg;
done
}
diff --git a/scripts/x64.nsh b/scripts/x64.nsh
new file mode 100644
index 0000000..e694c1e
--- /dev/null
+++ b/scripts/x64.nsh
@@ -0,0 +1,54 @@
+; ---------------------
+; x64.nsh
+; ---------------------
+;
+; A few simple macros to handle installations on x64 machines.
+;
+; RunningX64 checks if the installer is running on x64.
+;
+; ${If} ${RunningX64}
+; MessageBox MB_OK "running on x64"
+; ${EndIf}
+;
+; DisableX64FSRedirection disables file system redirection.
+; EnableX64FSRedirection enables file system redirection.
+;
+; SetOutPath $SYSDIR
+; ${DisableX64FSRedirection}
+; File some.dll # extracts to C:\Windows\System32
+; ${EnableX64FSRedirection}
+; File some.dll # extracts to C:\Windows\SysWOW64
+;
+
+!ifndef ___X64__NSH___
+!define ___X64__NSH___
+
+!include LogicLib.nsh
+
+!macro _RunningX64 _a _b _t _f
+ !insertmacro _LOGICLIB_TEMP
+ System::Call kernel32::GetCurrentProcess()i.s
+ System::Call kernel32::IsWow64Process(is,*i.s)
+ Pop $_LOGICLIB_TEMP
+ !insertmacro _!= $_LOGICLIB_TEMP 0 `${_t}` `${_f}`
+!macroend
+
+!define RunningX64 `"" RunningX64 ""`
+
+!macro DisableX64FSRedirection
+
+ System::Call kernel32::Wow64EnableWow64FsRedirection(i0)
+
+!macroend
+
+!define DisableX64FSRedirection "!insertmacro DisableX64FSRedirection"
+
+!macro EnableX64FSRedirection
+
+ System::Call kernel32::Wow64EnableWow64FsRedirection(i1)
+
+!macroend
+
+!define EnableX64FSRedirection "!insertmacro EnableX64FSRedirection"
+
+!endif # !___X64__NSH___
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;
}
diff --git a/testdata/scad/features/child-child-test.scad b/testdata/scad/features/child-child-test.scad
new file mode 100644
index 0000000..e5e6d93
--- /dev/null
+++ b/testdata/scad/features/child-child-test.scad
@@ -0,0 +1,12 @@
+module up() {
+ translate([0,0,1]) child(0);
+}
+
+module red() {
+ color("Red") child(0);
+}
+
+up() cylinder(r=5);
+translate([5,0,0]) up() up() cylinder(r=5);
+translate([10,0,0]) up() up() up() red() cylinder(r=5);
+translate([15,0,0]) red() up() up() up() up() cylinder(r=5);
diff --git a/testdata/scad/features/child-tests.scad b/testdata/scad/features/child-tests.scad
index e4e3572..cf983b4 100644
--- a/testdata/scad/features/child-tests.scad
+++ b/testdata/scad/features/child-tests.scad
@@ -1,7 +1,7 @@
$fn=16;
-module parent() {
- for (i=[0:2]) {
+module parent(range=[0:2]) {
+ for (i=range) {
translate([2.5*i,0,0]) child(i);
}
}
@@ -32,3 +32,6 @@ module parent3() {
}
translate([5,3,0]) parent3() { cube(); sphere(); }
+
+// Leaking variables to child list is not allowed
+translate([0,6,0]) parent(range=[0:1], testvar=10) { sphere(); cube(testvar, center=true);}
diff --git a/testdata/scad/features/hull2-tests.scad b/testdata/scad/features/hull2-tests.scad
index e656e6a..82b56e4 100644
--- a/testdata/scad/features/hull2-tests.scad
+++ b/testdata/scad/features/hull2-tests.scad
@@ -31,7 +31,15 @@ module hull2dForLoop() {
}
}
+module hull2null() {
+ hull() {
+ square(0);
+ circle(0);
+ }
+}
+
convex2dHole();
translate([40,0,0]) convex2dSimple();
translate([0,-20,0]) concave2dSimple();
translate([30,-25,0]) hull2dForLoop();
+hull2null(); \ No newline at end of file
diff --git a/testdata/scad/features/hull3-tests.scad b/testdata/scad/features/hull3-tests.scad
index e3fc8e7..0f48b8f 100644
--- a/testdata/scad/features/hull3-tests.scad
+++ b/testdata/scad/features/hull3-tests.scad
@@ -26,3 +26,12 @@ translate([-5,-5,-5]) {
}
}
}
+
+module hull3null() {
+ hull() {
+ cube(0);
+ sphere(0);
+ }
+}
+hull3null();
+
diff --git a/testdata/scad/features/linear_extrude-scale-zero-tests.scad b/testdata/scad/features/linear_extrude-scale-zero-tests.scad
new file mode 100644
index 0000000..8a85203
--- /dev/null
+++ b/testdata/scad/features/linear_extrude-scale-zero-tests.scad
@@ -0,0 +1,56 @@
+// test cases for linear extrude with scale
+// by TakeItAndRun 2013
+
+// syntax: linear_extrude(height=a, slices=b, twist=c, scale=[x,y])
+
+a=3;
+b=20;
+c=0;
+x=1;
+y=1;
+
+module linear_extrudes_of_different_shapes(a=a,b=b,c=c,x=x,y=y) {
+ translate(00*[4,0,0])
+ // linear_extrude of shape with hole
+ linear_extrude(height=a, slices=b, twist=c, scale=[x,y])
+ difference() {
+ square(2,true); square(1,true);
+ }
+
+ translate(01*[4,0,0])
+ // linear_extrude of disjoint polygons shapes
+ linear_extrude(height=a, slices=b, twist=c, scale=[x,y]) {
+ translate([1,0,0]) square(1,true);
+ translate([-1,0,0]) square(1,true);
+ }
+
+ translate(02*[4,0,0])
+ // linear_extrude with a coplanar face
+ linear_extrude(height=a, slices=b, twist=c, scale=[x,y]) {
+ translate([.5,0,0])square();
+ translate([-.5,0,0])square();
+ }
+
+ translate(03*[4,0,0])
+ // linear_extrude with internal hole and one coplanar edge
+ linear_extrude(height=a, slices=b, twist=c, scale=[x,y])
+ difference() {
+ square(2,true);
+ translate([-0.5,0,0]) square(1,true);
+ }
+}
+
+
+// Test varying parameters
+translate(00*[0,3,0])
+linear_extrudes_of_different_shapes(c=0,x=0,y=y);
+translate(01*[0,3,0])
+linear_extrudes_of_different_shapes(c=0,x=x,y=0);
+translate(02*[0,3,0])
+linear_extrudes_of_different_shapes(c=0,x=0,y=0);
+translate(03*[0,3,0])
+linear_extrudes_of_different_shapes(c=180,x=0,y=y);
+translate(04*[0,3,0])
+linear_extrudes_of_different_shapes(c=180,x=x,y=0);
+translate(05*[0,3,0])
+linear_extrudes_of_different_shapes(c=180,x=0,y=0);
diff --git a/testdata/scad/features/linear_extrude-tests.scad b/testdata/scad/features/linear_extrude-tests.scad
index 67de8e6..528eea2 100644
--- a/testdata/scad/features/linear_extrude-tests.scad
+++ b/testdata/scad/features/linear_extrude-tests.scad
@@ -11,3 +11,14 @@ translate([31.5,2.5,0]) linear_extrude(height=10, twist=-45) polygon(points = [[
translate([0,20,0]) linear_extrude(height=20, twist=45, slices=2) square([10,10]);
translate([19,20,0]) linear_extrude(height=20, twist=45, slices=10) square([10,10]);
+
+translate([0,-15,0]) linear_extrude(5) square([10,10]);
+
+// scale given as a scalar
+translate([-25,-10,0]) linear_extrude(height=10, scale=2) square(5, center=true);
+// scale given as a 3-dim vector
+translate([-15,20,0]) linear_extrude(height=20, scale=[4,5,6]) square(10);
+// scale is negative
+translate([-10,5,0]) linear_extrude(height=15, scale=-2) square(10, center=true);
+// scale given as undefined
+translate([-15,-15,0]) linear_extrude(height=10, scale=var_undef) square(10);
diff --git a/testdata/scad/features/module-recursion.scad b/testdata/scad/features/module-recursion.scad
new file mode 100644
index 0000000..f67a1d0
--- /dev/null
+++ b/testdata/scad/features/module-recursion.scad
@@ -0,0 +1,15 @@
+module tree(currentScale, levels)
+{
+ h = currentScale;
+ w = currentScale/5;
+ childScale = currentScale * 0.7;
+
+ if (levels > 0) {
+ cylinder(r=w, h=h);
+ translate([0,0,h]) for (i = [1:2]) {
+ rotate([40, 0, i * 180]) tree(childScale, levels-1);
+ }
+ }
+}
+
+tree(1, 4);
diff --git a/testdata/scad/features/modulevariables.scad b/testdata/scad/features/modulevariables.scad
new file mode 100644
index 0000000..fc7a183
--- /dev/null
+++ b/testdata/scad/features/modulevariables.scad
@@ -0,0 +1,7 @@
+module mymodule(modparam) {
+ inner_variable = 23;
+ inner_variable2 = modparam * 2;
+ cylinder(r1=inner_variable, r2=inner_variable2, h=10);
+}
+
+mymodule(5);
diff --git a/testdata/scad/features/surface-simple.dat b/testdata/scad/features/surface-simple.dat
index 32eba08..166c600 100644
--- a/testdata/scad/features/surface-simple.dat
+++ b/testdata/scad/features/surface-simple.dat
@@ -1,2 +1,6 @@
0 1
2 3
+
+# Comment
+
+
diff --git a/testdata/scad/features/surface-simple.scad b/testdata/scad/features/surface-simple.scad
index 9659143..1215a0b 100644
--- a/testdata/scad/features/surface-simple.scad
+++ b/testdata/scad/features/surface-simple.scad
@@ -1 +1,3 @@
surface("surface-simple.dat", center=true);
+// Surface without a trailing newline
+translate([2,0,0]) surface("surface-simple2.dat", center=true);
diff --git a/testdata/scad/features/surface-simple2.dat b/testdata/scad/features/surface-simple2.dat
new file mode 100644
index 0000000..a711970
--- /dev/null
+++ b/testdata/scad/features/surface-simple2.dat
@@ -0,0 +1,3 @@
+# Surface without a trailing newline
+0 1
+2 3 \ No newline at end of file
diff --git a/testdata/scad/misc/localfiles-test.scad b/testdata/scad/misc/localfiles-test.scad
new file mode 100644
index 0000000..31efe96
--- /dev/null
+++ b/testdata/scad/misc/localfiles-test.scad
@@ -0,0 +1,3 @@
+use <localfiles_dir/localfiles_module.scad>
+
+localfiles_module();
diff --git a/testdata/scad/misc/localfiles_dir/localfile.dat b/testdata/scad/misc/localfiles_dir/localfile.dat
new file mode 100644
index 0000000..32eba08
--- /dev/null
+++ b/testdata/scad/misc/localfiles_dir/localfile.dat
@@ -0,0 +1,2 @@
+0 1
+2 3
diff --git a/testdata/scad/misc/localfiles_dir/localfile.dxf b/testdata/scad/misc/localfiles_dir/localfile.dxf
new file mode 100644
index 0000000..933e263
--- /dev/null
+++ b/testdata/scad/misc/localfiles_dir/localfile.dxf
@@ -0,0 +1,1968 @@
+999
+dxflib 2.2.0.0
+ 0
+SECTION
+ 2
+HEADER
+ 9
+$ACADVER
+ 1
+AC1015
+ 9
+$HANDSEED
+ 5
+FFFF
+ 9
+$DIMASZ
+ 40
+2.5
+ 9
+$PLIMMIN
+ 10
+0.0
+ 20
+0.0
+ 9
+$DIMEXE
+ 40
+1.25
+ 9
+$DIMGAP
+ 40
+0.625
+ 9
+$PLIMMAX
+ 10
+210.0
+ 20
+297.0
+ 9
+$INSUNITS
+ 70
+4
+ 9
+$DIMSTYLE
+ 2
+Standard
+ 9
+$CLAYER
+ 8
+0
+ 9
+$DIMEXO
+ 40
+0.625
+ 9
+$DIMTXT
+ 40
+2.5
+ 9
+$CLAYER
+ 8
+0
+ 0
+ENDSEC
+ 0
+SECTION
+ 2
+TABLES
+ 0
+TABLE
+ 2
+VPORT
+ 5
+8
+100
+AcDbSymbolTable
+ 70
+1
+ 0
+VPORT
+ 5
+30
+100
+AcDbSymbolTableRecord
+100
+AcDbViewportTableRecord
+ 2
+*Active
+ 70
+0
+ 10
+0.0
+ 20
+0.0
+ 11
+1.0
+ 21
+1.0
+ 12
+286.3055555555554861
+ 22
+148.5
+ 13
+0.0
+ 23
+0.0
+ 14
+10.0
+ 24
+10.0
+ 15
+10.0
+ 25
+10.0
+ 16
+0.0
+ 26
+0.0
+ 36
+1.0
+ 17
+0.0
+ 27
+0.0
+ 37
+0.0
+ 40
+297.0
+ 41
+1.92798353909465
+ 42
+50.0
+ 43
+0.0
+ 44
+0.0
+ 50
+0.0
+ 51
+0.0
+ 71
+0
+ 72
+100
+ 73
+1
+ 74
+3
+ 75
+1
+ 76
+1
+ 77
+0
+ 78
+0
+281
+0
+ 65
+1
+110
+0.0
+120
+0.0
+130
+0.0
+111
+1.0
+121
+0.0
+131
+0.0
+112
+0.0
+122
+1.0
+132
+0.0
+ 79
+0
+146
+0.0
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+LTYPE
+ 5
+5
+100
+AcDbSymbolTable
+ 70
+21
+ 0
+LTYPE
+ 5
+14
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+ByBlock
+ 70
+0
+ 3
+
+ 72
+65
+ 73
+0
+ 40
+0.0
+ 0
+LTYPE
+ 5
+15
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+ByLayer
+ 70
+0
+ 3
+
+ 72
+65
+ 73
+0
+ 40
+0.0
+ 0
+LTYPE
+ 5
+16
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+CONTINUOUS
+ 70
+0
+ 3
+Solid line
+ 72
+65
+ 73
+0
+ 40
+0.0
+ 0
+LTYPE
+ 5
+31
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DOT
+ 70
+0
+ 3
+Dot . . . . . . . . . . . . . . . . . . . . . .
+ 72
+65
+ 73
+2
+ 40
+6.3499999999999996
+ 49
+0.0
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+32
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DOT2
+ 70
+0
+ 3
+Dot (.5x) .....................................
+ 72
+65
+ 73
+2
+ 40
+3.1749999999999998
+ 49
+0.0
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+33
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DOTX2
+ 70
+0
+ 3
+Dot (2x) . . . . . . . . . . . . .
+ 72
+65
+ 73
+2
+ 40
+12.6999999999999993
+ 49
+0.0
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+LTYPE
+ 5
+34
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHED
+ 70
+0
+ 3
+Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _
+ 72
+65
+ 73
+2
+ 40
+19.0500000000000007
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+35
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHED2
+ 70
+0
+ 3
+Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ 72
+65
+ 73
+2
+ 40
+9.5250000000000004
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+36
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHEDX2
+ 70
+0
+ 3
+Dashed (2x) ____ ____ ____ ____ ____ ___
+ 72
+65
+ 73
+2
+ 40
+38.1000000000000014
+ 49
+25.3999999999999986
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+LTYPE
+ 5
+37
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHDOT
+ 70
+0
+ 3
+Dash dot __ . __ . __ . __ . __ . __ . __ . __
+ 72
+65
+ 73
+4
+ 40
+25.3999999999999986
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+38
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHDOT2
+ 70
+0
+ 3
+Dash dot (.5x) _._._._._._._._._._._._._._._.
+ 72
+65
+ 73
+4
+ 40
+12.6999999999999993
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+39
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DASHDOTX2
+ 70
+0
+ 3
+Dash dot (2x) ____ . ____ . ____ . ___
+ 72
+65
+ 73
+4
+ 40
+50.7999999999999972
+ 49
+25.3999999999999986
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+LTYPE
+ 5
+3A
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DIVIDE
+ 70
+0
+ 3
+Divide ____ . . ____ . . ____ . . ____ . . ____
+ 72
+65
+ 73
+6
+ 40
+31.75
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+3B
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DIVIDE2
+ 70
+0
+ 3
+Divide (.5x) __..__..__..__..__..__..__..__.._
+ 72
+65
+ 73
+6
+ 40
+15.875
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+3C
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+DIVIDEX2
+ 70
+0
+ 3
+Divide (2x) ________ . . ________ . . _
+ 72
+65
+ 73
+6
+ 40
+63.5
+ 49
+25.3999999999999986
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+LTYPE
+ 5
+3D
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+CENTER
+ 70
+0
+ 3
+Center ____ _ ____ _ ____ _ ____ _ ____ _ ____
+ 72
+65
+ 73
+4
+ 40
+50.7999999999999972
+ 49
+31.75
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+3E
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+CENTER2
+ 70
+0
+ 3
+Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___
+ 72
+65
+ 73
+4
+ 40
+28.5749999999999993
+ 49
+19.0500000000000007
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+3.1749999999999998
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+3F
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+CENTERX2
+ 70
+0
+ 3
+Center (2x) ________ __ ________ __ _____
+ 72
+65
+ 73
+4
+ 40
+101.5999999999999943
+ 49
+63.5
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+LTYPE
+ 5
+40
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+BORDER
+ 70
+0
+ 3
+Border __ __ . __ __ . __ __ . __ __ . __ __ .
+ 72
+65
+ 73
+6
+ 40
+44.4500000000000028
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+12.6999999999999993
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-6.3499999999999996
+ 74
+0
+ 0
+LTYPE
+ 5
+41
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+BORDER2
+ 70
+0
+ 3
+Border (.5x) __.__.__.__.__.__.__.__.__.__.__.
+ 72
+65
+ 73
+6
+ 40
+22.2250000000000014
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+6.3499999999999996
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-3.1749999999999998
+ 74
+0
+ 0
+LTYPE
+ 5
+42
+100
+AcDbSymbolTableRecord
+100
+AcDbLinetypeTableRecord
+ 2
+BORDERX2
+ 70
+0
+ 3
+Border (2x) ____ ____ . ____ ____ . ___
+ 72
+65
+ 73
+6
+ 40
+88.9000000000000057
+ 49
+25.3999999999999986
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+25.3999999999999986
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 49
+0.0
+ 74
+0
+ 49
+-12.6999999999999993
+ 74
+0
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+LAYER
+ 5
+2
+100
+AcDbSymbolTable
+ 70
+1
+ 0
+LAYER
+ 5
+10
+100
+AcDbSymbolTableRecord
+100
+AcDbLayerTableRecord
+ 2
+0
+ 70
+0
+ 62
+7
+420
+0
+ 6
+CONTINUOUS
+370
+25
+390
+F
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+STYLE
+ 5
+3
+100
+AcDbSymbolTable
+ 70
+1
+ 0
+STYLE
+ 5
+11
+100
+AcDbSymbolTableRecord
+100
+AcDbTextStyleTableRecord
+ 2
+Standard
+ 70
+0
+ 40
+0.0
+ 41
+0.75
+ 50
+0.0
+ 71
+0
+ 42
+2.5
+ 3
+txt
+ 4
+
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+VIEW
+ 5
+6
+100
+AcDbSymbolTable
+ 70
+0
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+UCS
+ 5
+7
+100
+AcDbSymbolTable
+ 70
+0
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+APPID
+ 5
+9
+100
+AcDbSymbolTable
+ 70
+1
+ 0
+APPID
+ 5
+12
+100
+AcDbSymbolTableRecord
+100
+AcDbRegAppTableRecord
+ 2
+ACAD
+ 70
+0
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+DIMSTYLE
+ 5
+A
+100
+AcDbSymbolTable
+ 70
+1
+100
+AcDbDimStyleTable
+ 71
+0
+ 0
+DIMSTYLE
+105
+27
+100
+AcDbSymbolTableRecord
+100
+AcDbDimStyleTableRecord
+ 2
+Standard
+ 41
+2.5
+ 42
+0.625
+ 43
+3.75
+ 44
+1.25
+ 70
+0
+ 73
+0
+ 74
+0
+ 77
+1
+ 78
+8
+140
+2.5
+141
+2.5
+143
+0.03937007874016
+147
+0.625
+171
+3
+172
+1
+271
+2
+272
+2
+274
+3
+278
+44
+283
+0
+284
+8
+340
+11
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+BLOCK_RECORD
+ 5
+1
+100
+AcDbSymbolTable
+ 70
+1
+ 0
+BLOCK_RECORD
+ 5
+1F
+100
+AcDbSymbolTableRecord
+100
+AcDbBlockTableRecord
+ 2
+*Model_Space
+340
+22
+ 0
+BLOCK_RECORD
+ 5
+1B
+100
+AcDbSymbolTableRecord
+100
+AcDbBlockTableRecord
+ 2
+*Paper_Space
+340
+1E
+ 0
+BLOCK_RECORD
+ 5
+23
+100
+AcDbSymbolTableRecord
+100
+AcDbBlockTableRecord
+ 2
+*Paper_Space0
+340
+26
+ 0
+ENDTAB
+ 0
+ENDSEC
+ 0
+SECTION
+ 2
+BLOCKS
+ 0
+BLOCK
+ 5
+20
+100
+AcDbEntity
+ 8
+0
+100
+AcDbBlockBegin
+ 2
+*Model_Space
+ 70
+0
+ 10
+0.0
+ 20
+0.0
+ 30
+0.0
+ 3
+*Model_Space
+ 1
+
+ 0
+ENDBLK
+ 5
+21
+100
+AcDbEntity
+ 8
+0
+100
+AcDbBlockEnd
+ 0
+BLOCK
+ 5
+1C
+100
+AcDbEntity
+ 67
+1
+ 8
+0
+100
+AcDbBlockBegin
+ 2
+*Paper_Space
+ 70
+0
+ 10
+0.0
+ 20
+0.0
+ 30
+0.0
+ 3
+*Paper_Space
+ 1
+
+ 0
+ENDBLK
+ 5
+1D
+100
+AcDbEntity
+ 67
+1
+ 8
+0
+100
+AcDbBlockEnd
+ 0
+BLOCK
+ 5
+24
+100
+AcDbEntity
+ 8
+0
+100
+AcDbBlockBegin
+ 2
+*Paper_Space0
+ 70
+0
+ 10
+0.0
+ 20
+0.0
+ 30
+0.0
+ 3
+*Paper_Space0
+ 1
+
+ 0
+ENDBLK
+ 5
+25
+100
+AcDbEntity
+ 8
+0
+100
+AcDbBlockEnd
+ 0
+ENDSEC
+ 0
+SECTION
+ 2
+ENTITIES
+ 0
+LINE
+ 5
+43
+100
+AcDbEntity
+100
+AcDbLine
+ 8
+0
+ 62
+256
+370
+-1
+ 6
+ByLayer
+ 10
+10.0
+ 20
+100.0
+ 30
+0.0
+ 11
+210.0
+ 21
+100.0
+ 31
+0.0
+ 0
+LINE
+ 5
+44
+100
+AcDbEntity
+100
+AcDbLine
+ 8
+0
+ 62
+256
+370
+-1
+ 6
+ByLayer
+ 10
+210.0
+ 20
+100.0
+ 30
+0.0
+ 11
+210.0
+ 21
+-100.0
+ 31
+0.0
+ 0
+LINE
+ 5
+45
+100
+AcDbEntity
+100
+AcDbLine
+ 8
+0
+ 62
+256
+370
+-1
+ 6
+ByLayer
+ 10
+210.0
+ 20
+-100.0
+ 30
+0.0
+ 11
+10.0
+ 21
+-100.0
+ 31
+0.0
+ 0
+LINE
+ 5
+46
+100
+AcDbEntity
+100
+AcDbLine
+ 8
+0
+ 62
+256
+370
+-1
+ 6
+ByLayer
+ 10
+10.0
+ 20
+-100.0
+ 30
+0.0
+ 11
+10.0
+ 21
+100.0
+ 31
+0.0
+ 0
+DIMENSION
+ 5
+47
+100
+AcDbEntity
+ 8
+0
+ 62
+256
+370
+-1
+ 6
+ByLayer
+100
+AcDbDimension
+ 10
+10.0000000000000018
+ 20
+150.0
+ 30
+0.0
+ 11
+110.0
+ 21
+151.875
+ 31
+0.0
+ 70
+1
+ 71
+5
+ 72
+1
+ 41
+1.0
+ 42
+0.0
+ 1
+localfile
+ 3
+Standard
+100
+AcDbAlignedDimension
+ 13
+10.0
+ 23
+130.0
+ 33
+0.0
+ 14
+210.0
+ 24
+130.0
+ 34
+0.0
+ 0
+ENDSEC
+ 0
+SECTION
+ 2
+OBJECTS
+ 0
+DICTIONARY
+ 5
+C
+100
+AcDbDictionary
+280
+0
+281
+1
+ 3
+ACAD_GROUP
+350
+D
+ 3
+ACAD_LAYOUT
+350
+1A
+ 3
+ACAD_MLINESTYLE
+350
+17
+ 3
+ACAD_PLOTSETTINGS
+350
+19
+ 3
+ACAD_PLOTSTYLENAME
+350
+E
+ 3
+AcDbVariableDictionary
+350
+48
+ 0
+DICTIONARY
+ 5
+D
+100
+AcDbDictionary
+280
+0
+281
+1
+ 0
+ACDBDICTIONARYWDFLT
+ 5
+E
+100
+AcDbDictionary
+281
+1
+ 3
+Normal
+350
+F
+100
+AcDbDictionaryWithDefault
+340
+F
+ 0
+ACDBPLACEHOLDER
+ 5
+F
+ 0
+DICTIONARY
+ 5
+17
+100
+AcDbDictionary
+280
+0
+281
+1
+ 3
+Standard
+350
+18
+ 0
+MLINESTYLE
+ 5
+18
+100
+AcDbMlineStyle
+ 2
+STANDARD
+ 70
+0
+ 3
+
+ 62
+256
+ 51
+90.0
+ 52
+90.0
+ 71
+2
+ 49
+0.5
+ 62
+256
+ 6
+BYLAYER
+ 49
+-0.5
+ 62
+256
+ 6
+BYLAYER
+ 0
+DICTIONARY
+ 5
+19
+100
+AcDbDictionary
+280
+0
+281
+1
+ 0
+DICTIONARY
+ 5
+1A
+100
+AcDbDictionary
+281
+1
+ 3
+Layout1
+350
+1E
+ 3
+Layout2
+350
+26
+ 3
+Model
+350
+22
+ 0
+LAYOUT
+ 5
+1E
+100
+AcDbPlotSettings
+ 1
+
+ 2
+C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3
+ 4
+
+ 6
+
+ 40
+0.0
+ 41
+0.0
+ 42
+0.0
+ 43
+0.0
+ 44
+0.0
+ 45
+0.0
+ 46
+0.0
+ 47
+0.0
+ 48
+0.0
+ 49
+0.0
+140
+0.0
+141
+0.0
+142
+1.0
+143
+1.0
+ 70
+688
+ 72
+0
+ 73
+0
+ 74
+5
+ 7
+
+ 75
+16
+147
+1.0
+148
+0.0
+149
+0.0
+100
+AcDbLayout
+ 1
+Layout1
+ 70
+1
+ 71
+1
+ 10
+0.0
+ 20
+0.0
+ 11
+420.0
+ 21
+297.0
+ 12
+0.0
+ 22
+0.0
+ 32
+0.0
+ 14
+100000000000000000000.0
+ 24
+100000000000000000000.0
+ 34
+100000000000000000000.0
+ 15
+-100000000000000000000.0
+ 25
+-100000000000000000000.0
+ 35
+-100000000000000000000.0
+146
+0.0
+ 13
+0.0
+ 23
+0.0
+ 33
+0.0
+ 16
+1.0
+ 26
+0.0
+ 36
+0.0
+ 17
+0.0
+ 27
+1.0
+ 37
+0.0
+ 76
+0
+330
+1B
+ 0
+LAYOUT
+ 5
+22
+100
+AcDbPlotSettings
+ 1
+
+ 2
+C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3
+ 4
+
+ 6
+
+ 40
+0.0
+ 41
+0.0
+ 42
+0.0
+ 43
+0.0
+ 44
+0.0
+ 45
+0.0
+ 46
+0.0
+ 47
+0.0
+ 48
+0.0
+ 49
+0.0
+140
+0.0
+141
+0.0
+142
+1.0
+143
+1.0
+ 70
+1712
+ 72
+0
+ 73
+0
+ 74
+0
+ 7
+
+ 75
+0
+147
+1.0
+148
+0.0
+149
+0.0
+100
+AcDbLayout
+ 1
+Model
+ 70
+1
+ 71
+0
+ 10
+0.0
+ 20
+0.0
+ 11
+12.0
+ 21
+9.0
+ 12
+0.0
+ 22
+0.0
+ 32
+0.0
+ 14
+0.0
+ 24
+0.0
+ 34
+0.0
+ 15
+0.0
+ 25
+0.0
+ 35
+0.0
+146
+0.0
+ 13
+0.0
+ 23
+0.0
+ 33
+0.0
+ 16
+1.0
+ 26
+0.0
+ 36
+0.0
+ 17
+0.0
+ 27
+1.0
+ 37
+0.0
+ 76
+0
+330
+1F
+ 0
+LAYOUT
+ 5
+26
+100
+AcDbPlotSettings
+ 1
+
+ 2
+C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3
+ 4
+
+ 6
+
+ 40
+0.0
+ 41
+0.0
+ 42
+0.0
+ 43
+0.0
+ 44
+0.0
+ 45
+0.0
+ 46
+0.0
+ 47
+0.0
+ 48
+0.0
+ 49
+0.0
+140
+0.0
+141
+0.0
+142
+1.0
+143
+1.0
+ 70
+688
+ 72
+0
+ 73
+0
+ 74
+5
+ 7
+
+ 75
+16
+147
+1.0
+148
+0.0
+149
+0.0
+100
+AcDbLayout
+ 1
+Layout2
+ 70
+1
+ 71
+2
+ 10
+0.0
+ 20
+0.0
+ 11
+12.0
+ 21
+9.0
+ 12
+0.0
+ 22
+0.0
+ 32
+0.0
+ 14
+0.0
+ 24
+0.0
+ 34
+0.0
+ 15
+0.0
+ 25
+0.0
+ 35
+0.0
+146
+0.0
+ 13
+0.0
+ 23
+0.0
+ 33
+0.0
+ 16
+1.0
+ 26
+0.0
+ 36
+0.0
+ 17
+0.0
+ 27
+1.0
+ 37
+0.0
+ 76
+0
+330
+23
+ 0
+DICTIONARY
+ 5
+48
+100
+AcDbDictionary
+281
+1
+ 3
+DIMASSOC
+350
+4A
+ 3
+HIDETEXT
+350
+49
+ 0
+DICTIONARYVAR
+ 5
+49
+100
+DictionaryVariables
+280
+0
+ 1
+2
+ 0
+DICTIONARYVAR
+ 5
+4A
+100
+DictionaryVariables
+280
+0
+ 1
+1
+ 0
+ENDSEC
+ 0
+EOF
diff --git a/testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad b/testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad
new file mode 100644
index 0000000..d6b197c
--- /dev/null
+++ b/testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad
@@ -0,0 +1,3 @@
+use <localfiles_subdir/localfiles_submodule.scad>
+
+localfiles_submodule();
diff --git a/testdata/scad/misc/localfiles_dir/localfiles_module.scad b/testdata/scad/misc/localfiles_dir/localfiles_module.scad
new file mode 100644
index 0000000..2611e71
--- /dev/null
+++ b/testdata/scad/misc/localfiles_dir/localfiles_module.scad
@@ -0,0 +1,9 @@
+module localfiles_module()
+{
+ linear_extrude(h=100) import("localfile.dxf");
+ translate([-250,0,0]) linear_extrude(file="localfile.dxf");
+ translate([0,350,0]) rotate_extrude(file="localfile.dxf");
+ translate([250,0,0]) scale([200,200,50]) surface("localfile.dat");
+
+ translate([0,-200,0]) sphere(r=dxf_dim(file="localfile.dxf", name="localfile")/2);
+}
diff --git a/testdata/scad/misc/localfiles_dir/localfiles_subdir/localfiles_submodule.scad b/testdata/scad/misc/localfiles_dir/localfiles_subdir/localfiles_submodule.scad
new file mode 100644
index 0000000..cab3499
--- /dev/null
+++ b/testdata/scad/misc/localfiles_dir/localfiles_subdir/localfiles_submodule.scad
@@ -0,0 +1,9 @@
+module localfiles_submodule()
+{
+ linear_extrude(h=100) import("localfile.dxf");
+ translate([-250,0,0]) linear_extrude(file="localfile.dxf");
+ translate([0,350,0]) rotate_extrude(file="localfile.dxf");
+ translate([250,0,0]) scale([200,200,50]) surface("localfile.dat");
+
+ translate([0,-200,0]) sphere(r=dxf_dim(file="localfile.dxf", name="localfile")/2);
+}
diff --git a/testdata/scad/misc/lookup-tests.scad b/testdata/scad/misc/lookup-tests.scad
new file mode 100644
index 0000000..c03ec95
--- /dev/null
+++ b/testdata/scad/misc/lookup-tests.scad
@@ -0,0 +1,17 @@
+echo(lookup(undef, undef));
+echo(lookup(undef, [undef]));
+echo(lookup(undef, [[undef]]));
+echo(lookup(undef, [[undef, undef]]));
+echo(lookup(0, [[0, 0]]));
+echo(lookup(0.5, [[0, 0],
+ [1, 1]]));
+
+table = [[-1, -5],
+ [-10, -55],
+ [0, 0],
+ [1, 3],
+ [10, 333]];
+indices = [-20,-10,-9.9, -0.5, 0, 0.3, 1.1, 10, 10.1];
+for (i=[0:len(indices)-1]) {
+ echo(lookup(indices[i], table));
+}
diff --git a/testdata/scad/misc/variable-scope-sub.scad b/testdata/scad/misc/variable-scope-sub.scad
new file mode 100644
index 0000000..fda9520
--- /dev/null
+++ b/testdata/scad/misc/variable-scope-sub.scad
@@ -0,0 +1,24 @@
+sub_global = 15;
+
+module submodule() {
+ echo($children);
+ echo(submodule_var);
+ submodule_var = 16;
+ module subsubmodule() {
+ echo($children);
+ subsubmodule_var = 17;
+ echo(subsubmodule_var);
+ child(0);
+ }
+ subsubmodule() {child(0); sphere();}
+}
+
+module submodule2() {
+ echo(sub_global);
+ echo($children);
+}
+
+module submain() {
+ echo(global_var); // Undefined global var
+ submodule() {submodule2() sphere(); cube();}
+}
diff --git a/testdata/scad/misc/variable-scope-tests.scad b/testdata/scad/misc/variable-scope-tests.scad
new file mode 100644
index 0000000..8426fbb
--- /dev/null
+++ b/testdata/scad/misc/variable-scope-tests.scad
@@ -0,0 +1,53 @@
+echo("special variable inheritance");
+module special_module(a) {
+ echo(a, $fn);
+ special_module2(a);
+}
+
+module special_module2(b) {
+ echo(a);
+ echo(b, $fn);
+}
+
+special_module(23, $fn=5);
+
+echo("inner variables shadows parameter");
+module inner_variables(a, b) {
+ b = 24;
+ echo(a, b);
+}
+
+inner_variables(5, 6);
+
+echo("user-defined special variables as parameter");
+module user_defined_special($b) {
+ echo($b);
+ user_defined_special2();
+}
+
+module user_defined_special2() {
+ echo($b);
+}
+
+user_defined_special(7);
+
+echo("assign only visible in children's scope");
+module assigning() {
+ echo(c);
+}
+
+module assigning2(c) {
+ echo(c);
+}
+
+assign(c=5) {
+ assigning();
+ assigning2(c);
+}
+
+echo("undeclared variable can still be passed and used");
+module undeclared_var() {
+ echo(d);
+}
+
+undeclared_var(d=6);
diff --git a/testdata/scad/templates/import_dxf-tests-template.scad b/testdata/scad/templates/import_dxf-tests-template.scad
index f10dd06..91eca7a 100644
--- a/testdata/scad/templates/import_dxf-tests-template.scad
+++ b/testdata/scad/templates/import_dxf-tests-template.scad
@@ -4,7 +4,7 @@ translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[0,110]);
translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5);
import(file="../../dxf/multiple-layers.dxf");
translate([-200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
-translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
+translate([0,200,0]) import(filename="../../dxf/multiple-layers.dxf", layername="0");
translate([200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="noname");
translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="Layer with a pretty long name including \\ \"special\" /'\\\\ characters");
translate([200,0,0]) import(file="@CMAKE_SOURCE_DIR@/../testdata/dxf/polygons.dxf");
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5eecaae..39dc341 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,7 +13,11 @@ include(CMakeParseArguments.cmake)
# Detect Lion and force gcc
IF (APPLE)
EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
- IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
+ IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
+ message("Detected Mountain Lion or later")
+ set(CMAKE_C_COMPILER "gcc")
+ set(CMAKE_CXX_COMPILER "g++")
+ ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
message("Detected Lion or later")
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
@@ -97,7 +101,7 @@ endif()
# Clang compiler
-if(CMAKE_CXX_COMPILER MATCHES ".*clang.*")
+if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*")
# disable enormous amount of warnings about CGAL
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable")
@@ -179,28 +183,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
FIND_LIBRARY(COCOA_LIBRARY Cocoa REQUIRED)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-# Qt4
-
-set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
-find_package(OpenGL REQUIRED)
-if ( "${OPENGL_glu_LIBRARY}" MATCHES "NOTFOUND" )
- # GLU and Mesa split in late 2012 so some systems dont have GLU
- find_library(OPENGL_glu_LIBRARY GLU HINTS "$ENV{OPENSCAD_LIBRARIES}/lib" REQUIRED)
- set( OPENGL_LIBRARY ${OPENGL_glu_LIBRARY} ${OPENGL_LIBRARY} )
-endif()
-
-if (MINGW_CROSS_ENV_DIR)
- mingw_cross_env_find_qt()
- mingw_cross_env_info()
- include_directories( ${QT_INCLUDE_DIRS} )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${QT_CFLAGS_OTHER}")
-else()
- find_package(Qt4 COMPONENTS QtCore REQUIRED)
- include(${QT_USE_FILE})
-endif()
-
-set(CMAKE_INCLUDE_DIRECTORIES_BEFORE OFF)
-
# Eigen
@@ -268,6 +250,20 @@ else()
inclusion(EIGEN_DIR EIGEN_INCLUDE_DIR)
endif()
+# OpenGL
+find_package(OpenGL REQUIRED)
+if (NOT OPENGL_GLU_FOUND)
+ message(STATUS "GLU not found in system paths...searching $ENV{OPENSCAD_LIBRARIES} ")
+ find_library(OPENGL_glu_LIBRARY GLU HINTS $ENV{OPENSCAD_LIBRARIES}/lib)
+ if (NOT OPENGL_glu_LIBRARY)
+ message(FATAL "GLU library not found")
+ endif()
+ set(OPENGL_LIBRARIES ${OPENGL_glu_LIBRARY} ${OPENGL_LIBRARIES})
+ message(STATUS "OpenGL LIBRARIES: ")
+ foreach(GLLIB ${OPENGL_LIBRARIES})
+ message(STATUS " " ${GLLIB})
+ endforeach()
+endif()
# OpenCSG
if (NOT $ENV{OPENCSGDIR} STREQUAL "")
@@ -374,7 +370,7 @@ if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)
endif()
inclusion(CGAL_DIR CGAL_INCLUDE_DIRS)
-if(CMAKE_CXX_COMPILER MATCHES ".*clang.*")
+if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
endif()
@@ -422,10 +418,13 @@ set(CORE_SOURCES
../src/value.cc
../src/expr.cc
../src/func.cc
+ ../src/localscope.cc
../src/module.cc
../src/ModuleCache.cc
../src/node.cc
../src/context.cc
+ ../src/modcontext.cc
+ ../src/evalcontext.cc
../src/csgterm.cc
../src/csgtermnormalizer.cc
../src/polyset.cc
@@ -443,7 +442,9 @@ set(CORE_SOURCES
../src/linearextrude.cc
../src/rotateextrude.cc
../src/printutils.cc
+ ../src/fileutils.cc
../src/progress.cc
+ ../src/boost-utils.cc
${FLEX_OpenSCADlexer_OUTPUTS}
${BISON_OpenSCADparser_OUTPUTS})
@@ -604,6 +605,10 @@ else()
set(GUI_BINPATH "${CMAKE_CURRENT_SOURCE_DIR}/../openscad")
endif()
+if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/openscad")
+ set(GUI_BINPATH "${CMAKE_CURRENT_BINARY_DIR}/openscad")
+endif()
+
if(EXISTS "${GUI_BINPATH}")
message(STATUS "Found OpenSCAD GUI binary: ${GUI_BINPATH}")
else()
@@ -764,17 +769,24 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
- ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad)
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad)
list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES})
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
- ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad)
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad)
list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILES})
list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
- ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad)
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad)
+
list(APPEND OPENCSGTEST_FILES ${CGALPNGTEST_FILES})
list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/bbox-transform-bug.scad)
list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/intersection-prune-test.scad)
diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc
index 3a0a855..67d3313 100644
--- a/tests/cgalcachetest.cc
+++ b/tests/cgalcachetest.cc
@@ -30,7 +30,7 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -40,7 +40,6 @@
#include "PolySetCGALEvaluator.h"
#include "CGALCache.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -57,7 +56,6 @@ namespace po = boost::program_options;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -124,19 +122,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
- currentdir = boosty::stringy( fs::current_path() );
+ currentdir = boosty::stringy(fs::current_path());
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
if (!root_module) {
@@ -148,7 +145,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc
index 52205fd..7b958de 100644
--- a/tests/cgalpngtest.cc
+++ b/tests/cgalpngtest.cc
@@ -30,7 +30,7 @@
#include "node.h"
#include "module.h"
#include "polyset.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -43,7 +43,6 @@
#include "cgal.h"
#include "OffscreenView.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -57,7 +56,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -97,31 +95,31 @@ int main(int argc, char **argv)
#endif
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
if (!root_module) {
exit(1);
}
- if (fs::path(filename).has_parent_path()) {
- fs::current_path(fs::path(filename).parent_path());
- }
+ 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();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc
index 2815463..4be7767 100644
--- a/tests/cgalstlsanitytest.cc
+++ b/tests/cgalstlsanitytest.cc
@@ -29,7 +29,7 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -38,11 +38,6 @@
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
-#include <QCoreApplication>
-#include <QFile>
-#include <QDir>
-#include <QSet>
-#include <QTextStream>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -56,7 +51,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -83,19 +77,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
if (!root_module) {
@@ -107,7 +100,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc
index 4a15050..d750da9 100644
--- a/tests/cgaltest.cc
+++ b/tests/cgaltest.cc
@@ -29,7 +29,7 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -38,7 +38,6 @@
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -52,7 +51,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -76,19 +74,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
if (!root_module) {
@@ -100,7 +97,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc
index e793c4a..1460bbd 100644
--- a/tests/csgtermtest.cc
+++ b/tests/csgtermtest.cc
@@ -31,14 +31,13 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
#include "Tree.h"
#include "csgterm.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -53,7 +52,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::cout;
@@ -71,19 +69,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
const AbstractNode *root_node;
root_module = parsefile(filename);
@@ -96,7 +93,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree(root_node);
diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc
index 7583a41..7b9dbab 100644
--- a/tests/csgtestcore.cc
+++ b/tests/csgtestcore.cc
@@ -6,7 +6,7 @@
#include "openscad.h"
#include "parsersettings.h"
#include "builtin.h"
-#include "context.h"
+#include "modcontext.h"
#include "node.h"
#include "module.h"
#include "polyset.h"
@@ -23,9 +23,6 @@
#include "csgtermnormalizer.h"
#include "OffscreenView.h"
-#include <QCoreApplication>
-#include <QTimer>
-
#include <sstream>
#include <vector>
@@ -128,20 +125,18 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
-
fs::path original_path = fs::current_path();
std::string currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
if (sysinfo_dump)
root_module = parse("sphere();","",false);
@@ -153,13 +148,14 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
}
if (!sysinfo_dump) {
- if (fs::path(filename).has_parent_path()) {
- fs::current_path(fs::path(filename).parent_path());
- }
+ 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();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc
index e050232..97902f6 100644
--- a/tests/csgtexttest.cc
+++ b/tests/csgtexttest.cc
@@ -31,13 +31,12 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
#include "Tree.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -52,7 +51,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
void csgTree(CSGTextCache &cache, const AbstractNode &root)
{
@@ -75,19 +73,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
root_module = parsefile(filename);
@@ -100,7 +97,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree;
tree.setRoot(root_node);
diff --git a/tests/dumptest.cc b/tests/dumptest.cc
index b75a2e2..4477703 100644
--- a/tests/dumptest.cc
+++ b/tests/dumptest.cc
@@ -29,13 +29,12 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
#include "Tree.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -50,7 +49,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -76,24 +74,22 @@ int main(int argc, char **argv)
const char *filename = argv[1];
const char *outfilename = argv[2];
-
int rc = 0;
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy(fs::current_path());
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
root_module = parsefile(filename);
@@ -101,12 +97,13 @@ int main(int argc, char **argv)
exit(1);
}
- if (fs::path(filename).has_parent_path()) {
- fs::current_path(fs::path(filename).parent_path());
- }
+ 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();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree;
tree.setRoot(root_node);
@@ -121,27 +118,32 @@ int main(int argc, char **argv)
fs::current_path(original_path);
std::ofstream outfile;
outfile.open(outfilename);
+ if (!outfile.is_open()) {
+ fprintf(stderr, "Error: Unable to open output file %s\n", outfilename);
+ exit(1);
+ }
+ std::cout << "Opened " << outfilename << "\n";
outfile << dumpstdstr << "\n";
outfile.close();
+ if (outfile.fail()) fprintf(stderr, "Failed to close file\n");
delete root_node;
delete root_module;
- root_module = parsefile(outfilename);
+ fs::current_path(original_path);
+ root_module = parsefile(outfilename, fparent.string().c_str());
if (!root_module) {
fprintf(stderr, "Error: Unable to read back dumped file\n");
exit(1);
}
- if (fs::path(filename).has_parent_path()) {
- fs::current_path(fs::path(filename).parent_path());
- }
-
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
tree.setRoot(root_node);
+ fs::current_path(fparent);
+
string readbackstr = dumptree(tree, *root_node);
if (dumpstdstr != readbackstr) {
fprintf(stderr, "Error: Readback is different from original dump:\n");
diff --git a/tests/echotest.cc b/tests/echotest.cc
index bf2f4a4..3051751 100644
--- a/tests/echotest.cc
+++ b/tests/echotest.cc
@@ -29,12 +29,11 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "builtin.h"
#include "printutils.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -49,7 +48,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -83,19 +81,18 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
root_module = parsefile(filename);
@@ -108,7 +105,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc
index 0028114..5531461 100644
--- a/tests/modulecachetest.cc
+++ b/tests/modulecachetest.cc
@@ -29,13 +29,12 @@
#include "parsersettings.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
#include "Tree.h"
-#include <QCoreApplication>
#ifndef _MSC_VER
#include <getopt.h>
#endif
@@ -50,7 +49,6 @@ namespace fs = boost::filesystem;
std::string commandline_commands;
std::string currentdir;
-QString examplesdir;
using std::string;
@@ -71,22 +69,20 @@ int main(int argc, char **argv)
Builtins::instance()->initialize();
- QCoreApplication app(argc, argv);
fs::path original_path = fs::current_path();
currentdir = boosty::stringy( fs::current_path() );
- parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
- add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
+ parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
+ add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- Context root_ctx;
- register_builtin(root_ctx);
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
- ModuleInstantiation root_inst;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
- root_module = parsefile(filename);
+ FileModule *root_module = parsefile(filename);
if (!root_module) {
fprintf(stderr, "Error: Unable to parse input file\n");
exit(1);
@@ -97,7 +93,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
@@ -112,7 +108,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
diff --git a/tests/regression/cgalpngtest/child-child-test-expected.png b/tests/regression/cgalpngtest/child-child-test-expected.png
new file mode 100644
index 0000000..80b70ba
--- /dev/null
+++ b/tests/regression/cgalpngtest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/child-tests-expected.png b/tests/regression/cgalpngtest/child-tests-expected.png
index ed6207c..eb34f18 100644
--- a/tests/regression/cgalpngtest/child-tests-expected.png
+++ b/tests/regression/cgalpngtest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/linear_extrude-scale-zero-tests-expected.png b/tests/regression/cgalpngtest/linear_extrude-scale-zero-tests-expected.png
new file mode 100644
index 0000000..3b1c934
--- /dev/null
+++ b/tests/regression/cgalpngtest/linear_extrude-scale-zero-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/linear_extrude-tests-expected.png b/tests/regression/cgalpngtest/linear_extrude-tests-expected.png
index 1486743..c85142e 100644
--- a/tests/regression/cgalpngtest/linear_extrude-tests-expected.png
+++ b/tests/regression/cgalpngtest/linear_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/localfiles-compatibility-test-expected.png b/tests/regression/cgalpngtest/localfiles-compatibility-test-expected.png
new file mode 100644
index 0000000..d0cfd50
--- /dev/null
+++ b/tests/regression/cgalpngtest/localfiles-compatibility-test-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/localfiles-test-expected.png b/tests/regression/cgalpngtest/localfiles-test-expected.png
new file mode 100644
index 0000000..d0cfd50
--- /dev/null
+++ b/tests/regression/cgalpngtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/module-recursion-expected.png b/tests/regression/cgalpngtest/module-recursion-expected.png
new file mode 100644
index 0000000..3012a12
--- /dev/null
+++ b/tests/regression/cgalpngtest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/modulevariables-expected.png b/tests/regression/cgalpngtest/modulevariables-expected.png
new file mode 100644
index 0000000..0dc18e8
--- /dev/null
+++ b/tests/regression/cgalpngtest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/surface-simple-expected.png b/tests/regression/cgalpngtest/surface-simple-expected.png
index 4152c38..d75cda7 100644
--- a/tests/regression/cgalpngtest/surface-simple-expected.png
+++ b/tests/regression/cgalpngtest/surface-simple-expected.png
Binary files differ
diff --git a/tests/regression/dumptest/allmodules-expected.txt b/tests/regression/dumptest/allmodules-expected.txt
index 86bb7fb..e6bd498 100644
--- a/tests/regression/dumptest/allmodules-expected.txt
+++ b/tests/regression/dumptest/allmodules-expected.txt
@@ -10,8 +10,8 @@
union();
difference();
intersection();
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
rotate_extrude(convexity = 1, $fn = 0, $fa = 12, $fs = 2);
rotate_extrude(convexity = 1, $fn = 0, $fa = 12, $fs = 2);
import(file = "", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
diff --git a/tests/regression/dumptest/child-child-test-expected.txt b/tests/regression/dumptest/child-child-test-expected.txt
new file mode 100644
index 0000000..13f098d
--- /dev/null
+++ b/tests/regression/dumptest/child-child-test-expected.txt
@@ -0,0 +1,59 @@
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, 5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false);
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ color([1, 0, 0, 1]) {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 15], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ color([1, 0, 0, 1]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
diff --git a/tests/regression/dumptest/child-tests-expected.txt b/tests/regression/dumptest/child-tests-expected.txt
index 9a886fe..e1a7557 100644
--- a/tests/regression/dumptest/child-tests-expected.txt
+++ b/tests/regression/dumptest/child-tests-expected.txt
@@ -37,4 +37,16 @@
multmatrix([[1, 0, 0, 5], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group();
}
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 6], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 16, $fa = 12, $fs = 2, r = 1);
+ }
+ multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ cube(size = [1, 1, 1], center = true);
+ }
+ }
+ }
+ }
diff --git a/tests/regression/dumptest/dxf_linear_extrude-expected.txt b/tests/regression/dumptest/dxf_linear_extrude-expected.txt
index ec46e66..9ad9e00 100644
--- a/tests/regression/dumptest/dxf_linear_extrude-expected.txt
+++ b/tests/regression/dumptest/dxf_linear_extrude-expected.txt
@@ -1,2 +1,2 @@
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
diff --git a/tests/regression/dumptest/example009-expected.txt b/tests/regression/dumptest/example009-expected.txt
index b293224..b4c7bcf 100644
--- a/tests/regression/dumptest/example009-expected.txt
+++ b/tests/regression/dumptest/example009-expected.txt
@@ -1,20 +1,20 @@
- %linear_extrude(height = 22, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 2) {
+ %linear_extrude(height = 22, center = true, convexity = 10, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
import(file = "example009.dxf", layer = "body", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
}
%group() {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 12], [0, 0, 0, 1]]) {
- linear_extrude(height = 2, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 2, center = true, convexity = 10, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
import(file = "example009.dxf", layer = "plate", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -12], [0, 0, 0, 1]]) {
- linear_extrude(height = 2, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 2, center = true, convexity = 10, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
import(file = "example009.dxf", layer = "plate", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
}
}
}
intersection() {
- linear_extrude(height = 20, center = true, convexity = 10, twist = -57.5288, slices = 4, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = true, convexity = 10, twist = -57.5288, slices = 4, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
import(file = "example009.dxf", layer = "fan_top", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
}
rotate_extrude(file = "example009.dxf", layer = "fan_side", origin = [0, -40], scale = 1, convexity = 10, $fn = 0, $fa = 12, $fs = 2);
diff --git a/tests/regression/dumptest/hull2-tests-expected.txt b/tests/regression/dumptest/hull2-tests-expected.txt
index e4c5a5b..c14282f 100644
--- a/tests/regression/dumptest/hull2-tests-expected.txt
+++ b/tests/regression/dumptest/hull2-tests-expected.txt
@@ -56,4 +56,10 @@
}
}
}
+ group() {
+ hull() {
+ square(size = [0, 0], center = false);
+ circle($fn = 0, $fa = 12, $fs = 2, r = 0);
+ }
+ }
diff --git a/tests/regression/dumptest/hull3-tests-expected.txt b/tests/regression/dumptest/hull3-tests-expected.txt
index 4c05e2c..f8def3b 100644
--- a/tests/regression/dumptest/hull3-tests-expected.txt
+++ b/tests/regression/dumptest/hull3-tests-expected.txt
@@ -27,4 +27,10 @@
}
}
}
+ group() {
+ hull() {
+ cube(size = [0, 0, 0], center = false);
+ sphere($fn = 0, $fa = 12, $fs = 2, r = 0);
+ }
+ }
diff --git a/tests/regression/dumptest/include-tests-expected.txt b/tests/regression/dumptest/include-tests-expected.txt
index 47f731e..3f3ecd9 100644
--- a/tests/regression/dumptest/include-tests-expected.txt
+++ b/tests/regression/dumptest/include-tests-expected.txt
@@ -62,7 +62,7 @@
multmatrix([[1, 0, 0, -6], [0, 1, 0, 0], [0, 0, 1, 19], [0, 0, 0, 1]]) {
multmatrix([[0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) {
group() {
- linear_extrude(height = 12, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 12, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
polygon(points = [[0, 0], [18, 0], [0, 4]], paths = [[0, 1, 2]], convexity = 1);
}
}
diff --git a/tests/regression/dumptest/linear_extrude-expected.txt b/tests/regression/dumptest/linear_extrude-expected.txt
index ec46e66..9ad9e00 100644
--- a/tests/regression/dumptest/linear_extrude-expected.txt
+++ b/tests/regression/dumptest/linear_extrude-expected.txt
@@ -1,2 +1,2 @@
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
diff --git a/tests/regression/dumptest/linear_extrude-scale-zero-tests-expected.txt b/tests/regression/dumptest/linear_extrude-scale-zero-tests-expected.txt
new file mode 100644
index 0000000..950c724
--- /dev/null
+++ b/tests/regression/dumptest/linear_extrude-scale-zero-tests-expected.txt
@@ -0,0 +1,253 @@
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 6], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 0, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 9], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 1], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 12], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [1, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 15], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 8], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = false);
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 3, center = false, convexity = 1, twist = 180, slices = 20, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ difference() {
+ square(size = [2, 2], center = true);
+ multmatrix([[1, 0, 0, -0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ square(size = [1, 1], center = true);
+ }
+ }
+ }
+ }
+ }
+ }
+
diff --git a/tests/regression/dumptest/linear_extrude-tests-expected.txt b/tests/regression/dumptest/linear_extrude-tests-expected.txt
index cba1189..c867388 100644
--- a/tests/regression/dumptest/linear_extrude-tests-expected.txt
+++ b/tests/regression/dumptest/linear_extrude-tests-expected.txt
@@ -3,11 +3,11 @@
rotate_extrude(convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
cube(size = [1, 1, 1], center = false);
}
- linear_extrude(height = 10, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 10, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
square(size = [10, 10], center = false);
}
multmatrix([[1, 0, 0, 19], [0, 1, 0, 5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 10, center = true, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 10, center = true, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
difference() {
circle($fn = 0, $fa = 12, $fs = 2, r = 5);
circle($fn = 0, $fa = 12, $fs = 2, r = 3);
@@ -15,17 +15,42 @@
}
}
multmatrix([[1, 0, 0, 31.5], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 10, center = false, convexity = 1, twist = -45, slices = 3, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 10, center = false, convexity = 1, twist = -45, slices = 3, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
polygon(points = [[-5, -2.5], [5, -2.5], [0, 2.5]], paths = undef, convexity = 1);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 20, center = false, convexity = 1, twist = 45, slices = 2, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = false, convexity = 1, twist = 45, slices = 2, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
square(size = [10, 10], center = false);
}
}
multmatrix([[1, 0, 0, 19], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 20, center = false, convexity = 1, twist = 45, slices = 10, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = false, convexity = 1, twist = 45, slices = 10, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [10, 10], center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -15], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 5, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [10, 10], center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, -25], [0, 1, 0, -10], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 10, center = false, convexity = 1, scale = [2, 2], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [5, 5], center = true);
+ }
+ }
+ multmatrix([[1, 0, 0, -15], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [10, 10], center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, -10], [0, 1, 0, 5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 15, center = false, convexity = 1, scale = [0, 0], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [10, 10], center = true);
+ }
+ }
+ multmatrix([[1, 0, 0, -15], [0, 1, 0, -15], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 10, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
square(size = [10, 10], center = false);
}
}
diff --git a/tests/regression/dumptest/localfiles-compatibility-test-expected.txt b/tests/regression/dumptest/localfiles-compatibility-test-expected.txt
new file mode 100644
index 0000000..95ba49b
--- /dev/null
+++ b/tests/regression/dumptest/localfiles-compatibility-test-expected.txt
@@ -0,0 +1,20 @@
+ group() {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ import(file = "localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, -250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(file = "localfile.dxf", layer = "", origin = [0, 0], height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 350], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ rotate_extrude(file = "localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, 250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ multmatrix([[200, 0, 0, 0], [0, 200, 0, 0], [0, 0, 50, 0], [0, 0, 0, 1]]) {
+ surface(file = "localfile.dat", center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -200], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 0, $fa = 12, $fs = 2, r = 100);
+ }
+ }
+
diff --git a/tests/regression/dumptest/localfiles-test-expected.txt b/tests/regression/dumptest/localfiles-test-expected.txt
new file mode 100644
index 0000000..a7e81e5
--- /dev/null
+++ b/tests/regression/dumptest/localfiles-test-expected.txt
@@ -0,0 +1,20 @@
+ group() {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ import(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, -250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 350], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ rotate_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
+ }
+ multmatrix([[1, 0, 0, 250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ multmatrix([[200, 0, 0, 0], [0, 200, 0, 0], [0, 0, 50, 0], [0, 0, 0, 1]]) {
+ surface(file = "localfiles_dir/localfile.dat", center = false);
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -200], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 0, $fa = 12, $fs = 2, r = 100);
+ }
+ }
+
diff --git a/tests/regression/dumptest/module-recursion-expected.txt b/tests/regression/dumptest/module-recursion-expected.txt
new file mode 100644
index 0000000..9ad8877
--- /dev/null
+++ b/tests/regression/dumptest/module-recursion-expected.txt
@@ -0,0 +1,244 @@
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 0.2, r2 = 0.2, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false);
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) {
+ group() {
+ multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) {
+ group() {
+ group();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
diff --git a/tests/regression/dumptest/modulevariables-expected.txt b/tests/regression/dumptest/modulevariables-expected.txt
new file mode 100644
index 0000000..fed4bbc
--- /dev/null
+++ b/tests/regression/dumptest/modulevariables-expected.txt
@@ -0,0 +1,4 @@
+ group() {
+ cylinder($fn = 0, $fa = 12, $fs = 2, h = 10, r1 = 23, r2 = 10, center = false);
+ }
+
diff --git a/tests/regression/dumptest/projection-tests-expected.txt b/tests/regression/dumptest/projection-tests-expected.txt
index 69cb49c..92e6870 100644
--- a/tests/regression/dumptest/projection-tests-expected.txt
+++ b/tests/regression/dumptest/projection-tests-expected.txt
@@ -3,13 +3,13 @@
projection(cut = true, convexity = 0) {
square(size = [1, 1], center = false);
}
- linear_extrude(height = 20, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = false, convexity = 0) {
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
}
}
multmatrix([[1, 0, 0, 22], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 20, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = true, convexity = 0) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 9], [0, 0, 0, 1]]) {
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
@@ -18,7 +18,7 @@
}
}
multmatrix([[1, 0, 0, 44], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 20, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = true, convexity = 0) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 7], [0, 0, 0, 1]]) {
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
@@ -27,7 +27,7 @@
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, -22], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 5, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 5, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = true, convexity = 0) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -4.999999], [0, 0, 0, 1]]) {
cube(size = [10, 10, 10], center = true);
@@ -36,7 +36,7 @@
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, -44], [0, 0, 1, 0], [0, 0, 0, 1]]) {
- linear_extrude(height = 5, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 5, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = true, convexity = 0) {
union() {
difference() {
diff --git a/tests/regression/dumptest/scale2D-tests-expected.txt b/tests/regression/dumptest/scale2D-tests-expected.txt
index 6d4c096..9465b8c 100644
--- a/tests/regression/dumptest/scale2D-tests-expected.txt
+++ b/tests/regression/dumptest/scale2D-tests-expected.txt
@@ -17,14 +17,14 @@
}
}
}
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
multmatrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group() {
square(size = [2, 3], center = true);
}
}
}
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
multmatrix([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group() {
square(size = [2, 3], center = true);
diff --git a/tests/regression/dumptest/scale3D-tests-expected.txt b/tests/regression/dumptest/scale3D-tests-expected.txt
index c06b2fe..e802117 100644
--- a/tests/regression/dumptest/scale3D-tests-expected.txt
+++ b/tests/regression/dumptest/scale3D-tests-expected.txt
@@ -19,21 +19,21 @@
}
}
}
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
multmatrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]) {
group() {
cylinder($fn = 8, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = true);
}
}
}
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
multmatrix([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]) {
group() {
cylinder($fn = 8, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = true);
}
}
}
- linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]) {
group() {
cylinder($fn = 8, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = true);
diff --git a/tests/regression/dumptest/surface-simple-expected.txt b/tests/regression/dumptest/surface-simple-expected.txt
index 3b42fcb..48c918f 100644
--- a/tests/regression/dumptest/surface-simple-expected.txt
+++ b/tests/regression/dumptest/surface-simple-expected.txt
@@ -1,2 +1,5 @@
surface(file = "surface-simple.dat", center = true);
+ multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ surface(file = "surface-simple2.dat", center = true);
+ }
diff --git a/tests/regression/dumptest/use-tests-expected.txt b/tests/regression/dumptest/use-tests-expected.txt
index dce0b7d..1095708 100644
--- a/tests/regression/dumptest/use-tests-expected.txt
+++ b/tests/regression/dumptest/use-tests-expected.txt
@@ -39,10 +39,10 @@
group() {
multmatrix([[0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1]]) {
union() {
- linear_extrude(height = 1.5, center = true, convexity = 1, twist = 0, slices = 2, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 1.5, center = true, convexity = 1, twist = 0, slices = 2, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
circle($fn = 30, $fa = 12, $fs = 2, r = 0.3);
}
- linear_extrude(height = 1.5, center = true, convexity = 1, twist = 0, slices = 2, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 1.5, center = true, convexity = 1, twist = 0, slices = 2, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
projection(cut = false, convexity = 0) {
multmatrix([[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.31819805153], [0, 0, 0, 1]]) {
@@ -81,7 +81,7 @@
multmatrix([[1, 0, 0, -6], [0, 1, 0, 0], [0, 0, 1, 19], [0, 0, 0, 1]]) {
multmatrix([[0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) {
group() {
- linear_extrude(height = 12, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
+ linear_extrude(height = 12, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
polygon(points = [[0, 0], [18, 0], [0, 4]], paths = [[0, 1, 2]], convexity = 1);
}
}
diff --git a/tests/regression/echotest/lookup-tests-expected.txt b/tests/regression/echotest/lookup-tests-expected.txt
new file mode 100644
index 0000000..b98ebe2
--- /dev/null
+++ b/tests/regression/echotest/lookup-tests-expected.txt
@@ -0,0 +1,15 @@
+ECHO: undef
+ECHO: undef
+ECHO: undef
+ECHO: undef
+ECHO: 0
+ECHO: 0.5
+ECHO: -55
+ECHO: -55
+ECHO: -54.44444444444
+ECHO: -2.5
+ECHO: 0
+ECHO: 0.9
+ECHO: 6.66666666666
+ECHO: 333
+ECHO: 333
diff --git a/tests/regression/echotest/recursion-tests-expected.txt b/tests/regression/echotest/recursion-tests-expected.txt
index f4897ee..e5c99b1 100644
--- a/tests/regression/echotest/recursion-tests-expected.txt
+++ b/tests/regression/echotest/recursion-tests-expected.txt
@@ -1,2 +1,2 @@
-Recursion detected calling function 'crash'
+ERROR: Recursion detected calling function 'crash'
ECHO: undef
diff --git a/tests/regression/echotest/search-tests-expected.txt b/tests/regression/echotest/search-tests-expected.txt
index 64df0b6..0269f43 100644
--- a/tests/regression/echotest/search-tests-expected.txt
+++ b/tests/regression/echotest/search-tests-expected.txt
@@ -1,9 +1,9 @@
- search term not found: "q"
- search term not found: 1000
- search term not found: "zzz"
- search term not found: "zzz"
- search term not found: 500
- search term not found: ""
+ WARNING: search term not found: "q"
+ WARNING: search term not found: 1000
+ WARNING: search term not found: "zzz"
+ WARNING: search term not found: "zzz"
+ WARNING: search term not found: 500
+ WARNING: search term not found: ""
ECHO: "Characters in string (\"a\"): [0]"
ECHO: "Characters in string (\"adeq\"): [[0, 5], [3, 8], [4], []]"
ECHO: "Default string search (\"abe\"): [0, 1, 8]"
diff --git a/tests/regression/echotest/variable-scope-tests-expected.txt b/tests/regression/echotest/variable-scope-tests-expected.txt
new file mode 100644
index 0000000..92db05d
--- /dev/null
+++ b/tests/regression/echotest/variable-scope-tests-expected.txt
@@ -0,0 +1,16 @@
+ECHO: "special variable inheritance"
+ECHO: 23, 5
+WARNING: Ignoring unknown variable 'a'.
+ECHO: undef
+ECHO: 23, 5
+ECHO: "inner variables shadows parameter"
+ECHO: 5, 24
+ECHO: "user-defined special variables as parameter"
+ECHO: 7
+ECHO: 7
+ECHO: "assign only visible in children's scope"
+WARNING: Ignoring unknown variable 'c'.
+ECHO: undef
+ECHO: 5
+ECHO: "undeclared variable can still be passed and used"
+ECHO: 6
diff --git a/tests/regression/opencsgtest/child-child-test-expected.png b/tests/regression/opencsgtest/child-child-test-expected.png
new file mode 100644
index 0000000..07d61c0
--- /dev/null
+++ b/tests/regression/opencsgtest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/child-tests-expected.png b/tests/regression/opencsgtest/child-tests-expected.png
index e8ea39b..2ff902c 100644
--- a/tests/regression/opencsgtest/child-tests-expected.png
+++ b/tests/regression/opencsgtest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/linear_extrude-scale-zero-tests-expected.png b/tests/regression/opencsgtest/linear_extrude-scale-zero-tests-expected.png
new file mode 100644
index 0000000..22e94ad
--- /dev/null
+++ b/tests/regression/opencsgtest/linear_extrude-scale-zero-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/linear_extrude-tests-expected.png b/tests/regression/opencsgtest/linear_extrude-tests-expected.png
index f31b22a..cbbdc11 100644
--- a/tests/regression/opencsgtest/linear_extrude-tests-expected.png
+++ b/tests/regression/opencsgtest/linear_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/localfiles-compatibility-test-expected.png b/tests/regression/opencsgtest/localfiles-compatibility-test-expected.png
new file mode 100644
index 0000000..f280efd
--- /dev/null
+++ b/tests/regression/opencsgtest/localfiles-compatibility-test-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/localfiles-test-expected.png b/tests/regression/opencsgtest/localfiles-test-expected.png
new file mode 100644
index 0000000..f280efd
--- /dev/null
+++ b/tests/regression/opencsgtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/module-recursion-expected.png b/tests/regression/opencsgtest/module-recursion-expected.png
new file mode 100644
index 0000000..324c260
--- /dev/null
+++ b/tests/regression/opencsgtest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/modulevariables-expected.png b/tests/regression/opencsgtest/modulevariables-expected.png
new file mode 100644
index 0000000..bf23265
--- /dev/null
+++ b/tests/regression/opencsgtest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/surface-simple-expected.png b/tests/regression/opencsgtest/surface-simple-expected.png
index 2abef81..08abd5a 100644
--- a/tests/regression/opencsgtest/surface-simple-expected.png
+++ b/tests/regression/opencsgtest/surface-simple-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/child-child-test-expected.png b/tests/regression/throwntogethertest/child-child-test-expected.png
new file mode 100644
index 0000000..07d61c0
--- /dev/null
+++ b/tests/regression/throwntogethertest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/child-tests-expected.png b/tests/regression/throwntogethertest/child-tests-expected.png
index 561334e..2ff902c 100644
--- a/tests/regression/throwntogethertest/child-tests-expected.png
+++ b/tests/regression/throwntogethertest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/linear_extrude-scale-zero-tests-expected.png b/tests/regression/throwntogethertest/linear_extrude-scale-zero-tests-expected.png
new file mode 100644
index 0000000..22e94ad
--- /dev/null
+++ b/tests/regression/throwntogethertest/linear_extrude-scale-zero-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/linear_extrude-tests-expected.png b/tests/regression/throwntogethertest/linear_extrude-tests-expected.png
index b672783..cbbdc11 100644
--- a/tests/regression/throwntogethertest/linear_extrude-tests-expected.png
+++ b/tests/regression/throwntogethertest/linear_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/localfiles-compatibility-test-expected.png b/tests/regression/throwntogethertest/localfiles-compatibility-test-expected.png
new file mode 100644
index 0000000..f280efd
--- /dev/null
+++ b/tests/regression/throwntogethertest/localfiles-compatibility-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/localfiles-test-expected.png b/tests/regression/throwntogethertest/localfiles-test-expected.png
new file mode 100644
index 0000000..f280efd
--- /dev/null
+++ b/tests/regression/throwntogethertest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/module-recursion-expected.png b/tests/regression/throwntogethertest/module-recursion-expected.png
new file mode 100644
index 0000000..324c260
--- /dev/null
+++ b/tests/regression/throwntogethertest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/modulevariables-expected.png b/tests/regression/throwntogethertest/modulevariables-expected.png
new file mode 100644
index 0000000..bf23265
--- /dev/null
+++ b/tests/regression/throwntogethertest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/surface-simple-expected.png b/tests/regression/throwntogethertest/surface-simple-expected.png
index 2abef81..08abd5a 100644
--- a/tests/regression/throwntogethertest/surface-simple-expected.png
+++ b/tests/regression/throwntogethertest/surface-simple-expected.png
Binary files differ
diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py
index eb01abd..470be1e 100755
--- a/tests/test_cmdline_tool.py
+++ b/tests/test_cmdline_tool.py
@@ -256,5 +256,6 @@ if __name__ == '__main__':
verification = verify_test(options.testname, options.cmd)
resultfile = run_test(options.testname, options.cmd, args[1:])
-
+ if not resultfile: exit(1)
+
if not verification or not compare_with_expected(resultfile): exit(1)
diff --git a/tests/tests-common.cc b/tests/tests-common.cc
index 703e1c5..3c66e1b 100644
--- a/tests/tests-common.cc
+++ b/tests/tests-common.cc
@@ -7,9 +7,14 @@
#include <sstream>
#include <fstream>
-Module *parsefile(const char *filename)
+/*!
+ fakepath is used to force the parser to believe that the file is
+ read from this location, in order to ensure that filepaths are
+ eavluated relative to this path (for testing purposes).
+*/
+FileModule *parsefile(const char *filename, const char *fakepath)
{
- Module *root_module = NULL;
+ FileModule *root_module = NULL;
handle_dep(filename);
std::ifstream ifs(filename);
@@ -19,7 +24,9 @@ Module *parsefile(const char *filename)
else {
std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
text += "\n" + commandline_commands;
- std::string pathname = boosty::stringy(fs::path(filename).parent_path());
+ std::string pathname;
+ if (fakepath) pathname = fakepath;
+ else pathname = boosty::stringy(fs::path(filename).parent_path());
root_module = parse(text.c_str(), pathname.c_str(), false);
if (root_module) {
root_module->handleDependencies();
diff --git a/tests/tests-common.h b/tests/tests-common.h
index 0047562..e16bcda 100644
--- a/tests/tests-common.h
+++ b/tests/tests-common.h
@@ -1,6 +1,8 @@
#ifndef TESTS_COMMON_H_
#define TESTS_COMMON_H_
-class Module *parsefile(const char *filename);
+#include <stdlib.h>
+
+class FileModule *parsefile(const char *filename, const char *fakepath = NULL);
#endif
contact: Jan Huwald // Impressum