about summary refs log tree commit diff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/lang/compiler/compiler.go33
-rw-r--r--pkg/lang/compiler/scope/scope_chain.go (renamed from pkg/lang/compiler/scope_chain.go)129
-rw-r--r--pkg/lang/compiler/scope/scopes.go50
-rw-r--r--pkg/lang/compiler/scope/symbol.go (renamed from pkg/lang/compiler/symbol.go)28
4 files changed, 127 insertions, 113 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go
index 728dec1..ad37ded 100644
--- a/pkg/lang/compiler/compiler.go
+++ b/pkg/lang/compiler/compiler.go
@@ -3,6 +3,7 @@ package compiler
 import (
 	"fmt"
 	"jinx/pkg/lang/ast"
+	"jinx/pkg/lang/compiler/scope"
 	"jinx/pkg/lang/vm/code"
 )
 
@@ -11,14 +12,14 @@ type Compiler struct {
 
 	funcs []*code.Builder
 
-	scopes ScopeChain
+	scopes scope.ScopeChain
 }
 
 func New(ast ast.Program) *Compiler {
 	return &Compiler{
 		ast:    ast,
 		funcs:  make([]*code.Builder, 0),
-		scopes: NewScopeChain(),
+		scopes: scope.NewScopeChain(),
 	}
 }
 
@@ -114,7 +115,7 @@ func (comp *Compiler) compileFnDeclStmt(t *code.Builder, fnDeclStmt ast.StmtFnDe
 
 			symbol := comp.scopes.GetFunction(symbolID)
 
-			marker = symbol.data.marker
+			marker = symbol.Data().Marker()
 		} else {
 			return fmt.Errorf("function %s already declared", fnDeclStmt.Name.Value)
 		}
@@ -382,8 +383,8 @@ func (comp *Compiler) compileForInStmt(t *code.Builder, forInStmt ast.StmtForIn)
 func (comp *Compiler) compileReturnStmt(t *code.Builder, returnStmt ast.StmtReturn) error {
 	// Check that we are in fact in a function
 	functionScope := comp.scopes.CurrentFunction()
-	if functionScope.data.(ScopeFunction).IsRootScope() {
-		return fmt.Errorf("can't return when not inside a function" + functionScope.data.(ScopeFunction).unit.String())
+	if functionScope.IsRootScope() {
+		return fmt.Errorf("can't return when not inside a function")
 	}
 
 	if returnStmt.Value.IsEmpty() {
@@ -491,8 +492,8 @@ func (comp *Compiler) compileAssignExpr(t *code.Builder, expr ast.ExprBinary) er
 		return fmt.Errorf("variable %s not declared", name)
 	}
 
-	if symbolId.symbolKind != SymbolKindVariable {
-		return fmt.Errorf("can't assign to a %v", symbolId.symbolKind)
+	if symbolId.SymbolKind() != scope.SymbolKindVariable {
+		return fmt.Errorf("can't assign to a %v", symbolId.SymbolKind())
 	}
 
 	symbol := comp.scopes.GetVariable(symbolId)
@@ -502,7 +503,7 @@ func (comp *Compiler) compileAssignExpr(t *code.Builder, expr ast.ExprBinary) er
 	}
 
 	t.AppendOp(code.OpSetLocal)
-	t.AppendInt(int64(symbol.data.localIndex))
+	t.AppendInt(int64(symbol.Data().LocalIndex()))
 
 	return nil
 }
@@ -587,24 +588,24 @@ func (comp *Compiler) compileIdentExpr(t *code.Builder, expr ast.ExprIdent) erro
 	}
 
 	// TODO: Add other ways how the symbol should be fetched. (local, env, global, etc.)
