Add index to map iteration

This commit is contained in:
Elara 2024-02-20 12:07:39 -08:00
parent 4501ef63d6
commit d91eef09bf

View File

@ -1,6 +1,7 @@
package salix package salix
import ( import (
"errors"
"reflect" "reflect"
"go.elara.ws/salix/ast" "go.elara.ws/salix/ast"
@ -10,35 +11,27 @@ import (
type forTag struct{} type forTag struct{}
func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error { func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
if len(args) == 0 || len(args) > 2 { if len(args) == 0 || len(args) > 3 {
return tc.PosError(tc.Tag, "invalid argument amount") return tc.PosError(tc.Tag, "invalid argument amount")
} }
var expr ast.Expr expr, ok := args[len(args)-1].(ast.Expr)
if len(args) == 1 {
expr2, ok := args[0].(ast.Expr)
if !ok { if !ok {
return tc.PosError(args[0], "invalid argument type: %T (expected ast.Expr)", args[0]) return tc.PosError(args[0], "invalid argument type: %T (expected ast.Expr)", args[0])
} }
expr = expr2
} else if len(args) == 2 {
expr2, ok := args[1].(ast.Expr)
if !ok {
return tc.PosError(args[1], "invalid argument type: %T (expected ast.Expr)", args[1])
}
expr = expr2
}
var vars []string var vars []string
var in reflect.Value var in reflect.Value
if len(args) == 2 { if len(args) > 1 {
varName, ok := unwrap(args[0]).(ast.Ident) for _, arg := range args[:len(args)-1] {
varName, ok := unwrap(arg).(ast.Ident)
if !ok { if !ok {
return tc.PosError(args[0], "invalid argument type: %T (expected ast.Ident)", expr.First) return tc.PosError(arg, "invalid argument type: %T (expected ast.Ident)", expr.First)
} }
vars = append(vars, varName.Value) vars = append(vars, varName.Value)
} }
}
varName, ok := unwrap(expr.First).(ast.Ident) varName, ok := unwrap(expr.First).(ast.Ident)
if !ok { if !ok {
@ -70,6 +63,8 @@ func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
} else if len(vars) == 2 { } else if len(vars) == 2 {
local[vars[0]] = i local[vars[0]] = i
local[vars[1]] = in.Index(i).Interface() local[vars[1]] = in.Index(i).Interface()
} else {
return errors.New("slices and arrays can only use two for loop variables")
} }
err = tc.Execute(block, local) err = tc.Execute(block, local)
@ -80,18 +75,25 @@ func (ft forTag) Run(tc *TagContext, block, args []ast.Node) error {
case reflect.Map: case reflect.Map:
local := map[string]any{} local := map[string]any{}
iter := in.MapRange() iter := in.MapRange()
i := 0
for iter.Next() { for iter.Next() {
if len(vars) == 1 { if len(vars) == 1 {
local[vars[0]] = iter.Value().Interface() local[vars[0]] = iter.Value().Interface()
} else if len(vars) == 2 { } else if len(vars) == 2 {
local[vars[0]] = iter.Key().Interface() local[vars[0]] = iter.Key().Interface()
local[vars[1]] = iter.Value().Interface() local[vars[1]] = iter.Value().Interface()
} else if len(vars) == 3 {
local[vars[0]] = i
local[vars[1]] = iter.Key().Interface()
local[vars[2]] = iter.Value().Interface()
} }
err = tc.Execute(block, local) err = tc.Execute(block, local)
if err != nil { if err != nil {
return err return err
} }
i++
} }
} }