-
Notifications
You must be signed in to change notification settings - Fork 2k
/
base.ts
157 lines (141 loc) Β· 5.28 KB
/
base.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { GRAMMAR } from "./grammar/parser_grammar.js";
/**
* Abstract class for handling nodes in an expression language. Subclasses
* must implement the `accepts` and `handle` methods.
*/
export abstract class NodeHandler {
constructor(protected parentHandler?: NodeHandler) {}
/**
* Determines whether the given node is acceptable.
* @param node The node to be checked.
* @returns A Promise that resolves to either the node itself or a boolean indicating whether the node is acceptable.
*/
abstract accepts(node: ExpressionNode): Promise<ExpressionNode | boolean>;
/**
* Handles the given node. The specifics of how the node is handled are
* determined by the subclass implementation.
* @param node The node to be handled.
* @returns A Promise that resolves to the result of handling the node.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
abstract handle(node: ExpressionNode): Promise<any>;
}
/**
* Utility class for parsing Abstract Syntax Trees (ASTs). Contains
* methods for identifying the type of a given node and a method for
* importing and generating a parser using the Peggy library.
*/
export class ASTParser {
static astParseInstance: ParseFunction;
/**
* Imports and generates a parser using the Peggy library.
* @returns A Promise that resolves to the parser instance.
*/
static async importASTParser() {
try {
if (!ASTParser.astParseInstance) {
const { default: peggy } = await import("peggy");
const parser = peggy.generate(GRAMMAR);
const { parse } = parser;
ASTParser.astParseInstance = parse as ParseFunction;
}
return ASTParser.astParseInstance;
} catch (e) {
throw new Error(
`Failed to import peggy. Please install peggy (i.e. "npm install peggy" or "yarn add peggy").`
);
}
}
/**
* Checks if the given node is a Program node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a Program node.
*/
static isProgram(node: ExpressionNode): node is Program {
return node.type === "Program";
}
/**
* Checks if the given node is an ExpressionStatement node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is an ExpressionStatement node.
*/
static isExpressionStatement(
node: ExpressionNode
): node is ExpressionStatement {
return node.type === "ExpressionStatement";
}
/**
* Checks if the given node is a CallExpression node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a CallExpression node.
*/
static isCallExpression(node: ExpressionNode): node is CallExpression {
return node.type === "CallExpression";
}
/**
* Checks if the given node is a StringLiteral node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a StringLiteral node.
*/
static isStringLiteral(node: ExpressionNode): node is StringLiteral {
return node.type === "StringLiteral" && typeof node.value === "string";
}
/**
* Checks if the given node is a NumericLiteral node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a NumericLiteral node.
*/
static isNumericLiteral(node: ExpressionNode): node is NumericLiteral {
return node.type === "NumericLiteral" && typeof node.value === "number";
}
/**
* Checks if the given node is a BooleanLiteral node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a BooleanLiteral node.
*/
static isBooleanLiteral(node: ExpressionNode): node is BooleanLiteral {
return node.type === "BooleanLiteral" && typeof node.value === "boolean";
}
/**
* Checks if the given node is an Identifier node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is an Identifier node.
*/
static isIdentifier(node: ExpressionNode): node is Identifier {
return node.type === "Identifier";
}
/**
* Checks if the given node is an ObjectExpression node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is an ObjectExpression node.
*/
static isObjectExpression(node: ExpressionNode): node is ObjectExpression {
return node.type === "ObjectExpression";
}
/**
* Checks if the given node is an ArrayExpression node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is an ArrayExpression node.
*/
static isArrayExpression(node: ExpressionNode): node is ArrayExpression {
return node.type === "ArrayExpression";
}
/**
* Checks if the given node is a PropertyAssignment node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a PropertyAssignment node.
*/
static isPropertyAssignment(
node: ExpressionNode
): node is PropertyAssignment {
return node.type === "PropertyAssignment";
}
/**
* Checks if the given node is a MemberExpression node.
* @param node The node to be checked.
* @returns A boolean indicating whether the node is a MemberExpression node.
*/
static isMemberExpression(node: ExpressionNode): node is MemberExpression {
return node.type === "MemberExpression";
}
}