123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // 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) {
- this.token = token
- this.isExpr = !!isExpr
- this.preserveSpace = !!preserveSpace
- this.override = override
- }
- }
- 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)
- }
- 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)
- return true
- if (prevType == tt.braceL)
- return this.curContext() === types.b_stat
- return !this.exprAllowed
- }
- 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()
- if (out === types.b_stat && this.curContext() === types.f_expr) {
- 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
- }
|