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_spec.rb 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. RSpec.describe Parser do
  2. def parse(source)
  3. Parser.new(Lexer.new(source)).parse
  4. end
  5. it 'parses null' do
  6. expect(parse('null;')).to eq([AST::Null.new])
  7. end
  8. it 'parses booleans' do
  9. expect(parse('true;')).to eq([AST::Boolean.new(true)])
  10. expect(parse('false;')).to eq([AST::Boolean.new(false)])
  11. end
  12. it 'parses numbers' do
  13. expect(parse('5;')).to eq([AST::Number.new(5.0)])
  14. end
  15. it 'parses strings' do
  16. expect(parse('"hello world";')).to eq([AST::String.new('hello world')])
  17. end
  18. it 'parses addition' do
  19. expect(parse('1 + 2;')).to eq(
  20. [
  21. AST::Binary.new(
  22. AST::Operators::ADD,
  23. AST::Number.new(1.0),
  24. AST::Number.new(2.0)
  25. )
  26. ]
  27. )
  28. end
  29. it 'parses subtraction' do
  30. expect(parse('1 - 2;')).to eq(
  31. [
  32. AST::Binary.new(
  33. AST::Operators::SUBTRACT,
  34. AST::Number.new(1.0),
  35. AST::Number.new(2.0)
  36. )
  37. ]
  38. )
  39. end
  40. it 'parses multiplication' do
  41. expect(parse('1 * 2;')).to eq(
  42. [
  43. AST::Binary.new(
  44. AST::Operators::MULTIPLY,
  45. AST::Number.new(1.0),
  46. AST::Number.new(2.0)
  47. )
  48. ]
  49. )
  50. end
  51. it 'parses division' do
  52. expect(parse('1 / 2;')).to eq(
  53. [
  54. AST::Binary.new(
  55. AST::Operators::DIVIDE,
  56. AST::Number.new(1.0),
  57. AST::Number.new(2.0)
  58. )
  59. ]
  60. )
  61. end
  62. it 'gives multiplication higher precedence than addition' do
  63. expect(parse('1 + 2 * 3;')).to eq(
  64. [
  65. AST::Binary.new(
  66. AST::Operators::ADD,
  67. AST::Number.new(1.0),
  68. AST::Binary.new(
  69. AST::Operators::MULTIPLY,
  70. AST::Number.new(2.0),
  71. AST::Number.new(3.0)
  72. )
  73. )
  74. ]
  75. )
  76. end
  77. it 'gives multiplication higher precedence than subtraction' do
  78. expect(parse('1 - 2 / 3;')).to eq(
  79. [
  80. AST::Binary.new(
  81. AST::Operators::SUBTRACT,
  82. AST::Number.new(1.0),
  83. AST::Binary.new(
  84. AST::Operators::DIVIDE,
  85. AST::Number.new(2.0),
  86. AST::Number.new(3.0)
  87. )
  88. )
  89. ]
  90. )
  91. end
  92. it 'parses if statement' do
  93. expect(parse('if true { "true"; }')).to eq(
  94. [
  95. AST::Conditional.new(
  96. [
  97. AST::Branch.new(
  98. AST::Boolean.new(true),
  99. AST::Block.new([AST::String.new('true')])
  100. )
  101. ]
  102. )
  103. ]
  104. )
  105. end
  106. it 'parses if else statement' do
  107. expect(parse('if true { "true"; } else { "false"; }')).to eq(
  108. [
  109. AST::Conditional.new(
  110. [
  111. AST::Branch.new(
  112. AST::Boolean.new(true),
  113. AST::Block.new([AST::String.new('true')])
  114. ),
  115. AST::Branch.new(
  116. AST::Boolean.new(true),
  117. AST::Block.new([AST::String.new('false')])
  118. )
  119. ]
  120. )
  121. ]
  122. )
  123. end
  124. it 'parses if elseif else statement' do
  125. expect(
  126. parse('if true { "true"; } elseif false { "false"; } else { "neither"; }')
  127. ).to eq(
  128. [
  129. AST::Conditional.new(
  130. [
  131. AST::Branch.new(
  132. AST::Boolean.new(true),
  133. AST::Block.new([AST::String.new('true')])
  134. ),
  135. AST::Branch.new(
  136. AST::Boolean.new(false),
  137. AST::Block.new([AST::String.new('false')])
  138. ),
  139. AST::Branch.new(
  140. AST::Boolean.new(true),
  141. AST::Block.new([AST::String.new('neither')])
  142. )
  143. ]
  144. )
  145. ]
  146. )
  147. end
  148. it 'parses comparisons' do
  149. expect(parse('1 < 2;')).to eq(
  150. [
  151. AST::Binary.new(
  152. AST::Operators::LESS_THAN,
  153. AST::Number.new(1.0),
  154. AST::Number.new(2.0)
  155. )
  156. ]
  157. )
  158. expect(parse('1 > 2;')).to eq(
  159. [
  160. AST::Binary.new(
  161. AST::Operators::GREATER_THAN,
  162. AST::Number.new(1.0),
  163. AST::Number.new(2.0)
  164. )
  165. ]
  166. )
  167. expect(parse('1 <= 2;')).to eq(
  168. [
  169. AST::Binary.new(
  170. AST::Operators::LESS_THAN_OR_EQUAL,
  171. AST::Number.new(1.0),
  172. AST::Number.new(2.0)
  173. )
  174. ]
  175. )
  176. expect(parse('1 >= 2;')).to eq(
  177. [
  178. AST::Binary.new(
  179. AST::Operators::GREATER_THAN_OR_EQUAL,
  180. AST::Number.new(1.0),
  181. AST::Number.new(2.0)
  182. )
  183. ]
  184. )
  185. expect(parse('1 or 2;')).to eq(
  186. [
  187. AST::Binary.new(
  188. AST::Operators::OR,
  189. AST::Number.new(1.0),
  190. AST::Number.new(2.0)
  191. )
  192. ]
  193. )
  194. expect(parse('1 and 2;')).to eq(
  195. [
  196. AST::Binary.new(
  197. AST::Operators::AND,
  198. AST::Number.new(1.0),
  199. AST::Number.new(2.0)
  200. )
  201. ]
  202. )
  203. end
  204. it 'parses identifier' do
  205. expect(parse('x;')).to eq([AST::Identifier.new('x')])
  206. end
  207. it 'parses variable declaration' do
  208. expect(parse('let x = 1;')).to eq(
  209. [
  210. AST::VariableDeclaration.new(
  211. AST::Identifier.new('x'),
  212. AST::Number.new(1.0)
  213. )
  214. ]
  215. )
  216. end
  217. it 'parses function definition' do
  218. result = [
  219. AST::FunctionDefinition.new(
  220. AST::Identifier.new('add_one'),
  221. [AST::Identifier.new('x')],
  222. AST::Block.new(
  223. [
  224. AST::Binary.new(
  225. AST::Operators::ADD,
  226. AST::Identifier.new('x'),
  227. AST::Number.new(1.0)
  228. )
  229. ]
  230. )
  231. )
  232. ]
  233. expect(parse('function add_one(x) { x + 1; }')).to eq(result)
  234. expect(parse('function add_one(x,) { x + 1; }')).to eq(result)
  235. end
  236. it 'parses function call' do
  237. result = [
  238. AST::FunctionCall.new(
  239. AST::Identifier.new('func'),
  240. [AST::Number.new(1.0), AST::Number.new(2.0)]
  241. )
  242. ]
  243. expect(parse('func(1, 2);')).to eq(result)
  244. expect(parse('func(1, 2,);')).to eq(result)
  245. end
  246. it 'parses array literal' do
  247. result = [
  248. AST::Array.new(
  249. [AST::Number.new(1.0), AST::Number.new(2.0), AST::Number.new(3.0)]
  250. )
  251. ]
  252. expect(parse('[1, 2, 3];')).to eq(result)
  253. expect(parse('[1, 2, 3,];')).to eq(result)
  254. end
  255. it 'parses a class definition do' do
  256. expect(
  257. parse(<<~CLASS)
  258. class Class {
  259. public foo, bar;
  260. private baz;
  261. function method() {
  262. "method";
  263. }
  264. }
  265. CLASS
  266. ).to eq(
  267. [
  268. AST::ClassDefinition.new(
  269. AST::Identifier.new('Class'),
  270. [
  271. AST::PropertyDeclaration.new(AST::Identifier.new('foo'), true),
  272. AST::PropertyDeclaration.new(AST::Identifier.new('bar'), true),
  273. AST::PropertyDeclaration.new(AST::Identifier.new('baz'), false)
  274. ],
  275. [
  276. AST::FunctionDefinition.new(
  277. AST::Identifier.new('method'),
  278. [],
  279. AST::Block.new([AST::String.new('method')])
  280. )
  281. ]
  282. )
  283. ]
  284. )
  285. end
  286. it 'gives function calls higher precedence than binary operations' do
  287. expect(parse('x + func(y);')).to eq(
  288. [
  289. AST::Binary.new(
  290. AST::Operators::ADD,
  291. AST::Identifier.new('x'),
  292. AST::FunctionCall.new(
  293. AST::Identifier.new('func'),
  294. [AST::Identifier.new('y')]
  295. )
  296. )
  297. ]
  298. )
  299. end
  300. it 'parses hashes' do
  301. expect(parse('{ :a => 1, :b => 2 };')).to eq(
  302. [AST::Hash.new({ a: AST::Number.new(1.0), b: AST::Number.new(2.0) })]
  303. )
  304. end
  305. it 'parses bracket indexing' do
  306. expect(parse('array[0];')).to eq(
  307. [AST::Index.new(AST::Identifier.new('array'), AST::Number.new(0))]
  308. )
  309. end
  310. it 'parses atoms' do
  311. expect(parse(':atom;')).to eq([AST::Atom.new(:atom)])
  312. end
  313. it 'parses unary expressions' do
  314. expect(parse('-1;')).to eq([AST::Unary.new(:-, AST::Number.new(1.0))])
  315. expect(parse('!true;')).to eq([AST::Unary.new(:!, AST::Boolean.new(true))])
  316. end
  317. it 'gives parenthetical expressions higher precedence' do
  318. expect(parse('(1 + 2) * 3;')).to eq(
  319. [
  320. AST::Binary.new(
  321. AST::Operators::MULTIPLY,
  322. AST::Binary.new(
  323. AST::Operators::ADD,
  324. AST::Number.new(1.0),
  325. AST::Number.new(2.0)
  326. ),
  327. AST::Number.new(3.0)
  328. )
  329. ]
  330. )
  331. end
  332. it 'parses for loops' do
  333. expect(parse('for x in xs { print(x); }')).to eq(
  334. [
  335. AST::ForLoop.new(
  336. AST::Identifier.new('x'),
  337. AST::Identifier.new('xs'),
  338. AST::Block.new(
  339. [
  340. AST::FunctionCall.new(
  341. AST::Identifier.new('print'),
  342. [AST::Identifier.new('x')]
  343. )
  344. ]
  345. )
  346. )
  347. ]
  348. )
  349. end
  350. it 'parses a function expression' do
  351. expect(parse('let sum = function(x, y) { x + y; };')).to eq(
  352. [
  353. AST::VariableDeclaration.new(
  354. AST::Identifier.new('sum'),
  355. AST::FunctionDefinition.new(
  356. nil,
  357. [AST::Identifier.new('x'), AST::Identifier.new('y')],
  358. AST::Block.new(
  359. [
  360. AST::Binary.new(
  361. AST::Operators::ADD,
  362. AST::Identifier.new('x'),
  363. AST::Identifier.new('y')
  364. )
  365. ]
  366. )
  367. )
  368. )
  369. ]
  370. )
  371. end
  372. it 'allows returning an anonymous function from another function' do
  373. expect(
  374. parse('function outer() { function() { print("Hello world"); }; }')
  375. ).to eq(
  376. [
  377. AST::FunctionDefinition.new(
  378. AST::Identifier.new('outer'),
  379. [],
  380. AST::Block.new(
  381. [
  382. AST::FunctionDefinition.new(
  383. nil,
  384. [],
  385. AST::Block.new(
  386. [
  387. AST::FunctionCall.new(
  388. AST::Identifier.new('print'),
  389. [AST::String.new('Hello world')]
  390. )
  391. ]
  392. )
  393. )
  394. ]
  395. )
  396. )
  397. ]
  398. )
  399. end
  400. it 'allows toplevel function expressions' do
  401. expect(parse('function() { print("Hello world"); };')).to eq(
  402. [
  403. AST::FunctionDefinition.new(
  404. nil,
  405. [],
  406. AST::Block.new(
  407. [
  408. AST::FunctionCall.new(
  409. AST::Identifier.new('print'),
  410. [AST::String.new('Hello world')]
  411. )
  412. ]
  413. )
  414. )
  415. ]
  416. )
  417. end
  418. it 'parses assignments' do
  419. expect(parse('x = 5;')).to eq(
  420. [AST::Assignment.new(AST::Identifier.new('x'), AST::Number.new(5.0))]
  421. )
  422. end
  423. it 'allows calling the result of a function call as a function' do
  424. expect(parse('func()();')).to eq(
  425. [
  426. AST::FunctionCall.new(
  427. AST::FunctionCall.new(
  428. AST::Identifier.new('func'),
  429. [],
  430. ),
  431. []
  432. )
  433. ]
  434. )
  435. end
  436. it 'allows arbitrarily chaining function calls and indexes' do
  437. expect(parse('func()[0]()[1][2]();')).to eq(
  438. [
  439. AST::FunctionCall.new(
  440. AST::Index.new(
  441. AST::Index.new(
  442. AST::FunctionCall.new(
  443. AST::Index.new(
  444. AST::FunctionCall.new(
  445. AST::Identifier.new('func'),
  446. []
  447. ),
  448. AST::Number.new(0.0)
  449. ),
  450. []
  451. ),
  452. AST::Number.new(1.0)
  453. ),
  454. AST::Number.new(2.0)
  455. ),
  456. []
  457. )
  458. ]
  459. )
  460. end
  461. end