diff --git a/src/macro/Expressions.cc b/src/macro/Expressions.cc index 731cd4ab..813866ec 100644 --- a/src/macro/Expressions.cc +++ b/src/macro/Expressions.cc @@ -531,38 +531,29 @@ Array::eval() { if (arr.empty() && range1 && range2) { - DoublePtr range1int = dynamic_pointer_cast(range1->eval()); - DoublePtr range2int = dynamic_pointer_cast(range2->eval()); - if (!range1int || !range2int) + DoublePtr range1dbl = dynamic_pointer_cast(range1->eval()); + DoublePtr range2dbl = dynamic_pointer_cast(range2->eval()); + if (!range1dbl || !range2dbl) throw StackTrace("To create an array from a range using the colon operator, " - "both arguments must be doubles"); + "the arguments must evaluate to doubles"); + DoublePtr incdbl = make_shared(1, env); if (increment) { - auto incrementp = dynamic_pointer_cast(increment->eval()); - if (*incrementp == 0) - throw StackTrace("the increment cannot be equal to zero"); - - if (*range1int <= *range2int) - if (*incrementp < 0) - throw StackTrace("In this case the increment cannot be negative"); - else - for (int i = *range1int; i <= *range2int; i += *incrementp) - arr.emplace_back(make_shared(i, env)); - else - if (*incrementp > 0) - throw StackTrace("In this case the increment cannot be positive"); - else - for (int i = *range1int; i >= *range2int; i += *incrementp) - arr.emplace_back(make_shared(i, env)); + incdbl = dynamic_pointer_cast(increment->eval()); + if (!incdbl) + throw StackTrace("To create an array from a range using the colon operator, " + "the increment must evaluate to a double"); } - else - for (int i = *range1int; i <= *range2int; i++) + + if (*incdbl > 0 && *range1dbl < *range2dbl) + for (double i = *range1dbl; i <= *range2dbl; i += *incdbl) + arr.emplace_back(make_shared(i, env)); + else if (*range1dbl > *range2dbl && *incdbl < 0) + for (double i = *range1dbl; i >= *range2dbl; i += *incdbl) arr.emplace_back(make_shared(i, env)); - range1 = nullptr; - increment = nullptr; - range2 = nullptr; + range1 = increment = range2 = nullptr; } vector retval; diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy index 89011455..1cf97875 100644 --- a/src/macro/Parser.yy +++ b/src/macro/Parser.yy @@ -70,7 +70,7 @@ using namespace macro; %left EQUAL_EQUAL NOT_EQUAL %left LESS GREATER LESS_EQUAL GREATER_EQUAL %nonassoc IN -%nonassoc COLON +%left COLON %left UNION %left INTERSECTION %left PLUS MINUS @@ -88,7 +88,7 @@ using namespace macro; %type symbol %type > comma_name -%type > comma_expr function_args tuple_comma_expr +%type > comma_expr function_args tuple_comma_expr colon_expr %% @@ -278,6 +278,12 @@ tuple_comma_expr : %empty { $1.emplace_back($3); $$ = $1; } ; +colon_expr : expr COLON expr + { $$ = vector{$1, $3}; } + | colon_expr COLON expr + { $1.emplace_back($3); $$ = $1; } + ; + expr : LPAREN expr RPAREN { $$ = $2; } | symbol @@ -292,8 +298,15 @@ expr : LPAREN expr RPAREN { $$ = make_shared($1, driver.env, @$); } | QUOTED_STRING { $$ = make_shared($1, driver.env, @$); } - | expr COLON expr - { $$ = make_shared($1, $3, driver.env, @$); } + | colon_expr + { + if ($1.size() == 2) + $$ = make_shared($1[0], $1[1], driver.env, @$); + else if ($1.size() == 3) + $$ = make_shared($1[0], $1[1], $1[2], driver.env, @$); + else + error(@$, "The colon operator only works with 2 or 3 arguments"); + } | LBRACKET comma_expr RBRACKET { $$ = make_shared($2, driver.env, @$); } | symbol LBRACKET comma_expr RBRACKET