tokencontext.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // The algorithm used to determine whether a regexp can appear at a
  2. // given point in the program is loosely based on sweet.js' approach.
  3. // See https://github.com/mozilla/sweet.js/wiki/design
  4. import {Parser} from "./state"
  5. import {types as tt} from "./tokentype"
  6. import {lineBreak} from "./whitespace"
  7. export class TokContext {
  8. constructor(token, isExpr, preserveSpace, override, generator) {
  9. this.token = token
  10. this.isExpr = !!isExpr
  11. this.preserveSpace = !!preserveSpace
  12. this.override = override
  13. this.generator = !!generator
  14. }
  15. }
  16. export const types = {
  17. b_stat: new TokContext("{", false),
  18. b_expr: new TokContext("{", true),
  19. b_tmpl: new TokContext("${", true),
  20. p_stat: new TokContext("(", false),
  21. p_expr: new TokContext("(", true),
  22. q_tmpl: new TokContext("`", true, true, p => p.readTmplToken()),
  23. f_expr: new TokContext("function", true),
  24. f_expr_gen: new TokContext("function", true, false, null, true),
  25. f_gen: new TokContext("function", false, false, null, true)
  26. }
  27. const pp = Parser.prototype
  28. pp.initialContext = function() {
  29. return [types.b_stat]
  30. }
  31. pp.braceIsBlock = function(prevType) {
  32. if (prevType === tt.colon) {
  33. let parent = this.curContext()
  34. if (parent === types.b_stat || parent === types.b_expr)
  35. return !parent.isExpr
  36. }
  37. if (prevType === tt._return)
  38. return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
  39. if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType == tt.arrow)
  40. return true
  41. if (prevType == tt.braceL)
  42. return this.curContext() === types.b_stat
  43. return !this.exprAllowed
  44. }
  45. pp.inGeneratorContext = function() {
  46. for (let i = this.context.length - 1; i >= 0; i--)
  47. if (this.context[i].generator) return true
  48. return false
  49. }
  50. pp.updateContext = function(prevType) {
  51. let update, type = this.type
  52. if (type.keyword && prevType == tt.dot)
  53. this.exprAllowed = false
  54. else if (update = type.updateContext)
  55. update.call(this, prevType)
  56. else
  57. this.exprAllowed = type.beforeExpr
  58. }
  59. // Token-specific context update code
  60. tt.parenR.updateContext = tt.braceR.updateContext = function() {
  61. if (this.context.length == 1) {
  62. this.exprAllowed = true
  63. return
  64. }
  65. let out = this.context.pop(), cur
  66. if (out === types.b_stat && (cur = this.curContext()) && cur.token === "function") {
  67. this.context.pop()
  68. this.exprAllowed = false
  69. } else if (out === types.b_tmpl) {
  70. this.exprAllowed = true
  71. } else {
  72. this.exprAllowed = !out.isExpr
  73. }
  74. }
  75. tt.braceL.updateContext = function(prevType) {
  76. this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr)
  77. this.exprAllowed = true
  78. }
  79. tt.dollarBraceL.updateContext = function() {
  80. this.context.push(types.b_tmpl)
  81. this.exprAllowed = true
  82. }
  83. tt.parenL.updateContext = function(prevType) {
  84. let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while
  85. this.context.push(statementParens ? types.p_stat : types.p_expr)
  86. this.exprAllowed = true
  87. }
  88. tt.incDec.updateContext = function() {
  89. // tokExprAllowed stays unchanged
  90. }
  91. tt._function.updateContext = function(prevType) {
  92. if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else &&
  93. !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat))
  94. this.context.push(types.f_expr)
  95. this.exprAllowed = false
  96. }
  97. tt.backQuote.updateContext = function() {
  98. if (this.curContext() === types.q_tmpl)
  99. this.context.pop()
  100. else
  101. this.context.push(types.q_tmpl)
  102. this.exprAllowed = false
  103. }
  104. tt.star.updateContext = function(prevType) {
  105. if (prevType == tt._function) {
  106. if (this.curContext() === types.f_expr)
  107. this.context[this.context.length - 1] = types.f_expr_gen
  108. else
  109. this.context.push(types.f_gen)
  110. }
  111. this.exprAllowed = true
  112. }
  113. tt.name.updateContext = function(prevType) {
  114. let allowed = false
  115. if (this.options.ecmaVersion >= 6) {
  116. if (this.value == "of" && !this.exprAllowed ||
  117. this.value == "yield" && this.inGeneratorContext())
  118. allowed = true
  119. }
  120. this.exprAllowed = allowed
  121. }