circuitscript 0.1.5 → 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 (96) 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/geometry.js +1 -0
  8. package/dist/cjs/globals.js +11 -6
  9. package/dist/cjs/helpers.js +135 -127
  10. package/dist/cjs/index.js +5 -0
  11. package/dist/cjs/layout.js +37 -12
  12. package/dist/cjs/main.js +31 -19
  13. package/dist/cjs/objects/ExecutionScope.js +33 -0
  14. package/dist/cjs/objects/ParamDefinition.js +15 -15
  15. package/dist/cjs/parser.js +27 -21
  16. package/dist/cjs/regenerate-tests.js +9 -6
  17. package/dist/cjs/render.js +3 -1
  18. package/dist/cjs/sizing.js +5 -58
  19. package/dist/cjs/utils.js +85 -30
  20. package/dist/cjs/validate/SymbolTable.js +96 -0
  21. package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
  22. package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
  23. package/dist/cjs/validate.js +52 -44
  24. package/dist/cjs/visitor.js +140 -24
  25. package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +98 -45
  26. package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
  27. package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
  28. package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +20 -16
  29. package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +7 -7
  30. package/dist/esm/environment.js +110 -0
  31. package/dist/esm/{execute.mjs → execute.js} +66 -25
  32. package/dist/esm/{export.mjs → export.js} +2 -2
  33. package/dist/esm/{geometry.mjs → geometry.js} +6 -5
  34. package/dist/esm/{globals.mjs → globals.js} +6 -1
  35. package/dist/esm/helpers.js +377 -0
  36. package/dist/esm/index.js +20 -0
  37. package/dist/esm/{layout.mjs → layout.js} +42 -20
  38. package/dist/esm/{lexer.mjs → lexer.js} +2 -2
  39. package/dist/esm/{main.mjs → main.js} +33 -21
  40. package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +5 -4
  41. package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +33 -0
  42. package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
  43. package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
  44. package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
  45. package/dist/esm/parser.js +71 -0
  46. package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +10 -7
  47. package/dist/esm/{render.mjs → render.js} +11 -9
  48. package/dist/esm/{sizing.mjs → sizing.js} +6 -34
  49. package/dist/esm/{utils.mjs → utils.js} +61 -17
  50. package/dist/esm/validate/SymbolTable.js +90 -0
  51. package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
  52. package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
  53. package/dist/esm/validate.js +86 -0
  54. package/dist/esm/{visitor.mjs → visitor.js} +151 -35
  55. package/dist/fonts/Arial.ttf +0 -0
  56. package/dist/fonts/Inter-Bold.ttf +0 -0
  57. package/dist/fonts/Inter-Regular.ttf +0 -0
  58. package/dist/fonts/OpenSans-Regular.ttf +0 -0
  59. package/dist/fonts/Roboto-Regular.ttf +0 -0
  60. package/dist/libs/lib.cst +423 -0
  61. package/dist/types/BaseVisitor.d.ts +34 -21
  62. package/dist/types/SemanticTokenVisitor.d.ts +6 -5
  63. package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
  64. package/dist/types/builtinMethods.d.ts +3 -2
  65. package/dist/types/environment.d.ts +31 -0
  66. package/dist/types/globals.d.ts +4 -1
  67. package/dist/types/helpers.d.ts +12 -14
  68. package/dist/types/index.d.ts +5 -0
  69. package/dist/types/objects/ClassComponent.d.ts +1 -0
  70. package/dist/types/objects/ExecutionScope.d.ts +11 -0
  71. package/dist/types/objects/types.d.ts +6 -1
  72. package/dist/types/parser.d.ts +7 -11
  73. package/dist/types/sizing.d.ts +0 -3
  74. package/dist/types/utils.d.ts +30 -6
  75. package/dist/types/validate/SymbolTable.d.ts +40 -0
  76. package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
  77. package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
  78. package/dist/types/validate.d.ts +1 -1
  79. package/package.json +14 -13
  80. package/dist/cjs/SymbolValidatorVisitor.js +0 -233
  81. package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
  82. package/dist/esm/helpers.mjs +0 -364
  83. package/dist/esm/index.mjs +0 -15
  84. package/dist/esm/parser.mjs +0 -64
  85. package/dist/esm/validate.mjs +0 -74
  86. package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
  87. package/dist/types/layout.d.ts +0 -148
  88. /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
  89. /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
  90. /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
  91. /package/dist/esm/{logger.mjs → logger.js} +0 -0
  92. /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
  93. /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
  94. /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
  95. /package/dist/esm/objects/{types.mjs → types.js} +0 -0
  96. /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,
