Skip to content

Commit

Permalink
✨ adding support for unary operations
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkulman committed Dec 8, 2017
1 parent 20ba190 commit d6fdec5
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 1 deletion.
1 change: 1 addition & 0 deletions SwiftPascalInterpreter/SwiftPascalInterpreter/AST.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ import Foundation

public enum AST {
case number(Int)
indirect case unaryOperation(operation: Operation, child: AST)
indirect case binaryOperation(left: AST, operation: Operation, right: AST)
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ extension AST: CustomStringConvertible {
switch node {
case let .number(value):
return ("\(value)", nil, nil)
case let .unaryOperation(operation: operation, child: child):
return ("u\(operation.shortDescription)", child, nil)
case let .binaryOperation(left: left, operation: operation, right: right):
return ("\(operation.shortDescription)", left, right)
}
Expand All @@ -133,6 +135,8 @@ extension AST: Equatable {
switch (lhs, rhs) {
case let (.number(left), .number(right)):
return left == right
case let (.unaryOperation(operation: leftOperation, child: leftChild), .unaryOperation(operation: rightOperation, child: rightChild)):
return leftOperation == rightOperation && leftChild == rightChild
case let (.binaryOperation(left: leftLeft, operation: leftOperation, right: leftRight), .binaryOperation(left: rightLeft, operation: rightOperation, right: rightRight)):
return leftLeft == rightLeft && leftOperation == rightOperation && leftRight == rightRight
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ public class Interpreter {
switch node {
case let .number(value):
return value
case let .unaryOperation(operation: operation, child: child):
switch operation {
case .plus:
return +visit(child)
case .minus:
return -visit(child)
default:
fatalError("Unsupported unary operation \(operation)")
}
case let .binaryOperation(left: left, operation: operation, right: right):
switch operation {
case .plus:
Expand Down
4 changes: 4 additions & 0 deletions SwiftPascalInterpreter/SwiftPascalInterpreter/Notations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class RPN: Notation {
switch node {
case let .number(value):
return "\(value)"
case let .unaryOperation(operation: operation, child: child):
return "\(visit(child)) \(operation.shortDescription)"
case let .binaryOperation(left: left, operation: operation, right: right):
return "\(visit(left)) \(visit(right)) \(operation.shortDescription)"
}
Expand All @@ -56,6 +58,8 @@ public class LISPNotation: Notation {
switch node {
case let .number(value):
return "\(value)"
case let .unaryOperation(operation: operation, child: child):
return "(\(operation.shortDescription) \(visit(child)))"
case let .binaryOperation(left: left, operation: operation, right: right):
return "(\(operation.shortDescription) \(visit(left)) \(visit(right)))"
}
Expand Down
8 changes: 7 additions & 1 deletion SwiftPascalInterpreter/SwiftPascalInterpreter/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ public class Parser {
let result = expr()
eat(.parenthesis(.right))
return result
case .operation(.plus):
eat(.operation(.plus))
return .unaryOperation(operation: .plus, child: factor())
case .operation(.minus):
eat(.operation(.minus))
return .unaryOperation(operation: .minus, child: factor())
default:
fatalError("Syntax error")
}
Expand Down Expand Up @@ -78,7 +84,7 @@ public class Parser {
expr : term (PLUS | MINUS) term)*
term : factor ((MUL | DIV) factor)*
factor : INTEGER | LPAREN factor RPAREN
factor : (PLUS | MINUS) factor | INTEGER | LPAREN factor RPAREN
Returns: AST node
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ class InterpreterTests: XCTestCase {
XCTAssert(Interpreter("7 + 3 * (10 / (12 / (3 + 1) - 1)) / (2 + 3) - 5 - 3 + (8)").eval() == 10)
XCTAssert(Interpreter("7 + (((3 + 2)))").eval() == 12)
}

func testUnaryOperations() {
let interpeter = Interpreter("5 - - -2")
let result = interpeter.eval()
XCTAssert(result == 3)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,15 @@ class LexerTests: XCTestCase {
XCTAssert(lexer.getNextToken() == .parenthesis(.right))
XCTAssert(lexer.getNextToken() == .eof)
}

func testUnaryOperators() {
let lexer = Lexer("5 - - - 2")

XCTAssert(lexer.getNextToken() == .integer(5))
XCTAssert(lexer.getNextToken() == .operation(.minus))
XCTAssert(lexer.getNextToken() == .operation(.minus))
XCTAssert(lexer.getNextToken() == .operation(.minus))
XCTAssert(lexer.getNextToken() == .integer(2))
XCTAssert(lexer.getNextToken() == .eof)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,15 @@ class ParserTests: XCTestCase {
let result = parser.expr()
XCTAssert(result == node)
}

func testUnaryOperatorNodesNodes() {
let five = AST.number(5)
let two = AST.number(2)
let un1 = AST.unaryOperation(operation: .minus, child: two)
let un2 = AST.unaryOperation(operation: .minus, child: un1)
let node = AST.binaryOperation(left: five, operation: .minus, right: un2)
let parser = Parser("5 - - - 2")
let result = parser.expr()
XCTAssert(result == node)
}
}

0 comments on commit d6fdec5

Please sign in to comment.