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) {
val, err := t.getValue(expr.Segment, local)
val, err := t.getValue(expr.First, local)
if err != nil {
return nil, err
}
a := reflect.ValueOf(val)
for _, exprB := range expr.Rest {
val, err := t.getValue(exprB.Segment, 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)
val, err := t.getValue(exprB.First, local)
if err != nil {
return nil, err
}

View File

@ -17,15 +17,15 @@ func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
return ErrForTagInvalidArgs
}
var expr ast.ExprSegment
var expr ast.Expr
if len(args) == 1 {
expr2, ok := args[0].(ast.ExprSegment)
expr2, ok := args[0].(ast.Expr)
if !ok {
return ErrForTagInvalidArgs
}
expr = expr2
} else if len(args) == 2 {
expr2, ok := args[1].(ast.ExprSegment)
expr2, ok := args[1].(ast.Expr)
if !ok {
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 {
return ErrForTagInvalidArgs
}

2
go.mod
View File

@ -1,3 +1,5 @@
module go.elara.ws/salix
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 {
Segment Node
Logical Logical
First Node
Operator Operator
Rest []Expr
Position Position
}
@ -73,17 +73,6 @@ func (e Expr) Pos() 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 {
Name Ident
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)* {
@ -55,54 +74,32 @@ EndTag = "#!" name:Ident {
}, nil
}
ExprTag = "#(" item:Item ')' {
ExprTag = "#(" item:Expr ')' {
return ast.ExprTag{
Value: item.(ast.Node),
Position: getPos(c),
}, nil
}
Item = Ternary / Expr
Expr = Ternary / LogicalExpr
Expr = first:ExprSegment rest:(_ Logical _ ExprSegment)* {
restSlice := toAnySlice(rest)
if len(restSlice) == 0 {
return first, nil
}
out := ast.Expr{Segment: first.(ast.Node), Position: getPos(c)}
for _, restValue := range restSlice {
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
LogicalExpr = _ first:ComparisonExpr rest:(_ LogicalOp _ ComparisonExpr)* _ {
return toExpr(c, first, rest), nil
}
ExprSegment = first:Value rest:(_ Operator _ Value)* {
restSlice := toAnySlice(rest)
if len(restSlice) == 0 {
return first, nil
}
out := ast.ExprSegment{Value: first.(ast.Node), Position: getPos(c)}
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
ComparisonExpr = _ first:ArithmeticExpr rest:(_ ComparisonOp _ ArithmeticExpr)* _ {
return toExpr(c, first, rest), nil
}
ParamList = '(' params:(Item ( ',' _ Item )* )? ')' {
ArithmeticExpr = _ first:Value rest:(_ ArithmeticOp _ Value)* _ {
return toExpr(c, first, rest), nil
}
ParenExpr = '(' expr:Expr ')' {
return expr, nil
}
ParamList = '(' params:(Expr ( ',' _ Expr )* )? ')' {
paramSlice := toAnySlice(params)
if len(paramSlice) == 0 {
return []ast.Node{}, nil
@ -116,7 +113,7 @@ ParamList = '(' params:(Item ( ',' _ Item )* )? ')' {
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{
Node: node.(ast.Node),
Not: not != nil,
@ -218,15 +215,22 @@ Bool = ("true"i / "false"i) {
}, err
}
Operator = ("==" / "<=" / ">=" / "in"i / '<' / '>' / '+' / '-' / '/' / '*') {
LogicalOp = ("||" / "&&") {
return ast.Operator{
Value: string(c.text),
Position: getPos(c),
}, nil
}
Logical = ("&&" / "||") {
return ast.Logical{
ComparisonOp = ("==" / "<=" / ">=" / '<' / '>' / "in"i) {
return ast.Operator{
Value: string(c.text),
Position: getPos(c),
}, nil
}
ArithmeticOp = ('+' / '-' / '/' / '*' / '%') {
return ast.Operator{
Value: string(c.text),
Position: getPos(c),
}, nil

View File

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