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

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