diff options
| author | Mel <einebeere@gmail.com> | 2022-08-11 01:25:47 +0000 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-08-11 01:25:47 +0000 |
| commit | 86f31acf6789be116dcc54ed85b069a37c0f7aa8 (patch) | |
| tree | bc7afd6a8c340825996d29c6cfd392ae42b4fbd5 /pkg/lang/compiler/compiler.go | |
| parent | c46b2bc7ce6df1f2c6c9494ef08015ec29992da5 (diff) | |
| download | jinx-86f31acf6789be116dcc54ed85b069a37c0f7aa8.tar.zst jinx-86f31acf6789be116dcc54ed85b069a37c0f7aa8.zip | |
Actual modules and core
Diffstat (limited to 'pkg/lang/compiler/compiler.go')
| -rw-r--r-- | pkg/lang/compiler/compiler.go | 143 |
1 files changed, 132 insertions, 11 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go index 8010b16..d647aff 100644 --- a/pkg/lang/compiler/compiler.go +++ b/pkg/lang/compiler/compiler.go @@ -4,31 +4,43 @@ import ( "fmt" "jinx/pkg/lang/ast" "jinx/pkg/lang/compiler/scope" + "jinx/pkg/lang/modules" "jinx/pkg/lang/vm/code" ) type Compiler struct { - ast ast.Program + name string + author string + ast ast.Program funcs []*code.Builder + globals []string + deps map[modules.ModuleRef]struct{} + scopes scope.ScopeChain } -func New(ast ast.Program) *Compiler { +func New(name, author string, ast ast.Program) *Compiler { return &Compiler{ - ast: ast, - funcs: make([]*code.Builder, 0), + name: name, + author: author, + ast: ast, + funcs: make([]*code.Builder, 0), + globals: []string{}, + deps: map[modules.ModuleRef]struct{}{ + modules.CoreModuleRef: {}, // All modules depend on core + }, scopes: scope.NewScopeChain(), } } -func (comp *Compiler) Compile() (code.Code, error) { +func (comp *Compiler) Compile() (modules.Module, error) { target := code.NewBuilder() for _, stmt := range comp.ast.Stmts { if err := comp.compileStmt(&target, stmt); err != nil { - return code.Code{}, err + return modules.Module{}, err } } @@ -38,7 +50,23 @@ func (comp *Compiler) Compile() (code.Code, error) { target.AppendBuilder(*function) } - return target.Build() + bc, err := target.Build() + if err != nil { + return modules.Module{}, err + } + + deps := make([]modules.ModuleRef, 0, len(comp.deps)) + for dep := range comp.deps { + deps = append(deps, dep) + } + + return modules.NewModule( + comp.author, + comp.name, + &bc, + deps, + comp.globals, + ), nil } func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { @@ -47,7 +75,11 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { case ast.StmtKindEmpty: // Do nothing. case ast.StmtKindUse: - panic("use statements not implemented") + useStmt := stmt.Value.(ast.StmtUse) + err = comp.compileUseStmt(t, useStmt) + case ast.StmtKindGlobal: + globalStmt := stmt.Value.(ast.StmtGlobal) + err = comp.compileGlobalStmt(t, globalStmt) case ast.StmtKindFnDecl: fnDeclStmt := stmt.Value.(ast.StmtFnDecl) err = comp.compileFnDeclStmt(t, fnDeclStmt) @@ -89,6 +121,57 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { return err } +func (comp *Compiler) compileUseStmt(t *code.Builder, stmt ast.StmtUse) error { + if len(stmt.Globals) == 0 { + // TODO: I don't want to have module objects in the VM... + // Maybe compileMemberExpr could check whether Obj is a reference to a module and compile the whole thing as a global reference? + panic("importing entire module not implemented") + } + + // TODO: Try to resolve the module during compilation, so we don't have to fail at runtime. + + for _, global := range stmt.Globals { + if ok := comp.scopes.DeclareGlobal(global.Value, stmt.Module.Value, stmt.Author.Value); !ok { + return fmt.Errorf("global %s already declared", global.Value) + } + } + + comp.deps[modules.NewRef(stmt.Author.Value, stmt.Module.Value)] = struct{}{} + + return nil +} + +func (comp *Compiler) compileGlobalStmt(t *code.Builder, stmt ast.StmtGlobal) error { + if !comp.scopes.IsRootScope() { + return fmt.Errorf("global variables can only be declared at the root scope") + } + + symbolId, symbolExists := comp.scopes.Lookup(stmt.Name.Value) + if !symbolExists { + return fmt.Errorf("variable %s not declared", stmt.Name.Value) + } + + if symbolId.SymbolKind() != scope.SymbolKindVariable { + return fmt.Errorf("%s is not a variable", stmt.Name.Value) + } + + if symbolId.ScopeID() != scope.ScopeID(0) { + return fmt.Errorf("%s is not in root scope", stmt.Name.Value) + } + + symbol := comp.scopes.GetVariable(symbolId) + + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(symbol.Data().LocalIndex())) + + t.AppendOp(code.OpAddGlobal) + t.AppendString(stmt.Name.Value) + + comp.globals = append(comp.globals, stmt.Name.Value) + + return nil +} + func (comp *Compiler) compileFnDeclStmt(t *code.Builder, fnDeclStmt ast.StmtFnDecl) error { _, ok := comp.scopes.Declare(fnDeclStmt.Name.Value) if !ok { @@ -198,7 +281,10 @@ func (comp *Compiler) compileTypeDeclStmt(t *code.Builder, typeDeclStmt ast.Stmt } if !constructorDeclared { - return fmt.Errorf("type %s must have a constructor", typeDeclStmt.Name.Value) + // The core module is allowed to have no constructor + if !comp.areWeCompilingCore() { + return fmt.Errorf("type %s must have a constructor", typeDeclStmt.Name.Value) + } } // Add methods to the type @@ -228,6 +314,9 @@ func (comp *Compiler) compileTypeDeclStmt(t *code.Builder, typeDeclStmt ast.Stmt t.AppendOp(code.OpCall) t.AppendInt(int64(2)) + + t.AppendOp(code.OpDrop) + t.AppendInt(int64(1)) } return nil @@ -653,8 +742,8 @@ func (comp *Compiler) compileAssignExpr(t *code.Builder, expr ast.ExprBinary) er t.AppendOp(code.OpSetEnv) t.AppendInt(int64(symbol.Data().IndexInEnv())) - default: - panic("unknown symbol kind") + case scope.SymbolKindGlobal: + return fmt.Errorf("cannot assign to global variable %s", name) } case ast.ExprKindMember: memberExpr := expr.Left.Value.(ast.ExprMember) @@ -695,6 +784,13 @@ func (comp *Compiler) compileUnaryExpr(t *code.Builder, expr ast.ExprUnary) erro } func (comp *Compiler) compileCallExpr(t *code.Builder, expr ast.ExprCall) error { + // Check if call is a native call + if expr.Callee.Kind == ast.ExprKindIdent && + expr.Callee.Value.(ast.ExprIdent).Value.Value == "native" && + expr.Args[0].Kind == ast.ExprKindStringLit { + return comp.compileNativeCallExpr(t, expr.Args[0].Value.(ast.ExprStringLit).Value, expr.Args[1:]) + } + if err := comp.compileExpr(t, expr.Callee); err != nil { return err } @@ -711,6 +807,22 @@ func (comp *Compiler) compileCallExpr(t *code.Builder, expr ast.ExprCall) error return nil } +func (comp *Compiler) compileNativeCallExpr(t *code.Builder, nativeID string, args []ast.Expr) error { + t.AppendOp(code.OpGetGlobal) + t.AppendString(fmt.Sprintf("%s#native", nativeID)) + + for i := 0; i < len(args); i++ { + if err := comp.compileExpr(t, args[i]); err != nil { + return err + } + } + + t.AppendOp(code.OpCall) + t.AppendInt(int64(len(args))) + + return nil +} + func (comp *Compiler) compileSubscriptionExpr(t *code.Builder, expr ast.ExprSubscription) error { if err := comp.compileExpr(t, expr.Obj); err != nil { return err @@ -781,6 +893,11 @@ func (comp *Compiler) compileIdentExpr(t *code.Builder, expr ast.ExprIdent) erro t.AppendOp(code.OpGetEnv) t.AppendInt(int64(symbol.Data().IndexInEnv())) + case scope.SymbolKindGlobal: + symbol := comp.scopes.GetGlobal(symbolId) + + t.AppendOp(code.OpGetGlobal) + t.AppendString(symbol.Data().ID()) default: panic(fmt.Errorf("unknown symbol kind: %v", symbolId.SymbolKind())) } @@ -890,3 +1007,7 @@ func (comp *Compiler) exitScopeAndCleanStack(t *code.Builder) { t.AppendInt(int64(stackSpace)) } } + +func (comp *Compiler) areWeCompilingCore() bool { + return modules.NewRef(comp.author, comp.name) == modules.CoreModuleRef +} |
