about summary refs log tree commit diff
path: root/pkg/lang/compiler
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/lang/compiler
parent73ac132294f3e659f1d769c961aa45bafdd19b45 (diff)
downloadjinx-18c6d49cc9982ad4362e82730812e1134478ea64.tar.zst
jinx-18c6d49cc9982ad4362e82730812e1134478ea64.zip
Allow shadowing through function scopes
Diffstat (limited to 'pkg/lang/compiler')
-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),
 	}