about summary refs log tree commit diff
path: root/pkg/lang/compiler/scope/scope_chain.go
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-07-26 03:54:06 +0200
committerMel <einebeere@gmail.com>2022-07-26 03:54:06 +0200
commit20bd5570465c73b89458de58c9fb8cd4e5919b44 (patch)
tree21bb690611853a1863a0364045c93ece53b8c280 /pkg/lang/compiler/scope/scope_chain.go
parent917e721ca612cdc5ba6b4b1ab3fc969d55b728b3 (diff)
downloadjinx-20bd5570465c73b89458de58c9fb8cd4e5919b44.tar.zst
jinx-20bd5570465c73b89458de58c9fb8cd4e5919b44.zip
Compile function environments
Diffstat (limited to 'pkg/lang/compiler/scope/scope_chain.go')
-rw-r--r--pkg/lang/compiler/scope/scope_chain.go60
1 files changed, 50 insertions, 10 deletions
diff --git a/pkg/lang/compiler/scope/scope_chain.go b/pkg/lang/compiler/scope/scope_chain.go
index f4b9f46..1b83c75 100644
--- a/pkg/lang/compiler/scope/scope_chain.go
+++ b/pkg/lang/compiler/scope/scope_chain.go
@@ -91,19 +91,14 @@ func (sc *ScopeChain) Exit() int {
 	id := sc.CurrentScopeID()
 	stackSpace := len(sc.symbolScopes[id].variableSymbols)
 
-	sc.symbolScopes[id] = SymbolScope{}
 	sc.symbolScopes = sc.symbolScopes[:id]
 
 	if sc.CurrentLoop() != nil && sc.CurrentLoop().id == id {
-		lastLoopScope := len(sc.loopScopes) - 1
-		sc.loopScopes[lastLoopScope] = LoopScope{}
-		sc.loopScopes = sc.loopScopes[:lastLoopScope]
+		sc.loopScopes = sc.loopScopes[:len(sc.loopScopes)-1]
 	}
 
 	if sc.CurrentFunction().id == id {
-		lastFunctionScope := len(sc.functionScopes) - 1
-		sc.functionScopes[lastFunctionScope] = FunctionScope{}
-		sc.functionScopes = sc.functionScopes[:lastFunctionScope]
+		sc.functionScopes = sc.functionScopes[:len(sc.functionScopes)-1]
 	}
 
 	return stackSpace
@@ -178,11 +173,23 @@ func (sc *ScopeChain) CreateFunctionSubUnit(subUnitName string) code.Marker {
 }
 
 func (sc *ScopeChain) Lookup(name string) (SymbolID, bool) {
-	if id, ok := sc.nameToSymbol[name]; ok {
-		return id, true
+	id, ok := sc.nameToSymbol[name]
+	if !ok {
+		return SymbolID{}, false
 	}
 
-	return SymbolID{}, false
+	// Check whether the symbol is outside the current function scope.
+	fnScope := sc.CurrentFunction()
+	if id.scopeID < fnScope.id {
+		// Return env symbol instead of a local symbol.
+		return SymbolID{
+			symbolKind:   SymbolKindEnv,
+			scopeID:      id.scopeID,
+			indexInScope: id.indexInScope,
+		}, true
+	}
+
+	return id, true
 }
 
 func (sc *ScopeChain) GetVariable(id SymbolID) Symbol[SymbolVariable] {
@@ -192,3 +199,36 @@ func (sc *ScopeChain) GetVariable(id SymbolID) Symbol[SymbolVariable] {
 
 	return sc.symbolScopes[id.scopeID].variableSymbols[id.indexInScope]
 }
+
+func (sc *ScopeChain) GetEnv(id SymbolID) Symbol[SymbolEnv] {
+	if id.symbolKind != SymbolKindEnv {
+		panic("incorrect symbol id kind given")
+	}
+
+	symbol := sc.symbolScopes[id.scopeID].variableSymbols[id.indexInScope]
+
+	// Add the local to the function scope, if it is not already there.
+	fnScope := sc.CurrentFunction()
+
+	var indexInEnv int
+	alreadyUsed := false
+	for i, env := range fnScope.outsideSymbolsInEnv {
+		if env == id {
+			alreadyUsed = true
+			indexInEnv = i
+			break
+		}
+	}
+
+	if !alreadyUsed {
+		indexInEnv = len(fnScope.outsideSymbolsInEnv)
+		fnScope.outsideSymbolsInEnv = append(fnScope.outsideSymbolsInEnv, id)
+	}
+
+	return Symbol[SymbolEnv]{
+		name: symbol.name,
+		data: SymbolEnv{
+			indexInEnv: indexInEnv,
+		},
+	}
+}