Add ternary expressions
This commit is contained in:
parent
9d44c8d02c
commit
c1a2e56f4f
@ -10,10 +10,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-menu" id="navbarMenu">
|
<div class="navbar-menu" id="navbarMenu">
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<a class='navbar-item #if(title == "Home"):is-active#!if' href="/">
|
<a class='navbar-item #(title == "Home" ? "is-active" : "")' href="/">
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
<a class='navbar-item #if(title == "About"):is-active#!if' href="/about">
|
<a class='navbar-item #(title == "About" ? "is-active" : "")' href="/about">
|
||||||
About
|
About
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,3 +199,14 @@ func (l Logical) Pos() Position {
|
|||||||
func (l Logical) Op() string {
|
func (l Logical) Op() string {
|
||||||
return l.Value
|
return l.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Ternary struct {
|
||||||
|
Condition Node
|
||||||
|
IfTrue Node
|
||||||
|
Else Node
|
||||||
|
Position Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Ternary) Pos() Position {
|
||||||
|
return t.Position
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -55,13 +55,15 @@ EndTag = "#!" name:Ident {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprTag = "#(" expr:Expr ')' {
|
ExprTag = "#(" item:Item ')' {
|
||||||
return ast.ExprTag{
|
return ast.ExprTag{
|
||||||
Value: expr.(ast.Node),
|
Value: item.(ast.Node),
|
||||||
Position: getPos(c),
|
Position: getPos(c),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item = Ternary / Expr
|
||||||
|
|
||||||
Expr = first:ExprSegment rest:(_ Logical _ ExprSegment)* {
|
Expr = first:ExprSegment rest:(_ Logical _ ExprSegment)* {
|
||||||
restSlice := toAnySlice(rest)
|
restSlice := toAnySlice(rest)
|
||||||
if len(restSlice) == 0 {
|
if len(restSlice) == 0 {
|
||||||
@ -100,7 +102,7 @@ ExprSegment = first:Value rest:(_ Operator _ Value)* {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamList = '(' params:(Expr ( ',' _ Expr )* )? ')' {
|
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
|
||||||
@ -121,6 +123,14 @@ Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / F
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ternary = cond:Expr _ '?' _ ifTrue:Value _ ':' _ elseVal:Value {
|
||||||
|
return ast.Ternary{
|
||||||
|
Condition: cond.(ast.Node),
|
||||||
|
IfTrue: ifTrue.(ast.Node),
|
||||||
|
Else: elseVal.(ast.Node),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
MethodCall = value:Value '.' name:Ident params:ParamList {
|
MethodCall = value:Value '.' name:Ident params:ParamList {
|
||||||
return ast.MethodCall{
|
return ast.MethodCall{
|
||||||
Value: value.(ast.Node),
|
Value: value.(ast.Node),
|
||||||
|
21
salix.go
21
salix.go
@ -27,6 +27,7 @@ var (
|
|||||||
ErrFuncTooManyReturns = errors.New("template functions can only have two return values")
|
ErrFuncTooManyReturns = errors.New("template functions can only have two return values")
|
||||||
ErrFuncNoReturns = errors.New("template functions must return at least one value")
|
ErrFuncNoReturns = errors.New("template functions must return at least one value")
|
||||||
ErrFuncSecondReturnType = errors.New("the second return value of a template function must be an error")
|
ErrFuncSecondReturnType = errors.New("the second return value of a template function must be an error")
|
||||||
|
ErrTernaryCondBool = errors.New("ternary condition must be a boolean")
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTML represents unescaped HTML strings
|
// HTML represents unescaped HTML strings
|
||||||
@ -215,6 +216,8 @@ func (t *Template) getValue(node ast.Node, local map[string]any) (any, error) {
|
|||||||
return t.getField(node, local)
|
return t.getField(node, local)
|
||||||
case ast.MethodCall:
|
case ast.MethodCall:
|
||||||
return t.execMethodCall(node, local)
|
return t.execMethodCall(node, local)
|
||||||
|
case ast.Ternary:
|
||||||
|
return t.evalTernary(node, local)
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -427,6 +430,24 @@ func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, lo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Template) evalTernary(tr ast.Ternary, local map[string]any) (any, error) {
|
||||||
|
condVal, err := t.getValue(tr.Condition, local)
|
||||||
|
if err != nil {
|
||||||
|
return nil, t.posError(tr.Condition, "%w", ErrTernaryCondBool)
|
||||||
|
}
|
||||||
|
|
||||||
|
cond, ok := condVal.(bool)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("ternary condition must be a boolean")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cond {
|
||||||
|
return t.getValue(tr.IfTrue, local)
|
||||||
|
} else {
|
||||||
|
return t.getValue(tr.Else, local)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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