Add support for maps and arrays
This commit is contained in:
parent
b4bc463326
commit
b8d3314ada
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.
|
||||
|
Loading…
Reference in New Issue
Block a user