circuitscript 0.0.24 → 0.0.25
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 +487 -0
- package/dist/cjs/SemanticTokenVisitor.js +218 -0
- package/dist/cjs/SymbolValidatorVisitor.js +233 -0
- package/dist/cjs/antlr/CircuitScriptLexer.js +209 -195
- package/dist/cjs/antlr/CircuitScriptParser.js +2310 -2087
- package/dist/cjs/antlr/CircuitScriptVisitor.js +4 -3
- package/dist/cjs/draw_symbols.js +67 -22
- package/dist/cjs/execute.js +51 -53
- package/dist/cjs/geometry.js +28 -8
- package/dist/cjs/helpers.js +175 -5
- 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 +6 -11
- package/dist/cjs/objects/ClassComponent.js +3 -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/validate.js +81 -0
- package/dist/cjs/visitor.js +529 -820
- package/dist/esm/BaseVisitor.mjs +488 -0
- package/dist/esm/SemanticTokenVisitor.mjs +215 -0
- package/dist/esm/SymbolValidatorVisitor.mjs +222 -0
- package/dist/esm/antlr/CircuitScriptLexer.mjs +184 -194
- package/dist/esm/antlr/CircuitScriptParser.mjs +2279 -2084
- package/dist/esm/antlr/CircuitScriptVisitor.mjs +8 -3
- package/dist/esm/draw_symbols.mjs +67 -22
- package/dist/esm/execute.mjs +50 -52
- package/dist/esm/geometry.mjs +28 -8
- package/dist/esm/helpers.mjs +165 -6
- 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 +7 -12
- package/dist/esm/objects/ClassComponent.mjs +3 -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/validate.mjs +74 -0
- package/dist/esm/visitor.mjs +343 -640
- package/dist/types/BaseVisitor.d.ts +69 -0
- package/dist/types/SemanticTokenVisitor.d.ts +36 -0
- package/dist/types/SymbolValidatorVisitor.d.ts +61 -0
- package/dist/types/antlr/CircuitScriptLexer.d.ts +8 -7
- package/dist/types/antlr/CircuitScriptParser.d.ts +513 -469
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +69 -59
- package/dist/types/draw_symbols.d.ts +9 -0
- package/dist/types/execute.d.ts +5 -8
- package/dist/types/geometry.d.ts +4 -0
- 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/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 +40 -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 +183 -0
- package/package.json +11 -6
package/dist/esm/helpers.mjs
CHANGED
|
@@ -1,23 +1,165 @@
|
|
|
1
|
-
import { writeFileSync } from "fs";
|
|
1
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
2
2
|
import { generateKiCADNetList } from "./export.mjs";
|
|
3
3
|
import { LayoutEngine } from "./layout.mjs";
|
|
4
4
|
import { SequenceAction } from "./objects/ExecutionScope.mjs";
|
|
5
5
|
import { parseFileWithVisitor } from "./parser.mjs";
|
|
6
6
|
import { generateSVG2 } from "./render.mjs";
|
|
7
7
|
import { SimpleStopwatch } from "./utils.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { ParserVisitor, VisitorExecutionException } from "./visitor.mjs";
|
|
9
9
|
import { createContext } from "this-file";
|
|
10
|
+
import { SymbolValidatorResolveVisitor, SymbolValidatorVisitor } from "./SymbolValidatorVisitor.mjs";
|
|
11
|
+
import { BaseErrorListener, CharStream, CommonTokenStream, DefaultErrorStrategy } from "antlr4ng";
|
|
12
|
+
import { MainLexer } from "./lexer.mjs";
|
|
13
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.mjs";
|
|
14
|
+
import { prepareTokens, SemanticTokensVisitor } from "./SemanticTokenVisitor.mjs";
|
|
15
|
+
import path from "path";
|
|
10
16
|
export var JSModuleType;
|
|
11
17
|
(function (JSModuleType) {
|
|
12
18
|
JSModuleType["CommonJs"] = "cjs";
|
|
13
19
|
JSModuleType["ESM"] = "mjs";
|
|
14
20
|
})(JSModuleType || (JSModuleType = {}));
|
|
21
|
+
export function prepareFile(textData) {
|
|
22
|
+
const chars = CharStream.fromString(textData);
|
|
23
|
+
const lexer = new MainLexer(chars);
|
|
24
|
+
const lexerTimer = new SimpleStopwatch();
|
|
25
|
+
const tokens = new CommonTokenStream(lexer);
|
|
26
|
+
tokens.fill();
|
|
27
|
+
const lexerTimeTaken = lexerTimer.lap();
|
|
28
|
+
const parser = new CircuitScriptParser(tokens);
|
|
29
|
+
return {
|
|
30
|
+
parser,
|
|
31
|
+
lexer,
|
|
32
|
+
lexerTimeTaken,
|
|
33
|
+
tokens
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function getScriptText(filePath) {
|
|
37
|
+
try {
|
|
38
|
+
return readFileSync(filePath, { encoding: 'utf-8' });
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function getSemanticTokens(scriptData, options) {
|
|
45
|
+
const { parser, lexer, tokens } = prepareFile(scriptData);
|
|
46
|
+
const tree = parser.script();
|
|
47
|
+
const { currentDirectory = null, defaultLibsPath, } = options;
|
|
48
|
+
const visitor = new SemanticTokensVisitor(true, null, currentDirectory, defaultLibsPath, lexer, scriptData);
|
|
49
|
+
parser.removeErrorListeners();
|
|
50
|
+
visitor.onImportFile = (visitor, textData) => {
|
|
51
|
+
let hasError = false;
|
|
52
|
+
let hasParseError = false;
|
|
53
|
+
if (textData !== null) {
|
|
54
|
+
const { parser } = prepareFile(textData);
|
|
55
|
+
const tree = parser.script();
|
|
56
|
+
try {
|
|
57
|
+
visitor.visit(tree);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.log('Error while parsing: ', err);
|
|
61
|
+
hasParseError = true;
|
|
62
|
+
hasError = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log('File does not exist');
|
|
67
|
+
hasError = true;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
hasError, hasParseError
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
visitor.visit(tree);
|
|
74
|
+
const semanticTokens = visitor.getTokens();
|
|
75
|
+
const parsedTokens = prepareTokens(tokens.getTokens(), lexer, scriptData);
|
|
76
|
+
const finalParsedTokens = [];
|
|
77
|
+
parsedTokens.forEach(token => {
|
|
78
|
+
const location = `${token.line}_${token.column}`;
|
|
79
|
+
if (semanticTokens.has(location)) {
|
|
80
|
+
finalParsedTokens.push(semanticTokens.get(location));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
finalParsedTokens.push(token);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
visitor,
|
|
88
|
+
parsedTokens: finalParsedTokens
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
class TokenErrorListener extends BaseErrorListener {
|
|
92
|
+
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
|
93
|
+
console.log(msg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export class ParseErrorStrategy extends DefaultErrorStrategy {
|
|
97
|
+
reportUnwantedToken(recognizer) {
|
|
98
|
+
if (this.inErrorRecoveryMode(recognizer)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this.beginErrorCondition(recognizer);
|
|
102
|
+
const t = recognizer.getCurrentToken();
|
|
103
|
+
const tokenName = this.getTokenErrorDisplay(t);
|
|
104
|
+
const msg = "extraneous input " + tokenName;
|
|
105
|
+
recognizer.notifyErrorListeners(msg, t, null);
|
|
106
|
+
this.endErrorCondition(recognizer);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export function validateScript(scriptData, options) {
|
|
110
|
+
const { parser } = prepareFile(scriptData);
|
|
111
|
+
parser.removeErrorListeners();
|
|
112
|
+
parser.errorHandler = new ParseErrorStrategy();
|
|
113
|
+
parser.addErrorListener(new TokenErrorListener());
|
|
114
|
+
const tree = parser.script();
|
|
115
|
+
const { currentDirectory = null, defaultLibsPath, } = options;
|
|
116
|
+
const visitor = new SymbolValidatorVisitor(true, null, currentDirectory, defaultLibsPath);
|
|
117
|
+
visitor.onImportFile = (visitor, textData) => {
|
|
118
|
+
let hasError = false;
|
|
119
|
+
let hasParseError = false;
|
|
120
|
+
if (textData !== null) {
|
|
121
|
+
const { parser } = prepareFile(textData);
|
|
122
|
+
const tree = parser.script();
|
|
123
|
+
try {
|
|
124
|
+
visitor.visit(tree);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.log('got an error while parsing tree: ', err);
|
|
128
|
+
hasParseError = true;
|
|
129
|
+
hasError = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log('file does not exist!');
|
|
134
|
+
hasError = true;
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
hasError, hasParseError
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
visitor.visit(tree);
|
|
141
|
+
const symbolTable = visitor.getSymbols();
|
|
142
|
+
symbolTable.clearUndefined();
|
|
143
|
+
const visitorResolver = new SymbolValidatorResolveVisitor(true, null, currentDirectory, defaultLibsPath);
|
|
144
|
+
visitorResolver.setSymbols(visitor.getSymbols());
|
|
145
|
+
visitorResolver.onImportFile = visitor.onImportFile;
|
|
146
|
+
visitorResolver.visit(tree);
|
|
147
|
+
return visitorResolver;
|
|
148
|
+
}
|
|
15
149
|
export function renderScript(scriptData, outputPath, options) {
|
|
16
150
|
const { currentDirectory = null, defaultLibsPath, dumpNets = false, dumpData = false, kicadNetlistPath = null, showStats = false } = options;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
151
|
+
const onErrorHandler = (line, column, message, error) => {
|
|
152
|
+
if (error instanceof VisitorExecutionException) {
|
|
153
|
+
console.log('Error', line, column, message, error.errorMessage);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const visitor = new ParserVisitor(true, onErrorHandler, currentDirectory, defaultLibsPath);
|
|
157
|
+
visitor.onImportFile = (visitor, fileData) => {
|
|
158
|
+
const { hasError, hasParseError } = parseFileWithVisitor(visitor, fileData);
|
|
159
|
+
return { hasError, hasParseError };
|
|
160
|
+
};
|
|
161
|
+
visitor.log('reading file');
|
|
162
|
+
visitor.log('done reading file');
|
|
21
163
|
const { tree, parser, hasParseError, hasError, parserTimeTaken, lexerTimeTaken } = parseFileWithVisitor(visitor, scriptData);
|
|
22
164
|
showStats && console.log('Lexing took:', lexerTimeTaken);
|
|
23
165
|
showStats && console.log('Parsing took:', parserTimeTaken);
|
|
@@ -91,3 +233,20 @@ export function getCurrentPath() {
|
|
|
91
233
|
const filename = context.filename;
|
|
92
234
|
return { filePath: filename };
|
|
93
235
|
}
|
|
236
|
+
function getToolsPath() {
|
|
237
|
+
const { filePath } = getCurrentPath();
|
|
238
|
+
return path.normalize(path.dirname(filePath) + '/../../');
|
|
239
|
+
}
|
|
240
|
+
export function getFontsPath() {
|
|
241
|
+
const toolsPath = getToolsPath();
|
|
242
|
+
return path.normalize(toolsPath + "fonts");
|
|
243
|
+
}
|
|
244
|
+
export function getDefaultLibsPath() {
|
|
245
|
+
const toolsPath = getToolsPath();
|
|
246
|
+
return path.normalize(toolsPath + "libs");
|
|
247
|
+
}
|
|
248
|
+
export function getPackageVersion() {
|
|
249
|
+
const packageJson = JSON.parse(readFileSync(getToolsPath() + 'package.json').toString());
|
|
250
|
+
const { version } = packageJson;
|
|
251
|
+
return version;
|
|
252
|
+
}
|
package/dist/esm/index.mjs
CHANGED
package/dist/esm/layout.mjs
CHANGED
|
@@ -393,6 +393,14 @@ export class LayoutEngine {
|
|
|
393
393
|
didSetAngle = true;
|
|
394
394
|
tmpSymbol.angle = component.parameters.get('angle');
|
|
395
395
|
}
|
|
396
|
+
if (component.parameters.has('flipX')) {
|
|
397
|
+
tmpSymbol.flipX =
|
|
398
|
+
component.parameters.get('flipX');
|
|
399
|
+
}
|
|
400
|
+
if (component.parameters.has('flipY')) {
|
|
401
|
+
tmpSymbol.flipY =
|
|
402
|
+
component.parameters.get('flipY');
|
|
403
|
+
}
|
|
396
404
|
if (tmpSymbol instanceof SymbolCustom && widthProp) {
|
|
397
405
|
tmpSymbol.bodyWidth = widthProp;
|
|
398
406
|
}
|
package/dist/esm/lexer.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CommonToken } from "
|
|
2
|
-
import CircuitScriptParser from "./antlr/CircuitScriptParser.mjs";
|
|
3
|
-
import CircuitScriptLexer from "./antlr/CircuitScriptLexer.mjs";
|
|
1
|
+
import { CommonToken } from "antlr4ng";
|
|
2
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.mjs";
|
|
3
|
+
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.mjs";
|
|
4
4
|
export class MainLexer extends CircuitScriptLexer {
|
|
5
5
|
tokens;
|
|
6
6
|
indents;
|
|
@@ -22,7 +22,7 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
22
22
|
this.tokens.push(token);
|
|
23
23
|
}
|
|
24
24
|
nextToken() {
|
|
25
|
-
if (this.
|
|
25
|
+
if (this.inputStream.LA(1) === CircuitScriptParser.EOF && this.indents.length) {
|
|
26
26
|
this.tokens = this.tokens.filter(function (val) {
|
|
27
27
|
return val.type !== CircuitScriptParser.EOF;
|
|
28
28
|
});
|
|
@@ -40,20 +40,20 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
40
40
|
return this.commonToken(CircuitScriptParser.DEDENT, "");
|
|
41
41
|
}
|
|
42
42
|
getCharIndex() {
|
|
43
|
-
return this.
|
|
43
|
+
return this.inputStream.index;
|
|
44
44
|
}
|
|
45
45
|
commonToken(type, text) {
|
|
46
46
|
const stop = this.getCharIndex() - 1;
|
|
47
47
|
const start = text.length ? stop - text.length + 1 : stop;
|
|
48
|
-
const token =
|
|
49
|
-
let tokenTypeString;
|
|
48
|
+
const token = CommonToken.fromSource([this, this.inputStream], type, 0, start, stop);
|
|
49
|
+
let tokenTypeString = null;
|
|
50
50
|
if (type === CircuitScriptParser.INDENT) {
|
|
51
51
|
tokenTypeString = "indent";
|
|
52
52
|
}
|
|
53
53
|
else if (type === CircuitScriptParser.DEDENT) {
|
|
54
54
|
tokenTypeString = "dedent";
|
|
55
55
|
}
|
|
56
|
-
if (tokenTypeString) {
|
|
56
|
+
if (tokenTypeString !== null) {
|
|
57
57
|
token.text = tokenTypeString;
|
|
58
58
|
}
|
|
59
59
|
return token;
|
|
@@ -82,8 +82,8 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
82
82
|
onNewLine() {
|
|
83
83
|
const newLine = this.text.replace(/[^\r\n]+/g, '');
|
|
84
84
|
const spaces = this.text.replace(/[\r\n]+/g, '');
|
|
85
|
-
const next = this.
|
|
86
|
-
const nextnext = this.
|
|
85
|
+
const next = this.inputStream.LA(1);
|
|
86
|
+
const nextnext = this.inputStream.LA(2);
|
|
87
87
|
if (this.opened > 0 || (nextnext != -1 &&
|
|
88
88
|
(next === 13 || next === 10 || next === 35))) {
|
|
89
89
|
this.skip();
|
package/dist/esm/main.mjs
CHANGED
|
@@ -4,16 +4,11 @@ import figlet from 'figlet';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { readFileSync, watch } from 'fs';
|
|
6
6
|
import { prepareSVGEnvironment } from './sizing.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import { getDefaultLibsPath, getFontsPath, getPackageVersion, renderScript } from './helpers.mjs';
|
|
8
8
|
export default async function main() {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const fontsPath = toolDirectory + '/fonts';
|
|
13
|
-
const defaultLibsPath = toolDirectory + '/libs';
|
|
14
|
-
const packageJson = JSON.parse(readFileSync(toolDirectory + 'package.json').toString());
|
|
15
|
-
;
|
|
16
|
-
const { version } = packageJson;
|
|
9
|
+
const fontsPath = getFontsPath();
|
|
10
|
+
const defaultLibsPath = getDefaultLibsPath();
|
|
11
|
+
const version = getPackageVersion();
|
|
17
12
|
program
|
|
18
13
|
.description('generate graphical output from circuitscript files')
|
|
19
14
|
.version(version)
|
|
@@ -56,7 +51,7 @@ export default async function main() {
|
|
|
56
51
|
currentDirectory = path.dirname(inputFilePath);
|
|
57
52
|
}
|
|
58
53
|
}
|
|
59
|
-
const
|
|
54
|
+
const scriptOptions = {
|
|
60
55
|
currentDirectory,
|
|
61
56
|
defaultLibsPath,
|
|
62
57
|
dumpNets,
|
|
@@ -64,7 +59,7 @@ export default async function main() {
|
|
|
64
59
|
kicadNetlistPath: kicadNetlist,
|
|
65
60
|
showStats: options.stats,
|
|
66
61
|
};
|
|
67
|
-
const output = renderScript(scriptData, outputPath,
|
|
62
|
+
const output = renderScript(scriptData, outputPath, scriptOptions);
|
|
68
63
|
if (outputPath === null && output) {
|
|
69
64
|
console.log(output);
|
|
70
65
|
}
|
|
@@ -72,7 +67,7 @@ export default async function main() {
|
|
|
72
67
|
watch(inputFilePath, event => {
|
|
73
68
|
if (event === 'change') {
|
|
74
69
|
const scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
|
|
75
|
-
renderScript(scriptData, outputPath,
|
|
70
|
+
renderScript(scriptData, outputPath, scriptOptions);
|
|
76
71
|
console.log('done');
|
|
77
72
|
}
|
|
78
73
|
});
|
|
@@ -129,6 +129,9 @@ export class ClassComponent {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
for (const [key, value] of this.parameters) {
|
|
132
|
+
if (key === 'flipX' || key === 'flipY' || key === 'angle') {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
132
135
|
component.parameters.set(key, value);
|
|
133
136
|
}
|
|
134
137
|
for (const [key, value] of this.pins) {
|
|
@@ -4,3 +4,9 @@ export class UndeclaredReference {
|
|
|
4
4
|
this.reference = reference;
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
+
export var ParseSymbolType;
|
|
8
|
+
(function (ParseSymbolType) {
|
|
9
|
+
ParseSymbolType["Variable"] = "variable";
|
|
10
|
+
ParseSymbolType["Function"] = "function";
|
|
11
|
+
ParseSymbolType["Undefined"] = "undefined";
|
|
12
|
+
})(ParseSymbolType || (ParseSymbolType = {}));
|
package/dist/esm/parser.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import CircuitScriptParser, { Atom_exprContext, Create_component_exprContext, Create_graphic_exprContext, Function_def_exprContext, Property_key_exprContext, Sub_exprContext } from './antlr/CircuitScriptParser.mjs';
|
|
1
|
+
import { CircuitScriptParser } from './antlr/CircuitScriptParser.mjs';
|
|
3
2
|
import { MainLexer } from './lexer.mjs';
|
|
4
3
|
import { SimpleStopwatch } from './utils.mjs';
|
|
4
|
+
import { CharStream, CommonTokenStream, DefaultErrorStrategy } from 'antlr4ng';
|
|
5
5
|
export function parseFileWithVisitor(visitor, data) {
|
|
6
|
-
const chars =
|
|
6
|
+
const chars = CharStream.fromString(data);
|
|
7
7
|
const lexer = new MainLexer(chars);
|
|
8
8
|
const lexerTimer = new SimpleStopwatch();
|
|
9
9
|
const tokens = new CommonTokenStream(lexer);
|
|
@@ -11,259 +11,54 @@ export function parseFileWithVisitor(visitor, data) {
|
|
|
11
11
|
const lexerTimeTaken = lexerTimer.lap();
|
|
12
12
|
const parserTimer = new SimpleStopwatch();
|
|
13
13
|
const parser = new CircuitScriptParser(tokens);
|
|
14
|
-
parser.removeErrorListeners();
|
|
15
|
-
const errorListener = new CircuitscriptParserErrorListener();
|
|
16
|
-
parser.addErrorListener(errorListener);
|
|
17
14
|
const tree = parser.script();
|
|
18
15
|
let hasError = false;
|
|
19
16
|
try {
|
|
20
17
|
visitor.visit(tree);
|
|
21
18
|
}
|
|
22
19
|
catch (err) {
|
|
23
|
-
|
|
20
|
+
console.log(err);
|
|
24
21
|
hasError = true;
|
|
25
22
|
}
|
|
26
23
|
const parserTimeTaken = parserTimer.lap();
|
|
27
|
-
const semanticTokenVisitor = new SemanticTokensVisitor(lexer, data);
|
|
28
|
-
semanticTokenVisitor.visit(tree);
|
|
29
|
-
const semanticTokens = semanticTokenVisitor.semanticTokens;
|
|
30
|
-
const parsedTokens = prepareTokens(tokens.tokens, lexer, data);
|
|
31
|
-
const finalParsedTokens = [];
|
|
32
|
-
parsedTokens.forEach(token => {
|
|
33
|
-
const location = `${token.line}_${token.column}`;
|
|
34
|
-
if (semanticTokens.has(location)) {
|
|
35
|
-
finalParsedTokens.push(semanticTokens.get(location));
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
finalParsedTokens.push(token);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
24
|
return {
|
|
42
25
|
tree, parser,
|
|
43
|
-
hasParseError:
|
|
26
|
+
hasParseError: false,
|
|
44
27
|
hasError,
|
|
45
28
|
parserTimeTaken,
|
|
46
29
|
lexerTimeTaken,
|
|
47
|
-
tokens: finalParsedTokens,
|
|
48
30
|
};
|
|
49
31
|
}
|
|
50
|
-
export class
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
script;
|
|
54
|
-
semanticTokens = new Map();
|
|
55
|
-
constructor(lexer, script) {
|
|
56
|
-
super();
|
|
57
|
-
this.lexer = lexer;
|
|
58
|
-
this.script = script;
|
|
59
|
-
}
|
|
60
|
-
visit(ctx) {
|
|
61
|
-
const here = this;
|
|
62
|
-
if (Array.isArray(ctx)) {
|
|
63
|
-
return ctx.map(function (child) {
|
|
64
|
-
try {
|
|
65
|
-
here.checkContext(child);
|
|
66
|
-
return child.accept(this);
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
this.handleError(child, err);
|
|
70
|
-
}
|
|
71
|
-
}, this);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
try {
|
|
75
|
-
this.checkContext(ctx);
|
|
76
|
-
return ctx.accept(this);
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
this.handleError(ctx, err);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
32
|
+
export class TempErrorStrategy extends DefaultErrorStrategy {
|
|
33
|
+
recover(recognizer, e) {
|
|
34
|
+
throw new Error('Method not implemented.');
|
|
82
35
|
}
|
|
83
|
-
|
|
84
|
-
|
|
36
|
+
reportError(recognizer, e) {
|
|
37
|
+
throw new Error('Method not implemented.');
|
|
85
38
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.addSemanticToken(this.parseToken(ctx.Create(), ['defaultLibrary'], 'function'));
|
|
93
|
-
}
|
|
94
|
-
else if (ctx instanceof Atom_exprContext) {
|
|
95
|
-
if (ctx.ID()) {
|
|
96
|
-
if (ctx.trailer_expr_list().length > 0) {
|
|
97
|
-
this.addSemanticToken(this.parseToken(ctx.ID(), ['declaration'], 'function'));
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
this.addSemanticToken(this.parseToken(ctx.ID(), ['declaration'], 'variable'));
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
else if (ctx instanceof Property_key_exprContext) {
|
|
105
|
-
let useToken = null;
|
|
106
|
-
if (ctx.ID()) {
|
|
107
|
-
useToken = ctx.ID();
|
|
108
|
-
}
|
|
109
|
-
else if (ctx.INTEGER_VALUE()) {
|
|
110
|
-
useToken = ctx.INTEGER_VALUE();
|
|
111
|
-
}
|
|
112
|
-
else if (ctx.STRING_VALUE()) {
|
|
113
|
-
useToken = ctx.STRING_VALUE();
|
|
114
|
-
}
|
|
115
|
-
useToken && this.addSemanticToken(this.parseToken(useToken, ['declaration'], 'property'));
|
|
116
|
-
}
|
|
117
|
-
else if (ctx instanceof Sub_exprContext) {
|
|
118
|
-
let useToken = null;
|
|
119
|
-
if (ctx.ID()) {
|
|
120
|
-
useToken = ctx.ID();
|
|
121
|
-
}
|
|
122
|
-
else if (ctx.Pin()) {
|
|
123
|
-
useToken = ctx.Pin();
|
|
124
|
-
}
|
|
125
|
-
useToken && this.addSemanticToken(this.parseToken(useToken, ['defaultLibrary'], 'function'));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
addSemanticToken(parsedToken) {
|
|
129
|
-
this.semanticTokens.set(parsedToken.line + "_" + parsedToken.column, parsedToken);
|
|
39
|
+
}
|
|
40
|
+
export class CircuitscriptParserErrorListener {
|
|
41
|
+
syntaxErrorCounter = 0;
|
|
42
|
+
onErrorHandler = null;
|
|
43
|
+
constructor(onErrorHandler = null) {
|
|
44
|
+
this.onErrorHandler = onErrorHandler;
|
|
130
45
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let textPart = "";
|
|
135
|
-
if (this.lexer.symbolicNames[token.type] !== null && this.lexer.symbolicNames[token.type] !== undefined) {
|
|
136
|
-
stringValue = this.lexer.symbolicNames[token.type];
|
|
137
|
-
if (stringValue !== "NEWLINE") {
|
|
138
|
-
textPart = this.script.substring(token.start, token.stop + 1);
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
textPart = token.text.length - 1;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
else if (this.lexer.literalNames[token.type] !== null && this.lexer.literalNames[token.type] !== undefined) {
|
|
145
|
-
stringValue = this.lexer.literalNames[token.type];
|
|
146
|
-
textPart = this.script.substring(token.start, token.stop + 1);
|
|
46
|
+
syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
|
|
47
|
+
if (this.onErrorHandler) {
|
|
48
|
+
this.onErrorHandler(line, charPositionInLine, msg, e);
|
|
147
49
|
}
|
|
148
50
|
else {
|
|
149
|
-
|
|
51
|
+
console.log("Syntax error at line", line, ':', charPositionInLine, ' - ', msg);
|
|
150
52
|
}
|
|
151
|
-
|
|
152
|
-
line: token.line,
|
|
153
|
-
column: token.column,
|
|
154
|
-
length: token.stop - token.start + 1,
|
|
155
|
-
tokenType: tokenType !== null ? tokenType : stringValue,
|
|
156
|
-
tokenModifiers: modifiers,
|
|
157
|
-
textValue: textPart,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
function prepareTokens(tokens, lexer, script) {
|
|
162
|
-
const parsedTokens = [];
|
|
163
|
-
tokens.forEach(item => {
|
|
164
|
-
if (item.type !== -1) {
|
|
165
|
-
let stringValue = "";
|
|
166
|
-
let textPart = "";
|
|
167
|
-
if (lexer.symbolicNames[item.type] !== null && lexer.symbolicNames[item.type] !== undefined) {
|
|
168
|
-
stringValue = lexer.symbolicNames[item.type];
|
|
169
|
-
if (stringValue !== "NEWLINE") {
|
|
170
|
-
textPart = script.substring(item.start, item.stop + 1);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
textPart = item.text.length - 1;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else if (lexer.literalNames[item.type] !== null && lexer.literalNames[item.type] !== undefined) {
|
|
177
|
-
stringValue = lexer.literalNames[item.type];
|
|
178
|
-
textPart = script.substring(item.start, item.stop + 1);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
stringValue = item._text;
|
|
182
|
-
}
|
|
183
|
-
if (textPart !== 0 && textPart !== '') {
|
|
184
|
-
parsedTokens.push({
|
|
185
|
-
line: item.line,
|
|
186
|
-
column: item.column,
|
|
187
|
-
length: item.stop - item.start + 1,
|
|
188
|
-
tokenType: resolveTokenType(stringValue),
|
|
189
|
-
tokenModifiers: resolveTokenModifiers(stringValue),
|
|
190
|
-
textValue: textPart,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
return parsedTokens;
|
|
196
|
-
}
|
|
197
|
-
const languageKeywords = [
|
|
198
|
-
'break', 'branch', 'create', 'component',
|
|
199
|
-
'graphic', 'wire', 'pin', 'add', 'at', 'to',
|
|
200
|
-
'point', 'join', 'parallel', 'return', 'def', 'import',
|
|
201
|
-
'true', 'false', 'nc', 'frame',
|
|
202
|
-
];
|
|
203
|
-
const operatorKeywords = [
|
|
204
|
-
'at', 'to', 'wire', 'add', 'frame', 'join', 'parallel', 'point'
|
|
205
|
-
];
|
|
206
|
-
function resolveTokenType(tokenType) {
|
|
207
|
-
if (operatorKeywords.indexOf(tokenType.toLowerCase()) !== -1) {
|
|
208
|
-
return 'graphKeyword';
|
|
53
|
+
this.syntaxErrorCounter++;
|
|
209
54
|
}
|
|
210
|
-
|
|
211
|
-
return 'keyword';
|
|
55
|
+
reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) {
|
|
212
56
|
}
|
|
213
|
-
|
|
214
|
-
switch (tokenType) {
|
|
215
|
-
case 'INTEGER_VALUE':
|
|
216
|
-
case 'NUMERIC_VALUE':
|
|
217
|
-
case 'DECIMAL_VALUE':
|
|
218
|
-
case 'PERCENTAGE_VALUE':
|
|
219
|
-
return 'number';
|
|
220
|
-
case 'STRING_VALUE':
|
|
221
|
-
return 'string';
|
|
222
|
-
case 'ID':
|
|
223
|
-
return 'variable';
|
|
224
|
-
case 'Define':
|
|
225
|
-
return 'keyword';
|
|
226
|
-
case 'COMMENT':
|
|
227
|
-
return 'comment';
|
|
228
|
-
}
|
|
229
|
-
return null;
|
|
57
|
+
reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
|
|
230
58
|
}
|
|
231
|
-
|
|
232
|
-
function resolveTokenModifiers(tokenType) {
|
|
233
|
-
return [];
|
|
234
|
-
}
|
|
235
|
-
function dumpTokens(tokens, lexer, scriptData) {
|
|
236
|
-
tokens.forEach(item => {
|
|
237
|
-
if (item.type !== -1) {
|
|
238
|
-
let stringValue = "";
|
|
239
|
-
let textPart = "";
|
|
240
|
-
if (lexer.symbolicNames[item.type] !== null && lexer.symbolicNames[item.type] !== undefined) {
|
|
241
|
-
stringValue = lexer.symbolicNames[item.type];
|
|
242
|
-
if (stringValue !== "NEWLINE") {
|
|
243
|
-
textPart = scriptData.substring(item.start, item.stop + 1);
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
textPart = item.text.length - 1;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
else if (lexer.literalNames[item.type] !== null && lexer.literalNames[item.type] !== undefined) {
|
|
250
|
-
stringValue = lexer.literalNames[item.type];
|
|
251
|
-
textPart = scriptData.substring(item.start, item.stop + 1);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
stringValue = item._text;
|
|
255
|
-
}
|
|
256
|
-
console.log('line', item.line + ':' + item.column, `\t${stringValue} (${item.type})`.padEnd(30), textPart);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
export class CircuitscriptParserErrorListener extends ErrorListener {
|
|
261
|
-
syntaxErrorCounter = 0;
|
|
262
|
-
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
|
263
|
-
console.log("Syntax error at line", line, ':', column, ' - ', msg);
|
|
264
|
-
this.syntaxErrorCounter++;
|
|
59
|
+
reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs) {
|
|
265
60
|
}
|
|
266
|
-
|
|
61
|
+
hasSyntaxErrors() {
|
|
267
62
|
return (this.syntaxErrorCounter > 0);
|
|
268
63
|
}
|
|
269
64
|
}
|