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) }