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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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].include?(@current_token.type)
  243. case @current_token.type
  244. when TokenKinds::LPAREN
  245. args = arguments
  246. expr = AST::FunctionCall.new(expr, args)
  247. when TokenKinds::LBRACKET
  248. eat(TokenKinds::LBRACKET)
  249. key = expression
  250. eat(TokenKinds::RBRACKET)
  251. expr = AST::Index.new(expr, key)
  252. end
  253. end
  254. expr
  255. end
  256. def function_expression
  257. eat(TokenKinds::FUNCTION)
  258. params = parameters
  259. body = block
  260. AST::FunctionDefinition.new(nil, params, body)
  261. end
  262. def identifier
  263. token = eat(TokenKinds::IDENTIFIER)
  264. AST::Identifier.new(token.value)
  265. end
  266. def array
  267. elements = Array.new
  268. eat(TokenKinds::LBRACKET)
  269. until @current_token.type == TokenKinds::RBRACKET
  270. elements << expression
  271. if @current_token.type == TokenKinds::COMMA
  272. eat(TokenKinds::COMMA)
  273. else
  274. break
  275. end
  276. end
  277. eat(TokenKinds::RBRACKET)
  278. AST::Array.new(elements)
  279. end
  280. def hash
  281. h = Hash.new
  282. eat(TokenKinds::LBRACE)
  283. until @current_token.type == TokenKinds::RBRACE
  284. key = eat(TokenKinds::ATOM).value
  285. eat(TokenKinds::ROCKET)
  286. value = expression
  287. h[key] = value
  288. if @current_token.type == TokenKinds::COMMA
  289. eat(TokenKinds::COMMA)
  290. else
  291. break
  292. end
  293. end
  294. eat(TokenKinds::RBRACE)
  295. AST::Hash.new(h)
  296. end
  297. def arguments
  298. args = Array.new
  299. eat(TokenKinds::LPAREN)
  300. until @current_token.type == TokenKinds::RPAREN
  301. args << expression
  302. if @current_token.type == TokenKinds::COMMA
  303. eat(TokenKinds::COMMA)
  304. else
  305. break
  306. end
  307. end
  308. eat(TokenKinds::RPAREN)
  309. args
  310. end
  311. def eat(type)
  312. token = @current_token
  313. if token.type == type
  314. advance
  315. token
  316. else
  317. if token.nil?
  318. raise "Unexpected #{token.type} - expected #{type}"
  319. else
  320. raise "Unexpected #{token.type} - expected #{type}"
  321. end
  322. end
  323. end
  324. def advance
  325. @current_token = @lexer.get_token
  326. end
  327. def at_end
  328. @current_token.type == TokenKinds::EOF
  329. end
  330. end