Added support for assignments
All checks were successful
Test / build (push) Successful in 1m1s

This commit is contained in:
Leon Mika 2025-05-18 07:20:52 +10:00
parent 0f1ceba090
commit 51e35aa9a6
3 changed files with 66 additions and 14 deletions

View file

@ -103,9 +103,10 @@ type astDot struct {
} }
type astCmd struct { type astCmd struct {
Pos lexer.Position Pos lexer.Position
Name astDot `parser:"@@"` Name astDot `parser:"@@"`
Args []astDot `parser:"@@*"` Assign *astDot `parser:"( EQ @@"`
InvokeArgs []astDot `parser:" | @@+ )?"`
} }
type astPipeline struct { type astPipeline struct {
@ -141,6 +142,7 @@ var scanner = lexer.MustStateful(lexer.Rules{
{"RC", `\}`, nil}, {"RC", `\}`, nil},
{"NL", `[;\n][; \n\t]*`, nil}, {"NL", `[;\n][; \n\t]*`, nil},
{"PIPE", `\|`, nil}, {"PIPE", `\|`, nil},
{"EQ", `=`, nil},
{"Ident", `[-]*[a-zA-Z_][\w-!?]*`, nil}, {"Ident", `[-]*[a-zA-Z_][\w-!?]*`, nil},
}, },
"String": { "String": {

View file

@ -72,6 +72,14 @@ 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) { func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, currentPipe Object, ast *astCmd) (Object, error) {
switch { switch {
case ast.Assign != nil:
// Assignment
assignVal, err := e.evalDot(ctx, ec, *ast.Assign)
if err != nil {
return nil, err
}
return e.assignDot(ctx, ec, ast.Assign, assignVal)
case (ast.Name.Arg.Ident != nil) && len(ast.Name.DotSuffix) == 0: case (ast.Name.Arg.Ident != nil) && len(ast.Name.DotSuffix) == 0:
name := ast.Name.Arg.Ident.String() name := ast.Name.Arg.Ident.String()
@ -85,7 +93,7 @@ func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, currentPipe Object,
} else { } else {
return nil, errors.New("unknown command: " + name) return nil, errors.New("unknown command: " + name)
} }
case len(ast.Args) > 0: case len(ast.InvokeArgs) > 0:
nameElem, err := e.evalDot(ctx, ec, ast.Name) nameElem, err := e.evalDot(ctx, ec, ast.Name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -117,7 +125,7 @@ func (e evaluator) evalInvokable(ctx context.Context, ec *evalCtx, currentPipe O
if currentPipe != nil { if currentPipe != nil {
argsPtr.Append(currentPipe) argsPtr.Append(currentPipe)
} }
for _, arg := range ast.Args { for _, arg := range ast.InvokeArgs {
if ident := arg.Arg.Ident; len(arg.DotSuffix) == 0 && ident != nil && ident.String()[0] == '-' { if ident := arg.Arg.Ident; len(arg.DotSuffix) == 0 && ident != nil && ident.String()[0] == '-' {
// Arg switch // Arg switch
if kwargs == nil { if kwargs == nil {
@ -176,6 +184,14 @@ func (e evaluator) evalDot(ctx context.Context, ec *evalCtx, n astDot) (Object,
return res, nil return res, nil
} }
func (e evaluator) assignDot(ctx context.Context, ec *evalCtx, n *astDot, toVal Object) (Object, error) {
if len(n.DotSuffix) == 0 {
return e.assignArg(ctx, ec, n.Arg, toVal)
}
panic("TODO")
}
func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Object, error) { func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Object, error) {
switch { switch {
case n.Literal != nil: case n.Literal != nil:
@ -211,6 +227,40 @@ func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Objec
return nil, errors.New("unhandled arg type") return nil, errors.New("unhandled arg type")
} }
func (e evaluator) assignArg(ctx context.Context, ec *evalCtx, n astCmdArg, toVal Object) (Object, error) {
switch {
case n.Literal != nil:
// We may use this for variable setting?
return nil, errors.New("cannot assign to a literal")
case n.Var != nil:
ec.setOrDefineVar(*n.Var, toVal)
return toVal, nil
case n.PseudoVar != nil:
pvar, ok := ec.getPseudoVar(*n.PseudoVar)
if ok {
if err := pvar.set(ctx, *n.PseudoVar, toVal); err != nil {
return nil, err
}
return toVal, nil
}
if pvar := e.inst.missingPseudoVarHandler; pvar != nil {
if err := pvar.set(ctx, *n.PseudoVar, toVal); err != nil {
return nil, err
}
return toVal, nil
}
return nil, errors.New("unknown pseudo-variable: " + *n.Var)
case n.MaybeSub != nil:
return nil, errors.New("cannot assign to a subexpression")
case n.ListOrHash != nil:
return nil, errors.New("cannot assign to a list or hash")
case n.Block != nil:
return nil, errors.New("cannot assign to a block")
}
return nil, errors.New("unhandled arg type")
}
func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astListOrHash) (Object, error) { func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astListOrHash) (Object, error) {
if loh.EmptyList { if loh.EmptyList {
return &ListObject{}, nil return &ListObject{}, nil

View file

@ -279,7 +279,7 @@ type macroArgs struct {
} }
func (ma macroArgs) nargs() int { func (ma macroArgs) nargs() int {
return len(ma.ast.Args[ma.argShift:]) return len(ma.ast.InvokeArgs[ma.argShift:])
} }
func (ma *macroArgs) shift(n int) { func (ma *macroArgs) shift(n int) {
@ -287,15 +287,15 @@ func (ma *macroArgs) shift(n int) {
} }
func (ma macroArgs) identIs(ctx context.Context, n int, expectedIdent string) bool { func (ma macroArgs) identIs(ctx context.Context, n int, expectedIdent string) bool {
if n >= len(ma.ast.Args[ma.argShift:]) { if n >= len(ma.ast.InvokeArgs[ma.argShift:]) {
return false return false
} }
if len(ma.ast.Args[ma.argShift+n].DotSuffix) != 0 { if len(ma.ast.InvokeArgs[ma.argShift+n].DotSuffix) != 0 {
return false return false
} }
lit := ma.ast.Args[ma.argShift+n].Arg.Ident lit := ma.ast.InvokeArgs[ma.argShift+n].Arg.Ident
if lit == nil { if lit == nil {
return false return false
} }
@ -304,15 +304,15 @@ func (ma macroArgs) identIs(ctx context.Context, n int, expectedIdent string) bo
} }
func (ma *macroArgs) shiftIdent(ctx context.Context) (string, bool) { func (ma *macroArgs) shiftIdent(ctx context.Context) (string, bool) {
if ma.argShift >= len(ma.ast.Args) { if ma.argShift >= len(ma.ast.InvokeArgs) {
return "", false return "", false
} }
if len(ma.ast.Args[ma.argShift].DotSuffix) != 0 { if len(ma.ast.InvokeArgs[ma.argShift].DotSuffix) != 0 {
return "", false return "", false
} }
lit := ma.ast.Args[ma.argShift].Arg.Ident lit := ma.ast.InvokeArgs[ma.argShift].Arg.Ident
if lit != nil { if lit != nil {
ma.argShift += 1 ma.argShift += 1
return lit.String(), true return lit.String(), true
@ -321,11 +321,11 @@ func (ma *macroArgs) shiftIdent(ctx context.Context) (string, bool) {
} }
func (ma macroArgs) evalArg(ctx context.Context, n int) (Object, error) { func (ma macroArgs) evalArg(ctx context.Context, n int) (Object, error) {
if n >= len(ma.ast.Args[ma.argShift:]) { if n >= len(ma.ast.InvokeArgs[ma.argShift:]) {
return nil, errors.New("not enough arguments") // FIX return nil, errors.New("not enough arguments") // FIX
} }
return ma.eval.evalDot(ctx, ma.ec, ma.ast.Args[ma.argShift+n]) return ma.eval.evalDot(ctx, ma.ec, ma.ast.InvokeArgs[ma.argShift+n])
} }
func (ma macroArgs) evalBlock(ctx context.Context, n int, args []Object, pushScope bool) (Object, error) { func (ma macroArgs) evalBlock(ctx context.Context, n int, args []Object, pushScope bool) (Object, error) {