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 8.9KB

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