Add variable assignment
This commit is contained in:
parent
ee4aa95dc3
commit
236e178cea
10
ast/ast.go
10
ast/ast.go
@ -90,6 +90,16 @@ func (e Expr) Pos() Position {
|
||||
return e.Position
|
||||
}
|
||||
|
||||
type Assignment struct {
|
||||
Name Ident
|
||||
Value Node
|
||||
Position Position
|
||||
}
|
||||
|
||||
func (a Assignment) Pos() Position {
|
||||
return a.Position
|
||||
}
|
||||
|
||||
type FuncCall struct {
|
||||
Name Ident
|
||||
Params []Node
|
||||
|
@ -33,7 +33,7 @@ var (
|
||||
type includeTag struct{}
|
||||
|
||||
func (it includeTag) Run(tc *TagContext, block, args []ast.Node) error {
|
||||
if len(args) != 1 {
|
||||
if len(args) < 1 {
|
||||
return ErrIncludeInvalidArgs
|
||||
}
|
||||
|
||||
@ -52,5 +52,22 @@ func (it includeTag) Run(tc *TagContext, block, args []ast.Node) error {
|
||||
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)
|
||||
}
|
||||
|
23
macro_tag.go
23
macro_tag.go
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
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")
|
||||
)
|
||||
|
||||
@ -15,7 +15,7 @@ var (
|
||||
type macroTag struct{}
|
||||
|
||||
func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error {
|
||||
if len(args) != 1 {
|
||||
if len(args) < 1 {
|
||||
return ErrMacroInvalidArgs
|
||||
}
|
||||
|
||||
@ -30,11 +30,28 @@ func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error {
|
||||
}
|
||||
|
||||
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]
|
||||
if !ok {
|
||||
return ErrNoSuchMacro
|
||||
}
|
||||
return tc.Execute(macro, nil)
|
||||
return tc.Execute(macro, local)
|
||||
} else {
|
||||
tc.t.macros[name] = block
|
||||
}
|
||||
|
633
parser/parser.go
633
parser/parser.go
File diff suppressed because it is too large
Load Diff
@ -99,7 +99,8 @@ ExprTag = "#(" item:Expr ')' {
|
||||
}, nil
|
||||
}
|
||||
|
||||
Expr = Ternary / LogicalExpr
|
||||
Expr = Ternary / Assignment / LogicalExpr
|
||||
Assignable = Ternary / LogicalExpr
|
||||
|
||||
LogicalExpr = _ first:ComparisonExpr rest:(_ LogicalOp _ ComparisonExpr)* _ {
|
||||
return toExpr(c, first, rest), nil
|
||||
@ -138,14 +139,22 @@ Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / F
|
||||
}, nil
|
||||
}
|
||||
|
||||
VariableOr = variable:Ident _ '|' _ or:Expr {
|
||||
VariableOr = variable:Ident _ '|' _ or:Assignable {
|
||||
return ast.VariableOr{
|
||||
Variable: variable.(ast.Ident),
|
||||
Or: or.(ast.Node),
|
||||
}, 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{
|
||||
Condition: cond.(ast.Node),
|
||||
IfTrue: ifTrue.(ast.Node),
|
||||
|
18
salix.go
18
salix.go
@ -24,7 +24,6 @@ import (
|
||||
"html"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"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 {
|
||||
return err
|
||||
}
|
||||
if _, ok := v.(ast.Assignment); ok {
|
||||
continue
|
||||
}
|
||||
_, err = io.WriteString(w, t.toString(v))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -210,6 +212,8 @@ func (t *Template) getValue(node ast.Node, local map[string]any) (any, error) {
|
||||
return t.evalTernary(node, local)
|
||||
case ast.VariableOr:
|
||||
return t.evalVariableOr(node, local)
|
||||
case ast.Assignment:
|
||||
return node, t.handleAssignment(node, local)
|
||||
default:
|
||||
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())
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -448,6 +455,15 @@ func (t *Template) evalVariableOr(vo ast.VariableOr, local map[string]any) (any,
|
||||
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 {
|
||||
return ast.PosError(n, t.name, format, v...)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user