Merge branch 'master' into translation2

Conflicts:
	src/PlatformUtils.h
master
Torsten Paul 2014-12-04 20:51:44 +01:00
commit b6167b0b60
53 changed files with 1839 additions and 1011 deletions

View File

@ -259,7 +259,9 @@ HEADERS += src/typedefs.h \
src/dxfdim.h \
src/export.h \
src/expression.h \
src/stackcheck.h \
src/function.h \
src/exceptions.h \
src/grid.h \
src/highlighter.h \
src/localscope.h \
@ -335,6 +337,7 @@ SOURCES += src/version_check.cc \
src/handle_dep.cc \
src/value.cc \
src/expr.cc \
src/stackcheck.cc \
src/func.cc \
src/localscope.cc \
src/module.cc \

View File

@ -4,17 +4,13 @@ GLView::GLView() {}
void GLView::setRenderer(Renderer* r) {}
void GLView::initializeGL() {}
void GLView::resizeGL(int w, int h) {}
void GLView::setupGimbalCamPerspective() {}
void GLView::setupGimbalCamOrtho(double distance, bool offset) {}
void GLView::setupVectorCamPerspective() {}
void GLView::setupVectorCamOrtho(bool offset) {}
void GLView::setCamera( Camera &cam ) {}
void GLView::setCamera(const Camera &cam ) {assert(false && "not implemented");}
void GLView::paintGL() {}
void GLView::vectorCamPaintGL() {}
void GLView::gimbalCamPaintGL() {}
void GLView::showSmallaxes() {}
void GLView::showAxes() {}
void GLView::showSmallaxes(const Color4f &col) {}
void GLView::showAxes(const Color4f &col) {}
void GLView::showCrosshairs() {}
void GLView::setColorScheme(const ColorScheme &cs){assert(false && "not implemented");}
void GLView::setColorScheme(const std::string &cs) {assert(false && "not implemented");}
#include "ThrownTogetherRenderer.h"
@ -23,12 +19,16 @@ ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain,
void ThrownTogetherRenderer::draw(bool /*showfaces*/, bool showedges) const {}
void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool
highlight, bool background, bool showedges, bool fberror) const {}
BoundingBox ThrownTogetherRenderer::getBoundingBox() const {assert(false && "not implemented");}
#include "CGALRenderer.h"
CGALRenderer::CGALRenderer(shared_ptr<const class Geometry> geom) {}
CGALRenderer::~CGALRenderer() {}
void CGALRenderer::draw(bool showfaces, bool showedges) const {}
BoundingBox CGALRenderer::getBoundingBox() const {assert(false && "not implemented");}
void CGALRenderer::setColorScheme(const ColorScheme &cs){assert(false && "not implemented");}
#include "system-gl.h"

View File

@ -18,5 +18,22 @@ std::string PlatformUtils::userConfigPath()
return std::string([[appSupportDir path] UTF8String]) + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
}
unsigned long PlatformUtils::stackLimit()
{
struct rlimit limit;
int ret = getrlimit(RLIMIT_STACK, &limit);
if (ret == 0) {
if (limit.rlim_cur > STACK_BUFFER_SIZE) {
return limit.rlim_cur - STACK_BUFFER_SIZE;
}
if (limit.rlim_max > STACK_BUFFER_SIZE) {
return limit.rlim_max - STACK_BUFFER_SIZE;
}
}
return STACK_LIMIT_DEFAULT;
}
void PlatformUtils::ensureStdIO(void) {}

View File

@ -1,3 +1,5 @@
#include <sys/resource.h>
#include "PlatformUtils.h"
#include "boosty.h"
@ -41,5 +43,22 @@ std::string PlatformUtils::userConfigPath()
return "";
}
unsigned long PlatformUtils::stackLimit()
{
struct rlimit limit;
int ret = getrlimit(RLIMIT_STACK, &limit);
if (ret == 0) {
if (limit.rlim_cur > STACK_BUFFER_SIZE) {
return limit.rlim_cur - STACK_BUFFER_SIZE;
}
if (limit.rlim_max > STACK_BUFFER_SIZE) {
return limit.rlim_max - STACK_BUFFER_SIZE;
}
}
return STACK_LIMIT_DEFAULT;
}
void PlatformUtils::ensureStdIO(void) {}

View File

@ -92,6 +92,11 @@ std::string PlatformUtils::userConfigPath()
return retval + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
}
unsigned long PlatformUtils::stackLimit()
{
return STACK_LIMIT_DEFAULT;
}
#include <io.h>
#include <stdio.h>
#include <fstream>

View File

@ -4,6 +4,9 @@
#include "boosty.h"
#define STACK_BUFFER_SIZE (64 * 1024)
#define STACK_LIMIT_DEFAULT (8 * 1024 * 1024 - STACK_BUFFER_SIZE)
namespace PlatformUtils {
extern const char *OPENSCAD_FOLDER_NAME;
@ -41,6 +44,14 @@ namespace PlatformUtils {
*/
int setenv(const char *name, const char *value, int overwrite);
/**
* Return system defined stack limit. If the system does not define
* a specific limit, the platform specific code will select a value.
*
* @return maximum stack size in bytes.
*/
unsigned long stackLimit();
/**
* Single character separating path specifications in a list
* (e.g. OPENSCADPATH). On Windows that's ';' and on most other

View File

@ -95,19 +95,19 @@ std::string Builtins::isDeprecated(const std::string &name)
Builtins::Builtins()
{
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new Expression(Value(2.0)))));
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new Expression(Value(12.0)))));
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(2.0)))));
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(12.0)))));
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
Value::VectorType zero3;
zero3.push_back(Value(0.0));
zero3.push_back(Value(0.0));
zero3.push_back(Value(0.0));
Value zero3val(zero3);
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new Expression(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new Expression(500))));
ValuePtr zero3val(zero3);
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new ExpressionConst(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new ExpressionConst(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(500)))));
}
Builtins::~Builtins()

View File

@ -64,8 +64,11 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
Value convexity, path, subdiv_type, level;
ValuePtr convexity = ValuePtr::undefined;
ValuePtr path = ValuePtr::undefined;
ValuePtr subdiv_type = ValuePtr::undefined;
ValuePtr level = ValuePtr::undefined;
if (type == MINKOWSKI) {
convexity = c.lookup_variable("convexity", true);
}
@ -82,31 +85,31 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
}
if (type == RESIZE) {
Value ns = c.lookup_variable("newsize");
ValuePtr ns = c.lookup_variable("newsize");
node->newsize << 0,0,0;
if ( ns.type() == Value::VECTOR ) {
Value::VectorType vs = ns.toVector();
if ( ns->type() == Value::VECTOR ) {
const Value::VectorType &vs = ns->toVector();
if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
if ( vs.size() >= 2 ) node->newsize[1] = vs[1].toDouble();
if ( vs.size() >= 3 ) node->newsize[2] = vs[2].toDouble();
}
Value autosize = c.lookup_variable("auto");
ValuePtr autosize = c.lookup_variable("auto");
node->autosize << false, false, false;
if ( autosize.type() == Value::VECTOR ) {
Value::VectorType va = autosize.toVector();
if ( autosize->type() == Value::VECTOR ) {
const Value::VectorType &va = autosize->toVector();
if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
}
else if ( autosize.type() == Value::BOOL ) {
node->autosize << autosize.toBool(),autosize.toBool(),autosize.toBool();
else if ( autosize->type() == Value::BOOL ) {
node->autosize << autosize->toBool(),autosize->toBool(),autosize->toBool();
}
}
node->convexity = (int)convexity.toDouble();
node->convexity = (int)convexity->toDouble();
node->path = path;
node->subdiv_type = subdiv_type.toString();
node->level = (int)level.toDouble();
node->subdiv_type = subdiv_type->toString();
node->level = (int)level->toDouble();
if (node->level <= 1)
node->level = 1;
@ -151,7 +154,7 @@ std::string CgaladvNode::toString() const
stream << "(convexity = " << this->convexity << ")";
break;
case GLIDE:
stream << "(path = " << this->path << ", convexity = " << this->convexity << ")";
stream << "(path = " << *this->path << ", convexity = " << this->convexity << ")";
break;
case SUBDIV:
stream << "(level = " << this->level << ", convexity = " << this->convexity << ")";

View File

@ -26,7 +26,7 @@ public:
virtual std::string toString() const;
virtual std::string name() const;
Value path;
ValuePtr path;
std::string subdiv_type;
int convexity, level;
Vector3d newsize;

View File

@ -35,7 +35,7 @@ namespace /* anonymous */ {
return Result(CGAL::to_double(v[0]),CGAL::to_double(v[1]),CGAL::to_double(v[2]));
}
#define GEN_SURFACE_DEBUG
#undef GEN_SURFACE_DEBUG
class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS>
{

View File

@ -221,15 +221,15 @@ AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantia
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {
ValuePtr v = c.lookup_variable("c");
if (v->type() == Value::VECTOR) {
for (size_t i = 0; i < 4; i++) {
node->color[i] = i < v.toVector().size() ? v.toVector()[i].toDouble() : 1.0;
node->color[i] = i < v->toVector().size() ? v->toVector()[i].toDouble() : 1.0;
if (node->color[i] > 1)
PRINTB_NOCACHE("WARNING: color() expects numbers between 0.0 and 1.0. Value of %.1f is too large.", node->color[i]);
}
} else if (v.type() == Value::STRING) {
std::string colorname = v.toString();
} else if (v->type() == Value::STRING) {
std::string colorname = v->toString();
boost::algorithm::to_lower(colorname);
Color4f color;
if (webcolors.find(colorname) != webcolors.end()) {
@ -239,9 +239,9 @@ AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantia
PRINT_NOCACHE("WARNING: http://en.wikipedia.org/wiki/Web_colors");
}
}
Value alpha = c.lookup_variable("alpha");
if (alpha.type() == Value::NUMBER) {
node->color[3] = alpha.toDouble();
ValuePtr alpha = c.lookup_variable("alpha");
if (alpha->type() == Value::NUMBER) {
node->color[3] = alpha->toDouble();
}
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);

View File

@ -78,14 +78,14 @@ void Context::setVariables(const AssignmentList &args,
const EvalContext *evalctx)
{
BOOST_FOREACH(const Assignment &arg, args) {
set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : Value());
set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : ValuePtr::undefined);
}
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);
ValuePtr val = evalctx->getArgValue(i);
if (name.empty()) {
if (posarg < args.size()) this->set_variable(args[posarg++].first, val);
} else {
@ -95,13 +95,18 @@ void Context::setVariables(const AssignmentList &args,
}
}
void Context::set_variable(const std::string &name, const Value &value)
void Context::set_variable(const std::string &name, const ValuePtr &value)
{
if (is_config_variable(name)) this->config_variables[name] = value;
else this->variables[name] = value;
}
void Context::set_constant(const std::string &name, const Value &value)
void Context::set_variable(const std::string &name, const Value &value)
{
set_variable(name, ValuePtr(value));
}
void Context::set_constant(const std::string &name, const ValuePtr &value)
{
if (this->constants.find(name) != this->constants.end()) {
PRINTB("WARNING: Attempt to modify constant '%s'.", name);
@ -111,11 +116,23 @@ void Context::set_constant(const std::string &name, const Value &value)
}
}
Value Context::lookup_variable(const std::string &name, bool silent) const
void Context::set_constant(const std::string &name, const Value &value)
{
set_constant(name, ValuePtr(value));
}
void Context::apply_variables(const Context &other)
{
for (ValueMap::const_iterator it = other.variables.begin();it != other.variables.end();it++) {
set_variable((*it).first, (*it).second);
}
}
ValuePtr Context::lookup_variable(const std::string &name, bool silent) const
{
if (!this->ctx_stack) {
PRINT("ERROR: Context had null stack in lookup_variable()!!");
return Value();
return ValuePtr::undefined;
}
if (is_config_variable(name)) {
for (int i = this->ctx_stack->size()-1; i >= 0; i--) {
@ -123,7 +140,7 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
if (confvars.find(name) != confvars.end())
return confvars.find(name)->second;
}
return Value();
return ValuePtr::undefined;
}
if (!this->parent && this->constants.find(name) != this->constants.end())
return this->constants.find(name)->second;
@ -133,7 +150,7 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
return this->parent->lookup_variable(name, silent);
if (!silent)
PRINTB("WARNING: Ignoring unknown variable '%s'.", name);
return Value();
return ValuePtr::undefined;
}
bool Context::has_local_variable(const std::string &name) const
@ -145,17 +162,30 @@ bool Context::has_local_variable(const std::string &name) const
return variables.find(name) != variables.end();
}
Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const
/**
* This is separated because PRINTB uses quite a lot of stack space
* and the methods using it evaluate_function() and instantiate_module()
* are called often when recursive functions or modules are evaluated.
*
* @param what what is ignored
* @param name name of the ignored object
*/
static void print_ignore_warning(const char *what, const char *name)
{
PRINTB("WARNING: Ignoring unknown %s '%s'.", what % name);
}
ValuePtr Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const
{
if (this->parent) return this->parent->evaluate_function(name, evalctx);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
print_ignore_warning("function", name.c_str());
return ValuePtr::undefined;
}
AbstractNode *Context::instantiate_module(const ModuleInstantiation &inst, EvalContext *evalctx) const
{
if (this->parent) return this->parent->instantiate_module(inst, evalctx);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());
print_ignore_warning("module", inst.name().c_str());
return NULL;
}
@ -190,7 +220,7 @@ std::string Context::dump(const AbstractModule *mod, const ModuleInstantiation *
}
}
}
typedef std::pair<std::string, Value> ValueMapType;
typedef std::pair<std::string, ValuePtr> ValueMapType;
s << " vars:";
BOOST_FOREACH(const ValueMapType &v, constants) {
s << boost::format(" %s = %s") % v.first % v.second;

View File

@ -5,6 +5,7 @@
#include <boost/unordered_map.hpp>
#include "value.h"
#include "typedefs.h"
#include "memory.h"
class Context
{
@ -14,29 +15,32 @@ public:
virtual ~Context();
const Context *getParent() const { return this->parent; }
virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
virtual ValuePtr evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, EvalContext *evalctx) const;
void setVariables(const AssignmentList &args,
const class EvalContext *evalctx = NULL);
void set_variable(const std::string &name, const ValuePtr &value);
void set_variable(const std::string &name, const Value &value);
void set_constant(const std::string &name, const ValuePtr &value);
void set_constant(const std::string &name, const Value &value);
Value lookup_variable(const std::string &name, bool silent = false) const;
void apply_variables(const Context &other);
ValuePtr lookup_variable(const std::string &name, bool silent = false) const;
bool has_local_variable(const std::string &name) 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:
protected:
const Context *parent;
Stack *ctx_stack;
typedef boost::unordered_map<std::string, Value> ValueMap;
typedef boost::unordered_map<std::string, ValuePtr> ValueMap;
ValueMap constants;
ValueMap variables;
ValueMap config_variables;

View File

@ -63,7 +63,7 @@ public: // methods
static const EvalContext* getLastModuleCtx(const EvalContext *evalctx);
static AbstractNode* getChild(const Value& value, const EvalContext* modulectx);
static AbstractNode* getChild(const Value &value, const EvalContext* modulectx);
private: // data
Type type;
@ -75,27 +75,27 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst
{
if (evalctx->numArgs() > l) {
const std::string &it_name = evalctx->getArgName(l);
const Value &it_values = evalctx->getArgValue(l, ctx);
ValuePtr it_values = evalctx->getArgValue(l, ctx);
Context c(ctx);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
if (it_values->type() == Value::RANGE) {
Value::RangeType range = it_values->toRange();
boost::uint32_t steps = range.nbsteps();
if (steps >= 10000) {
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
} else {
for (Value::RangeType::iterator it = range.begin();it != range.end();it++) {
c.set_variable(it_name, Value(*it));
c.set_variable(it_name, ValuePtr(*it));
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]);
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, &c, evalctx);
}
}
else if (it_values.type() != Value::UNDEFINED) {
else if (it_values->type() != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
for_eval(node, inst, l+1, &c, evalctx);
}
@ -173,7 +173,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
int n = 0;
if (evalctx->numArgs() > 0) {
double v;
if (evalctx->getArgValue(0).getDouble(v)) {
if (evalctx->getArgValue(0)->getDouble(v)) {
n = trunc(v);
if (n < 0) {
PRINTB("WARNING: Negative child index (%d) not allowed", n);
@ -221,13 +221,13 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
}
else if (evalctx->numArgs()>0) {
// one (or more ignored) parameter
const Value& value = evalctx->getArgValue(0);
if (value.type() == Value::NUMBER) {
return getChild(value,modulectx);
ValuePtr value = evalctx->getArgValue(0);
if (value->type() == Value::NUMBER) {
return getChild(*value, modulectx);
}
else if (value.type() == Value::VECTOR) {
else if (value->type() == Value::VECTOR) {
AbstractNode* node = new AbstractNode(inst);
const Value::VectorType& vect = value.toVector();
const Value::VectorType& vect = value->toVector();
foreach (const Value::VectorType::value_type& vectvalue, vect) {
AbstractNode* childnode = getChild(vectvalue,modulectx);
if (childnode==NULL) continue; // error
@ -235,9 +235,9 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
}
return node;
}
else if (value.type() == Value::RANGE) {
else if (value->type() == Value::RANGE) {
AbstractNode* node = new AbstractNode(inst);
Value::RangeType range = value.toRange();
Value::RangeType range = value->toRange();
boost::uint32_t steps = range.nbsteps();
if (steps >= 10000) {
PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps);
@ -253,7 +253,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
else {
// Invalid parameter
// (e.g. first child of difference is invalid)
PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString());
PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value->toString());
return NULL;
}
}
@ -268,11 +268,11 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
for (size_t i = 0; i < inst->arguments.size(); i++) {
if (i > 0) msg << ", ";
if (!evalctx->getArgName(i).empty()) msg << evalctx->getArgName(i) << " = ";
Value val = evalctx->getArgValue(i);
if (val.type() == Value::STRING) {
msg << '"' << val.toString() << '"';
ValuePtr val = evalctx->getArgValue(i);
if (val->type() == Value::STRING) {
msg << '"' << val->toString() << '"';
} else {
msg << val.toString();
msg << val->toString();
}
}
PRINTB("%s", msg.str());
@ -308,7 +308,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
case IF: {
node = new AbstractNode(inst);
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) {
if (evalctx->numArgs() > 0 && evalctx->getArgValue(0)->toBool()) {
inst->scope.apply(*evalctx);
std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());

View File

@ -39,11 +39,11 @@
#include <stdint.h>
#include <boost/filesystem.hpp>
boost::unordered_map<std::string,Value> dxf_dim_cache;
boost::unordered_map<std::string,Value> dxf_cross_cache;
boost::unordered_map<std::string, ValuePtr> dxf_dim_cache;
boost::unordered_map<std::string, ValuePtr> dxf_cross_cache;
namespace fs = boost::filesystem;
Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
ValuePtr builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@ -56,17 +56,16 @@ Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
// 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(),
ValuePtr n = evalctx->getArgName(i);
ValuePtr v = evalctx->getArgValue(i);
if (evalctx->getArgName(i) == "file") {
filename = lookup_file(v->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();
}
if (n == "layer") layername = v->toString();
if (n == "origin") v->getVec2(xorigin, yorigin);
if (n == "scale") v->getDouble(scale);
if (n == "name") name = v->toString();
}
std::stringstream keystream;
@ -100,46 +99,46 @@ Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
double y = d->coords[4][1] - d->coords[3][1];
double angle = d->angle;
double distance_projected_on_line = fabs(x * cos(angle*M_PI/180) + y * sin(angle*M_PI/180));
return dxf_dim_cache[key] = Value(distance_projected_on_line);
return dxf_dim_cache[key] = ValuePtr(distance_projected_on_line);
}
else if (type == 1) {
// Aligned
double x = d->coords[4][0] - d->coords[3][0];
double y = d->coords[4][1] - d->coords[3][1];
return dxf_dim_cache[key] = Value(sqrt(x*x + y*y));
return dxf_dim_cache[key] = ValuePtr(sqrt(x*x + y*y));
}
else if (type == 2) {
// Angular
double a1 = atan2(d->coords[0][0] - d->coords[5][0], d->coords[0][1] - d->coords[5][1]);
double a2 = atan2(d->coords[4][0] - d->coords[3][0], d->coords[4][1] - d->coords[3][1]);
return dxf_dim_cache[key] = Value(fabs(a1 - a2) * 180 / M_PI);
return dxf_dim_cache[key] = ValuePtr(fabs(a1 - a2) * 180 / M_PI);
}
else if (type == 3 || type == 4) {
// Diameter or Radius
double x = d->coords[5][0] - d->coords[0][0];
double y = d->coords[5][1] - d->coords[0][1];
return dxf_dim_cache[key] = Value(sqrt(x*x + y*y));
return dxf_dim_cache[key] = ValuePtr(sqrt(x*x + y*y));
}
else if (type == 5) {
// Angular 3 Point
}
else if (type == 6) {
// Ordinate
return dxf_dim_cache[key] = Value((d->type & 64) ? d->coords[3][0] : d->coords[3][1]);
return dxf_dim_cache[key] = ValuePtr((d->type & 64) ? d->coords[3][0] : d->coords[3][1]);
}
PRINTB("WARNING: Dimension '%s' in '%s', layer '%s' has unsupported type!",
name % filename % layername);
return Value();
return ValuePtr::undefined;
}
PRINTB("WARNING: Can't find dimension '%s' in '%s', layer '%s'!",
name % filename % layername);
return Value();
return ValuePtr::undefined;
}
Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
ValuePtr builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@ -151,14 +150,12 @@ Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
// 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);
ValuePtr n = evalctx->getArgName(i);
ValuePtr v = evalctx->getArgValue(i);
if (n == "file") filename = ctx->getAbsolutePath(v->toString());
if (n == "layer") layername = v->toString();
if (n == "origin") v->getVec2(xorigin, yorigin);
if (n == "scale") v->getDouble(scale);
}
std::stringstream keystream;
@ -174,8 +171,9 @@ Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
<< "|" << filesize;
std::string key = keystream.str();
if (dxf_cross_cache.find(key) != dxf_cross_cache.end())
if (dxf_cross_cache.find(key) != dxf_cross_cache.end()) {
return dxf_cross_cache.find(key)->second;
}
DxfData dxf(36, 0, 0, filename, layername, xorigin, yorigin, scale);
@ -204,13 +202,13 @@ Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
Value::VectorType ret;
ret.push_back(Value(x));
ret.push_back(Value(y));
return dxf_cross_cache[key] = Value(ret);
return dxf_cross_cache[key] = ValuePtr(ret);
}
}
PRINTB("WARNING: Can't find cross in '%s', layer '%s'!", filename % layername);
return Value();
return ValuePtr::undefined;
}
void initialize_builtin_dxf_dim()

View File

@ -3,5 +3,5 @@
#include <boost/unordered_map.hpp>
#include "value.h"
extern boost::unordered_map<std::string,Value> dxf_dim_cache;
extern boost::unordered_map<std::string,Value> dxf_cross_cache;
extern boost::unordered_map<std::string, ValuePtr> dxf_dim_cache;
extern boost::unordered_map<std::string, ValuePtr> dxf_cross_cache;

View File

@ -5,6 +5,7 @@
#include "printutils.h"
#include "builtin.h"
#include "localscope.h"
#include "exceptions.h"
#include <boost/foreach.hpp>
@ -20,11 +21,15 @@ const std::string &EvalContext::getArgName(size_t i) const
return this->eval_arguments[i].first;
}
Value EvalContext::getArgValue(size_t i, const Context *ctx) const
ValuePtr 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();
ValuePtr v;
if (arg.second) {
v = arg.second->evaluate(ctx ? ctx : this);
}
return v;
}
size_t EvalContext::numChildren() const
@ -62,7 +67,7 @@ std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiati
if (m) {
s << boost::format(" module args:");
BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
s << boost::format(" %s = %s") % arg.first % variables[arg.first];
s << boost::format(" %s = %s") % arg.first % *(variables[arg.first]);
}
}
}

