Merge branch 'lc-extensions' into lc-extensions-cstyle-for

Make C-style for an experimental feature
This commit is contained in:
Marius Kintel 2016-01-20 00:35:28 -05:00
commit a7a629cec9
13 changed files with 126 additions and 46 deletions

View file

@ -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) {}
};

View file

@ -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)

View file

@ -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());
}
}

View file

@ -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);
};

View file

@ -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());
}

View file

@ -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
;

View 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] ]);

View file

@ -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] ]);

View file

@ -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] ];

View file

@ -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

View file

@ -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]]

View file

@ -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]]

View file

@ -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)]];