Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80551 views
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
5
import {Parser} from "./state"
6
import {types as tt} from "./tokentype"
7
import {lineBreak} from "./whitespace"
8
9
export class TokContext {
10
constructor(token, isExpr, preserveSpace, override) {
11
this.token = token
12
this.isExpr = isExpr
13
this.preserveSpace = preserveSpace
14
this.override = override
15
}
16
}
17
18
export const types = {
19
b_stat: new TokContext("{", false),
20
b_expr: new TokContext("{", true),
21
b_tmpl: new TokContext("${", true),
22
p_stat: new TokContext("(", false),
23
p_expr: new TokContext("(", true),
24
q_tmpl: new TokContext("`", true, true, p => p.readTmplToken()),
25
f_expr: new TokContext("function", true)
26
}
27
28
const pp = Parser.prototype
29
30
pp.initialContext = function() {
31
return [types.b_stat]
32
}
33
34
pp.braceIsBlock = function(prevType) {
35
let parent
36
if (prevType === tt.colon && (parent = this.curContext()).token == "{")
37
return !parent.isExpr
38
if (prevType === tt._return)
39
return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
40
if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof)
41
return true
42
if (prevType == tt.braceL)
43
return this.curContext() === types.b_stat
44
return !this.exprAllowed
45
}
46
47
pp.updateContext = function(prevType) {
48
let update, type = this.type
49
if (type.keyword && prevType == tt.dot)
50
this.exprAllowed = false
51
else if (update = type.updateContext)
52
update.call(this, prevType)
53
else
54
this.exprAllowed = type.beforeExpr
55
}
56
57
// Token-specific context update code
58
59
tt.parenR.updateContext = tt.braceR.updateContext = function() {
60
if (this.context.length == 1) {
61
this.exprAllowed = true
62
return
63
}
64
let out = this.context.pop()
65
if (out === types.b_stat && this.curContext() === types.f_expr) {
66
this.context.pop()
67
this.exprAllowed = false
68
} else if (out === types.b_tmpl) {
69
this.exprAllowed = true
70
} else {
71
this.exprAllowed = !out.isExpr
72
}
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
80
tt.dollarBraceL.updateContext = function() {
81
this.context.push(types.b_tmpl)
82
this.exprAllowed = true
83
}
84
85
tt.parenL.updateContext = function(prevType) {
86
let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while
87
this.context.push(statementParens ? types.p_stat : types.p_expr)
88
this.exprAllowed = true
89
}
90
91
tt.incDec.updateContext = function() {
92
// tokExprAllowed stays unchanged
93
}
94
95
tt._function.updateContext = function() {
96
if (this.curContext() !== types.b_stat)
97
this.context.push(types.f_expr)
98
this.exprAllowed = false
99
}
100
101
tt.backQuote.updateContext = function() {
102
if (this.curContext() === types.q_tmpl)
103
this.context.pop()
104
else
105
this.context.push(types.q_tmpl)
106
this.exprAllowed = false
107
}
108
109