diff --git a/parser/macro.go b/parser/macro.go
index dc47b420..dcd23225 100644
--- a/parser/macro.go
+++ b/parser/macro.go
@@ -259,8 +259,13 @@ var (
// ExistsOneMacro expands "range.exists_one(var, predicate)", which is true if for exactly one
// element in range the predicate holds.
+ // Deprecated: Use ExistsOneMacroNew
ExistsOneMacro = NewReceiverMacro(operators.ExistsOne, 2, MakeExistsOne)
+ // ExistsOneMacroNew expands "range.existsOne(var, predicate)", which is true if for exactly one
+ // element in range the predicate holds.
+ ExistsOneMacroNew = NewReceiverMacro("existsOne", 2, MakeExistsOne)
+
// MapMacro expands "range.map(var, function)" into a comprehension which applies the function
// to each element in the range to produce a new list.
MapMacro = NewReceiverMacro(operators.Map, 2, MakeMap)
@@ -280,6 +285,7 @@ var (
AllMacro,
ExistsMacro,
ExistsOneMacro,
+ ExistsOneMacroNew,
MapMacro,
MapFilterMacro,
FilterMacro,
@@ -336,6 +342,9 @@ func MakeMap(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common
if !found {
return nil, eh.NewError(args[0].ID(), "argument is not an identifier")
}
+ if v == AccumulatorName {
+ return nil, eh.NewError(args[0].ID(), "iteration variable overwrites accumulator variable")
+ }
var fn ast.Expr
var filter ast.Expr
@@ -366,6 +375,9 @@ func MakeFilter(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *com
if !found {
return nil, eh.NewError(args[0].ID(), "argument is not an identifier")
}
+ if v == AccumulatorName {
+ return nil, eh.NewError(args[0].ID(), "iteration variable overwrites accumulator variable")
+ }
filter := args[1]
init := eh.NewList()
@@ -389,6 +401,9 @@ func makeQuantifier(kind quantifierKind, eh ExprHelper, target ast.Expr, args []
if !found {
return nil, eh.NewError(args[0].ID(), "argument must be a simple name")
}
+ if v == AccumulatorName {
+ return nil, eh.NewError(args[0].ID(), "iteration variable overwrites accumulator variable")
+ }
var init ast.Expr
var condition ast.Expr
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 72bb587f..f174c8fe 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -438,6 +438,13 @@ var testCases = []testInfo{
m^#2:*expr.Expr_IdentExpr#.f^#3:*expr.Expr_SelectExpr#
)^#4:has#`,
},
+ {
+ I: `has(m)`,
+ E: `ERROR: :1:5: invalid argument to has() macro
+ | has(m)
+ | ....^`,
+ },
+
{
I: `m.exists(v, f)`,
P: `__comprehension__(
@@ -495,7 +502,7 @@ var testCases = []testInfo{
)^#11:all#`,
},
{
- I: `m.exists_one(v, f)`,
+ I: `m.existsOne(v, f)`,
P: `__comprehension__(
// Variable
v,
@@ -521,10 +528,16 @@ var testCases = []testInfo{
__result__^#12:*expr.Expr_IdentExpr#,
1^#13:*expr.Constant_Int64Value#
)^#14:*expr.Expr_CallExpr#)^#15:*expr.Expr_ComprehensionExpr#`,
- M: `m^#1:*expr.Expr_IdentExpr#.exists_one(
+ M: `m^#1:*expr.Expr_IdentExpr#.existsOne(
v^#3:*expr.Expr_IdentExpr#,
f^#4:*expr.Expr_IdentExpr#
- )^#15:exists_one#`,
+ )^#15:existsOne#`,
+ },
+ {
+ I: `[].existsOne(__result__, __result__)`,
+ E: `ERROR: :1:14: iteration variable overwrites accumulator variable
+ | [].existsOne(__result__, __result__)
+ | .............^`,
},
{
I: `m.map(v, f)`,
@@ -553,7 +566,12 @@ var testCases = []testInfo{
f^#4:*expr.Expr_IdentExpr#
)^#11:map#`,
},
-
+ {
+ I: `m.map(__result__, __result__)`,
+ E: `ERROR: :1:7: iteration variable overwrites accumulator variable
+ | m.map(__result__, __result__)
+ | ......^`,
+ },
{
I: `m.map(v, p, f)`,
P: `__comprehension__(
@@ -618,6 +636,18 @@ var testCases = []testInfo{
p^#4:*expr.Expr_IdentExpr#
)^#13:filter#`,
},
+ {
+ I: `m.filter(__result__, false)`,
+ E: `ERROR: :1:10: iteration variable overwrites accumulator variable
+ | m.filter(__result__, false)
+ | .........^`,
+ },
+ {
+ I: `m.filter(a.b, false)`,
+ E: `ERROR: :1:11: argument is not an identifier
+ | m.filter(a.b, false)
+ | ..........^`,
+ },
// Tests from C++ parser
{