From 621f624f50a7bef16eeed02113b470e79e790cd9 Mon Sep 17 00:00:00 2001 From: Mel Date: Mon, 20 Jun 2022 00:37:01 +0200 Subject: Compile rudimetary variables --- pkg/lang/compiler/scope_chain.go | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 pkg/lang/compiler/scope_chain.go (limited to 'pkg/lang/compiler/scope_chain.go') diff --git a/pkg/lang/compiler/scope_chain.go b/pkg/lang/compiler/scope_chain.go new file mode 100644 index 0000000..8d942ea --- /dev/null +++ b/pkg/lang/compiler/scope_chain.go @@ -0,0 +1,76 @@ +package compiler + +type ScopeID int + +type ScopeChain struct { + scopes []Scope +} + +func NewScopeChain() ScopeChain { + scopes := make([]Scope, 1) + scopes[0] = Scope{ + kind: ScopeKindGlobal, + symbols: make(map[string]Symbol), + } + + return ScopeChain{ + scopes: scopes, + } +} + +func (sc *ScopeChain) Current() *Scope { + return &sc.scopes[len(sc.scopes)-1] +} + +func (sc *ScopeChain) Enter(kind ScopeKind) { + sc.scopes = append(sc.scopes, Scope{ + kind: kind, + symbols: make(map[string]Symbol), + }) +} + +func (sc *ScopeChain) Exit() { + sc.scopes[len(sc.scopes)-1] = Scope{} + sc.scopes = sc.scopes[:len(sc.scopes)-1] +} + +func (sc *ScopeChain) Declare(name string) bool { + // Check whether the symbol is already declared in any of the scopes. + for _, scope := range sc.scopes { + if _, ok := scope.symbols[name]; ok { + return false + } + } + + // Declare the symbol in the current scope. + sc.Current().symbols[name] = Symbol{ + kind: SymbolKindVariable, + name: name, + localIndex: len(sc.Current().symbols), + } + + return true +} + +func (sc *ScopeChain) Lookup(name string) (Symbol, bool) { + for i := len(sc.scopes) - 1; i >= 0; i-- { + if symbol, ok := sc.scopes[i].symbols[name]; ok { + return symbol, true + } + } + + return Symbol{}, false +} + +type ScopeKind int + +const ( + ScopeKindGlobal ScopeKind = iota + ScopeKindFunction + ScopeKindBlock +) + +type Scope struct { + kind ScopeKind + symbols map[string]Symbol +} -- cgit 1.4.1