circuitscript 0.1.5 → 0.1.8
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/export.js +0 -5
- package/dist/cjs/geometry.js +1 -0
- package/dist/cjs/globals.js +11 -6
- package/dist/cjs/helpers.js +152 -127
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/layout.js +86 -44
- 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 +14 -10
- 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 +71 -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 -7
- package/dist/esm/{geometry.mjs → geometry.js} +6 -5
- package/dist/esm/{globals.mjs → globals.js} +6 -1
- package/dist/esm/helpers.js +394 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/{layout.mjs → layout.js} +72 -53
- 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} +15 -11
- 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 +105 -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/layout.d.ts +2 -2
- 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 +15 -14
- 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/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,394 @@
|
|
|
1
|
+
import { writeFileSync, createWriteStream, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import PDFDocument from "pdfkit";
|
|
4
|
+
import { generateKiCADNetList, printTree } from "./export.js";
|
|
5
|
+
import { LayoutEngine } from "./layout.js";
|
|
6
|
+
import { parseFileWithVisitor } from "./parser.js";
|
|
7
|
+
import { generatePdfOutput, generateSvgOutput, renderSheetsToSVG } from "./render.js";
|
|
8
|
+
import { generateDebugSequenceAction, ParseError, ParseSyntaxError, RenderError, resolveToNumericValue, RuntimeExecutionError, sequenceActionString, SimpleStopwatch } from "./utils.js";
|
|
9
|
+
import { ParserVisitor } from "./visitor.js";
|
|
10
|
+
import { SymbolValidatorVisitor } from "./validate/SymbolValidatorVisitor.js";
|
|
11
|
+
import { SymbolValidatorResolveVisitor } from "./validate/SymbolValidatorResolveVisitor.js";
|
|
12
|
+
import { BaseErrorListener, CharStream, CommonTokenStream, DefaultErrorStrategy, RecognitionException } from "antlr4ng";
|
|
13
|
+
import { MainLexer } from "./lexer.js";
|
|
14
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.js";
|
|
15
|
+
import { prepareTokens, SemanticTokensVisitor } from "./SemanticTokenVisitor.js";
|
|
16
|
+
import { defaultPageMarginMM, defaultZoomScale, LengthUnit, MilsToMM, PxToMM } from "./globals.js";
|
|
17
|
+
import { FrameParamKeys } from "./objects/Frame.js";
|
|
18
|
+
import Big from "big.js";
|
|
19
|
+
import { Logger } from "./logger.js";
|
|
20
|
+
export var JSModuleType;
|
|
21
|
+
(function (JSModuleType) {
|
|
22
|
+
JSModuleType["CommonJs"] = "cjs";
|
|
23
|
+
JSModuleType["ESM"] = "mjs";
|
|
24
|
+
})(JSModuleType || (JSModuleType = {}));
|
|
25
|
+
export function prepareFile(textData) {
|
|
26
|
+
const chars = CharStream.fromString(textData);
|
|
27
|
+
const lexer = new MainLexer(chars);
|
|
28
|
+
const lexerTimer = new SimpleStopwatch();
|
|
29
|
+
const tokens = new CommonTokenStream(lexer);
|
|
30
|
+
tokens.fill();
|
|
31
|
+
const lexerTimeTaken = lexerTimer.lap();
|
|
32
|
+
const parser = new CircuitScriptParser(tokens);
|
|
33
|
+
return {
|
|
34
|
+
parser,
|
|
35
|
+
lexer,
|
|
36
|
+
lexerTimeTaken,
|
|
37
|
+
tokens
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export async function getSemanticTokens(scriptData, options) {
|
|
41
|
+
const { parser, lexer, tokens } = prepareFile(scriptData);
|
|
42
|
+
const tree = parser.script();
|
|
43
|
+
const visitor = new SemanticTokensVisitor(true, null, options.environment, lexer, scriptData);
|
|
44
|
+
parser.removeErrorListeners();
|
|
45
|
+
visitor.onImportFile = async (visitor, filePath, textData) => {
|
|
46
|
+
let hasError = false;
|
|
47
|
+
let hasParseError = false;
|
|
48
|
+
if (textData !== null) {
|
|
49
|
+
const { parser } = prepareFile(textData);
|
|
50
|
+
const tree = parser.script();
|
|
51
|
+
try {
|
|
52
|
+
visitor.visit(tree);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.log('Error while parsing: ', err);
|
|
56
|
+
hasParseError = true;
|
|
57
|
+
hasError = true;
|
|
58
|
+
throw new ParseError(`Error parsing semantic tokens in imported file: ${err}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log('File does not exist');
|
|
63
|
+
hasError = true;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
hasError, hasParseError
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
await visitor.visitAsync(tree);
|
|
70
|
+
const semanticTokens = visitor.getTokens();
|
|
71
|
+
const parsedTokens = prepareTokens(tokens.getTokens(), lexer, scriptData);
|
|
72
|
+
const finalParsedTokens = [];
|
|
73
|
+
parsedTokens.forEach(token => {
|
|
74
|
+
const location = `${token.line}_${token.column}`;
|
|
75
|
+
if (semanticTokens.has(location)) {
|
|
76
|
+
finalParsedTokens.push(semanticTokens.get(location));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
finalParsedTokens.push(token);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
visitor,
|
|
84
|
+
parsedTokens: finalParsedTokens
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
class TokenErrorListener extends BaseErrorListener {
|
|
88
|
+
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
|
89
|
+
console.log(msg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class ParseErrorStrategy extends DefaultErrorStrategy {
|
|
93
|
+
reportUnwantedToken(recognizer) {
|
|
94
|
+
if (this.inErrorRecoveryMode(recognizer)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.beginErrorCondition(recognizer);
|
|
98
|
+
const t = recognizer.getCurrentToken();
|
|
99
|
+
const tokenName = this.getTokenErrorDisplay(t);
|
|
100
|
+
const msg = "extraneous input " + tokenName;
|
|
101
|
+
recognizer.notifyErrorListeners(msg, t, null);
|
|
102
|
+
this.endErrorCondition(recognizer);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function validateScript(filePath, scriptData, options) {
|
|
106
|
+
const { parser } = prepareFile(scriptData);
|
|
107
|
+
parser.removeErrorListeners();
|
|
108
|
+
parser.errorHandler = new ParseErrorStrategy();
|
|
109
|
+
parser.addErrorListener(new TokenErrorListener());
|
|
110
|
+
const tree = parser.script();
|
|
111
|
+
const visitor = new SymbolValidatorVisitor(true, null, options.environment);
|
|
112
|
+
visitor.enterFile(filePath);
|
|
113
|
+
visitor.onImportFile = async (visitor, filePath, textData) => {
|
|
114
|
+
visitor.enterFile(filePath);
|
|
115
|
+
let hasError = false;
|
|
116
|
+
let hasParseError = false;
|
|
117
|
+
if (textData !== null) {
|
|
118
|
+
const { parser } = prepareFile(textData);
|
|
119
|
+
const tree = parser.script();
|
|
120
|
+
try {
|
|
121
|
+
await visitor.visitAsync(tree);
|
|
122
|
+
visitor.exitFile();
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.log('got an error while parsing tree: ', err);
|
|
126
|
+
hasParseError = true;
|
|
127
|
+
hasError = true;
|
|
128
|
+
throw new ParseError(`Error parsing validation in imported file: ${err}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log('file does not exist!');
|
|
133
|
+
hasError = true;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
hasError, hasParseError
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
await visitor.visitAsync(tree);
|
|
140
|
+
const symbolTable = visitor.getSymbols();
|
|
141
|
+
symbolTable.clearUndefined();
|
|
142
|
+
const visitorResolver = new SymbolValidatorResolveVisitor(true, null, options.environment);
|
|
143
|
+
visitorResolver.enterFile(filePath);
|
|
144
|
+
visitorResolver.setSymbols(visitor.getSymbols());
|
|
145
|
+
visitorResolver.onImportFile = visitor.onImportFile;
|
|
146
|
+
await visitorResolver.visitAsync(tree);
|
|
147
|
+
return visitorResolver;
|
|
148
|
+
}
|
|
149
|
+
export async function renderScript(scriptData, outputPath, options) {
|
|
150
|
+
const { dumpNets = false, dumpData = false, showStats = false, environment } = options;
|
|
151
|
+
const errors = [];
|
|
152
|
+
const onErrorHandler = (message, context, error) => {
|
|
153
|
+
if (error && error instanceof RuntimeExecutionError) {
|
|
154
|
+
errors.push(error);
|
|
155
|
+
}
|
|
156
|
+
else if (error && error instanceof RecognitionException) {
|
|
157
|
+
if (context !== null) {
|
|
158
|
+
errors.push(new ParseSyntaxError(message, context.start, context.stop));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (error.recognizer) {
|
|
162
|
+
const recognizer = error.recognizer;
|
|
163
|
+
errors.push(new ParseSyntaxError(message, {
|
|
164
|
+
line: recognizer.currentTokenStartLine,
|
|
165
|
+
column: recognizer.currentTokenColumn
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
errors.push(new ParseSyntaxError(message));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
errors.push(new ParseError(message, context.start, context.stop));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const visitor = new ParserVisitor(true, onErrorHandler, options.environment);
|
|
178
|
+
visitor.onImportFile = async (visitor, filePath, fileData) => {
|
|
179
|
+
const { hasError, hasParseError } = await parseFileWithVisitor(visitor, fileData);
|
|
180
|
+
if (hasError || hasParseError) {
|
|
181
|
+
throw new ParseError(`Error parsing imported file: ${filePath}`, undefined, undefined, filePath);
|
|
182
|
+
}
|
|
183
|
+
return { hasError, hasParseError };
|
|
184
|
+
};
|
|
185
|
+
visitor.log('reading file');
|
|
186
|
+
visitor.log('done reading file');
|
|
187
|
+
const { tree, parser, parserTimeTaken, lexerTimeTaken } = await parseFileWithVisitor(visitor, scriptData);
|
|
188
|
+
showStats && console.log('Lexing took:', lexerTimeTaken);
|
|
189
|
+
showStats && console.log('Parsing took:', parserTimeTaken);
|
|
190
|
+
if (dumpNets) {
|
|
191
|
+
const nets = visitor.dumpNets();
|
|
192
|
+
nets.forEach(item => console.log(item.join(" | ")));
|
|
193
|
+
}
|
|
194
|
+
const dumpDirectory = environment.getRelativeToModule('/dump/');
|
|
195
|
+
if (dumpData) {
|
|
196
|
+
console.log('Dump data to:', dumpDirectory);
|
|
197
|
+
if (!existsSync(dumpDirectory)) {
|
|
198
|
+
mkdirSync(dumpDirectory);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
dumpData && writeFileSync(dumpDirectory + 'tree.lisp', tree.toStringTree(null, parser));
|
|
202
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-parser.txt', visitor.logger.dump());
|
|
203
|
+
let svgOutput = "";
|
|
204
|
+
if (errors.length === 0) {
|
|
205
|
+
const { frameComponent } = visitor.applySheetFrameComponent();
|
|
206
|
+
try {
|
|
207
|
+
visitor.annotateComponents();
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
|
|
211
|
+
}
|
|
212
|
+
const { sequence, nets } = visitor.getGraph();
|
|
213
|
+
const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
|
|
214
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
|
|
215
|
+
try {
|
|
216
|
+
let fileExtension = null;
|
|
217
|
+
let outputDefaultZoom = defaultZoomScale;
|
|
218
|
+
if (outputPath) {
|
|
219
|
+
fileExtension = path.extname(outputPath).substring(1);
|
|
220
|
+
if (fileExtension === "pdf") {
|
|
221
|
+
outputDefaultZoom = 1;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (fileExtension === 'net') {
|
|
225
|
+
const { tree: kicadNetList, missingFootprints } = generateKiCADNetList(visitor.getNetList());
|
|
226
|
+
missingFootprints.forEach(entry => {
|
|
227
|
+
console.log(`${entry.refdes} (${entry.instanceName}) does not have footprint`);
|
|
228
|
+
});
|
|
229
|
+
writeFileSync(outputPath, printTree(kicadNetList));
|
|
230
|
+
console.log('Generated file', outputPath);
|
|
231
|
+
return {
|
|
232
|
+
svgOutput: null,
|
|
233
|
+
errors,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const layoutEngine = new LayoutEngine();
|
|
237
|
+
const layoutTimer = new SimpleStopwatch();
|
|
238
|
+
let sheetFrames;
|
|
239
|
+
try {
|
|
240
|
+
sheetFrames = layoutEngine.runLayout(sequence, nets);
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
throw new RenderError(`Error during layout generation: ${err}`, 'layout');
|
|
244
|
+
}
|
|
245
|
+
layoutEngine.printWarnings();
|
|
246
|
+
showStats && console.log('Layout took:', layoutTimer.lap());
|
|
247
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-layout.txt', layoutEngine.logger.dump());
|
|
248
|
+
const generateSvgTimer = new SimpleStopwatch();
|
|
249
|
+
const renderLogger = new Logger();
|
|
250
|
+
let svgCanvas;
|
|
251
|
+
try {
|
|
252
|
+
svgCanvas = renderSheetsToSVG(sheetFrames, renderLogger);
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
throw new RenderError(`Error during SVG generation: ${err}`, 'svg_generation');
|
|
256
|
+
}
|
|
257
|
+
showStats && console.log('Render took:', generateSvgTimer.lap());
|
|
258
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-render.txt', renderLogger.dump());
|
|
259
|
+
try {
|
|
260
|
+
svgOutput = generateSvgOutput(svgCanvas, outputDefaultZoom);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
throw new RenderError(`Error generating SVG output: ${err}`, 'svg_output');
|
|
264
|
+
}
|
|
265
|
+
if (outputPath) {
|
|
266
|
+
if (fileExtension === 'svg') {
|
|
267
|
+
try {
|
|
268
|
+
writeFileSync(outputPath, svgOutput);
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
throw new RenderError(`Error writing SVG file: ${err}`, 'file_output');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else if (fileExtension === 'pdf') {
|
|
275
|
+
let sheetSize = "A4";
|
|
276
|
+
let sheetSizeDefined = false;
|
|
277
|
+
if (frameComponent) {
|
|
278
|
+
sheetSize = frameComponent.getParam(FrameParamKeys.PaperSize);
|
|
279
|
+
sheetSizeDefined = true;
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const doc = new PDFDocument({
|
|
283
|
+
layout: 'landscape',
|
|
284
|
+
size: sheetSize
|
|
285
|
+
});
|
|
286
|
+
const outputStream = createWriteStream(outputPath);
|
|
287
|
+
generatePdfOutput(doc, svgCanvas, sheetSize, sheetSizeDefined, outputDefaultZoom);
|
|
288
|
+
doc.pipe(outputStream);
|
|
289
|
+
doc.end();
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
throw new RenderError(`Error generating PDF file: ${err}`, 'pdf_output');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
throw new RenderError(`Invalid output format: ${fileExtension}`, 'file_output');
|
|
297
|
+
}
|
|
298
|
+
console.log('Generated file', outputPath);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
throw new RenderError(`Error during rendering: ${err}`, 'output_generation');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
svgOutput,
|
|
307
|
+
errors
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
export function detectJSModuleType() {
|
|
311
|
+
if (typeof __filename === 'undefined' &&
|
|
312
|
+
typeof __dirname === 'undefined') {
|
|
313
|
+
return JSModuleType.ESM;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
return JSModuleType.CommonJs;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
export class UnitDimension {
|
|
320
|
+
type;
|
|
321
|
+
value;
|
|
322
|
+
constructor(value, type = LengthUnit.mils) {
|
|
323
|
+
this.value = value;
|
|
324
|
+
this.type = type;
|
|
325
|
+
}
|
|
326
|
+
getMM() {
|
|
327
|
+
switch (this.type) {
|
|
328
|
+
case LengthUnit.mm:
|
|
329
|
+
return this.value;
|
|
330
|
+
case LengthUnit.mils:
|
|
331
|
+
return this.value * MilsToMM;
|
|
332
|
+
case LengthUnit.px:
|
|
333
|
+
return this.value * PxToMM;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
static mm(value) {
|
|
337
|
+
return new UnitDimension(value, LengthUnit.mm);
|
|
338
|
+
}
|
|
339
|
+
static mils(value) {
|
|
340
|
+
return new UnitDimension(value, LengthUnit.mils);
|
|
341
|
+
}
|
|
342
|
+
static px(value) {
|
|
343
|
+
return new UnitDimension(value, LengthUnit.px);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
export function milsToMM(value) {
|
|
347
|
+
if (typeof value === 'number') {
|
|
348
|
+
value = resolveToNumericValue(new Big(value));
|
|
349
|
+
}
|
|
350
|
+
return resolveToNumericValue(value.toBigNumber().mul(new Big(MilsToMM)).round(6));
|
|
351
|
+
}
|
|
352
|
+
export function pxToMM(value) {
|
|
353
|
+
return value * PxToMM;
|
|
354
|
+
}
|
|
355
|
+
const PaperSizes = {
|
|
356
|
+
'A0': [1189, 841],
|
|
357
|
+
'A1': [841, 594],
|
|
358
|
+
'A2': [594, 420],
|
|
359
|
+
'A3': [420, 297],
|
|
360
|
+
'A4': [297, 210],
|
|
361
|
+
'A5': [210, 148],
|
|
362
|
+
'A6': [148, 105],
|
|
363
|
+
};
|
|
364
|
+
export const PaperGridReferences = {
|
|
365
|
+
'A0': [16, 24],
|
|
366
|
+
'A1': [12, 16],
|
|
367
|
+
'A2': [8, 12],
|
|
368
|
+
'A3': [6, 8],
|
|
369
|
+
'A4': [4, 6],
|
|
370
|
+
};
|
|
371
|
+
export function isSupportedPaperSize(type) {
|
|
372
|
+
if (PaperSizes[type]) {
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
export function getPaperSize(type, margin = defaultPageMarginMM) {
|
|
378
|
+
if (PaperSizes[type]) {
|
|
379
|
+
const [width, height] = PaperSizes[type];
|
|
380
|
+
const useWidth = width - margin * 2;
|
|
381
|
+
const useHeight = height - margin * 2;
|
|
382
|
+
return {
|
|
383
|
+
width: Math.floor(useWidth * (1 / MilsToMM)),
|
|
384
|
+
height: Math.floor(useHeight * (1 / MilsToMM)),
|
|
385
|
+
widthMM: useWidth,
|
|
386
|
+
heightMM: useHeight,
|
|
387
|
+
originalWidthMM: width,
|
|
388
|
+
originalHeightMM: height,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
return getPaperSize('A4');
|
|
393
|
+
}
|
|
394
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './draw_symbols.js';
|
|
2
|
+
export * from './execute.js';
|
|
3
|
+
export * from './export.js';
|
|
4
|
+
export * from './geometry.js';
|
|
5
|
+
export * from './globals.js';
|
|
6
|
+
export * from './helpers.js';
|
|
7
|
+
export * from './layout.js';
|
|
8
|
+
export * from './lexer.js';
|
|
9
|
+
export * from './logger.js';
|
|
10
|
+
export * from './parser.js';
|
|
11
|
+
export * from './render.js';
|
|
12
|
+
export * from './utils.js';
|
|
13
|
+
export * from './visitor.js';
|
|
14
|
+
export * from './sizing.js';
|
|
15
|
+
export * from './objects/types.js';
|
|
16
|
+
export * from './builtinMethods.js';
|
|
17
|
+
export * from './validate/SymbolTable.js';
|
|
18
|
+
export * from './validate/SymbolValidatorResolveVisitor.js';
|
|
19
|
+
export * from './validate/SymbolValidatorVisitor.js';
|
|
20
|
+
export * from './environment.js';
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { Graph
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import graphlib, { Graph } from '@dagrejs/graphlib';
|
|
2
|
+
const { alg } = graphlib;
|
|
3
|
+
import { SymbolCustom, SymbolDrawing, SymbolCustomModule, SymbolPlaceholder, SymbolText, PlaceHolderCommands } from "./draw_symbols.js";
|
|
4
|
+
import { FrameAction, SequenceAction } from "./objects/ExecutionScope.js";
|
|
5
|
+
import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys, SymbolPinSide, WireAutoDirection } from './globals.js';
|
|
6
|
+
import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.js';
|
|
7
|
+
import { Logger } from './logger.js';
|
|
8
|
+
import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.js';
|
|
9
|
+
import { areasOverlap, combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, roundValue, toNearestGrid } from './utils.js';
|
|
10
|
+
import { Direction } from './objects/types.js';
|
|
11
|
+
import { milsToMM, UnitDimension } from './helpers.js';
|
|
12
|
+
import { numeric, NumericValue } from './objects/ParamDefinition.js';
|
|
12
13
|
export class LayoutEngine {
|
|
13
14
|
logger;
|
|
14
15
|
layoutWarnings = [];
|
|
@@ -29,7 +30,7 @@ export class LayoutEngine {
|
|
|
29
30
|
return "[" + value + "]" + padding;
|
|
30
31
|
}
|
|
31
32
|
runLayout(sequence, nets) {
|
|
32
|
-
const logNodesAndEdges =
|
|
33
|
+
const logNodesAndEdges = true;
|
|
33
34
|
this.print('===== creating graph and populating with nodes =====');
|
|
34
35
|
const { graph, containerFrames } = this.generateLayoutGraph(sequence, nets);
|
|
35
36
|
this.print('===== done populating graph =====');
|
|
@@ -46,7 +47,7 @@ export class LayoutEngine {
|
|
|
46
47
|
this.print('===== graph nodes =====');
|
|
47
48
|
const nodes = graph.nodes();
|
|
48
49
|
nodes.forEach(node => {
|
|
49
|
-
this.print(node, graph.node(node));
|
|
50
|
+
this.print(`name:${node}, value:${graph.node(node)}`);
|
|
50
51
|
});
|
|
51
52
|
this.print('===== end nodes =====');
|
|
52
53
|
this.print('');
|
|
@@ -109,6 +110,7 @@ export class LayoutEngine {
|
|
|
109
110
|
findJunctions(wireGroups) {
|
|
110
111
|
const junctions = [];
|
|
111
112
|
const mergedWires = [];
|
|
113
|
+
const debugSegments = false;
|
|
112
114
|
for (const [key, wires] of wireGroups) {
|
|
113
115
|
const allLines = wires.map(wire => {
|
|
114
116
|
return wire.points.map(pt => {
|
|
@@ -118,15 +120,35 @@ export class LayoutEngine {
|
|
|
118
120
|
};
|
|
119
121
|
});
|
|
120
122
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
if (debugSegments) {
|
|
124
|
+
const tmpSegments = [];
|
|
125
|
+
allLines.forEach(wire => {
|
|
126
|
+
for (let i = 1; i < wire.length; i++) {
|
|
127
|
+
const pt1 = wire[i - 1];
|
|
128
|
+
const pt2 = wire[i];
|
|
129
|
+
tmpSegments.push([
|
|
130
|
+
[pt1.x.toNumber(), pt1.y.toNumber()],
|
|
131
|
+
[pt2.x.toNumber(), pt2.y.toNumber()],
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
mergedWires.push({
|
|
136
|
+
netName: key,
|
|
137
|
+
segments: tmpSegments,
|
|
138
|
+
intersectPoints: [],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const { intersectPoints, segments } = Geometry.mergeWires(allLines);
|
|
143
|
+
mergedWires.push({
|
|
144
|
+
netName: key,
|
|
145
|
+
segments,
|
|
146
|
+
intersectPoints,
|
|
147
|
+
});
|
|
148
|
+
intersectPoints.forEach(([x, y]) => {
|
|
149
|
+
junctions.push(new RenderJunction(numeric(x), numeric(y)));
|
|
150
|
+
});
|
|
151
|
+
}
|
|
130
152
|
}
|
|
131
153
|
return {
|
|
132
154
|
junctions,
|
|
@@ -584,7 +606,7 @@ export class LayoutEngine {
|
|
|
584
606
|
let previousNode = null;
|
|
585
607
|
let previousPin = null;
|
|
586
608
|
const graph = new Graph({
|
|
587
|
-
directed:
|
|
609
|
+
directed: true,
|
|
588
610
|
compound: true,
|
|
589
611
|
});
|
|
590
612
|
this.print('sequence length:', sequence.length);
|
|
@@ -602,7 +624,7 @@ export class LayoutEngine {
|
|
|
602
624
|
const tmpInstanceName = component.instanceName;
|
|
603
625
|
if (!graph.hasNode(tmpInstanceName)) {
|
|
604
626
|
this.print('create instance', tmpInstanceName);
|
|
605
|
-
const { displayProp = null
|
|
627
|
+
const { displayProp = null } = component;
|
|
606
628
|
let tmpSymbol;
|
|
607
629
|
if (displayProp instanceof SymbolDrawing) {
|
|
608
630
|
tmpSymbol = new SymbolPlaceholder(displayProp);
|
|
@@ -618,26 +640,6 @@ export class LayoutEngine {
|
|
|
618
640
|
}
|
|
619
641
|
}
|
|
620
642
|
applyComponentParamsToSymbol(component, tmpSymbol);
|
|
621
|
-
if (component.parameters.has(ParamKeys.angle)) {
|
|
622
|
-
const value = component.parameters.get(ParamKeys.angle).toNumber();
|
|
623
|
-
tmpSymbol.angle = value;
|
|
624
|
-
}
|
|
625
|
-
if (component.parameters.has(ParamKeys.flipX)) {
|
|
626
|
-
tmpSymbol.flipX =
|
|
627
|
-
component.parameters.get(ParamKeys.flipX);
|
|
628
|
-
}
|
|
629
|
-
if (component.parameters.has(ParamKeys.flipY)) {
|
|
630
|
-
tmpSymbol.flipY =
|
|
631
|
-
component.parameters.get(ParamKeys.flipY);
|
|
632
|
-
}
|
|
633
|
-
if (tmpSymbol instanceof SymbolCustom) {
|
|
634
|
-
if (widthProp) {
|
|
635
|
-
tmpSymbol.bodyWidth = milsToMM(widthProp);
|
|
636
|
-
}
|
|
637
|
-
if (heightProp) {
|
|
638
|
-
tmpSymbol.bodyHeight = milsToMM(heightProp);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
643
|
tmpSymbol.refreshDrawing();
|
|
642
644
|
const { width: useWidth, height: useHeight } = tmpSymbol.size();
|
|
643
645
|
tmpComponent = new RenderComponent(component, useWidth, useHeight);
|
|
@@ -743,7 +745,11 @@ export class LayoutEngine {
|
|
|
743
745
|
};
|
|
744
746
|
}
|
|
745
747
|
setGraphEdge(graph, node1, node2, edgeValue) {
|
|
748
|
+
if (!graph.isDirected && graph.hasEdge(node1, node2)) {
|
|
749
|
+
this.print(`Warning: edge already exists ${node1} ${node2}`);
|
|
750
|
+
}
|
|
746
751
|
graph.setEdge(node1, node2, edgeValue);
|
|
752
|
+
this.print(`created edge: node1:${node1} node2:${node2} edgeValue:${edgeValue}`);
|
|
747
753
|
}
|
|
748
754
|
sizeSubGraphs(graph) {
|
|
749
755
|
const subGraphs = alg.components(graph);
|
|
@@ -800,7 +806,6 @@ export class LayoutEngine {
|
|
|
800
806
|
this.placeSubgraphV2(graph, firstNodeId, subgraphEdges);
|
|
801
807
|
}
|
|
802
808
|
placeSubgraphV2(graph, firstNodeId, subgraphEdges) {
|
|
803
|
-
let firstNodePlaced = false;
|
|
804
809
|
const originNodes = [];
|
|
805
810
|
const originNodeGroups = new Map();
|
|
806
811
|
function findOriginNode(node) {
|
|
@@ -826,14 +831,6 @@ export class LayoutEngine {
|
|
|
826
831
|
const [nodeId1, pin1, nodeId2, pin2] = graph.edge(edge);
|
|
827
832
|
const [, node1] = graph.node(nodeId1);
|
|
828
833
|
const [, node2] = graph.node(nodeId2);
|
|
829
|
-
if (nodeId1 === firstNodeId && !firstNodePlaced) {
|
|
830
|
-
this.print('first node placed at origin');
|
|
831
|
-
this.placeNodeAtPosition(numeric(0), numeric(0), node1, pin1);
|
|
832
|
-
firstNodePlaced = true;
|
|
833
|
-
node1.isFloating = false;
|
|
834
|
-
originNodes.push(node1);
|
|
835
|
-
originNodeGroups.set(node1.toString(), [node1]);
|
|
836
|
-
}
|
|
837
834
|
this.print('edge:', '[', node1, pin1, node1.isFloating, ']', '[', node2, pin2, node2.isFloating, ']');
|
|
838
835
|
if (!node1.isFloating && node2.isFloating) {
|
|
839
836
|
fixedNode = node1;
|
|
@@ -911,6 +908,7 @@ export class LayoutEngine {
|
|
|
911
908
|
this.print(`set wire auto end at: ${untilX} ${untilY}`);
|
|
912
909
|
}
|
|
913
910
|
});
|
|
911
|
+
this.print('----');
|
|
914
912
|
});
|
|
915
913
|
}
|
|
916
914
|
mergeOriginNodes(node1, pin1, node2, pin2, originNode1, originNode2, originNodes, originNodeGroups) {
|
|
@@ -1110,11 +1108,32 @@ function generateLayoutPinDefinition(component) {
|
|
|
1110
1108
|
return symbolPinDefinitions;
|
|
1111
1109
|
}
|
|
1112
1110
|
export function applyComponentParamsToSymbol(component, symbol) {
|
|
1111
|
+
const { widthProp = null, heightProp = null } = component;
|
|
1113
1112
|
const newMap = new Map(component.parameters);
|
|
1114
1113
|
if (!newMap.has('refdes')) {
|
|
1115
1114
|
newMap.set('refdes', component.assignedRefDes ?? "?");
|
|
1116
1115
|
}
|
|
1117
1116
|
symbol.drawing.variables = newMap;
|
|
1117
|
+
if (component.parameters.has(ParamKeys.angle)) {
|
|
1118
|
+
const value = component.parameters.get(ParamKeys.angle).toNumber();
|
|
1119
|
+
symbol.angle = value;
|
|
1120
|
+
}
|
|
1121
|
+
if (component.parameters.has(ParamKeys.flipX)) {
|
|
1122
|
+
symbol.flipX =
|
|
1123
|
+
component.parameters.get(ParamKeys.flipX);
|
|
1124
|
+
}
|
|
1125
|
+
if (component.parameters.has(ParamKeys.flipY)) {
|
|
1126
|
+
symbol.flipY =
|
|
1127
|
+
component.parameters.get(ParamKeys.flipY);
|
|
1128
|
+
}
|
|
1129
|
+
if (symbol instanceof SymbolCustom) {
|
|
1130
|
+
if (widthProp) {
|
|
1131
|
+
symbol.bodyWidth = milsToMM(widthProp);
|
|
1132
|
+
}
|
|
1133
|
+
if (heightProp) {
|
|
1134
|
+
symbol.bodyHeight = milsToMM(heightProp);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1118
1137
|
}
|
|
1119
1138
|
function calculateSymbolAngle(symbol, pin, direction) {
|
|
1120
1139
|
let directionVector = 0;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommonToken } from "antlr4ng";
|
|
2
|
-
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.
|
|
3
|
-
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.
|
|
2
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.js";
|
|
3
|
+
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.js";
|
|
4
4
|
export class MainLexer extends CircuitScriptLexer {
|
|
5
5
|
tokens;
|
|
6
6
|
indents;
|