circuitscript 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/cjs/BaseVisitor.js +149 -80
  2. package/dist/cjs/SemanticTokenVisitor.js +19 -13
  3. package/dist/cjs/antlr/CircuitScriptParser.js +711 -671
  4. package/dist/cjs/builtinMethods.js +48 -22
  5. package/dist/cjs/draw_symbols.js +4 -1
  6. package/dist/cjs/environment.js +118 -0
  7. package/dist/cjs/execute.js +98 -46
  8. package/dist/cjs/geometry.js +1 -0
  9. package/dist/cjs/globals.js +14 -7
  10. package/dist/cjs/helpers.js +142 -150
  11. package/dist/cjs/index.js +5 -0
  12. package/dist/cjs/layout.js +39 -14
  13. package/dist/cjs/main.js +34 -21
  14. package/dist/cjs/objects/ClassComponent.js +4 -1
  15. package/dist/cjs/objects/ExecutionScope.js +40 -2
  16. package/dist/cjs/objects/ParamDefinition.js +15 -15
  17. package/dist/cjs/parser.js +27 -21
  18. package/dist/cjs/regenerate-tests.js +9 -6
  19. package/dist/cjs/render.js +3 -1
  20. package/dist/cjs/sizing.js +10 -60
  21. package/dist/cjs/utils.js +148 -17
  22. package/dist/cjs/validate/SymbolTable.js +96 -0
  23. package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
  24. package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
  25. package/dist/cjs/validate.js +52 -44
  26. package/dist/cjs/visitor.js +149 -31
  27. package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +124 -56
  28. package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
  29. package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
  30. package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +40 -14
  31. package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +11 -8
  32. package/dist/esm/environment.js +110 -0
  33. package/dist/esm/{execute.mjs → execute.js} +111 -58
  34. package/dist/esm/{export.mjs → export.js} +2 -2
  35. package/dist/esm/{geometry.mjs → geometry.js} +6 -5
  36. package/dist/esm/{globals.mjs → globals.js} +9 -2
  37. package/dist/esm/helpers.js +377 -0
  38. package/dist/esm/index.js +20 -0
  39. package/dist/esm/{layout.mjs → layout.js} +44 -22
  40. package/dist/esm/{lexer.mjs → lexer.js} +2 -2
  41. package/dist/esm/{main.mjs → main.js} +36 -23
  42. package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +9 -5
  43. package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +40 -2
  44. package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
  45. package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
  46. package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
  47. package/dist/esm/parser.js +71 -0
  48. package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +10 -7
  49. package/dist/esm/{render.mjs → render.js} +11 -9
  50. package/dist/esm/{sizing.mjs → sizing.js} +11 -36
  51. package/dist/esm/utils.js +286 -0
  52. package/dist/esm/validate/SymbolTable.js +90 -0
  53. package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
  54. package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
  55. package/dist/esm/validate.js +86 -0
  56. package/dist/esm/{visitor.mjs → visitor.js} +160 -42
  57. package/dist/fonts/Arial.ttf +0 -0
  58. package/dist/fonts/Inter-Bold.ttf +0 -0
  59. package/dist/fonts/Inter-Regular.ttf +0 -0
  60. package/dist/fonts/OpenSans-Regular.ttf +0 -0
  61. package/dist/fonts/Roboto-Regular.ttf +0 -0
  62. package/dist/libs/lib.cst +423 -0
  63. package/dist/types/BaseVisitor.d.ts +36 -22
  64. package/dist/types/SemanticTokenVisitor.d.ts +6 -5
  65. package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
  66. package/dist/types/builtinMethods.d.ts +3 -2
  67. package/dist/types/draw_symbols.d.ts +2 -6
  68. package/dist/types/environment.d.ts +31 -0
  69. package/dist/types/execute.d.ts +2 -3
  70. package/dist/types/globals.d.ts +7 -2
  71. package/dist/types/helpers.d.ts +12 -14
  72. package/dist/types/index.d.ts +5 -0
  73. package/dist/types/objects/ClassComponent.d.ts +2 -3
  74. package/dist/types/objects/ExecutionScope.d.ts +20 -6
  75. package/dist/types/objects/types.d.ts +6 -1
  76. package/dist/types/parser.d.ts +7 -11
  77. package/dist/types/sizing.d.ts +0 -3
  78. package/dist/types/utils.d.ts +33 -4
  79. package/dist/types/validate/SymbolTable.d.ts +40 -0
  80. package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
  81. package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
  82. package/dist/types/validate.d.ts +1 -1
  83. package/libs/lib.cst +12 -22
  84. package/package.json +14 -13
  85. package/dist/cjs/SymbolValidatorVisitor.js +0 -233
  86. package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
  87. package/dist/esm/helpers.mjs +0 -380
  88. package/dist/esm/index.mjs +0 -15
  89. package/dist/esm/parser.mjs +0 -64
  90. package/dist/esm/utils.mjs +0 -169
  91. package/dist/esm/validate.mjs +0 -74
  92. package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
  93. package/dist/types/layout.d.ts +0 -148
  94. /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
  95. /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
  96. /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
  97. /package/dist/esm/{logger.mjs → logger.js} +0 -0
  98. /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
  99. /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
  100. /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
  101. /package/dist/esm/objects/{types.mjs → types.js} +0 -0
  102. /package/dist/esm/{server.mjs → server.js} +0 -0
