Improve expression handling and add parentheses support
This commit is contained in:
parent
900de82d6a
commit
136e8cb26e
23
expr.go
23
expr.go
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
2
go.mod
@ -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
2
go.sum
@ -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=
|
@ -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
@ -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)}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprSegment = first:Value rest:(_ Operator _ Value)* {
|
ComparisonExpr = _ first:ArithmeticExpr rest:(_ ComparisonOp _ ArithmeticExpr)* _ {
|
||||||
restSlice := toAnySlice(rest)
|
return toExpr(c, first, rest), nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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
|
||||||
|
2
salix.go
2
salix.go
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user