Improve expression handling and add parentheses support

This commit is contained in:
Elara 2023-10-30 15:02:41 -07:00
parent 900de82d6a
commit 136e8cb26e
8 changed files with 583 additions and 416 deletions

23
expr.go
View File

@ -8,33 +8,14 @@ import (
) )
func (t *Template) evalExpr(expr ast.Expr, local map[string]any) (any, error) { func (t *Template) evalExpr(expr ast.Expr, local map[string]any) (any, error) {
val, err := t.getValue(expr.Segment, local) val, err := t.getValue(expr.First, local)
if err != nil { if err != nil {
return nil, err return nil, err
} }
a := reflect.ValueOf(val) a := reflect.ValueOf(val)
for _, exprB := range expr.Rest { for _, exprB := range expr.Rest {
val, err := t.getValue(exprB.Segment, local) val, err := t.getValue(exprB.First, local)
if err != nil {
return nil, err
}
b := reflect.ValueOf(val)
a = reflect.ValueOf(t.performOp(a, b, exprB.Logical))
}
return a.Interface(), nil
}
func (t *Template) evalExprSegment(expr ast.ExprSegment, local map[string]any) (any, error) {
val, err := t.getValue(expr.Value, local)
if err != nil {
return nil, err
}
a := reflect.ValueOf(val)
for _, exprB := range expr.Rest {
val, err := t.getValue(exprB.Value, local)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,15 +17,15 @@ func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
return ErrForTagInvalidArgs return ErrForTagInvalidArgs
} }
var expr ast.ExprSegment var expr ast.Expr
if len(args) == 1 { if len(args) == 1 {
expr2, ok := args[0].(ast.ExprSegment) expr2, ok := args[0].(ast.Expr)
if !ok { if !ok {
return ErrForTagInvalidArgs return ErrForTagInvalidArgs
} }
expr = expr2 expr = expr2
} else if len(args) == 2 { } else if len(args) == 2 {
expr2, ok := args[1].(ast.ExprSegment) expr2, ok := args[1].(ast.Expr)
if !ok { if !ok {
return ErrForTagInvalidArgs return ErrForTagInvalidArgs
} }
@ -44,7 +44,7 @@ func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
} }
varName, ok := unwrap(expr.Value).(ast.Ident) varName, ok := unwrap(expr.First).(ast.Ident)
if !ok { if !ok {
return ErrForTagInvalidArgs return ErrForTagInvalidArgs
} }

2
go.mod
View File

@ -1,3 +1,5 @@
module go.elara.ws/salix module go.elara.ws/salix
go 1.21.2 go 1.21.2
require github.com/davecgh/go-spew v1.1.1

2
go.sum
View File

@ -0,0 +1,2 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -63,8 +63,8 @@ type Value struct {
} }
type Expr struct { type Expr struct {
Segment Node First Node
Logical Logical Operator Operator
Rest []Expr Rest []Expr
Position Position Position Position
} }
@ -73,17 +73,6 @@ func (e Expr) Pos() Position {
return e.Position return e.Position
} }
type ExprSegment struct {
Value Node
Operator Operator
Rest []ExprSegment
Position Position
}
func (es ExprSegment) Pos() Position {
return es.Position
}
type FuncCall struct { type FuncCall struct {
Name Ident Name Ident
Params []Node Params []Node

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,25 @@ func getPos(c *current) ast.Position {
} }
} }
func toExpr(c *current, first, rest any) ast.Node {
restSlice := toAnySlice(rest)
if len(restSlice) == 0 {
return first.(ast.Node)
}
out := ast.Expr{First: first.(ast.Node), Position: getPos(c)}
for _, restValue := range restSlice {
valueSlice := toAnySlice(restValue)
out.Rest = append(out.Rest, ast.Expr{
Operator: valueSlice[1].(ast.Operator),
First: valueSlice[3].(ast.Node),
Position: valueSlice[3].(ast.Node).Pos(),
})
}
return out
}
} }
Root = items:(Tag / ExprTag / EndTag / Text)* { Root = items:(Tag / ExprTag / EndTag / Text)* {
@ -55,54 +74,32 @@ EndTag = "#!" name:Ident {
}, nil }, nil
} }
ExprTag = "#(" item:Item ')' { ExprTag = "#(" item:Expr ')' {
return ast.ExprTag{ return ast.ExprTag{
Value: item.(ast.Node), Value: item.(ast.Node),
Position: getPos(c), Position: getPos(c),
}, nil }, nil
} }
Item = Ternary / Expr Expr = Ternary / LogicalExpr
Expr = first:ExprSegment rest:(_ Logical _ ExprSegment)* { LogicalExpr = _ first:ComparisonExpr rest:(_ LogicalOp _ ComparisonExpr)* _ {
restSlice := toAnySlice(rest) return toExpr(c, first, rest), nil
if len(restSlice) == 0 {
return first, nil
} }
out := ast.Expr{Segment: first.(ast.Node), Position: getPos(c)} ComparisonExpr = _ first:ArithmeticExpr rest:(_ ComparisonOp _ ArithmeticExpr)* _ {
for _, restValue := range restSlice { return toExpr(c, first, rest), nil
valueSlice := toAnySlice(restValue)
out.Rest = append(out.Rest, ast.Expr{
Logical: valueSlice[1].(ast.Logical),
Segment: valueSlice[3].(ast.Node),
Position: valueSlice[3].(ast.Node).Pos(),
})
} }
return out, nil ArithmeticExpr = _ first:Value rest:(_ ArithmeticOp _ Value)* _ {
return toExpr(c, first, rest), nil
} }
ExprSegment = first:Value rest:(_ Operator _ Value)* { ParenExpr = '(' expr:Expr ')' {
restSlice := toAnySlice(rest) return expr, nil
if len(restSlice) == 0 {
return first, nil
} }
out := ast.ExprSegment{Value: first.(ast.Node), Position: getPos(c)} ParamList = '(' params:(Expr ( ',' _ Expr )* )? ')' {
for _, restValue := range restSlice {
valueSlice := toAnySlice(restValue)
out.Rest = append(out.Rest, ast.ExprSegment{
Operator: valueSlice[1].(ast.Operator),
Value: valueSlice[3].(ast.Node),
Position: valueSlice[3].(ast.Node).Pos(),
})
}
return out, nil
}
ParamList = '(' params:(Item ( ',' _ Item )* )? ')' {
paramSlice := toAnySlice(params) paramSlice := toAnySlice(params)
if len(paramSlice) == 0 { if len(paramSlice) == 0 {
return []ast.Node{}, nil return []ast.Node{}, nil
@ -116,7 +113,7 @@ ParamList = '(' params:(Item ( ',' _ Item )* )? ')' {
return out, nil return out, nil
} }
Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / Float / Integer / Bool / FuncCall / VariableOr / Ident) { Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / Float / Integer / Bool / FuncCall / VariableOr / Ident / ParenExpr) {
return ast.Value{ return ast.Value{
Node: node.(ast.Node), Node: node.(ast.Node),
Not: not != nil, Not: not != nil,
@ -218,15 +215,22 @@ Bool = ("true"i / "false"i) {
}, err }, err
} }
Operator = ("==" / "<=" / ">=" / "in"i / '<' / '>' / '+' / '-' / '/' / '*') { LogicalOp = ("||" / "&&") {
return ast.Operator{ return ast.Operator{
Value: string(c.text), Value: string(c.text),
Position: getPos(c), Position: getPos(c),
}, nil }, nil
} }
Logical = ("&&" / "||") { ComparisonOp = ("==" / "<=" / ">=" / '<' / '>' / "in"i) {
return ast.Logical{ return ast.Operator{
Value: string(c.text),
Position: getPos(c),
}, nil
}
ArithmeticOp = ('+' / '-' / '/' / '*' / '%') {
return ast.Operator{
Value: string(c.text), Value: string(c.text),
Position: getPos(c), Position: getPos(c),
}, nil }, nil

View File

@ -206,8 +206,6 @@ func (t *Template) getValue(node ast.Node, local map[string]any) (any, error) {
return node.Value, nil return node.Value, nil
case ast.Expr: case ast.Expr:
return t.evalExpr(node, local) return t.evalExpr(node, local)
case ast.ExprSegment:
return t.evalExprSegment(node, local)
case ast.FuncCall: case ast.FuncCall:
return t.execFuncCall(node, local) return t.execFuncCall(node, local)
case ast.Index: case ast.Index: