diff --git a/lang/interpret_test/TestAstFunc2/lexer-parser0.txtar b/lang/interpret_test/TestAstFunc2/lexer-parser0.txtar index eaf4aed5bc..8e60e5fa23 100644 --- a/lang/interpret_test/TestAstFunc2/lexer-parser0.txtar +++ b/lang/interpret_test/TestAstFunc2/lexer-parser0.txtar @@ -1,16 +1,16 @@ -- main.mcl -- import "fmt" -# unfortunately, for now `in` is a reserved keyword, see: -# https://github.com/purpleidea/mgmt/issues/728 $map = 55 -$fn = func($in) { # in is a special keyword +# in is a special keyword, but accepted in a variable name +$fn = func($in) { 13 } test fmt.printf("%d", $fn(0)) {} -func fn($in) { # in is a special keyword +func fn($in) { 42 + $map } test fmt.printf("%d", $fn(0)) {} test fmt.printf("%d", fn(0)) {} -- OUTPUT -- -# err: errLexParse: parser: `syntax error: unexpected IN, expecting MAP_IDENTIFIER or IDENTIFIER` @5:2 +Vertex: test[13] +Vertex: test[97] diff --git a/lang/parser/lexer.nex b/lang/parser/lexer.nex index b0f1a9b7cd..73ac3273fb 100644 --- a/lang/parser/lexer.nex +++ b/lang/parser/lexer.nex @@ -159,6 +159,15 @@ lval.str = yylex.Text() return ARROW } +/\$[a-z0-9_\.]+/ { + yylex.pos(lval) // our pos + // drop the dollar sign + lval.str = strings.TrimLeft(yylex.Text(), "$") + if strings.Contains(lval.str, ".") { + return DOTTED_VARNAME + } + return UNDOTTED_VARNAME + } /\./ { yylex.pos(lval) // our pos lval.str = yylex.Text() @@ -168,11 +177,7 @@ } return DOT } -/\$/ { - yylex.pos(lval) // our pos - lval.str = yylex.Text() - return DOLLAR - } + /bool/ { yylex.pos(lval) // our pos lval.str = yylex.Text() diff --git a/lang/parser/lexparse.go b/lang/parser/lexparse.go index 892afad256..542db4a3a1 100644 --- a/lang/parser/lexparse.go +++ b/lang/parser/lexparse.go @@ -54,6 +54,7 @@ const ( ErrParseError = interfaces.Error("parser") ErrParseSetType = interfaces.Error("can't set return type in parser") ErrParseResFieldInvalid = interfaces.Error("can't use unknown resource field") + ErrInvalidVariableName = interfaces.Error("invalid variable name") ErrParseAdditionalEquals = interfaces.Error(errstrParseAdditionalEquals) ErrParseExpectingComma = interfaces.Error(errstrParseExpectingComma) ) diff --git a/lang/parser/parser.y b/lang/parser/parser.y index 057d2a5fa8..cdb9a29374 100644 --- a/lang/parser/parser.y +++ b/lang/parser/parser.y @@ -93,7 +93,8 @@ func init() { %token OPEN_BRACK CLOSE_BRACK %token IF ELSE %token BOOL STRING INTEGER FLOAT -%token EQUALS DOLLAR +%token EQUALS DOTTED_VARNAME +%token UNDOTTED_VARNAME %token COMMA COLON SEMICOLON %token ELVIS DEFAULT ROCKET ARROW DOT %token BOOL_IDENTIFIER STR_IDENTIFIER INT_IDENTIFIER FLOAT_IDENTIFIER @@ -1406,11 +1407,13 @@ undotted_identifier: } ; var_identifier: - // eg: $ foo (dollar prefix + identifier) - DOLLAR undotted_identifier + UNDOTTED_VARNAME { posLast(yylex, yyDollar) // our pos - $$.str = $2.str // don't include the leading $ + if $1.str == "" || strings.HasPrefix($1.str, "_") || strings.HasSuffix($1.str, "_") { + yylex.Error(fmt.Sprintf("%s: %s", ErrInvalidVariableName, $1.str)) + } + $$.str = $1.str } ; colon_identifier: @@ -1439,13 +1442,24 @@ dotted_identifier: $$.str = $1.str + interfaces.ModuleSep + $3.str } ; -// there are different ways the lexer/parser might choose to represent this... dotted_var_identifier: - // eg: $ foo.bar.baz (dollar prefix + dotted identifier) - DOLLAR dotted_identifier + DOTTED_VARNAME + { + posLast(yylex, yyDollar) // our pos + for _, ident := range strings.Split($1.str, ".") { + if ident == "" || strings.HasPrefix(ident, "_") || strings.HasSuffix(ident, "_") { + yylex.Error(fmt.Sprintf("%s: %s", ErrInvalidVariableName, $1.str)) + } + } + $$.str = $1.str + } +| UNDOTTED_VARNAME { posLast(yylex, yyDollar) // our pos - $$.str = $2.str // don't include the leading $ + if $1.str == "" || strings.HasPrefix($1.str, "_") || strings.HasSuffix($1.str, "_") { + yylex.Error(fmt.Sprintf("%s: %s", ErrInvalidVariableName, $1.str)) + } + $$.str = $1.str } ; capitalized_res_identifier: