Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve issue with variable names like $in or $struct #748

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions lang/interpret_test/TestAstFunc2/lexer-parser0.txtar
Original file line number Diff line number Diff line change
@@ -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]
15 changes: 10 additions & 5 deletions lang/parser/lexer.nex
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down
1 change: 1 addition & 0 deletions lang/parser/lexparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
Expand Down
29 changes: 21 additions & 8 deletions lang/parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func init() {
%token OPEN_BRACK CLOSE_BRACK
%token IF ELSE
%token BOOL STRING INTEGER FLOAT
%token EQUALS DOLLAR
%token EQUALS DOTTED_VARNAME UNDOTTED_VARNAME
%token COMMA COLON SEMICOLON
%token ELVIS DEFAULT ROCKET ARROW DOT
%token BOOL_IDENTIFIER STR_IDENTIFIER INT_IDENTIFIER FLOAT_IDENTIFIER
Expand Down Expand Up @@ -1406,11 +1406,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:
Expand Down Expand Up @@ -1439,13 +1441,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:
Expand Down
3 changes: 2 additions & 1 deletion test/test-vet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ function parser-indentation() {
fi
# indent the pipe too (no spaces!)
# skip over any lines with leading comments
# or boolean or '||'
# the $ before the \t magically makes grep match the tab somehow...
if grep ' |' "$1" | grep -v '^['$'\t'']*// '; then
if grep ' |' "$1" | grep -v '^['$'\t'']*// ' | grep -v '||'; then
return 1
fi
if grep '^ ' "$1"; then # format with tabs, no leading spaces
Expand Down
Loading