ranuts 0.1.0-alpha → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/img/sort/bubble.gif +0 -0
- package/assets/img/sort/complexity.png +0 -0
- package/assets/img/sort/select.gif +0 -0
- package/assets/img/sort/sort.png +0 -0
- package/assets/img/tree/balanceTree.png +0 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +1078 -44
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/dist/src/file/fileInfo.d.ts +7 -0
- package/dist/src/file/fs.d.ts +2 -0
- package/dist/src/file/readDir.d.ts +6 -0
- package/dist/src/file/readFile.d.ts +8 -0
- package/dist/src/file/watchFile.d.ts +8 -0
- package/dist/src/file/writeFile.d.ts +8 -0
- package/dist/src/mode/subscribe.d.ts +16 -0
- package/dist/src/ranlog/behavior.d.ts +1 -0
- package/dist/src/ranlog/env.d.ts +5 -0
- package/dist/src/ranlog/error.d.ts +2 -0
- package/dist/src/ranlog/index.d.ts +26 -0
- package/dist/src/ranlog/performance.d.ts +21 -0
- package/dist/src/ranlog/report.d.ts +7 -0
- package/dist/src/ranlog/request.d.ts +18 -0
- package/dist/src/ranlog/utils.d.ts +19 -0
- package/dist/src/utils/filterObj.d.ts +8 -0
- package/dist/src/utils/str2Xml.d.ts +8 -0
- package/dist/src/vnode/h.d.ts +6 -0
- package/dist/src/vnode/hooks.d.ts +23 -0
- package/dist/src/vnode/htmlDomApi.d.ts +33 -0
- package/dist/src/vnode/init.d.ts +2 -0
- package/dist/src/vnode/is.d.ts +5 -0
- package/dist/src/vnode/modules/attributes.d.ts +8 -0
- package/dist/src/vnode/modules/class.d.ts +8 -0
- package/dist/src/vnode/modules/index.d.ts +7 -0
- package/dist/src/vnode/modules/listeners.d.ts +14 -0
- package/dist/src/vnode/modules/props.d.ts +8 -0
- package/dist/src/vnode/modules/style.d.ts +14 -0
- package/dist/src/vnode/vnode.d.ts +31 -0
- package/package.json +32 -9
- package/readme.md +1 -0
- package/src/astParser/Parser.ts +654 -0
- package/src/astParser/Tokenizer.ts +447 -0
- package/src/astParser/nodeTypes.ts +194 -0
- package/src/astParser/utils.ts +27 -0
- package/src/babel/parser.ts +10 -0
- package/src/colors/fmt.ts +29 -0
- package/src/colors/isColorSupported.ts +13 -0
- package/src/file/appendFile.ts +29 -0
- package/src/file/fileInfo.ts +22 -0
- package/src/file/fs.ts +9 -0
- package/src/file/readDir.ts +18 -0
- package/src/file/readFile.ts +26 -0
- package/src/file/watchFile.ts +31 -0
- package/src/file/writeFile.ts +38 -0
- package/src/mode/subscribe.ts +89 -0
- package/src/ran/commit.ts +0 -0
- package/src/ran/dom.ts +0 -0
- package/src/ran/hooks.ts +0 -0
- package/src/ran/reconcile.ts +0 -0
- package/src/ran/schedule.ts +0 -0
- package/src/ranlog/behavior.ts +5 -0
- package/src/ranlog/console.ts +16 -0
- package/src/ranlog/env.ts +29 -0
- package/src/ranlog/error.ts +11 -0
- package/src/ranlog/performance.ts +65 -0
- package/src/ranlog/report.ts +33 -0
- package/src/ranlog/request.ts +60 -0
- package/src/ranlog/utils.ts +92 -0
- package/src/ranpack/ast/Declaration.ts +120 -0
- package/src/ranpack/ast/Node.ts +7 -0
- package/src/ranpack/ast/Reference.ts +32 -0
- package/src/ranpack/ast/Scope.ts +80 -0
- package/src/ranpack/bundle.ts +50 -0
- package/src/ranpack/graph.ts +143 -0
- package/src/ranpack/module.ts +431 -0
- package/src/ranpack/moduleLoader.ts +73 -0
- package/src/ranpack/plugins.ts +70 -0
- package/src/ranpack/statement.ts +66 -0
- package/src/ranpack/utils/buildScope.ts +77 -0
- package/src/ranpack/utils/findReference.ts +36 -0
- package/src/ranpack/utils/isFunctionDeclaration.ts +41 -0
- package/src/ranpack/utils/makeLegalIdentifier.ts +18 -0
- package/src/ranpack/utils/object.ts +8 -0
- package/src/ranpack/utils/resolve.ts +32 -0
- package/src/ranpack/utils/walk.ts +66 -0
- package/src/ranpack/ws.ts +269 -0
- package/src/server/connectType.ts +9 -0
- package/src/server/encodeUrl.ts +46 -0
- package/src/server/escapeHtml.ts +46 -0
- package/src/server/get.ts +36 -0
- package/src/server/jitter.ts +77 -0
- package/src/server/mimeType.ts +858 -0
- package/src/server/paresUrl.ts +40 -0
- package/src/server/send.ts +89 -0
- package/src/server/server.ts +67 -0
- package/src/server/status.ts +191 -0
- package/src/server/traverse.ts +54 -0
- package/src/server/websocket.ts +200 -0
- package/src/sort/bubble.ts +21 -0
- package/src/sort/bucket.ts +11 -0
- package/src/sort/count.ts +10 -0
- package/src/sort/heap.ts +10 -0
- package/src/sort/insert.ts +20 -0
- package/src/sort/merge.ts +35 -0
- package/src/sort/quick.ts +50 -0
- package/src/sort/radix.ts +11 -0
- package/src/sort/randomArray.ts +21 -0
- package/src/sort/select.ts +23 -0
- package/src/sort/shell.ts +22 -0
- package/src/utils/compose.ts +37 -0
- package/src/utils/filterObj.ts +21 -0
- package/src/utils/mergeObj.ts +12 -0
- package/src/utils/startTask.ts +15 -0
- package/src/utils/str2Xml.ts +26 -0
- package/src/utils/taskEnd.ts +14 -0
- package/src/vnode/h.ts +108 -0
- package/src/vnode/hooks.ts +25 -0
- package/src/vnode/htmlDomApi.ts +199 -0
- package/src/vnode/init.ts +429 -0
- package/src/vnode/is.ts +17 -0
- package/src/vnode/modules/attributes.ts +70 -0
- package/src/vnode/modules/class.ts +46 -0
- package/src/vnode/modules/listeners.ts +123 -0
- package/src/vnode/modules/props.ts +41 -0
- package/src/vnode/modules/style.ts +118 -0
- package/src/vnode/vnode.ts +65 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
import type { Token } from './Tokenizer'
|
|
2
|
+
import { TokenType } from './Tokenizer'
|
|
3
|
+
import type {
|
|
4
|
+
BinaryExpression,
|
|
5
|
+
BlockStatement,
|
|
6
|
+
CallExpression,
|
|
7
|
+
ExportDeclaration,
|
|
8
|
+
ExportSpecifier,
|
|
9
|
+
Expression,
|
|
10
|
+
ExpressionStatement,
|
|
11
|
+
FunctionDeclaration,
|
|
12
|
+
FunctionExpression,
|
|
13
|
+
Identifier,
|
|
14
|
+
ImportDeclaration,
|
|
15
|
+
ImportDefaultSpecifier,
|
|
16
|
+
ImportNamespaceSpecifier,
|
|
17
|
+
ImportSpecifier,
|
|
18
|
+
ImportSpecifiers,
|
|
19
|
+
Literal,
|
|
20
|
+
MemberExpression,
|
|
21
|
+
Program,
|
|
22
|
+
ReturnStatement,
|
|
23
|
+
Statement,
|
|
24
|
+
VariableDeclaration,
|
|
25
|
+
VariableDeclarator,
|
|
26
|
+
VariableKind,
|
|
27
|
+
} from './nodeTypes'
|
|
28
|
+
import { FunctionType, NodeType } from './nodeTypes'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @description: 语法分析器
|
|
32
|
+
* 在解析出词法 token 之后,我们就可以进入语法分析阶段了。
|
|
33
|
+
* 在这个阶段,我们会依次遍历 token,对代码进行语法结构层面的分析,最后的目标是生成 AST 数据结构。
|
|
34
|
+
* AST 结构可以通过 https://astexplorer.net/ 去查看
|
|
35
|
+
*/
|
|
36
|
+
export class Parser {
|
|
37
|
+
private _tokens: Token[] = []
|
|
38
|
+
private _currentIndex = 0
|
|
39
|
+
constructor(token: Token[]) {
|
|
40
|
+
this._tokens = [...token]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
parse(): Program {
|
|
44
|
+
const program = this._parseProgram()
|
|
45
|
+
return program
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @description: 解析生成 AST 的核心逻辑
|
|
49
|
+
* 一个程序(Program)实际上由各个语句(Statement)来构成
|
|
50
|
+
* 因此在_parseProgram逻辑中,需要扫描一个个语句,然后放到 Program 对象的 body 中。
|
|
51
|
+
*/
|
|
52
|
+
private _parseProgram(): Program {
|
|
53
|
+
const program: Program = {
|
|
54
|
+
type: NodeType.Program,
|
|
55
|
+
body: [],
|
|
56
|
+
start: 0,
|
|
57
|
+
end: Infinity,
|
|
58
|
+
}
|
|
59
|
+
while (!this._isEnd()) {
|
|
60
|
+
const node = this._parseStatement()
|
|
61
|
+
program.body.push(node)
|
|
62
|
+
if (this._isEnd()) {
|
|
63
|
+
program.end = node.end
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return program
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @description: 对于不同的token类型,有不同的解析逻辑
|
|
70
|
+
* @return {Statement}
|
|
71
|
+
*/
|
|
72
|
+
private _parseStatement(): Statement {
|
|
73
|
+
// TokenType 来自 Tokenizer 的实现中
|
|
74
|
+
if (this._checkCurrentTokenType(TokenType.Function)) return this._parseFunctionDeclaration()
|
|
75
|
+
if (this._checkCurrentTokenType(TokenType.Identifier)) return this._parseExpressionStatement()
|
|
76
|
+
if (this._checkCurrentTokenType(TokenType.LeftCurly)) return this._parseBlockStatement()
|
|
77
|
+
if (this._checkCurrentTokenType(TokenType.Return)) return this._parseReturnStatement()
|
|
78
|
+
if (this._checkCurrentTokenType(TokenType.Import)) return this._parseImportDeclaration()
|
|
79
|
+
if (this._checkCurrentTokenType(TokenType.Export)) return this._parseExportDeclaration()
|
|
80
|
+
if (this._checkCurrentTokenType([TokenType.Let,TokenType.Var,TokenType.Const])) return this._parseVariableDeclaration()
|
|
81
|
+
console.log('Unexpected token:', this._getCurrentToken())
|
|
82
|
+
throw new Error('Unexpected token')
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @description: 解析 import 声明
|
|
86
|
+
* @return {ImportDeclaration}
|
|
87
|
+
*/
|
|
88
|
+
private _parseImportDeclaration(): ImportDeclaration {
|
|
89
|
+
const { start } = this._getCurrentToken()
|
|
90
|
+
const specifiers:ImportSpecifiers = []
|
|
91
|
+
this._goNext(TokenType.Import)
|
|
92
|
+
// import a
|
|
93
|
+
if (this._checkCurrentTokenType(TokenType.Identifier)) {
|
|
94
|
+
const local = this._parseIdentifier()
|
|
95
|
+
const defaultSpecifier:ImportDefaultSpecifier = {
|
|
96
|
+
type: NodeType.ImportDefaultSpecifier,
|
|
97
|
+
local,
|
|
98
|
+
start: local.start,
|
|
99
|
+
end: local.end,
|
|
100
|
+
}
|
|
101
|
+
specifiers.push(defaultSpecifier)
|
|
102
|
+
if (this._checkCurrentTokenType(TokenType.Comma)) {
|
|
103
|
+
this._goNext(TokenType.Comma)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// import { name1 }
|
|
107
|
+
if (this._checkCurrentTokenType(TokenType.LeftCurly)) {
|
|
108
|
+
this._goNext(TokenType.LeftCurly)
|
|
109
|
+
while (!this._checkCurrentTokenType(TokenType.RightCurly)) {
|
|
110
|
+
const specifier = this._parseIdentifier()
|
|
111
|
+
let local = null
|
|
112
|
+
if (this._checkCurrentTokenType(TokenType.As)) {
|
|
113
|
+
this._goNext(TokenType.As)
|
|
114
|
+
local = this._parseIdentifier()
|
|
115
|
+
}
|
|
116
|
+
const importSpecifier:ImportSpecifier = {
|
|
117
|
+
type: NodeType.ImportSpecifier,
|
|
118
|
+
imported: specifier,
|
|
119
|
+
local: local ? local : specifier,
|
|
120
|
+
start: specifier.start,
|
|
121
|
+
end: local ? local.end : specifier.end,
|
|
122
|
+
}
|
|
123
|
+
specifiers.push(importSpecifier)
|
|
124
|
+
if (this._checkCurrentTokenType(TokenType.Comma)) {
|
|
125
|
+
this._goNext(TokenType.Comma)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this._goNext(TokenType.RightCurly)
|
|
129
|
+
}
|
|
130
|
+
// import * as a
|
|
131
|
+
else if (this._checkCurrentTokenType(TokenType.Asterisk)) {
|
|
132
|
+
const { start } = this._getCurrentToken()
|
|
133
|
+
this._goNext(TokenType.Asterisk)
|
|
134
|
+
this._goNext(TokenType.As)
|
|
135
|
+
const local = this._parseIdentifier()
|
|
136
|
+
const importNamespaceSpecifier:ImportNamespaceSpecifier = {
|
|
137
|
+
type: NodeType.ImportNamespaceSpecifier,
|
|
138
|
+
local,
|
|
139
|
+
start,
|
|
140
|
+
end: local.end,
|
|
141
|
+
}
|
|
142
|
+
specifiers.push(importNamespaceSpecifier)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// from 'a'
|
|
146
|
+
if (this._checkCurrentTokenType(TokenType.From)) {
|
|
147
|
+
this._goNext(TokenType.From)
|
|
148
|
+
}
|
|
149
|
+
const source = this._parseLiteral()
|
|
150
|
+
const node: ImportDeclaration = {
|
|
151
|
+
type: NodeType.ImportDeclaration,
|
|
152
|
+
specifiers: specifiers as ImportSpecifiers,
|
|
153
|
+
start,
|
|
154
|
+
end: source.end,
|
|
155
|
+
source,
|
|
156
|
+
}
|
|
157
|
+
this._skipSemicolon()
|
|
158
|
+
return node
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @description: 解析 export 声明
|
|
162
|
+
* @return {ExportDeclaration}
|
|
163
|
+
*/
|
|
164
|
+
private _parseExportDeclaration(): ExportDeclaration {
|
|
165
|
+
const { start } = this._getCurrentToken()
|
|
166
|
+
let exportDeclaration: ExportDeclaration | undefined
|
|
167
|
+
const specifiers: ExportSpecifier[] = []
|
|
168
|
+
this._goNext(TokenType.Export)
|
|
169
|
+
// export default
|
|
170
|
+
if (this._checkCurrentTokenType(TokenType.Default)) {
|
|
171
|
+
this._goNext(TokenType.Default)
|
|
172
|
+
// export default a
|
|
173
|
+
// export default obj.a
|
|
174
|
+
if (this._checkCurrentTokenType(TokenType.Identifier)) {
|
|
175
|
+
const local = this._parseExpression()
|
|
176
|
+
exportDeclaration = {
|
|
177
|
+
type: NodeType.ExportDefaultDeclaration,
|
|
178
|
+
declaration: local,
|
|
179
|
+
start: local.start,
|
|
180
|
+
end: local.end,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// export default function() {}
|
|
184
|
+
if (this._checkCurrentTokenType(TokenType.Function)) {
|
|
185
|
+
const declaration = this._parseFunctionDeclaration()
|
|
186
|
+
exportDeclaration = {
|
|
187
|
+
type: NodeType.ExportDefaultDeclaration,
|
|
188
|
+
declaration,
|
|
189
|
+
start,
|
|
190
|
+
end: declaration.end,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// export default class {}
|
|
194
|
+
// TODO: export default { a: 1 };
|
|
195
|
+
}
|
|
196
|
+
// export {
|
|
197
|
+
else if (this._checkCurrentTokenType(TokenType.LeftCurly)) {
|
|
198
|
+
this._goNext(TokenType.LeftCurly)
|
|
199
|
+
while (!this._checkCurrentTokenType(TokenType.RightCurly)) {
|
|
200
|
+
const local = this._parseIdentifier()
|
|
201
|
+
let exported = local
|
|
202
|
+
if (this._checkCurrentTokenType(TokenType.As)) {
|
|
203
|
+
this._goNext(TokenType.As)
|
|
204
|
+
exported = this._parseIdentifier()
|
|
205
|
+
}
|
|
206
|
+
const exportSpecifier: ExportSpecifier = {
|
|
207
|
+
type: NodeType.ExportSpecifier,
|
|
208
|
+
local,
|
|
209
|
+
exported,
|
|
210
|
+
start: local.start,
|
|
211
|
+
end: exported.end,
|
|
212
|
+
}
|
|
213
|
+
specifiers.push(exportSpecifier)
|
|
214
|
+
if (this._checkCurrentTokenType(TokenType.Comma)) {
|
|
215
|
+
this._goNext(TokenType.Comma)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
this._goNext(TokenType.RightCurly)
|
|
219
|
+
if (this._checkCurrentTokenType(TokenType.From)) {
|
|
220
|
+
this._goNext(TokenType.From)
|
|
221
|
+
}
|
|
222
|
+
const source = this._parseLiteral()
|
|
223
|
+
exportDeclaration = {
|
|
224
|
+
type: NodeType.ExportNamedDeclaration,
|
|
225
|
+
specifiers,
|
|
226
|
+
start,
|
|
227
|
+
declaration: null,
|
|
228
|
+
end: source.end,
|
|
229
|
+
source,
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// export const/let/var
|
|
233
|
+
else if (
|
|
234
|
+
this._checkCurrentTokenType([
|
|
235
|
+
TokenType.Const,
|
|
236
|
+
TokenType.Let,
|
|
237
|
+
TokenType.Var,
|
|
238
|
+
])
|
|
239
|
+
) {
|
|
240
|
+
const declaration = this._parseVariableDeclaration()
|
|
241
|
+
exportDeclaration = {
|
|
242
|
+
type: NodeType.ExportNamedDeclaration,
|
|
243
|
+
declaration,
|
|
244
|
+
start,
|
|
245
|
+
end: declaration.end,
|
|
246
|
+
specifiers: specifiers as ExportSpecifier[],
|
|
247
|
+
source: null,
|
|
248
|
+
}
|
|
249
|
+
return exportDeclaration
|
|
250
|
+
}
|
|
251
|
+
// export function
|
|
252
|
+
else if (this._checkCurrentTokenType(TokenType.Function)) {
|
|
253
|
+
const declaration =
|
|
254
|
+
this._parseFunctionDeclaration() as FunctionDeclaration
|
|
255
|
+
exportDeclaration = {
|
|
256
|
+
type: NodeType.ExportNamedDeclaration,
|
|
257
|
+
declaration,
|
|
258
|
+
start,
|
|
259
|
+
end: declaration.end,
|
|
260
|
+
specifiers: specifiers as ExportSpecifier[],
|
|
261
|
+
source: null,
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// export * from 'mod'
|
|
265
|
+
else {
|
|
266
|
+
this._goNext(TokenType.Asterisk)
|
|
267
|
+
let exported: Identifier | null = null
|
|
268
|
+
if (this._checkCurrentTokenType(TokenType.As)) {
|
|
269
|
+
this._goNext(TokenType.As)
|
|
270
|
+
exported = this._parseIdentifier()
|
|
271
|
+
}
|
|
272
|
+
this._goNext(TokenType.From)
|
|
273
|
+
const source = this._parseLiteral()
|
|
274
|
+
exportDeclaration = {
|
|
275
|
+
type: NodeType.ExportAllDeclaration,
|
|
276
|
+
start,
|
|
277
|
+
end: source.end,
|
|
278
|
+
source,
|
|
279
|
+
exported,
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!exportDeclaration) {
|
|
283
|
+
throw new Error('Export declaration cannot be parsed')
|
|
284
|
+
}
|
|
285
|
+
this._skipSemicolon()
|
|
286
|
+
return exportDeclaration!
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* @description: 解析变量的声明
|
|
290
|
+
* 发现 let 关键词对应的 token,进入 _parseVariableDeclaration
|
|
291
|
+
* 解析变量名,如示例代码中的 foo
|
|
292
|
+
* 解析函数表达式,如示例代码中的 function() {}
|
|
293
|
+
* 其中,解析变量名的过程我们通过 _parseIdentifier 方法实现,解析函数表达式的过程由 _parseFunctionExpression 来实现
|
|
294
|
+
* @return {VariableDeclaration}
|
|
295
|
+
*/
|
|
296
|
+
private _parseVariableDeclaration(): VariableDeclaration {
|
|
297
|
+
// 获取语句开始位置
|
|
298
|
+
const { start } = this._getCurrentToken()
|
|
299
|
+
// 拿到 let
|
|
300
|
+
const kind = this._getCurrentToken().value
|
|
301
|
+
this._goNext([TokenType.Let, TokenType.Var, TokenType.Const])
|
|
302
|
+
const declarations = []
|
|
303
|
+
const isVariableDeclarationEnded = (): boolean => {
|
|
304
|
+
if (this._checkCurrentTokenType(TokenType.Semicolon)) {
|
|
305
|
+
return true
|
|
306
|
+
}
|
|
307
|
+
const nextToken = this._getNextToken()
|
|
308
|
+
// 往后看一个 token,如果是 =,则表示没有结束
|
|
309
|
+
if (nextToken && nextToken.type === TokenType.Assign) {
|
|
310
|
+
return false
|
|
311
|
+
}
|
|
312
|
+
return true
|
|
313
|
+
}
|
|
314
|
+
while (!isVariableDeclarationEnded()) {
|
|
315
|
+
// 解析变量名 foo
|
|
316
|
+
const id = this._parseIdentifier()
|
|
317
|
+
let init = null
|
|
318
|
+
if (this._checkCurrentTokenType(TokenType.Assign)) {
|
|
319
|
+
this._goNext(TokenType.Assign)
|
|
320
|
+
if (
|
|
321
|
+
this._checkCurrentTokenType([
|
|
322
|
+
TokenType.Number,
|
|
323
|
+
TokenType.StringLiteral,
|
|
324
|
+
])
|
|
325
|
+
) {
|
|
326
|
+
init = this._parseLiteral()
|
|
327
|
+
} else {
|
|
328
|
+
init = this._parseExpression()
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const declarator: VariableDeclarator = {
|
|
332
|
+
type: NodeType.VariableDeclarator,
|
|
333
|
+
id,
|
|
334
|
+
init,
|
|
335
|
+
start: id.start,
|
|
336
|
+
end: init ? init.end : id.end,
|
|
337
|
+
}
|
|
338
|
+
declarations.push(declarator)
|
|
339
|
+
if (this._checkCurrentTokenType(TokenType.Comma)) {
|
|
340
|
+
this._goNext(TokenType.Comma)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// 构造 Declaration 节点
|
|
344
|
+
const node: VariableDeclaration = {
|
|
345
|
+
type: NodeType.VariableDeclaration,
|
|
346
|
+
kind: kind as VariableKind,
|
|
347
|
+
declarations,
|
|
348
|
+
start,
|
|
349
|
+
end: this._getPreviousToken().end,
|
|
350
|
+
}
|
|
351
|
+
this._skipSemicolon()
|
|
352
|
+
return node
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private _parseReturnStatement(): ReturnStatement {
|
|
356
|
+
const { start } = this._getCurrentToken()
|
|
357
|
+
this._goNext(TokenType.Return)
|
|
358
|
+
const argument = this._parseExpression()
|
|
359
|
+
const node: ReturnStatement = {
|
|
360
|
+
type: NodeType.ReturnStatement,
|
|
361
|
+
argument,
|
|
362
|
+
start,
|
|
363
|
+
end: argument.end,
|
|
364
|
+
}
|
|
365
|
+
this._skipSemicolon()
|
|
366
|
+
return node
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private _parseExpressionStatement(): ExpressionStatement {
|
|
370
|
+
const expression = this._parseExpression()
|
|
371
|
+
const expressionStatement: ExpressionStatement = {
|
|
372
|
+
type: NodeType.ExpressionStatement,
|
|
373
|
+
expression,
|
|
374
|
+
start: expression.start,
|
|
375
|
+
end: expression.end,
|
|
376
|
+
}
|
|
377
|
+
return expressionStatement
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// 解析对象的 a.b.c 嵌套结构
|
|
381
|
+
private _parseExpression(): Expression {
|
|
382
|
+
// 先检查是否是一个函数表达式
|
|
383
|
+
if (this._checkCurrentTokenType(TokenType.Function)) {
|
|
384
|
+
// 解析函数表达式
|
|
385
|
+
return this._parseFunctionExpression()
|
|
386
|
+
}
|
|
387
|
+
if (
|
|
388
|
+
this._checkCurrentTokenType([TokenType.Number, TokenType.StringLiteral])
|
|
389
|
+
) {
|
|
390
|
+
return this._parseLiteral()
|
|
391
|
+
}
|
|
392
|
+
// 拿到标识符,如 a
|
|
393
|
+
let expression: Expression = this._parseIdentifier()
|
|
394
|
+
while (!this._isEnd()) {
|
|
395
|
+
if (this._checkCurrentTokenType(TokenType.LeftParen)) {
|
|
396
|
+
expression = this._parseCallExpression(expression)
|
|
397
|
+
} else if (this._checkCurrentTokenType(TokenType.Dot)) {
|
|
398
|
+
// 继续解析,a.b
|
|
399
|
+
expression = this._parseMemberExpression(expression as MemberExpression)
|
|
400
|
+
} else if (this._checkCurrentTokenType(TokenType.Operator)) {
|
|
401
|
+
// 解析 a + b
|
|
402
|
+
expression = this.__parseBinaryOperatorExpression(expression)
|
|
403
|
+
} else {
|
|
404
|
+
break
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return expression
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private __parseBinaryOperatorExpression(
|
|
411
|
+
expression: Expression,
|
|
412
|
+
): BinaryExpression {
|
|
413
|
+
const { start } = this._getCurrentToken()
|
|
414
|
+
const operator = this._getCurrentToken().value!
|
|
415
|
+
this._goNext(TokenType.Operator)
|
|
416
|
+
const right = this._parseExpression()
|
|
417
|
+
const node: BinaryExpression = {
|
|
418
|
+
type: NodeType.BinaryExpression,
|
|
419
|
+
operator,
|
|
420
|
+
left: expression,
|
|
421
|
+
right,
|
|
422
|
+
start,
|
|
423
|
+
end: right.end,
|
|
424
|
+
}
|
|
425
|
+
return node
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private _parseMemberExpression(
|
|
429
|
+
object: Identifier | MemberExpression,
|
|
430
|
+
): MemberExpression {
|
|
431
|
+
this._goNext(TokenType.Dot)
|
|
432
|
+
const property = this._parseIdentifier()
|
|
433
|
+
const node: MemberExpression = {
|
|
434
|
+
type: NodeType.MemberExpression,
|
|
435
|
+
object,
|
|
436
|
+
property,
|
|
437
|
+
start: object.start,
|
|
438
|
+
end: property.end,
|
|
439
|
+
computed: false,
|
|
440
|
+
}
|
|
441
|
+
return node
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private _parseCallExpression(callee: Expression) {
|
|
445
|
+
const args = this._parseParams(FunctionType.CallExpression) as Expression[]
|
|
446
|
+
// 获取最后一个字符的结束位置
|
|
447
|
+
const { end } = this._getPreviousToken()
|
|
448
|
+
const node: CallExpression = {
|
|
449
|
+
type: NodeType.CallExpression,
|
|
450
|
+
callee,
|
|
451
|
+
arguments: args,
|
|
452
|
+
start: callee.start,
|
|
453
|
+
end,
|
|
454
|
+
}
|
|
455
|
+
this._skipSemicolon()
|
|
456
|
+
return node
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private _parseFunctionDeclaration(): FunctionDeclaration {
|
|
460
|
+
const { start } = this._getCurrentToken()
|
|
461
|
+
this._goNext(TokenType.Function)
|
|
462
|
+
let id = null
|
|
463
|
+
if (this._checkCurrentTokenType(TokenType.Identifier)) {
|
|
464
|
+
id = this._parseIdentifier()
|
|
465
|
+
}
|
|
466
|
+
const params = this._parseParams()
|
|
467
|
+
const body = this._parseBlockStatement()
|
|
468
|
+
const node: FunctionDeclaration = {
|
|
469
|
+
type: NodeType.FunctionDeclaration,
|
|
470
|
+
id,
|
|
471
|
+
params,
|
|
472
|
+
body,
|
|
473
|
+
start,
|
|
474
|
+
end: body.end,
|
|
475
|
+
}
|
|
476
|
+
return node
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* @description: 解析函数表达式
|
|
480
|
+
* @return {*}
|
|
481
|
+
*/
|
|
482
|
+
private _parseFunctionExpression(): FunctionExpression {
|
|
483
|
+
const { start } = this._getCurrentToken()
|
|
484
|
+
this._goNext(TokenType.Function)
|
|
485
|
+
let id = null
|
|
486
|
+
if (this._checkCurrentTokenType(TokenType.Identifier)) {
|
|
487
|
+
id = this._parseIdentifier()
|
|
488
|
+
}
|
|
489
|
+
const params = this._parseParams()
|
|
490
|
+
const body = this._parseBlockStatement()
|
|
491
|
+
const node: FunctionExpression = {
|
|
492
|
+
type: NodeType.FunctionExpression,
|
|
493
|
+
id,
|
|
494
|
+
params,
|
|
495
|
+
body,
|
|
496
|
+
start,
|
|
497
|
+
end: body.end,
|
|
498
|
+
}
|
|
499
|
+
return node
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* @description: 解析函数参数
|
|
503
|
+
*
|
|
504
|
+
*/
|
|
505
|
+
private _parseParams(
|
|
506
|
+
mode: FunctionType = FunctionType.FunctionDeclaration,
|
|
507
|
+
): Identifier[] | Expression[] {
|
|
508
|
+
// 消费 "("
|
|
509
|
+
this._goNext(TokenType.LeftParen)
|
|
510
|
+
const params = []
|
|
511
|
+
// 逐个解析括号中的参数
|
|
512
|
+
while (!this._checkCurrentTokenType(TokenType.RightParen)) {
|
|
513
|
+
const param =
|
|
514
|
+
mode === FunctionType.FunctionDeclaration
|
|
515
|
+
? // 函数声明
|
|
516
|
+
this._parseIdentifier()
|
|
517
|
+
: // 函数调用
|
|
518
|
+
this._parseExpression()
|
|
519
|
+
params.push(param)
|
|
520
|
+
if (!this._checkCurrentTokenType(TokenType.RightParen)) {
|
|
521
|
+
this._goNext(TokenType.Comma)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
// 消费 ")"
|
|
525
|
+
this._goNext(TokenType.RightParen)
|
|
526
|
+
return params
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* @description: 解析字面量,const name = 'value', value就是字面量
|
|
530
|
+
* @return {Literal}
|
|
531
|
+
*/
|
|
532
|
+
private _parseLiteral(): Literal {
|
|
533
|
+
const token = this._getCurrentToken()
|
|
534
|
+
let value: string | number | boolean = token.value!
|
|
535
|
+
if (token.type === TokenType.Number) {
|
|
536
|
+
value = Number(value)
|
|
537
|
+
}
|
|
538
|
+
const literal: Literal = {
|
|
539
|
+
type: NodeType.Literal,
|
|
540
|
+
value: token.value!,
|
|
541
|
+
start: token.start,
|
|
542
|
+
end: token.end,
|
|
543
|
+
raw: token.raw!,
|
|
544
|
+
}
|
|
545
|
+
this._goNext(token.type)
|
|
546
|
+
return literal
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* @description: 解析变量名
|
|
550
|
+
* @return {Identifier}
|
|
551
|
+
*/
|
|
552
|
+
private _parseIdentifier(): Identifier {
|
|
553
|
+
const token = this._getCurrentToken()
|
|
554
|
+
const identifier: Identifier = {
|
|
555
|
+
type: NodeType.Identifier,
|
|
556
|
+
name: token.value!,
|
|
557
|
+
start: token.start,
|
|
558
|
+
end: token.end,
|
|
559
|
+
}
|
|
560
|
+
this._goNext(TokenType.Identifier)
|
|
561
|
+
return identifier
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* @description: 解析函数体
|
|
565
|
+
* @return {BlockStatement}
|
|
566
|
+
*/
|
|
567
|
+
private _parseBlockStatement(): BlockStatement {
|
|
568
|
+
const { start } = this._getCurrentToken()
|
|
569
|
+
const blockStatement: BlockStatement = {
|
|
570
|
+
type: NodeType.BlockStatement,
|
|
571
|
+
body: [],
|
|
572
|
+
start,
|
|
573
|
+
end: Infinity,
|
|
574
|
+
}
|
|
575
|
+
// 消费 "{"
|
|
576
|
+
this._goNext(TokenType.LeftCurly)
|
|
577
|
+
while (!this._checkCurrentTokenType(TokenType.RightCurly)) {
|
|
578
|
+
// 递归调用 _parseStatement 解析函数体中的语句(Statement)
|
|
579
|
+
const node = this._parseStatement()
|
|
580
|
+
blockStatement.body.push(node)
|
|
581
|
+
}
|
|
582
|
+
blockStatement.end = this._getCurrentToken().end
|
|
583
|
+
// 消费 "}"
|
|
584
|
+
this._goNext(TokenType.RightCurly)
|
|
585
|
+
return blockStatement
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// 检查当前的token类型是否等于传入的类型(this._tokens[this._currentIndex])
|
|
589
|
+
private _checkCurrentTokenType(type: TokenType | TokenType[]): boolean {
|
|
590
|
+
if (this._isEnd()) {
|
|
591
|
+
return false
|
|
592
|
+
}
|
|
593
|
+
const currentToken = this._tokens[this._currentIndex]
|
|
594
|
+
if (Array.isArray(type)) {
|
|
595
|
+
return type.includes(currentToken.type)
|
|
596
|
+
} else {
|
|
597
|
+
return currentToken.type === type
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private _skipSemicolon(): void {
|
|
602
|
+
if (this._checkCurrentTokenType(TokenType.Semicolon)) {
|
|
603
|
+
this._goNext(TokenType.Semicolon)
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* @description: 工具方法,表示消费当前 Token,扫描位置移动到下一个 token
|
|
608
|
+
* @param {TokenType} type
|
|
609
|
+
* @return {Token}
|
|
610
|
+
*/
|
|
611
|
+
private _goNext(type: TokenType | TokenType[]): Token {
|
|
612
|
+
const currentToken = this._tokens[this._currentIndex]
|
|
613
|
+
// 断言当前 Token 的类型,如果不能匹配,则抛出错误
|
|
614
|
+
if (Array.isArray(type)) {
|
|
615
|
+
if (!type.includes(currentToken.type)) {
|
|
616
|
+
throw new Error(
|
|
617
|
+
`Expect ${type.join(',')}, but got ${currentToken.type}`,
|
|
618
|
+
)
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
if (currentToken.type !== type) {
|
|
622
|
+
throw new Error(`Expect ${type}, but got ${currentToken.type}`)
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
this._currentIndex++
|
|
626
|
+
return currentToken
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* @description: token 是否已经扫描完
|
|
630
|
+
* @return {boolean}
|
|
631
|
+
*/
|
|
632
|
+
private _isEnd(): boolean {
|
|
633
|
+
return this._currentIndex >= this._tokens.length
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* @description: 获取当前的token
|
|
637
|
+
* @return {Token}
|
|
638
|
+
*/
|
|
639
|
+
private _getCurrentToken(): Token {
|
|
640
|
+
return this._tokens[this._currentIndex]
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private _getPreviousToken(): Token {
|
|
644
|
+
return this._tokens[this._currentIndex - 1]
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private _getNextToken(): Token | false {
|
|
648
|
+
if (this._currentIndex + 1 < this._tokens.length) {
|
|
649
|
+
return this._tokens[this._currentIndex + 1]
|
|
650
|
+
} else {
|
|
651
|
+
return false
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|