rules.test.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. var options = require("option");
  2. var rules = require("../lib/rules");
  3. var testing = require("../lib/testing");
  4. var TokenIterator = require("../lib/TokenIterator");
  5. var errors = require("../lib/errors");
  6. var results = require("../lib/parsing-results");
  7. var StringSource = require("../lib/StringSource");
  8. var assertIsSuccess = testing.assertIsSuccess;
  9. var assertIsSuccessWithValue = testing.assertIsSuccessWithValue;
  10. var assertIsFailure = testing.assertIsFailure;
  11. var assertIsFailureWithRemaining = testing.assertIsFailureWithRemaining;
  12. var assertIsError = testing.assertIsError;
  13. var Tokeniser = require("./Tokeniser");
  14. var Token = require("../lib/Token");
  15. var stringSourceRange = function(string, startIndex, endIndex) {
  16. return new StringSource(string).range(startIndex, endIndex);
  17. };
  18. var token = function(tokenType, value, source) {
  19. return new Token(tokenType, value, source);
  20. };
  21. var keyword = function(value) {
  22. return rules.token("keyword", value);
  23. };
  24. var identifier = function(value) {
  25. return rules.token("identifier", value);
  26. };
  27. exports.tokenRuleFailsIfInputIsEmpty = function(test) {
  28. var tokens = [];
  29. var rule = rules.token("keyword", "true");
  30. var result = rule(new TokenIterator(tokens));
  31. assertIsFailure(test, result, {
  32. remaining: [],
  33. errors: [errors.error({
  34. expected: "keyword \"true\"",
  35. actual: "end of tokens"
  36. })]
  37. });
  38. test.done();
  39. };
  40. exports.tokenRuleConsumeTokenWhenTokenIsOfCorrectType = function(test) {
  41. var parser = rules.token("keyword", "true");
  42. var result = parseString(parser, "true");
  43. assertIsSuccess(test, result, {
  44. value: "true",
  45. source: stringSourceRange("true", 0, 4)
  46. });
  47. test.done();
  48. };
  49. exports.parsingTokenFailsIfTokenIsOfWrongType = function(test) {
  50. var parser = rules.token("keyword", "true");
  51. var result = parseString(parser, "blah");
  52. assertIsFailure(test, result, {
  53. remaining: [
  54. token("identifier", "blah", stringSourceRange("blah", 0, 4)),
  55. token("end", null, stringSourceRange("blah", 4, 4))
  56. ],
  57. errors: [errors.error({
  58. expected: "keyword \"true\"",
  59. actual: "identifier \"blah\"",
  60. location: stringSourceRange("blah", 0, 4)
  61. })]
  62. });
  63. test.done();
  64. };
  65. exports.parsingTokenFailsIfTokenIsOfWrongValue = function(test) {
  66. var parser = rules.token("keyword", "true");
  67. var result = parseString(parser, "false");
  68. assertIsFailure(test, result, {
  69. remaining: [
  70. token("keyword", "false", stringSourceRange("false", 0, 5)),
  71. token("end", null, stringSourceRange("false", 5, 5))
  72. ],
  73. errors: [errors.error({
  74. expected: "keyword \"true\"",
  75. actual: "keyword \"false\"",
  76. location: stringSourceRange("false", 0, 5)
  77. })]
  78. });
  79. test.done();
  80. };
  81. exports.anyValueIsAcceptedIfValueOfTokenIsNotSpecified = function(test) {
  82. var parser = rules.token("keyword");
  83. var result = parseString(parser, "true");
  84. assertIsSuccess(test, result, {
  85. value: "true",
  86. source: stringSourceRange("true", 0, 4)
  87. });
  88. test.done();
  89. };
  90. exports.firstSuccessIsReturnedByFirstOf = function(test) {
  91. var trueParser = keyword("true");
  92. var falseParser = keyword("false");
  93. var evilParser = function() {
  94. throw new Error("Hahaha!");
  95. };
  96. var result = parseString(rules.firstOf("Boolean", trueParser, falseParser, evilParser), "false");
  97. assertIsSuccessWithValue(test, result, "false");
  98. test.done();
  99. };
  100. exports.firstOfFailsIfNoParsersMatch = function(test) {
  101. var trueParser = keyword("true");
  102. var falseParser = keyword("false");
  103. var result = parseString(rules.firstOf("Boolean", trueParser, falseParser), "blah");
  104. assertIsFailure(test, result, {
  105. remaining:[
  106. identifier("blah", stringSourceRange("blah", 0, 4)),
  107. token("end", null, stringSourceRange("blah", 4, 4))
  108. ],
  109. errors: [errors.error({
  110. expected: "Boolean",
  111. actual: "identifier \"blah\"",
  112. location: stringSourceRange("blah", 0, 4)
  113. })]
  114. });
  115. test.done();
  116. };
  117. exports.firstOfReturnsErrorIfSubRuleReturnsErrorEvenIfLaterRuleSucceeds = function(test) {
  118. var trueParser = rules.sequence(rules.sequence.cut(), keyword("true"));
  119. var falseParser = keyword("false");
  120. var result = parseString(rules.firstOf("Boolean", trueParser, falseParser), "false");
  121. assertIsError(test, result, {
  122. remaining:[
  123. keyword("false", stringSourceRange("false", 0, 5)),
  124. token("end", null, stringSourceRange("false", 5, 5))
  125. ],
  126. errors: [errors.error({
  127. expected: "keyword \"true\"",
  128. actual: "keyword \"false\"",
  129. location: stringSourceRange("false", 0, 5)
  130. })]
  131. });
  132. test.done();
  133. };
  134. exports.thenReturnsFailureIfOriginalResultIsFailure = function(test) {
  135. var parser = rules.then(keyword("true"), function() { return true; });
  136. var result = parseString(parser, "blah");
  137. assertIsFailure(test, result, {
  138. remaining:[
  139. identifier("blah", stringSourceRange("blah", 0, 4)),
  140. token("end", null, stringSourceRange("blah", 4, 4))
  141. ],
  142. errors: [errors.error({
  143. expected: "keyword \"true\"",
  144. actual: "identifier \"blah\"",
  145. location: stringSourceRange("blah", 0, 4)
  146. })]
  147. });
  148. test.done();
  149. };
  150. exports.thenMapsOverValueIfOriginalResultIsSuccess = function(test) {
  151. var parser = rules.then(keyword("true"), function() { return true; });
  152. var result = parseString(parser, "true");
  153. assertIsSuccessWithValue(test, result, true);
  154. test.done();
  155. };
  156. exports.sequenceSucceedsIfSubParsersCanBeAppliedInOrder = function(test) {
  157. var parser = rules.sequence(identifier("one"), identifier("two"));
  158. var result = parseString(parser, "one two");
  159. assertIsSuccess(test, result, {
  160. source: stringSourceRange("one two", 0, 7)
  161. });
  162. test.done();
  163. };
  164. exports.sequenceFailIfSubParserFails = function(test) {
  165. var parser = rules.sequence(identifier("("), identifier(")"));
  166. var result = parseString(parser, "(");
  167. assertIsFailure(test, result, {
  168. remaining:[token("end", null, stringSourceRange("(", 1, 1))],
  169. errors: [errors.error({
  170. expected: "identifier \")\"",
  171. actual: "end",
  172. location: stringSourceRange("(", 1, 1)
  173. })]
  174. });
  175. test.done();
  176. };
  177. exports.sequenceFailIfSubParserFailsAndFinalParserSucceeds = function(test) {
  178. var parser = rules.sequence(identifier("("), identifier(")"));
  179. var result = parseString(parser, ")");
  180. assertIsFailure(test, result, {
  181. remaining:[
  182. identifier(")", stringSourceRange(")", 0, 1)),
  183. token("end", null, stringSourceRange(")", 1, 1))
  184. ],
  185. errors: [errors.error({
  186. expected: "identifier \"(\"",
  187. actual: "identifier \")\"",
  188. location: stringSourceRange(")", 0, 1)
  189. })]
  190. });
  191. test.done();
  192. };
  193. exports.sequenceReturnsMapOfCapturedValues = function(test) {
  194. var name = rules.sequence.capture(identifier(), "name");
  195. var parser = rules.sequence(identifier("("), name, identifier(")"));
  196. var result = parseString(parser, "( bob )");
  197. assertIsSuccess(test, result);
  198. test.deepEqual(result.value().get(name), "bob");
  199. test.done();
  200. };
  201. exports.failureInSubRuleInSequenceBeforeCutCausesSequenceToFail = function(test) {
  202. var parser = rules.sequence(identifier("("), rules.sequence.cut(), identifier(), identifier(")"));
  203. var result = parseString(parser, "bob");
  204. assertIsFailure(test, result);
  205. test.done();
  206. };
  207. exports.failureInSubRuleInSequenceAfterCutCausesError = function(test) {
  208. var parser = rules.sequence(identifier("("), rules.sequence.cut(), identifier(), identifier(")"));
  209. var result = parseString(parser, "( true");
  210. assertIsError(test, result, {
  211. remaining: [
  212. token("keyword", "true", stringSourceRange("( true", 2, 6)),
  213. token("end", null, stringSourceRange("( true", 6, 6))
  214. ],
  215. errors: [errors.error({
  216. expected: "identifier",
  217. actual: "keyword \"true\"",
  218. location: stringSourceRange("( true", 2, 6)
  219. })]
  220. });
  221. test.done();
  222. };
  223. exports.canPullSingleValueOutOfCapturedValuesUsingExtract = function(test) {
  224. var name = rules.sequence.capture(identifier(), "name");
  225. var parser = rules.then(
  226. rules.sequence(identifier("("), name, identifier(")")),
  227. rules.sequence.extract(name)
  228. );
  229. var result = parseString(parser, "( bob )");
  230. assertIsSuccessWithValue(test, result, "bob");
  231. test.done();
  232. };
  233. exports.canPullSingleValueOutOfCapturedValuesUsingHeadOnSequenceRule = function(test) {
  234. var name = rules.sequence.capture(identifier(), "name");
  235. var parser =
  236. rules.sequence(identifier("("), name, identifier(")"))
  237. .head();
  238. var result = parseString(parser, "( bob )");
  239. assertIsSuccessWithValue(test, result, "bob");
  240. test.done();
  241. };
  242. exports.canApplyValuesFromSequenceToFunction = function(test) {
  243. var firstName = rules.sequence.capture(identifier(), "firstName");
  244. var secondName = rules.sequence.capture(identifier(), "secondName");
  245. var parser = rules.then(
  246. rules.sequence(
  247. secondName,
  248. identifier(","),
  249. firstName
  250. ),
  251. rules.sequence.applyValues(function(firstName, secondName) {
  252. return {first: firstName, second: secondName};
  253. }, firstName, secondName)
  254. );
  255. var result = parseString(parser, "Bobertson , Bob");
  256. assertIsSuccessWithValue(test, result, {first: "Bob", second: "Bobertson"});
  257. test.done();
  258. };
  259. exports.canApplyValuesAndSourceFromSequenceToFunctionUsingMapOnSequenceRule = function(test) {
  260. var firstName = rules.sequence.capture(identifier(), "firstName");
  261. var secondName = rules.sequence.capture(identifier());
  262. var parser = rules.sequence(
  263. secondName,
  264. identifier(","),
  265. firstName
  266. ).map(function(secondName, firstName, source) {
  267. return {first: firstName, second: secondName, source: source};
  268. });
  269. var result = parseString(parser, "Bobertson , Bob");
  270. assertIsSuccessWithValue(test, result, {
  271. first: "Bob",
  272. second: "Bobertson",
  273. source: stringSourceRange("Bobertson , Bob", 0, 15)
  274. });
  275. test.done();
  276. };
  277. exports.canApplyValuesWithSourceFromSequenceToFunction = function(test) {
  278. var firstName = rules.sequence.capture(identifier(), "firstName");
  279. var secondName = rules.sequence.capture(identifier(), "secondName");
  280. var parser = rules.then(
  281. rules.sequence(
  282. secondName,
  283. identifier(","),
  284. firstName
  285. ),
  286. rules.sequence.applyValues(function(firstName, secondName, source) {
  287. return {first: firstName, second: secondName, source: source};
  288. }, firstName, secondName, rules.sequence.source)
  289. );
  290. var result = parseString(parser, "Bobertson , Bob");
  291. assertIsSuccessWithValue(test, result, {
  292. first: "Bob",
  293. second: "Bobertson",
  294. source: stringSourceRange("Bobertson , Bob", 0, 15)
  295. });
  296. test.done();
  297. };
  298. exports.exceptionIfTryingToReadAValueThatHasntBeenCaptured = function(test) {
  299. var name = rules.sequence.capture(identifier(), "name");
  300. var parser = rules.sequence(identifier("("), identifier(")"));
  301. var result = parseString(parser, "( )");
  302. assertIsSuccess(test, result);
  303. try {
  304. result.value().get(name);
  305. test.ok(false, "Expected exception");
  306. } catch (error) {
  307. test.equal(error.message, "No value for capture \"name\"");
  308. }
  309. test.done();
  310. };
  311. exports.exceptionIfTryingToCaptureValueWithUsedName = function(test) {
  312. var firstName = rules.sequence.capture(identifier(), "name");
  313. var secondName = rules.sequence.capture(identifier(), "name");
  314. var parser = rules.sequence(secondName, identifier(","), firstName);
  315. try {
  316. parseString(parser, "Bobertson , Bob")
  317. test.ok(false, "Expected exception");
  318. } catch (error) {
  319. test.equal(error.message, "Cannot add second value for capture \"name\"");
  320. }
  321. test.done();
  322. };
  323. exports.optionalRuleDoesNothingIfValueDoesNotMatch = function(test) {
  324. var parser = rules.optional(identifier("("));
  325. var result = parseString(parser, "");
  326. assertIsSuccess(test, result);
  327. test.deepEqual(result.value(), options.none);
  328. test.done();
  329. };
  330. exports.optionalRuleConsumesInputIfPossible = function(test) {
  331. var parser = rules.optional(identifier("("));
  332. var result = parseString(parser, "(");
  333. assertIsSuccess(test, result);
  334. test.deepEqual(result.value(), options.some("("));
  335. test.done();
  336. };
  337. exports.optionalRulePreservesErrors = function(test) {
  338. var error = results.error([errors.error({
  339. expected: "something",
  340. actual: "something else"
  341. })]);
  342. var parser = rules.optional(function(input) {
  343. return error;
  344. });
  345. var result = parseString(parser, "");
  346. test.deepEqual(result, error);
  347. test.done();
  348. };
  349. exports.zeroOrMoreWithSeparatorParsesEmptyStringAndReturnsEmptyArray = function(test) {
  350. var parser = rules.zeroOrMoreWithSeparator(identifier(), identifier(","));
  351. var result = parseString(parser, "");
  352. assertIsSuccessWithValue(test, result, []);
  353. test.done();
  354. };
  355. exports.zeroOrMoreWithSeparatorParsesSingleInstanceOfRuleAndReturnsSingleElementArray = function(test) {
  356. var parser = rules.zeroOrMoreWithSeparator(identifier(), identifier(","));
  357. var result = parseString(parser, "blah");
  358. assertIsSuccessWithValue(test, result, ["blah"]);
  359. test.done();
  360. };
  361. exports.zeroOrMoreWithSeparatorParsesMultipleInstanceOfRuleAndReturnsArray = function(test) {
  362. var parser = rules.zeroOrMoreWithSeparator(identifier(), identifier(","));
  363. var result = parseString(parser, "apple , banana , coconut");
  364. assertIsSuccessWithValue(test, result, ["apple", "banana", "coconut"]);
  365. test.done();
  366. };
  367. exports.zeroOrMoreWithSeparatorDoesNotConsumeFinalSeparatorIfItIsNotFollowedByMainRule = function(test) {
  368. var parser = rules.zeroOrMoreWithSeparator(identifier(), identifier(","));
  369. var result = parseString(parser, "apple , banana ,");
  370. assertIsSuccess(test, result, {
  371. remaining: [
  372. token("identifier", ",", stringSourceRange("apple , banana ,", 15, 16)),
  373. token("end", null, stringSourceRange("apple , banana ,", 16, 16))
  374. ],
  375. });
  376. test.done();
  377. };
  378. exports.zeroOrMoreReturnsErrorIfFirstUseOfRuleReturnsError = function(test) {
  379. var parser = rules.zeroOrMoreWithSeparator(
  380. rules.sequence(identifier(), rules.sequence.cut(), identifier()),
  381. identifier(",")
  382. );
  383. var result = parseString(parser, "apple");
  384. assertIsError(test, result);
  385. test.done();
  386. };
  387. exports.zeroOrMoreParsesEmptyStringAndReturnsEmptyArray = function(test) {
  388. var parser = rules.zeroOrMore(identifier());
  389. var result = parseString(parser, "");
  390. assertIsSuccessWithValue(test, result, []);
  391. test.done();
  392. };
  393. exports.zeroOrMoreParsesSingleInstanceOfRuleAndReturnsSingleElementArray = function(test) {
  394. var parser = rules.zeroOrMore(identifier());
  395. var result = parseString(parser, "blah");
  396. assertIsSuccessWithValue(test, result, ["blah"]);
  397. test.done();
  398. };
  399. exports.zeroOrMoreParsesMultipleInstanceOfRuleAndReturnsArray = function(test) {
  400. var parser = rules.zeroOrMore(identifier());
  401. var result = parseString(parser, "( , )");
  402. assertIsSuccessWithValue(test, result, ["(", ",", ")"]);
  403. test.done();
  404. };
  405. exports.zeroOrMoreReturnsErrorIfSubRuleReturnsError = function(test) {
  406. var parser = rules.zeroOrMore(
  407. rules.sequence(identifier(), rules.sequence.cut(), identifier(";"))
  408. );
  409. var result = parseString(parser, "blah");
  410. assertIsError(test, result, {
  411. remaining:[
  412. token("end", null, stringSourceRange("blah", 4, 4))
  413. ],
  414. errors: [errors.error({
  415. expected: "identifier \";\"",
  416. actual: "end",
  417. location: stringSourceRange("blah", 4, 4)
  418. })]
  419. });
  420. test.done();
  421. };
  422. exports.oneOrMoreWithSeparatorFailsOnEmptyString = function(test) {
  423. var parser = rules.oneOrMoreWithSeparator(identifier(), identifier(","));
  424. var result = parseString(parser, "");
  425. assertIsFailure(test, result, {
  426. remaining:[
  427. token("end", null, stringSourceRange("", 0, 0))
  428. ],
  429. errors: [errors.error({
  430. expected: "identifier",
  431. actual: "end",
  432. location: stringSourceRange("", 0, 0)
  433. })]
  434. });
  435. test.done();
  436. };
  437. exports.oneOrMoreWithSeparatorParsesSingleInstanceOfRuleAndReturnsSingleElementArray = function(test) {
  438. var parser = rules.oneOrMoreWithSeparator(identifier(), identifier(","));
  439. var result = parseString(parser, "blah");
  440. assertIsSuccessWithValue(test, result, ["blah"]);
  441. test.done();
  442. };
  443. exports.oneOrMoreWithSeparatorParsesMultipleInstanceOfRuleAndReturnsArray = function(test) {
  444. var parser = rules.oneOrMoreWithSeparator(identifier(), identifier(","));
  445. var result = parseString(parser, "apple , banana , coconut");
  446. assertIsSuccessWithValue(test, result, ["apple", "banana", "coconut"]);
  447. test.done();
  448. };
  449. exports.oneOrMoreFailsOnEmptyString = function(test) {
  450. var parser = rules.oneOrMore(identifier());
  451. var result = parseString(parser, "");
  452. assertIsFailure(test, result, {
  453. remaining:[
  454. token("end", null, stringSourceRange("", 0, 0))
  455. ],
  456. errors: [errors.error({
  457. expected: "identifier",
  458. actual: "end",
  459. location: stringSourceRange("", 0, 0)
  460. })]
  461. });
  462. test.done();
  463. };
  464. exports.oneOrMoreParsesSingleInstanceOfRuleAndReturnsSingleElementArray = function(test) {
  465. var parser = rules.oneOrMore(identifier());
  466. var result = parseString(parser, "blah");
  467. assertIsSuccessWithValue(test, result, ["blah"]);
  468. test.done();
  469. };
  470. exports.oneOrMoreParsesMultipleInstanceOfRuleAndReturnsArray = function(test) {
  471. var parser = rules.oneOrMore(identifier());
  472. var result = parseString(parser, "apple banana coconut");
  473. assertIsSuccessWithValue(test, result, ["apple", "banana", "coconut"]);
  474. test.done();
  475. };
  476. exports.leftAssociativeConsumesNothingIfLeftHandSideDoesntMatch = function(test) {
  477. var parser = rules.leftAssociative(
  478. keyword(),
  479. identifier("+"),
  480. function(left, right) {
  481. return [left, right];
  482. }
  483. );
  484. var result = parseString(parser, "+ +");
  485. assertIsFailure(test, result, {
  486. remaining:[
  487. token("identifier", "+", stringSourceRange("+ +", 0, 1)),
  488. token("identifier", "+", stringSourceRange("+ +", 2, 3)),
  489. token("end", null, stringSourceRange("+ +", 3, 3))
  490. ],
  491. errors: [errors.error({
  492. expected: "keyword",
  493. actual: "identifier \"+\"",
  494. location: stringSourceRange("+ +", 0, 1)
  495. })]
  496. });
  497. test.done();
  498. };
  499. exports.leftAssociativeReturnsValueOfLeftHandSideIfRightHandSideDoesntMatch = function(test) {
  500. var parser = rules.leftAssociative(
  501. identifier(),
  502. identifier("+"),
  503. function(left, right) {
  504. return [left, right];
  505. }
  506. );
  507. var result = parseString(parser, "apple");
  508. assertIsSuccessWithValue(test, result, "apple");
  509. test.done();
  510. };
  511. exports.leftAssociativeAllowsLeftAssociativeRules = function(test) {
  512. var parser = rules.leftAssociative(
  513. identifier(),
  514. identifier("+"),
  515. function(left, right) {
  516. return [left, right];
  517. }
  518. );
  519. var result = parseString(parser, "apple + +");
  520. assertIsSuccessWithValue(test, result, [["apple", "+"], "+"]);
  521. test.done();
  522. };
  523. exports.leftAssociativeCanHaveMultipleChoicesForRight = function(test) {
  524. var parser = rules.leftAssociative(
  525. identifier(),
  526. rules.leftAssociative.firstOf(
  527. {rule: identifier("+"), func: function(left, right) { return [left, right]; }},
  528. {rule: identifier(","), func: function(left, right) { return [left]; }}
  529. )
  530. );
  531. var result = parseString(parser, "apple + ,");
  532. assertIsSuccessWithValue(test, result, [["apple", "+"]]);
  533. test.done();
  534. };
  535. exports.leftAssociativeReturnsErrorIfRightHandSideReturnsError = function(test) {
  536. var parser = rules.leftAssociative(
  537. identifier(),
  538. rules.leftAssociative.firstOf(
  539. {rule: rules.sequence(rules.sequence.cut(), identifier("+")), func: function() {}}
  540. )
  541. );
  542. var result = parseString(parser, "apple");
  543. assertIsError(test, result);
  544. test.done();
  545. };
  546. exports.nonConsumingRuleDoesNotConsumeInput = function(test) {
  547. var parser = rules.nonConsuming(rules.token("keyword", "true"));
  548. var result = parseString(parser, "true");
  549. assertIsSuccess(test, result, {
  550. value: "true",
  551. source: stringSourceRange("true", 0, 4),
  552. remaining: [token("keyword", "true"), token("end", null)]
  553. });
  554. test.done();
  555. };
  556. var parseString = function(parser, string) {
  557. var keywords = ["true", "false"];
  558. var tokens = new Tokeniser({keywords: keywords}).tokenise(string);
  559. return parser(new TokenIterator(tokens));
  560. };
  561. var parseTokens = function(parser, tokens) {
  562. return parser(new TokenIterator(tokens));
  563. };