Add ternary expressions
This commit is contained in:
		| @@ -10,10 +10,10 @@ | ||||
|     </div>   | ||||
|     <div class="navbar-menu" id="navbarMenu"> | ||||
|         <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 | ||||
|             </a> | ||||
|             <a class='navbar-item #if(title == "About"):is-active#!if' href="/about"> | ||||
|             <a class='navbar-item #(title == "About" ? "is-active" : "")' href="/about"> | ||||
|                 About | ||||
|             </a> | ||||
|         </div> | ||||
|   | ||||
| @@ -199,3 +199,14 @@ func (l Logical) Pos() Position { | ||||
| func (l Logical) Op() string { | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| ExprTag = "#(" expr:Expr ')' { | ||||
| ExprTag = "#(" item:Item ')' { | ||||
|     return ast.ExprTag{ | ||||
|         Value:    expr.(ast.Node), | ||||
|         Value:    item.(ast.Node), | ||||
|         Position: getPos(c), | ||||
|     }, nil | ||||
| } | ||||
|  | ||||
| Item = Ternary / Expr | ||||
|  | ||||
| Expr = first:ExprSegment rest:(_ Logical _ ExprSegment)* { | ||||
|     restSlice := toAnySlice(rest) | ||||
|     if len(restSlice) == 0 { | ||||
| @@ -100,7 +102,7 @@ ExprSegment = first:Value rest:(_ Operator _ Value)* { | ||||
|     return out, nil | ||||
| } | ||||
|  | ||||
| ParamList = '(' params:(Expr ( ',' _ Expr )* )? ')' { | ||||
| ParamList = '(' params:(Item ( ',' _ Item )* )? ')' { | ||||
|     paramSlice := toAnySlice(params) | ||||
|     if len(paramSlice) == 0 { | ||||
|         return []ast.Node{}, nil | ||||
| @@ -121,6 +123,14 @@ Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / F | ||||
|     }, 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 { | ||||
|     return ast.MethodCall{ | ||||
|         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") | ||||
| 	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") | ||||
| 	ErrTernaryCondBool      = errors.New("ternary condition must be a boolean") | ||||
| ) | ||||
|  | ||||
| // 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) | ||||
| 	case ast.MethodCall: | ||||
| 		return t.execMethodCall(node, local) | ||||
| 	case ast.Ternary: | ||||
| 		return t.evalTernary(node, local) | ||||
| 	default: | ||||
| 		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 { | ||||
| 	return ast.PosError(n, t.name, format, v...) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user