package main var ( unknownVarType gotype = gotype{Plain: `unknown`} // placeholder mixedVarType gotype = gotype{Plain: `mixed`} // when setting an incompatible type ) type LocalVar struct { Name string Type gotype } type Scope struct { parent *Scope locals []LocalVar } func NewScope() *Scope { return &Scope{} } func (this *Scope) NewScope() *Scope { return &Scope{ parent: this, } } func (this *Scope) Has(varName string) *LocalVar { for idx := range this.locals { if this.locals[idx].Name == varName { return &this.locals[idx] // Mutable } } if this.parent != nil { return this.parent.Has(varName) } return nil // not found } func (this *Scope) Set(Name string, Type gotype) *LocalVar { if lv := this.Has(Name); lv != nil { // Update known type for existing variable if lv.Type.Equals(&unknownVarType) { lv.Type = Type } else if lv.Type.Equals(&Type) { // no-op, more evidence for the same type } else if !lv.Type.Equals(&Type) { // conflicting type information lv.Type = mixedVarType } return lv } // Insert new this.locals = append(this.locals, LocalVar{Name: Name, Type: Type}) return &this.locals[len(this.locals)-1] }