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 | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 	First    Node | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| 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{ | ||||
|         Node: node.(ast.Node), | ||||
|         Not:  not != 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 { | ||||
|     return ast.VariableOr{ | ||||
|         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) | ||||
| 	case ast.VariableOr: | ||||
| 		return t.evalVariableOr(node, local) | ||||
| 	case ast.Map: | ||||
| 		return t.convertMap(node, local) | ||||
| 	case ast.Array: | ||||
| 		return t.convertArray(node, local) | ||||
| 	case ast.Assignment: | ||||
| 		return node, t.handleAssignment(node, local) | ||||
| 	default: | ||||
| @@ -290,6 +294,23 @@ func valueToString(node ast.Node) string { | ||||
| 		} else { | ||||
| 			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: | ||||
| 		return "#!" + node.Name.Value | ||||
| 	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 | ||||
| func (t *Template) unwrapASTValue(node ast.Value, local map[string]any) (any, error) { | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| // it'll try the global variable map. If it doesn't exist in either map, | ||||
| // it will return an error. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user