aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-08-18 20:04:24 +0000
committerMel <einebeere@gmail.com>2022-08-18 20:04:24 +0000
commit18c6d49cc9982ad4362e82730812e1134478ea64 (patch)
tree35c27cae8a6c32a45e4cb88fb761d4e626c7b9cd /pkg
parent73ac132294f3e659f1d769c961aa45bafdd19b45 (diff)
downloadjinx-18c6d49cc9982ad4362e82730812e1134478ea64.tar.zst
jinx-18c6d49cc9982ad4362e82730812e1134478ea64.zip
Allow shadowing through function scopes
Diffstat (limited to 'pkg')
-rw-r--r--pkg/lang/compiler/scope/scope_chain.go46
-rw-r--r--pkg/lang/compiler/scope/scopes.go6
2 files changed, 40 insertions, 12 deletions
diff --git a/pkg/lang/compiler/scope/scope_chain.go b/pkg/lang/compiler/scope/scope_chain.go
index 419a982..ba4c4c2 100644
--- a/pkg/lang/compiler/scope/scope_chain.go
+++ b/pkg/lang/compiler/scope/scope_chain.go
@@ -6,8 +6,6 @@ import (
)
type ScopeChain struct {
- nameToSymbol map[string]SymbolID
-
symbolScopes []SymbolScope // All other scopes are bound to this by ID.
functionScopes []FunctionScope
loopScopes []LoopScope
@@ -23,8 +21,6 @@ func NewScopeChain() ScopeChain {
loopScopes := make([]LoopScope, 0)
return ScopeChain{
- nameToSymbol: make(map[string]SymbolID),
-
symbolScopes: symbolScopes,
functionScopes: functionScopes,
loopScopes: loopScopes,
@@ -80,6 +76,25 @@ func (sc *ScopeChain) CalculateTopLocalIndex() int {
return sumLocals
}
+func (sc *ScopeChain) CanSymbolBeDeclared(name string) bool {
+ topFunctionScope := sc.CurrentFunction()
+
+ for scopeIndex := len(sc.symbolScopes) - 1; scopeIndex >= 0; scopeIndex-- {
+ scope := sc.symbolScopes[scopeIndex]
+
+ if _, ok := scope.nameToSymbol[name]; ok {
+ return false
+ }
+
+ // Shadowing only allowed with at least one function scope in the chain.
+ if ScopeID(scopeIndex) == topFunctionScope.id {
+ return true
+ }
+ }
+
+ return true
+}
+
func (sc *ScopeChain) Enter() {
sc.symbolScopes = append(sc.symbolScopes, NewSymbolScope())
}
@@ -133,7 +148,7 @@ func (sc *ScopeChain) Exit() int {
func (sc *ScopeChain) Declare(name string) (int, bool) {
// Check whether the symbol is already declared in any of the scopes.
- if _, ok := sc.nameToSymbol[name]; ok {
+ if !sc.CanSymbolBeDeclared(name) {
return 0, false
}
@@ -156,7 +171,7 @@ func (sc *ScopeChain) Declare(name string) (int, bool) {
},
})
- sc.nameToSymbol[name] = symbolID
+ current.nameToSymbol[name] = symbolID
return localIndex, true
}
@@ -180,7 +195,7 @@ func (sc *ScopeChain) DeclareTemporary() int {
}
func (sc *ScopeChain) DeclareGlobal(name, module, author string) bool {
- if _, ok := sc.nameToSymbol[name]; ok {
+ if !sc.CanSymbolBeDeclared(name) {
return false
}
@@ -203,7 +218,7 @@ func (sc *ScopeChain) DeclareGlobal(name, module, author string) bool {
},
})
- sc.nameToSymbol[name] = symbolID
+ current.nameToSymbol[name] = symbolID
return true
}
@@ -231,9 +246,18 @@ func (sc *ScopeChain) CreateFunctionSubUnit(subUnitName string) code.Marker {
}
func (sc *ScopeChain) Lookup(name string) (SymbolID, bool) {
- id, ok := sc.nameToSymbol[name]
- if !ok {
- return SymbolID{}, false
+ var id SymbolID
+ for scopeIndex := len(sc.symbolScopes) - 1; scopeIndex >= 0; scopeIndex-- {
+ scope := sc.symbolScopes[scopeIndex]
+
+ if foundID, ok := scope.nameToSymbol[name]; ok {
+ id = foundID
+ break
+ }
+
+ if scopeIndex == 0 {
+ return SymbolID{}, false
+ }
}
// Check whether the symbol is outside the current function scope.
diff --git a/pkg/lang/compiler/scope/scopes.go b/pkg/lang/compiler/scope/scopes.go
index e1a7a9f..f62ab56 100644
--- a/pkg/lang/compiler/scope/scopes.go
+++ b/pkg/lang/compiler/scope/scopes.go
@@ -13,12 +13,16 @@ const (
)
type SymbolScope struct {
+ nameToSymbol map[string]SymbolID
+
variableSymbols []Symbol[SymbolVariable]
- globalSymbols []Symbol[SymbolGlobal]
+ globalSymbols []Symbol[SymbolGlobal]
}
func NewSymbolScope() SymbolScope {
return SymbolScope{
+ nameToSymbol: make(map[string]SymbolID),
+
variableSymbols: make([]Symbol[SymbolVariable], 0),
globalSymbols: make([]Symbol[SymbolGlobal], 0),
}