about summary refs log tree commit diff
path: root/pkg/lang/compiler/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/compiler/compiler.go')
-rw-r--r--pkg/lang/compiler/compiler.go52
1 files changed, 38 insertions, 14 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go
index ad37ded..4167088 100644
--- a/pkg/lang/compiler/compiler.go
+++ b/pkg/lang/compiler/compiler.go
@@ -88,9 +88,11 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error {
 		returnStmt := stmt.Value.(ast.StmtReturn)
 		err = comp.compileReturnStmt(t, returnStmt)
 	case ast.StmtKindContinue:
-		panic("continue statements not implemented")
+		continueStmt := stmt.Value.(ast.StmtContinue)
+		err = comp.compileContinueStmt(t, continueStmt)
 	case ast.StmtKindBreak:
-		panic("break statements not implemented")
+		breakStmt := stmt.Value.(ast.StmtBreak)
+		err = comp.compileBreakStmt(t, breakStmt)
 	case ast.StmtKindThrow:
 		panic("throw statements not implemented")
 	case ast.StmtKindExpr:
@@ -234,12 +236,9 @@ func (comp *Compiler) compileForCondStmt(t *code.Builder, forCondStmt ast.StmtFo
 	// 3. Do block: Does something
 	// 4. Repeat jump: Jumps back to start
 
-	parentMarker := comp.scopes.CreateAnonymousFunctionSubUnit()
-
-	startMarker := parentMarker.SubMarker("start")
-	endMarker := parentMarker.SubMarker("end")
+	endMarker, repeatMarker := comp.scopes.EnterLoop()
 
-	t.PutMarker(startMarker)
+	t.PutMarker(repeatMarker)
 
 	if !forCondStmt.Cond.IsEmpty() {
 		// Condition check
@@ -259,10 +258,12 @@ func (comp *Compiler) compileForCondStmt(t *code.Builder, forCondStmt ast.StmtFo
 
 	// Repeat jump
 	t.AppendOp(code.OpJmp)
-	t.AppendMarkerReference(startMarker)
+	t.AppendMarkerReference(repeatMarker)
 
 	t.PutMarker(endMarker)
 
+	comp.scopes.Exit()
+
 	return nil
 }
 
@@ -301,10 +302,7 @@ func (comp *Compiler) compileForInStmt(t *code.Builder, forInStmt ast.StmtForIn)
 	// @end:
 	// halt
 
-	parentMarker := comp.scopes.CreateAnonymousFunctionSubUnit()
-
-	checkMarker := parentMarker.SubUnit("check")
-	endMarker := parentMarker.SubUnit("end")
+	endMarker, repeatMarker := comp.scopes.EnterLoop()
 
 	// Preparation
 	if err := comp.compileExpr(t, forInStmt.Collection); err != nil {
@@ -323,7 +321,7 @@ func (comp *Compiler) compileForInStmt(t *code.Builder, forInStmt ast.StmtForIn)
 	}
 
 	// Condition check
-	t.PutMarker(checkMarker)
+	t.PutMarker(repeatMarker)
 
 	t.AppendOp(code.OpGetLocal)
 	t.AppendInt(int64(iLocal))
@@ -373,10 +371,12 @@ func (comp *Compiler) compileForInStmt(t *code.Builder, forInStmt ast.StmtForIn)
 
 	// Repeat jump
 	t.AppendOp(code.OpJmp)
-	t.AppendMarkerReference(checkMarker)
+	t.AppendMarkerReference(repeatMarker)
 
 	t.PutMarker(endMarker)
 
+	comp.scopes.Exit()
+
 	return nil
 }
 
@@ -400,6 +400,30 @@ func (comp *Compiler) compileReturnStmt(t *code.Builder, returnStmt ast.StmtRetu
 	return nil
 }
 
+func (comp *Compiler) compileContinueStmt(t *code.Builder, continueStmt ast.StmtContinue) error {
+	loopScope := comp.scopes.CurrentLoop()
+	if loopScope == nil {
+		return fmt.Errorf("can't continue when not inside a loop")
+	}
+
+	t.AppendOp(code.OpJmp)
+	t.AppendMarkerReference(loopScope.ContinueMarker())
+
+	return nil
+}
+
+func (comp *Compiler) compileBreakStmt(t *code.Builder, breakStmt ast.StmtBreak) error {
+	loopScope := comp.scopes.CurrentLoop()
+	if loopScope == nil {
+		return fmt.Errorf("can't break when not inside a loop")
+	}
+
+	t.AppendOp(code.OpJmp)
+	t.AppendMarkerReference(loopScope.BreakMarker())
+
+	return nil
+}
+
 func (comp *Compiler) compileExpr(t *code.Builder, expr ast.Expr) error {
 	switch expr.Kind {
 	case ast.ExprKindBinary: