Merge remote-tracking branch 'origin/master' into c++11
This commit is contained in:
commit
f2b5382247
17 changed files with 314 additions and 126 deletions
|
|
@ -1,6 +1,14 @@
|
|||
#include <exception>
|
||||
#pragma once
|
||||
|
||||
class RecursionException: public std::runtime_error {
|
||||
#include <stdexcept>
|
||||
|
||||
class EvaluationException : public std::runtime_error {
|
||||
public:
|
||||
EvaluationException(const std::string &what_arg) : std::runtime_error(what_arg) {}
|
||||
virtual ~EvaluationException() throw() {}
|
||||
};
|
||||
|
||||
class RecursionException: public EvaluationException {
|
||||
public:
|
||||
static RecursionException create(const char *recursiontype, const std::string &name) {
|
||||
std::stringstream out;
|
||||
|
|
@ -10,5 +18,5 @@ public:
|
|||
virtual ~RecursionException() throw() {}
|
||||
|
||||
private:
|
||||
RecursionException(const std::string &what_arg) : std::runtime_error(what_arg) {}
|
||||
RecursionException(const std::string &what_arg) : EvaluationException(what_arg) {}
|
||||
};
|
||||
|
|
|
|||
227
src/expr.cc
227
src/expr.cc
|
|
@ -33,6 +33,7 @@
|
|||
#include "printutils.h"
|
||||
#include "stackcheck.h"
|
||||
#include "exceptions.h"
|
||||
#include "feature.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
// unnamed namespace
|
||||
|
|
@ -409,7 +410,14 @@ ValuePtr ExpressionVector::evaluate(const Context *context) const
|
|||
Value::VectorType vec;
|
||||
for(const auto &e : this->children) {
|
||||
ValuePtr tmpval = e->evaluate(context);
|
||||
vec.push_back(tmpval);
|
||||
if (e->isListComprehension()) {
|
||||
const Value::VectorType result = tmpval->toVector();
|
||||
for (size_t i = 0;i < result.size();i++) {
|
||||
vec.push_back(result[i]);
|
||||
}
|
||||
} else {
|
||||
vec.push_back(tmpval);
|
||||
}
|
||||
}
|
||||
return ValuePtr(vec);
|
||||
}
|
||||
|
|
@ -505,29 +513,12 @@ void ExpressionLet::print(std::ostream &stream) const
|
|||
stream << "let(" << this->call_arguments << ") " << *first;
|
||||
}
|
||||
|
||||
ExpressionLcExpression::ExpressionLcExpression(Expression *expr) : Expression(expr)
|
||||
ExpressionLc::ExpressionLc(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)
|
||||
ExpressionLc::ExpressionLc(Expression *expr1, Expression *expr2)
|
||||
: Expression(expr1, expr2)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -536,78 +527,150 @@ bool ExpressionLc::isListComprehension() const
|
|||
return true;
|
||||
}
|
||||
|
||||
ValuePtr ExpressionLc::evaluate(const Context *context) const
|
||||
ExpressionLcIf::ExpressionLcIf(Expression *cond, Expression *exprIf, Expression *exprElse)
|
||||
: ExpressionLc(exprIf, exprElse), cond(cond)
|
||||
{
|
||||
}
|
||||
|
||||
ValuePtr ExpressionLcIf::evaluate(const Context *context) const
|
||||
{
|
||||
if (this->second) {
|
||||
ExperimentalFeatureException::check(Feature::ExperimentalElseExpression);
|
||||
}
|
||||
|
||||
const Expression *expr = this->cond->evaluate(context) ? this->first : this->second;
|
||||
|
||||
Value::VectorType vec;
|
||||
if (expr) {
|
||||
if (expr->isListComprehension()) {
|
||||
return expr->evaluate(context);
|
||||
} else {
|
||||
vec.push_back(expr->evaluate(context));
|
||||
}
|
||||
}
|
||||
|
||||
return ValuePtr(vec);
|
||||
}
|
||||
|
||||
void ExpressionLcIf::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "if(" << *this->cond << ") (" << *this->first << ")";
|
||||
if (this->second) {
|
||||
stream << " else (" << *this->second << ")";
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionLcEach::ExpressionLcEach(Expression *expr)
|
||||
: ExpressionLc(expr)
|
||||
{
|
||||
}
|
||||
|
||||
ValuePtr ExpressionLcEach::evaluate(const Context *context) const
|
||||
{
|
||||
ExperimentalFeatureException::check(Feature::ExperimentalEachExpression);
|
||||
|
||||
Value::VectorType vec;
|
||||
|
||||
ValuePtr v = this->first->evaluate(context);
|
||||
|
||||
if (v->type() == Value::RANGE) {
|
||||
RangeType range = v->toRange();
|
||||
boost::uint32_t steps = range.numValues();
|
||||
if (steps >= 1000000) {
|
||||
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
|
||||
} else {
|
||||
for (RangeType::iterator it = range.begin();it != range.end();it++) {
|
||||
vec.push_back(ValuePtr(*it));
|
||||
}
|
||||
}
|
||||
} else if (v->type() == Value::VECTOR) {
|
||||
Value::VectorType vector = v->toVector();
|
||||
for (size_t i = 0; i < v->toVector().size(); i++) {
|
||||
vec.push_back(vector[i]);
|
||||
}
|
||||
} else if (v->type() != Value::UNDEFINED) {
|
||||
vec.push_back(v);
|
||||
}
|
||||
|
||||
if (this->first->isListComprehension()) {
|
||||
return ValuePtr(flatten(vec));
|
||||
} else {
|
||||
return ValuePtr(vec);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionLcEach::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "each (" << *this->first << ")";
|
||||
}
|
||||
|
||||
ExpressionLcFor::ExpressionLcFor(const AssignmentList &arglist, Expression *expr)
|
||||
: ExpressionLc(expr), call_arguments(arglist)
|
||||
{
|
||||
}
|
||||
|
||||
ValuePtr ExpressionLcFor::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);
|
||||
EvalContext for_context(context, this->call_arguments);
|
||||
|
||||
Context assign_context(context);
|
||||
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);
|
||||
// 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);
|
||||
Context c(context);
|
||||
|
||||
if (it_values->type() == Value::RANGE) {
|
||||
RangeType range = it_values->toRange();
|
||||
boost::uint32_t steps = range.numValues();
|
||||
if (steps >= 1000000) {
|
||||
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
|
||||
} else {
|
||||
for (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);
|
||||
if (it_values->type() == Value::RANGE) {
|
||||
RangeType range = it_values->toRange();
|
||||
boost::uint32_t steps = range.numValues();
|
||||
if (steps >= 1000000) {
|
||||
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
|
||||
} else {
|
||||
for (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));
|
||||
}
|
||||
|
||||
return this->first->evaluate(&c);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
if (this->first->isListComprehension()) {
|
||||
return ValuePtr(flatten(vec));
|
||||
} else {
|
||||
return ValuePtr(vec);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionLc::print(std::ostream &stream) const
|
||||
void ExpressionLcFor::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");
|
||||
}
|
||||
stream << "for(" << this->call_arguments << ") (" << *this->first << ")";
|
||||
}
|
||||
|
||||
ExpressionLcLet::ExpressionLcLet(const AssignmentList &arglist, Expression *expr)
|
||||
: ExpressionLc(expr), call_arguments(arglist)
|
||||
{
|
||||
}
|
||||
|
||||
ValuePtr ExpressionLcLet::evaluate(const Context *context) const
|
||||
{
|
||||
Context c(context);
|
||||
evaluate_sequential_assignment(this->call_arguments, &c);
|
||||
return this->first->evaluate(&c);
|
||||
}
|
||||
|
||||
void ExpressionLcLet::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "let(" << this->call_arguments << ") (" << *this->first << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const Expression &expr)
|
||||
|
|
|
|||
|
|
@ -231,25 +231,48 @@ 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);
|
||||
ExpressionLc(Expression *expr);
|
||||
ExpressionLc(Expression *expr1, Expression *expr2);
|
||||
};
|
||||
|
||||
class ExpressionLcIf : public ExpressionLc
|
||||
{
|
||||
public:
|
||||
ExpressionLcIf(Expression *cond, Expression *exprIf, Expression *exprElse);
|
||||
ValuePtr evaluate(const class Context *context) const;
|
||||
virtual void print(std::ostream &stream) const;
|
||||
private:
|
||||
Expression *cond;
|
||||
};
|
||||
|
||||
class ExpressionLcFor : public ExpressionLc
|
||||
{
|
||||
public:
|
||||
ExpressionLcFor(const AssignmentList &arglist, Expression *expr);
|
||||
ValuePtr evaluate(const class Context *context) const;
|
||||
virtual void print(std::ostream &stream) const;
|
||||
private:
|
||||
AssignmentList call_arguments;
|
||||
};
|
||||
|
||||
class ExpressionLcEach : public ExpressionLc
|
||||
{
|
||||
public:
|
||||
ExpressionLcEach(Expression *expr);
|
||||
ValuePtr evaluate(const class Context *context) const;
|
||||
virtual void print(std::ostream &stream) const;
|
||||
};
|
||||
|
||||
class ExpressionLcLet : public ExpressionLc
|
||||
{
|
||||
public:
|
||||
ExpressionLcLet(const AssignmentList &arglist, Expression *expr);
|
||||
ValuePtr evaluate(const class Context *context) const;
|
||||
virtual void print(std::ostream &stream) const;
|
||||
private:
|
||||
std::string name;
|
||||
AssignmentList call_arguments;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
|
@ -18,6 +19,8 @@ Feature::list_t Feature::feature_list;
|
|||
* argument to enable the option and for saving the option value in GUI
|
||||
* context.
|
||||
*/
|
||||
const Feature Feature::ExperimentalEachExpression("lc-each", "Enable <code>each</code> expression in list comprehensions.");
|
||||
const Feature Feature::ExperimentalElseExpression("lc-else", "Enable <code>else</code> expression in list comprehensions.");
|
||||
|
||||
Feature::Feature(const std::string &name, const std::string &description)
|
||||
: enabled(false), name(name), description(description)
|
||||
|
|
@ -76,3 +79,23 @@ void Feature::dump_features()
|
|||
std::cout << "Feature('" << it->first << "') = " << (it->second->is_enabled() ? "enabled" : "disabled") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
ExperimentalFeatureException::ExperimentalFeatureException(const std::string &what_arg)
|
||||
: EvaluationException(what_arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ExperimentalFeatureException::~ExperimentalFeatureException() throw()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ExperimentalFeatureException::check(const Feature &feature)
|
||||
{
|
||||
if (!feature.is_enabled()) {
|
||||
std::stringstream out;
|
||||
out << "ERROR: Experimental feature not enabled: '" << feature.get_name() << "'. Please check preferences.";
|
||||
throw ExperimentalFeatureException(out.str());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,17 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "exceptions.h"
|
||||
|
||||
class Feature
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Feature *> list_t;
|
||||
typedef list_t::iterator iterator;
|
||||
|
||||
static const Feature ExperimentalEachExpression;
|
||||
static const Feature ExperimentalElseExpression;
|
||||
|
||||
const std::string& get_name() const;
|
||||
const std::string& get_description() const;
|
||||
|
||||
|
|
@ -37,3 +42,13 @@ private:
|
|||
Feature(const std::string &name, const std::string &description);
|
||||
virtual ~Feature();
|
||||
};
|
||||
|
||||
class ExperimentalFeatureException : public EvaluationException
|
||||
{
|
||||
public:
|
||||
static void check(const Feature &feature);
|
||||
virtual ~ExperimentalFeatureException() throw();
|
||||
|
||||
private:
|
||||
ExperimentalFeatureException(const std::string &what_arg);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ Highlighter::Highlighter(QTextDocument *parent)
|
|||
{
|
||||
tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";";
|
||||
tokentypes["math"] << "abs" << "sign" << "acos" << "asin" << "atan" << "atan2" << "sin" << "cos" << "floor" << "round" << "ceil" << "ln" << "log" << "lookup" << "min" << "max" << "pow" << "sqrt" << "exp" << "rands";
|
||||
tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign" << "echo"<< "search" << "str" << "let";
|
||||
tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign" << "echo"<< "search" << "str" << "let" << "each";
|
||||
tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull" << "resize" << "mirror" << "minkowski";
|
||||
tokentypes["csgop"] << "union" << "intersection" << "difference" << "render";
|
||||
tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron";
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
|
|||
"else" return TOK_ELSE;
|
||||
"let" return TOK_LET;
|
||||
"for" return TOK_FOR;
|
||||
"each" return TOK_EACH;
|
||||
|
||||
"true" return TOK_TRUE;
|
||||
"false" return TOK_FALSE;
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
|
|||
std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(context);
|
||||
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
|
||||
}
|
||||
catch (RecursionException &e) {
|
||||
catch (EvaluationException &e) {
|
||||
PRINT(e.what());
|
||||
}
|
||||
|
||||
|
|
|
|||
44
src/parser.y
44
src/parser.y
|
|
@ -24,7 +24,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
%expect 1 /* Expect 1 shift/reduce conflict for ifelse_statement - "dangling else problem" */
|
||||
%expect 2 /* Expect 2 shift/reduce conflict for ifelse_statement - "dangling else problem" */
|
||||
|
||||
%{
|
||||
|
||||
|
|
@ -89,6 +89,7 @@ std::string parser_source_path;
|
|||
%token TOK_ELSE
|
||||
%token TOK_FOR
|
||||
%token TOK_LET
|
||||
%token TOK_EACH
|
||||
|
||||
%token <text> TOK_ID
|
||||
%token <text> TOK_STRING
|
||||
|
|
@ -119,6 +120,7 @@ std::string parser_source_path;
|
|||
%type <expr> expr
|
||||
%type <expr> vector_expr
|
||||
%type <expr> list_comprehension_elements
|
||||
%type <expr> list_comprehension_elements_p
|
||||
%type <expr> list_comprehension_elements_or_expr
|
||||
|
||||
%type <inst> module_instantiation
|
||||
|
|
@ -284,10 +286,11 @@ child_statement:
|
|||
}
|
||||
;
|
||||
|
||||
// "for" is a valid module identifier
|
||||
// "for" and "each" are a valid module identifier
|
||||
module_id:
|
||||
TOK_ID { $$ = $1; }
|
||||
| TOK_FOR { $$ = strdup("for"); }
|
||||
| TOK_EACH { $$ = strdup("each"); }
|
||||
;
|
||||
|
||||
single_module_instantiation:
|
||||
|
|
@ -346,10 +349,6 @@ expr:
|
|||
{
|
||||
$$ = new ExpressionRange($2, $4, $6);
|
||||
}
|
||||
| '[' list_comprehension_elements ']'
|
||||
{
|
||||
$$ = new ExpressionLcExpression($2);
|
||||
}
|
||||
| '[' optional_commas ']'
|
||||
{
|
||||
$$ = new ExpressionConst(ValuePtr(Value::VectorType()));
|
||||
|
|
@ -445,11 +444,15 @@ expr:
|
|||
list_comprehension_elements:
|
||||
/* The last set element may not be a "let" (as that would instead
|
||||
be parsed as an expression) */
|
||||
TOK_LET '(' arguments_call ')' list_comprehension_elements
|
||||
TOK_LET '(' arguments_call ')' list_comprehension_elements_p
|
||||
{
|
||||
$$ = new ExpressionLc("let", *$3, $5);
|
||||
$$ = new ExpressionLcLet(*$3, $5);
|
||||
delete $3;
|
||||
}
|
||||
| TOK_EACH list_comprehension_elements_or_expr
|
||||
{
|
||||
$$ = new ExpressionLcEach($2);
|
||||
}
|
||||
| TOK_FOR '(' arguments_call ')' list_comprehension_elements_or_expr
|
||||
{
|
||||
$$ = $5;
|
||||
|
|
@ -458,19 +461,32 @@ list_comprehension_elements:
|
|||
for (int i = $3->size()-1; i >= 0; i--) {
|
||||
AssignmentList arglist;
|
||||
arglist.push_back((*$3)[i]);
|
||||
Expression *e = new ExpressionLc("for", arglist, $$);
|
||||
Expression *e = new ExpressionLcFor(arglist, $$);
|
||||
$$ = e;
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr
|
||||
{
|
||||
$$ = new ExpressionLc("if", $3, $5);
|
||||
$$ = new ExpressionLcIf($3, $5, 0);
|
||||
}
|
||||
| TOK_IF '(' expr ')' list_comprehension_elements_or_expr TOK_ELSE list_comprehension_elements_or_expr
|
||||
{
|
||||
$$ = new ExpressionLcIf($3, $5, $7);
|
||||
}
|
||||
;
|
||||
|
||||
// list_comprehension_elements with optional parenthesis
|
||||
list_comprehension_elements_p:
|
||||
list_comprehension_elements
|
||||
| '(' list_comprehension_elements ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
list_comprehension_elements_or_expr:
|
||||
list_comprehension_elements
|
||||
list_comprehension_elements_p
|
||||
| expr
|
||||
;
|
||||
|
||||
|
|
@ -484,7 +500,11 @@ vector_expr:
|
|||
{
|
||||
$$ = new ExpressionVector($1);
|
||||
}
|
||||
| vector_expr ',' optional_commas expr
|
||||
| list_comprehension_elements
|
||||
{
|
||||
$$ = new ExpressionVector($1);
|
||||
}
|
||||
| vector_expr ',' optional_commas list_comprehension_elements_or_expr
|
||||
{
|
||||
$$ = $1;
|
||||
$$->children.push_back($4);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ ScadLexer::ScadLexer(QObject *parent) : QsciLexerCPP(parent)
|
|||
{
|
||||
// -> Style: Keyword (lexer.l)
|
||||
keywordSet[0] =
|
||||
"if else let for module function true false undef "
|
||||
"if else let for each module function true false undef "
|
||||
"include use";
|
||||
|
||||
// -> Style: KeywordSet2 (func.cc)
|
||||
|
|
|
|||
8
testdata/scad/functions/list-comprehensions-experimental.scad
vendored
Normal file
8
testdata/scad/functions/list-comprehensions-experimental.scad
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
echo([ for (a = [0,1,2]) if (a == 1) "-" else "+" ]);
|
||||
echo([ for (a = [0,1,2]) if (a > 0) if (a == 1) "A" else "B" ]);
|
||||
echo([ for (a = [0,1,2]) if (a > 0) if (a == 1) "A" else "B" else "-" ]);
|
||||
echo([ for (a = [0 : 3]) if (a < 2) if (a < 1) ["+", a] else ["-", a] ]);
|
||||
echo([ for (a = [0 : 3]) if (a < 2) ( if (a < 1) ["+", a] ) else ["-", a] ]);
|
||||
echo([ for (a = [2 : 4]) each [ a, a*a ] ]);
|
||||
function f() = [ for (a = [0 : 4]) pow(2, a) ];
|
||||
echo([ each ["a", "b"], each [-5 : -2 : -9], each f(), each "c", each 42, each true ]);
|
||||
|
|
@ -27,3 +27,5 @@ echo([ for (a=[0:1]) if (true) if (true) a]);
|
|||
echo([ for (a=[0:1]) for (b=[a:2]) [b,a]]);
|
||||
echo([ for (a=[0:1]) if (true) for (b=[a:2]) [b,a]]);
|
||||
echo([ for (a=[0:1]) if (true) if (true) for (b=[a:2]) [b,a]]);
|
||||
echo([ -1, for (a = [0:1:3]) a, for (b = [3:-1:0]) b, -1 ]);
|
||||
echo([ for (a = [2:3]) a * 2, for (a = [5:9]) if ((a % 2) == 0) [ a, a + 1 ] , -1 ]);
|
||||
|
|
|
|||
4
testdata/scad/misc/allexpressions.scad
vendored
4
testdata/scad/misc/allexpressions.scad
vendored
|
|
@ -30,3 +30,7 @@ aa = k ? l : m;
|
|||
bb = n[o];
|
||||
cc = let(a=1) a;
|
||||
dd = [for (a=[0,1]) let(b=a) if (true) b];
|
||||
ee = ["abc", for (a=[0,1]) let(b=a) if (true) b, true, for(c=[1:3]) c, 3];
|
||||
ff = [for (a=[0,1]) if (a == 0) "A" else ( "B" )];
|
||||
gg = [each [ "a", 0, false ]];
|
||||
hh = [for (a = [0 : 3]) if (a < 2) ( if (a < 1) ["+", a] ) else ["-", a] ];
|
||||
|
|
|
|||
|
|
@ -885,6 +885,17 @@ macro(disable_tests)
|
|||
endforeach()
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# Tags tests as experimental. This will add all the --enable=<feature>
|
||||
# options for the tagged tests.
|
||||
#
|
||||
macro(experimental_tests)
|
||||
foreach (TESTNAME ${ARGN})
|
||||
# message("Marking as experimental ${TESTNAME}")
|
||||
list(APPEND EXPERIMENTAL_TESTS ${TESTNAME})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# Tags the given tests as belonging to the given CONFIG, i.e. will
|
||||
# only be executed when run using ctest -C <CONFIG>
|
||||
|
|
@ -978,16 +989,12 @@ function(add_cmdline_test TESTCMD_BASENAME)
|
|||
|
||||
if (${DISABLED} EQUAL -1)
|
||||
|
||||
set(EXPERIMENTAL_OPTION "")
|
||||
string(REGEX MATCH "csgtexttest" match_result1 ${TEST_FULLNAME})
|
||||
string(REGEX MATCH "cgalstlsanity" match_result2 ${TEST_FULLNAME})
|
||||
string(REGEX MATCH "dumptest" match_result3 ${TEST_FULLNAME})
|
||||
if( "${match_result1}" STREQUAL "" )
|
||||
if( "${match_result2}" STREQUAL "" )
|
||||
if( "${match_result3}" STREQUAL "" )
|
||||
set(EXPERIMENTAL_OPTION "")
|
||||
endif()
|
||||
endif()
|
||||
list(FIND EXPERIMENTAL_TESTS ${TEST_FULLNAME} EXPERIMENTAL)
|
||||
|
||||
if (${EXPERIMENTAL} EQUAL -1)
|
||||
set(EXPERIMENTAL_OPTION "")
|
||||
else()
|
||||
set(EXPERIMENTAL_OPTION "--enable=lc-each" "--enable=lc-else")
|
||||
endif()
|
||||
|
||||
# 2D tests should be viewed from the top, not an angle.
|
||||
|
|
@ -1166,8 +1173,7 @@ list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allmodules.scad)
|
||||
|
||||
list(APPEND CGALPNGTEST_2D_FILES ${FEATURES_2D_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_2D_FILES})
|
||||
list(APPEND CGALPNGTEST_3D_FILES ${FEATURES_3D_FILES} ${DEPRECATED_3D_FILES} ${ISSUES_3D_FILES}
|
||||
${EXAMPLE_3D_FILES})
|
||||
list(APPEND CGALPNGTEST_3D_FILES ${FEATURES_3D_FILES} ${DEPRECATED_3D_FILES} ${ISSUES_3D_FILES} ${EXAMPLE_3D_FILES})
|
||||
list(APPEND CGALPNGTEST_3D_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad
|
||||
|
|
@ -1300,6 +1306,8 @@ disable_tests(csgpngtest_primitive-inf-tests
|
|||
cgalpngtest_empty-shape-tests
|
||||
csgpngtest_issue1258)
|
||||
|
||||
experimental_tests(echotest_list-comprehensions-experimental)
|
||||
|
||||
# Test config handling
|
||||
|
||||
# Heavy tests are tests taking more than 10 seconds on a development computer
|
||||
|
|
|
|||
|
|
@ -24,3 +24,5 @@ ECHO: [0, 1]
|
|||
ECHO: [[0, 0], [1, 0], [2, 0], [1, 1], [2, 1]]
|
||||
ECHO: [[0, 0], [1, 0], [2, 0], [1, 1], [2, 1]]
|
||||
ECHO: [[0, 0], [1, 0], [2, 0], [1, 1], [2, 1]]
|
||||
ECHO: [-1, 0, 1, 2, 3, 3, 2, 1, 0, -1]
|
||||
ECHO: [4, 6, [6, 7], [8, 9], -1]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
ECHO: ["+", "-", "+"]
|
||||
ECHO: ["A", "B"]
|
||||
ECHO: ["-", "A", "B"]
|
||||
ECHO: [["+", 0], ["-", 1]]
|
||||
ECHO: [["+", 0], ["-", 2], ["-", 3]]
|
||||
ECHO: [2, 4, 3, 9, 4, 16]
|
||||
ECHO: ["a", "b", -5, -7, -9, 1, 2, 4, 8, 16, "c", 42, true]
|
||||
|
|
@ -29,5 +29,9 @@ z = j;
|
|||
aa = (k ? l : m);
|
||||
bb = n[o];
|
||||
cc = let(a = 1) a;
|
||||
dd = [for(a = [0, 1]) let(b = a) if(true) b];
|
||||
dd = [for(a = [0, 1]) (let(b = a) (if(true) (b)))];
|
||||
ee = ["abc", for(a = [0, 1]) (let(b = a) (if(true) (b))), true, for(c = [1 : 3]) (c), 3];
|
||||
ff = [for(a = [0, 1]) (if((a == 0)) ("A") else ("B"))];
|
||||
gg = [each (["a", 0, false])];
|
||||
hh = [for(a = [0 : 3]) (if((a < 2)) (if((a < 1)) (["+", a])) else (["-", a]))];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue