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

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