Merge branch 'lc-extensions' into lc-extensions-cstyle-for
Make C-style for an experimental feature
This commit is contained in:
commit
a7a629cec9
13 changed files with 126 additions and 46 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) {}
|
||||
};
|
||||
|
|
|
|||
19
src/expr.cc
19
src/expr.cc
|
|
@ -33,6 +33,7 @@
|
|||
#include "printutils.h"
|
||||
#include "stackcheck.h"
|
||||
#include "exceptions.h"
|
||||
#include "feature.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
|
|
@ -534,6 +535,10 @@ ExpressionLcIf::ExpressionLcIf(Expression *cond, Expression *exprIf, Expression
|
|||
|
||||
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;
|
||||
|
|
@ -550,9 +555,9 @@ ValuePtr ExpressionLcIf::evaluate(const Context *context) const
|
|||
|
||||
void ExpressionLcIf::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "if(" << *this->cond << ") " << *this->first;
|
||||
stream << "if(" << *this->cond << ") (" << *this->first << ")";
|
||||
if (this->second) {
|
||||
stream << " else " << *this->second;
|
||||
stream << " else (" << *this->second << ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -563,6 +568,8 @@ ExpressionLcEach::ExpressionLcEach(Expression *expr)
|
|||
|
||||
ValuePtr ExpressionLcEach::evaluate(const Context *context) const
|
||||
{
|
||||
ExperimentalFeatureException::check(Feature::ExperimentalEachExpression);
|
||||
|
||||
Value::VectorType vec;
|
||||
|
||||
ValuePtr v = this->first->evaluate(context);
|
||||
|
|
@ -595,7 +602,7 @@ ValuePtr ExpressionLcEach::evaluate(const Context *context) const
|
|||
|
||||
void ExpressionLcEach::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "each " << *this->first;
|
||||
stream << "each (" << *this->first << ")";
|
||||
}
|
||||
|
||||
ExpressionLcFor::ExpressionLcFor(const AssignmentList &arglist, Expression *expr)
|
||||
|
|
@ -647,7 +654,7 @@ ValuePtr ExpressionLcFor::evaluate(const Context *context) const
|
|||
|
||||
void ExpressionLcFor::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "for(" << this->call_arguments << ") " << *this->first;
|
||||
stream << "for(" << this->call_arguments << ") (" << *this->first << ")";
|
||||
}
|
||||
|
||||
ExpressionLcForC::ExpressionLcForC(const AssignmentList &arglist, const AssignmentList &incrargs, Expression *cond, Expression *expr)
|
||||
|
|
@ -657,6 +664,8 @@ ExpressionLcForC::ExpressionLcForC(const AssignmentList &arglist, const Assignme
|
|||
|
||||
ValuePtr ExpressionLcForC::evaluate(const Context *context) const
|
||||
{
|
||||
ExperimentalFeatureException::check(Feature::ExperimentalForCExpression);
|
||||
|
||||
Value::VectorType vec;
|
||||
|
||||
Context c(context);
|
||||
|
|
@ -703,7 +712,7 @@ ValuePtr ExpressionLcLet::evaluate(const Context *context) const
|
|||
|
||||
void ExpressionLcLet::print(std::ostream &stream) const
|
||||
{
|
||||
stream << "let(" << this->call_arguments << ") " << *this->first;
|
||||
stream << "let(" << this->call_arguments << ") (" << *this->first << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const Expression &expr)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
|
@ -18,6 +19,9 @@ 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.");
|
||||
const Feature Feature::ExperimentalForCExpression("lc-for-c", "Enable C-style <code>for</code> expression in list comprehensions.");
|
||||
|
||||
Feature::Feature(const std::string &name, const std::string &description)
|
||||
: enabled(false), name(name), description(description)
|
||||
|
|
@ -76,3 +80,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,18 @@
|
|||
#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;
|
||||
static const Feature ExperimentalForCExpression;
|
||||
|
||||
const std::string& get_name() const;
|
||||
const std::string& get_description() const;
|
||||
|
||||
|
|
@ -37,3 +43,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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -355,7 +355,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());
|
||||
}
|
||||
|
||||
|
|
|
|||
14
src/parser.y
14
src/parser.y
|
|
@ -121,6 +121,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
|
||||
|
|
@ -444,7 +445,7 @@ 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 ExpressionLcLet(*$3, $5);
|
||||
delete $3;
|
||||
|
|
@ -482,8 +483,17 @@ list_comprehension_elements:
|
|||
}
|
||||
;
|
||||
|
||||
list_comprehension_elements_or_expr:
|
||||
// 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_p
|
||||
| expr
|
||||
;
|
||||
|
||||
|
|
|
|||
10
testdata/scad/functions/list-comprehensions-experimental.scad
vendored
Normal file
10
testdata/scad/functions/list-comprehensions-experimental.scad
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
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 ]);
|
||||
echo([ for (i=2;i<=10;i=i+2) i ]);
|
||||
echo([ for (i=1,n=1;i<=4;i=i+1,n=(n+i)*i) [i,n] ]);
|
||||
|
|
@ -29,11 +29,3 @@ 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 ]);
|
||||
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 = [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 ]);
|
||||
echo([ for (i=2;i<=10;i=i+2) i ]);
|
||||
echo([ for (i=1,n=1;i<=4;i=i+1,n=(n+i)*i) [i,n] ]);
|
||||
|
|
|
|||
5
testdata/scad/misc/allexpressions.scad
vendored
5
testdata/scad/misc/allexpressions.scad
vendored
|
|
@ -31,6 +31,7 @@ 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"];
|
||||
ff = [for (a=[0,1]) if (a == 0) "A" else ( "B" )];
|
||||
gg = [each [ "a", 0, false ]];
|
||||
hh = [for (a=0,b=1;a < 5;a=a+1,b=b+2) [a,b*b] ];
|
||||
hh = [for (a = [0 : 3]) if (a < 2) ( if (a < 1) ["+", a] ) else ["-", a] ];
|
||||
ii = [for (a=0,b=1;a < 5;a=a+1,b=b+2) [a,b*b] ];
|
||||
|
|
|
|||
|
|
@ -888,6 +888,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>
|
||||
|
|
@ -981,16 +992,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" "--enable=lc-for-c")
|
||||
endif()
|
||||
|
||||
# 2D tests should be viewed from the top, not an angle.
|
||||
|
|
@ -1169,8 +1176,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
|
||||
|
|
@ -1299,6 +1305,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
|
||||
|
|
|
|||
|
|
@ -26,10 +26,3 @@ 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]
|
||||
ECHO: ["+", "-", "+"]
|
||||
ECHO: ["A", "B"]
|
||||
ECHO: ["-", "A", "B"]
|
||||
ECHO: [2, 4, 3, 9, 4, 16]
|
||||
ECHO: ["a", "b", -5, -7, -9, 1, 2, 4, 8, 16, "c", 42, true]
|
||||
ECHO: [2, 4, 6, 8, 10]
|
||||
ECHO: [[1, 1], [2, 6], [3, 27], [4, 124]]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
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]
|
||||
ECHO: [2, 4, 6, 8, 10]
|
||||
ECHO: [[1, 1], [2, 6], [3, 27], [4, 124]]
|
||||
|
|
@ -29,9 +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];
|
||||
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, b = 1;(a < 5);a = (a + 1), b = (b + 2)) [a, (b * 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]))];
|
||||
ii = [for(a = 0, b = 1;(a < 5);a = (a + 1), b = (b + 2)) [a, (b * b)]];
|
||||
|
|
|
|||
Loading…
Reference in a new issue