@@ -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)
@@ -33,11 +32,13 @@ export default async function main() {
33
32
  const watchFileChanges = options.watch;
34
33
  const dumpNets = options.dumpNets;
35
34
  const dumpData = options.dumpData;
36
- let currentDirectory = options.currentDirectory ?? null;
35
+ if (options.currentDirectory) {
36
+ throw "Parameter not supported yet";
37
+ }
37
38
  if (watchFileChanges) {
38
39
  console.log('watching for file changes...');
39
40
  }
40
- await prepareSVGEnvironment(fontsPath);
41
+ await env.prepareSVGEnvironment();
41
42
  let inputFilePath = "";
42
43
  if (args.length > 2) {
43
44
  console.log("Error: Extra arguments passed");
@@ -46,11 +47,8 @@ export default async function main() {
46
47
  let scriptData;
47
48
  if (args.length > 0 && args[0]) {
48
49
  inputFilePath = args[0];
49
- if (existsSync(inputFilePath)) {
50
- scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
51
- if (currentDirectory === null) {
52
- currentDirectory = path.dirname(inputFilePath);
53
- }
50
+ if ((await env.exists(inputFilePath))) {
51
+ scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
54
52
  }
55
53
  else {
56
54
  console.error("Error: File could not be found");
@@ -65,28 +63,42 @@ export default async function main() {
65
63
  return;
66
64
  }
67
65
  const scriptOptions = {
68
- currentDirectory,
69
- defaultLibsPath,
70
66
  dumpNets,
71
67
  dumpData,
72
68
  showStats: options.stats,
69
+ environment: env,
73
70
  };
74
71
  let outputPath = null;
75
72
  if (args.length > 0 && args[1]) {
76
73
  outputPath = args[1];
77
74
  }
78
- const output = renderScript(scriptData, outputPath, scriptOptions);
75
+ const output = await parseFile(scriptData, outputPath, scriptOptions);
79
76
  if (outputPath === null && output && (options.skipOutput === undefined)) {
80
77
  console.log(output);
81
78
  }
82
79
  if (watchFileChanges) {
83
- watch(inputFilePath, event => {
80
+ watch(inputFilePath, async (event) => {
84
81
  if (event === 'change') {
85
- const scriptData = readFileSync(inputFilePath, { encoding: 'utf-8' });
86
- renderScript(scriptData, outputPath, scriptOptions);
87
- console.log('done');
82
+ const scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
83
+ parseFile(scriptData, outputPath, scriptOptions);
88
84
  }
89
85
  });
90
86
  }
91
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
+ }
92
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;
@@ -14,6 +14,7 @@ export class ClassComponent {
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;
@@ -1,3 +1,4 @@
1
+ import { Property_key_exprContext } from '../antlr/CircuitScriptParser.js';
1
2
  export class ExecutionScope {
2
3
  scopeId;
3
4
  nets = [];
@@ -6,6 +7,8 @@ export class ExecutionScope {
6
7
  variables = new Map();
7
8
  symbols = new Map();
8
9
  blockStack = new Map();
10
+ contextStack = [];
11
+ onPropertyHandler = [];
9
12
  breakStack = [];
10
13
  wires = [];
11
14
  frames = [];
@@ -122,6 +125,36 @@ export class ExecutionScope {
122
125
  this.currentPin = null;
123
126
  }
124
127
  }
128
+ enterContext(context) {
129
+ this.contextStack.push(context);
130
+ }
131
+ exitContext() {
132
+ return this.contextStack.pop();
133
+ }
134
+ findPropertyKeyTree() {
135
+ const keyNames = [];
136
+ for (let i = this.contextStack.length - 1; i >= 0; i--) {
137
+ const ctx = this.contextStack[i];
138
+ if (ctx instanceof Property_key_exprContext) {
139
+ keyNames.push([ctx, ctx.getText()]);
140
+ }
141
+ else if (typeof ctx === 'number') {
142
+ keyNames.push(['index', ctx]);
143
+ }
144
+ }
145
+ return keyNames.reverse();
146
+ }
147
+ setOnPropertyHandler(handler) {
148
+ this.onPropertyHandler.push(handler);
149
+ }
150
+ popOnPropertyHandler() {
151
+ return this.onPropertyHandler.pop();
152
+ }
153
+ triggerPropertyHandler(value, valueCtx) {
154
+ const lastHandler = this.onPropertyHandler[this.onPropertyHandler.length - 1];
155
+ const propertyTree = this.findPropertyKeyTree();
156
+ lastHandler && lastHandler(propertyTree, value, valueCtx);
157
+ }
125
158
  }
126
159
  export var SequenceAction;
127
160
  (function (SequenceAction) {
@@ -1,4 +1,4 @@
1
- import { FrameType } from "../globals.mjs";
1
+ import { FrameType } from "../globals.js";
2
2
  export class Frame {
3
3
  parameters = new Map();
4
4
  frameId;
@@ -1,4 +1,4 @@
1
- import { getNumberExponential, getNumberExponentialText, resolveToNumericValue } from "../utils";
1
+ import { getNumberExponential, getNumberExponentialText, resolveToNumericValue } from "../utils.js";
2
2
  import { Big } from 'big.js';
3
3
  export class ParamDefinition {
4
4
  paramName;
@@ -1,4 +1,4 @@
1
- import { PinTypes } from './PinTypes.mjs';
1
+ import { PinTypes } from './PinTypes.js';
2
2
  export class PinDefinition {
3
3
  id;
4
4
  idType;