View File

@ -17,7 +17,7 @@ public:
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;
ValuePtr getArgValue(size_t i, const Context *ctx = NULL) const;
size_t numChildren() const;
ModuleInstantiation *getChild(size_t i) const;

16
src/exceptions.h Normal file
View File

@ -0,0 +1,16 @@
#include <exception>
class RecursionException: public std::exception {
public:
RecursionException(const char *recursiontype, const std::string &name)
: rectype(recursiontype), name(name) {}
virtual ~RecursionException() throw() {}
virtual const char *what() const throw() {
std::stringstream out;
out << "ERROR: Recursion detected calling " << this->rectype << " '" << this->name << "'";
return out.str().c_str();
}
private:
const char *rectype;
const std::string name;
};

View File

@ -23,7 +23,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "expression.h"
#include "value.h"
#include "evalcontext.h"
@ -32,123 +31,21 @@
#include <algorithm>
#include "stl-utils.h"
#include "printutils.h"
#include "stackcheck.h"
#include "exceptions.h"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
Expression::Expression() : recursioncount(0)
{
}
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)
{
}
Expression::~Expression()
{
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
}
Value Expression::sub_evaluate_range(const Context *context) const
{
Value v1 = this->children[0]->evaluate(context);
if (v1.type() == Value::NUMBER) {
Value v2 = this->children[1]->evaluate(context);
if (v2.type() == Value::NUMBER) {
if (this->children.size() == 2) {
Value::RangeType range(v1.toDouble(), v2.toDouble());
return Value(range);
} else {
Value v3 = this->children[2]->evaluate(context);
if (v3.type() == Value::NUMBER) {
Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble());
return Value(range);
}
}
}
}
return Value();
}
Value Expression::sub_evaluate_member(const Context *context) const
{
Value v = this->children[0]->evaluate(context);
if (v.type() == Value::VECTOR) {
if (this->var_name == "x") return v[0];
if (this->var_name == "y") return v[1];
if (this->var_name == "z") return v[2];
} else if (v.type() == Value::RANGE) {
if (this->var_name == "begin") return Value(v[0]);
if (this->var_name == "step") return Value(v[1]);
if (this->var_name == "end") return Value(v[2]);
}
return Value();
}
Value Expression::sub_evaluate_vector(const Context *context) const
{
Value::VectorType vec;
BOOST_FOREACH(const Expression *e, this->children) {
vec.push_back(e->evaluate(context));
}
return Value(vec);
}
Value Expression::sub_evaluate_function(const Context *context) const
{
if (this->recursioncount >= 1000) {
PRINTB("ERROR: Recursion detected calling function '%s'", this->call_funcname);
// TO DO: throw function_recursion_detected();
return Value();
}
this->recursioncount += 1;
EvalContext c(context, this->call_arguments);
const Value &result = context->evaluate_function(this->call_funcname, &c);
this->recursioncount -= 1;
return result;
}
#define TYPE2INT(c,c1) ((int)(c) | ((int)(c1)<<8))
static inline int type2int(register const char *typestr)
{
// the following asserts basic ASCII only so sign extension does not matter
// utilize the fact that type strings must have one or two non-null characters
#if 0 // defined(DEBUG) // may need this code as template for future development
register int c1, result = *typestr;
if (result && 0 != (c1 = typestr[1])) {
// take the third character for error checking only
result |= (c1 << 8) | ((int)typestr[2] << 16);
}
return result;
#else
return TYPE2INT(typestr[0], typestr[1]);
#endif
}
// unnamed namespace
namespace {
Value::VectorType flatten(Value::VectorType const& vec) {
int n = 0;
for (int i = 0; i < vec.size(); i++) {
for (unsigned int i = 0; i < vec.size(); i++) {
assert(vec[i].type() == Value::VECTOR);
n += vec[i].toVector().size();
}
Value::VectorType ret; ret.reserve(n);
for (int i = 0; i < vec.size(); i++) {
for (unsigned int i = 0; i < vec.size(); i++) {
std::copy(vec[i].toVector().begin(),vec[i].toVector().end(),std::back_inserter(ret));
}
return ret;
@ -159,9 +56,9 @@ namespace {
const bool allow_reassignment = false;
for (int i = 0; i < let_context.numArgs(); i++) {
for (unsigned int i = 0; i < let_context.numArgs(); i++) {
if (!allow_reassignment && context->has_local_variable(let_context.getArgName(i))) {
PRINTB("WARNING: Ignoring duplicate variable assignment %s = %s", let_context.getArgName(i) % let_context.getArgValue(i, context).toString());
PRINTB("WARNING: Ignoring duplicate variable assignment %s = %s", let_context.getArgName(i) % let_context.getArgValue(i, context)->toString());
} else {
// NOTE: iteratively evaluated list of arguments
context->set_variable(let_context.getArgName(i), let_context.getArgValue(i, context));
@ -170,133 +67,32 @@ namespace {
}
}
Value Expression::sub_evaluate_let_expression(const Context *context) const
Expression::Expression() : first(NULL), second(NULL), third(NULL)
{
Context c(context);
evaluate_sequential_assignment(this->call_arguments, &c);
return this->children[0]->evaluate(&c);
}
Value Expression::sub_evaluate_list_comprehension(const Context *context) const
Expression::Expression(Expression *expr) : first(expr), second(NULL), third(NULL)
{
Value::VectorType vec;
if (this->call_funcname == "if") {
if (this->children[0]->evaluate(context)) {
if (this->children[1]->type == "c") {
return this->children[1]->evaluate(context);
} else {
vec.push_back(this->children[1]->evaluate(context));
}
}
return vec;
} else if (this->call_funcname == "for") {
EvalContext for_context(context, this->call_arguments);
Context assign_context(context);
// comprehension for statements are by the parser reduced to only contain one single element
const std::string &it_name = for_context.getArgName(0);
const Value &it_values = for_context.getArgValue(0, &assign_context);
Context c(context);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
boost::uint32_t steps = range.nbsteps();
if (steps >= 1000000) {
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
} else {
for (Value::RangeType::iterator it = range.begin();it != range.end();it++) {
c.set_variable(it_name, Value(*it));
vec.push_back(this->children[0]->evaluate(&c));
}
}
}
else if (it_values.type() == Value::VECTOR) {
for (size_t i = 0; i < it_values.toVector().size(); i++) {
c.set_variable(it_name, it_values.toVector()[i]);
vec.push_back(this->children[0]->evaluate(&c));
}
}
else if (it_values.type() != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
vec.push_back(this->children[0]->evaluate(&c));
}
if (this->children[0]->type == "c") {
return flatten(vec);
} else {
return vec;
}
} else if (this->call_funcname == "let") {
Context c(context);
evaluate_sequential_assignment(this->call_arguments, &c);
return this->children[0]->evaluate(&c);
} else {
abort();
}
children.push_back(expr);
}
Value Expression::evaluate(const Context *context) const
Expression::Expression(Expression *left, Expression *right) : first(left), second(right), third(NULL)
{
switch (type2int(this->type.c_str())) {
case '!':
return ! this->children[0]->evaluate(context);
case TYPE2INT('&','&'):
return this->children[0]->evaluate(context) && this->children[1]->evaluate(context);
case TYPE2INT('|','|'):
return this->children[0]->evaluate(context) || this->children[1]->evaluate(context);
case '*':
return this->children[0]->evaluate(context) * this->children[1]->evaluate(context);
case '/':
return this->children[0]->evaluate(context) / this->children[1]->evaluate(context);
case '%':
return this->children[0]->evaluate(context) % this->children[1]->evaluate(context);
case '+':
return this->children[0]->evaluate(context) + this->children[1]->evaluate(context);
case '-':
return this->children[0]->evaluate(context) - this->children[1]->evaluate(context);
case '<':
return this->children[0]->evaluate(context) < this->children[1]->evaluate(context);
case TYPE2INT('<','='):
return this->children[0]->evaluate(context) <= this->children[1]->evaluate(context);
case TYPE2INT('=','='):
return this->children[0]->evaluate(context) == this->children[1]->evaluate(context);
case TYPE2INT('!','='):
return this->children[0]->evaluate(context) != this->children[1]->evaluate(context);
case TYPE2INT('>','='):
return this->children[0]->evaluate(context) >= this->children[1]->evaluate(context);
case '>':
return this->children[0]->evaluate(context) > this->children[1]->evaluate(context);
case TYPE2INT('?',':'):
return this->children[this->children[0]->evaluate(context) ? 1 : 2]->evaluate(context);
case TYPE2INT('[',']'):
return this->children[0]->evaluate(context)[this->children[1]->evaluate(context)];
case 'I':
return -this->children[0]->evaluate(context);
case 'C':
return this->const_value;
case 'R':
return sub_evaluate_range(context);
case 'V':
return sub_evaluate_vector(context);
case 'L':
return context->lookup_variable(this->var_name);
case 'N':
return sub_evaluate_member(context);
case 'F':
return sub_evaluate_function(context);
case 'l':
return sub_evaluate_let_expression(context);
case 'i': // list comprehension expression
return this->children[0]->evaluate(context);
case 'c':
return sub_evaluate_list_comprehension(context);
}
abort();
children.push_back(left);
children.push_back(right);
}
Expression::Expression(Expression *expr1, Expression *expr2, Expression *expr3)
: first(expr1), second(expr2), third(expr3)
{
children.push_back(expr1);
children.push_back(expr2);
children.push_back(expr3);
}
Expression::~Expression()
{
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
}
namespace /* anonymous*/ {
@ -313,89 +109,509 @@ namespace /* anonymous*/ {
}
std::string Expression::toString() const
bool Expression::isListComprehension() const
{
std::stringstream stream;
return false;
}
if (this->type == "*" || this->type == "/" || this->type == "%" || this->type == "+" ||
this->type == "-" || this->type == "<" || this->type == "<=" || this->type == "==" ||
this->type == "!=" || this->type == ">=" || this->type == ">" ||
this->type == "&&" || this->type == "||") {
stream << "(" << *this->children[0] << " " << this->type << " " << *this->children[1] << ")";
}
else if (this->type == "?:") {
stream << "(" << *this->children[0] << " ? " << *this->children[1] << " : " << *this->children[2] << ")";
}
else if (this->type == "[]") {
stream << *this->children[0] << "[" << *this->children[1] << "]";
}
else if (this->type == "I") {
stream << "-" << *this->children[0];
}
else if (this->type == "!") {
stream << "!" << *this->children[0];
}
else if (this->type == "C") {
stream << this->const_value;
}
else if (this->type == "R") {
stream << "[" << *this->children[0] << " : " << *this->children[1];
if (this->children.size() > 2) {
stream << " : " << *this->children[2];
}
stream << "]";
}
else if (this->type == "V") {
stream << "[";
for (size_t i=0; i < this->children.size(); i++) {
if (i > 0) stream << ", ";
stream << *this->children[i];
}
stream << "]";
}
else if (this->type == "L") {
stream << this->var_name;
}
else if (this->type == "N") {
stream << *this->children[0] << "." << this->var_name;
}
else if (this->type == "F") {
stream << this->call_funcname << "(" << this->call_arguments << ")";
}
else if (this->type == "l") {
stream << "let(" << this->call_arguments << ") " << *this->children[0];
}
else if (this->type == "i") { // list comprehension expression
Expression const* c = this->children[0];
ExpressionNot::ExpressionNot(Expression *expr) : Expression(expr)
{
}
stream << "[";
ValuePtr ExpressionNot::evaluate(const Context *context) const
{
return !first->evaluate(context);
}
do {
if (c->call_funcname == "for") {
stream << "for(" << c->call_arguments << ") ";
c = c->children[0];
} else if (c->call_funcname == "if") {
stream << "if(" << *c->children[0] << ") ";
c = c->children[1];
} else if (c->call_funcname == "let") {
stream << "let(" << c->call_arguments << ") ";
c = c->children[0];
void ExpressionNot::print(std::ostream &stream) const
{
stream << "!" << *first;
}
ExpressionLogicalAnd::ExpressionLogicalAnd(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionLogicalAnd::evaluate(const Context *context) const
{
return this->first->evaluate(context) && this->second->evaluate(context);
}
void ExpressionLogicalAnd::print(std::ostream &stream) const
{
stream << "(" << *first << " && " << *second << ")";
}
ExpressionLogicalOr::ExpressionLogicalOr(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionLogicalOr::evaluate(const Context *context) const
{
return this->first->evaluate(context) || this->second->evaluate(context);
}
void ExpressionLogicalOr::print(std::ostream &stream) const
{
stream << "(" << *first << " || " << *second << ")";
}
ExpressionMultiply::ExpressionMultiply(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionMultiply::evaluate(const Context *context) const
{
return this->first->evaluate(context) * this->second->evaluate(context);
}
void ExpressionMultiply::print(std::ostream &stream) const
{
stream << "(" << *first << " * " << *second << ")";
}
ExpressionDivision::ExpressionDivision(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionDivision::evaluate(const Context *context) const
{
return this->first->evaluate(context) / this->second->evaluate(context);
}
void ExpressionDivision::print(std::ostream &stream) const
{
stream << "(" << *first << " / " << *second << ")";
}
ExpressionModulo::ExpressionModulo(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionModulo::evaluate(const Context *context) const
{
return this->first->evaluate(context) % this->second->evaluate(context);
}
void ExpressionModulo::print(std::ostream &stream) const
{
stream << "(" << *first << " % " << *second << ")";
}
ExpressionPlus::ExpressionPlus(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionPlus::evaluate(const Context *context) const
{
return this->first->evaluate(context) + this->second->evaluate(context);
}
void ExpressionPlus::print(std::ostream &stream) const
{
stream << "(" << *first << " + " << *second << ")";
}
ExpressionMinus::ExpressionMinus(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionMinus::evaluate(const Context *context) const
{
return this->first->evaluate(context) - this->second->evaluate(context);
}
void ExpressionMinus::print(std::ostream &stream) const
{
stream << "(" << *first << " - " << *second << ")";
}
ExpressionLess::ExpressionLess(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionLess::evaluate(const Context *context) const
{
return this->first->evaluate(context) < this->second->evaluate(context);
}
void ExpressionLess::print(std::ostream &stream) const
{
stream << "(" << *first << " < " << *second << ")";
}
ExpressionLessOrEqual::ExpressionLessOrEqual(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionLessOrEqual::evaluate(const Context *context) const
{
return this->first->evaluate(context) <= this->second->evaluate(context);
}
void ExpressionLessOrEqual::print(std::ostream &stream) const
{
stream << "(" << *first << " <= " << *second << ")";
}
ExpressionEqual::ExpressionEqual(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionEqual::evaluate(const Context *context) const
{
return this->first->evaluate(context) == this->second->evaluate(context);
}
void ExpressionEqual::print(std::ostream &stream) const
{
stream << "(" << *first << " == " << *second << ")";
}
ExpressionNotEqual::ExpressionNotEqual(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionNotEqual::evaluate(const Context *context) const
{
return this->first->evaluate(context) != this->second->evaluate(context);
}
void ExpressionNotEqual::print(std::ostream &stream) const
{
stream << "(" << *first << " != " << *second << ")";
}
ExpressionGreaterOrEqual::ExpressionGreaterOrEqual(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionGreaterOrEqual::evaluate(const Context *context) const
{
return this->first->evaluate(context) >= this->second->evaluate(context);
}
void ExpressionGreaterOrEqual::print(std::ostream &stream) const
{
stream << "(" << *first << " >= " << *second << ")";
}
ExpressionGreater::ExpressionGreater(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionGreater::evaluate(const Context *context) const
{
return this->first->evaluate(context) > this->second->evaluate(context);
}
void ExpressionGreater::print(std::ostream &stream) const
{
stream << "(" << *first << " > " << *second << ")";
}
ExpressionTernary::ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3) : Expression(expr1, expr2, expr3)
{
}
ValuePtr ExpressionTernary::evaluate(const Context *context) const
{
return (this->first->evaluate(context) ? this->second : this->third)->evaluate(context);
}
void ExpressionTernary::print(std::ostream &stream) const
{
stream << "(" << *first << " ? " << *second << " : " << *third << ")";
}
ExpressionArrayLookup::ExpressionArrayLookup(Expression *left, Expression *right) : Expression(left, right)
{
}
ValuePtr ExpressionArrayLookup::evaluate(const Context *context) const {
return this->first->evaluate(context)[this->second->evaluate(context)];
}
void ExpressionArrayLookup::print(std::ostream &stream) const
{
stream << *first << "[" << *second << "]";
}
ExpressionInvert::ExpressionInvert(Expression *expr) : Expression(expr)
{
}
ValuePtr ExpressionInvert::evaluate(const Context *context) const
{
return -this->first->evaluate(context);
}
void ExpressionInvert::print(std::ostream &stream) const
{
stream << "-" << *first;
}
ExpressionConst::ExpressionConst(const ValuePtr &val) : const_value(val)
{
}
ValuePtr ExpressionConst::evaluate(const class Context *) const
{
return ValuePtr(this->const_value);
}
void ExpressionConst::print(std::ostream &stream) const
{
stream << *this->const_value;
}
ExpressionRange::ExpressionRange(Expression *expr1, Expression *expr2) : Expression(expr1, expr2)
{
}
ExpressionRange::ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3) : Expression(expr1, expr2, expr3)
{
}
ValuePtr ExpressionRange::evaluate(const Context *context) const
{
ValuePtr v1 = this->first->evaluate(context);
if (v1->type() == Value::NUMBER) {
ValuePtr v2 = this->second->evaluate(context);
if (v2->type() == Value::NUMBER) {
if (this->children.size() == 2) {
Value::RangeType range(v1->toDouble(), v2->toDouble());
return ValuePtr(range);
} else {
assert(false && "Illegal list comprehension element");
ValuePtr v3 = this->third->evaluate(context);
if (v3->type() == Value::NUMBER) {
Value::RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble());
return ValuePtr(range);
}
}
} while (c->type == "c");
stream << *c << "]";
}
else {
assert(false && "Illegal expression type");
}
}
return ValuePtr::undefined;
}
return stream.str();
void ExpressionRange::print(std::ostream &stream) const
{
stream << "[" << *first << " : " << *second;
if (this->children.size() > 2) stream << " : " << *third;
stream << "]";
}
ExpressionVector::ExpressionVector(Expression *expr) : Expression(expr)
{
}
ValuePtr ExpressionVector::evaluate(const Context *context) const
{
Value::VectorType vec;
BOOST_FOREACH(const Expression *e, this->children) {
vec.push_back(*(e->evaluate(context)));
}
return ValuePtr(vec);
}
void ExpressionVector::print(std::ostream &stream) const
{
stream << "[";
for (size_t i=0; i < this->children.size(); i++) {
if (i > 0) stream << ", ";
stream << *this->children[i];
}
stream << "]";
}
ExpressionLookup::ExpressionLookup(const std::string &var_name) : var_name(var_name)
{
}
ValuePtr ExpressionLookup::evaluate(const Context *context) const
{
return context->lookup_variable(this->var_name);
}
void ExpressionLookup::print(std::ostream &stream) const
{
stream << this->var_name;
}
ExpressionMember::ExpressionMember(Expression *expr, const std::string &member)
: Expression(expr), member(member)
{
}
ValuePtr ExpressionMember::evaluate(const Context *context) const
{
ValuePtr v = this->first->evaluate(context);
if (v->type() == Value::VECTOR) {
if (this->member == "x") return v[0];
if (this->member == "y") return v[1];
if (this->member == "z") return v[2];
} else if (v->type() == Value::RANGE) {
if (this->member == "begin") return v[0];
if (this->member == "step") return v[1];
if (this->member == "end") return v[2];
}
return ValuePtr::undefined;
}
void ExpressionMember::print(std::ostream &stream) const
{
stream << *first << "." << this->member;
}
ExpressionFunctionCall::ExpressionFunctionCall(const std::string &funcname,
const AssignmentList &arglist)
: funcname(funcname), call_arguments(arglist)
{
}
ValuePtr ExpressionFunctionCall::evaluate(const Context *context) const
{
if (StackCheck::inst()->check()) {
throw RecursionException("function", funcname);
}
EvalContext c(context, this->call_arguments);
ValuePtr result = context->evaluate_function(this->funcname, &c);
return result;
}
void ExpressionFunctionCall::print(std::ostream &stream) const
{
stream << this->funcname << "(" << this->call_arguments << ")";
}
ExpressionLet::ExpressionLet(const AssignmentList &arglist, Expression *expr)
: Expression(expr), call_arguments(arglist)
{
}
ValuePtr ExpressionLet::evaluate(const Context *context) const
{
Context c(context);
evaluate_sequential_assignment(this->call_arguments, &c);
return this->first->evaluate(&c);
}
void ExpressionLet::print(std::ostream &stream) const
{
stream << "let(" << this->call_arguments << ") " << *first;
}
ExpressionLcExpression::ExpressionLcExpression(Expression *expr) : Expression(expr)
{
}
ValuePtr ExpressionLcExpression::evaluate(const Context *context) const
{
return this->first->evaluate(context);
}
void ExpressionLcExpression::print(std::ostream &stream) const
{
stream << "[" << *this->first << "]";
}
ExpressionLc::ExpressionLc(const std::string &name,
const AssignmentList &arglist, Expression *expr)
: Expression(expr), name(name), call_arguments(arglist)
{
}
ExpressionLc::ExpressionLc(const std::string &name,
Expression *expr1, Expression *expr2)
: Expression(expr1, expr2), name(name)
{
}
bool ExpressionLc::isListComprehension() const
{
return true;
}
ValuePtr ExpressionLc::evaluate(const Context *context) const
{
Value::VectorType vec;
if (this->name == "if") {
if (this->first->evaluate(context)) {
if (this->second->isListComprehension()) {
return this->second->evaluate(context);
} else {
vec.push_back((*this->second->evaluate(context)));
}
}
return ValuePtr(vec);
} else if (this->name == "for") {
EvalContext for_context(context, this->call_arguments);
Context assign_context(context);
// comprehension for statements are by the parser reduced to only contain one single element
const std::string &it_name = for_context.getArgName(0);
ValuePtr it_values = for_context.getArgValue(0, &assign_context);
Context c(context);
if (it_values->type() == Value::RANGE) {
Value::RangeType range = it_values->toRange();
boost::uint32_t steps = range.nbsteps();
if (steps >= 1000000) {
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
} else {
for (Value::RangeType::iterator it = range.begin();it != range.end();it++) {
c.set_variable(it_name, ValuePtr(*it));
vec.push_back((*this->first->evaluate(&c)));
}
}
}
else if (it_values->type() == Value::VECTOR) {
for (size_t i = 0; i < it_values->toVector().size(); i++) {
c.set_variable(it_name, it_values->toVector()[i]);
vec.push_back((*this->first->evaluate(&c)));
}
}
else if (it_values->type() != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
vec.push_back((*this->first->evaluate(&c)));
}
if (this->first->isListComprehension()) {
return ValuePtr(flatten(vec));
} else {
return ValuePtr(vec);
}
} else if (this->name == "let") {
Context c(context);
evaluate_sequential_assignment(this->call_arguments, &c);
return this->first->evaluate(&c);
} else {
abort();
}
}
void ExpressionLc::print(std::ostream &stream) const
{
stream << this->name;
if (this->name == "if") {
stream << "(" << *this->first << ") " << *this->second;
}
else if (this->name == "for" || this->name == "let") {
stream << "(" << this->call_arguments << ") " << *this->first;
} else {
assert(false && "Illegal list comprehension element");
}
}
std::ostream &operator<<(std::ostream &stream, const Expression &expr)
{
stream << expr.toString();
expr.print(stream);
return stream;
}

View File

@ -9,51 +9,247 @@ class Expression
{
public:
std::vector<Expression*> children;
const Value const_value;
std::string var_name;
std::string call_funcname;
AssignmentList call_arguments;
// Boolean: ! && ||
// Operators: * / % + -
// Relations: < <= == != >= >
// Vector element: []
// Condition operator: ?:
// Invert (prefix '-'): I
// Constant value: C
// Create Range: R
// Create Vector: V
// Create Matrix: M
// Lookup Variable: L
// Lookup member per name: N
// Function call: F
// Let expression: l
// List comprehension expression: i
// List comprehension: c
std::string type;
Expression *first;
Expression *second;
Expression *third;
Expression();
Expression(const Value &val);
Expression(const std::string &type, Expression *left, Expression *right);
Expression(const std::string &type, Expression *expr);
~Expression();
Expression(Expression *expr);
Expression(Expression *left, Expression *right);
Expression(Expression *expr1, Expression *expr2, Expression *expr3);
virtual ~Expression();
Value evaluate(const class Context *context) const;
std::string toString() const;
private:
mutable int recursioncount;
// The following sub_* methods are needed to minimize stack usage only.
Value sub_evaluate_function(const class Context *context) const;
Value sub_evaluate_member(const class Context *context) const;
Value sub_evaluate_range(const class Context *context) const;
Value sub_evaluate_vector(const class Context *context) const;
Value sub_evaluate_let_expression(const class Context *context) const;
Value sub_evaluate_list_comprehension(const class Context *context) const;
virtual bool isListComprehension() const;
virtual ValuePtr evaluate(const class Context *context) const = 0;
virtual void print(std::ostream &stream) const = 0;
};
std::ostream &operator<<(std::ostream &stream, const Expression &expr);
class ExpressionNot : public Expression
{
public:
ExpressionNot(Expression *expr);
virtual ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLogicalAnd : public Expression
{
public:
ExpressionLogicalAnd(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLogicalOr : public Expression
{
public:
ExpressionLogicalOr(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionMultiply : public Expression
{
public:
ExpressionMultiply(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionDivision : public Expression
{
public:
ExpressionDivision(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionModulo : public Expression
{
public:
ExpressionModulo(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionPlus : public Expression
{
public:
ExpressionPlus(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionMinus : public Expression
{
public:
ExpressionMinus(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLess : public Expression
{
public:
ExpressionLess(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLessOrEqual : public Expression
{
public:
ExpressionLessOrEqual(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionEqual : public Expression
{
public:
ExpressionEqual(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionNotEqual : public Expression
{
public:
ExpressionNotEqual(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionGreaterOrEqual : public Expression
{
public:
ExpressionGreaterOrEqual(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionGreater : public Expression
{
public:
ExpressionGreater(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionTernary : public Expression
{
public:
ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionArrayLookup : public Expression
{
public:
ExpressionArrayLookup(Expression *left, Expression *right);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
};
class ExpressionInvert : public Expression
{
public:
ExpressionInvert(Expression *expr);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionConst : public Expression
{
public:
ExpressionConst(const ValuePtr &val);
ValuePtr evaluate(const class Context *) const;
virtual void print(std::ostream &stream) const;
private:
ValuePtr const_value;
};
class ExpressionRange : public Expression
{
public:
ExpressionRange(Expression *expr1, Expression *expr2);
ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionVector : public Expression
{
public:
ExpressionVector(Expression *expr);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLookup : public Expression
{
public:
ExpressionLookup(const std::string &var_name);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
std::string var_name;
};
class ExpressionMember : public Expression
{
public:
ExpressionMember(Expression *expr, const std::string &member);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
std::string member;
};
class ExpressionFunctionCall : public Expression
{
public:
ExpressionFunctionCall(const std::string &funcname, const AssignmentList &arglist);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
public:
std::string funcname;
AssignmentList call_arguments;
};
class ExpressionLet : public Expression
{
public:
ExpressionLet(const AssignmentList &arglist, Expression *expr);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
AssignmentList call_arguments;
};
class ExpressionLcExpression : public Expression
{
public:
ExpressionLcExpression(Expression *expr);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
};
class ExpressionLc : public Expression
{
virtual bool isListComprehension() const;
public:
ExpressionLc(const std::string &name,
const AssignmentList &arglist, Expression *expr);
ExpressionLc(const std::string &name,
Expression *expr1, Expression *expr2);
ValuePtr evaluate(const class Context *context) const;
virtual void print(std::ostream &stream) const;
private:
std::string name;
AssignmentList call_arguments;
};

View File

@ -35,6 +35,7 @@
#include <algorithm>
#include "stl-utils.h"
#include "printutils.h"
#include "stackcheck.h"
#include <boost/foreach.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
@ -69,10 +70,11 @@ AbstractFunction::~AbstractFunction()
{
}
Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const
// FIXME: Is this needed?
ValuePtr AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const
{
(void)evalctx; // unusued parameter
return Value();
return ValuePtr::undefined;
}
std::string AbstractFunction::dump(const std::string &indent, const std::string &name) const
@ -82,17 +84,24 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string
return dump.str();
}
Function::Function(const char *name, AssignmentList &definition_arguments, Expression *expr)
: name(name), definition_arguments(definition_arguments), expr(expr)
{
}
Function::~Function()
{
delete expr;
}
Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
ValuePtr Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
if (!expr) return Value();
if (!expr) return ValuePtr::undefined;
Context c(ctx);
c.setVariables(definition_arguments, evalctx);
return expr->evaluate(&c);
ValuePtr result = expr->evaluate(&c);
return result;
}
std::string Function::dump(const std::string &indent, const std::string &name) const
@ -109,11 +118,71 @@ std::string Function::dump(const std::string &indent, const std::string &name) c
return dump.str();
}
class FunctionTailRecursion : public Function
{
private:
bool invert;
ExpressionFunctionCall *call; // memory owned by the main expression
Expression *endexpr; // memory owned by the main expression
public:
FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert);
virtual ~FunctionTailRecursion();
virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const;
};
FunctionTailRecursion::FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert)
: Function(name, definition_arguments, expr), invert(invert), call(call), endexpr(endexpr)
{
}
FunctionTailRecursion::~FunctionTailRecursion()
{
}
ValuePtr FunctionTailRecursion::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
if (!expr) return ValuePtr::undefined;
Context c(ctx);
c.setVariables(definition_arguments, evalctx);
EvalContext ec(&c, call->call_arguments);
Context tmp(&c);
while (invert ^ expr->first->evaluate(&c)) {
tmp.setVariables(definition_arguments, &ec);
c.apply_variables(tmp);
}
ValuePtr result = endexpr->evaluate(&c);
return result;
}
Function * Function::create(const char *name, AssignmentList &definition_arguments, Expression *expr)
{
if (dynamic_cast<ExpressionTernary *>(expr)) {
ExpressionFunctionCall *f1 = dynamic_cast<ExpressionFunctionCall *>(expr->second);
ExpressionFunctionCall *f2 = dynamic_cast<ExpressionFunctionCall *>(expr->third);
if (f1 && !f2) {
if (name == f1->funcname) {
return new FunctionTailRecursion(name, definition_arguments, expr, f1, expr->third, false);
}
} else if (f2 && !f1) {
if (name == f2->funcname) {
return new FunctionTailRecursion(name, definition_arguments, expr, f2, expr->second, true);
}
}
}
return new Function(name, definition_arguments, expr);
}
BuiltinFunction::~BuiltinFunction()
{
}
Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const
ValuePtr BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
return eval_func(ctx, evalctx);
}
@ -135,51 +204,51 @@ static inline double rad2deg(double x)
return x * 180.0 / M_PI;
}
Value builtin_abs(const Context *, const EvalContext *evalctx)
ValuePtr builtin_abs(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(fabs(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(fabs(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_sign(const Context *, const EvalContext *evalctx)
ValuePtr builtin_sign(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER) {
register double x = v.toDouble();
return Value((x<0) ? -1.0 : ((x>0) ? 1.0 : 0.0));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER) {
register double x = v->toDouble();
return ValuePtr((x<0) ? -1.0 : ((x>0) ? 1.0 : 0.0));
}
}
return Value();
return ValuePtr::undefined;
}
Value builtin_rands(const Context *, const EvalContext *evalctx)
ValuePtr builtin_rands(const Context *, const EvalContext *evalctx)
{
size_t n = evalctx->numArgs();
if (n == 3 || n == 4) {
const Value &v0 = evalctx->getArgValue(0);
if (v0.type() != Value::NUMBER) goto quit;
double min = v0.toDouble();
ValuePtr v0 = evalctx->getArgValue(0);
if (v0->type() != Value::NUMBER) goto quit;
double min = v0->toDouble();
const Value &v1 = evalctx->getArgValue(1);
if (v1.type() != Value::NUMBER) goto quit;
double max = v1.toDouble();
ValuePtr v1 = evalctx->getArgValue(1);
if (v1->type() != Value::NUMBER) goto quit;
double max = v1->toDouble();
if (max < min) {
register double tmp = min; min = max; max = tmp;
}
const Value &v2 = evalctx->getArgValue(2);
if (v2.type() != Value::NUMBER) goto quit;
size_t numresults = std::max( 0, static_cast<int>( v2.toDouble() ) );
ValuePtr v2 = evalctx->getArgValue(2);
if (v2->type() != Value::NUMBER) goto quit;
size_t numresults = std::max(0, static_cast<int>(v2->toDouble()));
bool deterministic = false;
if (n > 3) {
const Value &v3 = evalctx->getArgValue(3);
if (v3.type() != Value::NUMBER) goto quit;
deterministic_rng.seed( (unsigned int) v3.toDouble() );
ValuePtr v3 = evalctx->getArgValue(3);
if (v3->type() != Value::NUMBER) goto quit;
deterministic_rng.seed((unsigned int) v3->toDouble());
deterministic = true;
}
boost::uniform_real<> distributor( min, max );
@ -190,83 +259,81 @@ Value builtin_rands(const Context *, const EvalContext *evalctx)
} else {
for (size_t i=0; i < numresults; i++) {
if ( deterministic ) {
vec.push_back( Value( distributor( deterministic_rng ) ) );
vec.push_back(Value(distributor(deterministic_rng)));
} else {
vec.push_back( Value( distributor( lessdeterministic_rng ) ) );
vec.push_back(Value(distributor(lessdeterministic_rng)));
}
}
}
return Value(vec);
return ValuePtr(vec);
}
quit:
return Value();
return ValuePtr::undefined;
}
Value builtin_min(const Context *, const EvalContext *evalctx)
ValuePtr builtin_min(const Context *, const EvalContext *evalctx)
{
// preserve special handling of the first argument
// as a template for vector processing
size_t n = evalctx->numArgs();
if (n >= 1) {
const Value &v0 = evalctx->getArgValue(0);
ValuePtr v0 = evalctx->getArgValue(0);
if (n == 1 && v0.type() == Value::VECTOR && !v0.toVector().empty()) {
Value min = v0.toVector()[0];
for (size_t i = 1; i < v0.toVector().size(); i++) {
if (v0.toVector()[i] < min)
min = v0.toVector()[i];
if (n == 1 && v0->type() == Value::VECTOR && !v0->toVector().empty()) {
Value min = v0->toVector()[0];
for (size_t i = 1; i < v0->toVector().size(); i++) {
if (v0->toVector()[i] < min) min = v0->toVector()[i];
}
return min;
return ValuePtr(min);
}
if (v0.type() == Value::NUMBER) {
double val = v0.toDouble();
if (v0->type() == Value::NUMBER) {
double val = v0->toDouble();
for (size_t i = 1; i < n; ++i) {
const Value &v = evalctx->getArgValue(i);
ValuePtr v = evalctx->getArgValue(i);
// 4/20/14 semantic change per discussion:
// break on any non-number
if (v.type() != Value::NUMBER) goto quit;
register double x = v.toDouble();
if (v->type() != Value::NUMBER) goto quit;
register double x = v->toDouble();
if (x < val) val = x;
}
return Value(val);
return ValuePtr(val);
}
}
quit:
return Value();
return ValuePtr::undefined;
}
Value builtin_max(const Context *, const EvalContext *evalctx)
ValuePtr builtin_max(const Context *, const EvalContext *evalctx)
{
// preserve special handling of the first argument
// as a template for vector processing
size_t n = evalctx->numArgs();
if (n >= 1) {
const Value &v0 = evalctx->getArgValue(0);
ValuePtr v0 = evalctx->getArgValue(0);
if (n == 1 && v0.type() == Value::VECTOR && !v0.toVector().empty()) {
Value max = v0.toVector()[0];
for (size_t i = 1; i < v0.toVector().size(); i++) {
if (v0.toVector()[i] > max)
max = v0.toVector()[i];
if (n == 1 && v0->type() == Value::VECTOR && !v0->toVector().empty()) {
Value max = v0->toVector()[0];
for (size_t i = 1; i < v0->toVector().size(); i++) {
if (v0->toVector()[i] > max) max = v0->toVector()[i];
}
return max;
return ValuePtr(max);
}
if (v0.type() == Value::NUMBER) {
double val = v0.toDouble();
if (v0->type() == Value::NUMBER) {
double val = v0->toDouble();
for (size_t i = 1; i < n; ++i) {
const Value &v = evalctx->getArgValue(i);
ValuePtr v = evalctx->getArgValue(i);
// 4/20/14 semantic change per discussion:
// break on any non-number
if (v.type() != Value::NUMBER) goto quit;
register double x = v.toDouble();
if (v->type() != Value::NUMBER) goto quit;
register double x = v->toDouble();
if (x > val) val = x;
}
return Value(val);
return ValuePtr(val);
}
}
quit:
return Value();
return ValuePtr::undefined;
}
// this limit assumes 26+26=52 bits mantissa
@ -307,14 +374,14 @@ double sin_degrees(register double x)
return oppose ? -x : x;
}
Value builtin_sin(const Context *, const EvalContext *evalctx)
ValuePtr builtin_sin(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(sin_degrees(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(sin_degrees(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
double cos_degrees(register double x)
@ -354,220 +421,221 @@ double cos_degrees(register double x)
return oppose ? -x : x;
}
Value builtin_cos(const Context *, const EvalContext *evalctx)
ValuePtr builtin_cos(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(cos_degrees(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(cos_degrees(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_asin(const Context *, const EvalContext *evalctx)
ValuePtr builtin_asin(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(rad2deg(asin(v.toDouble())));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(rad2deg(asin(v->toDouble())));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_acos(const Context *, const EvalContext *evalctx)
ValuePtr builtin_acos(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(rad2deg(acos(v.toDouble())));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(rad2deg(acos(v->toDouble())));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_tan(const Context *, const EvalContext *evalctx)
ValuePtr builtin_tan(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(tan(deg2rad(v.toDouble())));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(tan(deg2rad(v->toDouble())));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_atan(const Context *, const EvalContext *evalctx)
ValuePtr builtin_atan(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(rad2deg(atan(v.toDouble())));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(rad2deg(atan(v->toDouble())));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_atan2(const Context *, const EvalContext *evalctx)
ValuePtr builtin_atan2(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 2) {
Value v0 = evalctx->getArgValue(0), v1 = evalctx->getArgValue(1);
if (v0.type() == Value::NUMBER && v1.type() == Value::NUMBER)
return Value(rad2deg(atan2(v0.toDouble(), v1.toDouble())));
ValuePtr v0 = evalctx->getArgValue(0), v1 = evalctx->getArgValue(1);
if (v0->type() == Value::NUMBER && v1->type() == Value::NUMBER)
return ValuePtr(rad2deg(atan2(v0->toDouble(), v1->toDouble())));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_pow(const Context *, const EvalContext *evalctx)
ValuePtr builtin_pow(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 2) {
Value v0 = evalctx->getArgValue(0), v1 = evalctx->getArgValue(1);
if (v0.type() == Value::NUMBER && v1.type() == Value::NUMBER)
return Value(pow(v0.toDouble(), v1.toDouble()));
ValuePtr v0 = evalctx->getArgValue(0), v1 = evalctx->getArgValue(1);
if (v0->type() == Value::NUMBER && v1->type() == Value::NUMBER)
return ValuePtr(pow(v0->toDouble(), v1->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_round(const Context *, const EvalContext *evalctx)
ValuePtr builtin_round(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(round(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(round(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_ceil(const Context *, const EvalContext *evalctx)
ValuePtr builtin_ceil(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(ceil(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(ceil(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_floor(const Context *, const EvalContext *evalctx)
ValuePtr builtin_floor(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(floor(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(floor(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_sqrt(const Context *, const EvalContext *evalctx)
ValuePtr builtin_sqrt(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(sqrt(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(sqrt(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_exp(const Context *, const EvalContext *evalctx)
ValuePtr builtin_exp(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(exp(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(exp(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_length(const Context *, const EvalContext *evalctx)
ValuePtr builtin_length(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::VECTOR) return Value(int(v.toVector().size()));
if (v.type() == Value::STRING) {
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::VECTOR) return ValuePtr(int(v->toVector().size()));
if (v->type() == Value::STRING) {
//Unicode glyph count for the length -- rather than the string (num. of bytes) length.
std::string text = v.toString();
return Value(int( g_utf8_strlen( text.c_str(), text.size() ) ));
std::string text = v->toString();
return ValuePtr(int( g_utf8_strlen( text.c_str(), text.size() ) ));
}
}
return Value();
return ValuePtr::undefined;
}
Value builtin_log(const Context *, const EvalContext *evalctx)
ValuePtr builtin_log(const Context *, const EvalContext *evalctx)
{
size_t n = evalctx->numArgs();
if (n == 1 || n == 2) {
const Value &v0 = evalctx->getArgValue(0);
if (v0.type() == Value::NUMBER) {
double x = 10.0, y = v0.toDouble();
ValuePtr v0 = evalctx->getArgValue(0);
if (v0->type() == Value::NUMBER) {
double x = 10.0, y = v0->toDouble();
if (n > 1) {
const Value &v1 = evalctx->getArgValue(1);
if (v1.type() != Value::NUMBER) goto quit;
x = y; y = v1.toDouble();
ValuePtr v1 = evalctx->getArgValue(1);
if (v1->type() != Value::NUMBER) goto quit;
x = y; y = v1->toDouble();
}
return Value(log(y) / log(x));
return ValuePtr(log(y) / log(x));
}
}
quit:
return Value();
return ValuePtr::undefined;
}
Value builtin_ln(const Context *, const EvalContext *evalctx)
ValuePtr builtin_ln(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() == Value::NUMBER)
return Value(log(v.toDouble()));
ValuePtr v = evalctx->getArgValue(0);
if (v->type() == Value::NUMBER)
return ValuePtr(log(v->toDouble()));
}
return Value();
return ValuePtr::undefined;
}
Value builtin_str(const Context *, const EvalContext *evalctx)
ValuePtr builtin_str(const Context *, const EvalContext *evalctx)
{
std::stringstream stream;
for (size_t i = 0; i < evalctx->numArgs(); i++) {
stream << evalctx->getArgValue(i).toString();
stream << evalctx->getArgValue(i)->toString();
}
return Value(stream.str());
return ValuePtr(stream.str());
}
Value builtin_chr(const Context *, const EvalContext *evalctx)
ValuePtr builtin_chr(const Context *, const EvalContext *evalctx)
{
std::stringstream stream;
for (size_t i = 0; i < evalctx->numArgs(); i++) {
const Value v = evalctx->getArgValue(i);
stream << v.chrString();
ValuePtr v = evalctx->getArgValue(i);
stream << v->chrString();
}
return Value(stream.str());
return ValuePtr(stream.str());
}
Value builtin_concat(const Context *, const EvalContext *evalctx)
ValuePtr builtin_concat(const Context *, const EvalContext *evalctx)
{
Value::VectorType result;
for (size_t i = 0; i < evalctx->numArgs(); i++) {
const Value v = evalctx->getArgValue(i);
if (v.type() == Value::VECTOR) {
Value::VectorType vec = v.toVector();
ValuePtr v = evalctx->getArgValue(i);
if (v->type() == Value::VECTOR) {
Value::VectorType vec = v->toVector();
for (Value::VectorType::const_iterator it = vec.begin(); it != vec.end(); it++) {
result.push_back(*it);
}
} else {
result.push_back(v);
result.push_back(*v);
}
}
return Value(result);
return ValuePtr(result);
}
Value builtin_lookup(const Context *, const EvalContext *evalctx)
ValuePtr builtin_lookup(const Context *, const EvalContext *evalctx)
{
double p, low_p, low_v, high_p, high_v;
if (evalctx->numArgs() < 2 || // Needs two args
!evalctx->getArgValue(0).getDouble(p)) // First must be a number
return Value();
!evalctx->getArgValue(0)->getDouble(p)) // First must be a number
return ValuePtr::undefined;
const Value::VectorType vec = evalctx->getArgValue(1).toVector();
ValuePtr v1 = evalctx->getArgValue(1);
const Value::VectorType &vec = v1->toVector();
if (vec[0].toVector().size() < 2) // Second must be a vector of vectors
return Value();
return ValuePtr::undefined;
if (!vec[0].getVec2(low_p, low_v) || !vec[0].getVec2(high_p, high_v))
return Value();
return ValuePtr::undefined;
for (size_t i = 1; i < vec.size(); i++) {
double this_p, this_v;
if (vec[i].getVec2(this_p, this_v)) {
@ -582,11 +650,11 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx)
}
}
if (p <= low_p)
return Value(high_v);
return ValuePtr(high_v);
if (p >= high_p)
return Value(low_v);
return ValuePtr(low_v);
double f = (p-low_p) / (high_p-low_p);
return Value(high_v * f + low_v * (1-f));
return ValuePtr(high_v * f + low_v * (1-f));
}
/*
@ -715,48 +783,48 @@ static Value::VectorType search(const std::string &find, const Value::VectorType
return returnvec;
}
Value builtin_search(const Context *, const EvalContext *evalctx)
ValuePtr builtin_search(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() < 2) return Value();
if (evalctx->numArgs() < 2) return ValuePtr::undefined;
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;
ValuePtr findThis = evalctx->getArgValue(0);
ValuePtr 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;
if (findThis.type() == Value::NUMBER) {
if (findThis->type() == Value::NUMBER) {
unsigned int matchCount = 0;
for (size_t j = 0; j < searchTable.toVector().size(); j++) {
const Value& search_element = searchTable.toVector()[j];
for (size_t j = 0; j < searchTable->toVector().size(); j++) {
const Value &search_element = searchTable->toVector()[j];
if ((index_col_num == 0 && findThis == search_element) ||
if ((index_col_num == 0 && *findThis == search_element) ||
(index_col_num < search_element.toVector().size() &&
findThis == search_element.toVector()[index_col_num])) {
*findThis == search_element.toVector()[index_col_num])) {
returnvec.push_back(Value(double(j)));
matchCount++;
if (num_returns_per_match != 0 && matchCount >= num_returns_per_match) break;
}
}
} else if (findThis.type() == Value::STRING) {
if (searchTable.type() == Value::STRING) {
returnvec = search(findThis.toString(), searchTable.toString(), num_returns_per_match, index_col_num);
} else if (findThis->type() == Value::STRING) {
if (searchTable->type() == Value::STRING) {
returnvec = search(findThis->toString(), searchTable->toString(), num_returns_per_match, index_col_num);
}
else {
returnvec = search(findThis.toString(), searchTable.toVector(), num_returns_per_match, index_col_num);
returnvec = search(findThis->toString(), searchTable->toVector(), num_returns_per_match, index_col_num);
}
} else if (findThis.type() == Value::VECTOR) {
for (size_t i = 0; i < findThis.toVector().size(); i++) {
} else if (findThis->type() == Value::VECTOR) {
for (size_t i = 0; i < findThis->toVector().size(); i++) {
unsigned int matchCount = 0;
Value::VectorType resultvec;
Value const& find_value = findThis.toVector()[i];
Value const& find_value = findThis->toVector()[i];
for (size_t j = 0; j < searchTable.toVector().size(); j++) {
for (size_t j = 0; j < searchTable->toVector().size(); j++) {
Value const& search_element = searchTable.toVector()[j];
Value const& search_element = searchTable->toVector()[j];
if ((index_col_num == 0 && find_value == search_element) ||
(index_col_num < search_element.toVector().size() &&
@ -773,53 +841,53 @@ Value builtin_search(const Context *, const EvalContext *evalctx)
}
}
if (num_returns_per_match == 1 && matchCount == 0) {
if (findThis.toVector()[i].type() == Value::NUMBER) {
PRINTB(" WARNING: search term not found: %s",findThis.toVector()[i].toDouble());
if (findThis->toVector()[i].type() == Value::NUMBER) {
PRINTB(" WARNING: search term not found: %s",findThis->toVector()[i].toDouble());
}
else if (findThis.toVector()[i].type() == Value::STRING) {
PRINTB(" WARNING: search term not found: \"%s\"",findThis.toVector()[i].toString());
else if (findThis->toVector()[i].type() == Value::STRING) {
PRINTB(" WARNING: search term not found: \"%s\"",findThis->toVector()[i].toString());
}
returnvec.push_back(Value(resultvec));
returnvec.push_back(resultvec);
}
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
returnvec.push_back(Value(resultvec));
returnvec.push_back(resultvec);
}
}
} else {
PRINTB(" WARNING: search: none performed on input %s", findThis);
return Value();
return ValuePtr::undefined;
}
return Value(returnvec);
return ValuePtr(returnvec);
}
#define QUOTE(x__) # x__
#define QUOTED(x__) QUOTE(x__)
Value builtin_version(const Context *, const EvalContext *evalctx)
ValuePtr builtin_version(const Context *, const EvalContext *evalctx)
{
(void)evalctx; // unusued parameter
Value::VectorType val;
val.push_back(Value(double(OPENSCAD_YEAR)));
val.push_back(Value(double(OPENSCAD_MONTH)));
val.push_back(double(OPENSCAD_YEAR));
val.push_back(double(OPENSCAD_MONTH));
#ifdef OPENSCAD_DAY
val.push_back(Value(double(OPENSCAD_DAY)));
val.push_back(double(OPENSCAD_DAY));
#endif
return Value(val);
return ValuePtr(val);
}
Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)
ValuePtr builtin_version_num(const Context *ctx, const EvalContext *evalctx)
{
Value val = (evalctx->numArgs() == 0) ? builtin_version(ctx, evalctx) : evalctx->getArgValue(0);
ValuePtr 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)) {
return Value();
if (!val->getVec3(y, m, d)) {
if (!val->getVec2(y, m)) {
return ValuePtr::undefined;
}
}
return Value(y * 10000 + m * 100 + d);
return ValuePtr(y * 10000 + m * 100 + d);
}
Value builtin_parent_module(const Context *, const EvalContext *evalctx)
ValuePtr builtin_parent_module(const Context *, const EvalContext *evalctx)
{
int n;
double d;
@ -827,30 +895,30 @@ Value builtin_parent_module(const Context *, const EvalContext *evalctx)
if (evalctx->numArgs() == 0)
d=1; // parent module
else if (evalctx->numArgs() == 1) {
const Value &v = evalctx->getArgValue(0);
if (v.type() != Value::NUMBER) return Value();
v.getDouble(d);
ValuePtr v = evalctx->getArgValue(0);
if (v->type() != Value::NUMBER) return ValuePtr::undefined;
v->getDouble(d);
} else
return Value();
return ValuePtr::undefined;
n=trunc(d);
if (n < 0) {
PRINTB("WARNING: Negative parent module index (%d) not allowed", n);
return Value();
return ValuePtr::undefined;
}
if (n >= s) {
PRINTB("WARNING: Parent module index (%d) greater than the number of modules on the stack", n);
return Value();
return ValuePtr::undefined;
}
return Value(Module::stack_element(s - 1 - n));
return ValuePtr(Module::stack_element(s - 1 - n));
}
Value builtin_norm(const Context *, const EvalContext *evalctx)
ValuePtr builtin_norm(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
const Value &val = evalctx->getArgValue(0);
if (val.type() == Value::VECTOR) {
ValuePtr val = evalctx->getArgValue(0);
if (val->type() == Value::VECTOR) {
double sum = 0;
Value::VectorType v = val.toVector();
Value::VectorType v = val->toVector();
size_t n = v.size();
for (size_t i = 0; i < n; i++)
if (v[i].type() == Value::NUMBER) {
@ -859,48 +927,48 @@ Value builtin_norm(const Context *, const EvalContext *evalctx)
sum += x*x;
} else {
PRINT(" WARNING: Incorrect arguments to norm()");
return Value();
return ValuePtr::undefined;
}
return Value(sqrt(sum));
return ValuePtr(sqrt(sum));
}
}
return Value();
return ValuePtr::undefined;
}
Value builtin_cross(const Context *, const EvalContext *evalctx)
ValuePtr builtin_cross(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() != 2) {
PRINT("WARNING: Invalid number of parameters for cross()");
return Value();
return ValuePtr::undefined;
}
Value arg0 = evalctx->getArgValue(0);
Value arg1 = evalctx->getArgValue(1);
if ((arg0.type() != Value::VECTOR) || (arg1.type() != Value::VECTOR)) {
ValuePtr arg0 = evalctx->getArgValue(0);
ValuePtr arg1 = evalctx->getArgValue(1);
if ((arg0->type() != Value::VECTOR) || (arg1->type() != Value::VECTOR)) {
PRINT("WARNING: Invalid type of parameters for cross()");
return Value();
return ValuePtr::undefined;
}
Value::VectorType v0 = arg0.toVector();
Value::VectorType v1 = arg1.toVector();
Value::VectorType v0 = arg0->toVector();
Value::VectorType v1 = arg1->toVector();
if ((v0.size() != 3) || (v1.size() != 3)) {
PRINT("WARNING: Invalid vector size of parameter for cross()");
return Value();
return ValuePtr::undefined;
}
for (unsigned int a = 0;a < 3;a++) {
if ((v0[a].type() != Value::NUMBER) || (v1[a].type() != Value::NUMBER)) {
PRINT("WARNING: Invalid value in parameter vector for cross()");
return Value();
return ValuePtr::undefined;
}
double d0 = v0[a].toDouble();
double d1 = v1[a].toDouble();
if (boost::math::isnan(d0) || boost::math::isnan(d1)) {
PRINT("WARNING: Invalid value (NaN) in parameter vector for cross()");
return Value();
return ValuePtr::undefined;
}
if (boost::math::isinf(d0) || boost::math::isinf(d1)) {
PRINT("WARNING: Invalid value (INF) in parameter vector for cross()");
return Value();
return ValuePtr::undefined;
}
}
@ -912,7 +980,7 @@ Value builtin_cross(const Context *, const EvalContext *evalctx)
result.push_back(Value(x));
result.push_back(Value(y));
result.push_back(Value(z));
return Value(result);
return ValuePtr(result);
}
void register_builtin_functions()

View File

@ -7,45 +7,47 @@
#include <string>
#include <vector>
class AbstractFunction
{
private:
const Feature *feature;
const Feature *feature;
public:
AbstractFunction() : feature(NULL) {}
AbstractFunction(const Feature& feature) : feature(&feature) {}
AbstractFunction() : feature(NULL) {}
AbstractFunction(const Feature& feature) : feature(&feature) {}
virtual ~AbstractFunction();
virtual bool is_experimental() const { return feature != NULL; }
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); }
virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
virtual bool is_experimental() const { return feature != NULL; }
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); }
virtual ValuePtr evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class BuiltinFunction : public AbstractFunction
{
public:
typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);
typedef ValuePtr (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);
eval_func_t eval_func;
BuiltinFunction(eval_func_t f) : eval_func(f) { }
BuiltinFunction(eval_func_t f, const Feature& feature) : AbstractFunction(feature), eval_func(f) { }
virtual ~BuiltinFunction();
virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual ValuePtr 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::string name;
AssignmentList definition_arguments;
Expression *expr;
Function() { }
Function(const char *name, AssignmentList &definition_arguments, Expression *expr);
virtual ~Function();
virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
static Function * create(const char *name, AssignmentList &definition_arguments, Expression *expr);
};

View File

@ -91,18 +91,18 @@ AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstanti
c.dump(this, inst);
#endif
Value v = c.lookup_variable("file");
if (v.isUndefined()) {
ValuePtr v = c.lookup_variable("file");
if (v->isUndefined()) {
v = c.lookup_variable("filename");
if (!v.isUndefined()) {
if (!v->isUndefined()) {
printDeprecation("DEPRECATED: filename= is deprecated. Please use file=");
}
}
std::string filename = lookup_file(v.isUndefined() ? "" : v.toString(), inst->path(), ctx->documentPath());
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) );
std::string ext = boost::algorithm::to_lower_copy( extraw );
std::string extraw = boosty::extension_str(fs::path(filename));
std::string ext = boost::algorithm::to_lower_copy(extraw);
if (ext == ".stl") actualtype = TYPE_STL;
else if (ext == ".off") actualtype = TYPE_OFF;
else if (ext == ".dxf") actualtype = TYPE_DXF;
@ -110,31 +110,30 @@ AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstanti
ImportNode *node = new ImportNode(inst, actualtype);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
node->fn = c.lookup_variable("$fn")->toDouble();
node->fs = c.lookup_variable("$fs")->toDouble();
node->fa = c.lookup_variable("$fa")->toDouble();
node->filename = filename;
Value layerval = c.lookup_variable("layer", true);
Value layerval = *c.lookup_variable("layer", true);
if (layerval.isUndefined()) {
layerval = c.lookup_variable("layername");
layerval = *c.lookup_variable("layername");
if (!layerval.isUndefined()) {
printDeprecation("DEPRECATED: layername= is deprecated. Please use layer=");
}
}
node->layername = layerval.isUndefined() ? "" : layerval.toString();
node->convexity = c.lookup_variable("convexity", true).toDouble();
node->convexity = c.lookup_variable("convexity", true)->toDouble();
if (node->convexity <= 0) node->convexity = 1;
Value origin = c.lookup_variable("origin", true);
ValuePtr origin = c.lookup_variable("origin", true);
node->origin_x = node->origin_y = 0;
origin.getVec2(node->origin_x, node->origin_y);
origin->getVec2(node->origin_x, node->origin_y);
node->scale = c.lookup_variable("scale", true).toDouble();
node->scale = c.lookup_variable("scale", true)->toDouble();
if (node->scale <= 0)
node->scale = 1;
if (node->scale <= 0) node->scale = 1;
return node;
}

View File

@ -60,46 +60,46 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
node->fn = c.lookup_variable("$fn")->toDouble();
node->fs = c.lookup_variable("$fs")->toDouble();
node->fa = c.lookup_variable("$fa")->toDouble();
Value file = c.lookup_variable("file");
Value layer = c.lookup_variable("layer", true);
Value height = c.lookup_variable("height", true);
Value convexity = c.lookup_variable("convexity", true);
Value origin = c.lookup_variable("origin", true);
Value scale = c.lookup_variable("scale", true);
Value center = c.lookup_variable("center", true);
Value twist = c.lookup_variable("twist", true);
Value slices = c.lookup_variable("slices", true);
ValuePtr file = c.lookup_variable("file");
ValuePtr layer = c.lookup_variable("layer", true);
ValuePtr height = c.lookup_variable("height", true);
ValuePtr convexity = c.lookup_variable("convexity", true);
ValuePtr origin = c.lookup_variable("origin", true);
ValuePtr scale = c.lookup_variable("scale", true);
ValuePtr center = c.lookup_variable("center", true);
ValuePtr twist = c.lookup_variable("twist", true);
ValuePtr slices = c.lookup_variable("slices", true);
if (!file.isUndefined() && file.type() == Value::STRING) {
if (!file->isUndefined() && file->type() == Value::STRING) {
printDeprecation("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead.");
node->filename = lookup_file(file.toString(), inst->path(), c.documentPath());
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() &&
if (c.lookup_variable("height")->isUndefined() &&
evalctx->numArgs() > 0 &&
evalctx->getArgName(0) == "") {
const Value &val = evalctx->getArgValue(0);
if (val.type() == Value::NUMBER) height = val;
ValuePtr val = evalctx->getArgValue(0);
if (val->type() == Value::NUMBER) height = val;
}
node->layername = layer.isUndefined() ? "" : layer.toString();
node->layername = layer->isUndefined() ? "" : layer->toString();
node->height = 100;
height.getDouble(node->height);
node->convexity = (int)convexity.toDouble();
origin.getVec2(node->origin_x, node->origin_y);
height->getDouble(node->height);
node->convexity = (int)convexity->toDouble();
origin->getVec2(node->origin_x, node->origin_y);
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);
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();
if (center->type() == Value::BOOL)
node->center = center->toBool();
if (node->height <= 0) node->height = 0;
@ -109,10 +109,10 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
if (node->scale_x < 0) node->scale_x = 0;
if (node->scale_y < 0) node->scale_y = 0;
if (slices.type() == Value::NUMBER) node->slices = (int)slices.toDouble();
if (slices->type() == Value::NUMBER) node->slices = (int)slices->toDouble();
if (twist.type() == Value::NUMBER) {
node->twist = twist.toDouble();
if (twist->type() == Value::NUMBER) {
node->twist = twist->toDouble();
if (node->twist != 0.0) {
if (node->slices == 0) {
node->slices = (int)fmax(2, fabs(Calc::get_fragments_from_r(node->height,

View File

@ -1486,7 +1486,7 @@ bool MainWindow::eventFilter(QObject* obj, QEvent *event)
void MainWindow::updateTemporalVariables()
{
this->top_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
this->top_ctx.set_variable("$t", ValuePtr(this->e_tval->text().toDouble()));
Value::VectorType vpt;
vpt.push_back(Value(-qglview->cam.object_trans.x()));
@ -1498,9 +1498,9 @@ void MainWindow::updateTemporalVariables()
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)));
top_ctx.set_variable("$vpr", Value(vpr));
top_ctx.set_variable("$vpr", ValuePtr(vpr));
top_ctx.set_variable("$vpd", Value(qglview->cam.viewer_distance));
top_ctx.set_variable("$vpd", ValuePtr(qglview->cam.viewer_distance));
}
@ -1527,25 +1527,25 @@ void MainWindow::updateCamera()
double d = cam.viewer_distance;
double x, y, z;
const Value vpr = root_module->lookup_variable("$vpr");
if (vpr.getVec3(x, y, z)) {
const ValuePtr vpr = root_module->lookup_variable("$vpr");
if (vpr->getVec3(x, y, z)) {
rx = x;
ry = y;
rz = z;
camera_set = true;
}
const Value vpt = root_module->lookup_variable("$vpt");
if (vpt.getVec3(x, y, z)) {
const ValuePtr vpt = root_module->lookup_variable("$vpt");
if (vpt->getVec3(x, y, z)) {
tx = x;
ty = y;
tz = z;
camera_set = true;
}
const Value vpd = root_module->lookup_variable("$vpd");
if (vpd.type() == Value::NUMBER) {
d = vpd.toDouble();
const ValuePtr vpd = root_module->lookup_variable("$vpd");
if (vpd->type() == Value::NUMBER) {
d = vpd->toDouble();
camera_set = true;
}

View File

@ -1,6 +1,8 @@
#pragma once
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
using boost::shared_ptr;
using boost::make_shared;
using boost::dynamic_pointer_cast;
using boost::static_pointer_cast;

View File

@ -24,8 +24,8 @@ void ModuleContext::evaluateAssignments(const AssignmentList &assignments)
// First, assign all simple variables
std::list<std::string> undefined_vars;
BOOST_FOREACH(const Assignment &ass, assignments) {
Value tmpval = ass.second->evaluate(this);
if (tmpval.isUndefined()) undefined_vars.push_back(ass.first);
ValuePtr tmpval = ass.second->evaluate(this);
if (tmpval->isUndefined()) undefined_vars.push_back(ass.first);
else this->set_variable(ass.first, tmpval);
}
@ -46,12 +46,12 @@ void ModuleContext::evaluateAssignments(const AssignmentList &assignments)
boost::unordered_map<std::string, Expression *>::iterator found = tmpass.find(*curr);
if (found != tmpass.end()) {
const Expression *expr = found->second;
Value tmpval = expr->evaluate(this);
ValuePtr tmpval = expr->evaluate(this);
// FIXME: it's not enough to check for undefined;
// we need to check for any undefined variable in the subexpression
// For now, ignore this and revisit the validity and order of variable
// assignments later
if (!tmpval.isUndefined()) {
if (!tmpval->isUndefined()) {
changed = true;
this->set_variable(*curr, tmpval);
undefined_vars.erase(curr);
@ -90,7 +90,7 @@ void ModuleContext::registerBuiltin()
this->set_variable(ass.first, ass.second->evaluate(this));
}
this->set_constant("PI",Value(M_PI));
this->set_constant("PI", ValuePtr(M_PI));
}
const AbstractFunction *ModuleContext::findLocalFunction(const std::string &name) const
@ -123,7 +123,8 @@ const AbstractModule *ModuleContext::findLocalModule(const std::string &name) co
return NULL;
}
Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
ValuePtr ModuleContext::evaluate_function(const std::string &name,
const EvalContext *evalctx) const
{
const AbstractFunction *foundf = findLocalFunction(name);
if (foundf) return foundf->evaluate(this, evalctx);
@ -157,7 +158,7 @@ std::string ModuleContext::dump(const AbstractModule *mod, const ModuleInstantia
}
}
}
typedef std::pair<std::string, Value> ValueMapType;
typedef std::pair<std::string, ValuePtr> ValueMapType;
s << " vars:";
BOOST_FOREACH(const ValueMapType &v, constants) {
s << boost::format(" %s = %s") % v.first % v.second;
@ -178,9 +179,9 @@ FileContext::FileContext(const class FileModule &module, const Context *parent)
if (!module.modulePath().empty()) this->document_path = module.modulePath();
}
Value FileContext::sub_evaluate_function(const std::string &name, const EvalContext *evalctx,
FileModule *usedmod) const
ValuePtr FileContext::sub_evaluate_function(const std::string &name,
const EvalContext *evalctx,
FileModule *usedmod) const
{
FileContext ctx(*usedmod, this->parent);
@ -193,7 +194,8 @@ Value FileContext::sub_evaluate_function(const std::string &name, const EvalCont
return usedmod->scope.functions[name]->evaluate(&ctx, evalctx);
}
Value FileContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
ValuePtr FileContext::evaluate_function(const std::string &name,
const EvalContext *evalctx) const
{
const AbstractFunction *foundf = findLocalFunction(name);
if (foundf) return foundf->evaluate(this, evalctx);

View File

@ -18,8 +18,8 @@ public:
void initializeModule(const Module &m);
void registerBuiltin();
virtual Value evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
virtual ValuePtr evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
EvalContext *evalctx) const;
@ -45,7 +45,8 @@ 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 ValuePtr evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
EvalContext *evalctx) const;
@ -53,5 +54,7 @@ private:
const FileModule::ModuleContainer &usedlibs;
// This sub_* method is needed to minimize stack usage only.
Value sub_evaluate_function(const std::string &name, const EvalContext *evalctx, FileModule *usedmod) const;
ValuePtr sub_evaluate_function(const std::string &name,
const EvalContext *evalctx,
FileModule *usedmod) const;
};

View File

@ -33,6 +33,8 @@
#include "function.h"
#include "printutils.h"
#include "parsersettings.h"
#include "exceptions.h"
#include "stackcheck.h"
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
@ -59,14 +61,14 @@ AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstan
double AbstractModule::lookup_double_variable_with_default(Context &c, std::string variable, double def) const
{
const Value v = c.lookup_variable(variable, true);
return (v.type() == Value::NUMBER) ? v.toDouble() : def;
ValuePtr v = c.lookup_variable(variable, true);
return (v->type() == Value::NUMBER) ? v->toDouble() : def;
}
std::string AbstractModule::lookup_string_variable_with_default(Context &c, std::string variable, std::string def) const
{
const Value v = c.lookup_variable(variable, true);
return (v.type() == Value::STRING) ? v.toString() : def;
ValuePtr v = c.lookup_variable(variable, true);
return (v->type() == Value::STRING) ? v->toString() : def;
}
std::string AbstractModule::dump(const std::string &indent, const std::string &name) const
@ -151,8 +153,13 @@ AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
PRINT("New eval ctx:");
c.dump(NULL, this);
#endif
AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx
return node;
try {
AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx
return node;
} catch (RecursionException &e) {
PRINT(e.what());
return NULL;
}
}
std::vector<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
@ -171,25 +178,10 @@ Module::~Module()
{
}
class ModRecursionGuard
{
public:
ModRecursionGuard(const ModuleInstantiation &inst) : inst(inst) {
inst.recursioncount++;
}
~ModRecursionGuard() {
inst.recursioncount--;
}
bool recursion_detected() const { return (inst.recursioncount > 1000); }
private:
const ModuleInstantiation &inst;
};
AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{
ModRecursionGuard g(*inst);
if (g.recursion_detected()) {
PRINTB("ERROR: Recursion detected calling module '%s'", inst->name());
if (StackCheck::inst()->check()) {
throw RecursionException("module", inst->name());
return NULL;
}
@ -199,9 +191,9 @@ AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation
ModuleContext c(ctx, evalctx);
// set $children first since we might have variables depending on it
c.set_variable("$children", Value(double(inst->scope.children.size())));
c.set_variable("$children", ValuePtr(double(inst->scope.children.size())));
module_stack.push_back(inst->name());
c.set_variable("$parent_modules", Value(double(module_stack.size())));
c.set_variable("$parent_modules", ValuePtr(double(module_stack.size())));
c.initializeModule(*this);
// FIXME: Set document path to the path of the module
#if 0 && DEBUG
@ -365,17 +357,22 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
#endif
AbstractNode *node = new AbstractNode(inst);
std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(context);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
try {
std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(context);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
catch (RecursionException &e) {
PRINT(e.what());
}
return node;
}
Value FileModule::lookup_variable(const std::string &name) const
ValuePtr FileModule::lookup_variable(const std::string &name) const
{
if (!context) {
return Value::undefined;
return ValuePtr::undefined;
}
return context->lookup_variable(name, true);
}
}

View File

@ -18,7 +18,7 @@ class ModuleInstantiation
{
public:
ModuleInstantiation(const std::string &name = "")
: tag_root(false), tag_highlight(false), tag_background(false), recursioncount(0), modname(name) { }
: tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }
virtual ~ModuleInstantiation();
virtual std::string dump(const std::string &indent) const;
@ -40,7 +40,6 @@ public:
bool tag_root;
bool tag_highlight;
bool tag_background;
mutable int recursioncount;
protected:
std::string modname;
std::string modpath;
@ -112,7 +111,7 @@ public:
bool hasIncludes() const { return !this->includes.empty(); }
bool usesLibraries() const { return !this->usedlibs.empty(); }
bool isHandlingDependencies() const { return this->is_handling_dependencies; }
Value lookup_variable(const std::string &name) const;
ValuePtr lookup_variable(const std::string &name) const;
typedef boost::unordered_set<std::string> ModuleContainer;
ModuleContainer usedlibs;

View File

@ -60,21 +60,21 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
node->fn = c.lookup_variable("$fn")->toDouble();
node->fs = c.lookup_variable("$fs")->toDouble();
node->fa = c.lookup_variable("$fa")->toDouble();
Value delta = c.lookup_variable("delta");
ValuePtr delta = c.lookup_variable("delta");
node->delta = 1;
delta.getDouble(node->delta);
delta->getDouble(node->delta);
Value miter_limit = c.lookup_variable("miter_limit", true);
ValuePtr miter_limit = c.lookup_variable("miter_limit", true);
node->miter_limit = 2;
miter_limit.getDouble(node->miter_limit);
miter_limit->getDouble(node->miter_limit);
Value join_type = c.lookup_variable("join_type", true);
if (join_type.type() == Value::STRING) {
std::string jt = join_type.toString();
ValuePtr join_type = c.lookup_variable("join_type", true);
if (join_type->type() == Value::STRING) {
std::string jt = join_type->toString();
if (std::string("bevel") == jt) {
node->join_type = ClipperLib::jtSquare;
} else if (std::string("round") == jt) {
@ -85,7 +85,7 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti
PRINTB("WARNING: Unknown join_type for offset(): '%s'", jt);
}
if ((node->join_type != ClipperLib::jtMiter) && !miter_limit.isUndefined()) {
if ((node->join_type != ClipperLib::jtMiter) && !miter_limit->isUndefined()) {
PRINTB("WARNING: miter_limit is ignored in offset() for join_type: '%s'", jt);
}
}

View File

@ -39,6 +39,7 @@
#include "PlatformUtils.h"
#include "LibraryInfo.h"
#include "nodedumper.h"
#include "stackcheck.h"
#include "CocoaUtils.h"
#include <string>
@ -684,6 +685,8 @@ int main(int argc, char **argv)
{
int rc = 0;
bool isGuiLaunched = getenv("GUI_LAUNCHED") != 0;
StackCheck::inst()->init();
#ifdef Q_OS_MAC
if (isGuiLaunched) set_output_handler(CocoaUtils::nslog, NULL);
#else

View File

@ -166,9 +166,7 @@ statement:
}
| TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr
{
Function *func = new Function();
func->definition_arguments = *$4;
func->expr = $8;
Function *func = Function::create($2, *$4, $8);
scope_stack.top()->functions[$2] = func;
free($2);
delete $4;
@ -302,70 +300,55 @@ single_module_instantiation:
expr:
TOK_TRUE
{
$$ = new Expression(Value(true));
$$ = new ExpressionConst(ValuePtr(true));
}
| TOK_FALSE
{
$$ = new Expression(Value(false));
$$ = new ExpressionConst(ValuePtr(false));
}
| TOK_UNDEF
{
$$ = new Expression(Value::undefined);
$$ = new ExpressionConst(ValuePtr::undefined);
}
| TOK_ID
{
$$ = new Expression();
$$->type = "L";
$$->var_name = $1;
$$ = new ExpressionLookup($1);
free($1);
}
| expr '.' TOK_ID
{
$$ = new Expression("N", $1);
$$->var_name = $3;
$$ = new ExpressionMember($1, $3);
free($3);
}
| TOK_STRING
{
$$ = new Expression(Value(std::string($1)));
$$ = new ExpressionConst(ValuePtr(std::string($1)));
free($1);
}
| TOK_NUMBER
{
$$ = new Expression(Value($1));
$$ = new ExpressionConst(ValuePtr($1));
}
| TOK_LET '(' arguments_call ')' expr %prec LET
{
$$ = new Expression();
$$->type = "l";
$$->call_arguments = *$3;
$$ = new ExpressionLet(*$3, $5);
delete $3;
$$->children.push_back($5);
}
| '[' expr ':' expr ']'
{
$$ = new Expression();
$$->type = "R";
$$->children.push_back($2);
$$->children.push_back($4);
$$ = new ExpressionRange($2, $4);
}
| '[' expr ':' expr ':' expr ']'
{
$$ = new Expression();
$$->type = "R";
$$->children.push_back($2);
$$->children.push_back($4);
$$->children.push_back($6);
$$ = new ExpressionRange($2, $4, $6);
}
| '[' list_comprehension_elements ']'
{
$$ = new Expression();
$$->type = "i";
$$->children.push_back($2);
$$ = new ExpressionLcExpression($2);
}
| '[' optional_commas ']'
{
$$ = new Expression(Value(Value::VectorType()));
$$ = new ExpressionConst(ValuePtr(Value::VectorType()));
}
| '[' vector_expr optional_commas ']'
{
@ -373,55 +356,55 @@ expr:
}
| expr '*' expr
{
$$ = new Expression("*", $1, $3);
$$ = new ExpressionMultiply($1, $3);
}
| expr '/' expr
{
$$ = new Expression("/", $1, $3);
$$ = new ExpressionDivision($1, $3);
}
| expr '%' expr
{
$$ = new Expression("%", $1, $3);
$$ = new ExpressionModulo($1, $3);
}
| expr '+' expr
{
$$ = new Expression("+", $1, $3);
$$ = new ExpressionPlus($1, $3);
}
| expr '-' expr
{
$$ = new Expression("-", $1, $3);
$$ = new ExpressionMinus($1, $3);
}
| expr '<' expr
{
$$ = new Expression("<", $1, $3);
$$ = new ExpressionLess($1, $3);
}
| expr LE expr
{
$$ = new Expression("<=", $1, $3);
$$ = new ExpressionLessOrEqual($1, $3);
}
| expr EQ expr
{
$$ = new Expression("==", $1, $3);
$$ = new ExpressionEqual($1, $3);
}
| expr NE expr
{
$$ = new Expression("!=", $1, $3);
$$ = new ExpressionNotEqual($1, $3);
}
| expr GE expr
{
$$ = new Expression(">=", $1, $3);
$$ = new ExpressionGreaterOrEqual($1, $3);
}
| expr '>' expr
{
$$ = new Expression(">", $1, $3);
$$ = new ExpressionGreater($1, $3);
}
| expr AND expr
{
$$ = new Expression("&&", $1, $3);
$$ = new ExpressionLogicalAnd($1, $3);
}
| expr OR expr
{
$$ = new Expression("||", $1, $3);
$$ = new ExpressionLogicalOr($1, $3);
}
| '+' expr
{
@ -429,11 +412,11 @@ expr:
}
| '-' expr
{
$$ = new Expression("I", $2);
$$ = new ExpressionInvert($2);
}
| '!' expr
{
$$ = new Expression("!", $2);
$$ = new ExpressionNot($2);
}
| '(' expr ')'
{
@ -441,22 +424,15 @@ expr:
}
| expr '?' expr ':' expr
{
$$ = new Expression();
$$->type = "?:";
$$->children.push_back($1);
$$->children.push_back($3);
$$->children.push_back($5);
$$ = new ExpressionTernary($1, $3, $5);
}
| expr '[' expr ']'
{
$$ = new Expression("[]", $1, $3);
$$ = new ExpressionArrayLookup($1, $3);
}
| TOK_ID '(' arguments_call ')'
{
$$ = new Expression();
$$->type = "F";
$$->call_funcname = $1;
$$->call_arguments = *$3;
$$ = new ExpressionFunctionCall($1, *$3);
free($1);
delete $3;
}
@ -467,9 +443,7 @@ list_comprehension_elements:
be parsed as an expression) */
TOK_LET '(' arguments_call ')' list_comprehension_elements
{
$$ = new Expression("c", $5);
$$->call_funcname = "let";
$$->call_arguments = *$3;
$$ = new ExpressionLc("let", *$3, $5);
delete $3;
}
| TOK_FOR '(' arguments_call ')' list_comprehension_elements_or_expr
@ -478,17 +452,16 @@ list_comprehension_elements:
/* transform for(i=...,j=...) -> for(i=...) for(j=...) */
for (int i = $3->size()-1; i >= 0; i--) {
Expression *e = new Expression("c", $$);
e->call_funcname = "for";
e->call_arguments.push_back((*$3)[i]);
AssignmentList arglist;
arglist.push_back((*$3)[i]);
Expression *e = new ExpressionLc("for", arglist, $$);
$$ = e;
}
delete $3;
}
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr
{
$$ = new Expression("c", $3, $5);
$$->call_funcname = "if";
$$ = new ExpressionLc("if", $3, $5);
}
;
@ -505,7 +478,7 @@ optional_commas:
vector_expr:
expr
{
$$ = new Expression("V", $1);
$$ = new ExpressionVector($1);
}
| vector_expr ',' optional_commas expr
{

View File

@ -108,7 +108,7 @@ public:
double fn, fs, fa;
primitive_type_e type;
int convexity;
Value points, paths, faces;
ValuePtr points, paths, faces;
virtual Geometry *createGeometry() const;
};
@ -125,19 +125,19 @@ public:
*/
Value PrimitiveModule::lookup_radius(const Context &ctx, const std::string &diameter_var, const std::string &radius_var) const
{
const Value d = ctx.lookup_variable(diameter_var, true);
const Value r = ctx.lookup_variable(radius_var, true);
const bool r_defined = (r.type() == Value::NUMBER);
ValuePtr d = ctx.lookup_variable(diameter_var, true);
ValuePtr r = ctx.lookup_variable(radius_var, true);
const bool r_defined = (r->type() == Value::NUMBER);
if (d.type() == Value::NUMBER) {
if (d->type() == Value::NUMBER) {
if (r_defined) {
PRINTB("WARNING: Ignoring radius variable '%s' as diameter '%s' is defined too.", radius_var % diameter_var);
}
return Value(d.toDouble() / 2.0);
return Value(d->toDouble() / 2.0);
} else if (r_defined) {
return r;
return *r;
} else {
return Value();
return Value::undefined;
}
}
@ -179,9 +179,9 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
Context c(ctx);
c.setVariables(args, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
node->fn = c.lookup_variable("$fn")->toDouble();
node->fs = c.lookup_variable("$fs")->toDouble();
node->fa = c.lookup_variable("$fa")->toDouble();
if (node->fs < F_MINIMUM) {
PRINTB("WARNING: $fs too small - clamping to %f", F_MINIMUM);
@ -194,14 +194,14 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
switch (this->type) {
case CUBE: {
Value size = c.lookup_variable("size");
Value center = c.lookup_variable("center");
size.getDouble(node->x);
size.getDouble(node->y);
size.getDouble(node->z);
size.getVec3(node->x, node->y, node->z);
if (center.type() == Value::BOOL) {
node->center = center.toBool();
ValuePtr size = c.lookup_variable("size");
ValuePtr center = c.lookup_variable("center");
size->getDouble(node->x);
size->getDouble(node->y);
size->getDouble(node->z);
size->getVec3(node->x, node->y, node->z);
if (center->type() == Value::BOOL) {
node->center = center->toBool();
}
break;
}
@ -213,9 +213,9 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
break;
}
case CYLINDER: {
const Value h = c.lookup_variable("h");
if (h.type() == Value::NUMBER) {
node->h = h.toDouble();
ValuePtr h = c.lookup_variable("h");
if (h->type() == Value::NUMBER) {
node->h = h->toDouble();
}
const Value r = lookup_radius(c, "d", "r");
@ -232,32 +232,32 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
node->r2 = r2.toDouble();
}
const Value center = c.lookup_variable("center");
if (center.type() == Value::BOOL) {
node->center = center.toBool();
ValuePtr center = c.lookup_variable("center");
if (center->type() == Value::BOOL) {
node->center = center->toBool();
}
break;
}
case POLYHEDRON: {
node->points = c.lookup_variable("points");
node->faces = c.lookup_variable("faces");
if (node->faces.type() == Value::UNDEFINED) {
if (node->faces->type() == Value::UNDEFINED) {
// backwards compatible
node->faces = c.lookup_variable("triangles", true);
if (node->faces.type() != Value::UNDEFINED) {
if (node->faces->type() != Value::UNDEFINED) {
printDeprecation("DEPRECATED: polyhedron(triangles=[]) will be removed in future releases. Use polyhedron(faces=[]) instead.");
}
}
break;
}
case SQUARE: {
Value size = c.lookup_variable("size");
Value center = c.lookup_variable("center");
size.getDouble(node->x);
size.getDouble(node->y);
size.getVec2(node->x, node->y);
if (center.type() == Value::BOOL) {
node->center = center.toBool();
ValuePtr size = c.lookup_variable("size");
ValuePtr center = c.lookup_variable("center");
size->getDouble(node->x);
size->getDouble(node->y);
size->getVec2(node->x, node->y);
if (center->type() == Value::BOOL) {
node->center = center->toBool();
}
break;
}
@ -275,7 +275,7 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
}
}
node->convexity = c.lookup_variable("convexity", true).toDouble();
node->convexity = c.lookup_variable("convexity", true)->toDouble();
if (node->convexity < 1)
node->convexity = 1;
@ -505,15 +505,15 @@ Geometry *PrimitiveNode::createGeometry() const
PolySet *p = new PolySet(3);
g = p;
p->setConvexity(this->convexity);
for (size_t i=0; i<this->faces.toVector().size(); i++)
for (size_t i=0; i<this->faces->toVector().size(); i++)
{
p->append_poly();
const Value::VectorType &vec = this->faces.toVector()[i].toVector();
const Value::VectorType &vec = this->faces->toVector()[i].toVector();
for (size_t j=0; j<vec.size(); j++) {
size_t pt = vec[j].toDouble();
if (pt < this->points.toVector().size()) {
if (pt < this->points->toVector().size()) {
double px, py, pz;
if (!this->points.toVector()[pt].getVec3(px, py, pz) ||
if (!this->points->toVector()[pt].getVec3(px, py, pz) ||
isinf(px) || isinf(py) || isinf(pz)) {
PRINTB("ERROR: Unable to convert point at index %d to a vec3 of numbers", j);
return p;
@ -570,7 +570,7 @@ Geometry *PrimitiveNode::createGeometry() const
Outline2d outline;
double x,y;
const Value::VectorType &vec = this->points.toVector();
const Value::VectorType &vec = this->points->toVector();
for (unsigned int i=0;i<vec.size();i++) {
const Value &val = vec[i];
if (!val.getVec2(x, y) || isinf(x) || isinf(y)) {
@ -581,11 +581,11 @@ Geometry *PrimitiveNode::createGeometry() const
outline.vertices.push_back(Vector2d(x, y));
}
if (this->paths.toVector().size() == 0 && outline.vertices.size() > 2) {
if (this->paths->toVector().size() == 0 && outline.vertices.size() > 2) {
p->addOutline(outline);
}
else {
BOOST_FOREACH(const Value &polygon, this->paths.toVector()) {
BOOST_FOREACH(const Value &polygon, this->paths->toVector()) {
Outline2d curroutline;
BOOST_FOREACH(const Value &index, polygon.toVector()) {
unsigned int idx = index.toDouble();
@ -628,8 +628,8 @@ std::string PrimitiveNode::toString() const
<< ", r2 = " << this->r2 << ", center = " << (center ? "true" : "false") << ")";
break;
case POLYHEDRON:
stream << "(points = " << this->points
<< ", faces = " << this->faces
stream << "(points = " << *this->points
<< ", faces = " << *this->faces
<< ", convexity = " << this->convexity << ")";
break;
case SQUARE:
@ -641,7 +641,7 @@ std::string PrimitiveNode::toString() const
<< ", $fs = " << this->fs << ", r = " << this->r1 << ")";
break;
case POLYGON:
stream << "(points = " << this->points << ", paths = " << this->paths << ", convexity = " << this->convexity << ")";
stream << "(points = " << *this->points << ", paths = " << *this->paths << ", convexity = " << this->convexity << ")";
break;
default:
assert(false);

View File

@ -55,13 +55,13 @@ AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInst
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
Value convexity = c.lookup_variable("convexity", true);
Value cut = c.lookup_variable("cut", true);
ValuePtr convexity = c.lookup_variable("convexity", true);
ValuePtr cut = c.lookup_variable("cut", true);
node->convexity = (int)convexity.toDouble();
node->convexity = (int)convexity->toDouble();
if (cut.type() == Value::BOOL)
node->cut_mode = cut.toBool();
if (cut->type() == Value::BOOL)
node->cut_mode = cut->toBool();
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());

View File

@ -52,9 +52,9 @@ AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstanti
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
Value v = c.lookup_variable("convexity");
if (v.type() == Value::NUMBER)
node->convexity = (int)v.toDouble();
ValuePtr v = c.lookup_variable("convexity");
if (v->type() == Value::NUMBER)
node->convexity = (int)v->toDouble();
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());

View File

@ -58,25 +58,25 @@ AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleI
c.setVariables(args, evalctx);
inst->scope.apply(*evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
node->fn = c.lookup_variable("$fn")->toDouble();
node->fs = c.lookup_variable("$fs")->toDouble();
node->fa = c.lookup_variable("$fa")->toDouble();
Value file = c.lookup_variable("file");
Value layer = c.lookup_variable("layer", true);
Value convexity = c.lookup_variable("convexity", true);
Value origin = c.lookup_variable("origin", true);
Value scale = c.lookup_variable("scale", true);
ValuePtr file = c.lookup_variable("file");
ValuePtr layer = c.lookup_variable("layer", true);
ValuePtr convexity = c.lookup_variable("convexity", true);
ValuePtr origin = c.lookup_variable("origin", true);
ValuePtr scale = c.lookup_variable("scale", true);
if (!file.isUndefined()) {
if (!file->isUndefined()) {
printDeprecation("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead.");
node->filename = lookup_file(file.toString(), inst->path(), c.documentPath());
node->filename = lookup_file(file->toString(), inst->path(), c.documentPath());
}
node->layername = layer.isUndefined() ? "" : layer.toString();
node->convexity = (int)convexity.toDouble();
origin.getVec2(node->origin_x, node->origin_y);
node->scale = scale.toDouble();
node->layername = layer->isUndefined() ? "" : layer->toString();
node->convexity = (int)convexity->toDouble();
origin->getVec2(node->origin_x, node->origin_y);
node->scale = scale->toDouble();
if (node->convexity <= 0)
node->convexity = 1;

39
src/stackcheck.cc Normal file
View File

@ -0,0 +1,39 @@
#include <cstdlib>
#include "stackcheck.h"
#include "PlatformUtils.h"
StackCheck * StackCheck::self = 0;
StackCheck::StackCheck() : ptr(0)
{
}
StackCheck::~StackCheck()
{
}
void StackCheck::init()
{
unsigned char c;
ptr = &c;
}
unsigned long StackCheck::size()
{
unsigned char c;
return std::labs(ptr - &c);
}
bool StackCheck::check()
{
return size() >= PlatformUtils::stackLimit();
}
StackCheck * StackCheck::inst()
{
if (self == 0) {
self = new StackCheck();
}
return self;
}

19
src/stackcheck.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
class StackCheck
{
public:
StackCheck();
virtual ~StackCheck();
static StackCheck * inst();
void init();
bool check();
unsigned long size();
private:
unsigned char * ptr;
static StackCheck *self;
};

View File

@ -93,22 +93,22 @@ AbstractNode *SurfaceModule::instantiate(const Context *ctx, const ModuleInstant
Context c(ctx);
c.setVariables(args, evalctx);
Value fileval = c.lookup_variable("file");
node->filename = lookup_file(fileval.isUndefined() ? "" : fileval.toString(), inst->path(), c.documentPath());
ValuePtr fileval = c.lookup_variable("file");
node->filename = lookup_file(fileval->isUndefined() ? "" : fileval->toString(), inst->path(), c.documentPath());
Value center = c.lookup_variable("center", true);
if (center.type() == Value::BOOL) {
node->center = center.toBool();
ValuePtr center = c.lookup_variable("center", true);
if (center->type() == Value::BOOL) {
node->center = center->toBool();
}
Value convexity = c.lookup_variable("convexity", true);
if (convexity.type() == Value::NUMBER) {
node->convexity = (int)convexity.toDouble();
ValuePtr convexity = c.lookup_variable("convexity", true);
if (convexity->type() == Value::NUMBER) {
node->convexity = (int)convexity->toDouble();
}
Value invert = c.lookup_variable("invert", true);
if (invert.type() == Value::BOOL) {
node->invert = invert.toBool();
ValuePtr invert = c.lookup_variable("invert", true);
if (invert->type() == Value::BOOL) {
node->invert = invert->toBool();
}
return node;

View File

@ -54,9 +54,9 @@ AbstractNode *TextModule::instantiate(const Context *ctx, const ModuleInstantiat
Context c(ctx);
c.setVariables(args, evalctx);
double fn = c.lookup_variable("$fn").toDouble();
double fa = c.lookup_variable("$fa").toDouble();
double fs = c.lookup_variable("$fs").toDouble();
double fn = c.lookup_variable("$fn")->toDouble();
double fa = c.lookup_variable("$fa")->toDouble();
double fs = c.lookup_variable("$fs")->toDouble();
node->params.set_fn(fn);
node->params.set_fa(fa);

View File

@ -88,45 +88,45 @@ AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInsta
if (this->type == SCALE)
{
Vector3d scalevec(1,1,1);
Value v = c.lookup_variable("v");
if (!v.getVec3(scalevec[0], scalevec[1], scalevec[2], 1.0)) {
ValuePtr v = c.lookup_variable("v");
if (!v->getVec3(scalevec[0], scalevec[1], scalevec[2], 1.0)) {
double num;
if (v.getDouble(num)) scalevec.setConstant(num);
if (v->getDouble(num)) scalevec.setConstant(num);
}
node->matrix.scale(scalevec);
}
else if (this->type == ROTATE)
{
Value val_a = c.lookup_variable("a");
if (val_a.type() == Value::VECTOR)
ValuePtr val_a = c.lookup_variable("a");
if (val_a->type() == Value::VECTOR)
{
Eigen::AngleAxisd rotx(0, Vector3d::UnitX());
Eigen::AngleAxisd roty(0, Vector3d::UnitY());
Eigen::AngleAxisd rotz(0, Vector3d::UnitZ());
double a;
if (val_a.toVector().size() > 0) {
val_a.toVector()[0].getDouble(a);
if (val_a->toVector().size() > 0) {
val_a->toVector()[0].getDouble(a);
rotx = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitX());
}
if (val_a.toVector().size() > 1) {
val_a.toVector()[1].getDouble(a);
if (val_a->toVector().size() > 1) {
val_a->toVector()[1].getDouble(a);
roty = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitY());
}
if (val_a.toVector().size() > 2) {
val_a.toVector()[2].getDouble(a);
if (val_a->toVector().size() > 2) {
val_a->toVector()[2].getDouble(a);
rotz = Eigen::AngleAxisd(a*M_PI/180, Vector3d::UnitZ());
}
node->matrix.rotate(rotz * roty * rotx);
}
else
{
Value val_v = c.lookup_variable("v");
ValuePtr val_v = c.lookup_variable("v");
double a = 0;
val_a.getDouble(a);
val_a->getDouble(a);
Vector3d axis(0,0,1);
if (val_v.getVec3(axis[0], axis[1], axis[2])) {
if (val_v->getVec3(axis[0], axis[1], axis[2])) {
if (axis.squaredNorm() > 0) axis.normalize();
}
@ -137,10 +137,10 @@ AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInsta
}
else if (this->type == MIRROR)
{
Value val_v = c.lookup_variable("v");
ValuePtr val_v = c.lookup_variable("v");
double x = 1, y = 0, z = 0;
if (val_v.getVec3(x, y, z)) {
if (val_v->getVec3(x, y, z)) {
if (x != 0.0 || y != 0.0 || z != 0.0) {
double sn = 1.0 / sqrt(x*x + y*y + z*z);
x *= sn, y *= sn, z *= sn;
@ -159,19 +159,20 @@ AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInsta
}
else if (this->type == TRANSLATE)
{
Value v = c.lookup_variable("v");
ValuePtr v = c.lookup_variable("v");
Vector3d translatevec(0,0,0);
v.getVec3(translatevec[0], translatevec[1], translatevec[2]);
v->getVec3(translatevec[0], translatevec[1], translatevec[2]);
node->matrix.translate(translatevec);
}
else if (this->type == MULTMATRIX)
{
Value v = c.lookup_variable("m");
if (v.type() == Value::VECTOR) {
ValuePtr v = c.lookup_variable("m");
if (v->type() == Value::VECTOR) {
for (int i = 0; i < 16; i++) {
size_t x = i / 4, y = i % 4;
if (y < v.toVector().size() && v.toVector()[y].type() == Value::VECTOR && x < v.toVector()[y].toVector().size())
v.toVector()[y].toVector()[x].getDouble(node->matrix(y, x));
if (y < v->toVector().size() && v->toVector()[y].type() ==
Value::VECTOR && x < v->toVector()[y].toVector().size())
v->toVector()[y].toVector()[x].getDouble(node->matrix(y, x));
}
}
}
@ -190,7 +191,7 @@ std::string TransformNode::toString() const
for (int j=0;j<4;j++) {
stream << "[";
for (int i=0;i<4;i++) {
Value v( this->matrix(j, i) );
Value v(this->matrix(j, i));
stream << v;
if (i != 3) stream << ", ";
}

View File

@ -41,6 +41,9 @@
#include <boost/math/special_functions/fpclassify.hpp>
Value Value::undefined;
ValuePtr ValuePtr::undefined;
std::ostream &operator<<(std::ostream &stream, const Filename &filename)
{
fs::path fnpath = fs::path( (std::string)filename );
@ -77,8 +80,6 @@ std::ostream &operator<<(std::ostream &stream, const QuotedString &s)
return stream;
}
Value Value::undefined;
Value::Value() : value(boost::blank())
{
// std::cout << "creating undef\n";
@ -688,7 +689,7 @@ public:
}
};
Value Value::operator[](const Value &v)
Value Value::operator[](const Value &v) const
{
return boost::apply_visitor(bracket_visitor(), this->value, v.value);
}
@ -790,3 +791,119 @@ bool Value::RangeType::iterator::operator!=(const self_type &other) const
{
return !(*this == other);
}
ValuePtr::ValuePtr()
{
this->reset(new Value());
}
ValuePtr::ValuePtr(const Value &v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(bool v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(int v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(double v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(const std::string &v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(const char *v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(const char v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(const Value::VectorType &v)
{
this->reset(new Value(v));
}
ValuePtr::ValuePtr(const Value::RangeType &v)
{
this->reset(new Value(v));
}
bool ValuePtr::operator==(const ValuePtr &v) const
{
return ValuePtr(**this == *v);
}
bool ValuePtr::operator!=(const ValuePtr &v) const
{
return ValuePtr(**this != *v);
}
bool ValuePtr::operator<(const ValuePtr &v) const
{
return ValuePtr(**this < *v);
}
bool ValuePtr::operator<=(const ValuePtr &v) const
{
return ValuePtr(**this <= *v);
}
bool ValuePtr::operator>=(const ValuePtr &v) const
{
return ValuePtr(**this >= *v);
}
bool ValuePtr::operator>(const ValuePtr &v) const
{
return ValuePtr(**this > *v);
}
ValuePtr ValuePtr::operator-() const
{
return ValuePtr(-**this);
}
ValuePtr ValuePtr::operator[](const ValuePtr &v) const
{
return ValuePtr((**this)[*v]);
}
ValuePtr ValuePtr::operator+(const ValuePtr &v) const
{
return ValuePtr(**this + *v);
}
ValuePtr ValuePtr::operator-(const ValuePtr &v) const
{
return ValuePtr(**this - *v);
}
ValuePtr ValuePtr::operator*(const ValuePtr &v) const
{
return ValuePtr(**this * *v);
}
ValuePtr ValuePtr::operator/(const ValuePtr &v) const
{
return ValuePtr(**this / *v);
}
ValuePtr ValuePtr::operator%(const ValuePtr &v) const
{
return ValuePtr(**this % *v);
}

View File

@ -11,6 +11,7 @@
#include <boost/lexical_cast.hpp>
#endif
#include <boost/cstdint.hpp>
#include "memory.h"
class QuotedString : public std::string
{
@ -138,7 +139,7 @@ public:
bool operator>=(const Value &v) const;
bool operator>(const Value &v) const;
Value operator-() const;
Value operator[](const Value &v);
Value operator[](const Value &v) const;
Value operator+(const Value &v) const;
Value operator-(const Value &v) const;
Value operator*(const Value &v) const;
@ -160,3 +161,40 @@ private:
Variant value;
};
class ValuePtr : public shared_ptr<const Value>
{
public:
static ValuePtr undefined;
ValuePtr();
explicit ValuePtr(const Value &v);
ValuePtr(bool v);
ValuePtr(int v);
ValuePtr(double v);
ValuePtr(const std::string &v);
ValuePtr(const char *v);
ValuePtr(const char v);
ValuePtr(const Value::VectorType &v);
ValuePtr(const Value::RangeType &v);
operator bool() const { return **this; }
bool operator==(const ValuePtr &v) const;
bool operator!=(const ValuePtr &v) const;
bool operator<(const ValuePtr &v) const;
bool operator<=(const ValuePtr &v) const;
bool operator>=(const ValuePtr &v) const;
bool operator>(const ValuePtr &v) const;
ValuePtr operator-() const;
ValuePtr operator[](const ValuePtr &v) const;
ValuePtr operator+(const ValuePtr &v) const;
ValuePtr operator-(const ValuePtr &v) const;
ValuePtr operator*(const ValuePtr &v) const;
ValuePtr operator/(const ValuePtr &v) const;
ValuePtr operator%(const ValuePtr &v) const;
const Value &operator*() const { return *this->get(); }
private:
};

View File

@ -1,2 +1,5 @@
function crash() = crash();
echo(crash());
module crash() crash();
crash();

View File

@ -0,0 +1,31 @@
function substring(text, start, end = -1, idx = -1, res = "") =
idx < end && idx < len(text)
? substring(text, start, end, idx < 0 ? start + 1 : idx + 1, str(res, text[idx < 0 ? start : idx]))
: res;
// normal recursion, no tail-recursion elimination possible
function f3a(a, ret = 0) = a <= 0 ? 0 : a + f3a(a - 1);
echo("without tail-recursion eliminiation: ", f3a(100));
// this allows tail-recursion eliminiation
function f3b(a, ret = 0) = a <= 0 ? ret : f3b(a - 1, ret + a);
echo("with tail-recursion eliminiation: ", f3b(100));
// check tail-recursion eliminiation by using a high loop count
function f3c(a, ret = 0) = a <= 0 ? ret : f3c(a - 1, ret + a);
echo("with tail-recursion eliminiation: ", f3c(2000));
// use nested function call
function f1(x, y = []) = x <= 0 ? y : f1(x - 1, concat(y, [[x, x]]));
echo(f1(2000)[20]);
// recursion in the "false" part of the ternary operator
function c(a, b) = chr(a % 26 + b);
function f2a(x, y = 0, t = "") = x <= 0 ? t : f2a(x - 1, y + 2, str(t, c(y, 65)));
s1 = f2a(50000);
echo(len(s1), substring(s1, 0, 40));
// recursion in the "true" part of the ternary operator
function f2b(x, y = 0, t = "") = x > 0 ? f2b(x - 1, y + 1, str(t, chr((y % 26) + 97))) : t;
s2 = f2b(50000);
echo(len(s2), substring(s2, 0, 40));

View File

@ -78,7 +78,6 @@ endif()
# Most tests will fail, but it can be used for testing/experiments
if(NULLGL)
set(ENABLE_OPENCSG_FLAG "") # OpenCSG is entirely an OpenGL software
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNULLGL")
set(SKIP_IMAGEMAGICK "1") # we dont generate png, so nothing to compare
else()
@ -620,6 +619,7 @@ set(CORE_SOURCES
../src/calc.cc
../src/expr.cc
../src/func.cc
../src/stackcheck.cc
../src/localscope.cc
../src/module.cc
../src/ModuleCache.cc
@ -736,16 +736,10 @@ target_link_libraries(tests-cgal tests-common ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_L
#
# Create non-CGAL tests
#
add_library(tests-nocgal STATIC ${NOCGAL_SOURCES})
target_link_libraries(tests-nocgal tests-common)
if (NOT NULLGL)
add_library(tests-nocgal STATIC ${NOCGAL_SOURCES})
set_target_properties(tests-nocgal PROPERTIES COMPILE_FLAGS ${ENABLE_OPENCSG_FLAG})
target_link_libraries(tests-nocgal tests-common)
else()
message(STATUS "NULLGL: cannot use GL/GLU tessellator. see dxftess.cc")
message(STATUS "NULLGL: non-CGAL tests will use CGAL's tessellator")
add_library(tests-nocgal STATIC ${NOCGAL_SOURCES})
set_target_properties(tests-nocgal PROPERTIES COMPILE_FLAGS ${ENABLE_OPENCSG_FLAG})
target_link_libraries(tests-nocgal tests-common)
set_target_properties(tests-nocgal PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG_FLAG}")
endif()
add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES})
@ -767,8 +761,8 @@ target_link_libraries(csgtexttest tests-nocgal)
# cgalcachetest
#
add_executable(cgalcachetest cgalcachetest.cc)
set_target_properties(cgalcachetest PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG_FLAG} -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
target_link_libraries(cgalcachetest tests-cgal ${GLEW_LIBRARY})
set_target_properties(cgalcachetest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
target_link_libraries(cgalcachetest tests-cgal)
#
# openscad no-qt
@ -1044,6 +1038,7 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests-unicode.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/tail-recursion-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad

View File

@ -38,6 +38,7 @@
#include "CGAL_Nef_polyhedron.h"
#include "GeometryEvaluator.h"
#include "CGALCache.h"
#include "stackcheck.h"
#ifndef _MSC_VER
#include <getopt.h>
@ -88,6 +89,8 @@ int main(int argc, char **argv)
{
const char *filename, *outfilename = NULL;
size_t cgalcachesize = 1*1024*1024;
StackCheck::inst()->init();
po::variables_map vm;
try {
vm = parse_options(argc, argv);

View File

@ -37,6 +37,7 @@
#include "builtin.h"
#include "Tree.h"
#include "PlatformUtils.h"
#include "stackcheck.h"
#ifndef _MSC_VER
#include <getopt.h>
@ -73,6 +74,7 @@ int main(int argc, char **argv)
int rc = 0;
StackCheck::inst()->init();
Builtins::instance()->initialize();
fs::path original_path = fs::current_path();

View File

@ -34,6 +34,7 @@
#include "export.h"
#include "builtin.h"
#include "Tree.h"
#include "stackcheck.h"
#ifndef _MSC_VER
#include <getopt.h>
@ -68,6 +69,7 @@ int main(int argc, char **argv)
int rc = 0;
StackCheck::inst()->init();
Builtins::instance()->initialize();
fs::path original_path = fs::current_path();

View File

@ -1,2 +1,3 @@
ERROR: Recursion detected calling function 'crash'
ECHO: undef
ERROR: Recursion detected calling module 'crash'

View File

@ -0,0 +1,6 @@
ECHO: "without tail-recursion eliminiation: ", 5050
ECHO: "with tail-recursion eliminiation: ", 5050
ECHO: "with tail-recursion eliminiation: ", 2001000
ECHO: [1980, 1980]
ECHO: 50000, "ACEGIKMOQSUWYACEGIKMOQSUWYACEGIKMOQSUWYA"
ECHO: 50000, "abcdefghijklmnopqrstuvwxyzabcdefghijklmn"