61 lines
1.1 KiB
Go
61 lines
1.1 KiB
Go
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]
|
|
}
|