diff options
Diffstat (limited to 'pkg/lang/compiler/compiler.go')
| -rw-r--r-- | pkg/lang/compiler/compiler.go | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go index cad4328..0356411 100644 --- a/pkg/lang/compiler/compiler.go +++ b/pkg/lang/compiler/compiler.go @@ -43,8 +43,11 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { decl := stmt.Value.(ast.StmtVarDecl) err = comp.compileVarDeclStmt(t, decl) case ast.StmtKindIf: - ifstmt := stmt.Value.(ast.StmtIf) - err = comp.compileIfStmt(t, ifstmt) + ifStmt := stmt.Value.(ast.StmtIf) + err = comp.compileIfStmt(t, ifStmt) + case ast.StmtKindForCond: + forCondStmt := stmt.Value.(ast.StmtForCond) + err = comp.compileForCondStmt(t, forCondStmt) case ast.StmtKindExpr: expr := stmt.Value.(ast.StmtExpr).Value err = comp.compileExpr(t, expr) @@ -137,6 +140,47 @@ func (comp *Compiler) compileIfStmt(t *code.Builder, ifStmt ast.StmtIf) error { return nil } +func (comp *Compiler) compileForCondStmt(t *code.Builder, forCondStmt ast.StmtForCond) error { + // Parts: + // 1. Condition check: Decides whether the loop should run + // 2. Condition jump: Jumps to the end of the for if condition was false + // 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 + } + + jmpLength := 9 + + conditionTarget := code.NewBuilder() + if !forCondStmt.Cond.IsEmpty() { + // Condition check + if err := comp.compileExpr(&conditionTarget, forCondStmt.Cond); err != nil { + return err + } + + endOfFor := conditionTarget.Len() + doTarget.Len() + jmpLength*2 + + // Condition jump + conditionTarget.AppendOp(code.OpJf) + conditionTarget.AppendReferenceToPc(int64(endOfFor)) + } + + subUnit := conditionTarget + subUnit.AppendBuilder(doTarget) + + // Repeat jump + subUnit.AppendOp(code.OpJmp) + subUnit.AppendReferenceToPc(int64(0)) // Start of the for + + t.AppendBuilder(subUnit) + + return nil +} + func (comp *Compiler) compileExpr(t *code.Builder, expr ast.Expr) error { switch expr.Kind { case ast.ExprKindBinary: |
