From 0dc9fd3c32818b2ff0e0ac26466ecee315c4a82e Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Sat, 4 May 2024 11:35:31 +1000 Subject: [PATCH] Fixed the issue with colons in ident --- ucl/ast.go | 23 ++++++++++++++++------- ucl/builtins.go | 19 +++++++++---------- ucl/eval.go | 8 ++++---- ucl/objs.go | 4 ++-- ucl/testbuiltins_test.go | 8 ++++---- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/ucl/ast.go b/ucl/ast.go index 79e9569..ab620a5 100644 --- a/ucl/ast.go +++ b/ucl/ast.go @@ -2,6 +2,7 @@ package ucl import ( "io" + "strings" "github.com/alecthomas/participle/v2" "github.com/alecthomas/participle/v2/lexer" @@ -12,11 +13,19 @@ type astLiteral struct { Int *int `parser:"| @Int"` } -type astHashKey struct { - Literal *astLiteral `parser:"@@"` - Ident *string `parser:"| @Ident"` - Var *string `parser:"| DOLLAR @Ident"` - Sub *astPipeline `parser:"| LP @@ RP"` +type astIdentNames struct { + Ident string `parser:"@Ident"` + ColonParts []string `parser:"( COLON @Ident )*"` +} + +func (ai *astIdentNames) String() string { + sb := strings.Builder{} + sb.WriteString(ai.Ident) + for _, p := range ai.ColonParts { + sb.WriteRune(':') + sb.WriteString(p) + } + return sb.String() } type astElementPair struct { @@ -41,7 +50,7 @@ type astMaybeSub struct { type astCmdArg struct { Literal *astLiteral `parser:"@@"` - Ident *string `parser:"| @Ident"` + Ident *astIdentNames `parser:"| @@"` Var *string `parser:"| DOLLAR @Ident"` MaybeSub *astMaybeSub `parser:"| LP @@ RP"` ListOrHash *astListOrHash `parser:"| @@"` @@ -83,7 +92,7 @@ var scanner = lexer.MustStateful(lexer.Rules{ {"RC", `\}`, nil}, {"NL", `[;\n][; \n\t]*`, nil}, {"PIPE", `\|`, nil}, - {"Ident", `[-]*[a-zA-Z_:][\w-:]*`, nil}, + {"Ident", `[-]*[a-zA-Z_][\w-]*`, nil}, }, }) var parser = participle.MustBuild[astScript](participle.Lexer(scanner), diff --git a/ucl/builtins.go b/ucl/builtins.go index a9ad5f0..b934f5e 100644 --- a/ucl/builtins.go +++ b/ucl/builtins.go @@ -334,18 +334,17 @@ func foreachBuiltin(ctx context.Context, args macroArgs) (object, error) { } } } - case hashObject: - for k, v := range t { + case hashable: + err := t.Each(func(k string, v object) error { last, err = args.evalBlock(ctx, blockIdx, []object{strObject(k), v}, true) - if err != nil { - if errors.As(err, &breakErr) { - if !breakErr.isCont { - return breakErr.ret, nil - } - } else { - return nil, err - } + return err + }) + if errors.As(err, &breakErr) { + if !breakErr.isCont { + return breakErr.ret, nil } + } else { + return nil, err } } diff --git a/ucl/eval.go b/ucl/eval.go index 56e8ce0..33f5157 100644 --- a/ucl/eval.go +++ b/ucl/eval.go @@ -72,7 +72,7 @@ func (e evaluator) evalPipeline(ctx context.Context, ec *evalCtx, n *astPipeline func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, currentPipe object, ast *astCmd) (object, error) { switch { case ast.Name.Ident != nil: - name := *ast.Name.Ident + name := ast.Name.Ident.String() // Regular command if cmd := ec.lookupInvokable(name); cmd != nil { @@ -117,14 +117,14 @@ func (e evaluator) evalInvokable(ctx context.Context, ec *evalCtx, currentPipe o argsPtr.Append(currentPipe) } for _, arg := range ast.Args { - if ident := arg.Ident; ident != nil && (*ident)[0] == '-' { + if ident := arg.Ident; ident != nil && ident.String()[0] == '-' { // Arg switch if kwargs == nil { kwargs = make(map[string]*listObject) } argsPtr = &listObject{} - kwargs[(*ident)[1:]] = argsPtr + kwargs[ident.String()[1:]] = argsPtr } else { ae, err := e.evalArg(ctx, ec, arg) if err != nil { @@ -153,7 +153,7 @@ func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (objec case n.Literal != nil: return e.evalLiteral(ctx, ec, n.Literal) case n.Ident != nil: - return strObject(*n.Ident), nil + return strObject(n.Ident.String()), nil case n.Var != nil: if v, ok := ec.getVar(*n.Var); ok { return v, nil diff --git a/ucl/objs.go b/ucl/objs.go index 3d3373d..5a73720 100644 --- a/ucl/objs.go +++ b/ucl/objs.go @@ -194,7 +194,7 @@ func (ma macroArgs) identIs(ctx context.Context, n int, expectedIdent string) bo return false } - return *lit == expectedIdent + return lit.String() == expectedIdent } func (ma *macroArgs) shiftIdent(ctx context.Context) (string, bool) { @@ -205,7 +205,7 @@ func (ma *macroArgs) shiftIdent(ctx context.Context) (string, bool) { lit := ma.ast.Args[ma.argShift].Ident if lit != nil { ma.argShift += 1 - return *lit, true + return lit.String(), true } return "", false } diff --git a/ucl/testbuiltins_test.go b/ucl/testbuiltins_test.go index 10a16ab..ede1137 100644 --- a/ucl/testbuiltins_test.go +++ b/ucl/testbuiltins_test.go @@ -465,20 +465,20 @@ func TestBuiltins_Map(t *testing.T) { proc makeUpper { |x| $x | toUpper } map ["a" "b" "c"] (proc { |x| makeUpper $x }) - `, want: "[A B C]\n"}, + `, want: "A\nB\nC\n"}, {desc: "map list 2", expr: ` set makeUpper (proc { |x| $x | toUpper }) map ["a" "b" "c"] $makeUpper - `, want: "[A B C]\n"}, + `, want: "A\nB\nC\n"}, {desc: "map list with pipe", expr: ` set makeUpper (proc { |x| $x | toUpper }) ["a" "b" "c"] | map $makeUpper - `, want: "[A B C]\n"}, + `, want: "A\nB\nC\n"}, {desc: "map list with block", expr: ` map ["a" "b" "c"] { |x| toUpper $x } - `, want: "[A B C]\n"}, + `, want: "A\nB\nC\n"}, {desc: "map list with stream", expr: ` set makeUpper (proc { |x| toUpper $x })