@@ -62,6 +62,7 @@ type Execution struct {
6262 capabilityContractsByName map [string ]CapabilityMethodContract
6363 receiverStack []Value
6464 envStack []* Env
65+ loopDepth int
6566 strictEffects bool
6667 allowRequire bool
6768}
@@ -93,6 +94,11 @@ type RuntimeError struct {
9394 Frames []StackFrame
9495}
9596
97+ var (
98+ errLoopBreak = errors .New ("loop break" )
99+ errLoopNext = errors .New ("loop next" )
100+ )
101+
96102func (re * RuntimeError ) Error () string {
97103 var b strings.Builder
98104 b .WriteString (re .Message )
@@ -340,6 +346,16 @@ func (exec *Execution) evalStatement(stmt Statement, env *Env) (Value, bool, err
340346 return exec .evalWhileStatement (s , env )
341347 case * UntilStmt :
342348 return exec .evalUntilStatement (s , env )
349+ case * BreakStmt :
350+ if exec .loopDepth == 0 {
351+ return NewNil (), false , exec .errorAt (s .Pos (), "break used outside of loop" )
352+ }
353+ return NewNil (), false , errLoopBreak
354+ case * NextStmt :
355+ if exec .loopDepth == 0 {
356+ return NewNil (), false , exec .errorAt (s .Pos (), "next used outside of loop" )
357+ }
358+ return NewNil (), false , errLoopNext
343359 default :
344360 return NewNil (), false , exec .errorAt (stmt .Pos (), "unsupported statement" )
345361 }
@@ -1071,6 +1087,11 @@ func (exec *Execution) evalRangeExpr(expr *RangeExpr, env *Env) (Value, error) {
10711087}
10721088
10731089func (exec * Execution ) evalForStatement (stmt * ForStmt , env * Env ) (Value , bool , error ) {
1090+ exec .loopDepth ++
1091+ defer func () {
1092+ exec .loopDepth --
1093+ }()
1094+
10741095 iterable , err := exec .evalExpression (stmt .Iterable , env )
10751096 if err != nil {
10761097 return NewNil (), false , err
@@ -1087,6 +1108,12 @@ func (exec *Execution) evalForStatement(stmt *ForStmt, env *Env) (Value, bool, e
10871108 env .Assign (stmt .Iterator , item )
10881109 val , returned , err := exec .evalStatements (stmt .Body , env )
10891110 if err != nil {
1111+ if errors .Is (err , errLoopBreak ) {
1112+ return last , false , nil
1113+ }
1114+ if errors .Is (err , errLoopNext ) {
1115+ continue
1116+ }
10901117 return NewNil (), false , err
10911118 }
10921119 if returned {
@@ -1101,6 +1128,12 @@ func (exec *Execution) evalForStatement(stmt *ForStmt, env *Env) (Value, bool, e
11011128 env .Assign (stmt .Iterator , NewInt (i ))
11021129 val , returned , err := exec .evalStatements (stmt .Body , env )
11031130 if err != nil {
1131+ if errors .Is (err , errLoopBreak ) {
1132+ return last , false , nil
1133+ }
1134+ if errors .Is (err , errLoopNext ) {
1135+ continue
1136+ }
11041137 return NewNil (), false , err
11051138 }
11061139 if returned {
@@ -1113,6 +1146,12 @@ func (exec *Execution) evalForStatement(stmt *ForStmt, env *Env) (Value, bool, e
11131146 env .Assign (stmt .Iterator , NewInt (i ))
11141147 val , returned , err := exec .evalStatements (stmt .Body , env )
11151148 if err != nil {
1149+ if errors .Is (err , errLoopBreak ) {
1150+ return last , false , nil
1151+ }
1152+ if errors .Is (err , errLoopNext ) {
1153+ continue
1154+ }
11161155 return NewNil (), false , err
11171156 }
11181157 if returned {
@@ -1129,6 +1168,11 @@ func (exec *Execution) evalForStatement(stmt *ForStmt, env *Env) (Value, bool, e
11291168}
11301169
11311170func (exec * Execution ) evalWhileStatement (stmt * WhileStmt , env * Env ) (Value , bool , error ) {
1171+ exec .loopDepth ++
1172+ defer func () {
1173+ exec .loopDepth --
1174+ }()
1175+
11321176 last := NewNil ()
11331177 for {
11341178 if err := exec .step (); err != nil {
@@ -1146,6 +1190,12 @@ func (exec *Execution) evalWhileStatement(stmt *WhileStmt, env *Env) (Value, boo
11461190 }
11471191 val , returned , err := exec .evalStatements (stmt .Body , env )
11481192 if err != nil {
1193+ if errors .Is (err , errLoopBreak ) {
1194+ return last , false , nil
1195+ }
1196+ if errors .Is (err , errLoopNext ) {
1197+ continue
1198+ }
11491199 return NewNil (), false , err
11501200 }
11511201 if returned {
@@ -1156,6 +1206,11 @@ func (exec *Execution) evalWhileStatement(stmt *WhileStmt, env *Env) (Value, boo
11561206}
11571207
11581208func (exec * Execution ) evalUntilStatement (stmt * UntilStmt , env * Env ) (Value , bool , error ) {
1209+ exec .loopDepth ++
1210+ defer func () {
1211+ exec .loopDepth --
1212+ }()
1213+
11591214 last := NewNil ()
11601215 for {
11611216 if err := exec .step (); err != nil {
@@ -1173,6 +1228,12 @@ func (exec *Execution) evalUntilStatement(stmt *UntilStmt, env *Env) (Value, boo
11731228 }
11741229 val , returned , err := exec .evalStatements (stmt .Body , env )
11751230 if err != nil {
1231+ if errors .Is (err , errLoopBreak ) {
1232+ return last , false , nil
1233+ }
1234+ if errors .Is (err , errLoopNext ) {
1235+ continue
1236+ }
11761237 return NewNil (), false , err
11771238 }
11781239 if returned {
0 commit comments