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.3KB

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