Add variable assignment

This commit is contained in:
Elara 2023-10-31 13:45:00 -07:00
parent ee4aa95dc3
commit 236e178cea
6 changed files with 460 additions and 260 deletions

View File

@ -90,6 +90,16 @@ func (e Expr) Pos() Position {
return e.Position return e.Position
} }
type Assignment struct {
Name Ident
Value Node
Position Position
}
func (a Assignment) Pos() Position {
return a.Position
}
type FuncCall struct { type FuncCall struct {
Name Ident Name Ident
Params []Node Params []Node

View File

@ -33,7 +33,7 @@ var (
type includeTag struct{} type includeTag struct{}
func (it includeTag) Run(tc *TagContext, block, args []ast.Node) error { func (it includeTag) Run(tc *TagContext, block, args []ast.Node) error {
if len(args) != 1 { if len(args) < 1 {
return ErrIncludeInvalidArgs return ErrIncludeInvalidArgs
} }
@ -52,5 +52,22 @@ func (it includeTag) Run(tc *TagContext, block, args []ast.Node) error {
return ErrNoSuchTemplate return ErrNoSuchTemplate
} }
return tc.Execute(tmpl.ast, nil) local := map[string]any{}
// Use the variable assignments after the first argument
// to set the local variables of the execution
for _, arg := range args[1:] {
if a, ok := arg.(ast.Assignment); ok {
val, err := tc.GetValue(a.Value, local)
if err != nil {
return err
}
local[a.Name.Value] = val
} else {
// If the argument isn't an assigment, return invalid args
return ErrIncludeInvalidArgs
}
}
return tc.Execute(tmpl.ast, local)
} }

View File

@ -7,7 +7,7 @@ import (
) )
var ( var (
ErrMacroInvalidArgs = errors.New("macro expects one string argument") ErrMacroInvalidArgs = errors.New("macro expects one string argument followed by variable assignments")
ErrNoSuchMacro = errors.New("no such template") ErrNoSuchMacro = errors.New("no such template")
) )
@ -15,7 +15,7 @@ var (
type macroTag struct{} type macroTag struct{}
func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error { func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error {
if len(args) != 1 { if len(args) < 1 {
return ErrMacroInvalidArgs return ErrMacroInvalidArgs
} }
@ -30,11 +30,28 @@ func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error {
} }
if len(block) == 0 { if len(block) == 0 {
local := map[string]any{}
// Use the variable assignments after the first argument
// to set the local variables of the execution
for _, arg := range args[1:] {
if a, ok := arg.(ast.Assignment); ok {
val, err := tc.GetValue(a.Value, local)
if err != nil {
return err
}
local[a.Name.Value] = val
} else {
// If the argument isn't an assigment, return invalid args
return ErrMacroInvalidArgs
}
}
macro, ok := tc.t.macros[name] macro, ok := tc.t.macros[name]
if !ok { if !ok {
return ErrNoSuchMacro return ErrNoSuchMacro
} }
return tc.Execute(macro, nil) return tc.Execute(macro, local)
} else { } else {
tc.t.macros[name] = block tc.t.macros[name] = block
} }

File diff suppressed because it is too large Load Diff

View File

@ -99,7 +99,8 @@ ExprTag = "#(" item:Expr ')' {
}, nil }, nil
} }
Expr = Ternary / LogicalExpr Expr = Ternary / Assignment / LogicalExpr
Assignable = Ternary / LogicalExpr
LogicalExpr = _ first:ComparisonExpr rest:(_ LogicalOp _ ComparisonExpr)* _ { LogicalExpr = _ first:ComparisonExpr rest:(_ LogicalOp _ ComparisonExpr)* _ {
return toExpr(c, first, rest), nil return toExpr(c, first, rest), nil
@ -138,14 +139,22 @@ Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / F
}, nil }, nil
} }
VariableOr = variable:Ident _ '|' _ or:Expr { VariableOr = variable:Ident _ '|' _ or:Assignable {
return ast.VariableOr{ return ast.VariableOr{
Variable: variable.(ast.Ident), Variable: variable.(ast.Ident),
Or: or.(ast.Node), Or: or.(ast.Node),
}, nil }, nil
} }
Ternary = cond:Expr _ '?' _ ifTrue:Value _ ':' _ elseVal:Value { Assignment = name:Ident _ '=' _ value:Assignable {
return ast.Assignment{
Name: name.(ast.Ident),
Value: value.(ast.Node),
Position: getPos(c),
}, nil
}
Ternary = cond:Assignable _ '?' _ ifTrue:Value _ ':' _ elseVal:Value {
return ast.Ternary{ return ast.Ternary{
Condition: cond.(ast.Node), Condition: cond.(ast.Node),
IfTrue: ifTrue.(ast.Node), IfTrue: ifTrue.(ast.Node),

View File

@ -24,7 +24,6 @@ import (
"html" "html"
"io" "io"
"reflect" "reflect"
"sync"
"go.elara.ws/salix/ast" "go.elara.ws/salix/ast"
) )
@ -126,6 +125,9 @@ func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any)
if err != nil { if err != nil {
return err return err
} }
if _, ok := v.(ast.Assignment); ok {
continue
}
_, err = io.WriteString(w, t.toString(v)) _, err = io.WriteString(w, t.toString(v))
if err != nil { if err != nil {
return err return err
@ -210,6 +212,8 @@ func (t *Template) getValue(node ast.Node, local map[string]any) (any, error) {
return t.evalTernary(node, local) return t.evalTernary(node, local)
case ast.VariableOr: case ast.VariableOr:
return t.evalVariableOr(node, local) return t.evalVariableOr(node, local)
case ast.Assignment:
return node, t.handleAssignment(node, local)
default: default:
return nil, nil return nil, nil
} }
@ -398,6 +402,9 @@ func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, lo
params := make([]reflect.Value, fnType.NumIn()) params := make([]reflect.Value, fnType.NumIn())
for i, arg := range args { for i, arg := range args {
if _, ok := arg.(ast.Assignment); ok {
return nil, t.posError(arg, "assignment cannot be used as a function argument")
}
paramVal, err := t.getValue(arg, local) paramVal, err := t.getValue(arg, local)
if err != nil { if err != nil {
return nil, err return nil, err
@ -448,6 +455,15 @@ func (t *Template) evalVariableOr(vo ast.VariableOr, local map[string]any) (any,
return val.Interface(), nil return val.Interface(), nil
} }
func (t *Template) handleAssignment(a ast.Assignment, local map[string]any) error {
val, err := t.getValue(a.Value, local)
if err != nil {
return err
}
local[a.Name.Value] = val
return nil
}
func (t *Template) posError(n ast.Node, format string, v ...any) error { func (t *Template) posError(n ast.Node, format string, v ...any) error {
return ast.PosError(n, t.name, format, v...) return ast.PosError(n, t.name, format, v...)
} }