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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. when TokenKinds::FUNCTION
  217. function_expression
  218. else
  219. raise "Unexpected token #{token.type}"
  220. end
  221. if @current_token.type == TokenKinds::LPAREN
  222. args = arguments
  223. AST::FunctionCall.new(expr, args)
  224. elsif @current_token.type == TokenKinds::LBRACKET
  225. eat(TokenKinds::LBRACKET)
  226. key = expression
  227. eat(TokenKinds::RBRACKET)
  228. AST::Index.new(expr, key)
  229. else
  230. expr
  231. end
  232. end
  233. def function_expression
  234. eat(TokenKinds::FUNCTION)
  235. params = parameters
  236. body = block
  237. AST::FunctionDefinition.new(nil, params, body)
  238. end
  239. def identifier
  240. token = eat(TokenKinds::IDENTIFIER)
  241. AST::Identifier.new(token.value)
  242. end
  243. def array
  244. elements = Array.new
  245. eat(TokenKinds::LBRACKET)
  246. until @current_token.type == TokenKinds::RBRACKET
  247. elements << expression
  248. if @current_token.type == TokenKinds::COMMA
  249. eat(TokenKinds::COMMA)
  250. else
  251. break
  252. end
  253. end
  254. eat(TokenKinds::RBRACKET)
  255. AST::Array.new(elements)
  256. end
  257. def hash
  258. h = Hash.new
  259. eat(TokenKinds::LBRACE)
  260. until @current_token.type == TokenKinds::RBRACE
  261. key = eat(TokenKinds::ATOM).value
  262. eat(TokenKinds::ROCKET)
  263. value = expression
  264. h[key] = value
  265. if @current_token.type == TokenKinds::COMMA
  266. eat(TokenKinds::COMMA)
  267. else
  268. break
  269. end
  270. end
  271. eat(TokenKinds::RBRACE)
  272. AST::Hash.new(h)
  273. end
  274. def arguments
  275. args = Array.new
  276. eat(TokenKinds::LPAREN)
  277. until @current_token.type == TokenKinds::RPAREN
  278. args << expression
  279. if @current_token.type == TokenKinds::COMMA
  280. eat(TokenKinds::COMMA)
  281. else
  282. break
  283. end
  284. end
  285. eat(TokenKinds::RPAREN)
  286. args
  287. end
  288. def eat(type)
  289. token = @current_token
  290. if token.type == type
  291. advance
  292. token
  293. else
  294. if token.nil?
  295. raise "Unexpected #{token.type} - expected #{type}"
  296. else
  297. raise "Unexpected #{token.type} - expected #{type}"
  298. end
  299. end
  300. end
  301. def advance
  302. @current_token = @lexer.get_token
  303. end
  304. def at_end
  305. @current_token.type == TokenKinds::EOF
  306. end
  307. end