circuitscript 0.1.5 → 0.1.7
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/dist/cjs/BaseVisitor.js +127 -73
- package/dist/cjs/SemanticTokenVisitor.js +19 -13
- package/dist/cjs/antlr/CircuitScriptParser.js +711 -671
- package/dist/cjs/builtinMethods.js +29 -25
- package/dist/cjs/environment.js +118 -0
- package/dist/cjs/execute.js +53 -12
- package/dist/cjs/geometry.js +1 -0
- package/dist/cjs/globals.js +11 -6
- package/dist/cjs/helpers.js +135 -127
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/layout.js +37 -12
- package/dist/cjs/main.js +31 -19
- package/dist/cjs/objects/ExecutionScope.js +33 -0
- package/dist/cjs/objects/ParamDefinition.js +15 -15
- package/dist/cjs/parser.js +27 -21
- package/dist/cjs/regenerate-tests.js +9 -6
- package/dist/cjs/render.js +3 -1
- package/dist/cjs/sizing.js +5 -58
- package/dist/cjs/utils.js +85 -30
- package/dist/cjs/validate/SymbolTable.js +96 -0
- package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
- package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
- package/dist/cjs/validate.js +52 -44
- package/dist/cjs/visitor.js +140 -24
- package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +98 -45
- package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
- package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
- package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +20 -16
- package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +7 -7
- package/dist/esm/environment.js +110 -0
- package/dist/esm/{execute.mjs → execute.js} +66 -25
- package/dist/esm/{export.mjs → export.js} +2 -2
- package/dist/esm/{geometry.mjs → geometry.js} +6 -5
- package/dist/esm/{globals.mjs → globals.js} +6 -1
- package/dist/esm/helpers.js +377 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/{layout.mjs → layout.js} +42 -20
- package/dist/esm/{lexer.mjs → lexer.js} +2 -2
- package/dist/esm/{main.mjs → main.js} +33 -21
- package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +5 -4
- package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +33 -0
- package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
- package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
- package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
- package/dist/esm/parser.js +71 -0
- package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +10 -7
- package/dist/esm/{render.mjs → render.js} +11 -9
- package/dist/esm/{sizing.mjs → sizing.js} +6 -34
- package/dist/esm/{utils.mjs → utils.js} +61 -17
- package/dist/esm/validate/SymbolTable.js +90 -0
- package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
- package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
- package/dist/esm/validate.js +86 -0
- package/dist/esm/{visitor.mjs → visitor.js} +151 -35
- package/dist/fonts/Arial.ttf +0 -0
- package/dist/fonts/Inter-Bold.ttf +0 -0
- package/dist/fonts/Inter-Regular.ttf +0 -0
- package/dist/fonts/OpenSans-Regular.ttf +0 -0
- package/dist/fonts/Roboto-Regular.ttf +0 -0
- package/dist/libs/lib.cst +423 -0
- package/dist/types/BaseVisitor.d.ts +34 -21
- package/dist/types/SemanticTokenVisitor.d.ts +6 -5
- package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
- package/dist/types/builtinMethods.d.ts +3 -2
- package/dist/types/environment.d.ts +31 -0
- package/dist/types/globals.d.ts +4 -1
- package/dist/types/helpers.d.ts +12 -14
- package/dist/types/index.d.ts +5 -0
- package/dist/types/objects/ClassComponent.d.ts +1 -0
- package/dist/types/objects/ExecutionScope.d.ts +11 -0
- package/dist/types/objects/types.d.ts +6 -1
- package/dist/types/parser.d.ts +7 -11
- package/dist/types/sizing.d.ts +0 -3
- package/dist/types/utils.d.ts +30 -6
- package/dist/types/validate/SymbolTable.d.ts +40 -0
- package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
- package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
- package/dist/types/validate.d.ts +1 -1
- package/package.json +14 -13
- package/dist/cjs/SymbolValidatorVisitor.js +0 -233
- package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
- package/dist/esm/helpers.mjs +0 -364
- package/dist/esm/index.mjs +0 -15
- package/dist/esm/parser.mjs +0 -64
- package/dist/esm/validate.mjs +0 -74
- package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
- package/dist/types/layout.d.ts +0 -148
- /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
- /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
- /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
- /package/dist/esm/{logger.mjs → logger.js} +0 -0
- /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
- /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
- /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
- /package/dist/esm/objects/{types.mjs → types.js} +0 -0
- /package/dist/esm/{server.mjs → server.js} +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { CircuitScriptParser } from './antlr/CircuitScriptParser.js';
|
|
2
|
+
import { MainLexer } from './lexer.js';
|
|
3
|
+
import { ParseSyntaxError, RuntimeExecutionError, SimpleStopwatch } from './utils.js';
|
|
4
|
+
import { CharStream, CommonTokenStream } from 'antlr4ng';
|
|
5
|
+
export async function parseFileWithVisitor(visitor, data) {
|
|
6
|
+
const lexerErrorListener = new CircuitscriptParserErrorListener(visitor.onErrorHandler);
|
|
7
|
+
const parserErrorListener = new CircuitscriptParserErrorListener(visitor.onErrorHandler);
|
|
8
|
+
const chars = CharStream.fromString(data);
|
|
9
|
+
const lexer = new MainLexer(chars);
|
|
10
|
+
lexer.removeErrorListeners();
|
|
11
|
+
lexer.addErrorListener(lexerErrorListener);
|
|
12
|
+
const lexerTimer = new SimpleStopwatch();
|
|
13
|
+
const tokens = new CommonTokenStream(lexer);
|
|
14
|
+
tokens.fill();
|
|
15
|
+
const lexerTimeTaken = lexerTimer.lap();
|
|
16
|
+
const parserTimer = new SimpleStopwatch();
|
|
17
|
+
const parser = new CircuitScriptParser(tokens);
|
|
18
|
+
parser.removeErrorListeners();
|
|
19
|
+
parser.addErrorListener(parserErrorListener);
|
|
20
|
+
const tree = parser.script();
|
|
21
|
+
try {
|
|
22
|
+
await visitor.visitAsync(tree);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (visitor.onErrorHandler) {
|
|
26
|
+
if (error instanceof RuntimeExecutionError) {
|
|
27
|
+
visitor.onErrorHandler(error.message, null, error);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const parserTimeTaken = parserTimer.lap();
|
|
35
|
+
return {
|
|
36
|
+
tree, parser,
|
|
37
|
+
hasParseError: false,
|
|
38
|
+
hasError: false,
|
|
39
|
+
parserTimeTaken,
|
|
40
|
+
lexerTimeTaken,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export class CircuitscriptParserErrorListener {
|
|
44
|
+
syntaxErrorCounter = 0;
|
|
45
|
+
onErrorHandler = null;
|
|
46
|
+
constructor(onErrorHandler = null) {
|
|
47
|
+
this.onErrorHandler = onErrorHandler;
|
|
48
|
+
}
|
|
49
|
+
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
|
50
|
+
if (this.onErrorHandler && e) {
|
|
51
|
+
this.onErrorHandler(msg, e.ctx, e);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (offendingSymbol && msg.match("extraneous input 'import' expecting")) {
|
|
55
|
+
msg = "Invalid import statement";
|
|
56
|
+
throw new ParseSyntaxError("Invalid import statement", offendingSymbol);
|
|
57
|
+
}
|
|
58
|
+
console.log("Syntax error at line", line, ':', column, ' - ', msg);
|
|
59
|
+
}
|
|
60
|
+
this.syntaxErrorCounter++;
|
|
61
|
+
}
|
|
62
|
+
reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) {
|
|
63
|
+
}
|
|
64
|
+
reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
|
|
65
|
+
}
|
|
66
|
+
reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs) {
|
|
67
|
+
}
|
|
68
|
+
hasSyntaxErrors() {
|
|
69
|
+
return (this.syntaxErrorCounter > 0);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { renderScript } from './helpers.js';
|
|
3
|
+
import { NodeScriptEnvironment } from "./environment.js";
|
|
4
4
|
const mainDir = './__tests__/renderData/';
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
const env = new NodeScriptEnvironment();
|
|
6
|
+
NodeScriptEnvironment.setInstance(env);
|
|
7
7
|
async function regenerateTests(extra = "") {
|
|
8
|
-
|
|
8
|
+
env.prepareSVGEnvironment();
|
|
9
9
|
const cstFiles = [];
|
|
10
10
|
const files = fs.readdirSync(mainDir);
|
|
11
11
|
files.forEach(file => {
|
|
@@ -17,9 +17,12 @@ async function regenerateTests(extra = "") {
|
|
|
17
17
|
const inputPath = mainDir + file;
|
|
18
18
|
const scriptData = fs.readFileSync(inputPath, { encoding: 'utf-8' });
|
|
19
19
|
const outputPath = mainDir + 'svgs/' + file + extra + '.svg';
|
|
20
|
+
env.setModuleDirectory(mainDir);
|
|
20
21
|
renderScript(scriptData, outputPath, {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
dumpNets: false,
|
|
23
|
+
dumpData: false,
|
|
24
|
+
showStats: false,
|
|
25
|
+
environment: env,
|
|
23
26
|
});
|
|
24
27
|
console.log('generated ', outputPath);
|
|
25
28
|
});
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { SVG, registerWindow } from '@svgdotjs/svg.js';
|
|
2
|
-
import { ExtractDrawingRects, RenderFrameType, getBounds } from "./layout.
|
|
3
|
-
import { applyFontsToSVG
|
|
4
|
-
import { ColorScheme, ComponentTypes, FrameType, MMToPt, MMToPx, ParamKeys, RenderFlags, defaultGridSizeUnits, defaultPageSpacingMM, defaultWireLineWidth, fontDisplayScale, junctionSize } from './globals.
|
|
5
|
-
import { numeric, NumericValue } from './objects/ParamDefinition.
|
|
6
|
-
import { combineMaps, getBoundsSize } from './utils.
|
|
7
|
-
import { getPaperSize, milsToMM } from './helpers.
|
|
2
|
+
import { ExtractDrawingRects, RenderFrameType, getBounds } from "./layout.js";
|
|
3
|
+
import { applyFontsToSVG } from './sizing.js';
|
|
4
|
+
import { ColorScheme, ComponentTypes, FrameType, MMToPt, MMToPx, ParamKeys, RenderFlags, defaultGridSizeUnits, defaultPageSpacingMM, defaultWireLineWidth, fontDisplayScale, junctionSize } from './globals.js';
|
|
5
|
+
import { numeric, NumericValue } from './objects/ParamDefinition.js';
|
|
6
|
+
import { combineMaps, getBoundsSize } from './utils.js';
|
|
7
|
+
import { getPaperSize, milsToMM } from './helpers.js';
|
|
8
|
+
import { NodeScriptEnvironment } from "./environment.js";
|
|
8
9
|
import SVGtoPDF from 'svg-to-pdfkit';
|
|
9
|
-
import { FrameParamKeys } from './objects/Frame.
|
|
10
|
-
import { SymbolPlaceholder } from './draw_symbols.
|
|
10
|
+
import { FrameParamKeys } from './objects/Frame.js';
|
|
11
|
+
import { SymbolPlaceholder } from './draw_symbols.js';
|
|
11
12
|
function createSvgCanvas() {
|
|
12
|
-
const
|
|
13
|
+
const env = NodeScriptEnvironment.getInstance();
|
|
14
|
+
const window = env.createSVGWindow();
|
|
13
15
|
const document = window.document;
|
|
14
16
|
registerWindow(window, document);
|
|
15
17
|
const canvas = SVG(document.documentElement);
|
|
@@ -1,42 +1,14 @@
|
|
|
1
|
-
import { SVG, registerWindow } from '@svgdotjs/svg.js';
|
|
2
1
|
import { Big } from 'big.js';
|
|
3
|
-
import { HorizontalAlign, HorizontalAlignProp, VerticalAlign, VerticalAlignProp } from './geometry.
|
|
4
|
-
import { defaultFont } from './globals.
|
|
5
|
-
import {
|
|
6
|
-
let MainCanvas = null;
|
|
7
|
-
const supportedFonts = {
|
|
8
|
-
'Arial': 'Arial.ttf',
|
|
9
|
-
};
|
|
10
|
-
let globalCreateSVGWindow;
|
|
11
|
-
export async function prepareSVGEnvironment(fontsPath) {
|
|
12
|
-
const moduleType = detectJSModuleType();
|
|
13
|
-
if (moduleType === JSModuleType.CommonJs) {
|
|
14
|
-
const { config, createSVGWindow } = await import('svgdom');
|
|
15
|
-
globalCreateSVGWindow = createSVGWindow;
|
|
16
|
-
if (fontsPath !== null) {
|
|
17
|
-
await config.setFontDir(fontsPath)
|
|
18
|
-
.setFontFamilyMappings(supportedFonts)
|
|
19
|
-
.preloadFonts();
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
export function getCreateSVGWindow() {
|
|
24
|
-
if (globalCreateSVGWindow === undefined) {
|
|
25
|
-
throw "SVG environment is not set up yet";
|
|
26
|
-
}
|
|
27
|
-
return globalCreateSVGWindow;
|
|
28
|
-
}
|
|
2
|
+
import { HorizontalAlign, HorizontalAlignProp, VerticalAlign, VerticalAlignProp } from './geometry.js';
|
|
3
|
+
import { defaultFont } from './globals.js';
|
|
4
|
+
import { NodeScriptEnvironment } from "./environment.js";
|
|
29
5
|
export function applyFontsToSVG(canvas) {
|
|
30
6
|
}
|
|
31
7
|
const measureTextSizeCache = {};
|
|
32
8
|
const measureTextSizeCacheHits = {};
|
|
33
9
|
export function measureTextSize2(text, fontFamily, fontSize, fontWeight = 'regular', anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const { document } = window;
|
|
37
|
-
registerWindow(window, document);
|
|
38
|
-
MainCanvas = SVG(document.documentElement);
|
|
39
|
-
}
|
|
10
|
+
const environment = NodeScriptEnvironment.getInstance();
|
|
11
|
+
const mainCanvas = environment.getCanvasWindow();
|
|
40
12
|
const key = `${text}-${fontFamily}-${fontSize}-${fontWeight}-${anchor}-${vanchor}`;
|
|
41
13
|
if (measureTextSizeCache[key] === undefined) {
|
|
42
14
|
let dominantBaseline = VerticalAlignProp.Hanging;
|
|
@@ -64,7 +36,7 @@ export function measureTextSize2(text, fontFamily, fontSize, fontWeight = 'regul
|
|
|
64
36
|
break;
|
|
65
37
|
}
|
|
66
38
|
fontFamily = defaultFont;
|
|
67
|
-
const tmpTextElement =
|
|
39
|
+
const tmpTextElement = mainCanvas.text(text).font({
|
|
68
40
|
family: fontFamily,
|
|
69
41
|
size: fontSize,
|
|
70
42
|
anchor: useAnchor,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Big } from 'big.js';
|
|
2
|
-
import { ClassComponent } from "./objects/ClassComponent";
|
|
3
|
-
import { NumericValue } from "./objects/ParamDefinition";
|
|
4
|
-
import { SequenceAction } from './objects/ExecutionScope';
|
|
5
|
-
import { BlockTypes } from './globals';
|
|
2
|
+
import { ClassComponent } from "./objects/ClassComponent.js";
|
|
3
|
+
import { NumericValue } from "./objects/ParamDefinition.js";
|
|
4
|
+
import { SequenceAction } from './objects/ExecutionScope.js';
|
|
5
|
+
import { BlockTypes } from './globals.js';
|
|
6
6
|
export class SimpleStopwatch {
|
|
7
7
|
startTime;
|
|
8
8
|
constructor() {
|
|
@@ -71,20 +71,17 @@ export function getPortType(component) {
|
|
|
71
71
|
export function roundValue(value) {
|
|
72
72
|
return resolveToNumericValue(new Big(value.toBigNumber().toFixed(7)));
|
|
73
73
|
}
|
|
74
|
-
export function throwWithContext(context,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const startString = startLine + ":" + startColumn;
|
|
78
|
-
const stopLine = context.stop?.line;
|
|
79
|
-
const stopColumn = context.stop?.column;
|
|
80
|
-
let stopString = "";
|
|
81
|
-
if (startLine === stopLine) {
|
|
82
|
-
stopString = stopColumn?.toString();
|
|
74
|
+
export function throwWithContext(context, messageOrError) {
|
|
75
|
+
if (messageOrError instanceof BaseError) {
|
|
76
|
+
throw messageOrError;
|
|
83
77
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw
|
|
78
|
+
throwWithTokenRange(messageOrError, context.start, context.stop);
|
|
79
|
+
}
|
|
80
|
+
export function throwWithToken(message, token) {
|
|
81
|
+
throw new ParseError(message, token);
|
|
82
|
+
}
|
|
83
|
+
export function throwWithTokenRange(message, startToken, endToken) {
|
|
84
|
+
throw new ParseError(message, startToken, endToken);
|
|
88
85
|
}
|
|
89
86
|
export function combineMaps(map1, map2) {
|
|
90
87
|
const newMap = new Map(map1);
|
|
@@ -240,3 +237,50 @@ export function getBlockTypeString(type) {
|
|
|
240
237
|
}
|
|
241
238
|
return returnValue;
|
|
242
239
|
}
|
|
240
|
+
export class BaseError extends Error {
|
|
241
|
+
name = 'BaseError';
|
|
242
|
+
message;
|
|
243
|
+
startToken;
|
|
244
|
+
endToken;
|
|
245
|
+
filePath;
|
|
246
|
+
constructor(message, startToken, endToken, filePath) {
|
|
247
|
+
super(message);
|
|
248
|
+
this.message = message;
|
|
249
|
+
this.startToken = startToken;
|
|
250
|
+
this.endToken = endToken;
|
|
251
|
+
this.filePath = filePath;
|
|
252
|
+
}
|
|
253
|
+
toString() {
|
|
254
|
+
const parts = [this.name];
|
|
255
|
+
if (this.startToken) {
|
|
256
|
+
const { line, column } = this.startToken;
|
|
257
|
+
if (this.endToken && (this.endToken.line !== this.startToken.line || this.endToken.column !== this.startToken.column)) {
|
|
258
|
+
const endLine = this.endToken.line;
|
|
259
|
+
const endColumn = this.endToken.column + (this.endToken.stop - this.endToken.start);
|
|
260
|
+
parts.push(` at ${line}:${column}-${endLine}:${endColumn}`);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
parts.push(` at ${line}:${column}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
parts.push(`: ${this.message}`);
|
|
267
|
+
return parts.join('');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export class ParseSyntaxError extends BaseError {
|
|
271
|
+
name = 'ParseSyntaxError';
|
|
272
|
+
}
|
|
273
|
+
export class ParseError extends ParseSyntaxError {
|
|
274
|
+
name = 'ParseError';
|
|
275
|
+
}
|
|
276
|
+
export class RuntimeExecutionError extends BaseError {
|
|
277
|
+
name = 'RuntimeExecutionError';
|
|
278
|
+
}
|
|
279
|
+
export class RenderError extends Error {
|
|
280
|
+
stage;
|
|
281
|
+
constructor(message, stage) {
|
|
282
|
+
super(message);
|
|
283
|
+
this.name = 'RenderError';
|
|
284
|
+
this.stage = stage;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ParseSymbolType } from "../objects/types.js";
|
|
2
|
+
export class SymbolTable {
|
|
3
|
+
symbols = new Map();
|
|
4
|
+
executonContextsNamespaces = [];
|
|
5
|
+
getSymbols() {
|
|
6
|
+
return this.symbols;
|
|
7
|
+
}
|
|
8
|
+
addFunction(token, fileName, executionContext, id, funcDefinedParameters) {
|
|
9
|
+
return this.add(fileName, executionContext, id, ParseSymbolType.Function, {
|
|
10
|
+
funcDefinedParameters
|
|
11
|
+
}, token);
|
|
12
|
+
}
|
|
13
|
+
addVariable(token, fileName, executionContext, id, variableValue) {
|
|
14
|
+
return this.add(fileName, executionContext, id, ParseSymbolType.Variable, {
|
|
15
|
+
variableValue
|
|
16
|
+
}, token);
|
|
17
|
+
}
|
|
18
|
+
addUndefined(filePath, executionContext, id, token) {
|
|
19
|
+
return this.add(filePath, executionContext, id, ParseSymbolType.Undefined, {}, token);
|
|
20
|
+
}
|
|
21
|
+
add(fileName, executionContext, id, type, extra, token) {
|
|
22
|
+
if (this.executonContextsNamespaces.indexOf(executionContext.namespace) === -1) {
|
|
23
|
+
this.executonContextsNamespaces.push(executionContext.namespace);
|
|
24
|
+
}
|
|
25
|
+
const item = {
|
|
26
|
+
id,
|
|
27
|
+
type,
|
|
28
|
+
context: executionContext,
|
|
29
|
+
fileName,
|
|
30
|
+
extra,
|
|
31
|
+
token,
|
|
32
|
+
instances: [],
|
|
33
|
+
};
|
|
34
|
+
if (token !== null) {
|
|
35
|
+
item.instances.push(token);
|
|
36
|
+
}
|
|
37
|
+
this.symbols.set(this.idName(executionContext, id), item);
|
|
38
|
+
return item;
|
|
39
|
+
}
|
|
40
|
+
idName(executionContext, id) {
|
|
41
|
+
return executionContext.namespace + id;
|
|
42
|
+
}
|
|
43
|
+
dumpSymbols() {
|
|
44
|
+
for (const [key, value] of this.symbols) {
|
|
45
|
+
console.log(value.type.padEnd(10, " "), key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exists(executionContext, id) {
|
|
49
|
+
const name = this.idName(executionContext, id);
|
|
50
|
+
return this.symbols.has(name);
|
|
51
|
+
}
|
|
52
|
+
existsAny(executionContext, id) {
|
|
53
|
+
if (this.exists(executionContext, id)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return this.searchParentContext(executionContext, id) !== null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
get(executionContext, id) {
|
|
61
|
+
const name = this.idName(executionContext, id);
|
|
62
|
+
return this.symbols.get(name);
|
|
63
|
+
}
|
|
64
|
+
getParentContexts(executionContext, contextsNamespace) {
|
|
65
|
+
if (executionContext.parentContext !== null) {
|
|
66
|
+
contextsNamespace.push(executionContext.parentContext.namespace);
|
|
67
|
+
this.getParentContexts(executionContext.parentContext, contextsNamespace);
|
|
68
|
+
}
|
|
69
|
+
return contextsNamespace;
|
|
70
|
+
}
|
|
71
|
+
searchParentContext(executionContext, id) {
|
|
72
|
+
const contextNames = this.getParentContexts(executionContext, []);
|
|
73
|
+
for (const [key,] of this.symbols) {
|
|
74
|
+
if (key.endsWith(`.${id}`)) {
|
|
75
|
+
const { context } = this.symbols.get(key);
|
|
76
|
+
if (contextNames.indexOf(context.namespace) !== -1) {
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
clearUndefined() {
|
|
84
|
+
for (const [key, value] of this.symbols) {
|
|
85
|
+
if (value.type === ParseSymbolType.Undefined) {
|
|
86
|
+
this.symbols.delete(key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SymbolValidatorVisitor } from "./SymbolValidatorVisitor.js";
|
|
2
|
+
export class SymbolValidatorResolveVisitor extends SymbolValidatorVisitor {
|
|
3
|
+
addSymbolVariable(token, name, value) {
|
|
4
|
+
}
|
|
5
|
+
addSymbolFunction(token, functionName, funcDefinedParameters) {
|
|
6
|
+
if (this.symbolTable.exists(this.getExecutor(), functionName)) {
|
|
7
|
+
this.symbolTable.addFunction(token, this.getCurrentFile(), this.getExecutor(), functionName, funcDefinedParameters);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { buildInMethodNamesList } from "../builtinMethods.js";
|
|
2
|
+
import { ParseSymbolType } from "../objects/types.js";
|
|
3
|
+
import { SymbolTable } from "./SymbolTable.js";
|
|
4
|
+
import { BaseVisitor } from "../BaseVisitor.js";
|
|
5
|
+
import { SymbolValidatorContext } from "../globals.js";
|
|
6
|
+
export class SymbolValidatorVisitor extends BaseVisitor {
|
|
7
|
+
symbolTable = new SymbolTable();
|
|
8
|
+
filePathStack = [];
|
|
9
|
+
enterFile(filePath) {
|
|
10
|
+
this.filePathStack.push(filePath);
|
|
11
|
+
}
|
|
12
|
+
exitFile() {
|
|
13
|
+
this.filePathStack.pop();
|
|
14
|
+
}
|
|
15
|
+
getCurrentFile() {
|
|
16
|
+
return this.filePathStack[this.filePathStack.length - 1];
|
|
17
|
+
}
|
|
18
|
+
addSymbolVariable(token, name, value, executor = null) {
|
|
19
|
+
const useExecutor = executor === null ? this.getExecutor() : executor;
|
|
20
|
+
this.symbolTable.addVariable(token, this.getCurrentFile(), useExecutor, name, value);
|
|
21
|
+
this.log2('add symbol variable: ' + name);
|
|
22
|
+
}
|
|
23
|
+
addSymbolFunction(token, functionName, funcDefinedParameters) {
|
|
24
|
+
if (!this.symbolTable.exists(this.getExecutor(), functionName)) {
|
|
25
|
+
this.symbolTable.addFunction(token, this.getCurrentFile(), this.getExecutor(), functionName, funcDefinedParameters);
|
|
26
|
+
this.log2('add symbol function: ' + functionName);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
handleAtomSymbol(atom) {
|
|
30
|
+
const atomId = atom.getText();
|
|
31
|
+
const executor = this.getExecutor();
|
|
32
|
+
let tmpSymbol;
|
|
33
|
+
if (this.symbolTable.exists(executor, atomId)) {
|
|
34
|
+
tmpSymbol = this.symbolTable.get(executor, atomId);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (buildInMethodNamesList.indexOf(atomId) !== -1) {
|
|
38
|
+
tmpSymbol = this.symbolTable.addFunction(null, "<builtIn>", this.getRootExecutor(), atomId, {});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const foundContext = this.symbolTable.searchParentContext(executor, atomId);
|
|
42
|
+
if (foundContext === null) {
|
|
43
|
+
tmpSymbol = this.symbolTable.addUndefined(this.getCurrentFile(), executor, atomId, atom.getSymbol());
|
|
44
|
+
this.log2('symbol not found: ' + atomId);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
tmpSymbol = this.symbolTable.get(foundContext, atomId);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (tmpSymbol.type !== ParseSymbolType.Undefined) {
|
|
52
|
+
this.addSymbolInstance(tmpSymbol, atom.getSymbol());
|
|
53
|
+
}
|
|
54
|
+
return tmpSymbol;
|
|
55
|
+
}
|
|
56
|
+
addSymbolInstance(symbol, token) {
|
|
57
|
+
symbol = symbol;
|
|
58
|
+
if (symbol.instances.indexOf(token) == -1) {
|
|
59
|
+
symbol.instances.push(token);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
setSymbols(symbolTable) {
|
|
63
|
+
this.symbolTable = symbolTable;
|
|
64
|
+
}
|
|
65
|
+
visitImport_expr = (ctx) => {
|
|
66
|
+
const ID = ctx.ID().toString();
|
|
67
|
+
const { pathExists } = this.handleImportFile(ID, false, ctx);
|
|
68
|
+
if (!pathExists) {
|
|
69
|
+
this.symbolTable.addUndefined(this.getCurrentFile(), this.getExecutor(), ID, ctx.ID().getSymbol());
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
visitAssignment_expr = (ctx) => {
|
|
73
|
+
const ctxDataExpr = ctx.data_expr();
|
|
74
|
+
this.visit(ctxDataExpr);
|
|
75
|
+
const value = this.getResult(ctxDataExpr);
|
|
76
|
+
const atomId = ctx.atom_expr().ID(0);
|
|
77
|
+
const atomText = atomId.getText();
|
|
78
|
+
const executor = this.getExecutor();
|
|
79
|
+
if (!this.symbolTable.exists(executor, atomText)) {
|
|
80
|
+
this.addSymbolVariable(atomId.getSymbol(), atomId.getText(), value);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const tmpSymbol = this.symbolTable.get(executor, atomText);
|
|
84
|
+
this.addSymbolInstance(tmpSymbol, atomId.getSymbol());
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
};
|
|
88
|
+
visitAtom_expr = (ctx) => {
|
|
89
|
+
const tmpSymbol = this.handleAtomSymbol(ctx.ID(0));
|
|
90
|
+
this.setResult(ctx, tmpSymbol);
|
|
91
|
+
};
|
|
92
|
+
visitFunction_call_expr = (ctx) => {
|
|
93
|
+
this.handleAtomSymbol(ctx.ID());
|
|
94
|
+
if (ctx.trailer_expr().length > 0) {
|
|
95
|
+
ctx.trailer_expr().forEach(item => {
|
|
96
|
+
if (item.OPEN_PAREN() && item.CLOSE_PAREN()) {
|
|
97
|
+
const params = item.parameters();
|
|
98
|
+
if (params) {
|
|
99
|
+
this.visit(params);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
visitValueAtomExpr = (ctx) => {
|
|
106
|
+
let value = null;
|
|
107
|
+
const ctxValueExpr = ctx.value_expr();
|
|
108
|
+
const cxtAtomExpr = ctx.atom_expr();
|
|
109
|
+
if (ctxValueExpr) {
|
|
110
|
+
this.visit(ctxValueExpr);
|
|
111
|
+
value = this.getResult(ctxValueExpr);
|
|
112
|
+
}
|
|
113
|
+
else if (cxtAtomExpr) {
|
|
114
|
+
this.visit(cxtAtomExpr);
|
|
115
|
+
value = this.getResult(cxtAtomExpr);
|
|
116
|
+
}
|
|
117
|
+
this.setResult(ctx, value);
|
|
118
|
+
};
|
|
119
|
+
visitUnaryOperatorExpr = (ctx) => {
|
|
120
|
+
this.visit(ctx.data_expr());
|
|
121
|
+
};
|
|
122
|
+
visitMultiplyExpr = (ctx) => {
|
|
123
|
+
this.visit(ctx.data_expr(0));
|
|
124
|
+
this.visit(ctx.data_expr(1));
|
|
125
|
+
};
|
|
126
|
+
visitAdditionExpr = (ctx) => {
|
|
127
|
+
this.visit(ctx.data_expr(0));
|
|
128
|
+
this.visit(ctx.data_expr(1));
|
|
129
|
+
};
|
|
130
|
+
visitBinaryOperatorExpr = (ctx) => {
|
|
131
|
+
this.visit(ctx.data_expr(0));
|
|
132
|
+
this.visit(ctx.data_expr(1));
|
|
133
|
+
};
|
|
134
|
+
visitDataExpr = (ctx) => {
|
|
135
|
+
return;
|
|
136
|
+
};
|
|
137
|
+
visitFunction_def_expr = (ctx) => {
|
|
138
|
+
const functionName = ctx.ID().getText();
|
|
139
|
+
let funcDefinedParameters = [];
|
|
140
|
+
const ctxFunctionArgsExpr = ctx.function_args_expr();
|
|
141
|
+
if (ctxFunctionArgsExpr) {
|
|
142
|
+
this.visit(ctxFunctionArgsExpr);
|
|
143
|
+
funcDefinedParameters = this.getResult(ctxFunctionArgsExpr);
|
|
144
|
+
}
|
|
145
|
+
this.addSymbolFunction(ctx.ID().getSymbol(), functionName, funcDefinedParameters);
|
|
146
|
+
const executionContextName = functionName + SymbolValidatorContext;
|
|
147
|
+
const passedInParamsNull = funcDefinedParameters.map((param, index) => {
|
|
148
|
+
return ['position', index, null];
|
|
149
|
+
});
|
|
150
|
+
const newExecutor = this.enterNewChildContext(this.executionStack, this.getExecutor(), executionContextName, { netNamespace: "" }, funcDefinedParameters, passedInParamsNull);
|
|
151
|
+
funcDefinedParameters.forEach(param => {
|
|
152
|
+
this.addSymbolVariable(param[1], param[0], null, newExecutor);
|
|
153
|
+
});
|
|
154
|
+
this.runExpressions(newExecutor, ctx.function_expr());
|
|
155
|
+
this.executionStack.pop();
|
|
156
|
+
};
|
|
157
|
+
getSymbols() {
|
|
158
|
+
return this.symbolTable;
|
|
159
|
+
}
|
|
160
|
+
dumpSymbols() {
|
|
161
|
+
this.symbolTable.dumpSymbols();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { readFileSync, existsSync } from 'fs';
|
|
4
|
+
import { getSemanticTokens, validateScript } from './helpers.js';
|
|
5
|
+
import { NodeScriptEnvironment } from "./environment.js";
|
|
6
|
+
import { ParseSymbolType } from './objects/types.js';
|
|
7
|
+
export default async function validate() {
|
|
8
|
+
const env = new NodeScriptEnvironment();
|
|
9
|
+
NodeScriptEnvironment.setInstance(env);
|
|
10
|
+
const version = env.getPackageVersion();
|
|
11
|
+
program
|
|
12
|
+
.description('generate validation output circuitscript files')
|
|
13
|
+
.version(version)
|
|
14
|
+
.argument('[input path]', 'Input path')
|
|
15
|
+
.argument('[output path]', 'Output path')
|
|
16
|
+
.option('-i, --input text <input text>', 'Input text directly')
|
|
17
|
+
.option('-c, --current-directory <path>', 'Set current directory')
|
|
18
|
+
.option('-w, --watch', 'Watch for file changes')
|
|
19
|
+
.option('-n, --dump-nets', 'Dump out net information')
|
|
20
|
+
.option('-d, --dump-data', 'Dump data during parsing')
|
|
21
|
+
.option('-s, --stats', 'Show stats during generation')
|
|
22
|
+
.option('-x, --skip-output', 'Skip output generation');
|
|
23
|
+
if (process.argv.length < 3) {
|
|
24
|
+
program.help();
|
|
25
|
+
}
|
|
26
|
+
program.parse();
|
|
27
|
+
const options = program.opts();
|
|
28
|
+
const args = program.args;
|
|
29
|
+
const watchFileChanges = options.watch;
|
|
30
|
+
const dumpNets = options.dumpNets;
|
|
31
|
+
const dumpData = options.dumpData;
|
|
32
|
+
if (options.currentDirectory) {
|
|
33
|
+
env.setModuleDirectory(options.currentDirectory);
|
|
34
|
+
}
|
|
35
|
+
if (watchFileChanges) {
|
|
36
|
+
console.log('watching for file changes...');
|
|
37
|
+
}
|
|
38
|
+
await env.prepareSVGEnvironment();
|
|
39
|
+
let inputFilePath = "";
|
|
40
|
+
if (args.length > 2) {
|
|
41
|
+
console.log("Error: Extra arguments passed");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let scriptData;
|
|
45
|
+
if (args.length > 0 && args[0]) {
|
|
46
|
+
inputFilePath = args[0];
|
|
47
|
+
if (existsSync(inputFilePath)) {
|
|
48
|
+
scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.error("Error: File could not be found");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (options.input) {
|
|
56
|
+
scriptData = options.input;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.error("Error: No input provided");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const scriptOptions = {
|
|
63
|
+
dumpNets,
|
|
64
|
+
dumpData,
|
|
65
|
+
showStats: options.stats,
|
|
66
|
+
environment: env,
|
|
67
|
+
};
|
|
68
|
+
const visitor = await validateScript(inputFilePath, scriptData, scriptOptions);
|
|
69
|
+
const symbols = visitor.getSymbols().getSymbols();
|
|
70
|
+
symbols.forEach((value, key) => {
|
|
71
|
+
if (value.type !== ParseSymbolType.Undefined) {
|
|
72
|
+
value = value;
|
|
73
|
+
const token = value.token;
|
|
74
|
+
console.log(key, value.fileName, token !== null ? (token.line + ":" + token.column) : "");
|
|
75
|
+
value.instances.forEach(instance => {
|
|
76
|
+
console.log(" " + instance.line + ":" + instance.column + " " + instance.start);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const { parsedTokens } = await getSemanticTokens(scriptData, scriptOptions);
|
|
81
|
+
parsedTokens.forEach(item => {
|
|
82
|
+
const { line, column, tokenType, tokenModifiers, textValue } = item;
|
|
83
|
+
console.log(`${line}:${column} - ${textValue} - ${tokenType} | ${tokenModifiers.join(',')}`);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
validate();
|