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
|
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user