@@ -0,0 +1,377 @@
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
+ errors.push(new ParseSyntaxError(message, context.start, context.stop));
158
+ }
159
+ else {
160
+ errors.push(new ParseError(message, context.start, context.stop));
161
+ }
162
+ };
163
+ const visitor = new ParserVisitor(true, onErrorHandler, options.environment);
164
+ visitor.onImportFile = async (visitor, filePath, fileData) => {
165
+ const { hasError, hasParseError } = await parseFileWithVisitor(visitor, fileData);
166
+ if (hasError || hasParseError) {
167
+ throw new ParseError(`Error parsing imported file: ${filePath}`, undefined, undefined, filePath);
168
+ }
169
+ return { hasError, hasParseError };
170
+ };
171
+ visitor.log('reading file');
172
+ visitor.log('done reading file');
173
+ const { tree, parser, parserTimeTaken, lexerTimeTaken } = await parseFileWithVisitor(visitor, scriptData);
174
+ showStats && console.log('Lexing took:', lexerTimeTaken);
175
+ showStats && console.log('Parsing took:', parserTimeTaken);
176
+ if (dumpNets) {
177
+ const nets = visitor.dumpNets();
178
+ nets.forEach(item => console.log(item.join(" | ")));
179
+ }
180
+ const dumpDirectory = environment.getRelativeToModule('/dump/');
181
+ if (dumpData) {
182
+ console.log('Dump data to:', dumpDirectory);
183
+ if (!existsSync(dumpDirectory)) {
184
+ mkdirSync(dumpDirectory);
185
+ }
186
+ }
187
+ dumpData && writeFileSync(dumpDirectory + 'tree.lisp', tree.toStringTree(null, parser));
188
+ dumpData && writeFileSync(dumpDirectory + 'raw-parser.txt', visitor.logger.dump());
189
+ let svgOutput = "";
190
+ if (errors.length === 0) {
191
+ const { frameComponent } = visitor.applySheetFrameComponent();
192
+ try {
193
+ visitor.annotateComponents();
194
+ }
195
+ catch (err) {
196
+ throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
197
+ }
198
+ const { sequence, nets } = visitor.getGraph();
199
+ const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
200
+ dumpData && writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
201
+ try {
202
+ let fileExtension = null;
203
+ let outputDefaultZoom = defaultZoomScale;
204
+ if (outputPath) {
205
+ fileExtension = path.extname(outputPath).substring(1);
206
+ if (fileExtension === "pdf") {
207
+ outputDefaultZoom = 1;
208
+ }
209
+ }
210
+ if (fileExtension === 'net') {
211
+ const { tree: kicadNetList, missingFootprints } = generateKiCADNetList(visitor.getNetList());
212
+ missingFootprints.forEach(entry => {
213
+ console.log(`${entry.refdes} (${entry.instanceName}) does not have footprint`);
214
+ });
215
+ writeFileSync(outputPath, printTree(kicadNetList));
216
+ console.log('Generated file', outputPath);
217
+ return null;
218
+ }
219
+ const layoutEngine = new LayoutEngine();
220
+ const layoutTimer = new SimpleStopwatch();
221
+ let sheetFrames;
222
+ try {
223
+ sheetFrames = layoutEngine.runLayout(sequence, nets);
224
+ }
225
+ catch (err) {
226
+ throw new RenderError(`Error during layout generation: ${err}`, 'layout');
227
+ }
228
+ layoutEngine.printWarnings();
229
+ showStats && console.log('Layout took:', layoutTimer.lap());
230
+ dumpData && writeFileSync(dumpDirectory + 'raw-layout.txt', layoutEngine.logger.dump());
231
+ const generateSvgTimer = new SimpleStopwatch();
232
+ const renderLogger = new Logger();
233
+ let svgCanvas;
234
+ try {
235
+ svgCanvas = renderSheetsToSVG(sheetFrames, renderLogger);
236
+ }
237
+ catch (err) {
238
+ throw new RenderError(`Error during SVG generation: ${err}`, 'svg_generation');
239
+ }
240
+ showStats && console.log('Render took:', generateSvgTimer.lap());
241
+ dumpData && writeFileSync(dumpDirectory + 'raw-render.txt', renderLogger.dump());
242
+ try {
243
+ svgOutput = generateSvgOutput(svgCanvas, outputDefaultZoom);
244
+ }
245
+ catch (err) {
246
+ throw new RenderError(`Error generating SVG output: ${err}`, 'svg_output');
247
+ }
248
+ if (outputPath) {
249
+ if (fileExtension === 'svg') {
250
+ try {
251
+ writeFileSync(outputPath, svgOutput);
252
+ }
253
+ catch (err) {
254
+ throw new RenderError(`Error writing SVG file: ${err}`, 'file_output');
255
+ }
256
+ }
257
+ else if (fileExtension === 'pdf') {
258
+ let sheetSize = "A4";
259
+ let sheetSizeDefined = false;
260
+ if (frameComponent) {
261
+ sheetSize = frameComponent.getParam(FrameParamKeys.PaperSize);
262
+ sheetSizeDefined = true;
263
+ }
264
+ try {
265
+ const doc = new PDFDocument({
266
+ layout: 'landscape',
267
+ size: sheetSize
268
+ });
269
+ const outputStream = createWriteStream(outputPath);
270
+ generatePdfOutput(doc, svgCanvas, sheetSize, sheetSizeDefined, outputDefaultZoom);
271
+ doc.pipe(outputStream);
272
+ doc.end();
273
+ }
274
+ catch (err) {
275
+ throw new RenderError(`Error generating PDF file: ${err}`, 'pdf_output');
276
+ }
277
+ }
278
+ else {
279
+ throw new RenderError(`Invalid output format: ${fileExtension}`, 'file_output');
280
+ }
281
+ console.log('Generated file', outputPath);
282
+ }
283
+ }
284
+ catch (err) {
285
+ throw new RenderError(`Error during rendering: ${err}`, 'output_generation');
286
+ }
287
+ }
288
+ return {
289
+ svgOutput,
290
+ errors
291
+ };
292
+ }
293
+ export function detectJSModuleType() {
294
+ if (typeof __filename === 'undefined' &&
295
+ typeof __dirname === 'undefined') {
296
+ return JSModuleType.ESM;
297
+ }
298
+ else {
299
+ return JSModuleType.CommonJs;
300
+ }
301
+ }
302
+ export class UnitDimension {
303
+ type;
304
+ value;
305
+ constructor(value, type = LengthUnit.mils) {
306
+ this.value = value;
307
+ this.type = type;
308
+ }
309
+ getMM() {
310
+ switch (this.type) {
311
+ case LengthUnit.mm:
312
+ return this.value;
313
+ case LengthUnit.mils:
314
+ return this.value * MilsToMM;
315
+ case LengthUnit.px:
316
+ return this.value * PxToMM;
317
+ }
318
+ }
319
+ static mm(value) {
320
+ return new UnitDimension(value, LengthUnit.mm);
321
+ }
322
+ static mils(value) {
323
+ return new UnitDimension(value, LengthUnit.mils);
324
+ }
325
+ static px(value) {
326
+ return new UnitDimension(value, LengthUnit.px);
327
+ }
328
+ }
329
+ export function milsToMM(value) {
330
+ if (typeof value === 'number') {
331
+ value = resolveToNumericValue(new Big(value));
332
+ }
333
+ return resolveToNumericValue(value.toBigNumber().mul(new Big(MilsToMM)).round(6));
334
+ }
335
+ export function pxToMM(value) {
336
+ return value * PxToMM;
337
+ }
338
+ const PaperSizes = {
339
+ 'A0': [1189, 841],
340
+ 'A1': [841, 594],
341
+ 'A2': [594, 420],
342
+ 'A3': [420, 297],
343
+ 'A4': [297, 210],
344
+ 'A5': [210, 148],
345
+ 'A6': [148, 105],
346
+ };
347
+ export const PaperGridReferences = {
348
+ 'A0': [16, 24],
349
+ 'A1': [12, 16],
350
+ 'A2': [8, 12],
351
+ 'A3': [6, 8],
352
+ 'A4': [4, 6],
353
+ };
354
+ export function isSupportedPaperSize(type) {
355
+ if (PaperSizes[type]) {
356
+ return true;
357
+ }
358
+ return false;
359
+ }
360
+ export function getPaperSize(type, margin = defaultPageMarginMM) {
361
+ if (PaperSizes[type]) {
362
+ const [width, height] = PaperSizes[type];
363
+ const useWidth = width - margin * 2;
364
+ const useHeight = height - margin * 2;
365
+ return {
366
+ width: Math.floor(useWidth * (1 / MilsToMM)),
367
+ height: Math.floor(useHeight * (1 / MilsToMM)),
368
+ widthMM: useWidth,
369
+ heightMM: useHeight,
370
+ originalWidthMM: width,
371
+ originalHeightMM: height,
372
+ };
373
+ }
374
+ else {
375
+ return getPaperSize('A4');
376
+ }
377
+ }
@@ -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 pkg from '@dagrejs/graphlib';
2
+ const { Graph, alg } = pkg;
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 = [];
@@ -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,
@@ -346,7 +368,7 @@ export class LayoutEngine {
346
368
  const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
347
369
  const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
348
370
  const doesOverlapAreasToAvoid = overlaps.length > 0;
349
- if (doesExceedFrameHeight || doesOverlapAreasToAvoid) {
371
+ if (boundPoints.length > 0 && (doesExceedFrameHeight || doesOverlapAreasToAvoid)) {
350
372
  innerFrameY = offsetY;
351
373
  const nextX = numeric(xmax).sub(offsetX).add(frame.gap);
352
374
  innerFrameX = offsetX.add(nextX);
@@ -376,7 +398,7 @@ export class LayoutEngine {
376
398
  const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
377
399
  const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
378
400
  const doesOverlapAreasToAvoid = overlaps.length > 0;
379
- if (doesExceedFrameWidth || doesOverlapAreasToAvoid) {
401
+ if (boundPoints.length > 0 && (doesExceedFrameWidth || doesOverlapAreasToAvoid)) {
380
402
  innerFrameX = offsetX.add(centeredOffsetX);
381
403
  const { ymax } = getBoundsFromPoints(boundPoints);
382
404
  const nextY = numeric(ymax).sub(offsetY).add(frame.gap);
@@ -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;
@@ -1,14 +1,13 @@
1
1
  #! /usr/bin/env node
2
2
  import { program } from 'commander';
3
3
  import figlet from 'figlet';
4
- import path from 'path';
5
- import { readFileSync, watch, existsSync } from 'fs';
6
- import { prepareSVGEnvironment } from './sizing.mjs';
7
- import { getDefaultLibsPath, getFontsPath, getPackageVersion, renderScript } from './helpers.mjs';
4
+ import { watch } from 'fs';
5
+ import { renderScript } from './helpers.js';
6
+ import { NodeScriptEnvironment } from "./environment.js";
8
7
  export default async function main() {
9
- const fontsPath = getFontsPath();
10
- const defaultLibsPath = getDefaultLibsPath();
11
- const version = getPackageVersion();
8
+ const env = new NodeScriptEnvironment();
9
+ NodeScriptEnvironment.setInstance(env);
10
+ const version = env.getPackageVersion();
12
11
  program
13
12
  .description('generate graphical output from circuitscript files')
14
13
  .version(version)
@@ -19,7 +18,8 @@ export default async function main() {
19
18
  .option('-w, --watch', 'Watch for file changes')
20
19
  .option('-n, --dump-nets', 'Dump out net information')
21
20
  .option('-d, --dump-data', 'Dump data during parsing')
22
- .option('-s, --stats', 'Show stats during generation');
21
+ .option('-s, --stats', 'Show stats during generation')
22
+ .option('-x, --skip-output', 'Skip output generation');
23
23
  program.addHelpText('before', figlet.textSync('circuitscript', {
24
24
  font: 'Small Slant'
25
25
  }));
@@ -32,11 +32,13 @@ export default async function main() {
32
32
  const watchFileChanges = options.watch;
33
33
  const dumpNets = options.dumpNets;
34
34
  const dumpData = options.dumpData;
35
- let currentDirectory = options.currentDirectory ?? null;
35
+ if (options.currentDirectory) {
36
+ throw "Parameter not supported yet";
37
+ }
36
38
  if (watchFileChanges) {
37
39
  console.log('watching for file changes...');
38
40
  }
39
- await prepareSVGEnvironment(fontsPath);
41
+ await env.prepareSVGEnvironment();
40
42
  let inputFilePath = "";
41
43
  if (args.length > 2) {
42
44
  console.log("Error: Extra arguments passed");
@@ -45,11 +47,8 @@ export default async function main() {
45
47
  let scriptData;
46
48
  if (args.length > 0 && args[0]) {
47
49
  inputFilePath = args[0];
48
- if (existsSync(inputFilePath)) {
49
- scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
50
- if (currentDirectory === null) {
51
- currentDirectory = path.dirname(inputFilePath);
52
- }
50
+ if ((await env.exists(inputFilePath))) {
51
+ scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
53
52
  }
54
53
  else {
55
54
  console.error("Error: File could not be found");
@@ -64,28 +63,42 @@ export default async function main() {
64
63
  return;
65
64
  }
66
65
  const scriptOptions = {
67
- currentDirectory,
68
- defaultLibsPath,
69
66
  dumpNets,
70
67
  dumpData,
71
68
  showStats: options.stats,
69
+ environment: env,
72
70
  };
73
71
  let outputPath = null;
74
72
  if (args.length > 0 && args[1]) {
75
73
  outputPath = args[1];
76
74
  }
77
- const output = renderScript(scriptData, outputPath, scriptOptions);
78
- if (outputPath === null && output) {
75
+ const output = await parseFile(scriptData, outputPath, scriptOptions);
76
+ if (outputPath === null && output && (options.skipOutput === undefined)) {
79
77
  console.log(output);
80
78
  }
81
79
  if (watchFileChanges) {
82
- watch(inputFilePath, event => {
80
+ watch(inputFilePath, async (event) => {
83
81
  if (event === 'change') {
84
- const scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
85
- renderScript(scriptData, outputPath, scriptOptions);
86
- console.log('done');
82
+ const scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
83
+ parseFile(scriptData, outputPath, scriptOptions);
87
84
  }
88
85
  });
89
86
  }
90
87
  }
88
+ async function parseFile(scriptData, outputPath, scriptOptions) {
89
+ try {
90
+ const { svgOutput: output, errors } = await renderScript(scriptData, outputPath, scriptOptions);
91
+ errors.forEach((err, index) => {
92
+ console.log(`[${index}] ${err}`);
93
+ });
94
+ if (errors.length > 0) {
95
+ console.log('Render failed due to syntax or parsing errors');
96
+ }
97
+ return output;
98
+ }
99
+ catch (error) {
100
+ console.error(`Unexpected Error: ${error}`);
101
+ }
102
+ return null;
103
+ }
91
104
  main();
@@ -1,7 +1,7 @@
1
- import { SymbolDrawingCommands } from '../draw_symbols.mjs';
2
- import { PinDefinition, PinIdType } from './PinDefinition.mjs';
3
- import { PinTypes } from './PinTypes.mjs';
4
- import { ParamKeys } from '../globals.mjs';
1
+ import { SymbolDrawingCommands } from '../draw_symbols.js';
2
+ import { PinDefinition, PinIdType } from './PinDefinition.js';
3
+ import { PinTypes } from './PinTypes.js';
4
+ import { ParamKeys } from '../globals.js';
5
5
  export class ClassComponent {
6
6
  instanceName;
7
7
  numPins;
@@ -9,11 +9,12 @@ export class ClassComponent {
9
9
  pins = new Map();
10
10
  pinNets = new Map();
11
11
  pinWires = new Map();
12
- pinsMaxPositions = {};
12
+ pinsMaxPositions = new Map();
13
13
  _cachedPins;
14
14
  _cachedParams;
15
15
  _copyID = null;
16
16
  _copyFrom = null;
17
+ _pointLinkComponent;
17
18
  arrangeProps = null;
18
19
  displayProp = null;
19
20
  widthProp = null;
@@ -145,6 +146,9 @@ export class ClassComponent {
145
146
  for (const [key, value] of this.pins) {
146
147
  component.pins.set(key, value);
147
148
  }
149
+ for (const [key, value] of this.pinsMaxPositions) {
150
+ component.pinsMaxPositions.set(key, value);
151
+ }
148
152
  component.refreshCache();
149
153
  return component;
150
154
  }