-	switch symbolId.symbolKind {
-	case SymbolKindVariable:
+	switch symbolId.SymbolKind() {
+	case scope.SymbolKindVariable:
 		symbol := comp.scopes.GetVariable(symbolId)
 
 		t.AppendOp(code.OpGetLocal)
-		t.AppendInt(int64(symbol.data.localIndex))
-	case SymbolKindFunction:
+		t.AppendInt(int64(symbol.Data().LocalIndex()))
+	case scope.SymbolKindFunction:
 		symbol := comp.scopes.GetFunction(symbolId)
 
 		t.AppendOp(code.OpPushFunction)
-		t.AppendMarkerReference(symbol.data.marker)
+		t.AppendMarkerReference(symbol.Data().Marker())
 
-		if symbol.data.args != 0 {
+		if symbol.Data().Args() != 0 {
 			t.AppendOp(code.OpSetArgCount)
-			t.AppendInt(int64(symbol.data.args))
+			t.AppendInt(int64(symbol.Data().Args()))
 		}
 	default:
-		panic(fmt.Errorf("unknown symbol kind: %v", symbolId.symbolKind))
+		panic(fmt.Errorf("unknown symbol kind: %v", symbolId.SymbolKind()))
 	}
 
 	return nil
diff --git a/pkg/lang/compiler/scope_chain.go b/pkg/lang/compiler/scope/scope_chain.go
index 6705852..683d53a 100644
--- a/pkg/lang/compiler/scope_chain.go
+++ b/pkg/lang/compiler/scope/scope_chain.go
@@ -1,57 +1,63 @@
-package compiler
+package scope
 
 import (
 	"fmt"
 	"jinx/pkg/lang/vm/code"
 )
 
-type ScopeID int
-
 type ScopeChain struct {
 	nameToSymbol map[string]SymbolID
-	scopes       []Scope
+
+	symbolScopes   []SymbolScope // All other scopes are bound to this by ID.
+	functionScopes []FunctionScope
 }
 
 func NewScopeChain() ScopeChain {
-	scopes := make([]Scope, 1)
-	scopes[0] = NewFunctionScope(0, "") // Top-most scope is a function scope, so it can have sub-units
+	symbolScopes := make([]SymbolScope, 1)
+	symbolScopes[0] = NewSymbolScope()
+
+	functionScopes := make([]FunctionScope, 1)
+	functionScopes[0] = NewFunctionScope(0, "") // Root function to house top-scope sub units
 
 	return ScopeChain{
 		nameToSymbol: make(map[string]SymbolID),
-		scopes:       scopes,
+
+		symbolScopes:   symbolScopes,
+		functionScopes: functionScopes,
 	}
 }
 
 func (sc *ScopeChain) CurrentScopeID() ScopeID {
-	return ScopeID(len(sc.scopes) - 1)
+	return ScopeID(len(sc.symbolScopes) - 1)
 }
 
 func (sc *ScopeChain) IsRootScope() bool {
 	return sc.CurrentScopeID() == ScopeID(0)
 }
 
-func (sc *ScopeChain) Current() *Scope {
-	return &sc.scopes[sc.CurrentScopeID()]
+func (sc *ScopeChain) Current() *SymbolScope {
+	if len(sc.functionScopes) == 0 {
+		panic("root scope is missing")
+	}
+
+	return &sc.symbolScopes[sc.CurrentScopeID()]
 }
 
-func (sc *ScopeChain) CurrentFunction() *Scope {
-	// TODO: Probably should make this lookup constant by making a seperate array of function scopes
-	for i := len(sc.scopes) - 1; i >= 0; i++ {
-		if sc.scopes[i].kind == ScopeKindFunction {
-			return &sc.scopes[i]
-		}
+func (sc *ScopeChain) CurrentFunction() *FunctionScope {
+	if len(sc.functionScopes) == 0 {
+		panic("root function scope is missing")
 	}
 
-	panic("top scope should always be a function scope")
+	return &sc.functionScopes[len(sc.functionScopes)-1]
 }
 
 func (sc *ScopeChain) Enter() {
-	sc.scopes = append(sc.scopes, NewNormalScope())
+	sc.symbolScopes = append(sc.symbolScopes, NewSymbolScope())
 }
 
 func (sc *ScopeChain) EnterFunction(unit code.Marker) {
-	id := sc.CurrentScopeID() + 1
-	sc.scopes = append(sc.scopes, NewFunctionScope(id, unit))
+	sc.Enter()
+	sc.functionScopes = append(sc.functionScopes, NewFunctionScope(sc.CurrentScopeID(), unit))
 }
 
 func (sc *ScopeChain) Exit() {
@@ -59,8 +65,8 @@ func (sc *ScopeChain) Exit() {
 		return
 	}
 
-	sc.scopes[sc.CurrentScopeID()] = Scope{}
-	sc.scopes = sc.scopes[:sc.CurrentScopeID()]
+	sc.symbolScopes[sc.CurrentScopeID()] = SymbolScope{}
+	sc.symbolScopes = sc.symbolScopes[:sc.CurrentScopeID()]
 }
 
 func (sc *ScopeChain) Declare(name string) (int, bool) {
@@ -140,21 +146,17 @@ func (sc *ScopeChain) DeclareTemporary() int {
 
 func (sc *ScopeChain) CreateAnonymousFunctionSubUnit() code.Marker {
 	fnScope := sc.CurrentFunction()
-	data := fnScope.data.(ScopeFunction)
 
-	index := data.subUnitCount
-	data.subUnitCount++
-
-	fnScope.data = data
+	index := fnScope.subUnitCount
+	fnScope.subUnitCount++
 
 	return sc.CreateFunctionSubUnit(fmt.Sprintf("anon_%d", index))
 }
 
 func (sc *ScopeChain) CreateFunctionSubUnit(subUnitName string) code.Marker {
 	fnScope := sc.CurrentFunction()
-	data := fnScope.data.(ScopeFunction)
 
-	name := data.unit
+	name := fnScope.unit
 	if name == "" {
 		name = code.Marker(subUnitName)
 	} else {
@@ -177,7 +179,7 @@ func (sc *ScopeChain) GetVariable(id SymbolID) Symbol[SymbolVariable] {
 		panic("incorrect symbol id kind given")
 	}
 
-	return sc.scopes[id.scopeID].variableSymbols[id.indexInScope]
+	return sc.symbolScopes[id.scopeID].variableSymbols[id.indexInScope]
 }
 
 func (sc *ScopeChain) GetFunction(id SymbolID) Symbol[SymbolFunction] {
@@ -185,70 +187,5 @@ func (sc *ScopeChain) GetFunction(id SymbolID) Symbol[SymbolFunction] {
 		panic("incorrect symbol id kind given")
 	}
 
-	return sc.scopes[id.scopeID].functionSymbols[id.indexInScope]
-}
-
-type SymbolID struct {
-	symbolKind   SymbolKind
-	scopeID      ScopeID
-	indexInScope int
-}
-
-type ScopeKind int
-
-const (
-	ScopeKindNormal ScopeKind = iota
-	ScopeKindFunction
-	ScopeKindLoop
-)
-
-type Scope struct {
-	variableSymbols []Symbol[SymbolVariable]
-	functionSymbols []Symbol[SymbolFunction]
-
-	kind ScopeKind
-	data any
-}
-
-func NewNormalScope() Scope {
-	return Scope{
-		variableSymbols: make([]Symbol[SymbolVariable], 0),
-		functionSymbols: make([]Symbol[SymbolFunction], 0),
-		kind:            ScopeKindNormal,
-		data:            ScopeNormal{},
-	}
-}
-
-func NewFunctionScope(id ScopeID, unit code.Marker) Scope {
-	return Scope{
-		variableSymbols: make([]Symbol[SymbolVariable], 0),
-		functionSymbols: make([]Symbol[SymbolFunction], 0),
-		kind:            ScopeKindFunction,
-		data: ScopeFunction{
-			id:           id,
-			unit:         unit,
-			subUnitCount: 0,
-		},
-	}
-}
-
-type ScopeNormal struct{}
-
-type ScopeFunction struct {
-	id           ScopeID
-	unit         code.Marker
-	subUnitCount int
-}
-
-func (sf ScopeFunction) ID() ScopeID {
-	return sf.id
-}
-
-func (sf ScopeFunction) IsRootScope() bool {
-	return sf.ID() == ScopeID(0)
-}
-
-type ScopeLoop struct {
-	breakMarker    code.Marker
-	continueMarker code.Marker
+	return sc.symbolScopes[id.scopeID].functionSymbols[id.indexInScope]
 }
diff --git a/pkg/lang/compiler/scope/scopes.go b/pkg/lang/compiler/scope/scopes.go
new file mode 100644
index 0000000..39e48ef
--- /dev/null
+++ b/pkg/lang/compiler/scope/scopes.go
@@ -0,0 +1,50 @@
+package scope
+
+import "jinx/pkg/lang/vm/code"
+
+type ScopeID int
+
+type ScopeKind int
+
+const (
+	ScopeKindNormal ScopeKind = iota
+	ScopeKindFunction
+)
+
+type SymbolScope struct {
+	variableSymbols []Symbol[SymbolVariable]
+	functionSymbols []Symbol[SymbolFunction]
+}
+
+func NewSymbolScope() SymbolScope {
+	return SymbolScope{
+		variableSymbols: make([]Symbol[SymbolVariable], 0),
+		functionSymbols: make([]Symbol[SymbolFunction], 0),
+	}
+}
+
+type FunctionScope struct {
+	id           ScopeID
+	unit         code.Marker
+	subUnitCount int
+}
+
+func NewFunctionScope(id ScopeID, unit code.Marker) FunctionScope {
+	return FunctionScope{
+		id:           id,
+		unit:         unit,
+		subUnitCount: 0,
+	}
+}
+
+func (sf FunctionScope) ID() ScopeID {
+	return sf.id
+}
+
+func (sf FunctionScope) Unit() code.Marker {
+	return sf.unit
+}
+
+func (sf FunctionScope) IsRootScope() bool {
+	return sf.ID() == ScopeID(0)
+}
diff --git a/pkg/lang/compiler/symbol.go b/pkg/lang/compiler/scope/symbol.go
index 453cb2b..df91899 100644
--- a/pkg/lang/compiler/symbol.go
+++ b/pkg/lang/compiler/scope/symbol.go
@@ -1,7 +1,17 @@
-package compiler
+package scope
 
 import "jinx/pkg/lang/vm/code"
 
+type SymbolID struct {
+	symbolKind   SymbolKind
+	scopeID      ScopeID
+	indexInScope int
+}
+
+func (id SymbolID) SymbolKind() SymbolKind {
+	return id.symbolKind
+}
+
 type SymbolKind int
 
 const (
@@ -25,6 +35,10 @@ type Symbol[D SymbolData] struct {
 	data D
 }
 
+func (s Symbol[D]) Data() D {
+	return s.data
+}
+
 type SymbolData interface {
 	SymbolVariable | SymbolFunction
 }
@@ -33,7 +47,19 @@ type SymbolVariable struct {
 	localIndex int
 }
 
+func (sv SymbolVariable) LocalIndex() int {
+	return sv.localIndex
+}
+
 type SymbolFunction struct {
 	marker code.Marker
 	args   uint
 }
+
+func (sf SymbolFunction) Marker() code.Marker {
+	return sf.marker
+}
+
+func (sf SymbolFunction) Args() uint {
+	return sf.args
+}