clarinet.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. ;(function (clarinet) {
  2. // non node-js needs to set clarinet debug on root
  3. var env
  4. , fastlist
  5. ;
  6. if(typeof process === 'object' && process.env) env = process.env;
  7. else env = window;
  8. clarinet.parser = function (opt) { return new CParser(opt);};
  9. clarinet.CParser = CParser;
  10. clarinet.CStream = CStream;
  11. clarinet.createStream = createStream;
  12. clarinet.MAX_BUFFER_LENGTH = 64 * 1024;
  13. clarinet.DEBUG = (env.CDEBUG==='debug');
  14. clarinet.INFO = (env.CDEBUG==='debug' || env.CDEBUG==='info');
  15. clarinet.EVENTS =
  16. [ "value"
  17. , "string"
  18. , "key"
  19. , "openobject"
  20. , "closeobject"
  21. , "openarray"
  22. , "closearray"
  23. , "error"
  24. , "end"
  25. , "ready"
  26. ];
  27. var buffers = [ "textNode", "numberNode" ]
  28. , streamWraps = clarinet.EVENTS.filter(function (ev) {
  29. return ev !== "error" && ev !== "end";
  30. })
  31. , S = 0
  32. , Stream
  33. ;
  34. clarinet.STATE =
  35. { BEGIN : S++
  36. , VALUE : S++ // general stuff
  37. , OPEN_OBJECT : S++ // {
  38. , CLOSE_OBJECT : S++ // }
  39. , OPEN_ARRAY : S++ // [
  40. , CLOSE_ARRAY : S++ // ]
  41. , TEXT_ESCAPE : S++ // \ stuff
  42. , STRING : S++ // ""
  43. , BACKSLASH : S++
  44. , END : S++ // No more stack
  45. , OPEN_KEY : S++ // , "a"
  46. , CLOSE_KEY : S++ // :
  47. , TRUE : S++ // r
  48. , TRUE2 : S++ // u
  49. , TRUE3 : S++ // e
  50. , FALSE : S++ // a
  51. , FALSE2 : S++ // l
  52. , FALSE3 : S++ // s
  53. , FALSE4 : S++ // e
  54. , NULL : S++ // u
  55. , NULL2 : S++ // l
  56. , NULL3 : S++ // l
  57. , NUMBER_DECIMAL_POINT : S++ // .
  58. , NUMBER_DIGIT : S++ // [0-9]
  59. };
  60. for (var s_ in clarinet.STATE) clarinet.STATE[clarinet.STATE[s_]] = s_;
  61. // switcharoo
  62. S = clarinet.STATE;
  63. if (!Object.create) {
  64. Object.create = function (o) {
  65. function f () { this["__proto__"] = o; }
  66. f.prototype = o;
  67. return new f;
  68. };
  69. }
  70. if (!Object.getPrototypeOf) {
  71. Object.getPrototypeOf = function (o) {
  72. return o["__proto__"];
  73. };
  74. }
  75. if (!Object.keys) {
  76. Object.keys = function (o) {
  77. var a = [];
  78. for (var i in o) if (o.hasOwnProperty(i)) a.push(i);
  79. return a;
  80. };
  81. }
  82. function checkBufferLength (parser) {
  83. var maxAllowed = Math.max(clarinet.MAX_BUFFER_LENGTH, 10)
  84. , maxActual = 0
  85. ;
  86. for (var i = 0, l = buffers.length; i < l; i ++) {
  87. var len = parser[buffers[i]].length;
  88. if (len > maxAllowed) {
  89. switch (buffers[i]) {
  90. case "text":
  91. closeText(parser);
  92. break;
  93. default:
  94. error(parser, "Max buffer length exceeded: "+ buffers[i]);
  95. }
  96. }
  97. maxActual = Math.max(maxActual, len);
  98. }
  99. parser.bufferCheckPosition = (clarinet.MAX_BUFFER_LENGTH - maxActual)
  100. + parser.position;
  101. }
  102. function clearBuffers (parser) {
  103. for (var i = 0, l = buffers.length; i < l; i ++) {
  104. parser[buffers[i]] = "";
  105. }
  106. }
  107. var stringTokenPattern = /[\\"\n]/g;
  108. function CParser (opt) {
  109. if (!(this instanceof CParser)) return new CParser (opt);
  110. var parser = this;
  111. clearBuffers(parser);
  112. parser.bufferCheckPosition = clarinet.MAX_BUFFER_LENGTH;
  113. parser.q = parser.c = parser.p = "";
  114. parser.opt = opt || {};
  115. parser.closed = parser.closedRoot = parser.sawRoot = false;
  116. parser.tag = parser.error = null;
  117. parser.state = S.BEGIN;
  118. parser.stack = new Array();
  119. // mostly just for error reporting
  120. parser.position = parser.column = 0;
  121. parser.line = 1;
  122. parser.slashed = false;
  123. parser.unicodeI = 0;
  124. parser.unicodeS = null;
  125. parser.depth = 0;
  126. emit(parser, "onready");
  127. }
  128. CParser.prototype =
  129. { end : function () { end(this); }
  130. , write : write
  131. , resume : function () { this.error = null; return this; }
  132. , close : function () { return this.write(null); }
  133. };
  134. try { Stream = require("stream").Stream; }
  135. catch (ex) { Stream = function () {}; }
  136. function createStream (opt) { return new CStream(opt); }
  137. function CStream (opt) {
  138. if (!(this instanceof CStream)) return new CStream(opt);
  139. this._parser = new CParser(opt);
  140. this.writable = true;
  141. this.readable = true;
  142. //var Buffer = this.Buffer || function Buffer () {}; // if we don't have Buffers, fake it so we can do `var instanceof Buffer` and not throw an error
  143. this.bytes_remaining = 0; // number of bytes remaining in multi byte utf8 char to read after split boundary
  144. this.bytes_in_sequence = 0; // bytes in multi byte utf8 char to read
  145. this.temp_buffs = { "2": new Buffer(2), "3": new Buffer(3), "4": new Buffer(4) }; // for rebuilding chars split before boundary is reached
  146. this.string = '';
  147. var me = this;
  148. Stream.apply(me);
  149. this._parser.onend = function () { me.emit("end"); };
  150. this._parser.onerror = function (er) {
  151. me.emit("error", er);
  152. me._parser.error = null;
  153. };
  154. streamWraps.forEach(function (ev) {
  155. Object.defineProperty(me, "on" + ev,
  156. { get : function () { return me._parser["on" + ev]; }
  157. , set : function (h) {
  158. if (!h) {
  159. me.removeAllListeners(ev);
  160. me._parser["on"+ev] = h;
  161. return h;
  162. }
  163. me.on(ev, h);
  164. }
  165. , enumerable : true
  166. , configurable : false
  167. });
  168. });
  169. }
  170. CStream.prototype = Object.create(Stream.prototype,
  171. { constructor: { value: CStream } });
  172. CStream.prototype.write = function (data) {
  173. data = new Buffer(data);
  174. for (var i = 0; i < data.length; i++) {
  175. var n = data[i];
  176. // check for carry over of a multi byte char split between data chunks
  177. // & fill temp buffer it with start of this data chunk up to the boundary limit set in the last iteration
  178. if (this.bytes_remaining > 0) {
  179. for (var j = 0; j < this.bytes_remaining; j++) {
  180. this.temp_buffs[this.bytes_in_sequence][this.bytes_in_sequence - this.bytes_remaining + j] = data[j];
  181. }
  182. this.string = this.temp_buffs[this.bytes_in_sequence].toString();
  183. this.bytes_in_sequence = this.bytes_remaining = 0;
  184. // move iterator forward by number of byte read during sequencing
  185. i = i + j - 1;
  186. // pass data to parser and move forward to parse rest of data
  187. this._parser.write(this.string);
  188. this.emit("data", this.string);
  189. continue;
  190. }
  191. // if no remainder bytes carried over, parse multi byte (>=128) chars one at a time
  192. if (this.bytes_remaining === 0 && n >= 128) {
  193. if ((n >= 194) && (n <= 223)) this.bytes_in_sequence = 2;
  194. if ((n >= 224) && (n <= 239)) this.bytes_in_sequence = 3;
  195. if ((n >= 240) && (n <= 244)) this.bytes_in_sequence = 4;
  196. if ((this.bytes_in_sequence + i) > data.length) { // if bytes needed to complete char fall outside data length, we have a boundary split
  197. for (var k = 0; k <= (data.length - 1 - i); k++) {
  198. this.temp_buffs[this.bytes_in_sequence][k] = data[i + k]; // fill temp data of correct size with bytes available in this chunk
  199. }
  200. this.bytes_remaining = (i + this.bytes_in_sequence) - data.length;
  201. // immediately return as we need another chunk to sequence the character
  202. return true;
  203. } else {
  204. this.string = data.slice(i, (i + this.bytes_in_sequence)).toString();
  205. i = i + this.bytes_in_sequence - 1;
  206. this._parser.write(this.string);
  207. this.emit("data", this.string);
  208. continue;
  209. }
  210. }
  211. // is there a range of characters that are immediately parsable?
  212. for (var p = i; p < data.length; p++) {
  213. if (data[p] >= 128) break;
  214. }
  215. this.string = data.slice(i, p).toString();
  216. this._parser.write(this.string);
  217. this.emit("data", this.string);
  218. i = p - 1;
  219. // handle any remaining characters using multibyte logic
  220. continue;
  221. }
  222. };
  223. CStream.prototype.end = function (chunk) {
  224. if (chunk && chunk.length) this._parser.write(chunk.toString());
  225. this._parser.end();
  226. return true;
  227. };
  228. CStream.prototype.on = function (ev, handler) {
  229. var me = this;
  230. if (!me._parser["on"+ev] && streamWraps.indexOf(ev) !== -1) {
  231. me._parser["on"+ev] = function () {
  232. var args = arguments.length === 1 ? [arguments[0]]
  233. : Array.apply(null, arguments);
  234. args.splice(0, 0, ev);
  235. me.emit.apply(me, args);
  236. };
  237. }
  238. return Stream.prototype.on.call(me, ev, handler);
  239. };
  240. CStream.prototype.destroy = function () {
  241. clearBuffers(this._parser);
  242. this.emit("close");
  243. };
  244. function emit(parser, event, data) {
  245. if(clarinet.INFO) console.log('-- emit', event, data);
  246. if (parser[event]) parser[event](data);
  247. }
  248. function emitNode(parser, event, data) {
  249. closeValue(parser);
  250. emit(parser, event, data);
  251. }
  252. function closeValue(parser, event) {
  253. parser.textNode = textopts(parser.opt, parser.textNode);
  254. if (parser.textNode) {
  255. emit(parser, (event ? event : "onvalue"), parser.textNode);
  256. }
  257. parser.textNode = "";
  258. }
  259. function closeNumber(parser) {
  260. if (parser.numberNode)
  261. emit(parser, "onvalue", parseFloat(parser.numberNode));
  262. parser.numberNode = "";
  263. }
  264. function textopts (opt, text) {
  265. if (opt.trim) text = text.trim();
  266. if (opt.normalize) text = text.replace(/\s+/g, " ");
  267. return text;
  268. }
  269. function error (parser, er) {
  270. closeValue(parser);
  271. er += "\nLine: "+parser.line+
  272. "\nColumn: "+parser.column+
  273. "\nChar: "+parser.c;
  274. er = new Error(er);
  275. parser.error = er;
  276. emit(parser, "onerror", er);
  277. return parser;
  278. }
  279. function end(parser) {
  280. if (parser.state !== S.VALUE || parser.depth !== 0)
  281. error(parser, "Unexpected end");
  282. closeValue(parser);
  283. parser.c = "";
  284. parser.closed = true;
  285. emit(parser, "onend");
  286. CParser.call(parser, parser.opt);
  287. return parser;
  288. }
  289. function write (chunk) {
  290. var parser = this;
  291. if (this.error) throw this.error;
  292. if (parser.closed) return error(parser,
  293. "Cannot write after close. Assign an onready handler.");
  294. if (chunk === null) return end(parser);
  295. var i = 0, c = chunk[0], p = parser.p;
  296. if (clarinet.DEBUG) console.log('write -> [' + chunk + ']');
  297. while (c) {
  298. p = c;
  299. parser.c = c = chunk.charAt(i++);
  300. // if chunk doesnt have next, like streaming char by char
  301. // this way we need to check if previous is really previous
  302. // if not we need to reset to what the parser says is the previous
  303. // from buffer
  304. if(p !== c ) parser.p = p;
  305. else p = parser.p;
  306. if(!c) break;
  307. if (clarinet.DEBUG) console.log(i,c,clarinet.STATE[parser.state]);
  308. parser.position ++;
  309. if (c === "\n") {
  310. parser.line ++;
  311. parser.column = 0;
  312. } else parser.column ++;
  313. switch (parser.state) {
  314. case S.BEGIN:
  315. if (c === "{") parser.state = S.OPEN_OBJECT;
  316. else if (c === "[") parser.state = S.OPEN_ARRAY;
  317. else if (c !== '\r' && c !== '\n' && c !== ' ' && c !== '\t')
  318. error(parser, "Non-whitespace before {[.");
  319. continue;
  320. case S.OPEN_KEY:
  321. case S.OPEN_OBJECT:
  322. if (c === '\r' || c === '\n' || c === ' ' || c === '\t') continue;
  323. if(parser.state === S.OPEN_KEY) parser.stack.push(S.CLOSE_KEY);
  324. else {
  325. if(c === '}') {
  326. emit(parser, 'onopenobject');
  327. this.depth++;
  328. emit(parser, 'oncloseobject');
  329. this.depth--;
  330. parser.state = parser.stack.pop() || S.VALUE;
  331. continue;
  332. } else parser.stack.push(S.CLOSE_OBJECT);
  333. }
  334. if(c === '"') parser.state = S.STRING;
  335. else error(parser, "Malformed object key should start with \"");
  336. continue;
  337. case S.CLOSE_KEY:
  338. case S.CLOSE_OBJECT:
  339. if (c === '\r' || c === '\n' || c === ' ' || c === '\t') continue;
  340. var event = (parser.state === S.CLOSE_KEY) ? 'key' : 'object';
  341. if(c===':') {
  342. if(parser.state === S.CLOSE_OBJECT) {
  343. parser.stack.push(S.CLOSE_OBJECT);
  344. closeValue(parser, 'onopenobject');
  345. this.depth++;
  346. } else closeValue(parser, 'onkey');
  347. parser.state = S.VALUE;
  348. } else if (c==='}') {
  349. emitNode(parser, 'oncloseobject');
  350. this.depth--;
  351. parser.state = parser.stack.pop() || S.VALUE;
  352. } else if(c===',') {
  353. if(parser.state === S.CLOSE_OBJECT)
  354. parser.stack.push(S.CLOSE_OBJECT);
  355. closeValue(parser);
  356. parser.state = S.OPEN_KEY;
  357. } else error(parser, 'Bad object');
  358. continue;
  359. case S.OPEN_ARRAY: // after an array there always a value
  360. case S.VALUE:
  361. if (c === '\r' || c === '\n' || c === ' ' || c === '\t') continue;
  362. if(parser.state===S.OPEN_ARRAY) {
  363. emit(parser, 'onopenarray');
  364. this.depth++;
  365. parser.state = S.VALUE;
  366. if(c === ']') {
  367. emit(parser, 'onclosearray');
  368. this.depth--;
  369. parser.state = parser.stack.pop() || S.VALUE;
  370. continue;
  371. } else {
  372. parser.stack.push(S.CLOSE_ARRAY);
  373. }
  374. }
  375. if(c === '"') parser.state = S.STRING;
  376. else if(c === '{') parser.state = S.OPEN_OBJECT;
  377. else if(c === '[') parser.state = S.OPEN_ARRAY;
  378. else if(c === 't') parser.state = S.TRUE;
  379. else if(c === 'f') parser.state = S.FALSE;
  380. else if(c === 'n') parser.state = S.NULL;
  381. else if(c === '-') { // keep and continue
  382. parser.numberNode += c;
  383. } else if(c==='0') {
  384. parser.numberNode += c;
  385. parser.state = S.NUMBER_DIGIT;
  386. } else if('123456789'.indexOf(c) !== -1) {
  387. parser.numberNode += c;
  388. parser.state = S.NUMBER_DIGIT;
  389. } else error(parser, "Bad value");
  390. continue;
  391. case S.CLOSE_ARRAY:
  392. if(c===',') {
  393. parser.stack.push(S.CLOSE_ARRAY);
  394. closeValue(parser, 'onvalue');
  395. parser.state = S.VALUE;
  396. } else if (c===']') {
  397. emitNode(parser, 'onclosearray');
  398. this.depth--;
  399. parser.state = parser.stack.pop() || S.VALUE;
  400. } else if (c === '\r' || c === '\n' || c === ' ' || c === '\t')
  401. continue;
  402. else error(parser, 'Bad array');
  403. continue;
  404. case S.STRING:
  405. // thanks thejh, this is an about 50% performance improvement.
  406. var starti = i-1
  407. , slashed = parser.slashed
  408. , unicodeI = parser.unicodeI
  409. ;
  410. STRING_BIGLOOP: while (true) {
  411. if (clarinet.DEBUG)
  412. console.log(i,c,clarinet.STATE[parser.state]
  413. ,slashed);
  414. // zero means "no unicode active". 1-4 mean "parse some more". end after 4.
  415. while (unicodeI > 0) {
  416. parser.unicodeS += c;
  417. c = chunk.charAt(i++);
  418. parser.position++;
  419. if (unicodeI === 4) {
  420. // TODO this might be slow? well, probably not used too often anyway
  421. parser.textNode += String.fromCharCode(parseInt(parser.unicodeS, 16));
  422. unicodeI = 0;
  423. starti = i-1;
  424. } else {
  425. unicodeI++;
  426. }
  427. // we can just break here: no stuff we skipped that still has to be sliced out or so
  428. if (!c) break STRING_BIGLOOP;
  429. }
  430. if (c === '"' && !slashed) {
  431. parser.state = parser.stack.pop() || S.VALUE;
  432. parser.textNode += chunk.substring(starti, i-1);
  433. parser.position += i - 1 - starti;
  434. if(!parser.textNode) {
  435. emit(parser, "onvalue", "");
  436. }
  437. break;
  438. }
  439. if (c === '\\' && !slashed) {
  440. slashed = true;
  441. parser.textNode += chunk.substring(starti, i-1);
  442. parser.position += i - 1 - starti;
  443. c = chunk.charAt(i++);
  444. parser.position++;
  445. if (!c) break;
  446. }
  447. if (slashed) {
  448. slashed = false;
  449. if (c === 'n') { parser.textNode += '\n'; }
  450. else if (c === 'r') { parser.textNode += '\r'; }
  451. else if (c === 't') { parser.textNode += '\t'; }
  452. else if (c === 'f') { parser.textNode += '\f'; }
  453. else if (c === 'b') { parser.textNode += '\b'; }
  454. else if (c === 'u') {
  455. // \uxxxx. meh!
  456. unicodeI = 1;
  457. parser.unicodeS = '';
  458. } else {
  459. parser.textNode += c;
  460. }
  461. c = chunk.charAt(i++);
  462. parser.position++;
  463. starti = i-1;
  464. if (!c) break;
  465. else continue;
  466. }
  467. stringTokenPattern.lastIndex = i;
  468. var reResult = stringTokenPattern.exec(chunk);
  469. if (reResult === null) {
  470. i = chunk.length+1;
  471. parser.textNode += chunk.substring(starti, i-1);
  472. parser.position += i - 1 - starti;
  473. break;
  474. }
  475. i = reResult.index+1;
  476. c = chunk.charAt(reResult.index);
  477. if (!c) {
  478. parser.textNode += chunk.substring(starti, i-1);
  479. parser.position += i - 1 - starti;
  480. break;
  481. }
  482. }
  483. parser.slashed = slashed;
  484. parser.unicodeI = unicodeI;
  485. continue;
  486. case S.TRUE:
  487. if (c==='') continue; // strange buffers
  488. if (c==='r') parser.state = S.TRUE2;
  489. else error(parser, 'Invalid true started with t'+ c);
  490. continue;
  491. case S.TRUE2:
  492. if (c==='') continue;
  493. if (c==='u') parser.state = S.TRUE3;
  494. else error(parser, 'Invalid true started with tr'+ c);
  495. continue;
  496. case S.TRUE3:
  497. if (c==='') continue;
  498. if(c==='e') {
  499. emit(parser, "onvalue", true);
  500. parser.state = parser.stack.pop() || S.VALUE;
  501. } else error(parser, 'Invalid true started with tru'+ c);
  502. continue;
  503. case S.FALSE:
  504. if (c==='') continue;
  505. if (c==='a') parser.state = S.FALSE2;
  506. else error(parser, 'Invalid false started with f'+ c);
  507. continue;
  508. case S.FALSE2:
  509. if (c==='') continue;
  510. if (c==='l') parser.state = S.FALSE3;
  511. else error(parser, 'Invalid false started with fa'+ c);
  512. continue;
  513. case S.FALSE3:
  514. if (c==='') continue;
  515. if (c==='s') parser.state = S.FALSE4;
  516. else error(parser, 'Invalid false started with fal'+ c);
  517. continue;
  518. case S.FALSE4:
  519. if (c==='') continue;
  520. if (c==='e') {
  521. emit(parser, "onvalue", false);
  522. parser.state = parser.stack.pop() || S.VALUE;
  523. } else error(parser, 'Invalid false started with fals'+ c);
  524. continue;
  525. case S.NULL:
  526. if (c==='') continue;
  527. if (c==='u') parser.state = S.NULL2;
  528. else error(parser, 'Invalid null started with n'+ c);
  529. continue;
  530. case S.NULL2:
  531. if (c==='') continue;
  532. if (c==='l') parser.state = S.NULL3;
  533. else error(parser, 'Invalid null started with nu'+ c);
  534. continue;
  535. case S.NULL3:
  536. if (c==='') continue;
  537. if(c==='l') {
  538. emit(parser, "onvalue", null);
  539. parser.state = parser.stack.pop() || S.VALUE;
  540. } else error(parser, 'Invalid null started with nul'+ c);
  541. continue;
  542. case S.NUMBER_DECIMAL_POINT:
  543. if(c==='.') {
  544. parser.numberNode += c;
  545. parser.state = S.NUMBER_DIGIT;
  546. } else error(parser, 'Leading zero not followed by .');
  547. continue;
  548. case S.NUMBER_DIGIT:
  549. if('0123456789'.indexOf(c) !== -1) parser.numberNode += c;
  550. else if (c==='.') {
  551. if(parser.numberNode.indexOf('.')!==-1)
  552. error(parser, 'Invalid number has two dots');
  553. parser.numberNode += c;
  554. } else if (c==='e' || c==='E') {
  555. if(parser.numberNode.indexOf('e')!==-1 ||
  556. parser.numberNode.indexOf('E')!==-1 )
  557. error(parser, 'Invalid number has two exponential');
  558. parser.numberNode += c;
  559. } else if (c==="+" || c==="-") {
  560. if(!(p==='e' || p==='E'))
  561. error(parser, 'Invalid symbol in number');
  562. parser.numberNode += c;
  563. } else {
  564. closeNumber(parser);
  565. i--; // go back one
  566. parser.state = parser.stack.pop() || S.VALUE;
  567. }
  568. continue;
  569. default:
  570. error(parser, "Unknown state: " + parser.state);
  571. }
  572. }
  573. if (parser.position >= parser.bufferCheckPosition)
  574. checkBufferLength(parser);
  575. return parser;
  576. }
  577. })(typeof exports === "undefined" ? clarinet = {} : exports);