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.
Files changed (97) hide show
  1. package/dist/cjs/BaseVisitor.js +127 -73
  2. package/dist/cjs/SemanticTokenVisitor.js +19 -13
  3. package/dist/cjs/antlr/CircuitScriptParser.js +711 -671
  4. package/dist/cjs/builtinMethods.js +29 -25
  5. package/dist/cjs/environment.js +118 -0
  6. package/dist/cjs/execute.js +53 -12
  7. package/dist/cjs/export.js +0 -5
  8. package/dist/cjs/geometry.js +1 -0
  9. package/dist/cjs/globals.js +11 -6
  10. package/dist/cjs/helpers.js +152 -127
  11. package/dist/cjs/index.js +5 -0
  12. package/dist/cjs/layout.js +86 -44
  13. package/dist/cjs/main.js +31 -19
  14. package/dist/cjs/objects/ExecutionScope.js +33 -0
  15. package/dist/cjs/objects/ParamDefinition.js +15 -15
  16. package/dist/cjs/parser.js +27 -21
  17. package/dist/cjs/regenerate-tests.js +14 -10
  18. package/dist/cjs/render.js +3 -1
  19. package/dist/cjs/sizing.js +5 -58
  20. package/dist/cjs/utils.js +85 -30
  21. package/dist/cjs/validate/SymbolTable.js +96 -0
  22. package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
  23. package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
  24. package/dist/cjs/validate.js +71 -44
  25. package/dist/cjs/visitor.js +140 -24
  26. package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +98 -45
  27. package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
  28. package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
  29. package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +20 -16
  30. package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +7 -7
  31. package/dist/esm/environment.js +110 -0
  32. package/dist/esm/{execute.mjs → execute.js} +66 -25
  33. package/dist/esm/{export.mjs → export.js} +2 -7
  34. package/dist/esm/{geometry.mjs → geometry.js} +6 -5
  35. package/dist/esm/{globals.mjs → globals.js} +6 -1
  36. package/dist/esm/helpers.js +394 -0
  37. package/dist/esm/index.js +20 -0
  38. package/dist/esm/{layout.mjs → layout.js} +72 -53
  39. package/dist/esm/{lexer.mjs → lexer.js} +2 -2
  40. package/dist/esm/{main.mjs → main.js} +33 -21
  41. package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +5 -4
  42. package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +33 -0
  43. package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
  44. package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
  45. package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
  46. package/dist/esm/parser.js +71 -0
  47. package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +15 -11
  48. package/dist/esm/{render.mjs → render.js} +11 -9
  49. package/dist/esm/{sizing.mjs → sizing.js} +6 -34
  50. package/dist/esm/{utils.mjs → utils.js} +61 -17
  51. package/dist/esm/validate/SymbolTable.js +90 -0
  52. package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
  53. package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
  54. package/dist/esm/validate.js +105 -0
  55. package/dist/esm/{visitor.mjs → visitor.js} +151 -35
  56. package/dist/fonts/Arial.ttf +0 -0
  57. package/dist/fonts/Inter-Bold.ttf +0 -0
  58. package/dist/fonts/Inter-Regular.ttf +0 -0
  59. package/dist/fonts/OpenSans-Regular.ttf +0 -0
  60. package/dist/fonts/Roboto-Regular.ttf +0 -0
  61. package/dist/libs/lib.cst +423 -0
  62. package/dist/types/BaseVisitor.d.ts +34 -21
  63. package/dist/types/SemanticTokenVisitor.d.ts +6 -5
  64. package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
  65. package/dist/types/builtinMethods.d.ts +3 -2
  66. package/dist/types/environment.d.ts +31 -0
  67. package/dist/types/globals.d.ts +4 -1
  68. package/dist/types/helpers.d.ts +12 -14
  69. package/dist/types/index.d.ts +5 -0
  70. package/dist/types/layout.d.ts +2 -2
  71. package/dist/types/objects/ClassComponent.d.ts +1 -0
  72. package/dist/types/objects/ExecutionScope.d.ts +11 -0
  73. package/dist/types/objects/types.d.ts +6 -1
  74. package/dist/types/parser.d.ts +7 -11
  75. package/dist/types/sizing.d.ts +0 -3
  76. package/dist/types/utils.d.ts +30 -6
  77. package/dist/types/validate/SymbolTable.d.ts +40 -0
  78. package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
  79. package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
  80. package/dist/types/validate.d.ts +1 -1
  81. package/package.json +15 -14
  82. package/dist/cjs/SymbolValidatorVisitor.js +0 -233
  83. package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
  84. package/dist/esm/helpers.mjs +0 -364
  85. package/dist/esm/index.mjs +0 -15
  86. package/dist/esm/parser.mjs +0 -64
  87. package/dist/esm/validate.mjs +0 -74
  88. package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
  89. /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
  90. /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
  91. /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
  92. /package/dist/esm/{logger.mjs → logger.js} +0 -0
  93. /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
  94. /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
  95. /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
  96. /package/dist/esm/objects/{types.mjs → types.js} +0 -0
  97. /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, alg } from '@dagrejs/graphlib';
2
- import { SymbolCustom, SymbolDrawing, SymbolCustomModule, SymbolPlaceholder, SymbolText, PlaceHolderCommands } from "./draw_symbols.mjs";
3
- import { FrameAction, SequenceAction } from "./objects/ExecutionScope.mjs";
4
- import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys, SymbolPinSide, WireAutoDirection } from './globals.mjs';
5
- import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.mjs';
6
- import { Logger } from './logger.mjs';
7
- import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.mjs';
8
- import { areasOverlap, combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, roundValue, toNearestGrid } from './utils.mjs';
9
- import { Direction } from './objects/types.mjs';
10
- import { milsToMM, UnitDimension } from './helpers.mjs';
11
- import { numeric, NumericValue } from './objects/ParamDefinition.mjs';
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 = false;
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
- const { intersectPoints, segments } = Geometry.mergeWires(allLines);
122
- mergedWires.push({
123
- netName: key,
124
- segments,
125
- intersectPoints,
126
- });
127
- intersectPoints.forEach(([x, y]) => {
128
- junctions.push(new RenderJunction(numeric(x), numeric(y)));
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: false,
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, widthProp = null, heightProp = null } = component;
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.mjs";
3
- import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.mjs";
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;