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
|
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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
23
macro_tag.go
23
macro_tag.go
@ -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
|
||||||
}
|
}
|
||||||
|
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
|
}, 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),
|
||||||
|
18
salix.go
18
salix.go
@ -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...)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user