diff --git a/slox/Interpreter.swift b/slox/Interpreter.swift index f962cbd..3d927fd 100644 --- a/slox/Interpreter.swift +++ b/slox/Interpreter.swift @@ -279,13 +279,13 @@ class Interpreter { break } catch JumpType.continue { if let incrementExpr { - let _ = try evaluate(expr: incrementExpr) + _ = try evaluate(expr: incrementExpr) } continue } if let incrementExpr { - let _ = try evaluate(expr: incrementExpr) + _ = try evaluate(expr: incrementExpr) } } } diff --git a/slox/Resolver.swift b/slox/Resolver.swift index 4ee8df3..c8c32b5 100644 --- a/slox/Resolver.swift +++ b/slox/Resolver.swift @@ -105,9 +105,12 @@ struct Resolver { methods: [Statement], staticMethods: [Statement]) throws -> ResolvedStatement { let previousClassType = currentClassType + let previousLoopType = currentLoopType currentClassType = .class + currentLoopType = .none defer { currentClassType = previousClassType + currentLoopType = previousLoopType } try declareVariable(name: nameToken.lexeme) @@ -421,10 +424,13 @@ struct Resolver { functionType: FunctionType) throws -> ResolvedExpression { beginScope() let previousFunctionType = currentFunctionType + let previousLoopType = currentLoopType currentFunctionType = functionType + currentLoopType = .none defer { endScope() currentFunctionType = previousFunctionType + currentLoopType = previousLoopType } for param in params { diff --git a/sloxTests/ResolverTests.swift b/sloxTests/ResolverTests.swift index 0eeb482..196157a 100644 --- a/sloxTests/ResolverTests.swift +++ b/sloxTests/ResolverTests.swift @@ -465,4 +465,37 @@ final class ResolverTests: XCTestCase { XCTAssertEqual(actualError as! ResolverError, expectedError) } } + + func testResolveBreakStatementFunctionInsideWhileLoop() throws { + // while (true) { + // fun foo() { + // break; + // } + // foo(); + //} + let statements: [Statement] = [ + .while( + .literal(.boolean(true)), + .block([ + .function( + Token(type: .identifier, lexeme: "foo", line: 2), + .lambda( + [], + [ + .break(Token(type: .break, lexeme: "break", line: 3)) + ])), + .expression( + .call( + .variable(Token(type: .identifier, lexeme: "foo", line: 5)), + Token(type: .rightParen, lexeme: ")", line: 5), + [])) + ])) + ] + + var resolver = Resolver() + let expectedError = ResolverError.cannotBreakOutsideLoop + XCTAssertThrowsError(try resolver.resolve(statements: statements)) { actualError in + XCTAssertEqual(actualError as! ResolverError, expectedError) + } + } }