123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // The algorithm used to determine whether a regexp can appear at a
- // given point in the program is loosely based on sweet.js' approach.
- // See https://github.com/mozilla/sweet.js/wiki/design
- import {Parser} from "./state"
- import {types as tt} from "./tokentype"
- import {lineBreak} from "./whitespace"
- export class TokContext {
- constructor(token, isExpr, preserveSpace, override, generator) {
- this.token = token
- this.isExpr = !!isExpr
- this.preserveSpace = !!preserveSpace
- this.override = override
- this.generator = !!generator
- }
- }
- export const types = {
- b_stat: new TokContext("{", false),
- b_expr: new TokContext("{", true),
- b_tmpl: new TokContext("${", true),
- p_stat: new TokContext("(", false),
- p_expr: new TokContext("(", true),
- q_tmpl: new TokContext("`", true, true, p => p.readTmplToken()),
- f_expr: new TokContext("function", true),
- f_expr_gen: new TokContext("function", true, false, null, true),
- f_gen: new TokContext("function", false, false, null, true)
- }
- const pp = Parser.prototype
- pp.initialContext = function() {
- return [types.b_stat]
- }
- pp.braceIsBlock = function(prevType) {
- if (prevType === tt.colon) {
- let parent = this.curContext()
- if (parent === types.b_stat || parent === types.b_expr)
- return !parent.isExpr
- }
- if (prevType === tt._return)
- return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
- if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType == tt.arrow)
- return true
- if (prevType == tt.braceL)
- return this.curContext() === types.b_stat
- return !this.exprAllowed
- }
- pp.inGeneratorContext = function() {
- for (let i = this.context.length - 1; i >= 0; i--)
- if (this.context[i].generator) return true
- return false
- }
- pp.updateContext = function(prevType) {
- let update, type = this.type
- if (type.keyword && prevType == tt.dot)
- this.exprAllowed = false
- else if (update = type.updateContext)
- update.call(this, prevType)
- else
- this.exprAllowed = type.beforeExpr
- }
- // Token-specific context update code
- tt.parenR.updateContext = tt.braceR.updateContext = function() {
- if (this.context.length == 1) {
- this.exprAllowed = true
- return
- }
- let out = this.context.pop(), cur
- if (out === types.b_stat && (cur = this.curContext()) && cur.token === "function") {
- this.context.pop()
- this.exprAllowed = false
- } else if (out === types.b_tmpl) {
- this.exprAllowed = true
- } else {
- this.exprAllowed = !out.isExpr
- }
- }
- tt.braceL.updateContext = function(prevType) {
- this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr)
- this.exprAllowed = true
- }
- tt.dollarBraceL.updateContext = function() {
- this.context.push(types.b_tmpl)
- this.exprAllowed = true
- }
- tt.parenL.updateContext = function(prevType) {
- let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while
- this.context.push(statementParens ? types.p_stat : types.p_expr)
- this.exprAllowed = true
- }
- tt.incDec.updateContext = function() {
- // tokExprAllowed stays unchanged
- }
- tt._function.updateContext = function(prevType) {
- if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else &&
- !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat))
- this.context.push(types.f_expr)
- this.exprAllowed = false
- }
- tt.backQuote.updateContext = function() {
- if (this.curContext() === types.q_tmpl)
- this.context.pop()
- else
- this.context.push(types.q_tmpl)
- this.exprAllowed = false
- }
- tt.star.updateContext = function(prevType) {
- if (prevType == tt._function) {
- if (this.curContext() === types.f_expr)
- this.context[this.context.length - 1] = types.f_expr_gen
- else
- this.context.push(types.f_gen)
- }
- this.exprAllowed = true
- }
- tt.name.updateContext = function(prevType) {
- let allowed = false
- if (this.options.ecmaVersion >= 6) {
- if (this.value == "of" && !this.exprAllowed ||
- this.value == "yield" && this.inGeneratorContext())
- allowed = true
- }
- this.exprAllowed = allowed
- }
|