diff options
Diffstat (limited to 'pkg/lang/compiler/compiler.go')
| -rw-r--r-- | pkg/lang/compiler/compiler.go | 231 |
1 files changed, 125 insertions, 106 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go index 116db1c..a31ade7 100644 --- a/pkg/lang/compiler/compiler.go +++ b/pkg/lang/compiler/compiler.go @@ -31,7 +31,7 @@ func (comp *Compiler) Compile() (code.Code, error) { target.AppendOp(code.OpHalt) - return target.Build(), nil + return target.Build() } func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { @@ -39,6 +39,12 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { switch stmt.Kind { case ast.StmtKindEmpty: // Do nothing. + case ast.StmtKindUse: + panic("use statements not implemented") + case ast.StmtKindFnDecl: + panic("function declaration statements not implemented") + case ast.StmtKindObjectDecl: + panic("object declaration statements not implemented") case ast.StmtKindVarDecl: decl := stmt.Value.(ast.StmtVarDecl) err = comp.compileVarDeclStmt(t, decl) @@ -51,11 +57,21 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { case ast.StmtKindForIn: forCondIn := stmt.Value.(ast.StmtForIn) err = comp.compileForInStmt(t, forCondIn) + case ast.StmtKindTry: + panic("try statements not implemented") + case ast.StmtKindReturn: + panic("return statements not implemented") + case ast.StmtKindContinue: + panic("continue statements not implemented") + case ast.StmtKindBreak: + panic("break statements not implemented") + case ast.StmtKindThrow: + panic("throw statements not implemented") case ast.StmtKindExpr: expr := stmt.Value.(ast.StmtExpr).Value err = comp.compileExpr(t, expr) default: - panic(fmt.Errorf("statement of kind %v not implemented", stmt.Kind)) + panic(fmt.Errorf("unknown statement kind: %d", stmt.Kind)) } return err @@ -90,54 +106,56 @@ func (comp *Compiler) compileIfStmt(t *code.Builder, ifStmt ast.StmtIf) error { // preventing other CondNodes from running. This is missing from the last CondNode. // Example: `jmp @end` - subUnits := make([]code.Builder, 0, len(ifStmt.Conds)) + // First we create all the markers we'll need for the if statement + parentMarker := comp.scopes.CreateAnonymousFunctionSubUnit() - totalLength := 0 + endMarker := parentMarker.SubMarker("end") + + condMarkers := make([]code.Marker, 0, len(ifStmt.Conds)-1) // We don't need a marker for the first CondNode. + for i := 0; i < len(ifStmt.Conds)-1; i++ { + condMarker := parentMarker.SubMarker("cond_%d", i+1) + condMarkers = append(condMarkers, condMarker) + } for i, cond := range ifStmt.Conds { - // Then block - thenTarget := code.NewBuilder() - if err := comp.compileBlockNode(&thenTarget, cond.Then); err != nil { - return err - } + isFirst := i == 0 + isLast := i == len(ifStmt.Conds)-1 - totalLength += thenTarget.Len() - if i != len(ifStmt.Conds)-1 { - totalLength += lengthOfAJumpInstruction + // If we aren't in the first CondNode, the node before it needs a marker to here. + if !isFirst { + marker := condMarkers[i-1] + t.PutMarker(marker) } - // Condition check - conditionTarget := code.NewBuilder() if !cond.Cond.IsEmpty() { - if err := comp.compileExpr(&conditionTarget, cond.Cond); err != nil { + // Condition check + if err := comp.compileExpr(t, cond.Cond); err != nil { return err } - totalLength += conditionTarget.Len() + lengthOfAJumpInstruction // condjmp - - conditionTarget.AppendOp(code.OpJf) // Condition jump - conditionTarget.AppendReferenceToPc(int64(totalLength)) + t.AppendOp(code.OpJf) + if isLast { + t.AppendMarkerReference(endMarker) + } else { + nextCondMarker := condMarkers[i] + t.AppendMarkerReference(nextCondMarker) + } } - subUnit := conditionTarget - subUnit.AppendBuilder(thenTarget) - subUnits = append(subUnits, subUnit) - } - - result := code.NewBuilder() - - // Then jumps - for i, subUnit := range subUnits { - if i != len(ifStmt.Conds)-1 { - subUnit.AppendOp(code.OpJmp) - subUnit.AppendReferenceToPc(int64(totalLength)) + // Then block + if err := comp.compileBlockNode(t, cond.Then); err != nil { + return err } - result.AppendBuilderWithoutAdjustingReferences(subUnit) + // Then jump + if !isLast { + t.AppendOp(code.OpJmp) + t.AppendMarkerReference(endMarker) + } } - t.AppendBuilder(result) + t.PutMarker(endMarker) return nil } @@ -149,34 +167,34 @@ func (comp *Compiler) compileForCondStmt(t *code.Builder, forCondStmt ast.StmtFo // 3. Do block: Does something // 4. Repeat jump: Jumps back to start - // Do block - doTarget := code.NewBuilder() - if err := comp.compileBlockNode(&doTarget, forCondStmt.Do); err != nil { - return err - } + parentMarker := comp.scopes.CreateAnonymousFunctionSubUnit() + + startMarker := parentMarker.SubMarker("start") + endMarker := parentMarker.SubMarker("end") + + t.PutMarker(startMarker) - conditionTarget := code.NewBuilder() if !forCondStmt.Cond.IsEmpty() { // Condition check - if err := comp.compileExpr(&conditionTarget, forCondStmt.Cond); err != nil { + if err := comp.compileExpr(t, forCondStmt.Cond); err != nil { return err } - endOfFor := conditionTarget.Len() + doTarget.Len() + lengthOfAJumpInstruction*2 - - // Condition jump - conditionTarget.AppendOp(code.OpJf) - conditionTarget.AppendReferenceToPc(int64(endOfFor)) + // Condition check + t.AppendOp(code.OpJf) + t.AppendMarkerReference(endMarker) } - subUnit := conditionTarget - subUnit.AppendBuilder(doTarget) + // Do block + if err := comp.compileBlockNode(t, forCondStmt.Do); err != nil { + return err + } // Repeat jump - subUnit.AppendOp(code.OpJmp) - subUnit.AppendReferenceToPc(int64(0)) // Start of the for + t.AppendOp(code.OpJmp) + t.AppendMarkerReference(startMarker) - t.AppendBuilder(subUnit) + t.PutMarker(endMarker) return nil } @@ -216,88 +234,81 @@ func (comp *Compiler) compileForInStmt(t *code.Builder, forInStmt ast.StmtForIn) // @end: // halt + parentMarker := comp.scopes.CreateAnonymousFunctionSubUnit() + + checkMarker := parentMarker.SubUnit("check") + endMarker := parentMarker.SubUnit("end") + // Preparation - preparationTarget := code.NewBuilder() - if err := comp.compileExpr(&preparationTarget, forInStmt.Collection); err != nil { + if err := comp.compileExpr(t, forInStmt.Collection); err != nil { return err } collectionLocal := comp.scopes.DeclareAnonymous() - preparationTarget.AppendOp(code.OpPushInt) - preparationTarget.AppendInt(0) + t.AppendOp(code.OpPushInt) + t.AppendInt(0) iLocal := comp.scopes.DeclareAnonymous() - preparationTarget.AppendOp(code.OpPushNull) + t.AppendOp(code.OpPushNull) nameLocal, ok := comp.scopes.Declare(forInStmt.Name.Value) if !ok { return fmt.Errorf("variable %s already declared", forInStmt.Name.Value) } // Condition check - conditionTarget := code.NewBuilder() + t.PutMarker(checkMarker) - conditionTarget.AppendOp(code.OpGetLocal) - conditionTarget.AppendInt(int64(iLocal)) + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(iLocal)) - conditionTarget.AppendOp(code.OpGetLocal) - conditionTarget.AppendInt(int64(collectionLocal)) + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(collectionLocal)) - conditionTarget.AppendOp(code.OpGetMember) - conditionTarget.AppendString("length") + t.AppendOp(code.OpGetMember) + t.AppendString("length") - conditionTarget.AppendOp(code.OpCall) - conditionTarget.AppendInt(0) + t.AppendOp(code.OpCall) + t.AppendInt(0) - conditionTarget.AppendOp(code.OpLt) + t.AppendOp(code.OpLt) - // Do Preparation - doPreparationTarget := code.NewBuilder() + // Condition jump + t.AppendOp(code.OpJf) + t.AppendMarkerReference(endMarker) - doPreparationTarget.AppendOp(code.OpGetLocal) - doPreparationTarget.AppendInt(int64(collectionLocal)) + // Do Preparation + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(collectionLocal)) - doPreparationTarget.AppendOp(code.OpGetLocal) - doPreparationTarget.AppendInt(int64(iLocal)) + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(iLocal)) - doPreparationTarget.AppendOp(code.OpIndex) + t.AppendOp(code.OpIndex) - doPreparationTarget.AppendOp(code.OpSetLocal) - doPreparationTarget.AppendInt(int64(nameLocal)) + t.AppendOp(code.OpSetLocal) + t.AppendInt(int64(nameLocal)) - doPreparationTarget.AppendOp(code.OpGetLocal) - doPreparationTarget.AppendInt(int64(iLocal)) + t.AppendOp(code.OpGetLocal) + t.AppendInt(int64(iLocal)) - doPreparationTarget.AppendOp(code.OpPushInt) - doPreparationTarget.AppendInt(1) + t.AppendOp(code.OpPushInt) + t.AppendInt(1) - doPreparationTarget.AppendOp(code.OpAdd) + t.AppendOp(code.OpAdd) - doPreparationTarget.AppendOp(code.OpSetLocal) - doPreparationTarget.AppendInt(int64(iLocal)) + t.AppendOp(code.OpSetLocal) + t.AppendInt(int64(iLocal)) // Do block - doTarget := code.NewBuilder() - if err := comp.compileBlockNode(&doTarget, forInStmt.Do); err != nil { + if err := comp.compileBlockNode(t, forInStmt.Do); err != nil { return err } - // Condition Jump - - endOfFor := preparationTarget.Len() + conditionTarget.Len() + doPreparationTarget.Len() + doTarget.Len() + lengthOfAJumpInstruction*2 - - conditionTarget.AppendOp(code.OpJf) - conditionTarget.AppendReferenceToPc(int64(endOfFor)) - - subUnit := preparationTarget - subUnit.AppendBuilderWithoutAdjustingReferences(conditionTarget) - subUnit.AppendBuilder(doPreparationTarget) - subUnit.AppendBuilder(doTarget) - // Repeat jump - subUnit.AppendOp(code.OpJmp) - subUnit.AppendReferenceToPc(int64(preparationTarget.Len())) + t.AppendOp(code.OpJmp) + t.AppendMarkerReference(checkMarker) - t.AppendBuilder(subUnit) + t.PutMarker(endMarker) return nil } @@ -389,17 +400,23 @@ func (comp *Compiler) compileAssignExpr(t *code.Builder, expr ast.ExprBinary) er } name := expr.Left.Value.(ast.ExprIdent).Value.Value - symbol, ok := comp.scopes.Lookup(name) + symbolId, ok := comp.scopes.Lookup(name) if !ok { return fmt.Errorf("variable %s not declared", name) } + if symbolId.symbolKind != SymbolKindVariable { + return fmt.Errorf("can't assign to a %v", symbolId.symbolKind) + } + + symbol := comp.scopes.GetVariable(symbolId) + if err := comp.compileExpr(t, expr.Right); err != nil { return err } t.AppendOp(code.OpSetLocal) - t.AppendInt(int64(symbol.localIndex)) + t.AppendInt(int64(symbol.data.localIndex)) return nil } @@ -478,14 +495,20 @@ func (comp *Compiler) compileArrayLitExpr(t *code.Builder, expr ast.ExprArrayLit } func (comp *Compiler) compileIdentExpr(t *code.Builder, expr ast.ExprIdent) error { - symbol, ok := comp.scopes.Lookup(expr.Value.Value) + symbolId, ok := comp.scopes.Lookup(expr.Value.Value) if !ok { return fmt.Errorf("undefined symbol %s", expr.Value.Value) } + if symbolId.symbolKind != SymbolKindVariable { + return fmt.Errorf("%v values are not implemeted yet", symbolId.symbolKind) + } + + symbol := comp.scopes.GetVariable(symbolId) + // TODO: Add boundries to check how the symbol should be fetched. (local, env, global, etc.) t.AppendOp(code.OpGetLocal) - t.AppendInt(int64(symbol.localIndex)) + t.AppendInt(int64(symbol.data.localIndex)) return nil } @@ -531,7 +554,3 @@ func (comp *Compiler) compileBlockNode(t *code.Builder, block ast.BlockNode) err return nil } - -const ( - lengthOfAJumpInstruction = 9 // The length of a jump Op (jmp, jf, jt) and it's following 64-bit integer. -) |
