Add support for maps and arrays
This commit is contained in:
		
							
								
								
									
										18
									
								
								ast/ast.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								ast/ast.go
									
									
									
									
									
								
							@@ -64,6 +64,24 @@ type Value struct {
 | 
				
			|||||||
	Not bool
 | 
						Not bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Map struct {
 | 
				
			||||||
 | 
						Map      map[Node]Node
 | 
				
			||||||
 | 
						Position Position
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m Map) Pos() Position {
 | 
				
			||||||
 | 
						return m.Position
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Array struct {
 | 
				
			||||||
 | 
						Array    []Node
 | 
				
			||||||
 | 
						Position Position
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a Array) Pos() Position {
 | 
				
			||||||
 | 
						return a.Position
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Expr struct {
 | 
					type Expr struct {
 | 
				
			||||||
	First    Node
 | 
						First    Node
 | 
				
			||||||
	Operator Operator
 | 
						Operator Operator
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										991
									
								
								parser/parser.go
									
									
									
									
									
								
							
							
						
						
									
										991
									
								
								parser/parser.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -116,13 +116,49 @@ ParamList = '(' params:(Expr ( ',' _ Expr )* )? ')' {
 | 
				
			|||||||
    return out, nil
 | 
					    return out, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / Float / Integer / Bool / FuncCall / VariableOr / Ident / ParenExpr) {
 | 
					Value = not:"!"? node:(MethodCall / FieldAccess / Index / String / RawString / Float / Integer / Bool / FuncCall / VariableOr / Ident / ParenExpr / Array / Map) {
 | 
				
			||||||
    return ast.Value{
 | 
					    return ast.Value{
 | 
				
			||||||
        Node: node.(ast.Node),
 | 
					        Node: node.(ast.Node),
 | 
				
			||||||
        Not:  not != nil,
 | 
					        Not:  not != nil,
 | 
				
			||||||
    }, nil
 | 
					    }, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Map = '{' _ fpair:(Assignable _ ':' _ Assignable)? _ pairs:(',' _ Assignable _ ':' _ Assignable _)* _ ','? _ '}' {
 | 
				
			||||||
 | 
					    out := ast.Map{
 | 
				
			||||||
 | 
					        Map: map[ast.Node]ast.Node{},
 | 
				
			||||||
 | 
					        Position: getPos(c),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fpairSlice := toAnySlice(fpair)
 | 
				
			||||||
 | 
					    if fpairSlice == nil {
 | 
				
			||||||
 | 
					        return out, nil
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        out.Map[fpairSlice[0].(ast.Node)] = fpairSlice[4].(ast.Node)
 | 
				
			||||||
 | 
					        for _, pair := range toAnySlice(pairs) {
 | 
				
			||||||
 | 
					            pairSlice := toAnySlice(pair)
 | 
				
			||||||
 | 
					            out.Map[pairSlice[2].(ast.Node)] = pairSlice[6].(ast.Node)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array = '[' _ fval:Assignable? _ vals:(',' _ Assignable _)* ','? _ ']' {
 | 
				
			||||||
 | 
					    out := ast.Array{Position: getPos(c)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if fval == nil {
 | 
				
			||||||
 | 
					        return out, nil
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        out.Array = append(out.Array, fval.(ast.Node))
 | 
				
			||||||
 | 
					        for _, val := range toAnySlice(vals) {
 | 
				
			||||||
 | 
					            valSlice := toAnySlice(val)
 | 
				
			||||||
 | 
					            out.Array = append(out.Array, valSlice[2].(ast.Node))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VariableOr = variable:Ident _ '|' _ or:Assignable {
 | 
					VariableOr = variable:Ident _ '|' _ or:Assignable {
 | 
				
			||||||
    return ast.VariableOr{
 | 
					    return ast.VariableOr{
 | 
				
			||||||
        Variable: variable.(ast.Ident),
 | 
					        Variable: variable.(ast.Ident),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								salix.go
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								salix.go
									
									
									
									
									
								
							@@ -222,6 +222,10 @@ func (t *Template) getValue(node ast.Node, local map[string]any) (any, error) {
 | 
				
			|||||||
		return t.evalTernary(node, local)
 | 
							return t.evalTernary(node, local)
 | 
				
			||||||
	case ast.VariableOr:
 | 
						case ast.VariableOr:
 | 
				
			||||||
		return t.evalVariableOr(node, local)
 | 
							return t.evalVariableOr(node, local)
 | 
				
			||||||
 | 
						case ast.Map:
 | 
				
			||||||
 | 
							return t.convertMap(node, local)
 | 
				
			||||||
 | 
						case ast.Array:
 | 
				
			||||||
 | 
							return t.convertArray(node, local)
 | 
				
			||||||
	case ast.Assignment:
 | 
						case ast.Assignment:
 | 
				
			||||||
		return node, t.handleAssignment(node, local)
 | 
							return node, t.handleAssignment(node, local)
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -290,6 +294,23 @@ func valueToString(node ast.Node) string {
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return "#" + node.Name.Value + "()"
 | 
								return "#" + node.Name.Value + "()"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						case ast.Map:
 | 
				
			||||||
 | 
							k, v := getOneMapPair(node)
 | 
				
			||||||
 | 
							if len(node.Map) > 1 {
 | 
				
			||||||
 | 
								return "{" + valueToString(k) + ": " + valueToString(v) + ", ...}"
 | 
				
			||||||
 | 
							} else if len(node.Map) == 1 {
 | 
				
			||||||
 | 
								return "{" + valueToString(k) + ": " + valueToString(v) + "}"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return "{}"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case ast.Array:
 | 
				
			||||||
 | 
							if len(node.Array) > 1 {
 | 
				
			||||||
 | 
								return "[" + valueToString(node.Array[0]) + ", ...]"
 | 
				
			||||||
 | 
							} else if len(node.Array) == 1 {
 | 
				
			||||||
 | 
								return "[" + valueToString(node.Array[0]) + "]"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return "[]"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	case ast.EndTag:
 | 
						case ast.EndTag:
 | 
				
			||||||
		return "#!" + node.Name.Value
 | 
							return "#!" + node.Name.Value
 | 
				
			||||||
	case ast.ExprTag:
 | 
						case ast.ExprTag:
 | 
				
			||||||
@@ -299,6 +320,13 @@ func valueToString(node ast.Node) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getOneMapPair(m ast.Map) (k, v ast.Node) {
 | 
				
			||||||
 | 
						for key, val := range m.Map {
 | 
				
			||||||
 | 
							return key, val
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// unwrapASTValue unwraps an ast.Value node into its underlying value
 | 
					// unwrapASTValue unwraps an ast.Value node into its underlying value
 | 
				
			||||||
func (t *Template) unwrapASTValue(node ast.Value, local map[string]any) (any, error) {
 | 
					func (t *Template) unwrapASTValue(node ast.Value, local map[string]any) (any, error) {
 | 
				
			||||||
	v, err := t.getValue(node.Node, local)
 | 
						v, err := t.getValue(node.Node, local)
 | 
				
			||||||
@@ -317,6 +345,40 @@ func (t *Template) unwrapASTValue(node ast.Value, local map[string]any) (any, er
 | 
				
			|||||||
	return v, err
 | 
						return v, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convertMap converts an ast.Map value into a map[any]any by recursively calling
 | 
				
			||||||
 | 
					// getValue on each of its keys and values.
 | 
				
			||||||
 | 
					func (t *Template) convertMap(node ast.Map, local map[string]any) (any, error) {
 | 
				
			||||||
 | 
						out := make(map[any]any, len(node.Map))
 | 
				
			||||||
 | 
						for keyNode, valNode := range node.Map {
 | 
				
			||||||
 | 
							key, err := t.getValue(keyNode, local)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							val, err := t.getValue(valNode, local)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							out[key] = val
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convertArray converts an ast.Array into an []any by recursively calling getValue
 | 
				
			||||||
 | 
					// on each of its elements.
 | 
				
			||||||
 | 
					func (t *Template) convertArray(node ast.Array, local map[string]any) (any, error) {
 | 
				
			||||||
 | 
						out := make([]any, len(node.Array))
 | 
				
			||||||
 | 
						for i, valNode := range node.Array {
 | 
				
			||||||
 | 
							val, err := t.getValue(valNode, local)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							out[i] = val
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getVar tries to get a variable from the local map. If it's not found,
 | 
					// getVar tries to get a variable from the local map. If it's not found,
 | 
				
			||||||
// it'll try the global variable map. If it doesn't exist in either map,
 | 
					// it'll try the global variable map. If it doesn't exist in either map,
 | 
				
			||||||
// it will return an error.
 | 
					// it will return an error.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user