A toy dynamic programming language written in Ruby
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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