77 lines
1.8 KiB
Go
77 lines
1.8 KiB
Go
package ast
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Index represents an indexing operation into another data structure
|
|
type Index struct {
|
|
Target Node
|
|
Key Node
|
|
Posx Pos
|
|
}
|
|
|
|
func (n *Index) Accept(v Visitor) Node {
|
|
n.Target = n.Target.Accept(v)
|
|
n.Key = n.Key.Accept(v)
|
|
return v(n)
|
|
}
|
|
|
|
func (n *Index) Pos() Pos {
|
|
return n.Posx
|
|
}
|
|
|
|
func (n *Index) String() string {
|
|
return fmt.Sprintf("Index(%s, %s)", n.Target, n.Key)
|
|
}
|
|
|
|
func (n *Index) Type(s Scope) (Type, error) {
|
|
variableAccess, ok := n.Target.(*VariableAccess)
|
|
if !ok {
|
|
return TypeInvalid, fmt.Errorf("target is not a variable")
|
|
}
|
|
|
|
variable, ok := s.LookupVar(variableAccess.Name)
|
|
if !ok {
|
|
return TypeInvalid, fmt.Errorf("unknown variable accessed: %s", variableAccess.Name)
|
|
}
|
|
|
|
switch variable.Type {
|
|
case TypeList:
|
|
return n.typeList(variable, variableAccess.Name)
|
|
case TypeMap:
|
|
return n.typeMap(variable, variableAccess.Name)
|
|
default:
|
|
return TypeInvalid, fmt.Errorf("invalid index operation into non-indexable type: %s", variable.Type)
|
|
}
|
|
}
|
|
|
|
func (n *Index) typeList(variable Variable, variableName string) (Type, error) {
|
|
// We assume type checking has already determined that this is a list
|
|
list := variable.Value.([]Variable)
|
|
|
|
return VariableListElementTypesAreHomogenous(variableName, list)
|
|
}
|
|
|
|
func (n *Index) typeMap(variable Variable, variableName string) (Type, error) {
|
|
// We assume type checking has already determined that this is a map
|
|
vmap := variable.Value.(map[string]Variable)
|
|
|
|
return VariableMapValueTypesAreHomogenous(variableName, vmap)
|
|
}
|
|
|
|
func reportTypes(typesFound map[Type]struct{}) string {
|
|
stringTypes := make([]string, len(typesFound))
|
|
i := 0
|
|
for k, _ := range typesFound {
|
|
stringTypes[0] = k.String()
|
|
i++
|
|
}
|
|
return strings.Join(stringTypes, ", ")
|
|
}
|
|
|
|
func (n *Index) GoString() string {
|
|
return fmt.Sprintf("*%#v", *n)
|
|
}
|