diff --git a/slox/Interpreter.swift b/slox/Interpreter.swift index 3d927fd..24910b7 100644 --- a/slox/Interpreter.swift +++ b/slox/Interpreter.swift @@ -384,13 +384,20 @@ class Interpreter { return .string(leftString + rightString) } + if case .instance(let leftList as LoxList) = leftValue, + case .instance(let rightList as LoxList) = rightValue, + case .plus = oper.type { + let newElements = leftList.elements + rightList.elements + return try makeList(elements: newElements) + } + switch oper.type { case .bangEqual: return .boolean(!leftValue.isEqual(to: rightValue)) case .equalEqual: return .boolean(leftValue.isEqual(to: rightValue)) case .plus: - throw RuntimeError.binaryOperandsMustBeNumbersOrStrings + throw RuntimeError.binaryOperandsMustBeNumbersOrStringsOrLists case .minus, .star, .slash, .greater, .greaterEqual, .less, .lessEqual: throw RuntimeError.binaryOperandsMustBeNumbers default: @@ -518,13 +525,7 @@ class Interpreter { return try evaluate(expr: element) } - guard case .instance(let listClass as LoxClass) = try environment.getValue(name: "List") else { - // TODO: Do we need throw an exception here? - fatalError() - } - - let list = LoxList(elements: elementValues, klass: listClass) - return .instance(list) + return try makeList(elements: elementValues) } private func handleSubscriptGetExpression(listExpr: ResolvedExpression, @@ -556,4 +557,13 @@ class Interpreter { list[Int(index)] = value return value } + + private func makeList(elements: [LoxValue]) throws -> LoxValue { + guard case .instance(let listClass as LoxClass) = try environment.getValue(name: "List") else { + fatalError() + } + + let list = LoxList(elements: elements, klass: listClass) + return .instance(list) + } } diff --git a/slox/RuntimeError.swift b/slox/RuntimeError.swift index 14d9dc4..2cf3a2e 100644 --- a/slox/RuntimeError.swift +++ b/slox/RuntimeError.swift @@ -11,7 +11,7 @@ enum RuntimeError: CustomStringConvertible, Equatable, LocalizedError { case unaryOperandMustBeNumber case unsupportedUnaryOperator case binaryOperandsMustBeNumbers - case binaryOperandsMustBeNumbersOrStrings + case binaryOperandsMustBeNumbersOrStringsOrLists case unsupportedBinaryOperator case undefinedVariable(String) case notAFunctionDeclaration @@ -34,8 +34,8 @@ enum RuntimeError: CustomStringConvertible, Equatable, LocalizedError { return "Error: unsupported unary operator" case .binaryOperandsMustBeNumbers: return "Error: operands must be both numbers" - case .binaryOperandsMustBeNumbersOrStrings: - return "Error: operands must be either both numbers or both strings" + case .binaryOperandsMustBeNumbersOrStringsOrLists: + return "Error: operands must be either both numbers, strings, or lists" case .unsupportedBinaryOperator: return "Error: unsupported binary operator" case .undefinedVariable(let name): diff --git a/sloxTests/InterpreterTests.swift b/sloxTests/InterpreterTests.swift index 52a8130..e36fb4c 100644 --- a/sloxTests/InterpreterTests.swift +++ b/sloxTests/InterpreterTests.swift @@ -479,6 +479,29 @@ quux.count XCTAssertEqual(actual, expected) } + func testInterpretAddingTwoLists() throws { + let input = """ +var xyzzy = [1, 2, 3] + [4, 5, 6]; +xyzzy +""" + + let interpreter = Interpreter() + guard case .instance(let list as LoxList) = try interpreter.interpretRepl(source: input) else { + XCTFail() + return + } + let actual = list.elements + let expected: [LoxValue] = [ + .number(1), + .number(2), + .number(3), + .number(4), + .number(5), + .number(6), + ] + XCTAssertEqual(actual, expected) + } + func testInterpretExpressionWithListSubscriptingMethodInvocationAndPropertyGetting() throws { let input = """ class Foo { }