package main const ( unknownVarType string = `unknown` // placeholder mixedVarType string = `mixed` // when setting an incompatible type ) type LocalVar struct { Name string Type string } 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, Type string) *LocalVar { if lv := this.Has(Name); lv != nil { // Update known type for existing variable if lv.Type == unknownVarType { lv.Type = Type } else if lv.Type == Type { // no-op, more evidence for the same type } else if lv.Type != 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] }