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_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