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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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. method my_method() {
  262. "my method";
  263. }
  264. classmethod my_classmethod() {
  265. "my classmethod";
  266. }
  267. }
  268. CLASS
  269. ).to eq(
  270. [
  271. AST::ClassDefinition.new(
  272. AST::Identifier.new('Class'),
  273. [
  274. AST::PropertyDeclaration.new(AST::Identifier.new('foo'), true),
  275. AST::PropertyDeclaration.new(AST::Identifier.new('bar'), true),
  276. AST::PropertyDeclaration.new(AST::Identifier.new('baz'), false)
  277. ],
  278. [
  279. AST::FunctionDefinition.new(
  280. AST::Identifier.new('my_method'),
  281. [],
  282. AST::Block.new([AST::String.new('method')])
  283. )
  284. ],
  285. [
  286. AST::FunctionDefinition.new(
  287. AST::Identifier.new('my_classmethod'),
  288. [],
  289. AST::Block.new([AST::String.new('my classmethod')])
  290. )
  291. ]
  292. )
  293. ]
  294. )
  295. end
  296. it 'gives function calls higher precedence than binary operations' do
  297. expect(parse('x + func(y);')).to eq(
  298. [
  299. AST::Binary.new(
  300. AST::Operators::ADD,
  301. AST::Identifier.new('x'),
  302. AST::FunctionCall.new(
  303. AST::Identifier.new('func'),
  304. [AST::Identifier.new('y')]
  305. )
  306. )
  307. ]
  308. )
  309. end
  310. it 'parses hashes' do
  311. expect(parse('{ :a => 1, :b => 2 };')).to eq(
  312. [AST::Hash.new({ a: AST::Number.new(1.0), b: AST::Number.new(2.0) })]
  313. )
  314. end
  315. it 'parses bracket indexing' do
  316. expect(parse('array[0];')).to eq(
  317. [AST::Index.new(AST::Identifier.new('array'), AST::Number.new(0))]
  318. )
  319. end
  320. it 'parses atoms' do
  321. expect(parse(':atom;')).to eq([AST::Atom.new(:atom)])
  322. end
  323. it 'parses unary expressions' do
  324. expect(parse('-1;')).to eq([AST::Unary.new(:-, AST::Number.new(1.0))])
  325. expect(parse('!true;')).to eq([AST::Unary.new(:!, AST::Boolean.new(true))])
  326. end
  327. it 'gives parenthetical expressions higher precedence' do
  328. expect(parse('(1 + 2) * 3;')).to eq(
  329. [
  330. AST::Binary.new(
  331. AST::Operators::MULTIPLY,
  332. AST::Binary.new(
  333. AST::Operators::ADD,
  334. AST::Number.new(1.0),
  335. AST::Number.new(2.0)
  336. ),
  337. AST::Number.new(3.0)
  338. )
  339. ]
  340. )
  341. end
  342. it 'parses for loops' do
  343. expect(parse('for x in xs { print(x); }')).to eq(
  344. [
  345. AST::ForLoop.new(
  346. AST::Identifier.new('x'),
  347. AST::Identifier.new('xs'),
  348. AST::Block.new(
  349. [
  350. AST::FunctionCall.new(
  351. AST::Identifier.new('print'),
  352. [AST::Identifier.new('x')]
  353. )
  354. ]
  355. )
  356. )
  357. ]
  358. )
  359. end
  360. it 'parses a function expression' do
  361. expect(parse('let sum = function(x, y) { x + y; };')).to eq(
  362. [
  363. AST::VariableDeclaration.new(
  364. AST::Identifier.new('sum'),
  365. AST::FunctionDefinition.new(
  366. nil,
  367. [AST::Identifier.new('x'), AST::Identifier.new('y')],
  368. AST::Block.new(
  369. [
  370. AST::Binary.new(
  371. AST::Operators::ADD,
  372. AST::Identifier.new('x'),
  373. AST::Identifier.new('y')
  374. )
  375. ]
  376. )
  377. )
  378. )
  379. ]
  380. )
  381. end
  382. it 'allows returning an anonymous function from another function' do
  383. expect(
  384. parse('function outer() { function() { print("Hello world"); }; }')
  385. ).to eq(
  386. [
  387. AST::FunctionDefinition.new(
  388. AST::Identifier.new('outer'),
  389. [],
  390. AST::Block.new(
  391. [
  392. AST::FunctionDefinition.new(
  393. nil,
  394. [],
  395. AST::Block.new(
  396. [
  397. AST::FunctionCall.new(
  398. AST::Identifier.new('print'),
  399. [AST::String.new('Hello world')]
  400. )
  401. ]
  402. )
  403. )
  404. ]
  405. )
  406. )
  407. ]
  408. )
  409. end
  410. it 'allows toplevel function expressions' do
  411. expect(parse('function() { print("Hello world"); };')).to eq(
  412. [
  413. AST::FunctionDefinition.new(
  414. nil,
  415. [],
  416. AST::Block.new(
  417. [
  418. AST::FunctionCall.new(
  419. AST::Identifier.new('print'),
  420. [AST::String.new('Hello world')]
  421. )
  422. ]
  423. )
  424. )
  425. ]
  426. )
  427. end
  428. it 'parses assignments' do
  429. expect(parse('x = 5;')).to eq(
  430. [AST::Assignment.new(AST::Identifier.new('x'), AST::Number.new(5.0))]
  431. )
  432. end
  433. it 'allows calling the result of a function call as a function' do
  434. expect(parse('func()();')).to eq(
  435. [
  436. AST::FunctionCall.new(
  437. AST::FunctionCall.new(AST::Identifier.new('func'), []),
  438. []
  439. )
  440. ]
  441. )
  442. end
  443. it 'allows arbitrarily chaining function calls and indexes' do
  444. expect(parse('func()[0]()[1][2]();')).to eq(
  445. [
  446. AST::FunctionCall.new(
  447. AST::Index.new(
  448. AST::Index.new(
  449. AST::FunctionCall.new(
  450. AST::Index.new(
  451. AST::FunctionCall.new(AST::Identifier.new('func'), []),
  452. AST::Number.new(0.0)
  453. ),
  454. []
  455. ),
  456. AST::Number.new(1.0)
  457. ),
  458. AST::Number.new(2.0)
  459. ),
  460. []
  461. )
  462. ]
  463. )
  464. end
  465. it 'parses property access' do
  466. expect(parse('hello#world;')).to eq(
  467. [
  468. AST::Property.new(
  469. AST::Identifier.new('hello'),
  470. AST::Identifier.new('world')
  471. )
  472. ]
  473. )
  474. end
  475. it 'parses allows calling properties (methods)' do
  476. expect(parse('hello#world();')).to eq(
  477. [
  478. AST::FunctionCall.new(
  479. AST::Property.new(
  480. AST::Identifier.new('hello'),
  481. AST::Identifier.new('world')
  482. ),
  483. []
  484. )
  485. ]
  486. )
  487. end
  488. end