A toy dynamic programming language written in Ruby
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.

parser.rb 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. class Parser
  2. def initialize(lexer)
  3. @lexer = lexer
  4. @current_token = @lexer.get_token
  5. end
  6. def parse
  7. tree = Array.new
  8. tree << statement until at_end
  9. tree
  10. end
  11. def statement
  12. if @current_token.type == TokenKinds::IF
  13. conditional
  14. elsif @current_token.type == TokenKinds::LET
  15. variable_declaration
  16. elsif @current_token.type == TokenKinds::FUNCTION
  17. function_definition
  18. elsif @current_token.type == TokenKinds::CLASS
  19. class_definition
  20. else
  21. expr = expression
  22. eat(TokenKinds::SEMICOLON)
  23. expr
  24. end
  25. end
  26. def variable_declaration
  27. eat(TokenKinds::LET)
  28. name = identifier
  29. eat(TokenKinds::EQUALS)
  30. value = expression
  31. eat(TokenKinds::SEMICOLON)
  32. AST::VariableDeclaration.new(name, value)
  33. end
  34. def function_definition
  35. eat(TokenKinds::FUNCTION)
  36. name = identifier
  37. params = parameters
  38. body = block
  39. AST::FunctionDefinition.new(name, params, body)
  40. end
  41. def class_definition
  42. eat(TokenKinds::CLASS)
  43. class_name = AST::Identifier.new(eat(TokenKinds::CLASS_NAME).value)
  44. eat(TokenKinds::LBRACE)
  45. members = Array.new
  46. while [TokenKinds::PUBLIC, TokenKinds::PRIVATE].include?(
  47. @current_token.type
  48. )
  49. is_public =
  50. if @current_token.type == TokenKinds::PUBLIC
  51. eat(TokenKinds::PUBLIC)
  52. true
  53. elsif @current_token.type == TokenKinds::PRIVATE
  54. eat(TokenKinds::PRIVATE)
  55. false
  56. end
  57. while !at_end && true
  58. name = identifier
  59. members << AST::Member.new(name, is_public)
  60. if @current_token.type == TokenKinds::COMMA
  61. eat(TokenKinds::COMMA)
  62. else
  63. break
  64. end
  65. end
  66. eat(TokenKinds::SEMICOLON)
  67. end
  68. methods = Array.new
  69. while @current_token.type == TokenKinds::FUNCTION
  70. methods << function_definition
  71. end
  72. eat(TokenKinds::RBRACE)
  73. AST::ClassDefinition.new(class_name, members, methods)
  74. end
  75. def conditional
  76. branches = Array.new
  77. eat(TokenKinds::IF)
  78. condition = expression
  79. block = self.block
  80. branches << AST::Branch.new(condition, block)
  81. while @current_token.type == TokenKinds::ELSEIF
  82. eat(TokenKinds::ELSEIF)
  83. condition = expression
  84. block = self.block
  85. branches << AST::Branch.new(condition, block)
  86. end
  87. if @current_token.type == TokenKinds::ELSE
  88. eat(TokenKinds::ELSE)
  89. block = self.block
  90. branches << AST::Branch.new(AST::Boolean.new(true), block)
  91. end
  92. AST::Conditional.new(branches)
  93. end
  94. def parameters
  95. params = Array.new
  96. eat(TokenKinds::LPAREN)
  97. while @current_token.type == TokenKinds::IDENTIFIER
  98. params << identifier
  99. if @current_token.type == TokenKinds::COMMA
  100. eat(TokenKinds::COMMA)
  101. else
  102. break
  103. end
  104. end
  105. eat(TokenKinds::RPAREN)
  106. params
  107. end
  108. def block
  109. statements = Array.new
  110. eat(TokenKinds::LBRACE)
  111. statements << statement until @current_token.type == TokenKinds::RBRACE
  112. eat(TokenKinds::RBRACE)
  113. AST::Block.new(statements)
  114. end
  115. def expression
  116. binary
  117. end
  118. private
  119. def binary
  120. left = comparison
  121. if @current_token.type == TokenKinds::OPERATOR
  122. operator = @current_token.value
  123. advance
  124. right = comparison
  125. AST::Binary.new(operator, left, right)
  126. else
  127. left
  128. end
  129. end
  130. def comparison
  131. left = multiplication
  132. if @current_token.type == TokenKinds::OPERATOR &&
  133. %i[< > <= >=].include?(@current_token.type)
  134. operator = @current_token.value
  135. advance
  136. right = multiplication
  137. AST::Binary.new(operator, left, right)
  138. else
  139. left
  140. end
  141. end
  142. def addition
  143. left = multiplication
  144. if @current_token.type == TokenKinds::OPERATOR &&
  145. %i[+ -].include?(@current_token.value)
  146. operator = @current_token.value
  147. advance
  148. right = multiplication
  149. AST::Binary.new(operator, left, right)
  150. else
  151. left
  152. end
  153. end
  154. def multiplication
  155. left = unary
  156. if @current_token.type == TokenKinds::OPERATOR &&
  157. %i[* /].include?(@current_token.value)
  158. operator = @current_token.value
  159. advance
  160. right = unary
  161. AST::Binary.new(operator, left, right)
  162. else
  163. left
  164. end
  165. end
  166. def unary
  167. if @current_token.type == TokenKinds::OPERATOR &&
  168. %i[- !].include?(@current_token.value)
  169. operator = eat(TokenKinds::OPERATOR).value
  170. expr = primary
  171. AST::Unary.new(operator, expr)
  172. else
  173. primary
  174. end
  175. end
  176. def primary
  177. token = @current_token
  178. expr =
  179. case token.type
  180. when TokenKinds::NULL
  181. advance
  182. AST::Null.new
  183. when TokenKinds::BOOLEAN
  184. advance
  185. AST::Boolean.new(token.value)
  186. when TokenKinds::NUMBER
  187. advance
  188. AST::Number.new(token.value)
  189. when TokenKinds::STRING
  190. advance
  191. AST::String.new(token.value)
  192. when TokenKinds::ATOM
  193. advance
  194. AST::Atom.new(token.value)
  195. when TokenKinds::IDENTIFIER
  196. identifier
  197. when TokenKinds::LBRACKET
  198. array
  199. when TokenKinds::LBRACE
  200. hash
  201. when TokenKinds::LPAREN
  202. eat(TokenKinds::LPAREN)
  203. e = expression
  204. eat(TokenKinds::RPAREN)
  205. e
  206. else
  207. raise "Unexpected token #{token.type}"
  208. end
  209. if @current_token.type == TokenKinds::LPAREN
  210. args = arguments
  211. AST::FunctionCall.new(expr, args)
  212. elsif @current_token.type == TokenKinds::LBRACKET
  213. eat(TokenKinds::LBRACKET)
  214. key = expression
  215. eat(TokenKinds::RBRACKET)
  216. AST::Index.new(expr, key)
  217. else
  218. expr
  219. end
  220. end
  221. def identifier
  222. token = eat(TokenKinds::IDENTIFIER)
  223. AST::Identifier.new(token.value)
  224. end
  225. def array
  226. elements = Array.new
  227. eat(TokenKinds::LBRACKET)
  228. until @current_token.type == TokenKinds::RBRACKET
  229. elements << expression
  230. if @current_token.type == TokenKinds::COMMA
  231. eat(TokenKinds::COMMA)
  232. else
  233. break
  234. end
  235. end
  236. eat(TokenKinds::RBRACKET)
  237. AST::Array.new(elements)
  238. end
  239. def hash
  240. h = Hash.new
  241. eat(TokenKinds::LBRACE)
  242. until @current_token.type == TokenKinds::RBRACE
  243. key = eat(TokenKinds::ATOM).value
  244. eat(TokenKinds::ROCKET)
  245. value = expression
  246. h[key] = value
  247. if @current_token.type == TokenKinds::COMMA
  248. eat(TokenKinds::COMMA)
  249. else
  250. break
  251. end
  252. end
  253. eat(TokenKinds::RBRACE)
  254. AST::Hash.new(h)
  255. end
  256. def arguments
  257. args = Array.new
  258. eat(TokenKinds::LPAREN)
  259. until @current_token.type == TokenKinds::RPAREN
  260. args << expression
  261. if @current_token.type == TokenKinds::COMMA
  262. eat(TokenKinds::COMMA)
  263. else
  264. break
  265. end
  266. end
  267. eat(TokenKinds::RPAREN)
  268. args
  269. end
  270. def eat(type)
  271. token = @current_token
  272. if token.type == type
  273. advance
  274. token
  275. else
  276. if token.nil?
  277. raise "Unexpected #{token.type} - expected #{type}"
  278. else
  279. raise "Unexpected #{token.type} - expected #{type}"
  280. end
  281. end
  282. end
  283. def advance
  284. @current_token = @lexer.get_token
  285. end
  286. def at_end
  287. @current_token.type == TokenKinds::EOF
  288. end
  289. end