circuitscript 0.3.1 → 0.4.0
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 +394 -262
- package/dist/cjs/LexerDiagnosticListener.js +375 -0
- package/dist/cjs/{ComponentAnnotater.js → annotate/ComponentAnnotater.js} +29 -15
- package/dist/cjs/annotate/DefaultPostAnnotationCallback.js +126 -0
- package/dist/cjs/{RefdesAnnotationVisitor.js → annotate/RefdesAnnotationVisitor.js} +10 -84
- package/dist/cjs/annotate/utils.js +70 -0
- package/dist/cjs/antlr/CircuitScriptLexer.js +279 -286
- package/dist/cjs/antlr/CircuitScriptParser.js +1954 -3535
- package/dist/cjs/antlr/CircuitScriptParserVisitor.js +7 -0
- package/dist/cjs/cache/deserializer.js +34 -0
- package/dist/cjs/cache/hash.js +8 -0
- package/dist/cjs/cache/serializer.js +122 -0
- package/dist/cjs/cache/storage.js +45 -0
- package/dist/cjs/cache/types.js +4 -0
- package/dist/cjs/{environment.js → environment/environment.js} +18 -6
- package/dist/cjs/environment/esm-environment.js +21 -0
- package/dist/cjs/environment/helpers.js +8 -0
- package/dist/cjs/execute.js +49 -15
- package/dist/cjs/globals.js +9 -1
- package/dist/cjs/helpers.js +3 -467
- package/dist/cjs/importResolver.js +102 -0
- package/dist/cjs/index.js +7 -6
- package/dist/cjs/lexer.js +48 -12
- package/dist/cjs/main.js +14 -4
- package/dist/cjs/objects/ClassComponent.js +1 -1
- package/dist/cjs/objects/ExecutionScope.js +0 -1
- package/dist/cjs/objects/types.js +17 -1
- package/dist/cjs/parser.js +18 -4
- package/dist/cjs/pipeline.js +284 -0
- package/dist/cjs/regenerate-tests.js +4 -3
- package/dist/cjs/render/KiCadNetListOutputHandler.js +30 -0
- package/dist/cjs/render/PaperSizes.js +46 -0
- package/dist/cjs/{draw_symbols.js → render/draw_symbols.js} +58 -36
- package/dist/cjs/{export.js → render/export.js} +2 -2
- package/dist/cjs/{geometry.js → render/geometry.js} +5 -5
- package/dist/cjs/{graph.js → render/graph.js} +7 -7
- package/dist/cjs/{layout.js → render/layout.js} +8 -8
- package/dist/cjs/{render.js → render/render.js} +9 -8
- package/dist/cjs/rules-check/no-connect-on-connected-pin.js +1 -1
- package/dist/cjs/rules-check/unconnected-pins.js +1 -1
- package/dist/cjs/{SemanticTokenVisitor.js → semantic-tokens/SemanticTokenVisitor.js} +12 -14
- package/dist/cjs/semantic-tokens/getSemanticTokens.js +55 -0
- package/dist/cjs/sizing.js +2 -2
- package/dist/cjs/utils.js +2 -2
- package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +6 -0
- package/dist/cjs/validate/SymbolValidatorVisitor.js +34 -39
- package/dist/cjs/validate/validateScript.js +54 -0
- package/dist/cjs/validate.js +5 -4
- package/dist/cjs/visitor.js +158 -212
- package/dist/esm/BaseVisitor.js +396 -264
- package/dist/esm/LexerDiagnosticListener.js +371 -0
- package/dist/esm/{ComponentAnnotater.js → annotate/ComponentAnnotater.js} +29 -15
- package/dist/esm/annotate/DefaultPostAnnotationCallback.js +122 -0
- package/dist/esm/{RefdesAnnotationVisitor.js → annotate/RefdesAnnotationVisitor.js} +10 -84
- package/dist/esm/annotate/utils.js +66 -0
- package/dist/esm/antlr/CircuitScriptLexer.js +279 -286
- package/dist/esm/antlr/CircuitScriptParser.js +1962 -3522
- package/dist/esm/antlr/{CircuitScriptVisitor.js → CircuitScriptParserVisitor.js} +14 -35
- package/dist/esm/cache/deserializer.js +30 -0
- package/dist/esm/cache/hash.js +4 -0
- package/dist/esm/cache/serializer.js +118 -0
- package/dist/esm/cache/storage.js +39 -0
- package/dist/esm/cache/types.js +1 -0
- package/dist/esm/{environment.js → environment/environment.js} +18 -6
- package/dist/esm/environment/esm-environment.js +17 -0
- package/dist/esm/environment/helpers.js +4 -0
- package/dist/esm/execute.js +49 -15
- package/dist/esm/globals.js +8 -0
- package/dist/esm/helpers.js +5 -456
- package/dist/esm/importResolver.js +96 -0
- package/dist/esm/index.js +7 -6
- package/dist/esm/lexer.js +51 -12
- package/dist/esm/main.js +13 -3
- package/dist/esm/objects/ClassComponent.js +1 -1
- package/dist/esm/objects/ExecutionScope.js +0 -1
- package/dist/esm/objects/types.js +21 -1
- package/dist/esm/parser.js +19 -5
- package/dist/esm/pipeline.js +276 -0
- package/dist/esm/regenerate-tests.js +3 -2
- package/dist/esm/render/KiCadNetListOutputHandler.js +20 -0
- package/dist/esm/render/PaperSizes.js +41 -0
- package/dist/esm/{draw_symbols.js → render/draw_symbols.js} +58 -36
- package/dist/esm/{export.js → render/export.js} +2 -2
- package/dist/esm/{geometry.js → render/geometry.js} +5 -5
- package/dist/esm/{graph.js → render/graph.js} +7 -7
- package/dist/esm/{layout.js → render/layout.js} +8 -8
- package/dist/esm/{render.js → render/render.js} +8 -7
- package/dist/esm/rules-check/no-connect-on-connected-pin.js +1 -1
- package/dist/esm/rules-check/unconnected-pins.js +1 -1
- package/dist/esm/{SemanticTokenVisitor.js → semantic-tokens/SemanticTokenVisitor.js} +12 -14
- package/dist/esm/semantic-tokens/getSemanticTokens.js +51 -0
- package/dist/esm/sizing.js +2 -2
- package/dist/esm/utils.js +2 -2
- package/dist/esm/validate/SymbolValidatorResolveVisitor.js +3 -0
- package/dist/esm/validate/SymbolValidatorVisitor.js +36 -41
- package/dist/esm/validate/validateScript.js +50 -0
- package/dist/esm/validate.js +4 -3
- package/dist/esm/visitor.js +160 -214
- package/dist/libs/std.cst +15 -19
- package/dist/types/BaseVisitor.d.ts +25 -18
- package/dist/types/BomGeneration.d.ts +1 -1
- package/dist/types/LexerDiagnosticListener.d.ts +85 -0
- package/dist/types/{ComponentAnnotater.d.ts → annotate/ComponentAnnotater.d.ts} +1 -1
- package/dist/types/annotate/DefaultPostAnnotationCallback.d.ts +7 -0
- package/dist/types/{RefdesAnnotationVisitor.d.ts → annotate/RefdesAnnotationVisitor.d.ts} +7 -9
- package/dist/types/annotate/utils.d.ts +6 -0
- package/dist/types/antlr/CircuitScriptLexer.d.ts +71 -70
- package/dist/types/antlr/CircuitScriptParser.d.ts +357 -515
- package/dist/types/antlr/{CircuitScriptVisitor.d.ts → CircuitScriptParserVisitor.d.ts} +27 -69
- package/dist/types/cache/deserializer.d.ts +5 -0
- package/dist/types/cache/hash.d.ts +1 -0
- package/dist/types/cache/serializer.d.ts +3 -0
- package/dist/types/cache/storage.d.ts +4 -0
- package/dist/types/cache/types.d.ts +20 -0
- package/dist/types/{environment.d.ts → environment/environment.d.ts} +5 -4
- package/dist/types/environment/esm-environment.d.ts +4 -0
- package/dist/types/environment/helpers.d.ts +2 -0
- package/dist/types/execute.d.ts +3 -2
- package/dist/types/globals.d.ts +1 -0
- package/dist/types/helpers.d.ts +31 -36
- package/dist/types/importResolver.d.ts +4 -0
- package/dist/types/index.d.ts +7 -6
- package/dist/types/lexer.d.ts +9 -5
- package/dist/types/objects/ClassComponent.d.ts +1 -1
- package/dist/types/objects/ExecutionScope.d.ts +1 -4
- package/dist/types/objects/types.d.ts +16 -2
- package/dist/types/parser.d.ts +9 -2
- package/dist/types/pipeline.d.ts +9 -0
- package/dist/types/render/KiCadNetListOutputHandler.d.ts +10 -0
- package/dist/types/render/PaperSizes.d.ts +12 -0
- package/dist/types/{draw_symbols.d.ts → render/draw_symbols.d.ts} +4 -4
- package/dist/types/{export.d.ts → render/export.d.ts} +1 -1
- package/dist/types/{geometry.d.ts → render/geometry.d.ts} +2 -2
- package/dist/types/{graph.d.ts → render/graph.d.ts} +6 -6
- package/dist/types/{layout.d.ts → render/layout.d.ts} +10 -10
- package/dist/types/{render.d.ts → render/render.d.ts} +1 -1
- package/dist/types/{SemanticTokenVisitor.d.ts → semantic-tokens/SemanticTokenVisitor.d.ts} +6 -6
- package/dist/types/semantic-tokens/getSemanticTokens.d.ts +6 -0
- package/dist/types/sizing.d.ts +1 -1
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +3 -0
- package/dist/types/validate/SymbolValidatorVisitor.d.ts +8 -8
- package/dist/types/validate/validateScript.d.ts +3 -0
- package/dist/types/visitor.d.ts +8 -14
- package/libs/std.cst +15 -19
- package/package.json +3 -6
- package/dist/cjs/antlr/CircuitScriptVisitor.js +0 -7
package/dist/esm/lexer.js
CHANGED
|
@@ -1,31 +1,46 @@
|
|
|
1
1
|
import { CommonToken } from "antlr4ng";
|
|
2
2
|
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.js";
|
|
3
3
|
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.js";
|
|
4
|
+
import { LexerDiagnosticCollector } from "./LexerDiagnosticListener.js";
|
|
4
5
|
export class MainLexer extends CircuitScriptLexer {
|
|
5
6
|
tokens;
|
|
7
|
+
tokensHead;
|
|
6
8
|
indents;
|
|
7
9
|
opened;
|
|
8
|
-
|
|
10
|
+
diagnosticCollector;
|
|
11
|
+
lineOffset;
|
|
12
|
+
constructor(input, enableDiagnostics = false) {
|
|
9
13
|
super(input);
|
|
10
14
|
this.tokens = [];
|
|
15
|
+
this.tokensHead = 0;
|
|
11
16
|
this.indents = [];
|
|
12
17
|
this.opened = 0;
|
|
18
|
+
this.lineOffset = 0;
|
|
19
|
+
this.diagnosticCollector = new LexerDiagnosticCollector();
|
|
20
|
+
this.diagnosticCollector.setEnabled(enableDiagnostics);
|
|
13
21
|
}
|
|
14
22
|
reset() {
|
|
15
23
|
this.tokens = [];
|
|
24
|
+
this.tokensHead = 0;
|
|
16
25
|
this.indents = [];
|
|
17
26
|
this.opened = 0;
|
|
18
27
|
super.reset();
|
|
19
28
|
}
|
|
20
29
|
emitToken(token) {
|
|
30
|
+
this.diagnosticCollector.onTokenStart();
|
|
21
31
|
super.emitToken(token);
|
|
22
32
|
this.tokens.push(token);
|
|
33
|
+
this.diagnosticCollector.onTokenGenerated(token, this.tokens.length - this.tokensHead);
|
|
23
34
|
}
|
|
24
35
|
nextToken() {
|
|
25
36
|
if (this.inputStream.LA(1) === CircuitScriptParser.EOF && this.indents.length) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
let writeIdx = this.tokensHead;
|
|
38
|
+
for (let i = this.tokensHead; i < this.tokens.length; i++) {
|
|
39
|
+
if (this.tokens[i].type !== CircuitScriptParser.EOF) {
|
|
40
|
+
this.tokens[writeIdx++] = this.tokens[i];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
this.tokens.length = writeIdx;
|
|
29
44
|
const fillerNewLine = this.commonToken(CircuitScriptParser.NEWLINE, "");
|
|
30
45
|
this.emitToken(fillerNewLine);
|
|
31
46
|
fillerNewLine.__skip = true;
|
|
@@ -36,7 +51,19 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
36
51
|
this.emitToken(this.commonToken(CircuitScriptParser.EOF, ""));
|
|
37
52
|
}
|
|
38
53
|
const next = super.nextToken();
|
|
39
|
-
|
|
54
|
+
let returnToken;
|
|
55
|
+
if (this.tokensHead < this.tokens.length) {
|
|
56
|
+
returnToken = this.tokens[this.tokensHead++];
|
|
57
|
+
if (this.tokensHead > 64) {
|
|
58
|
+
this.tokens = this.tokens.slice(this.tokensHead);
|
|
59
|
+
this.tokensHead = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
returnToken = next;
|
|
64
|
+
}
|
|
65
|
+
returnToken.line += this.lineOffset;
|
|
66
|
+
return returnToken;
|
|
40
67
|
}
|
|
41
68
|
createDedent() {
|
|
42
69
|
return this.commonToken(CircuitScriptParser.DEDENT, "");
|
|
@@ -80,9 +107,6 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
80
107
|
}
|
|
81
108
|
return count;
|
|
82
109
|
}
|
|
83
|
-
atStartOfInput() {
|
|
84
|
-
return this.getCharIndex() === 0;
|
|
85
|
-
}
|
|
86
110
|
openBrace() {
|
|
87
111
|
this.opened++;
|
|
88
112
|
}
|
|
@@ -90,8 +114,19 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
90
114
|
this.opened--;
|
|
91
115
|
}
|
|
92
116
|
onNewLine() {
|
|
93
|
-
const
|
|
94
|
-
|
|
117
|
+
const text = this.text;
|
|
118
|
+
let nlLen = 0;
|
|
119
|
+
while (nlLen < text.length) {
|
|
120
|
+
const c = text.charCodeAt(nlLen);
|
|
121
|
+
if (c === 13 || c === 10 || c === 12) {
|
|
122
|
+
nlLen++;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const newLine = text.substring(0, nlLen);
|
|
129
|
+
const spaces = text.substring(nlLen);
|
|
95
130
|
const next = this.inputStream.LA(1);
|
|
96
131
|
const nextnext = this.inputStream.LA(2);
|
|
97
132
|
if (this.opened > 0 || (nextnext != -1 &&
|
|
@@ -99,8 +134,9 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
99
134
|
this.skip();
|
|
100
135
|
}
|
|
101
136
|
else {
|
|
102
|
-
const
|
|
103
|
-
const
|
|
137
|
+
const charIndex = this.getCharIndex();
|
|
138
|
+
const start = charIndex - this.text.length;
|
|
139
|
+
const stop = charIndex - 1;
|
|
104
140
|
this.emitToken(this.commonToken(CircuitScriptParser.NEWLINE, newLine, start, start));
|
|
105
141
|
const indent = this.getIndentationCount(spaces);
|
|
106
142
|
const previous = this.indents.length ? this.indents[this.indents.length - 1] : 0;
|
|
@@ -119,4 +155,7 @@ export class MainLexer extends CircuitScriptLexer {
|
|
|
119
155
|
}
|
|
120
156
|
}
|
|
121
157
|
}
|
|
158
|
+
setLineOffset(offset) {
|
|
159
|
+
this.lineOffset = offset;
|
|
160
|
+
}
|
|
122
161
|
}
|
package/dist/esm/main.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import figlet from 'figlet';
|
|
4
4
|
import { watch } from 'fs';
|
|
5
|
-
import { renderScript } from
|
|
6
|
-
import { NodeScriptEnvironment } from "./environment.js";
|
|
5
|
+
import { renderScript } from "./pipeline.js";
|
|
6
|
+
import { NodeScriptEnvironment } from "./environment/environment.js";
|
|
7
7
|
export default async function main() {
|
|
8
8
|
const env = new NodeScriptEnvironment();
|
|
9
9
|
NodeScriptEnvironment.setInstance(env);
|
|
@@ -22,7 +22,12 @@ export default async function main() {
|
|
|
22
22
|
.option('-s, --stats', 'Show stats during generation')
|
|
23
23
|
.option('-x, --skip-output', 'Skip output generation')
|
|
24
24
|
.option('-e, --erc', 'Enable ERC output')
|
|
25
|
-
.option('-b, --bom [output-path]', 'Generate Bill of Materials in csv format')
|
|
25
|
+
.option('-b, --bom [output-path]', 'Generate Bill of Materials in csv format')
|
|
26
|
+
.option('-l, --lexer-diagnostics', 'Enable lexer performance diagnostics')
|
|
27
|
+
.option('--lexer-verbose', 'Log each token as it is generated (requires -l)')
|
|
28
|
+
.option('--lexer-tokens [limit]', 'Print token stream (optionally limit number of tokens, requires -l)')
|
|
29
|
+
.option('--lexer-mapping [lines]', 'Print character-to-token mapping (optionally specify line range like "1-10", requires -l)')
|
|
30
|
+
.option('--lexer-summary', 'Print lexer operation summary (requires -l)');
|
|
26
31
|
program.addHelpText('before', figlet.textSync('circuitscript', {
|
|
27
32
|
font: 'Small Slant'
|
|
28
33
|
}));
|
|
@@ -87,6 +92,11 @@ export default async function main() {
|
|
|
87
92
|
enableBom,
|
|
88
93
|
bomOutputPath,
|
|
89
94
|
environment: env,
|
|
95
|
+
lexerDiagnostics: options.lexerDiagnostics,
|
|
96
|
+
lexerVerbose: options.lexerVerbose,
|
|
97
|
+
lexerTokens: options.lexerTokens,
|
|
98
|
+
lexerMapping: options.lexerMapping,
|
|
99
|
+
lexerSummary: options.lexerSummary,
|
|
90
100
|
inputPath: inputFilePath,
|
|
91
101
|
updateSource,
|
|
92
102
|
saveAnnotatedCopy: saveAnnotatedCopyPath,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SymbolDrawingCommands } from '../draw_symbols.js';
|
|
1
|
+
import { SymbolDrawingCommands } from '../render/draw_symbols.js';
|
|
2
2
|
import { PinDefinition, PinId, PinIdType } from './PinDefinition.js';
|
|
3
3
|
import { PinTypes } from './PinTypes.js';
|
|
4
4
|
import { DefaultComponentUnit, ParamKeys } from '../globals.js';
|
|
@@ -7,6 +7,10 @@ export class CFunctionEntry {
|
|
|
7
7
|
execute;
|
|
8
8
|
uniqueId;
|
|
9
9
|
source;
|
|
10
|
+
lazyLoaded = false;
|
|
11
|
+
lazyLoader = null;
|
|
12
|
+
tokens;
|
|
13
|
+
tree;
|
|
10
14
|
constructor(namespace, name, execute, source, uniqueId) {
|
|
11
15
|
this.name = name;
|
|
12
16
|
this.namespace = namespace;
|
|
@@ -18,6 +22,9 @@ export class CFunctionEntry {
|
|
|
18
22
|
toString() {
|
|
19
23
|
return `[Function: ${this.name}]`;
|
|
20
24
|
}
|
|
25
|
+
getFunctionPath() {
|
|
26
|
+
return `${this.namespace}${this.name}`;
|
|
27
|
+
}
|
|
21
28
|
}
|
|
22
29
|
;
|
|
23
30
|
export class AnyReference {
|
|
@@ -128,7 +135,13 @@ export class ImportedLibrary {
|
|
|
128
135
|
enableRefdesAnnotationFile = false;
|
|
129
136
|
tree;
|
|
130
137
|
tokens;
|
|
131
|
-
|
|
138
|
+
referencedTokens = [];
|
|
139
|
+
fileHash;
|
|
140
|
+
writeToCache = false;
|
|
141
|
+
refdesAnnotations = new Map;
|
|
142
|
+
parseError = false;
|
|
143
|
+
importStatement;
|
|
144
|
+
constructor(libraryName, libraryNamespace, libraryFilePath, tree, tokens, context, flag, specifiedImports, fileHash, importStatement) {
|
|
132
145
|
this.libraryName = libraryName;
|
|
133
146
|
this.libraryNamespace = libraryNamespace;
|
|
134
147
|
this.libraryFilePath = libraryFilePath;
|
|
@@ -137,6 +150,13 @@ export class ImportedLibrary {
|
|
|
137
150
|
this.context = context;
|
|
138
151
|
this.importHandlingFlag = flag;
|
|
139
152
|
this.specifiedImports = specifiedImports;
|
|
153
|
+
this.fileHash = fileHash;
|
|
154
|
+
this.importStatement = importStatement;
|
|
155
|
+
}
|
|
156
|
+
addRefdesModifications(mods) {
|
|
157
|
+
for (const [ctx, modification] of mods) {
|
|
158
|
+
this.refdesAnnotations.set(ctx, modification);
|
|
159
|
+
}
|
|
140
160
|
}
|
|
141
161
|
}
|
|
142
162
|
export var ImportFunctionHandling;
|
package/dist/esm/parser.js
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
import { CircuitScriptParser } from './antlr/CircuitScriptParser.js';
|
|
2
2
|
import { MainLexer } from './lexer.js';
|
|
3
3
|
import { ParseSyntaxError, RuntimeExecutionError, SimpleStopwatch } from './utils.js';
|
|
4
|
-
import { CharStream, CommonTokenStream } from 'antlr4ng';
|
|
5
|
-
export
|
|
4
|
+
import { CharStream, CommonTokenStream, PredictionMode } from 'antlr4ng';
|
|
5
|
+
export function parseFileWithVisitor(visitor, data, options) {
|
|
6
6
|
const lexerErrorListener = new CircuitscriptParserErrorListener(visitor.onErrorHandler);
|
|
7
7
|
const parserErrorListener = new CircuitscriptParserErrorListener(visitor.onErrorHandler);
|
|
8
8
|
const chars = CharStream.fromString(data);
|
|
9
|
-
const
|
|
9
|
+
const enableDiagnostics = options?.enableLexerDiagnostics ?? false;
|
|
10
|
+
const enableVerbose = options?.enableLexerVerbose ?? false;
|
|
11
|
+
const enableTokenStream = options?.enableLexerTokenStream ?? false;
|
|
12
|
+
const lineOffset = options?.lineOffset ?? 0;
|
|
13
|
+
const lexer = new MainLexer(chars, enableDiagnostics);
|
|
14
|
+
lexer.setLineOffset(lineOffset);
|
|
15
|
+
if (enableDiagnostics) {
|
|
16
|
+
lexer.diagnosticCollector.setSourceText(data);
|
|
17
|
+
lexer.diagnosticCollector.setVerboseLogging(enableVerbose);
|
|
18
|
+
if (enableTokenStream) {
|
|
19
|
+
lexer.diagnosticCollector.setRecordTokenStream(true);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
10
22
|
lexer.removeErrorListeners();
|
|
11
23
|
lexer.addErrorListener(lexerErrorListener);
|
|
12
24
|
const lexerTimer = new SimpleStopwatch();
|
|
13
25
|
const tokens = new CommonTokenStream(lexer);
|
|
14
26
|
tokens.fill();
|
|
15
27
|
const lexerTimeTaken = lexerTimer.lap();
|
|
16
|
-
const parserTimer = new SimpleStopwatch();
|
|
17
28
|
const parser = new CircuitScriptParser(tokens);
|
|
29
|
+
parser.interpreter.predictionMode = PredictionMode.SLL;
|
|
18
30
|
parser.removeErrorListeners();
|
|
19
31
|
parser.addErrorListener(parserErrorListener);
|
|
32
|
+
const parserTimer = new SimpleStopwatch();
|
|
20
33
|
const tree = parser.script();
|
|
21
34
|
let throwError;
|
|
22
35
|
let hasError = false;
|
|
23
36
|
let hasParseError = false;
|
|
24
37
|
try {
|
|
25
|
-
|
|
38
|
+
visitor.visit(tree);
|
|
26
39
|
}
|
|
27
40
|
catch (error) {
|
|
28
41
|
if (visitor.onErrorHandler) {
|
|
@@ -40,6 +53,7 @@ export async function parseFileWithVisitor(visitor, data) {
|
|
|
40
53
|
return {
|
|
41
54
|
tree, parser,
|
|
42
55
|
tokens,
|
|
56
|
+
lexer,
|
|
43
57
|
hasParseError,
|
|
44
58
|
hasError,
|
|
45
59
|
parserTimeTaken,
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import PDFDocument from "pdfkit";
|
|
3
|
+
import { RecognitionException } from "antlr4ng";
|
|
4
|
+
import { DefaultPostAnnotationCallback } from "./annotate/DefaultPostAnnotationCallback.js";
|
|
5
|
+
import { generateBom, generateBomCSV, saveBomOutputCsv } from "./BomGeneration.js";
|
|
6
|
+
import { defaultZoomScale } from "./globals.js";
|
|
7
|
+
import { NetGraph } from "./render/graph.js";
|
|
8
|
+
import { LayoutEngine } from "./render/layout.js";
|
|
9
|
+
import { Logger } from "./logger.js";
|
|
10
|
+
import { FrameParamKeys } from "./objects/Frame.js";
|
|
11
|
+
import { parseFileWithVisitor } from "./parser.js";
|
|
12
|
+
import { KiCadNetListOutputHandler } from "./render/KiCadNetListOutputHandler.js";
|
|
13
|
+
import { renderSheetsToSVG, generateSvgOutput, generatePdfOutput } from "./render/render.js";
|
|
14
|
+
import { EvaluateERCRules } from "./rules-check/rules.js";
|
|
15
|
+
import { RuntimeExecutionError, ParseSyntaxError, ParseError, printWarnings, RenderError, generateDebugSequenceAction, sequenceActionString, SimpleStopwatch } from "./utils.js";
|
|
16
|
+
import { ParserVisitor } from "./visitor.js";
|
|
17
|
+
export async function renderScript(scriptData, outputPath, options) {
|
|
18
|
+
const parseHandlers = [
|
|
19
|
+
new KiCadNetListOutputHandler(),
|
|
20
|
+
];
|
|
21
|
+
return renderScriptCustom(scriptData, outputPath, options, parseHandlers, [DefaultPostAnnotationCallback]);
|
|
22
|
+
}
|
|
23
|
+
export async function renderScriptCustom(scriptData, outputPath, options, parseHandlers, postAnnotationCallbacks) {
|
|
24
|
+
const { dumpNets = false, dumpData = false, showStats = false, enableErc = false, enableBom = false, lexerDiagnostics = false, lexerVerbose = false, lexerTokens = false, lexerMapping = false, lexerSummary = false, inputPath = '', bomOutputPath = undefined, environment } = options;
|
|
25
|
+
const errors = [];
|
|
26
|
+
const onErrorHandler = (message, context, error) => {
|
|
27
|
+
if (error && error instanceof RuntimeExecutionError) {
|
|
28
|
+
errors.push(error);
|
|
29
|
+
}
|
|
30
|
+
else if (error && error instanceof RecognitionException) {
|
|
31
|
+
if (context !== null) {
|
|
32
|
+
errors.push(new ParseSyntaxError(message, context.start, context.stop));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
if (error.recognizer) {
|
|
36
|
+
const recognizer = error.recognizer;
|
|
37
|
+
errors.push(new ParseSyntaxError(message, {
|
|
38
|
+
line: recognizer.currentTokenStartLine,
|
|
39
|
+
column: recognizer.currentTokenColumn
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
errors.push(new ParseSyntaxError(message));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
errors.push(new ParseError(message, context.start, context.stop));
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const visitor = new ParserVisitor(true, onErrorHandler, environment);
|
|
52
|
+
environment.setCurrentFile(inputPath);
|
|
53
|
+
visitor.log(`current file: ${inputPath}`);
|
|
54
|
+
visitor.onImportFile = (visitor, filePath, fileData, errorHandler, fileLineOffset = 0) => {
|
|
55
|
+
visitor.enterFile(filePath);
|
|
56
|
+
errors.splice(0, errors.length);
|
|
57
|
+
const result = parseFileWithVisitor(visitor, fileData, {
|
|
58
|
+
enableLexerDiagnostics: lexerDiagnostics,
|
|
59
|
+
enableLexerVerbose: lexerVerbose,
|
|
60
|
+
lineOffset: fileLineOffset,
|
|
61
|
+
});
|
|
62
|
+
const { throwError, tree, tokens } = result;
|
|
63
|
+
let { hasError, hasParseError } = result;
|
|
64
|
+
if (errors.length > 0) {
|
|
65
|
+
hasError = true;
|
|
66
|
+
hasParseError = true;
|
|
67
|
+
}
|
|
68
|
+
visitor.exitFile();
|
|
69
|
+
if (hasError || hasParseError) {
|
|
70
|
+
let importErrorMsg = "";
|
|
71
|
+
if (throwError) {
|
|
72
|
+
importErrorMsg = ": " + throwError.message;
|
|
73
|
+
}
|
|
74
|
+
throw new ParseError(`Error parsing imported file: ${filePath}${importErrorMsg}`, undefined, undefined, filePath);
|
|
75
|
+
}
|
|
76
|
+
return { hasError, hasParseError, tree, tokens };
|
|
77
|
+
};
|
|
78
|
+
const dumpDirectory = environment.getRelativeToModule('/dump/');
|
|
79
|
+
if (dumpData) {
|
|
80
|
+
console.log('Dump data to:', dumpDirectory);
|
|
81
|
+
if (!environment.existsSync(dumpDirectory)) {
|
|
82
|
+
environment.mkdirSync(dumpDirectory);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (inputPath !== '') {
|
|
86
|
+
visitor.enterFile(inputPath);
|
|
87
|
+
}
|
|
88
|
+
await visitor.resolveImportsAndLoad(inputPath, scriptData);
|
|
89
|
+
const { tree, parser, tokens, lexer, parserTimeTaken, lexerTimeTaken, throwError } = await parseFileWithVisitor(visitor, scriptData, {
|
|
90
|
+
enableLexerDiagnostics: lexerDiagnostics,
|
|
91
|
+
enableLexerVerbose: lexerVerbose,
|
|
92
|
+
enableLexerTokenStream: lexerTokens !== false || lexerMapping !== false,
|
|
93
|
+
});
|
|
94
|
+
printWarnings(visitor.getWarnings());
|
|
95
|
+
showStats && console.log('Lexing took:', lexerTimeTaken);
|
|
96
|
+
showStats && console.log('Parsing took:', parserTimeTaken);
|
|
97
|
+
if (lexerDiagnostics && lexer.diagnosticCollector) {
|
|
98
|
+
console.log('\n');
|
|
99
|
+
if (lexerSummary) {
|
|
100
|
+
lexer.diagnosticCollector.printLexerOperationSummary();
|
|
101
|
+
}
|
|
102
|
+
if (lexerTokens !== false) {
|
|
103
|
+
const limit = typeof lexerTokens === 'number' ? lexerTokens : undefined;
|
|
104
|
+
lexer.diagnosticCollector.printTokenStream(limit);
|
|
105
|
+
}
|
|
106
|
+
if (lexerMapping !== false) {
|
|
107
|
+
if (typeof lexerMapping === 'string') {
|
|
108
|
+
const match = lexerMapping.match(/^(\d+)-(\d+)$/);
|
|
109
|
+
if (match) {
|
|
110
|
+
const startLine = parseInt(match[1], 10);
|
|
111
|
+
const endLine = parseInt(match[2], 10);
|
|
112
|
+
lexer.diagnosticCollector.printCharacterToTokenMapping(startLine, endLine);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log('Invalid line range format. Use format like "1-10"');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
lexer.diagnosticCollector.printCharacterToTokenMapping();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
lexer.diagnosticCollector.printReport();
|
|
123
|
+
const recommendations = lexer.diagnosticCollector.getRecommendations();
|
|
124
|
+
if (recommendations.length > 0) {
|
|
125
|
+
console.log('Performance Recommendations:');
|
|
126
|
+
recommendations.forEach((rec, idx) => {
|
|
127
|
+
console.log(` ${idx + 1}. ${rec}`);
|
|
128
|
+
});
|
|
129
|
+
console.log('');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
visitor.annotateComponents();
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
|
|
137
|
+
}
|
|
138
|
+
const componentLinks = visitor.getComponentCtxLinks();
|
|
139
|
+
const importedLibraries = Array.from(visitor.getScope().libraries.values());
|
|
140
|
+
for (let i = 0; i < postAnnotationCallbacks.length; i++) {
|
|
141
|
+
await postAnnotationCallbacks[i](options, scriptData, tree, tokens, componentLinks, importedLibraries, environment);
|
|
142
|
+
}
|
|
143
|
+
visitor.cacheLibraries();
|
|
144
|
+
if (dumpNets) {
|
|
145
|
+
const nets = visitor.dumpNets();
|
|
146
|
+
nets.forEach(item => console.log(item.join(" | ")));
|
|
147
|
+
}
|
|
148
|
+
dumpData && environment.writeFileSync(dumpDirectory + 'tree.lisp', tree.toStringTree(null, parser));
|
|
149
|
+
dumpData && environment.writeFileSync(dumpDirectory + 'raw-parser.txt', visitor.logger.dump());
|
|
150
|
+
if (throwError) {
|
|
151
|
+
errors.push(throwError);
|
|
152
|
+
}
|
|
153
|
+
let svgOutput = "";
|
|
154
|
+
if (errors.length === 0 && throwError === undefined) {
|
|
155
|
+
const { frameComponent } = visitor.applySheetFrameComponent();
|
|
156
|
+
const { sequence, nets } = visitor.getGraph();
|
|
157
|
+
if (enableBom && bomOutputPath) {
|
|
158
|
+
const documentVariable = visitor.getScope().variables.get('document');
|
|
159
|
+
const bomConfig = documentVariable.bom;
|
|
160
|
+
const bomData = generateBom(bomConfig, visitor.getScope().getInstances());
|
|
161
|
+
const bomCsvOutput = generateBomCSV(bomData);
|
|
162
|
+
await saveBomOutputCsv(environment, bomCsvOutput, bomOutputPath);
|
|
163
|
+
console.log('Generated BOM file', bomOutputPath);
|
|
164
|
+
}
|
|
165
|
+
const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
|
|
166
|
+
dumpData && environment.writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
|
|
167
|
+
try {
|
|
168
|
+
let fileExtension = null;
|
|
169
|
+
let outputDefaultZoom = defaultZoomScale;
|
|
170
|
+
if (outputPath) {
|
|
171
|
+
fileExtension = path.extname(outputPath).substring(1);
|
|
172
|
+
}
|
|
173
|
+
for (let i = 0; i < parseHandlers.length; i++) {
|
|
174
|
+
const handler = parseHandlers[i];
|
|
175
|
+
if (handler.beforeRender) {
|
|
176
|
+
const keepParsing = handler.parse(visitor, outputPath, fileExtension);
|
|
177
|
+
if (!keepParsing) {
|
|
178
|
+
return {
|
|
179
|
+
svgOutput: null,
|
|
180
|
+
errors
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const logger = new Logger();
|
|
186
|
+
const graphEngine = new NetGraph(logger);
|
|
187
|
+
const layoutEngine = new LayoutEngine(logger);
|
|
188
|
+
const layoutTimer = new SimpleStopwatch();
|
|
189
|
+
let sheetFrames;
|
|
190
|
+
try {
|
|
191
|
+
const { graph, containerFrames } = graphEngine.generateLayoutGraph(sequence, nets);
|
|
192
|
+
sheetFrames = layoutEngine.runLayout(graph, containerFrames, nets);
|
|
193
|
+
if (enableErc) {
|
|
194
|
+
const ercResults = EvaluateERCRules(visitor, graph, nets);
|
|
195
|
+
if (ercResults.length > 0) {
|
|
196
|
+
console.log(`ERC found ${ercResults.length} items:`);
|
|
197
|
+
ercResults.forEach((item, index) => {
|
|
198
|
+
console.log(`${(index + 1).toString().padStart(3)}. line ${item.start.line}, column ${item.start.column}: ${item.type} - ${item.message}`);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log('No ERC issues found');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
throw new RenderError(`Error during layout generation: ${err}`, 'layout');
|
|
208
|
+
}
|
|
209
|
+
layoutEngine.printWarnings();
|
|
210
|
+
showStats && console.log('Layout took:', layoutTimer.lap());
|
|
211
|
+
dumpData && environment.writeFileSync(dumpDirectory + 'raw-layout.txt', layoutEngine.logger.dump());
|
|
212
|
+
const generateSvgTimer = new SimpleStopwatch();
|
|
213
|
+
const renderLogger = new Logger();
|
|
214
|
+
let svgCanvas;
|
|
215
|
+
try {
|
|
216
|
+
svgCanvas = renderSheetsToSVG(sheetFrames, renderLogger);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
throw new RenderError(`Error during SVG generation: ${err}`, 'svg_generation');
|
|
220
|
+
}
|
|
221
|
+
showStats && console.log('Render took:', generateSvgTimer.lap());
|
|
222
|
+
dumpData && environment.writeFileSync(dumpDirectory + 'raw-render.txt', renderLogger.dump());
|
|
223
|
+
try {
|
|
224
|
+
if (fileExtension === "pdf") {
|
|
225
|
+
outputDefaultZoom = 1;
|
|
226
|
+
}
|
|
227
|
+
svgOutput = generateSvgOutput(svgCanvas, outputDefaultZoom);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
throw new RenderError(`Error generating SVG output: ${err}`, 'svg_output');
|
|
231
|
+
}
|
|
232
|
+
if (outputPath) {
|
|
233
|
+
if (fileExtension === 'svg') {
|
|
234
|
+
try {
|
|
235
|
+
environment.writeFileSync(outputPath, svgOutput);
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
throw new RenderError(`Error writing SVG file: ${err}`, 'file_output');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else if (fileExtension === 'pdf') {
|
|
242
|
+
let sheetSize = "A4";
|
|
243
|
+
let sheetSizeDefined = false;
|
|
244
|
+
if (frameComponent) {
|
|
245
|
+
sheetSize = frameComponent.getParam(FrameParamKeys.PaperSize);
|
|
246
|
+
sheetSizeDefined = true;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const doc = new PDFDocument({
|
|
250
|
+
layout: 'landscape',
|
|
251
|
+
size: sheetSize
|
|
252
|
+
});
|
|
253
|
+
const outputStream = environment.createWriteStream(outputPath);
|
|
254
|
+
generatePdfOutput(doc, svgCanvas, sheetSize, sheetSizeDefined, outputDefaultZoom);
|
|
255
|
+
doc.pipe(outputStream);
|
|
256
|
+
doc.end();
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
throw new RenderError(`Error generating PDF file: ${err}`, 'pdf_output');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
throw new RenderError(`Invalid output format: ${fileExtension}`, 'file_output');
|
|
264
|
+
}
|
|
265
|
+
console.log('Generated file', outputPath);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
throw new RenderError(`Error during rendering: ${err}`, 'output_generation');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
svgOutput,
|
|
274
|
+
errors
|
|
275
|
+
};
|
|
276
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import { renderScript } from
|
|
3
|
-
import { NodeScriptEnvironment } from "./environment.js";
|
|
2
|
+
import { renderScript } from "./pipeline.js";
|
|
3
|
+
import { NodeScriptEnvironment } from "./environment/environment.js";
|
|
4
4
|
const mainDir = './__tests__/testData/renderData/';
|
|
5
5
|
const env = new NodeScriptEnvironment();
|
|
6
6
|
NodeScriptEnvironment.setInstance(env);
|
|
@@ -21,6 +21,7 @@ async function regenerateTests(extra = "") {
|
|
|
21
21
|
env.setModuleDirectory(mainDir);
|
|
22
22
|
env.setDefaultLibsPath(mainDir + '../../../libs/');
|
|
23
23
|
await renderScript(scriptData, outputPath, {
|
|
24
|
+
inputPath,
|
|
24
25
|
dumpNets: false,
|
|
25
26
|
dumpData: false,
|
|
26
27
|
showStats: false,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { generateKiCadNetList, printTree } from "./export.js";
|
|
2
|
+
export class ParseOutputHandler {
|
|
3
|
+
beforeRender = false;
|
|
4
|
+
afterRender = false;
|
|
5
|
+
}
|
|
6
|
+
export class KiCadNetListOutputHandler extends ParseOutputHandler {
|
|
7
|
+
beforeRender = true;
|
|
8
|
+
parse(visitor, outputPath, fileExtension) {
|
|
9
|
+
if (outputPath !== null && fileExtension === "net") {
|
|
10
|
+
const { tree: kiCadNetList, missingFootprints } = generateKiCadNetList(visitor.getNetList());
|
|
11
|
+
missingFootprints.forEach(entry => {
|
|
12
|
+
console.log(`${entry.refdes} (${entry.instanceName}) does not have footprint`);
|
|
13
|
+
});
|
|
14
|
+
visitor.environment.writeFileSync(outputPath, printTree(kiCadNetList));
|
|
15
|
+
console.log('Generated file', outputPath);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { defaultPageMarginMM, MilsToMM } from "../globals.js";
|
|
2
|
+
const PaperSizes = {
|
|
3
|
+
'A0': [1189, 841],
|
|
4
|
+
'A1': [841, 594],
|
|
5
|
+
'A2': [594, 420],
|
|
6
|
+
'A3': [420, 297],
|
|
7
|
+
'A4': [297, 210],
|
|
8
|
+
'A5': [210, 148],
|
|
9
|
+
'A6': [148, 105],
|
|
10
|
+
};
|
|
11
|
+
export const PaperGridReferences = {
|
|
12
|
+
'A0': [16, 24],
|
|
13
|
+
'A1': [12, 16],
|
|
14
|
+
'A2': [8, 12],
|
|
15
|
+
'A3': [6, 8],
|
|
16
|
+
'A4': [4, 6],
|
|
17
|
+
};
|
|
18
|
+
export function isSupportedPaperSize(type) {
|
|
19
|
+
if (PaperSizes[type]) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
export function getPaperSize(type, margin = defaultPageMarginMM) {
|
|
25
|
+
if (PaperSizes[type]) {
|
|
26
|
+
const [width, height] = PaperSizes[type];
|
|
27
|
+
const useWidth = width - margin * 2;
|
|
28
|
+
const useHeight = height - margin * 2;
|
|
29
|
+
return {
|
|
30
|
+
width: Math.floor(useWidth * (1 / MilsToMM)),
|
|
31
|
+
height: Math.floor(useHeight * (1 / MilsToMM)),
|
|
32
|
+
widthMM: useWidth,
|
|
33
|
+
heightMM: useHeight,
|
|
34
|
+
originalWidthMM: width,
|
|
35
|
+
originalHeightMM: height,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return getPaperSize('A4');
|
|
40
|
+
}
|
|
41
|
+
}
|