You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
3.6 KiB

  1. //
  2. // Parser.swift
  3. // Kaleidoscope
  4. //
  5. // Created by Matthew Cheok on 15/11/15.
  6. // Copyright © 2015 Matthew Cheok. All rights reserved.
  7. //
  8. import Foundation
  9. public enum ParseError: Error {
  10. case unexpectToken
  11. case undefinedOperator(String)
  12. case expectCharacter(Character)
  13. case expectExpression
  14. case expectArgumentList
  15. case expectFunctionName
  16. }
  17. public class Parser {
  18. let tokens: [Token]
  19. var index = 0
  20. public init(tokens: [Token]) {
  21. self.tokens = tokens
  22. }
  23. func peekCurrentToken() -> Token {
  24. if index >= tokens.count {
  25. return .other("", 0..<0)
  26. }
  27. return tokens[index]
  28. }
  29. @discardableResult func popCurrentToken() -> Token {
  30. defer { index += 1 }
  31. return tokens[index]
  32. }
  33. func parseNumber() throws -> ExprNode {
  34. guard case let .number(value, _) = popCurrentToken() else {
  35. throw ParseError.unexpectToken
  36. }
  37. return NumberNode(value: value)
  38. }
  39. func parseExpression() throws -> ExprNode {
  40. let node = try parsePrimary()
  41. return try parseBinaryOp(node: node)
  42. }
  43. func parseParens() throws -> ExprNode {
  44. guard case .parensOpen = popCurrentToken() else {
  45. throw ParseError.expectCharacter("(")
  46. }
  47. let exp = try parseExpression()
  48. guard case .parensClose = popCurrentToken() else {
  49. throw ParseError.expectCharacter(")")
  50. }
  51. return exp
  52. }
  53. func parseIdentifier() throws -> ExprNode {
  54. guard case let .identifier(name, _) = popCurrentToken() else {
  55. throw ParseError.unexpectToken
  56. }
  57. guard case .parensOpen = peekCurrentToken() else {
  58. return VariableNode(name: name)
  59. }
  60. popCurrentToken()
  61. var arguments = [ExprNode]()
  62. if case .parensClose = peekCurrentToken() {
  63. } else {
  64. while true {
  65. let argument = try parseExpression()
  66. arguments.append(argument)
  67. if case .parensClose = peekCurrentToken() {
  68. break
  69. }
  70. guard case .comma = popCurrentToken() else {
  71. throw ParseError.expectArgumentList
  72. }
  73. }
  74. }
  75. popCurrentToken()
  76. return CallNode(name: name, arguments: arguments)
  77. }
  78. func parsePrimary() throws -> ExprNode {
  79. switch peekCurrentToken() {
  80. case .identifier:
  81. return try parseIdentifier()
  82. case .number:
  83. return try parseNumber()
  84. case .parensOpen:
  85. return try parseParens()
  86. default:
  87. throw ParseError.expectExpression
  88. }
  89. }
  90. let operatorPrecedence: [String: Int] = [
  91. "+": 20,
  92. "-": 20,
  93. "*": 40,
  94. "/": 40
  95. ]
  96. func getCurrentTokenPrecedence() throws -> Int {
  97. guard index < tokens.count else {
  98. return -1
  99. }
  100. guard case let .other(op, _) = peekCurrentToken() else {
  101. return -1
  102. }
  103. guard let precedence = operatorPrecedence[op] else {
  104. throw ParseError.undefinedOperator(op)
  105. }
  106. return precedence
  107. }
  108. func parseBinaryOp(node: ExprNode, exprPrecedence: Int = 0) throws -> ExprNode {
  109. var lhs = node
  110. while true {
  111. let tokenPrecedence = try getCurrentTokenPrecedence()
  112. if tokenPrecedence < exprPrecedence {
  113. return lhs
  114. }
  115. guard case let .other(op, _) = popCurrentToken() else {
  116. throw ParseError.unexpectToken
  117. }
  118. var rhs = try parsePrimary()
  119. let nextPrecedence = try getCurrentTokenPrecedence()
  120. if tokenPrecedence < nextPrecedence {
  121. rhs = try parseBinaryOp(node: rhs, exprPrecedence: tokenPrecedence+1)
  122. }
  123. lhs = BinaryOpNode(name: op, lhs: lhs, rhs: rhs)
  124. }
  125. }
  126. public func parse() throws -> [ExprNode] {
  127. index = 0
  128. var nodes = [ExprNode]()
  129. while index < tokens.count {
  130. let expr = try parsePrimary()
  131. nodes.append(expr)
  132. }
  133. return nodes
  134. }
  135. }