mirror of https://github.com/vitalif/openscad
commit
b6167b0b60
|
@ -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 \
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 << ")";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
16
src/color.cc
16
src/color.cc
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
818
src/expr.cc
818
src/expr.cc
|
@ -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;
|
||||
}
|
||||
|
|
280
src/expression.h
280
src/expression.h
|
@ -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;
|
||||
};
|
||||
|
|
546
src/func.cc
546
src/func.cc
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
101
src/parser.y
101
src/parser.y
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 << ", ";
|
||||
}
|
||||
|
|
123
src/value.cc
123
src/value.cc
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
40
src/value.h
40
src/value.h
|
@ -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:
|
||||
};
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
function crash() = crash();
|
||||
echo(crash());
|
||||
|
||||
module crash() crash();
|
||||
crash();
|
||||
|
|
|
@ -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));
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
ERROR: Recursion detected calling function 'crash'
|
||||
ECHO: undef
|
||||
ERROR: Recursion detected calling module 'crash'
|
||||
|
|
|
@ -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"
|
Loading…
Reference in New Issue