mirror of https://github.com/vitalif/openscad
Use class hierarchy for the different types of expressions.
parent
756f8079d8
commit
dc8f559b85
|
@ -94,19 +94,19 @@ std::string Builtins::isDeprecated(const std::string &name)
|
||||||
|
|
||||||
Builtins::Builtins()
|
Builtins::Builtins()
|
||||||
{
|
{
|
||||||
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new Expression(ValuePtr(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 Expression(ValuePtr(2.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 Expression(ValuePtr(12.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 Expression(ValuePtr(0.0)))));
|
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
|
||||||
|
|
||||||
Value::VectorType zero3;
|
Value::VectorType zero3;
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
ValuePtr zero3val(zero3);
|
ValuePtr zero3val(zero3);
|
||||||
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
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 Expression(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 Expression(ValuePtr(500)))));
|
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(500)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Builtins::~Builtins()
|
Builtins::~Builtins()
|
||||||
|
|
743
src/expr.cc
743
src/expr.cc
|
@ -23,7 +23,6 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "evalcontext.h"
|
#include "evalcontext.h"
|
||||||
|
@ -32,14 +31,10 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "stl-utils.h"
|
#include "stl-utils.h"
|
||||||
#include "printutils.h"
|
#include "printutils.h"
|
||||||
|
#include "stackcheck.h"
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
ExpressionEvaluator * Expression::evaluators[256];
|
|
||||||
|
|
||||||
// static initializer for the expression evaluator lookup table
|
|
||||||
ExpressionEvaluatorInit Expression::evaluatorInit;
|
|
||||||
|
|
||||||
// unnamed namespace
|
// unnamed namespace
|
||||||
namespace {
|
namespace {
|
||||||
Value::VectorType flatten(Value::VectorType const& vec) {
|
Value::VectorType flatten(Value::VectorType const& vec) {
|
||||||
|
@ -71,358 +66,49 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionEvaluatorAbort : public ExpressionEvaluator
|
Expression::Expression()
|
||||||
{
|
{
|
||||||
ValuePtr evaluate(const class Expression *, const class Context *) const {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorNot : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return ! expr->children[0]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLogicalAnd : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) && expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLogicalOr : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) || expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorMultiply : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) * expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorDivision : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) / expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorModulo : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) % expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorPlus : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) + expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorMinus : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) - expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLess : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) < expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLessOrEqual : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) <= expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorEqual : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) == expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorNotEqual : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children.at(0)->evaluate(context) != expr->children.at(1)->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorGreaterOrEqual : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) >= expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorGreater : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context) > expr->children[1]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorTernary : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[expr->children[0]->evaluate(context) ? 1 : 2]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorArray : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context)[expr->children[1]->evaluate(context)];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorInvert : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return -expr->children[0]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorConst : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *) const {
|
|
||||||
return ValuePtr(expr->const_value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorRange : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
ValuePtr v1 = expr->children[0]->evaluate(context);
|
|
||||||
if (v1->type() == Value::NUMBER) {
|
|
||||||
ValuePtr v2 = expr->children[1]->evaluate(context);
|
|
||||||
if (v2->type() == Value::NUMBER) {
|
|
||||||
if (expr->children.size() == 2) {
|
|
||||||
Value::RangeType range(v1->toDouble(), v2->toDouble());
|
|
||||||
return ValuePtr(range);
|
|
||||||
} else {
|
|
||||||
ValuePtr v3 = expr->children[2]->evaluate(context);
|
|
||||||
if (v3->type() == Value::NUMBER) {
|
|
||||||
Value::RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble());
|
|
||||||
return ValuePtr(range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ValuePtr::undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorVector : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
Value::VectorType vec;
|
|
||||||
BOOST_FOREACH(const Expression *e, expr->children) {
|
|
||||||
vec.push_back(*(e->evaluate(context)));
|
|
||||||
}
|
|
||||||
return ValuePtr(vec);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLookup : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return context->lookup_variable(expr->var_name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorMember : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
ValuePtr v = expr->children[0]->evaluate(context);
|
|
||||||
|
|
||||||
if (v->type() == Value::VECTOR) {
|
|
||||||
if (expr->var_name == "x") return v[0];
|
|
||||||
if (expr->var_name == "y") return v[1];
|
|
||||||
if (expr->var_name == "z") return v[2];
|
|
||||||
} else if (v->type() == Value::RANGE) {
|
|
||||||
if (expr->var_name == "begin") return v[0];
|
|
||||||
if (expr->var_name == "step") return v[1];
|
|
||||||
if (expr->var_name == "end") return v[2];
|
|
||||||
}
|
|
||||||
return ValuePtr::undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void function_recursion_detected(const char *func)
|
|
||||||
{
|
|
||||||
PRINTB("ERROR: Recursion detected calling function '%s'", func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionEvaluatorFunction : public ExpressionEvaluator
|
Expression::Expression(const ValuePtr &val)
|
||||||
{
|
{
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
const_value = val;
|
||||||
if (expr->recursioncount >= 1000) {
|
|
||||||
function_recursion_detected(expr->call_funcname.c_str());
|
|
||||||
// TO DO: throw function_recursion_detected();
|
|
||||||
return ValuePtr::undefined;
|
|
||||||
}
|
|
||||||
expr->recursioncount += 1;
|
|
||||||
EvalContext *c = new EvalContext(context, expr->call_arguments);
|
|
||||||
ValuePtr result = context->evaluate_function(expr->call_funcname, c);
|
|
||||||
delete c;
|
|
||||||
expr->recursioncount -= 1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLet : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
Context c(context);
|
|
||||||
evaluate_sequential_assignment(expr->call_arguments, &c);
|
|
||||||
|
|
||||||
return expr->children[0]->evaluate(&c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLcExpression : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
return expr->children[0]->evaluate(context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorLc : public ExpressionEvaluator
|
|
||||||
{
|
|
||||||
ValuePtr evaluate(const class Expression *expr, const class Context *context) const {
|
|
||||||
Value::VectorType vec;
|
|
||||||
|
|
||||||
if (expr->call_funcname == "if") {
|
|
||||||
if (expr->children[0]->evaluate(context)) {
|
|
||||||
if (expr->children[1]->type == EXPRESSION_TYPE_LC) {
|
|
||||||
return expr->children[1]->evaluate(context);
|
|
||||||
} else {
|
|
||||||
vec.push_back((*expr->children[1]->evaluate(context)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ValuePtr(vec);
|
|
||||||
} else if (expr->call_funcname == "for") {
|
|
||||||
EvalContext for_context(context, expr->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((*expr->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((*expr->children[0]->evaluate(&c)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (it_values->type() != Value::UNDEFINED) {
|
|
||||||
c.set_variable(it_name, it_values);
|
|
||||||
vec.push_back((*expr->children[0]->evaluate(&c)));
|
|
||||||
}
|
|
||||||
if (expr->children[0]->type == EXPRESSION_TYPE_LC) {
|
|
||||||
return ValuePtr(flatten(vec));
|
|
||||||
} else {
|
|
||||||
return ValuePtr(vec);
|
|
||||||
}
|
|
||||||
} else if (expr->call_funcname == "let") {
|
|
||||||
Context c(context);
|
|
||||||
evaluate_sequential_assignment(expr->call_arguments, &c);
|
|
||||||
|
|
||||||
return expr->children[0]->evaluate(&c);
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ExpressionEvaluatorInit::ExpressionEvaluatorInit()
|
|
||||||
{
|
|
||||||
ExpressionEvaluator *abort = new ExpressionEvaluatorAbort();
|
|
||||||
for (int a = 0;a < 256;a++) {
|
|
||||||
Expression::evaluators[a] = abort;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_NOT] = new ExpressionEvaluatorNot();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LOGICAL_AND] = new ExpressionEvaluatorLogicalAnd();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LOGICAL_OR] = new ExpressionEvaluatorLogicalOr();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_MULTIPLY] = new ExpressionEvaluatorMultiply();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_DIVISION] = new ExpressionEvaluatorDivision();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_MODULO] = new ExpressionEvaluatorModulo();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_PLUS] = new ExpressionEvaluatorPlus();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_MINUS] = new ExpressionEvaluatorMinus();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LESS] = new ExpressionEvaluatorLess();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LESS_OR_EQUAL] = new ExpressionEvaluatorLessOrEqual();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_EQUAL] = new ExpressionEvaluatorEqual();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_NOT_EQUAL] = new ExpressionEvaluatorNotEqual();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_GREATER_OR_EQUAL] = new ExpressionEvaluatorGreaterOrEqual();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_GREATER] = new ExpressionEvaluatorGreater();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_TERNARY] = new ExpressionEvaluatorTernary();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_ARRAY_ACCESS] = new ExpressionEvaluatorArray();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_INVERT] = new ExpressionEvaluatorInvert();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_CONST] = new ExpressionEvaluatorConst();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_RANGE] = new ExpressionEvaluatorRange();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_VECTOR] = new ExpressionEvaluatorVector();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LOOKUP] = new ExpressionEvaluatorLookup();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_MEMBER] = new ExpressionEvaluatorMember();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_FUNCTION] = new ExpressionEvaluatorFunction();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LET] = new ExpressionEvaluatorLet();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LC_EXPRESSION] = new ExpressionEvaluatorLcExpression();
|
|
||||||
Expression::evaluators[EXPRESSION_TYPE_LC] = new ExpressionEvaluatorLc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Expression(const unsigned char type) : recursioncount(0)
|
Expression::Expression(const std::string &val)
|
||||||
{
|
{
|
||||||
setType(type);
|
var_name = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Expression(const unsigned char type, Expression *left, Expression *right)
|
Expression::Expression(const std::string &val, Expression *expr)
|
||||||
: recursioncount(0)
|
|
||||||
{
|
{
|
||||||
setType(type);
|
var_name = val;
|
||||||
this->children.push_back(left);
|
children.push_back(expr);
|
||||||
this->children.push_back(right);
|
first = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Expression(const unsigned char type, Expression *expr)
|
Expression::Expression(Expression *expr)
|
||||||
: recursioncount(0)
|
|
||||||
{
|
{
|
||||||
setType(type);
|
children.push_back(expr);
|
||||||
this->children.push_back(expr);
|
first = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Expression(const ValuePtr &val) : const_value(val), recursioncount(0)
|
Expression::Expression(Expression *left, Expression *right)
|
||||||
{
|
{
|
||||||
setType(EXPRESSION_TYPE_CONST);
|
children.push_back(left);
|
||||||
|
children.push_back(right);
|
||||||
|
first = left;
|
||||||
|
second = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression::Expression(Expression *expr1, Expression *expr2, Expression *expr3)
|
||||||
|
{
|
||||||
|
children.push_back(expr1);
|
||||||
|
children.push_back(expr2);
|
||||||
|
children.push_back(expr3);
|
||||||
|
first = expr1;
|
||||||
|
second = expr2;
|
||||||
|
third = expr3;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::~Expression()
|
Expression::~Expression()
|
||||||
|
@ -430,20 +116,6 @@ Expression::~Expression()
|
||||||
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
|
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expression::setType(const unsigned char type)
|
|
||||||
{
|
|
||||||
this->type = type;
|
|
||||||
this->evaluator = evaluators[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
ValuePtr Expression::evaluate(const Context *context) const
|
|
||||||
{
|
|
||||||
char _c;
|
|
||||||
context->checkStack(&_c);
|
|
||||||
|
|
||||||
return evaluator->evaluate(this, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace /* anonymous*/ {
|
namespace /* anonymous*/ {
|
||||||
|
|
||||||
std::ostream &operator << (std::ostream &o, AssignmentList const& l) {
|
std::ostream &operator << (std::ostream &o, AssignmentList const& l) {
|
||||||
|
@ -458,10 +130,15 @@ namespace /* anonymous*/ {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Expression::isListComprehension()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Expression::toString() const
|
std::string Expression::toString() const
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
/*
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case EXPRESSION_TYPE_MULTIPLY:
|
case EXPRESSION_TYPE_MULTIPLY:
|
||||||
case EXPRESSION_TYPE_DIVISION:
|
case EXPRESSION_TYPE_DIVISION:
|
||||||
|
@ -561,9 +238,361 @@ std::string Expression::toString() const
|
||||||
assert(false && "Illegal expression type");
|
assert(false && "Illegal expression type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpressionNot::ExpressionNot(Expression *expr) : Expression(expr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionNot::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
return !first->evaluate(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionArray::ExpressionArray(Expression *left, Expression *right) : Expression(left, right)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionArray::evaluate(const Context *context) const {
|
||||||
|
return this->first->evaluate(context)[this->second->evaluate(context)];
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionInvert::ExpressionInvert(Expression *expr) : Expression(expr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionInvert::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
return -this->first->evaluate(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionConst::ExpressionConst(const ValuePtr &val) : Expression(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionConst::evaluate(const class Context *) const
|
||||||
|
{
|
||||||
|
return ValuePtr(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 {
|
||||||
|
ValuePtr v3 = this->third->evaluate(context);
|
||||||
|
if (v3->type() == Value::NUMBER) {
|
||||||
|
Value::RangeType range(v1->toDouble(), v2->toDouble(), v3->toDouble());
|
||||||
|
return ValuePtr(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ValuePtr::undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLookup::ExpressionLookup(const std::string &val) : Expression(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionLookup::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
return context->lookup_variable(this->var_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionMember::ExpressionMember(const std::string &val, Expression *expr) : Expression(val, expr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionMember::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
ValuePtr v = this->first->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 v[0];
|
||||||
|
if (this->var_name == "step") return v[1];
|
||||||
|
if (this->var_name == "end") return v[2];
|
||||||
|
}
|
||||||
|
return ValuePtr::undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void function_recursion_detected(const char *func)
|
||||||
|
{
|
||||||
|
PRINTB("ERROR: Recursion detected calling function '%s'", func);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionFunction::ExpressionFunction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionFunction::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
if (StackCheck::inst()->check()) {
|
||||||
|
function_recursion_detected(this->call_funcname.c_str());
|
||||||
|
// TO DO: throw function_recursion_detected();
|
||||||
|
return ValuePtr::undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
EvalContext *c = new EvalContext(context, this->call_arguments);
|
||||||
|
ValuePtr result = context->evaluate_function(this->call_funcname, c);
|
||||||
|
delete c;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLet::ExpressionLet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionLet::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
Context c(context);
|
||||||
|
evaluate_sequential_assignment(this->call_arguments, &c);
|
||||||
|
|
||||||
|
return this->children[0]->evaluate(&c);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLcExpression::ExpressionLcExpression(Expression *expr) : Expression(expr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionLcExpression::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
return this->children[0]->evaluate(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLc::ExpressionLc(Expression *expr) : Expression(expr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLc::ExpressionLc(Expression *expr1, Expression *expr2) : Expression(expr1, expr2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExpressionLc::isListComprehension()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr ExpressionLc::evaluate(const Context *context) const
|
||||||
|
{
|
||||||
|
Value::VectorType vec;
|
||||||
|
|
||||||
|
if (this->call_funcname == "if") {
|
||||||
|
if (this->children[0]->evaluate(context)) {
|
||||||
|
if (this->children[1]->isListComprehension()) {
|
||||||
|
return this->children[1]->evaluate(context);
|
||||||
|
} else {
|
||||||
|
vec.push_back((*this->children[1]->evaluate(context)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ValuePtr(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);
|
||||||
|
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->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]->isListComprehension()) {
|
||||||
|
return ValuePtr(flatten(vec));
|
||||||
|
} else {
|
||||||
|
return ValuePtr(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &stream, const Expression &expr)
|
std::ostream &operator<<(std::ostream &stream, const Expression &expr)
|
||||||
{
|
{
|
||||||
stream << expr.toString();
|
stream << expr.toString();
|
||||||
|
|
271
src/expression.h
271
src/expression.h
|
@ -5,49 +5,13 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "typedefs.h"
|
#include "typedefs.h"
|
||||||
|
|
||||||
#define EXPRESSION_TYPE_NOT ('!')
|
|
||||||
#define EXPRESSION_TYPE_LOGICAL_AND ('&')
|
|
||||||
#define EXPRESSION_TYPE_LOGICAL_OR ('|')
|
|
||||||
#define EXPRESSION_TYPE_MULTIPLY ('*')
|
|
||||||
#define EXPRESSION_TYPE_DIVISION ('/')
|
|
||||||
#define EXPRESSION_TYPE_MODULO ('%')
|
|
||||||
#define EXPRESSION_TYPE_PLUS ('+')
|
|
||||||
#define EXPRESSION_TYPE_MINUS ('-')
|
|
||||||
#define EXPRESSION_TYPE_LESS ('<')
|
|
||||||
#define EXPRESSION_TYPE_LESS_OR_EQUAL ('0')
|
|
||||||
#define EXPRESSION_TYPE_EQUAL ('=')
|
|
||||||
#define EXPRESSION_TYPE_NOT_EQUAL ('1')
|
|
||||||
#define EXPRESSION_TYPE_GREATER_OR_EQUAL ('2')
|
|
||||||
#define EXPRESSION_TYPE_GREATER ('>')
|
|
||||||
#define EXPRESSION_TYPE_TERNARY ('?')
|
|
||||||
#define EXPRESSION_TYPE_ARRAY_ACCESS ('[')
|
|
||||||
#define EXPRESSION_TYPE_INVERT ('I')
|
|
||||||
#define EXPRESSION_TYPE_CONST ('C')
|
|
||||||
#define EXPRESSION_TYPE_RANGE ('R')
|
|
||||||
#define EXPRESSION_TYPE_VECTOR ('V')
|
|
||||||
#define EXPRESSION_TYPE_LOOKUP ('L')
|
|
||||||
#define EXPRESSION_TYPE_MEMBER ('N')
|
|
||||||
#define EXPRESSION_TYPE_FUNCTION ('F')
|
|
||||||
#define EXPRESSION_TYPE_LET ('l')
|
|
||||||
#define EXPRESSION_TYPE_LC_EXPRESSION ('i')
|
|
||||||
#define EXPRESSION_TYPE_LC ('c')
|
|
||||||
|
|
||||||
class ExpressionEvaluator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ValuePtr evaluate(const class Expression *expr, const class Context *context) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionEvaluatorInit
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ExpressionEvaluatorInit();
|
|
||||||
};
|
|
||||||
|
|
||||||
class Expression
|
class Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<Expression*> children;
|
std::vector<Expression*> children;
|
||||||
|
Expression *first;
|
||||||
|
Expression *second;
|
||||||
|
Expression *third;
|
||||||
|
|
||||||
ValuePtr const_value;
|
ValuePtr const_value;
|
||||||
std::string var_name;
|
std::string var_name;
|
||||||
|
@ -55,45 +19,204 @@ public:
|
||||||
std::string call_funcname;
|
std::string call_funcname;
|
||||||
AssignmentList call_arguments;
|
AssignmentList call_arguments;
|
||||||
|
|
||||||
|
Expression();
|
||||||
Expression(const ValuePtr &val);
|
Expression(const ValuePtr &val);
|
||||||
Expression(const unsigned char type);
|
Expression(const std::string &val);
|
||||||
Expression(const unsigned char type, Expression *left, Expression *right);
|
Expression(const std::string &val, Expression *expr);
|
||||||
Expression(const unsigned char type, Expression *expr);
|
Expression(Expression *expr);
|
||||||
~Expression();
|
Expression(Expression *left, Expression *right);
|
||||||
|
Expression(Expression *expr1, Expression *expr2, Expression *expr3);
|
||||||
|
virtual ~Expression();
|
||||||
|
|
||||||
void setType(const unsigned char type);
|
virtual bool isListComprehension();
|
||||||
ValuePtr evaluate(const class Context *context) const;
|
virtual ValuePtr evaluate(const class Context *context) const = 0;
|
||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
|
||||||
private:
|
|
||||||
// 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
|
|
||||||
unsigned char type;
|
|
||||||
ExpressionEvaluator *evaluator;
|
|
||||||
|
|
||||||
mutable int recursioncount;
|
|
||||||
|
|
||||||
static ExpressionEvaluator *evaluators[256];
|
|
||||||
static ExpressionEvaluatorInit evaluatorInit;
|
|
||||||
|
|
||||||
friend class ExpressionEvaluatorInit;
|
|
||||||
friend class ExpressionEvaluatorLc; // for type
|
|
||||||
friend class ExpressionEvaluatorFunction; // for recursioncount
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &stream, const Expression &expr);
|
std::ostream &operator<<(std::ostream &stream, const Expression &expr);
|
||||||
|
|
||||||
|
class ExpressionNot : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionNot(Expression *expr);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLogicalAnd : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLogicalAnd(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLogicalOr : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLogicalOr(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionMultiply : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionMultiply(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionDivision : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionDivision(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionModulo : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionModulo(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionPlus : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionPlus(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionMinus : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionMinus(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLess : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLess(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLessOrEqual : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLessOrEqual(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionEqual : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionEqual(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionNotEqual : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionNotEqual(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionGreaterOrEqual : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionGreaterOrEqual(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionGreater : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionGreater(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionTernary : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionTernary(Expression *expr1, Expression *expr2, Expression *expr3);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionArray : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionArray(Expression *left, Expression *right);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionInvert : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionInvert(Expression *expr);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionConst : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionConst(const ValuePtr &val);
|
||||||
|
ValuePtr evaluate(const class Context *) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionRange : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionRange(Expression *expr1, Expression *expr2);
|
||||||
|
ExpressionRange(Expression *expr1, Expression *expr2, Expression *expr3);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionVector : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionVector(Expression *expr);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLookup : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLookup(const std::string &val);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionMember : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionMember(const std::string &val, Expression *expr);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionFunction : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionFunction();
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLet : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLet();
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLcExpression : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExpressionLcExpression(Expression *expr);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionLc : public Expression
|
||||||
|
{
|
||||||
|
bool isListComprehension();
|
||||||
|
public:
|
||||||
|
ExpressionLc(Expression *expr);
|
||||||
|
ExpressionLc(Expression *expr1, Expression *expr2);
|
||||||
|
ValuePtr evaluate(const class Context *context) const;
|
||||||
|
};
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "stl-utils.h"
|
#include "stl-utils.h"
|
||||||
#include "printutils.h"
|
#include "printutils.h"
|
||||||
|
#include "stackcheck.h"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
#include <boost/math/special_functions/fpclassify.hpp>
|
#include <boost/math/special_functions/fpclassify.hpp>
|
||||||
|
@ -88,21 +89,14 @@ Function::~Function()
|
||||||
delete expr;
|
delete expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *txt = "stack usage: ";
|
|
||||||
ValuePtr Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
|
ValuePtr Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
|
||||||
{
|
{
|
||||||
char _c;
|
|
||||||
bool set = ctx->setStack(&_c);
|
|
||||||
|
|
||||||
if (!expr) return ValuePtr::undefined;
|
if (!expr) return ValuePtr::undefined;
|
||||||
Context *c = new Context(ctx);
|
Context *c = new Context(ctx);
|
||||||
c->setVariables(definition_arguments, evalctx);
|
c->setVariables(definition_arguments, evalctx);
|
||||||
ValuePtr result = expr->evaluate(c);
|
ValuePtr result = expr->evaluate(c);
|
||||||
delete c;
|
delete c;
|
||||||
|
|
||||||
if (set) {
|
|
||||||
std::cout << txt << ctx->stackUsage() << std::endl;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
#include "LibraryInfo.h"
|
#include "LibraryInfo.h"
|
||||||
#include "nodedumper.h"
|
#include "nodedumper.h"
|
||||||
|
#include "stackcheck.h"
|
||||||
#include "CocoaUtils.h"
|
#include "CocoaUtils.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -655,6 +656,8 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
bool isGuiLaunched = getenv("GUI_LAUNCHED") != 0;
|
bool isGuiLaunched = getenv("GUI_LAUNCHED") != 0;
|
||||||
|
StackCheck::inst()->init();
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
if (isGuiLaunched) set_output_handler(CocoaUtils::nslog, NULL);
|
if (isGuiLaunched) set_output_handler(CocoaUtils::nslog, NULL);
|
||||||
#else
|
#else
|
||||||
|
|
79
src/parser.y
79
src/parser.y
|
@ -308,65 +308,57 @@ single_module_instantiation:
|
||||||
expr:
|
expr:
|
||||||
TOK_TRUE
|
TOK_TRUE
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr(true));
|
$$ = new ExpressionConst(ValuePtr(true));
|
||||||
}
|
}
|
||||||
| TOK_FALSE
|
| TOK_FALSE
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr(false));
|
$$ = new ExpressionConst(ValuePtr(false));
|
||||||
}
|
}
|
||||||
| TOK_UNDEF
|
| TOK_UNDEF
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr::undefined);
|
$$ = new ExpressionConst(ValuePtr::undefined);
|
||||||
}
|
}
|
||||||
| TOK_ID
|
| TOK_ID
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LOOKUP);
|
$$ = new ExpressionLookup($1);
|
||||||
$$->var_name = $1;
|
|
||||||
free($1);
|
free($1);
|
||||||
}
|
}
|
||||||
| expr '.' TOK_ID
|
| expr '.' TOK_ID
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_MEMBER, $1);
|
$$ = new ExpressionMember($3, $1);
|
||||||
$$->var_name = $3;
|
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| TOK_STRING
|
| TOK_STRING
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr(std::string($1)));
|
$$ = new ExpressionConst(ValuePtr(std::string($1)));
|
||||||
free($1);
|
free($1);
|
||||||
}
|
}
|
||||||
| TOK_NUMBER
|
| TOK_NUMBER
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr($1));
|
$$ = new ExpressionConst(ValuePtr($1));
|
||||||
}
|
}
|
||||||
| TOK_LET '(' arguments_call ')' expr %prec LET
|
| TOK_LET '(' arguments_call ')' expr %prec LET
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LET);
|
$$ = new ExpressionLet();
|
||||||
$$->call_arguments = *$3;
|
$$->call_arguments = *$3;
|
||||||
delete $3;
|
delete $3;
|
||||||
$$->children.push_back($5);
|
$$->children.push_back($5);
|
||||||
}
|
}
|
||||||
| '[' expr ':' expr ']'
|
| '[' expr ':' expr ']'
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_RANGE);
|
$$ = new ExpressionRange($2, $4);
|
||||||
$$->children.push_back($2);
|
|
||||||
$$->children.push_back($4);
|
|
||||||
}
|
}
|
||||||
| '[' expr ':' expr ':' expr ']'
|
| '[' expr ':' expr ':' expr ']'
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_RANGE);
|
$$ = new ExpressionRange($2, $4, $6);
|
||||||
$$->children.push_back($2);
|
|
||||||
$$->children.push_back($4);
|
|
||||||
$$->children.push_back($6);
|
|
||||||
}
|
}
|
||||||
| '[' list_comprehension_elements ']'
|
| '[' list_comprehension_elements ']'
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LC_EXPRESSION);
|
$$ = new ExpressionLcExpression($2);
|
||||||
$$->children.push_back($2);
|
|
||||||
}
|
}
|
||||||
| '[' optional_commas ']'
|
| '[' optional_commas ']'
|
||||||
{
|
{
|
||||||
$$ = new Expression(ValuePtr(Value::VectorType()));
|
$$ = new ExpressionConst(ValuePtr(Value::VectorType()));
|
||||||
}
|
}
|
||||||
| '[' vector_expr optional_commas ']'
|
| '[' vector_expr optional_commas ']'
|
||||||
{
|
{
|
||||||
|
@ -374,55 +366,55 @@ expr:
|
||||||
}
|
}
|
||||||
| expr '*' expr
|
| expr '*' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_MULTIPLY, $1, $3);
|
$$ = new ExpressionMultiply($1, $3);
|
||||||
}
|
}
|
||||||
| expr '/' expr
|
| expr '/' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_DIVISION, $1, $3);
|
$$ = new ExpressionDivision($1, $3);
|
||||||
}
|
}
|
||||||
| expr '%' expr
|
| expr '%' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_MODULO, $1, $3);
|
$$ = new ExpressionModulo($1, $3);
|
||||||
}
|
}
|
||||||
| expr '+' expr
|
| expr '+' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_PLUS, $1, $3);
|
$$ = new ExpressionPlus($1, $3);
|
||||||
}
|
}
|
||||||
| expr '-' expr
|
| expr '-' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_MINUS, $1, $3);
|
$$ = new ExpressionMinus($1, $3);
|
||||||
}
|
}
|
||||||
| expr '<' expr
|
| expr '<' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LESS, $1, $3);
|
$$ = new ExpressionLess($1, $3);
|
||||||
}
|
}
|
||||||
| expr LE expr
|
| expr LE expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LESS_OR_EQUAL, $1, $3);
|
$$ = new ExpressionLessOrEqual($1, $3);
|
||||||
}
|
}
|
||||||
| expr EQ expr
|
| expr EQ expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_EQUAL, $1, $3);
|
$$ = new ExpressionEqual($1, $3);
|
||||||
}
|
}
|
||||||
| expr NE expr
|
| expr NE expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_NOT_EQUAL, $1, $3);
|
$$ = new ExpressionNotEqual($1, $3);
|
||||||
}
|
}
|
||||||
| expr GE expr
|
| expr GE expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_GREATER_OR_EQUAL, $1, $3);
|
$$ = new ExpressionGreaterOrEqual($1, $3);
|
||||||
}
|
}
|
||||||
| expr '>' expr
|
| expr '>' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_GREATER, $1, $3);
|
$$ = new ExpressionGreater($1, $3);
|
||||||
}
|
}
|
||||||
| expr AND expr
|
| expr AND expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LOGICAL_AND, $1, $3);
|
$$ = new ExpressionLogicalAnd($1, $3);
|
||||||
}
|
}
|
||||||
| expr OR expr
|
| expr OR expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LOGICAL_OR, $1, $3);
|
$$ = new ExpressionLogicalOr($1, $3);
|
||||||
}
|
}
|
||||||
| '+' expr
|
| '+' expr
|
||||||
{
|
{
|
||||||
|
@ -430,11 +422,11 @@ expr:
|
||||||
}
|
}
|
||||||
| '-' expr
|
| '-' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_INVERT, $2);
|
$$ = new ExpressionInvert($2);
|
||||||
}
|
}
|
||||||
| '!' expr
|
| '!' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_NOT, $2);
|
$$ = new ExpressionNot($2);
|
||||||
}
|
}
|
||||||
| '(' expr ')'
|
| '(' expr ')'
|
||||||
{
|
{
|
||||||
|
@ -442,18 +434,15 @@ expr:
|
||||||
}
|
}
|
||||||
| expr '?' expr ':' expr
|
| expr '?' expr ':' expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_TERNARY);
|
$$ = new ExpressionTernary($1, $3, $5);
|
||||||
$$->children.push_back($1);
|
|
||||||
$$->children.push_back($3);
|
|
||||||
$$->children.push_back($5);
|
|
||||||
}
|
}
|
||||||
| expr '[' expr ']'
|
| expr '[' expr ']'
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_ARRAY_ACCESS, $1, $3);
|
$$ = new ExpressionArray($1, $3);
|
||||||
}
|
}
|
||||||
| TOK_ID '(' arguments_call ')'
|
| TOK_ID '(' arguments_call ')'
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_FUNCTION);
|
$$ = new ExpressionFunction();
|
||||||
$$->call_funcname = $1;
|
$$->call_funcname = $1;
|
||||||
$$->call_arguments = *$3;
|
$$->call_arguments = *$3;
|
||||||
free($1);
|
free($1);
|
||||||
|
@ -466,7 +455,7 @@ list_comprehension_elements:
|
||||||
be parsed as an expression) */
|
be parsed as an expression) */
|
||||||
TOK_LET '(' arguments_call ')' list_comprehension_elements
|
TOK_LET '(' arguments_call ')' list_comprehension_elements
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LC, $5);
|
$$ = new ExpressionLc($5);
|
||||||
$$->call_funcname = "let";
|
$$->call_funcname = "let";
|
||||||
$$->call_arguments = *$3;
|
$$->call_arguments = *$3;
|
||||||
delete $3;
|
delete $3;
|
||||||
|
@ -477,7 +466,7 @@ list_comprehension_elements:
|
||||||
|
|
||||||
/* transform for(i=...,j=...) -> for(i=...) for(j=...) */
|
/* transform for(i=...,j=...) -> for(i=...) for(j=...) */
|
||||||
for (int i = $3->size()-1; i >= 0; i--) {
|
for (int i = $3->size()-1; i >= 0; i--) {
|
||||||
Expression *e = new Expression(EXPRESSION_TYPE_LC, $$);
|
Expression *e = new ExpressionLc($$);
|
||||||
e->call_funcname = "for";
|
e->call_funcname = "for";
|
||||||
e->call_arguments.push_back((*$3)[i]);
|
e->call_arguments.push_back((*$3)[i]);
|
||||||
$$ = e;
|
$$ = e;
|
||||||
|
@ -486,7 +475,7 @@ list_comprehension_elements:
|
||||||
}
|
}
|
||||||
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr
|
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_LC, $3, $5);
|
$$ = new ExpressionLc($3, $5);
|
||||||
$$->call_funcname = "if";
|
$$->call_funcname = "if";
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -504,7 +493,7 @@ optional_commas:
|
||||||
vector_expr:
|
vector_expr:
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
$$ = new Expression(EXPRESSION_TYPE_VECTOR, $1);
|
$$ = new ExpressionVector($1);
|
||||||
}
|
}
|
||||||
| vector_expr ',' optional_commas expr
|
| vector_expr ',' optional_commas expr
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue