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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. members = 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. members << AST::Member.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, members, 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. binary
  135. end
  136. private
  137. def binary
  138. left = comparison
  139. if @current_token.type == TokenKinds::OPERATOR
  140. operator = @current_token.value
  141. advance
  142. right = comparison
  143. AST::Binary.new(operator, left, right)
  144. else
  145. left
  146. end
  147. end
  148. def comparison
  149. left = multiplication
  150. if @current_token.type == TokenKinds::OPERATOR &&
  151. %i[< > <= >=].include?(@current_token.type)
  152. operator = @current_token.value
  153. advance
  154. right = multiplication
  155. AST::Binary.new(operator, left, right)
  156. else
  157. left
  158. end
  159. end
  160. def addition
  161. left = multiplication
  162. if @current_token.type == TokenKinds::OPERATOR &&
  163. %i[+ -].include?(@current_token.value)
  164. operator = @current_token.value
  165. advance
  166. right = multiplication
  167. AST::Binary.new(operator, left, right)
  168. else
  169. left
  170. end
  171. end
  172. def multiplication
  173. left = unary
  174. if @current_token.type == TokenKinds::OPERATOR &&
  175. %i[* /].include?(@current_token.value)
  176. operator = @current_token.value
  177. advance
  178. right = unary
  179. AST::Binary.new(operator, left, right)
  180. else
  181. left
  182. end
  183. end
  184. def unary
  185. if @current_token.type == TokenKinds::OPERATOR &&
  186. %i[- !].include?(@current_token.value)
  187. operator = eat(TokenKinds::OPERATOR).value
  188. expr = primary
  189. AST::Unary.new(operator, expr)
  190. else
  191. primary
  192. end
  193. end
  194. def primary
  195. token = @current_token
  196. expr =
  197. case token.type
  198. when TokenKinds::NULL
  199. advance
  200. AST::Null.new
  201. when TokenKinds::BOOLEAN
  202. advance
  203. AST::Boolean.new(token.value)
  204. when TokenKinds::NUMBER
  205. advance
  206. AST::Number.new(token.value)
  207. when TokenKinds::STRING
  208. advance
  209. AST::String.new(token.value)
  210. when TokenKinds::ATOM
  211. advance
  212. AST::Atom.new(token.value)
  213. when TokenKinds::IDENTIFIER
  214. identifier
  215. when TokenKinds::LBRACKET
  216. array
  217. when TokenKinds::LBRACE
  218. hash
  219. when TokenKinds::LPAREN
  220. eat(TokenKinds::LPAREN)
  221. e = expression
  222. eat(TokenKinds::RPAREN)
  223. e
  224. when TokenKinds::FUNCTION
  225. function_expression
  226. else
  227. raise "Unexpected token #{token.type}"
  228. end
  229. if @current_token.type == TokenKinds::LPAREN
  230. args = arguments
  231. AST::FunctionCall.new(expr, args)
  232. elsif @current_token.type == TokenKinds::LBRACKET
  233. eat(TokenKinds::LBRACKET)
  234. key = expression
  235. eat(TokenKinds::RBRACKET)
  236. AST::Index.new(expr, key)
  237. else
  238. expr
  239. end
  240. end
  241. def function_expression
  242. eat(TokenKinds::FUNCTION)
  243. params = parameters
  244. body = block
  245. AST::FunctionDefinition.new(nil, params, body)
  246. end
  247. def identifier
  248. token = eat(TokenKinds::IDENTIFIER)
  249. AST::Identifier.new(token.value)
  250. end
  251. def array
  252. elements = Array.new
  253. eat(TokenKinds::LBRACKET)
  254. until @current_token.type == TokenKinds::RBRACKET
  255. elements << expression
  256. if @current_token.type == TokenKinds::COMMA
  257. eat(TokenKinds::COMMA)
  258. else
  259. break
  260. end
  261. end
  262. eat(TokenKinds::RBRACKET)
  263. AST::Array.new(elements)
  264. end
  265. def hash
  266. h = Hash.new
  267. eat(TokenKinds::LBRACE)
  268. until @current_token.type == TokenKinds::RBRACE
  269. key = eat(TokenKinds::ATOM).value
  270. eat(TokenKinds::ROCKET)
  271. value = expression
  272. h[key] = value
  273. if @current_token.type == TokenKinds::COMMA
  274. eat(TokenKinds::COMMA)
  275. else
  276. break
  277. end
  278. end
  279. eat(TokenKinds::RBRACE)
  280. AST::Hash.new(h)
  281. end
  282. def arguments
  283. args = Array.new
  284. eat(TokenKinds::LPAREN)
  285. until @current_token.type == TokenKinds::RPAREN
  286. args << expression
  287. if @current_token.type == TokenKinds::COMMA
  288. eat(TokenKinds::COMMA)
  289. else
  290. break
  291. end
  292. end
  293. eat(TokenKinds::RPAREN)
  294. args
  295. end
  296. def eat(type)
  297. token = @current_token
  298. if token.type == type
  299. advance
  300. token
  301. else
  302. if token.nil?
  303. raise "Unexpected #{token.type} - expected #{type}"
  304. else
  305. raise "Unexpected #{token.type} - expected #{type}"
  306. end
  307. end
  308. end
  309. def advance
  310. @current_token = @lexer.get_token
  311. end
  312. def at_end
  313. @current_token.type == TokenKinds::EOF
  314. end
  315. end