Skip to content

Commit

Permalink
Merge pull request #3 from quephird/reinstitute_interpreter_tests
Browse files Browse the repository at this point in the history
Reinstitute interpreter tests
  • Loading branch information
quephird committed Mar 1, 2024
2 parents 6c93ee6 + e67808a commit 062881d
Show file tree
Hide file tree
Showing 2 changed files with 253 additions and 67 deletions.
2 changes: 1 addition & 1 deletion slox/Interpreter.swift
Expand Up @@ -6,7 +6,7 @@
//

struct Interpreter {
private var environment: Environment = Environment()
var environment: Environment = Environment()

mutating func interpret(statements: [Statement]) throws {
for statement in statements {
Expand Down
318 changes: 252 additions & 66 deletions sloxTests/InterpreterTests.swift
Expand Up @@ -8,113 +8,299 @@
import XCTest

final class InterpreterTests: XCTestCase {
/*
func testInterpretStringLiteralExpression() throws {
let expr: Expression = .literal(.string("forty-two"))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .string("forty-two")
let stmt: Statement = .expression(.literal(.string("forty-two")))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])!
let expected: LoxValue = .string("forty-two")
XCTAssertEqual(actual, expected)
}

func testInterpretNumericLiteralExpression() throws {
let expr: Expression = .literal(.number(42))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .number(42)
let stmt: Statement = .expression(.literal(.number(42)))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])!
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretGroupingExpression() throws {
let expr: Expression = .grouping(.literal(.number(42)))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .number(42)
let stmt: Statement = .expression(.grouping(.literal(.number(42))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])!
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretUnaryExpression() throws {
let expr: Expression = .unary(
Token(type: .bang, lexeme: "!", line: 1),
.literal(.boolean(true)))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .boolean(false)
let stmt: Statement =
.expression(
.unary(
Token(type: .bang, lexeme: "!", line: 1),
.literal(.boolean(true))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])
let expected: LoxValue = .boolean(false)
XCTAssertEqual(actual, expected)
}

func testInterpretInvalidUnaryExpression() throws {
let expr: Expression = .unary(
Token(type: .minus, lexeme: "-", line: 1),
.literal(.string("forty-two")))
let interpreter = Interpreter()
let stmt: Statement =
.expression(
.unary(
Token(type: .minus, lexeme: "-", line: 1),
.literal(.string("forty-two"))))
var interpreter = Interpreter()

let expectedError = RuntimeError.unaryOperandMustBeNumber
XCTAssertThrowsError(try interpreter.interpret(expr: expr)) { actualError in
XCTAssertThrowsError(try interpreter.interpretRepl(statements: [stmt])!) { actualError in
XCTAssertEqual(actualError as! RuntimeError, expectedError)
}
}

func testInterpretNumericBinaryExpression() throws {
let expr: Expression = .binary(
.literal(.number(21)),
Token(type: .star, lexeme: "*", line: 1),
.literal(.number(2)))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .number(42)
let stmt: Statement =
.expression(
.binary(
.literal(.number(21)),
Token(type: .star, lexeme: "*", line: 1),
.literal(.number(2))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])!
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretStringlyBinaryExpression() throws {
let expr: Expression = .binary(
.literal(.string("forty")),
Token(type: .plus, lexeme: "+", line: 1),
.literal(.string("-two")))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .string("forty-two")
let stmt: Statement =
.expression(
.binary(
.literal(.string("forty")),
Token(type: .plus, lexeme: "+", line: 1),
.literal(.string("-two"))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])
let expected: LoxValue = .string("forty-two")
XCTAssertEqual(actual, expected)
}

func testInterpretEqualityExpression() throws {
let expr: Expression = .binary(
.literal(.boolean(true)),
Token(type: .bangEqual, lexeme: "!=", line: 1),
.literal(.boolean(false)))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .boolean(true)
let stmt: Statement =
.expression(
.binary(
.literal(.boolean(true)),
Token(type: .bangEqual, lexeme: "!=", line: 1),
.literal(.boolean(false))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])!
let expected: LoxValue = .boolean(true)
XCTAssertEqual(actual, expected)
}

func testInterpretInvalidBinaryExpression() throws {
let expr: Expression = .binary(
.literal(.string("twenty-one")),
Token(type: .star, lexeme: "*", line: 1),
.literal(.number(2)))
let interpreter = Interpreter()
let stmt: Statement =
.expression(
.binary(
.literal(.string("twenty-one")),
Token(type: .star, lexeme: "*", line: 1),
.literal(.number(2))))
var interpreter = Interpreter()

let expectedError = RuntimeError.binaryOperandsMustBeNumbers
XCTAssertThrowsError(try interpreter.interpret(expr: expr)) { actualError in
XCTAssertThrowsError(try interpreter.interpretRepl(statements: [stmt])!) { actualError in
XCTAssertEqual(actualError as! RuntimeError, expectedError)
}
}

func testInterpretComplexExpression() throws {
let expr: Expression = .binary(
.grouping(.unary(
Token(type: .minus, lexeme: "-", line: 1),
.literal(.number(2)))),
Token(type: .star, lexeme: "*", line: 1),
.grouping(.binary(
.literal(.number(3)),
Token(type: .plus, lexeme: "+", line: 1),
.literal(.number(4)))))
let interpreter = Interpreter()
let actual = try interpreter.interpret(expr: expr)
let expected: Literal = .number(-14)
XCTAssertEqual(actual, expected)
}
*/
let stmt: Statement =
.expression(
.binary(
.grouping(.unary(
Token(type: .minus, lexeme: "-", line: 1),
.literal(.number(2)))),
Token(type: .star, lexeme: "*", line: 1),
.grouping(.binary(
.literal(.number(3)),
Token(type: .plus, lexeme: "+", line: 1),
.literal(.number(4))))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])
let expected: LoxValue = .number(-14)
XCTAssertEqual(actual, expected)
}

func testInterpretLogicalExpression() throws {
let stmt: Statement =
.expression(
.logical(
.logical(
.literal(.boolean(true)),
Token(type: .and, lexeme: "and", line: 1),
.literal(.boolean(false))),
Token(type: .or, lexeme: "or", line: 1),
.literal(.boolean(true))))
var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])
let expected: LoxValue = .boolean(true)
XCTAssertEqual(actual, expected)
}

func testInterpretComparisonExpression() throws {
let stmt: Statement =
.expression(
.binary(
.literal(.number(10)),
Token(type: .less, lexeme: "<", line: 1),
.literal(.number(20))))

var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: [stmt])
let expected: LoxValue = .boolean(true)
XCTAssertEqual(actual, expected)
}

