JavaScriptFormatter.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * Copyright (C) 2011 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. function FormattedContentBuilder(content, mapping, originalOffset, formattedOffset, indentString)
  31. {
  32. this._originalContent = content;
  33. this._originalOffset = originalOffset;
  34. this._lastOriginalPosition = 0;
  35. this._formattedContent = [];
  36. this._formattedContentLength = 0;
  37. this._formattedOffset = formattedOffset;
  38. this._lastFormattedPosition = 0;
  39. this._mapping = mapping;
  40. this._lineNumber = 0;
  41. this._nestingLevel = 0;
  42. this._indentString = indentString;
  43. this._cachedIndents = {};
  44. }
  45. FormattedContentBuilder.prototype = {
  46. addToken: function(token)
  47. {
  48. for (var i = 0; i < token.comments_before.length; ++i)
  49. this._addComment(token.comments_before[i]);
  50. while (this._lineNumber < token.line) {
  51. this._addText("\n");
  52. this._addIndent();
  53. this._needNewLine = false;
  54. this._lineNumber += 1;
  55. }
  56. if (this._needNewLine) {
  57. this._addText("\n");
  58. this._addIndent();
  59. this._needNewLine = false;
  60. }
  61. this._addMappingIfNeeded(token.pos);
  62. this._addText(this._originalContent.substring(token.pos, token.endPos));
  63. this._lineNumber = token.endLine;
  64. },
  65. addSpace: function()
  66. {
  67. this._addText(" ");
  68. },
  69. addNewLine: function()
  70. {
  71. this._needNewLine = true;
  72. },
  73. increaseNestingLevel: function()
  74. {
  75. this._nestingLevel += 1;
  76. },
  77. decreaseNestingLevel: function()
  78. {
  79. this._nestingLevel -= 1;
  80. },
  81. content: function()
  82. {
  83. return this._formattedContent.join("");
  84. },
  85. mapping: function()
  86. {
  87. return { original: this._originalPositions, formatted: this._formattedPositions };
  88. },
  89. _addIndent: function()
  90. {
  91. if (this._cachedIndents[this._nestingLevel]) {
  92. this._addText(this._cachedIndents[this._nestingLevel]);
  93. return;
  94. }
  95. var fullIndent = "";
  96. for (var i = 0; i < this._nestingLevel; ++i)
  97. fullIndent += this._indentString;
  98. this._addText(fullIndent);
  99. // Cache a maximum of 20 nesting level indents.
  100. if (this._nestingLevel <= 20)
  101. this._cachedIndents[this._nestingLevel] = fullIndent;
  102. },
  103. _addComment: function(comment)
  104. {
  105. if (this._lineNumber < comment.line) {
  106. for (var j = this._lineNumber; j < comment.line; ++j)
  107. this._addText("\n");
  108. this._lineNumber = comment.line;
  109. this._needNewLine = false;
  110. this._addIndent();
  111. } else
  112. this.addSpace();
  113. this._addMappingIfNeeded(comment.pos);
  114. if (comment.type === "comment1")
  115. this._addText("//");
  116. else
  117. this._addText("/*");
  118. this._addText(comment.value);
  119. if (comment.type !== "comment1") {
  120. this._addText("*/");
  121. var position;
  122. while ((position = comment.value.indexOf("\n", position + 1)) !== -1)
  123. this._lineNumber += 1;
  124. }
  125. },
  126. _addText: function(text)
  127. {
  128. this._formattedContent.push(text);
  129. this._formattedContentLength += text.length;
  130. },
  131. _addMappingIfNeeded: function(originalPosition)
  132. {
  133. if (originalPosition - this._lastOriginalPosition === this._formattedContentLength - this._lastFormattedPosition)
  134. return;
  135. this._mapping.original.push(this._originalOffset + originalPosition);
  136. this._lastOriginalPosition = originalPosition;
  137. this._mapping.formatted.push(this._formattedOffset + this._formattedContentLength);
  138. this._lastFormattedPosition = this._formattedContentLength;
  139. }
  140. }
  141. var tokens = [
  142. ["EOS"],
  143. ["LPAREN", "("], ["RPAREN", ")"], ["LBRACK", "["], ["RBRACK", "]"], ["LBRACE", "{"], ["RBRACE", "}"], ["COLON", ":"], ["SEMICOLON", ";"], ["PERIOD", "."], ["CONDITIONAL", "?"],
  144. ["INC", "++"], ["DEC", "--"],
  145. ["ASSIGN", "="], ["ASSIGN_BIT_OR", "|="], ["ASSIGN_BIT_XOR", "^="], ["ASSIGN_BIT_AND", "&="], ["ASSIGN_SHL", "<<="], ["ASSIGN_SAR", ">>="], ["ASSIGN_SHR", ">>>="],
  146. ["ASSIGN_ADD", "+="], ["ASSIGN_SUB", "-="], ["ASSIGN_MUL", "*="], ["ASSIGN_DIV", "/="], ["ASSIGN_MOD", "%="],
  147. ["COMMA", ","], ["OR", "||"], ["AND", "&&"], ["BIT_OR", "|"], ["BIT_XOR", "^"], ["BIT_AND", "&"], ["SHL", "<<"], ["SAR", ">>"], ["SHR", ">>>"],
  148. ["ADD", "+"], ["SUB", "-"], ["MUL", "*"], ["DIV", "/"], ["MOD", "%"],
  149. ["EQ", "=="], ["NE", "!="], ["EQ_STRICT", "==="], ["NE_STRICT", "!=="], ["LT", "<"], ["GT", ">"], ["LTE", "<="], ["GTE", ">="],
  150. ["INSTANCEOF", "instanceof"], ["IN", "in"], ["NOT", "!"], ["BIT_NOT", "~"], ["DELETE", "delete"], ["TYPEOF", "typeof"], ["VOID", "void"],
  151. ["BREAK", "break"], ["CASE", "case"], ["CATCH", "catch"], ["CONTINUE", "continue"], ["DEBUGGER", "debugger"], ["DEFAULT", "default"], ["DO", "do"], ["ELSE", "else"], ["FINALLY", "finally"],
  152. ["FOR", "for"], ["FUNCTION", "function"], ["IF", "if"], ["NEW", "new"], ["RETURN", "return"], ["SWITCH", "switch"], ["THIS", "this"], ["THROW", "throw"], ["TRY", "try"], ["VAR", "var"],
  153. ["WHILE", "while"], ["WITH", "with"], ["NULL_LITERAL", "null"], ["TRUE_LITERAL", "true"], ["FALSE_LITERAL", "false"], ["NUMBER"], ["STRING"], ["IDENTIFIER"], ["CONST", "const"]
  154. ];
  155. var Tokens = {};
  156. for (var i = 0; i < tokens.length; ++i)
  157. Tokens[tokens[i][0]] = i;
  158. var TokensByValue = {};
  159. for (var i = 0; i < tokens.length; ++i) {
  160. if (tokens[i][1])
  161. TokensByValue[tokens[i][1]] = i;
  162. }
  163. var TokensByType = {
  164. "eof": Tokens.EOS,
  165. "name": Tokens.IDENTIFIER,
  166. "num": Tokens.NUMBER,
  167. "regexp": Tokens.DIV,
  168. "string": Tokens.STRING
  169. };
  170. function Tokenizer(content)
  171. {
  172. this._readNextToken = parse.tokenizer(content);
  173. this._state = this._readNextToken.context();
  174. }
  175. Tokenizer.prototype = {
  176. content: function()
  177. {
  178. return this._state.text;
  179. },
  180. next: function(forceRegexp)
  181. {
  182. var uglifyToken = this._readNextToken(forceRegexp);
  183. uglifyToken.endPos = this._state.pos;
  184. uglifyToken.endLine = this._state.line;
  185. uglifyToken.token = this._convertUglifyToken(uglifyToken);
  186. return uglifyToken;
  187. },
  188. _convertUglifyToken: function(uglifyToken)
  189. {
  190. var token = TokensByType[uglifyToken.type];
  191. if (typeof token === "number")
  192. return token;
  193. token = TokensByValue[uglifyToken.value];
  194. if (typeof token === "number")
  195. return token;
  196. throw "Unknown token type " + uglifyToken.type;
  197. }
  198. }
  199. function JavaScriptFormatter(tokenizer, builder)
  200. {
  201. this._tokenizer = tokenizer;
  202. this._builder = builder;
  203. this._token = null;
  204. this._nextToken = this._tokenizer.next();
  205. }
  206. JavaScriptFormatter.prototype = {
  207. format: function()
  208. {
  209. this._parseSourceElements(Tokens.EOS);
  210. this._consume(Tokens.EOS);
  211. },
  212. _peek: function()
  213. {
  214. return this._nextToken.token;
  215. },
  216. _next: function()
  217. {
  218. if (this._token && this._token.token === Tokens.EOS)
  219. throw "Unexpected EOS token";
  220. this._builder.addToken(this._nextToken);
  221. this._token = this._nextToken;
  222. this._nextToken = this._tokenizer.next(this._forceRegexp);
  223. this._forceRegexp = false;
  224. return this._token.token;
  225. },
  226. _consume: function(token)
  227. {
  228. var next = this._next();
  229. if (next !== token)
  230. throw "Unexpected token in consume: expected " + token + ", actual " + next;
  231. },
  232. _expect: function(token)
  233. {
  234. var next = this._next();
  235. if (next !== token)
  236. throw "Unexpected token: expected " + token + ", actual " + next;
  237. },
  238. _expectSemicolon: function()
  239. {
  240. if (this._peek() === Tokens.SEMICOLON)
  241. this._consume(Tokens.SEMICOLON);
  242. },
  243. _hasLineTerminatorBeforeNext: function()
  244. {
  245. return this._nextToken.nlb;
  246. },
  247. _parseSourceElements: function(endToken)
  248. {
  249. while (this._peek() !== endToken) {
  250. this._parseStatement();
  251. this._builder.addNewLine();
  252. }
  253. },
  254. _parseStatementOrBlock: function()
  255. {
  256. if (this._peek() === Tokens.LBRACE) {
  257. this._builder.addSpace();
  258. this._parseBlock();
  259. return true;
  260. }
  261. this._builder.addNewLine();
  262. this._builder.increaseNestingLevel();
  263. this._parseStatement();
  264. this._builder.decreaseNestingLevel();
  265. },
  266. _parseStatement: function()
  267. {
  268. switch (this._peek()) {
  269. case Tokens.LBRACE:
  270. return this._parseBlock();
  271. case Tokens.CONST:
  272. case Tokens.VAR:
  273. return this._parseVariableStatement();
  274. case Tokens.SEMICOLON:
  275. return this._next();
  276. case Tokens.IF:
  277. return this._parseIfStatement();
  278. case Tokens.DO:
  279. return this._parseDoWhileStatement();
  280. case Tokens.WHILE:
  281. return this._parseWhileStatement();
  282. case Tokens.FOR:
  283. return this._parseForStatement();
  284. case Tokens.CONTINUE:
  285. return this._parseContinueStatement();
  286. case Tokens.BREAK:
  287. return this._parseBreakStatement();
  288. case Tokens.RETURN:
  289. return this._parseReturnStatement();
  290. case Tokens.WITH:
  291. return this._parseWithStatement();
  292. case Tokens.SWITCH:
  293. return this._parseSwitchStatement();
  294. case Tokens.THROW:
  295. return this._parseThrowStatement();
  296. case Tokens.TRY:
  297. return this._parseTryStatement();
  298. case Tokens.FUNCTION:
  299. return this._parseFunctionDeclaration();
  300. case Tokens.DEBUGGER:
  301. return this._parseDebuggerStatement();
  302. default:
  303. return this._parseExpressionOrLabelledStatement();
  304. }
  305. },
  306. _parseFunctionDeclaration: function()
  307. {
  308. this._expect(Tokens.FUNCTION);
  309. this._builder.addSpace();
  310. this._expect(Tokens.IDENTIFIER);
  311. this._parseFunctionLiteral()
  312. },
  313. _parseBlock: function()
  314. {
  315. this._expect(Tokens.LBRACE);
  316. this._builder.addNewLine();
  317. this._builder.increaseNestingLevel();
  318. while (this._peek() !== Tokens.RBRACE) {
  319. this._parseStatement();
  320. this._builder.addNewLine();
  321. }
  322. this._builder.decreaseNestingLevel();
  323. this._expect(Tokens.RBRACE);
  324. },
  325. _parseVariableStatement: function()
  326. {
  327. this._parseVariableDeclarations();
  328. this._expectSemicolon();
  329. },
  330. _parseVariableDeclarations: function()
  331. {
  332. if (this._peek() === Tokens.VAR)
  333. this._consume(Tokens.VAR);
  334. else
  335. this._consume(Tokens.CONST)
  336. this._builder.addSpace();
  337. var isFirstVariable = true;
  338. do {
  339. if (!isFirstVariable) {
  340. this._consume(Tokens.COMMA);
  341. this._builder.addSpace();
  342. }
  343. isFirstVariable = false;
  344. this._expect(Tokens.IDENTIFIER);
  345. if (this._peek() === Tokens.ASSIGN) {
  346. this._builder.addSpace();
  347. this._consume(Tokens.ASSIGN);
  348. this._builder.addSpace();
  349. this._parseAssignmentExpression();
  350. }
  351. } while (this._peek() === Tokens.COMMA);
  352. },
  353. _parseExpressionOrLabelledStatement: function()
  354. {
  355. this._parseExpression();
  356. if (this._peek() === Tokens.COLON) {
  357. this._expect(Tokens.COLON);
  358. this._builder.addSpace();
  359. this._parseStatement();
  360. }
  361. this._expectSemicolon();
  362. },
  363. _parseIfStatement: function()
  364. {
  365. this._expect(Tokens.IF);
  366. this._builder.addSpace();
  367. this._expect(Tokens.LPAREN);
  368. this._parseExpression();
  369. this._expect(Tokens.RPAREN);
  370. var isBlock = this._parseStatementOrBlock();
  371. if (this._peek() === Tokens.ELSE) {
  372. if (isBlock)
  373. this._builder.addSpace();
  374. else
  375. this._builder.addNewLine();
  376. this._next();
  377. if (this._peek() === Tokens.IF) {
  378. this._builder.addSpace();
  379. this._parseStatement();
  380. } else
  381. this._parseStatementOrBlock();
  382. }
  383. },
  384. _parseContinueStatement: function()
  385. {
  386. this._expect(Tokens.CONTINUE);
  387. var token = this._peek();
  388. if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
  389. this._builder.addSpace();
  390. this._expect(Tokens.IDENTIFIER);
  391. }
  392. this._expectSemicolon();
  393. },
  394. _parseBreakStatement: function()
  395. {
  396. this._expect(Tokens.BREAK);
  397. var token = this._peek();
  398. if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
  399. this._builder.addSpace();
  400. this._expect(Tokens.IDENTIFIER);
  401. }
  402. this._expectSemicolon();
  403. },
  404. _parseReturnStatement: function()
  405. {
  406. this._expect(Tokens.RETURN);
  407. var token = this._peek();
  408. if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
  409. this._builder.addSpace();
  410. this._parseExpression();
  411. }
  412. this._expectSemicolon();
  413. },
  414. _parseWithStatement: function()
  415. {
  416. this._expect(Tokens.WITH);
  417. this._builder.addSpace();
  418. this._expect(Tokens.LPAREN);
  419. this._parseExpression();
  420. this._expect(Tokens.RPAREN);
  421. this._parseStatementOrBlock();
  422. },
  423. _parseCaseClause: function()
  424. {
  425. if (this._peek() === Tokens.CASE) {
  426. this._expect(Tokens.CASE);
  427. this._builder.addSpace();
  428. this._parseExpression();
  429. } else
  430. this._expect(Tokens.DEFAULT);
  431. this._expect(Tokens.COLON);
  432. this._builder.addNewLine();
  433. this._builder.increaseNestingLevel();
  434. while (this._peek() !== Tokens.CASE && this._peek() !== Tokens.DEFAULT && this._peek() !== Tokens.RBRACE) {
  435. this._parseStatement();
  436. this._builder.addNewLine();
  437. }
  438. this._builder.decreaseNestingLevel();
  439. },
  440. _parseSwitchStatement: function()
  441. {
  442. this._expect(Tokens.SWITCH);
  443. this._builder.addSpace();
  444. this._expect(Tokens.LPAREN);
  445. this._parseExpression();
  446. this._expect(Tokens.RPAREN);
  447. this._builder.addSpace();
  448. this._expect(Tokens.LBRACE);
  449. this._builder.addNewLine();
  450. this._builder.increaseNestingLevel();
  451. while (this._peek() !== Tokens.RBRACE)
  452. this._parseCaseClause();
  453. this._builder.decreaseNestingLevel();
  454. this._expect(Tokens.RBRACE);
  455. },
  456. _parseThrowStatement: function()
  457. {
  458. this._expect(Tokens.THROW);
  459. this._builder.addSpace();
  460. this._parseExpression();
  461. this._expectSemicolon();
  462. },
  463. _parseTryStatement: function()
  464. {
  465. this._expect(Tokens.TRY);
  466. this._builder.addSpace();
  467. this._parseBlock();
  468. var token = this._peek();
  469. if (token === Tokens.CATCH) {
  470. this._builder.addSpace();
  471. this._consume(Tokens.CATCH);
  472. this._builder.addSpace();
  473. this._expect(Tokens.LPAREN);
  474. this._expect(Tokens.IDENTIFIER);
  475. this._expect(Tokens.RPAREN);
  476. this._builder.addSpace();
  477. this._parseBlock();
  478. token = this._peek();
  479. }
  480. if (token === Tokens.FINALLY) {
  481. this._consume(Tokens.FINALLY);
  482. this._builder.addSpace();
  483. this._parseBlock();
  484. }
  485. },
  486. _parseDoWhileStatement: function()
  487. {
  488. this._expect(Tokens.DO);
  489. var isBlock = this._parseStatementOrBlock();
  490. if (isBlock)
  491. this._builder.addSpace();
  492. else
  493. this._builder.addNewLine();
  494. this._expect(Tokens.WHILE);
  495. this._builder.addSpace();
  496. this._expect(Tokens.LPAREN);
  497. this._parseExpression();
  498. this._expect(Tokens.RPAREN);
  499. this._expectSemicolon();
  500. },
  501. _parseWhileStatement: function()
  502. {
  503. this._expect(Tokens.WHILE);
  504. this._builder.addSpace();
  505. this._expect(Tokens.LPAREN);
  506. this._parseExpression();
  507. this._expect(Tokens.RPAREN);
  508. this._parseStatementOrBlock();
  509. },
  510. _parseForStatement: function()
  511. {
  512. this._expect(Tokens.FOR);
  513. this._builder.addSpace();
  514. this._expect(Tokens.LPAREN);
  515. if (this._peek() !== Tokens.SEMICOLON) {
  516. if (this._peek() === Tokens.VAR || this._peek() === Tokens.CONST) {
  517. this._parseVariableDeclarations();
  518. if (this._peek() === Tokens.IN) {
  519. this._builder.addSpace();
  520. this._consume(Tokens.IN);
  521. this._builder.addSpace();
  522. this._parseExpression();
  523. }
  524. } else
  525. this._parseExpression();
  526. }
  527. if (this._peek() !== Tokens.RPAREN) {
  528. this._expect(Tokens.SEMICOLON);
  529. this._builder.addSpace();
  530. if (this._peek() !== Tokens.SEMICOLON)
  531. this._parseExpression();
  532. this._expect(Tokens.SEMICOLON);
  533. this._builder.addSpace();
  534. if (this._peek() !== Tokens.RPAREN)
  535. this._parseExpression();
  536. }
  537. this._expect(Tokens.RPAREN);
  538. this._parseStatementOrBlock();
  539. },
  540. _parseExpression: function()
  541. {
  542. this._parseAssignmentExpression();
  543. while (this._peek() === Tokens.COMMA) {
  544. this._expect(Tokens.COMMA);
  545. this._builder.addSpace();
  546. this._parseAssignmentExpression();
  547. }
  548. },
  549. _parseAssignmentExpression: function()
  550. {
  551. this._parseConditionalExpression();
  552. var token = this._peek();
  553. if (Tokens.ASSIGN <= token && token <= Tokens.ASSIGN_MOD) {
  554. this._builder.addSpace();
  555. this._next();
  556. this._builder.addSpace();
  557. this._parseAssignmentExpression();
  558. }
  559. },
  560. _parseConditionalExpression: function()
  561. {
  562. this._parseBinaryExpression();
  563. if (this._peek() === Tokens.CONDITIONAL) {
  564. this._builder.addSpace();
  565. this._consume(Tokens.CONDITIONAL);
  566. this._builder.addSpace();
  567. this._parseAssignmentExpression();
  568. this._builder.addSpace();
  569. this._expect(Tokens.COLON);
  570. this._builder.addSpace();
  571. this._parseAssignmentExpression();
  572. }
  573. },
  574. _parseBinaryExpression: function()
  575. {
  576. this._parseUnaryExpression();
  577. var token = this._peek();
  578. while (Tokens.OR <= token && token <= Tokens.IN) {
  579. this._builder.addSpace();
  580. this._next();
  581. this._builder.addSpace();
  582. this._parseBinaryExpression();
  583. token = this._peek();
  584. }
  585. },
  586. _parseUnaryExpression: function()
  587. {
  588. var token = this._peek();
  589. if ((Tokens.NOT <= token && token <= Tokens.VOID) || token === Tokens.ADD || token === Tokens.SUB || token === Tokens.INC || token === Tokens.DEC) {
  590. this._next();
  591. if (token === Tokens.DELETE || token === Tokens.TYPEOF || token === Tokens.VOID)
  592. this._builder.addSpace();
  593. this._parseUnaryExpression();
  594. } else
  595. return this._parsePostfixExpression();
  596. },
  597. _parsePostfixExpression: function()
  598. {
  599. this._parseLeftHandSideExpression();
  600. var token = this._peek();
  601. if (!this._hasLineTerminatorBeforeNext() && (token === Tokens.INC || token === Tokens.DEC))
  602. this._next();
  603. },
  604. _parseLeftHandSideExpression: function()
  605. {
  606. if (this._peek() === Tokens.NEW)
  607. this._parseNewExpression();
  608. else
  609. this._parseMemberExpression();
  610. while (true) {
  611. switch (this._peek()) {
  612. case Tokens.LBRACK:
  613. this._consume(Tokens.LBRACK);
  614. this._parseExpression();
  615. this._expect(Tokens.RBRACK);
  616. break;
  617. case Tokens.LPAREN:
  618. this._parseArguments();
  619. break;
  620. case Tokens.PERIOD:
  621. this._consume(Tokens.PERIOD);
  622. this._expect(Tokens.IDENTIFIER);
  623. break;
  624. default:
  625. return;
  626. }
  627. }
  628. },
  629. _parseNewExpression: function()
  630. {
  631. this._expect(Tokens.NEW);
  632. this._builder.addSpace();
  633. if (this._peek() === Tokens.NEW)
  634. this._parseNewExpression();
  635. else
  636. this._parseMemberExpression();
  637. },
  638. _parseMemberExpression: function()
  639. {
  640. if (this._peek() === Tokens.FUNCTION) {
  641. this._expect(Tokens.FUNCTION);
  642. if (this._peek() === Tokens.IDENTIFIER) {
  643. this._builder.addSpace();
  644. this._expect(Tokens.IDENTIFIER);
  645. }
  646. this._parseFunctionLiteral();
  647. } else
  648. this._parsePrimaryExpression();
  649. while (true) {
  650. switch (this._peek()) {
  651. case Tokens.LBRACK:
  652. this._consume(Tokens.LBRACK);
  653. this._parseExpression();
  654. this._expect(Tokens.RBRACK);
  655. break;
  656. case Tokens.PERIOD:
  657. this._consume(Tokens.PERIOD);
  658. this._expect(Tokens.IDENTIFIER);
  659. break;
  660. case Tokens.LPAREN:
  661. this._parseArguments();
  662. break;
  663. default:
  664. return;
  665. }
  666. }
  667. },
  668. _parseDebuggerStatement: function()
  669. {
  670. this._expect(Tokens.DEBUGGER);
  671. this._expectSemicolon();
  672. },
  673. _parsePrimaryExpression: function()
  674. {
  675. switch (this._peek()) {
  676. case Tokens.THIS:
  677. return this._consume(Tokens.THIS);
  678. case Tokens.NULL_LITERAL:
  679. return this._consume(Tokens.NULL_LITERAL);
  680. case Tokens.TRUE_LITERAL:
  681. return this._consume(Tokens.TRUE_LITERAL);
  682. case Tokens.FALSE_LITERAL:
  683. return this._consume(Tokens.FALSE_LITERAL);
  684. case Tokens.IDENTIFIER:
  685. return this._consume(Tokens.IDENTIFIER);
  686. case Tokens.NUMBER:
  687. return this._consume(Tokens.NUMBER);
  688. case Tokens.STRING:
  689. return this._consume(Tokens.STRING);
  690. case Tokens.ASSIGN_DIV:
  691. return this._parseRegExpLiteral();
  692. case Tokens.DIV:
  693. return this._parseRegExpLiteral();
  694. case Tokens.LBRACK:
  695. return this._parseArrayLiteral();
  696. case Tokens.LBRACE:
  697. return this._parseObjectLiteral();
  698. case Tokens.LPAREN:
  699. this._consume(Tokens.LPAREN);
  700. this._parseExpression();
  701. this._expect(Tokens.RPAREN);
  702. return;
  703. default:
  704. return this._next();
  705. }
  706. },
  707. _parseArrayLiteral: function()
  708. {
  709. this._expect(Tokens.LBRACK);
  710. this._builder.increaseNestingLevel();
  711. while (this._peek() !== Tokens.RBRACK) {
  712. if (this._peek() !== Tokens.COMMA)
  713. this._parseAssignmentExpression();
  714. if (this._peek() !== Tokens.RBRACK) {
  715. this._expect(Tokens.COMMA);
  716. this._builder.addSpace();
  717. }
  718. }
  719. this._builder.decreaseNestingLevel();
  720. this._expect(Tokens.RBRACK);
  721. },
  722. _parseObjectLiteralGetSet: function()
  723. {
  724. var token = this._peek();
  725. if (token === Tokens.IDENTIFIER || token === Tokens.NUMBER || token === Tokens.STRING ||
  726. Tokens.DELETE <= token && token <= Tokens.FALSE_LITERAL ||
  727. token === Tokens.INSTANCEOF || token === Tokens.IN || token === Tokens.CONST) {
  728. this._next();
  729. this._parseFunctionLiteral();
  730. }
  731. },
  732. _parseObjectLiteral: function()
  733. {
  734. this._expect(Tokens.LBRACE);
  735. this._builder.increaseNestingLevel();
  736. while (this._peek() !== Tokens.RBRACE) {
  737. var token = this._peek();
  738. switch (token) {
  739. case Tokens.IDENTIFIER:
  740. this._consume(Tokens.IDENTIFIER);
  741. var name = this._token.value;
  742. if ((name === "get" || name === "set") && this._peek() !== Tokens.COLON) {
  743. this._builder.addSpace();
  744. this._parseObjectLiteralGetSet();
  745. if (this._peek() !== Tokens.RBRACE) {
  746. this._expect(Tokens.COMMA);
  747. }
  748. continue;
  749. }
  750. break;
  751. case Tokens.STRING:
  752. this._consume(Tokens.STRING);
  753. break;
  754. case Tokens.NUMBER:
  755. this._consume(Tokens.NUMBER);
  756. break;
  757. default:
  758. this._next();
  759. }
  760. this._expect(Tokens.COLON);
  761. this._builder.addSpace();
  762. this._parseAssignmentExpression();
  763. if (this._peek() !== Tokens.RBRACE) {
  764. this._expect(Tokens.COMMA);
  765. }
  766. }
  767. this._builder.decreaseNestingLevel();
  768. this._expect(Tokens.RBRACE);
  769. },
  770. _parseRegExpLiteral: function()
  771. {
  772. if (this._nextToken.type === "regexp")
  773. this._next();
  774. else {
  775. this._forceRegexp = true;
  776. this._next();
  777. }
  778. },
  779. _parseArguments: function()
  780. {
  781. this._expect(Tokens.LPAREN);
  782. var done = (this._peek() === Tokens.RPAREN);
  783. while (!done) {
  784. this._parseAssignmentExpression();
  785. done = (this._peek() === Tokens.RPAREN);
  786. if (!done) {
  787. this._expect(Tokens.COMMA);
  788. this._builder.addSpace();
  789. }
  790. }
  791. this._expect(Tokens.RPAREN);
  792. },
  793. _parseFunctionLiteral: function()
  794. {
  795. this._expect(Tokens.LPAREN);
  796. var done = (this._peek() === Tokens.RPAREN);
  797. while (!done) {
  798. this._expect(Tokens.IDENTIFIER);
  799. done = (this._peek() === Tokens.RPAREN);
  800. if (!done) {
  801. this._expect(Tokens.COMMA);
  802. this._builder.addSpace();
  803. }
  804. }
  805. this._expect(Tokens.RPAREN);
  806. this._builder.addSpace();
  807. this._expect(Tokens.LBRACE);
  808. this._builder.addNewLine();
  809. this._builder.increaseNestingLevel();
  810. this._parseSourceElements(Tokens.RBRACE);
  811. this._builder.decreaseNestingLevel();
  812. this._expect(Tokens.RBRACE);
  813. }
  814. }