statement.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. import {LooseParser} from "./state"
  2. import {isDummy} from "./parseutil"
  3. import {getLineInfo, tokTypes as tt} from "../index"
  4. const lp = LooseParser.prototype
  5. lp.parseTopLevel = function() {
  6. let node = this.startNodeAt(this.options.locations ? [0, getLineInfo(this.input, 0)] : 0)
  7. node.body = []
  8. while (this.tok.type !== tt.eof) node.body.push(this.parseStatement())
  9. this.last = this.tok
  10. if (this.options.ecmaVersion >= 6) {
  11. node.sourceType = this.options.sourceType
  12. }
  13. return this.finishNode(node, "Program")
  14. }
  15. lp.parseStatement = function() {
  16. let starttype = this.tok.type, node = this.startNode(), kind
  17. if (this.toks.isLet()) {
  18. starttype = tt._var
  19. kind = "let"
  20. }
  21. switch (starttype) {
  22. case tt._break: case tt._continue:
  23. this.next()
  24. let isBreak = starttype === tt._break
  25. if (this.semicolon() || this.canInsertSemicolon()) {
  26. node.label = null
  27. } else {
  28. node.label = this.tok.type === tt.name ? this.parseIdent() : null
  29. this.semicolon()
  30. }
  31. return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement")
  32. case tt._debugger:
  33. this.next()
  34. this.semicolon()
  35. return this.finishNode(node, "DebuggerStatement")
  36. case tt._do:
  37. this.next()
  38. node.body = this.parseStatement()
  39. node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent()
  40. this.semicolon()
  41. return this.finishNode(node, "DoWhileStatement")
  42. case tt._for:
  43. this.next()
  44. this.pushCx()
  45. this.expect(tt.parenL)
  46. if (this.tok.type === tt.semi) return this.parseFor(node, null)
  47. let isLet = this.toks.isLet()
  48. if (isLet || this.tok.type === tt._var || this.tok.type === tt._const) {
  49. let init = this.parseVar(true, isLet ? "let" : this.tok.value)
  50. if (init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) {
  51. return this.parseForIn(node, init)
  52. }
  53. return this.parseFor(node, init)
  54. }
  55. let init = this.parseExpression(true)
  56. if (this.tok.type === tt._in || this.isContextual("of"))
  57. return this.parseForIn(node, this.toAssignable(init))
  58. return this.parseFor(node, init)
  59. case tt._function:
  60. this.next()
  61. return this.parseFunction(node, true)
  62. case tt._if:
  63. this.next()
  64. node.test = this.parseParenExpression()
  65. node.consequent = this.parseStatement()
  66. node.alternate = this.eat(tt._else) ? this.parseStatement() : null
  67. return this.finishNode(node, "IfStatement")
  68. case tt._return:
  69. this.next()
  70. if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null
  71. else { node.argument = this.parseExpression(); this.semicolon() }
  72. return this.finishNode(node, "ReturnStatement")
  73. case tt._switch:
  74. let blockIndent = this.curIndent, line = this.curLineStart
  75. this.next()
  76. node.discriminant = this.parseParenExpression()
  77. node.cases = []
  78. this.pushCx()
  79. this.expect(tt.braceL)
  80. let cur
  81. while (!this.closes(tt.braceR, blockIndent, line, true)) {
  82. if (this.tok.type === tt._case || this.tok.type === tt._default) {
  83. let isCase = this.tok.type === tt._case
  84. if (cur) this.finishNode(cur, "SwitchCase")
  85. node.cases.push(cur = this.startNode())
  86. cur.consequent = []
  87. this.next()
  88. if (isCase) cur.test = this.parseExpression()
  89. else cur.test = null
  90. this.expect(tt.colon)
  91. } else {
  92. if (!cur) {
  93. node.cases.push(cur = this.startNode())
  94. cur.consequent = []
  95. cur.test = null
  96. }
  97. cur.consequent.push(this.parseStatement())
  98. }
  99. }
  100. if (cur) this.finishNode(cur, "SwitchCase")
  101. this.popCx()
  102. this.eat(tt.braceR)
  103. return this.finishNode(node, "SwitchStatement")
  104. case tt._throw:
  105. this.next()
  106. node.argument = this.parseExpression()
  107. this.semicolon()
  108. return this.finishNode(node, "ThrowStatement")
  109. case tt._try:
  110. this.next()
  111. node.block = this.parseBlock()
  112. node.handler = null
  113. if (this.tok.type === tt._catch) {
  114. let clause = this.startNode()
  115. this.next()
  116. this.expect(tt.parenL)
  117. clause.param = this.toAssignable(this.parseExprAtom(), true)
  118. this.expect(tt.parenR)
  119. clause.body = this.parseBlock()
  120. node.handler = this.finishNode(clause, "CatchClause")
  121. }
  122. node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null
  123. if (!node.handler && !node.finalizer) return node.block
  124. return this.finishNode(node, "TryStatement")
  125. case tt._var:
  126. case tt._const:
  127. return this.parseVar(false, kind || this.tok.value)
  128. case tt._while:
  129. this.next()
  130. node.test = this.parseParenExpression()
  131. node.body = this.parseStatement()
  132. return this.finishNode(node, "WhileStatement")
  133. case tt._with:
  134. this.next()
  135. node.object = this.parseParenExpression()
  136. node.body = this.parseStatement()
  137. return this.finishNode(node, "WithStatement")
  138. case tt.braceL:
  139. return this.parseBlock()
  140. case tt.semi:
  141. this.next()
  142. return this.finishNode(node, "EmptyStatement")
  143. case tt._class:
  144. return this.parseClass(true)
  145. case tt._import:
  146. return this.parseImport()
  147. case tt._export:
  148. return this.parseExport()
  149. default:
  150. if (this.toks.isAsyncFunction()) {
  151. this.next()
  152. this.next()
  153. return this.parseFunction(node, true, true)
  154. }
  155. let expr = this.parseExpression()
  156. if (isDummy(expr)) {
  157. this.next()
  158. if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement")
  159. return this.parseStatement()
  160. } else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) {
  161. node.body = this.parseStatement()
  162. node.label = expr
  163. return this.finishNode(node, "LabeledStatement")
  164. } else {
  165. node.expression = expr
  166. this.semicolon()
  167. return this.finishNode(node, "ExpressionStatement")
  168. }
  169. }
  170. }
  171. lp.parseBlock = function() {
  172. let node = this.startNode()
  173. this.pushCx()
  174. this.expect(tt.braceL)
  175. let blockIndent = this.curIndent, line = this.curLineStart
  176. node.body = []
  177. while (!this.closes(tt.braceR, blockIndent, line, true))
  178. node.body.push(this.parseStatement())
  179. this.popCx()
  180. this.eat(tt.braceR)
  181. return this.finishNode(node, "BlockStatement")
  182. }
  183. lp.parseFor = function(node, init) {
  184. node.init = init
  185. node.test = node.update = null
  186. if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression()
  187. if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression()
  188. this.popCx()
  189. this.expect(tt.parenR)
  190. node.body = this.parseStatement()
  191. return this.finishNode(node, "ForStatement")
  192. }
  193. lp.parseForIn = function(node, init) {
  194. let type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement"
  195. this.next()
  196. node.left = init
  197. node.right = this.parseExpression()
  198. this.popCx()
  199. this.expect(tt.parenR)
  200. node.body = this.parseStatement()
  201. return this.finishNode(node, type)
  202. }
  203. lp.parseVar = function(noIn, kind) {
  204. let node = this.startNode()
  205. node.kind = kind
  206. this.next()
  207. node.declarations = []
  208. do {
  209. let decl = this.startNode()
  210. decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom(), true) : this.parseIdent()
  211. decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null
  212. node.declarations.push(this.finishNode(decl, "VariableDeclarator"))
  213. } while (this.eat(tt.comma))
  214. if (!node.declarations.length) {
  215. let decl = this.startNode()
  216. decl.id = this.dummyIdent()
  217. node.declarations.push(this.finishNode(decl, "VariableDeclarator"))
  218. }
  219. if (!noIn) this.semicolon()
  220. return this.finishNode(node, "VariableDeclaration")
  221. }
  222. lp.parseClass = function(isStatement) {
  223. let node = this.startNode()
  224. this.next()
  225. if (isStatement == null) isStatement = this.tok.type === tt.name
  226. if (this.tok.type === tt.name) node.id = this.parseIdent()
  227. else if (isStatement) node.id = this.dummyIdent()
  228. else node.id = null
  229. node.superClass = this.eat(tt._extends) ? this.parseExpression() : null
  230. node.body = this.startNode()
  231. node.body.body = []
  232. this.pushCx()
  233. let indent = this.curIndent + 1, line = this.curLineStart
  234. this.eat(tt.braceL)
  235. if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart }
  236. while (!this.closes(tt.braceR, indent, line)) {
  237. if (this.semicolon()) continue
  238. let method = this.startNode(), isGenerator, isAsync
  239. if (this.options.ecmaVersion >= 6) {
  240. method.static = false
  241. isGenerator = this.eat(tt.star)
  242. }
  243. this.parsePropertyName(method)
  244. if (isDummy(method.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue }
  245. if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" &&
  246. (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) {
  247. method.static = true
  248. isGenerator = this.eat(tt.star)
  249. this.parsePropertyName(method)
  250. } else {
  251. method.static = false
  252. }
  253. if (!method.computed &&
  254. method.key.type === "Identifier" && method.key.name === "async" && this.tok.type !== tt.parenL &&
  255. !this.canInsertSemicolon()) {
  256. this.parsePropertyName(method)
  257. isAsync = true
  258. } else {
  259. isAsync = false
  260. }
  261. if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" &&
  262. !method.computed && (method.key.name === "get" || method.key.name === "set") &&
  263. this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) {
  264. method.kind = method.key.name
  265. this.parsePropertyName(method)
  266. method.value = this.parseMethod(false)
  267. } else {
  268. if (!method.computed && !method.static && !isGenerator && !isAsync && (
  269. method.key.type === "Identifier" && method.key.name === "constructor" ||
  270. method.key.type === "Literal" && method.key.value === "constructor")) {
  271. method.kind = "constructor"
  272. } else {
  273. method.kind = "method"
  274. }
  275. method.value = this.parseMethod(isGenerator, isAsync)
  276. }
  277. node.body.body.push(this.finishNode(method, "MethodDefinition"))
  278. }
  279. this.popCx()
  280. if (!this.eat(tt.braceR)) {
  281. // If there is no closing brace, make the node span to the start
  282. // of the next token (this is useful for Tern)
  283. this.last.end = this.tok.start
  284. if (this.options.locations) this.last.loc.end = this.tok.loc.start
  285. }
  286. this.semicolon()
  287. this.finishNode(node.body, "ClassBody")
  288. return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression")
  289. }
  290. lp.parseFunction = function(node, isStatement, isAsync) {
  291. let oldInAsync = this.inAsync
  292. this.initFunction(node)
  293. if (this.options.ecmaVersion >= 6) {
  294. node.generator = this.eat(tt.star)
  295. }
  296. if (this.options.ecmaVersion >= 8) {
  297. node.async = !!isAsync
  298. }
  299. if (isStatement == null) isStatement = this.tok.type === tt.name
  300. if (this.tok.type === tt.name) node.id = this.parseIdent()
  301. else if (isStatement) node.id = this.dummyIdent()
  302. this.inAsync = node.async
  303. node.params = this.parseFunctionParams()
  304. node.body = this.parseBlock()
  305. this.inAsync = oldInAsync
  306. return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
  307. }
  308. lp.parseExport = function() {
  309. let node = this.startNode()
  310. this.next()
  311. if (this.eat(tt.star)) {
  312. node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString()
  313. return this.finishNode(node, "ExportAllDeclaration")
  314. }
  315. if (this.eat(tt._default)) {
  316. // export default (function foo() {}) // This is FunctionExpression.
  317. let isAsync
  318. if (this.tok.type === tt._function || (isAsync = this.toks.isAsyncFunction())) {
  319. let fNode = this.startNode()
  320. this.next()
  321. if (isAsync) this.next()
  322. node.declaration = this.parseFunction(fNode, null, isAsync)
  323. } else if (this.tok.type === tt._class) {
  324. node.declaration = this.parseClass(null)
  325. } else {
  326. node.declaration = this.parseMaybeAssign()
  327. this.semicolon()
  328. }
  329. return this.finishNode(node, "ExportDefaultDeclaration")
  330. }
  331. if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) {
  332. node.declaration = this.parseStatement()
  333. node.specifiers = []
  334. node.source = null
  335. } else {
  336. node.declaration = null
  337. node.specifiers = this.parseExportSpecifierList()
  338. node.source = this.eatContextual("from") ? this.parseExprAtom() : null
  339. this.semicolon()
  340. }
  341. return this.finishNode(node, "ExportNamedDeclaration")
  342. }
  343. lp.parseImport = function() {
  344. let node = this.startNode()
  345. this.next()
  346. if (this.tok.type === tt.string) {
  347. node.specifiers = []
  348. node.source = this.parseExprAtom()
  349. node.kind = ''
  350. } else {
  351. let elt
  352. if (this.tok.type === tt.name && this.tok.value !== "from") {
  353. elt = this.startNode()
  354. elt.local = this.parseIdent()
  355. this.finishNode(elt, "ImportDefaultSpecifier")
  356. this.eat(tt.comma)
  357. }
  358. node.specifiers = this.parseImportSpecifierList()
  359. node.source = this.eatContextual("from") && this.tok.type == tt.string ? this.parseExprAtom() : this.dummyString()
  360. if (elt) node.specifiers.unshift(elt)
  361. }
  362. this.semicolon()
  363. return this.finishNode(node, "ImportDeclaration")
  364. }
  365. lp.parseImportSpecifierList = function() {
  366. let elts = []
  367. if (this.tok.type === tt.star) {
  368. let elt = this.startNode()
  369. this.next()
  370. elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent()
  371. elts.push(this.finishNode(elt, "ImportNamespaceSpecifier"))
  372. } else {
  373. let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart
  374. this.pushCx()
  375. this.eat(tt.braceL)
  376. if (this.curLineStart > continuedLine) continuedLine = this.curLineStart
  377. while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
  378. let elt = this.startNode()
  379. if (this.eat(tt.star)) {
  380. elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent()
  381. this.finishNode(elt, "ImportNamespaceSpecifier")
  382. } else {
  383. if (this.isContextual("from")) break
  384. elt.imported = this.parseIdent()
  385. if (isDummy(elt.imported)) break
  386. elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported
  387. this.finishNode(elt, "ImportSpecifier")
  388. }
  389. elts.push(elt)
  390. this.eat(tt.comma)
  391. }
  392. this.eat(tt.braceR)
  393. this.popCx()
  394. }
  395. return elts
  396. }
  397. lp.parseExportSpecifierList = function() {
  398. let elts = []
  399. let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart
  400. this.pushCx()
  401. this.eat(tt.braceL)
  402. if (this.curLineStart > continuedLine) continuedLine = this.curLineStart
  403. while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
  404. if (this.isContextual("from")) break
  405. let elt = this.startNode()
  406. elt.local = this.parseIdent()
  407. if (isDummy(elt.local)) break
  408. elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local
  409. this.finishNode(elt, "ExportSpecifier")
  410. elts.push(elt)
  411. this.eat(tt.comma)
  412. }
  413. this.eat(tt.braceR)
  414. this.popCx()
  415. return elts
  416. }