func testInterpretVariableDeclaration() throws {
let stmt: Statement =
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.number(42)))

var interpreter = Interpreter()
let _ = try interpreter.interpretRepl(statements: [stmt])
let environment = interpreter.environment
let actual = try environment.getValue(name: "theAnswer")
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretCompoundStatementInvolvingAVariable() throws {
// var theAnswer; theAnswer = 42; theAnswer
let statements: [Statement] = [
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.nil)),
.expression(
.assignment(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.number(42)))),
.expression(
.variable(
Token(type: .identifier, lexeme: "theAnswer", line: 1)))
]

var interpreter = Interpreter()
let actual = try interpreter.interpretRepl(statements: statements)
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretWhileStatement() throws {
// var i = 0;
// while (i < 3) {
// i = i + 1;
// }
let statements: [Statement] = [
.variableDeclaration(
Token(type: .identifier, lexeme: "i", line: 1),
.literal(.number(0))),
.while(
.binary(
.variable(Token(type: .identifier, lexeme: "i", line: 2)),
Token(type: .less, lexeme: "<", line: 2),
.literal(.number(3))),
.expression(
.assignment(
Token(type: .identifier, lexeme: "i", line: 3),
.binary(
.variable(Token(type: .identifier, lexeme: "i", line: 3)),
Token(type: .plus, lexeme: "+", line: 3),
.literal(.number(1)))))),
]
var interpreter = Interpreter()
let _ = try interpreter.interpretRepl(statements: statements)
let environment = interpreter.environment
let actual = try environment.getValue(name: "i")
let expected: LoxValue = .number(3)
XCTAssertEqual(actual, expected)
}

func testInterpretIfStatement() throws {
// var x;
// if (true)
// x = 42;
// else
// x = 0;
let statements: [Statement] = [
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
nil),
.if(
.literal(.boolean(true)),
.expression(
.assignment(
Token(type: .identifier, lexeme: "theAnswer", line: 3),
.literal(.number(42)))),
.expression(
.assignment(
Token(type: .identifier, lexeme: "theAnswer", line: 3),
.literal(.number(0))))),
]
var interpreter = Interpreter()
let _ = try interpreter.interpretRepl(statements: statements)
let environment = interpreter.environment
let actual = try environment.getValue(name: "theAnswer")
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretBlockStatement() throws {
// var theAnswer = 21
// {
// theAnswer = theAnswer * 2;
// }
let statements: [Statement] = [
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.number(21))),
.block([
.expression(
.assignment(
Token(type: .identifier, lexeme: "theAnswer", line: 3),
.binary(
.variable(Token(type: .identifier, lexeme: "theAnswer", line: 3)),
Token(type: .star, lexeme: "*", line: 3),
.literal(.number(2))))),
])
]
var interpreter = Interpreter()
let _ = try interpreter.interpretRepl(statements: statements)
let environment = interpreter.environment
let actual = try environment.getValue(name: "theAnswer")
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}

func testInterpretShadowingInBlockStatement() throws {
// var theAnswer = 42
// {
// var theAnswer = "forty-two";
// }
let statements: [Statement] = [
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.number(42))),
.block([
.variableDeclaration(
Token(type: .identifier, lexeme: "theAnswer", line: 1),
.literal(.string("forty-two"))),
])
]
var interpreter = Interpreter()
let _ = try interpreter.interpretRepl(statements: statements)
let environment = interpreter.environment
let actual = try environment.getValue(name: "theAnswer")
let expected: LoxValue = .number(42)
XCTAssertEqual(actual, expected)
}
}

0 comments on commit 062881d

Please sign in to comment.