aboutsummaryrefslogtreecommitdiff
path: root/pkg/lang
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-07-26 02:37:38 +0200
committerMel <einebeere@gmail.com>2022-07-26 02:37:38 +0200
commit41490ae52e3b1ff20980c5e0837d257043b3ca92 (patch)
tree9d2574dbcdc6f82a9b89cfcf64f7e25634484a5a /pkg/lang
parentb6fa4bc82398b09307f2e6b75e27422d1d1ecb33 (diff)
downloadjinx-41490ae52e3b1ff20980c5e0837d257043b3ca92.tar.zst
jinx-41490ae52e3b1ff20980c5e0837d257043b3ca92.zip
Store functions in locals and remove hoisting
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/compiler/compiler.go57
-rw-r--r--pkg/lang/compiler/compiler_test.go8
-rw-r--r--pkg/lang/compiler/scope/scope_chain.go37
-rw-r--r--pkg/lang/compiler/scope/scopes.go2
-rw-r--r--pkg/lang/compiler/scope/symbol.go21
5 files changed, 24 insertions, 101 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go
index e446dd6..0424862 100644
--- a/pkg/lang/compiler/compiler.go
+++ b/pkg/lang/compiler/compiler.go
@@ -24,15 +24,6 @@ func New(ast ast.Program) *Compiler {
}
func (comp *Compiler) Compile() (code.Code, error) {
- // Pre-declare all top-level functions
- for _, stmt := range comp.ast.Stmts {
- if stmt.Kind == ast.StmtKindFnDecl {
- if err := comp.preDeclareFunction(stmt.Value.(ast.StmtFnDecl)); err != nil {
- return code.Code{}, err
- }
- }
- }
-
target := code.NewBuilder()
for _, stmt := range comp.ast.Stmts {
@@ -50,14 +41,6 @@ func (comp *Compiler) Compile() (code.Code, error) {
return target.Build()
}
-func (comp *Compiler) preDeclareFunction(fnDeclStmt ast.StmtFnDecl) error {
- if _, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value, uint(len(fnDeclStmt.Args))); !ok {
- return fmt.Errorf("function %s already declared", fnDeclStmt.Name.Value)
- }
-
- return nil
-}
-
func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error {
var err error
switch stmt.Kind {
@@ -106,23 +89,13 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error {
}
func (comp *Compiler) compileFnDeclStmt(t *code.Builder, fnDeclStmt ast.StmtFnDecl) error {
- marker, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value, uint(len(fnDeclStmt.Args)))
+ _, ok := comp.scopes.Declare(fnDeclStmt.Name.Value)
if !ok {
- // If we are in the root scope, the function was simply predeclared :)
- if comp.scopes.IsRootScope() {
- symbolID, ok := comp.scopes.Lookup(fnDeclStmt.Name.Value)
- if !ok {
- panic("function said it was declared but apparently it was lying")
- }
-
- symbol := comp.scopes.GetFunction(symbolID)
-
- marker = symbol.Data().Marker()
- } else {
- return fmt.Errorf("function %s already declared", fnDeclStmt.Name.Value)
- }
+ return fmt.Errorf("function %s already declared", fnDeclStmt.Name.Value)
}
+ marker := comp.scopes.CreateFunctionSubUnit(fnDeclStmt.Name.Value)
+
functionTarget := code.NewBuilder()
functionTarget.PutMarker(marker)
@@ -144,6 +117,18 @@ func (comp *Compiler) compileFnDeclStmt(t *code.Builder, fnDeclStmt ast.StmtFnDe
comp.funcs = append(comp.funcs, &functionTarget)
+ // Put the function value on the stack
+
+ t.AppendOp(code.OpPushFunction)
+ t.AppendMarkerReference(marker)
+
+ if len(fnDeclStmt.Args) != 0 {
+ t.AppendOp(code.OpSetArgCount)
+ t.AppendInt(int64(len(fnDeclStmt.Args)))
+ }
+
+ // TODO: Attach the function environment
+
return nil
}
@@ -654,16 +639,6 @@ func (comp *Compiler) compileIdentExpr(t *code.Builder, expr ast.ExprIdent) erro
t.AppendOp(code.OpGetLocal)
t.AppendInt(int64(symbol.Data().LocalIndex()))
- case scope.SymbolKindFunction:
- symbol := comp.scopes.GetFunction(symbolId)
-
- t.AppendOp(code.OpPushFunction)
- t.AppendMarkerReference(symbol.Data().Marker())
-
- if symbol.Data().Args() != 0 {
- t.AppendOp(code.OpSetArgCount)
- t.AppendInt(int64(symbol.Data().Args()))
- }
default:
panic(fmt.Errorf("unknown symbol kind: %v", symbolId.SymbolKind()))
}
diff --git a/pkg/lang/compiler/compiler_test.go b/pkg/lang/compiler/compiler_test.go
index b8a6264..07586a6 100644
--- a/pkg/lang/compiler/compiler_test.go
+++ b/pkg/lang/compiler/compiler_test.go
@@ -434,15 +434,17 @@ func TestForIn(t *testing.T) {
func TestSimpleFunction(t *testing.T) {
src := `
- var result = the_meaning_of_life()
-
fn the_meaning_of_life() {
return 42
}
+
+ var result = the_meaning_of_life()
`
expected := `
push_function @the_meaning_of_life
+
+ get_local 0
call 0
halt
@@ -466,6 +468,8 @@ func TestFunctionArgs(t *testing.T) {
expected := `
push_function @add
set_arg_count 2
+
+ get_local 0
push_int 4
push_int 5
call 2
diff --git a/pkg/lang/compiler/scope/scope_chain.go b/pkg/lang/compiler/scope/scope_chain.go
index d0108ee..f4b9f46 100644
--- a/pkg/lang/compiler/scope/scope_chain.go
+++ b/pkg/lang/compiler/scope/scope_chain.go
@@ -137,35 +137,6 @@ func (sc *ScopeChain) Declare(name string) (int, bool) {
return indexInScope, true
}
-func (sc *ScopeChain) DeclareFunction(name string, args uint) (code.Marker, bool) {
- if _, ok := sc.nameToSymbol[name]; ok {
- return "", false
- }
-
- current := sc.Current()
- index := len(current.functionSymbols)
-
- symbolID := SymbolID{
- symbolKind: SymbolKindFunction,
- scopeID: sc.CurrentScopeID(),
- indexInScope: index,
- }
-
- unitName := sc.CreateFunctionSubUnit(name)
-
- current.functionSymbols = append(current.functionSymbols, Symbol[SymbolFunction]{
- name: name,
- data: SymbolFunction{
- marker: unitName,
- args: args,
- },
- })
-
- sc.nameToSymbol[name] = symbolID
-
- return unitName, true
-}
-
func (sc *ScopeChain) DeclareAnonymous() int {
current := sc.Current()
index := len(current.variableSymbols)
@@ -221,11 +192,3 @@ func (sc *ScopeChain) GetVariable(id SymbolID) Symbol[SymbolVariable] {
return sc.symbolScopes[id.scopeID].variableSymbols[id.indexInScope]
}
-
-func (sc *ScopeChain) GetFunction(id SymbolID) Symbol[SymbolFunction] {
- if id.symbolKind != SymbolKindFunction {
- panic("incorrect symbol id kind given")
- }
-
- return sc.symbolScopes[id.scopeID].functionSymbols[id.indexInScope]
-}
diff --git a/pkg/lang/compiler/scope/scopes.go b/pkg/lang/compiler/scope/scopes.go
index 5cfcd5d..e34b45a 100644
--- a/pkg/lang/compiler/scope/scopes.go
+++ b/pkg/lang/compiler/scope/scopes.go
@@ -14,13 +14,11 @@ const (
type SymbolScope struct {
variableSymbols []Symbol[SymbolVariable]
- functionSymbols []Symbol[SymbolFunction]
}
func NewSymbolScope() SymbolScope {
return SymbolScope{
variableSymbols: make([]Symbol[SymbolVariable], 0),
- functionSymbols: make([]Symbol[SymbolFunction], 0),
}
}
diff --git a/pkg/lang/compiler/scope/symbol.go b/pkg/lang/compiler/scope/symbol.go
index df91899..3b50108 100644
--- a/pkg/lang/compiler/scope/symbol.go
+++ b/pkg/lang/compiler/scope/symbol.go
@@ -1,7 +1,5 @@
package scope
-import "jinx/pkg/lang/vm/code"
-
type SymbolID struct {
symbolKind SymbolKind
scopeID ScopeID
@@ -15,16 +13,14 @@ func (id SymbolID) SymbolKind() SymbolKind {
type SymbolKind int
const (
+ // A variable symbol is bound to a local on the stack.
SymbolKindVariable SymbolKind = iota
- SymbolKindFunction
)
func (s SymbolKind) String() string {
switch s {
case SymbolKindVariable:
return "variable"
- case SymbolKindFunction:
- return "function"
default:
panic("unknown symbol kind")
}
@@ -40,7 +36,7 @@ func (s Symbol[D]) Data() D {
}
type SymbolData interface {
- SymbolVariable | SymbolFunction
+ SymbolVariable
}
type SymbolVariable struct {
@@ -50,16 +46,3 @@ type SymbolVariable struct {
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
-}