From 18b15784f2744174f48d40d0fab65e747dc6b57d Mon Sep 17 00:00:00 2001 From: quephird Date: Sun, 17 Mar 2024 13:50:06 -0700 Subject: [PATCH] Resolver now catches edge case that Becca pointed out to me. --- slox/Interpreter.swift | 4 ++-- slox/Resolver.swift | 6 ++++++ sloxTests/ResolverTests.swift | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) 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) + } + } }