circuitscript 0.0.24 → 0.0.26
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/LICENSE +1 -1
- package/dist/cjs/BaseVisitor.js +485 -0
- package/dist/cjs/SemanticTokenVisitor.js +218 -0
- package/dist/cjs/SymbolValidatorVisitor.js +233 -0
- package/dist/cjs/antlr/CircuitScriptLexer.js +256 -219
- package/dist/cjs/antlr/CircuitScriptParser.js +2891 -2151
- package/dist/cjs/antlr/CircuitScriptVisitor.js +4 -3
- package/dist/cjs/draw_symbols.js +73 -22
- package/dist/cjs/execute.js +70 -78
- package/dist/cjs/export.js +91 -5
- package/dist/cjs/geometry.js +28 -8
- package/dist/cjs/globals.js +1 -2
- package/dist/cjs/helpers.js +180 -7
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/layout.js +8 -0
- package/dist/cjs/lexer.js +19 -22
- package/dist/cjs/main.js +27 -20
- package/dist/cjs/objects/ClassComponent.js +4 -0
- package/dist/cjs/objects/ExecutionScope.js +1 -0
- package/dist/cjs/objects/types.js +7 -1
- package/dist/cjs/parser.js +29 -258
- package/dist/cjs/render.js +1 -1
- package/dist/cjs/validate.js +81 -0
- package/dist/cjs/visitor.js +601 -823
- package/dist/esm/BaseVisitor.mjs +486 -0
- package/dist/esm/SemanticTokenVisitor.mjs +215 -0
- package/dist/esm/SymbolValidatorVisitor.mjs +222 -0
- package/dist/esm/antlr/CircuitScriptLexer.mjs +231 -218
- package/dist/esm/antlr/CircuitScriptParser.mjs +2852 -2144
- package/dist/esm/antlr/CircuitScriptVisitor.mjs +13 -4
- package/dist/esm/draw_symbols.mjs +74 -23
- package/dist/esm/execute.mjs +70 -75
- package/dist/esm/export.mjs +89 -6
- package/dist/esm/geometry.mjs +28 -8
- package/dist/esm/globals.mjs +1 -2
- package/dist/esm/helpers.mjs +171 -9
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/layout.mjs +8 -0
- package/dist/esm/lexer.mjs +10 -10
- package/dist/esm/main.mjs +28 -21
- package/dist/esm/objects/ClassComponent.mjs +4 -0
- package/dist/esm/objects/ExecutionScope.mjs +1 -0
- package/dist/esm/objects/types.mjs +6 -0
- package/dist/esm/parser.mjs +25 -230
- package/dist/esm/render.mjs +2 -2
- package/dist/esm/validate.mjs +74 -0
- package/dist/esm/visitor.mjs +415 -643
- package/dist/types/BaseVisitor.d.ts +66 -0
- package/dist/types/SemanticTokenVisitor.d.ts +36 -0
- package/dist/types/SymbolValidatorVisitor.d.ts +61 -0
- package/dist/types/antlr/CircuitScriptLexer.d.ts +37 -29
- package/dist/types/antlr/CircuitScriptParser.d.ts +606 -494
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +78 -60
- package/dist/types/draw_symbols.d.ts +12 -3
- package/dist/types/execute.d.ts +5 -10
- package/dist/types/export.d.ts +27 -1
- package/dist/types/geometry.d.ts +4 -0
- package/dist/types/globals.d.ts +2 -3
- package/dist/types/helpers.d.ts +32 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lexer.d.ts +2 -2
- package/dist/types/objects/ClassComponent.d.ts +1 -0
- package/dist/types/objects/ExecutionScope.d.ts +4 -1
- package/dist/types/objects/types.d.ts +5 -0
- package/dist/types/parser.d.ts +15 -28
- package/dist/types/validate.d.ts +2 -0
- package/dist/types/visitor.d.ts +43 -95
- package/fonts/Inter-Bold.ttf +0 -0
- package/fonts/Inter-Regular.ttf +0 -0
- package/fonts/OpenSans-Regular.ttf +0 -0
- package/fonts/Roboto-Regular.ttf +0 -0
- package/libs/lib.cst +184 -0
- package/package.json +11 -6
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { ExpressionContext } from "./antlr/CircuitScriptParser";
|
|
4
|
+
import { CircuitScriptVisitor } from "./antlr/CircuitScriptVisitor";
|
|
5
|
+
import { ExecutionContext } from "./execute";
|
|
6
|
+
import { Logger } from "./logger";
|
|
7
|
+
import { ClassComponent } from "./objects/ClassComponent";
|
|
8
|
+
import { NumericValue, PercentageValue, PinBlankValue } from "./objects/ParamDefinition";
|
|
9
|
+
import { PinTypes } from "./objects/PinTypes";
|
|
10
|
+
import { UndeclaredReference } from "./objects/types";
|
|
11
|
+
import { ReferenceTypes } from './globals';
|
|
12
|
+
export class BaseVisitor extends CircuitScriptVisitor {
|
|
13
|
+
indentLevel = 0;
|
|
14
|
+
startingContext;
|
|
15
|
+
executionStack;
|
|
16
|
+
silent = false;
|
|
17
|
+
logger;
|
|
18
|
+
currentDirectory;
|
|
19
|
+
defaultLibsPath;
|
|
20
|
+
printStream = [];
|
|
21
|
+
printToConsole = true;
|
|
22
|
+
acceptedDirections = ['left', 'right', 'up', 'down'];
|
|
23
|
+
acceptedFlip = ['flipX', 'flipY'];
|
|
24
|
+
resultData = new Map;
|
|
25
|
+
paramData = new Map;
|
|
26
|
+
pinTypesList = [
|
|
27
|
+
PinTypes.Any,
|
|
28
|
+
PinTypes.Input,
|
|
29
|
+
PinTypes.Output,
|
|
30
|
+
PinTypes.IO,
|
|
31
|
+
PinTypes.Power,
|
|
32
|
+
];
|
|
33
|
+
onErrorCallbackHandler = null;
|
|
34
|
+
onImportFile = (visitor, filePath) => {
|
|
35
|
+
throw "Import file not implemented";
|
|
36
|
+
};
|
|
37
|
+
constructor(silent = false, onErrorHandler = null, currentDirectory, defaultLibsPath) {
|
|
38
|
+
super();
|
|
39
|
+
this.logger = new Logger();
|
|
40
|
+
this.onErrorCallbackHandler = onErrorHandler;
|
|
41
|
+
this.startingContext = new ExecutionContext('__', '__.', '/', 0, 0, silent, this.logger, null);
|
|
42
|
+
this.setupPrintFunction(this.startingContext);
|
|
43
|
+
this.executionStack = [this.startingContext];
|
|
44
|
+
this.startingContext.resolveNet =
|
|
45
|
+
this.createNetResolver(this.executionStack);
|
|
46
|
+
this.silent = silent;
|
|
47
|
+
this.currentDirectory = currentDirectory;
|
|
48
|
+
this.defaultLibsPath = defaultLibsPath;
|
|
49
|
+
}
|
|
50
|
+
getExecutor() {
|
|
51
|
+
return this.executionStack[this.executionStack.length - 1];
|
|
52
|
+
}
|
|
53
|
+
setupPrintFunction(context) {
|
|
54
|
+
context.createFunction('print', (params) => {
|
|
55
|
+
const items = params.map(([, , value]) => {
|
|
56
|
+
return value;
|
|
57
|
+
});
|
|
58
|
+
if (this.printToConsole) {
|
|
59
|
+
console.log('::', ...items);
|
|
60
|
+
}
|
|
61
|
+
this.printStream.push(...items);
|
|
62
|
+
return [this, null];
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
createNetResolver(executionStack) {
|
|
66
|
+
const resolveNet = (netName, netNamespace) => {
|
|
67
|
+
this.log('find net', netNamespace, netName);
|
|
68
|
+
const reversed = [...executionStack].reverse();
|
|
69
|
+
for (let i = 0; i < reversed.length; i++) {
|
|
70
|
+
const context = reversed[i];
|
|
71
|
+
const net = context.scope.getNetWithName(netName);
|
|
72
|
+
if (net !== null && net.namespace === netNamespace) {
|
|
73
|
+
return {
|
|
74
|
+
found: true,
|
|
75
|
+
net,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
found: false
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
return resolveNet;
|
|
84
|
+
}
|
|
85
|
+
log(...params) {
|
|
86
|
+
const indentOutput = ''.padStart(this.indentLevel * 4, ' ');
|
|
87
|
+
const indentLevelText = this.indentLevel.toString().padStart(3, ' ');
|
|
88
|
+
const args = ['[' + indentLevelText + ']', indentOutput, ...params];
|
|
89
|
+
this.logger.add(args.join(' '));
|
|
90
|
+
if (!this.silent) {
|
|
91
|
+
console.log.apply(null, args);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
log2(message) {
|
|
95
|
+
this.getExecutor().log(message);
|
|
96
|
+
}
|
|
97
|
+
visitScript = (ctx) => {
|
|
98
|
+
this.log('===', 'start', '===');
|
|
99
|
+
const result = this.visitChildren(ctx);
|
|
100
|
+
this.log('===', 'end', '===');
|
|
101
|
+
return result;
|
|
102
|
+
};
|
|
103
|
+
visitAssignment_expr = (ctx) => {
|
|
104
|
+
const atomStr = ctx.atom_expr().getText();
|
|
105
|
+
if (atomStr.indexOf('(') !== -1 || atomStr.indexOf(')') !== -1) {
|
|
106
|
+
throw "Invalid assignment expression!";
|
|
107
|
+
}
|
|
108
|
+
const ctxAtomExpr = ctx.atom_expr();
|
|
109
|
+
this.visit(ctxAtomExpr);
|
|
110
|
+
const reference = this.getResult(ctxAtomExpr);
|
|
111
|
+
const ctxDataExpr = ctx.data_expr();
|
|
112
|
+
this.visit(ctxDataExpr);
|
|
113
|
+
const value = this.getResult(ctxDataExpr);
|
|
114
|
+
if (value instanceof ClassComponent) {
|
|
115
|
+
const instances = this.getExecutor().scope.instances;
|
|
116
|
+
const tmpComponent = value;
|
|
117
|
+
const oldName = tmpComponent.instanceName;
|
|
118
|
+
tmpComponent.instanceName = reference.name;
|
|
119
|
+
instances.delete(oldName);
|
|
120
|
+
instances.set(reference.name, tmpComponent);
|
|
121
|
+
this.getExecutor().log(`assigned '${reference.name}' to ClassComponent`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const trailers = reference.trailers ?? [];
|
|
125
|
+
if (trailers.length === 0) {
|
|
126
|
+
this.getExecutor().scope.variables.set(reference.name, value);
|
|
127
|
+
}
|
|
128
|
+
else if (reference.value instanceof ClassComponent) {
|
|
129
|
+
this.setInstanceParam(reference.value, trailers, value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.setResult(ctx, value);
|
|
133
|
+
};
|
|
134
|
+
visitAtom_expr = (ctx) => {
|
|
135
|
+
const executor = this.getExecutor();
|
|
136
|
+
const firstId = ctx.ID(0);
|
|
137
|
+
const atomId = firstId.getText();
|
|
138
|
+
let currentReference;
|
|
139
|
+
if (this.pinTypesList.indexOf(atomId) !== -1) {
|
|
140
|
+
currentReference = {
|
|
141
|
+
found: true,
|
|
142
|
+
value: atomId,
|
|
143
|
+
type: ReferenceTypes.pinType,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
currentReference = executor.resolveVariable(this.executionStack, atomId);
|
|
148
|
+
}
|
|
149
|
+
if (currentReference.found && currentReference.type === 'instance') {
|
|
150
|
+
const tmpComponent = currentReference.value;
|
|
151
|
+
for (const [pinId, net] of tmpComponent.pinNets) {
|
|
152
|
+
executor.scope.setNet(tmpComponent, pinId, net);
|
|
153
|
+
}
|
|
154
|
+
if (ctx.ID().length > 1) {
|
|
155
|
+
currentReference.trailers = [];
|
|
156
|
+
const idLength = ctx.ID().length;
|
|
157
|
+
for (let i = 1; i < idLength; i++) {
|
|
158
|
+
const tmpCtx = ctx.ID(i);
|
|
159
|
+
currentReference.trailers.push(tmpCtx.getText());
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (ctx.parent instanceof ExpressionContext && !currentReference.found) {
|
|
164
|
+
throw "Unknown symbol: " + atomId;
|
|
165
|
+
}
|
|
166
|
+
this.setResult(ctx, currentReference);
|
|
167
|
+
};
|
|
168
|
+
visitFunctionCallExpr = (ctx) => {
|
|
169
|
+
const tmpCtx = ctx.function_call_expr();
|
|
170
|
+
this.visit(tmpCtx);
|
|
171
|
+
const result = this.getResult(tmpCtx);
|
|
172
|
+
this.setResult(ctx, result);
|
|
173
|
+
};
|
|
174
|
+
visitFunction_call_expr = (ctx) => {
|
|
175
|
+
const executor = this.getExecutor();
|
|
176
|
+
const atomId = ctx.ID().getText();
|
|
177
|
+
let passedNetNamespace = null;
|
|
178
|
+
const netNameSpaceExpr = ctx.net_namespace_expr();
|
|
179
|
+
if (netNameSpaceExpr) {
|
|
180
|
+
this.visit(netNameSpaceExpr);
|
|
181
|
+
passedNetNamespace = this.getResult(netNameSpaceExpr);
|
|
182
|
+
}
|
|
183
|
+
let currentReference = executor.resolveVariable(this.executionStack, atomId);
|
|
184
|
+
if (ctx.trailer_expr().length > 0) {
|
|
185
|
+
if (!currentReference.found) {
|
|
186
|
+
throw "Unknown function name: " + atomId;
|
|
187
|
+
}
|
|
188
|
+
currentReference.trailers = [];
|
|
189
|
+
ctx.trailer_expr().forEach(item => {
|
|
190
|
+
const itemValue = item.getText();
|
|
191
|
+
if (item.OPEN_PAREN() && item.CLOSE_PAREN()) {
|
|
192
|
+
let parameters = [];
|
|
193
|
+
const ctxParameters = item.parameters();
|
|
194
|
+
if (ctxParameters) {
|
|
195
|
+
this.visit(ctxParameters);
|
|
196
|
+
parameters = this.getResult(ctxParameters);
|
|
197
|
+
}
|
|
198
|
+
const useNetNamespace = this.getNetNamespace(executor.netNamespace, passedNetNamespace);
|
|
199
|
+
const [, functionResult] = executor.callFunction(currentReference.name, parameters, this.executionStack, useNetNamespace);
|
|
200
|
+
currentReference = {
|
|
201
|
+
found: true,
|
|
202
|
+
value: functionResult,
|
|
203
|
+
type: (functionResult instanceof ClassComponent) ?
|
|
204
|
+
'instance' : 'value',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
currentReference.trailers.push(itemValue);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
this.setResult(ctx, currentReference.value);
|
|
213
|
+
};
|
|
214
|
+
visitValue_expr = (ctx) => {
|
|
215
|
+
const sign = ctx.Minus() ? -1 : 1;
|
|
216
|
+
const ctxIntegerValue = ctx.INTEGER_VALUE();
|
|
217
|
+
const ctxDecimalValue = ctx.DECIMAL_VALUE();
|
|
218
|
+
const ctxNumericValue = ctx.NUMERIC_VALUE();
|
|
219
|
+
const ctxBooleanValue = ctx.BOOLEAN_VALUE();
|
|
220
|
+
const ctxStringValue = ctx.STRING_VALUE();
|
|
221
|
+
const ctxPercentageValue = ctx.PERCENTAGE_VALUE();
|
|
222
|
+
const ctxBlankExpr = ctx.blank_expr();
|
|
223
|
+
let result = null;
|
|
224
|
+
if (ctxIntegerValue || ctxDecimalValue || ctxNumericValue) {
|
|
225
|
+
if (ctxIntegerValue) {
|
|
226
|
+
result = sign * Number(ctxIntegerValue.getText());
|
|
227
|
+
}
|
|
228
|
+
else if (ctxDecimalValue) {
|
|
229
|
+
result = sign * Number(ctxDecimalValue.getText());
|
|
230
|
+
}
|
|
231
|
+
else if (ctxNumericValue) {
|
|
232
|
+
const textExtra = ctx.Minus() ? '-' : '';
|
|
233
|
+
result = new NumericValue(textExtra + ctxNumericValue.getText());
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
if (sign === -1) {
|
|
238
|
+
throw "Invalid value!";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (ctxBooleanValue) {
|
|
242
|
+
const stringValue = ctxBooleanValue.getText();
|
|
243
|
+
if (stringValue === 'true') {
|
|
244
|
+
result = true;
|
|
245
|
+
}
|
|
246
|
+
else if (stringValue === 'false') {
|
|
247
|
+
result = false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (ctxStringValue) {
|
|
251
|
+
result = this.prepareStringValue(ctxStringValue.getText());
|
|
252
|
+
}
|
|
253
|
+
else if (ctxPercentageValue) {
|
|
254
|
+
result = new PercentageValue(ctxPercentageValue.getText());
|
|
255
|
+
}
|
|
256
|
+
else if (ctxBlankExpr) {
|
|
257
|
+
this.visit(ctxBlankExpr);
|
|
258
|
+
result = this.getResult(ctxBlankExpr);
|
|
259
|
+
}
|
|
260
|
+
this.setResult(ctx, result);
|
|
261
|
+
};
|
|
262
|
+
visitBlank_expr = (ctx) => {
|
|
263
|
+
this.setResult(ctx, new PinBlankValue(Number(ctx.INTEGER_VALUE().getText())));
|
|
264
|
+
};
|
|
265
|
+
visitValueAtomExpr = (ctx) => {
|
|
266
|
+
let value = null;
|
|
267
|
+
const ctxValueExpr = ctx.value_expr();
|
|
268
|
+
const ctxAtomExpr = ctx.atom_expr();
|
|
269
|
+
if (ctxValueExpr) {
|
|
270
|
+
this.visit(ctxValueExpr);
|
|
271
|
+
value = this.getResult(ctxValueExpr);
|
|
272
|
+
}
|
|
273
|
+
else if (ctxAtomExpr) {
|
|
274
|
+
this.visit(ctxAtomExpr);
|
|
275
|
+
const reference = this.getResult(ctxAtomExpr);
|
|
276
|
+
if (!reference.found) {
|
|
277
|
+
value = new UndeclaredReference(reference);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
if (reference.type && reference.type === ReferenceTypes.pinType) {
|
|
281
|
+
value = reference;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
value = reference.value;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
this.setResult(ctx, value);
|
|
289
|
+
};
|
|
290
|
+
visitFunction_args_expr = (ctx) => {
|
|
291
|
+
const defaultValuesProvided = ctx.value_expr();
|
|
292
|
+
const IDs = ctx.ID();
|
|
293
|
+
const boundary = IDs.length - defaultValuesProvided.length;
|
|
294
|
+
const result = IDs.map((id, index) => {
|
|
295
|
+
const idText = id.getText();
|
|
296
|
+
if (index >= boundary) {
|
|
297
|
+
const tmpCtx = defaultValuesProvided[index - boundary];
|
|
298
|
+
this.visit(tmpCtx);
|
|
299
|
+
const defaultValue = this.getResult(tmpCtx);
|
|
300
|
+
return [idText, defaultValue];
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
return [idText];
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
this.setResult(ctx, result);
|
|
307
|
+
};
|
|
308
|
+
visitParameters = (ctx) => {
|
|
309
|
+
const dataExpressions = ctx.data_expr();
|
|
310
|
+
const keywordAssignmentExpressions = ctx.keyword_assignment_expr();
|
|
311
|
+
const returnList = [];
|
|
312
|
+
dataExpressions.forEach((item, index) => {
|
|
313
|
+
this.visit(item);
|
|
314
|
+
const value = this.getResult(item);
|
|
315
|
+
returnList.push(['position', index, value]);
|
|
316
|
+
});
|
|
317
|
+
keywordAssignmentExpressions.forEach((item) => {
|
|
318
|
+
this.visit(item);
|
|
319
|
+
const [key, value] = this.getResult(item);
|
|
320
|
+
returnList.push(['keyword', key, value]);
|
|
321
|
+
});
|
|
322
|
+
this.setResult(ctx, returnList);
|
|
323
|
+
};
|
|
324
|
+
visitImport_expr = (ctx) => {
|
|
325
|
+
const ID = ctx.ID().toString();
|
|
326
|
+
this.log('import', ID);
|
|
327
|
+
this.handleImportFile(ID, true);
|
|
328
|
+
this.log('done import', ID);
|
|
329
|
+
};
|
|
330
|
+
visitFunction_return_expr = (ctx) => {
|
|
331
|
+
const executor = this.getExecutor();
|
|
332
|
+
executor.log('return from function');
|
|
333
|
+
const ctxDataExpr = ctx.data_expr();
|
|
334
|
+
this.visit(ctxDataExpr);
|
|
335
|
+
const returnValue = this.getResult(ctxDataExpr);
|
|
336
|
+
executor.stopFurtherExpressions = true;
|
|
337
|
+
executor.returnValue = returnValue;
|
|
338
|
+
this.setResult(ctx, returnValue);
|
|
339
|
+
};
|
|
340
|
+
visitBreak_keyword = (ctx) => {
|
|
341
|
+
this.getExecutor().breakBranch();
|
|
342
|
+
this.setResult(ctx, -1);
|
|
343
|
+
};
|
|
344
|
+
setResult(ctx, value) {
|
|
345
|
+
this.resultData.set(ctx, value);
|
|
346
|
+
}
|
|
347
|
+
getResult(ctx) {
|
|
348
|
+
return this.resultData.get(ctx);
|
|
349
|
+
}
|
|
350
|
+
handleImportFile(name, throwErrors = true) {
|
|
351
|
+
let hasError = false;
|
|
352
|
+
let hasParseError = false;
|
|
353
|
+
let pathExists = false;
|
|
354
|
+
const tmpFilePath = join(this.currentDirectory, name + ".cst");
|
|
355
|
+
this.log('importing path:', tmpFilePath);
|
|
356
|
+
let fileData = null;
|
|
357
|
+
try {
|
|
358
|
+
fileData = readFileSync(tmpFilePath, { encoding: 'utf8' });
|
|
359
|
+
pathExists = true;
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
pathExists = false;
|
|
363
|
+
}
|
|
364
|
+
if (!pathExists) {
|
|
365
|
+
try {
|
|
366
|
+
const tmpFilePath2 = join(this.defaultLibsPath, name + ".cst");
|
|
367
|
+
fileData = readFileSync(tmpFilePath2, { encoding: 'utf8' });
|
|
368
|
+
pathExists = true;
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
pathExists = false;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
if (pathExists) {
|
|
376
|
+
this.log('done reading imported file data');
|
|
377
|
+
const importResult = this.onImportFile(this, fileData, this.onErrorCallbackHandler);
|
|
378
|
+
hasError = importResult.hasError;
|
|
379
|
+
hasParseError = importResult.hasParseError;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch (err) {
|
|
383
|
+
this.log('Failed to import file: ', err.message);
|
|
384
|
+
}
|
|
385
|
+
if (throwErrors && (hasError || hasParseError || !pathExists)) {
|
|
386
|
+
if (!pathExists) {
|
|
387
|
+
throw `File does not exist: ${name}`;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
throw `Failed to import: ${name}`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
hasError,
|
|
395
|
+
hasParseError,
|
|
396
|
+
pathExists,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
visitRoundedBracketsExpr = (ctx) => {
|
|
400
|
+
const ctxDataExpr = ctx.data_expr();
|
|
401
|
+
this.visit(ctxDataExpr);
|
|
402
|
+
const innerResult = this.getResult(ctxDataExpr);
|
|
403
|
+
this.setResult(ctx, innerResult);
|
|
404
|
+
};
|
|
405
|
+
setupDefinedParameters(funcDefinedParameters, passedInParameters, executor) {
|
|
406
|
+
for (let i = 0; i < funcDefinedParameters.length; i++) {
|
|
407
|
+
const tmpFuncArg = funcDefinedParameters[i];
|
|
408
|
+
if (i < passedInParameters.length) {
|
|
409
|
+
const tmpPassedInArgs = passedInParameters[i];
|
|
410
|
+
if (tmpPassedInArgs[0] === 'position') {
|
|
411
|
+
const variableName = tmpFuncArg[0];
|
|
412
|
+
executor.log('set variable in scope, var name: ', variableName);
|
|
413
|
+
executor.scope.variables.set(variableName, tmpPassedInArgs[2]);
|
|
414
|
+
if (tmpPassedInArgs[2] instanceof ClassComponent) {
|
|
415
|
+
const component = tmpPassedInArgs[2];
|
|
416
|
+
for (const [pinNumber, net] of component.pinNets) {
|
|
417
|
+
executor.scope.setNet(component, pinNumber, net);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
else if (tmpFuncArg.length === 2) {
|
|
423
|
+
const variableName = tmpFuncArg[0];
|
|
424
|
+
const defaultValue = tmpFuncArg[1];
|
|
425
|
+
executor.log('set variable in scope, var name: ', variableName);
|
|
426
|
+
executor.scope.variables.set(variableName, defaultValue);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
throw `Invalid arguments got: ` + passedInParameters;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
runExpressions(executor, expressions) {
|
|
434
|
+
let returnValue = null;
|
|
435
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
436
|
+
const expr = expressions[i];
|
|
437
|
+
this.visit(expr);
|
|
438
|
+
if (executor.stopFurtherExpressions) {
|
|
439
|
+
returnValue = executor.returnValue;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return returnValue;
|
|
444
|
+
}
|
|
445
|
+
getNetNamespace(executorNetNamespace, passedNetNamespace) {
|
|
446
|
+
let result = executorNetNamespace;
|
|
447
|
+
if (passedNetNamespace !== null && passedNetNamespace.length > 0) {
|
|
448
|
+
if (passedNetNamespace === '/' || passedNetNamespace === '_') {
|
|
449
|
+
result = '';
|
|
450
|
+
}
|
|
451
|
+
else if (passedNetNamespace[0] === '+') {
|
|
452
|
+
if (executorNetNamespace === '/') {
|
|
453
|
+
result = passedNetNamespace.slice(1);
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
result = executorNetNamespace + passedNetNamespace.slice(2);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
result = passedNetNamespace;
|
|
461
|
+
}
|
|
462
|
+
result = result + '/';
|
|
463
|
+
}
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
setInstanceParam(object, trailers, value) {
|
|
467
|
+
const paramName = trailers[0];
|
|
468
|
+
object.setParam(paramName, value);
|
|
469
|
+
this.getExecutor().log(`set instance ${object.instanceName} param ${paramName} to ${value}`);
|
|
470
|
+
}
|
|
471
|
+
enterNewChildContext(executionStack, parentContext, executionContextName, options, funcDefinedParameters, passedInParameters) {
|
|
472
|
+
const { netNamespace = "" } = options;
|
|
473
|
+
const currentExecutionContext = executionStack[executionStack.length - 1];
|
|
474
|
+
const executionLevel = currentExecutionContext.executionLevel;
|
|
475
|
+
const executionContextNamespace = currentExecutionContext.namespace
|
|
476
|
+
+ executionContextName + ".";
|
|
477
|
+
const newExecutor = new ExecutionContext(executionContextName, executionContextNamespace, netNamespace, executionLevel + 1, this.getExecutor().scope.indentLevel + 1, currentExecutionContext.silent, currentExecutionContext.logger, parentContext);
|
|
478
|
+
this.setupPrintFunction(newExecutor);
|
|
479
|
+
executionStack.push(newExecutor);
|
|
480
|
+
this.setupDefinedParameters(funcDefinedParameters, passedInParameters, newExecutor);
|
|
481
|
+
return newExecutor;
|
|
482
|
+
}
|
|
483
|
+
prepareStringValue(value) {
|
|
484
|
+
return value.slice(1, value.length - 1);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Assignment_exprContext } from "./antlr/CircuitScriptParser";
|
|
2
|
+
import { BaseVisitor } from "./BaseVisitor";
|
|
3
|
+
export class SemanticTokensVisitor extends BaseVisitor {
|
|
4
|
+
parsedTokens = [];
|
|
5
|
+
lexer;
|
|
6
|
+
script;
|
|
7
|
+
semanticTokens = new Map();
|
|
8
|
+
constructor(silent = false, onErrorHandler = null, currentDirectory, defaultsLibsPath, lexer, script) {
|
|
9
|
+
super(silent, onErrorHandler, currentDirectory, defaultsLibsPath);
|
|
10
|
+
this.lexer = lexer;
|
|
11
|
+
this.script = script;
|
|
12
|
+
}
|
|
13
|
+
visitFunction_args_expr = (ctx) => {
|
|
14
|
+
const IDs = ctx.ID();
|
|
15
|
+
IDs.map(id => {
|
|
16
|
+
this.addSemanticToken(id, ['declaration'], 'parameter');
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
visitFunction_call_expr = (ctx) => {
|
|
20
|
+
this.addSemanticToken(ctx.ID(), [], 'function');
|
|
21
|
+
};
|
|
22
|
+
visitFunction_def_expr = (ctx) => {
|
|
23
|
+
const functionName = ctx.ID().getText();
|
|
24
|
+
this.addSemanticToken(ctx.ID(), ['declaration'], 'function');
|
|
25
|
+
const ctxFunctionArgsExpr = ctx.function_args_expr();
|
|
26
|
+
if (ctxFunctionArgsExpr) {
|
|
27
|
+
this.visit(ctxFunctionArgsExpr);
|
|
28
|
+
}
|
|
29
|
+
const executionContextName = functionName + '_validate';
|
|
30
|
+
const newExecutor = this.enterNewChildContext(this.executionStack, this.getExecutor(), executionContextName, { netNamespace: "" }, [], []);
|
|
31
|
+
this.runExpressions(newExecutor, ctx.function_expr());
|
|
32
|
+
this.executionStack.pop();
|
|
33
|
+
};
|
|
34
|
+
visitCreate_component_expr = (ctx) => {
|
|
35
|
+
this.addSemanticToken(ctx.Create(), ['defaultLibrary'], 'function');
|
|
36
|
+
ctx.property_expr().forEach(property_expr => {
|
|
37
|
+
this.visit(property_expr);
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
visitCreate_graphic_expr = (ctx) => {
|
|
41
|
+
this.addSemanticToken(ctx.Create(), ['defaultLibrary'], 'function');
|
|
42
|
+
ctx.graphic_expr().forEach(graphic_expr => {
|
|
43
|
+
this.visit(graphic_expr);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
visitProperty_key_expr = (ctx) => {
|
|
47
|
+
let useValue = null;
|
|
48
|
+
const ctxId = ctx.ID();
|
|
49
|
+
const ctxIntegerValue = ctx.INTEGER_VALUE();
|
|
50
|
+
const ctxStringValue = ctx.STRING_VALUE();
|
|
51
|
+
if (ctxId) {
|
|
52
|
+
useValue = ctxId;
|
|
53
|
+
}
|
|
54
|
+
else if (ctxIntegerValue) {
|
|
55
|
+
useValue = ctxIntegerValue;
|
|
56
|
+
}
|
|
57
|
+
else if (ctxStringValue) {
|
|
58
|
+
useValue = ctxStringValue;
|
|
59
|
+
}
|
|
60
|
+
if (useValue) {
|
|
61
|
+
this.addSemanticToken(useValue, [], 'property');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
visitGraphic_expr = (ctx) => {
|
|
65
|
+
let useValue = null;
|
|
66
|
+
const ctxId = ctx.ID();
|
|
67
|
+
const ctxPin = ctx.Pin();
|
|
68
|
+
if (ctxId) {
|
|
69
|
+
useValue = ctxId;
|
|
70
|
+
}
|
|
71
|
+
else if (ctxPin) {
|
|
72
|
+
useValue = ctxPin;
|
|
73
|
+
}
|
|
74
|
+
if (useValue) {
|
|
75
|
+
this.addSemanticToken(useValue, [], 'property');
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
visitValueAtomExpr = (ctx) => {
|
|
79
|
+
const ctxValueExpr = ctx.value_expr();
|
|
80
|
+
const ctxAtomExpr = ctx.atom_expr();
|
|
81
|
+
if (ctxValueExpr) {
|
|
82
|
+
this.visit(ctxValueExpr);
|
|
83
|
+
}
|
|
84
|
+
else if (ctxAtomExpr) {
|
|
85
|
+
this.visit(ctxAtomExpr);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
visitAssignment_expr = (ctx) => {
|
|
89
|
+
this.visit(ctx.atom_expr());
|
|
90
|
+
this.visit(ctx.data_expr());
|
|
91
|
+
};
|
|
92
|
+
visitAtom_expr = (ctx) => {
|
|
93
|
+
if (ctx.parent instanceof Assignment_exprContext && ctx.ID(0)) {
|
|
94
|
+
this.addSemanticToken(ctx.ID(0), [], 'variable');
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
visitImport_expr = (ctx) => {
|
|
98
|
+
this.addSemanticToken(ctx.ID(), [], 'namespace');
|
|
99
|
+
};
|
|
100
|
+
addSemanticToken(node, modifiers, tokenType = null) {
|
|
101
|
+
const parsedToken = this.parseToken(node, modifiers, tokenType);
|
|
102
|
+
this.semanticTokens.set(parsedToken.line + "_" + parsedToken.column, parsedToken);
|
|
103
|
+
}
|
|
104
|
+
parseToken(node, modifiers, tokenType = null) {
|
|
105
|
+
const token = node.symbol;
|
|
106
|
+
let stringValue = "";
|
|
107
|
+
let textPart = "";
|
|
108
|
+
if (this.lexer.symbolicNames[token.type] !== null && this.lexer.symbolicNames[token.type] !== undefined) {
|
|
109
|
+
stringValue = this.lexer.symbolicNames[token.type];
|
|
110
|
+
if (stringValue !== "NEWLINE") {
|
|
111
|
+
textPart = this.script.substring(token.start, token.stop + 1);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
textPart = token.text.length - 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (this.lexer.literalNames[token.type] !== null && this.lexer.literalNames[token.type] !== undefined) {
|
|
118
|
+
stringValue = this.lexer.literalNames[token.type];
|
|
119
|
+
textPart = this.script.substring(token.start, token.stop + 1);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
stringValue = token._text;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
line: token.line,
|
|
126
|
+
column: token.column,
|
|
127
|
+
length: token.stop - token.start + 1,
|
|
128
|
+
tokenType: tokenType !== null ? tokenType : stringValue,
|
|
129
|
+
tokenModifiers: modifiers,
|
|
130
|
+
textValue: textPart,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
dumpTokens() {
|
|
134
|
+
for (const [id, value] of this.semanticTokens) {
|
|
135
|
+
console.log(id, value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
getTokens() {
|
|
139
|
+
return this.semanticTokens;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export function prepareTokens(tokens, lexer, script) {
|
|
143
|
+
const parsedTokens = [];
|
|
144
|
+
tokens.forEach(item => {
|
|
145
|
+
if (item.type !== -1) {
|
|
146
|
+
let stringValue = "";
|
|
147
|
+
let textPart = "";
|
|
148
|
+
if (lexer.symbolicNames[item.type] !== null && lexer.symbolicNames[item.type] !== undefined) {
|
|
149
|
+
stringValue = lexer.symbolicNames[item.type];
|
|
150
|
+
if (stringValue !== "NEWLINE") {
|
|
151
|
+
textPart = script.substring(item.start, item.stop + 1);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
textPart = item.text.length - 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (lexer.literalNames[item.type] !== null && lexer.literalNames[item.type] !== undefined) {
|
|
158
|
+
stringValue = lexer.literalNames[item.type];
|
|
159
|
+
textPart = script.substring(item.start, item.stop + 1);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
stringValue = item._text;
|
|
163
|
+
}
|
|
164
|
+
if (textPart !== 0 && textPart !== '') {
|
|
165
|
+
parsedTokens.push({
|
|
166
|
+
line: item.line,
|
|
167
|
+
column: item.column,
|
|
168
|
+
length: item.stop - item.start + 1,
|
|
169
|
+
tokenType: resolveTokenType(stringValue),
|
|
170
|
+
tokenModifiers: resolveTokenModifiers(stringValue),
|
|
171
|
+
textValue: textPart,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return parsedTokens;
|
|
177
|
+
}
|
|
178
|
+
const languageKeywords = [
|
|
179
|
+
'break', 'branch', 'create', 'component',
|
|
180
|
+
'graphic', 'wire', 'pin', 'add', 'at', 'to',
|
|
181
|
+
'point', 'join', 'parallel', 'return', 'def', 'import',
|
|
182
|
+
'true', 'false', 'nc', 'frame',
|
|
183
|
+
];
|
|
184
|
+
const operatorKeywords = [
|
|
185
|
+
'at', 'to', 'wire', 'add', 'frame', 'join', 'parallel', 'point'
|
|
186
|
+
];
|
|
187
|
+
function resolveTokenType(tokenType) {
|
|
188
|
+
if (operatorKeywords.indexOf(tokenType.toLowerCase()) !== -1) {
|
|
189
|
+
return 'graphKeyword';
|
|
190
|
+
}
|
|
191
|
+
else if (languageKeywords.indexOf(tokenType.toLowerCase()) !== -1) {
|
|
192
|
+
return 'keyword';
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
switch (tokenType) {
|
|
196
|
+
case 'INTEGER_VALUE':
|
|
197
|
+
case 'NUMERIC_VALUE':
|
|
198
|
+
case 'DECIMAL_VALUE':
|
|
199
|
+
case 'PERCENTAGE_VALUE':
|
|
200
|
+
return 'number';
|
|
201
|
+
case 'STRING_VALUE':
|
|
202
|
+
return 'string';
|
|
203
|
+
case 'ID':
|
|
204
|
+
return 'variable';
|
|
205
|
+
case 'Define':
|
|
206
|
+
return 'keyword';
|
|
207
|
+
case 'COMMENT':
|
|
208
|
+
return 'comment';
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function resolveTokenModifiers(tokenType) {
|
|
214
|
+
return [];
|
|
215
|
+
}
|