circuitscript 0.1.19 → 0.1.22

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 (50) hide show
  1. package/dist/cjs/BaseVisitor.js +22 -0
  2. package/dist/cjs/ComponentAnnotater.js +88 -0
  3. package/dist/cjs/RefdesAnnotationVisitor.js +197 -0
  4. package/dist/cjs/antlr/CircuitScriptLexer.js +202 -197
  5. package/dist/cjs/antlr/CircuitScriptParser.js +964 -831
  6. package/dist/cjs/environment.js +15 -1
  7. package/dist/cjs/execute.js +45 -2
  8. package/dist/cjs/graph.js +23 -2
  9. package/dist/cjs/helpers.js +21 -4
  10. package/dist/cjs/layout.js +3 -0
  11. package/dist/cjs/lexer.js +21 -9
  12. package/dist/cjs/main.js +13 -0
  13. package/dist/cjs/objects/ClassComponent.js +4 -1
  14. package/dist/cjs/objects/ExecutionScope.js +1 -0
  15. package/dist/cjs/parser.js +1 -0
  16. package/dist/cjs/visitor.js +119 -71
  17. package/dist/esm/BaseVisitor.js +22 -0
  18. package/dist/esm/ComponentAnnotater.js +84 -0
  19. package/dist/esm/RefdesAnnotationVisitor.js +196 -0
  20. package/dist/esm/antlr/CircuitScriptLexer.js +202 -197
  21. package/dist/esm/antlr/CircuitScriptParser.js +960 -829
  22. package/dist/esm/antlr/CircuitScriptVisitor.js +2 -0
  23. package/dist/esm/environment.js +15 -1
  24. package/dist/esm/execute.js +45 -2
  25. package/dist/esm/graph.js +23 -2
  26. package/dist/esm/helpers.js +21 -4
  27. package/dist/esm/layout.js +4 -0
  28. package/dist/esm/lexer.js +21 -9
  29. package/dist/esm/main.js +13 -0
  30. package/dist/esm/objects/ClassComponent.js +4 -1
  31. package/dist/esm/objects/ExecutionScope.js +1 -0
  32. package/dist/esm/parser.js +1 -0
  33. package/dist/esm/visitor.js +117 -69
  34. package/dist/types/BaseVisitor.d.ts +3 -0
  35. package/dist/types/ComponentAnnotater.d.ts +16 -0
  36. package/dist/types/RefdesAnnotationVisitor.d.ts +35 -0
  37. package/dist/types/antlr/CircuitScriptLexer.d.ts +15 -14
  38. package/dist/types/antlr/CircuitScriptParser.d.ts +80 -60
  39. package/dist/types/antlr/CircuitScriptVisitor.d.ts +4 -0
  40. package/dist/types/environment.d.ts +1 -0
  41. package/dist/types/execute.d.ts +8 -1
  42. package/dist/types/helpers.d.ts +6 -3
  43. package/dist/types/layout.d.ts +2 -0
  44. package/dist/types/lexer.d.ts +1 -1
  45. package/dist/types/objects/ClassComponent.d.ts +9 -0
  46. package/dist/types/objects/ExecutionScope.d.ts +2 -1
  47. package/dist/types/objects/types.d.ts +1 -0
  48. package/dist/types/parser.d.ts +2 -1
  49. package/dist/types/visitor.d.ts +8 -1
  50. package/package.json +1 -1
@@ -22,6 +22,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
22
22
  visitAt_to_multiple_line_expr_to_pin;
23
23
  visitAt_block;
24
24
  visitAt_block_expressions;
25
+ visitAt_block_header;
25
26
  visitAt_block_pin_expr;
26
27
  visitAt_block_pin_expression_simple;
27
28
  visitAt_block_pin_expression_complex;
@@ -78,4 +79,5 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
78
79
  visitElse_expr;
79
80
  visitWhile_expr;
80
81
  visitFor_expr;
82
+ visitAnnotation_comment_expr;
81
83
  }
@@ -14,6 +14,7 @@ export class NodeScriptEnvironment {
14
14
  useModuleDirectoryPath = null;
15
15
  useDefaultLibsPath = null;
16
16
  globalCreateSVGWindow = null;
17
+ cachedVersion = null;
17
18
  supportedFonts = {
18
19
  'Arial': 'Arial.ttf',
19
20
  };
@@ -24,7 +25,20 @@ export class NodeScriptEnvironment {
24
25
  this.useDefaultLibsPath = path;
25
26
  }
26
27
  getPackageVersion() {
27
- return TOOL_VERSION;
28
+ if (this.cachedVersion !== null) {
29
+ return this.cachedVersion;
30
+ }
31
+ try {
32
+ const packageJsonPath = path.join(this.getToolsPath(), '../', 'package.json');
33
+ const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
34
+ const packageJson = JSON.parse(packageJsonContent);
35
+ this.cachedVersion = packageJson.version || TOOL_VERSION;
36
+ return this.cachedVersion;
37
+ }
38
+ catch (error) {
39
+ console.warn('Failed to read version from package.json, using fallback version:', error);
40
+ return TOOL_VERSION;
41
+ }
28
42
  }
29
43
  getModuleDirectory() {
30
44
  if (this.useModuleDirectoryPath !== null) {
@@ -28,6 +28,7 @@ export class ExecutionContext {
28
28
  parentContext;
29
29
  componentAngleFollowsWire = true;
30
30
  warnings = [];
31
+ indexedStack = new Map();
31
32
  constructor(name, namespace, netNamespace, executionLevel = 0, scopeLevel = 0, silent = false, logger, warnings, parent) {
32
33
  this.name = name;
33
34
  this.namespace = namespace;
@@ -547,9 +548,39 @@ export class ExecutionContext {
547
548
  this.log('did not find block point');
548
549
  return null;
549
550
  }
551
+ getParentBreakContext() {
552
+ if (this.scope.breakStack.length > 0) {
553
+ return this.scope.breakStack[this.scope.breakStack.length - 1];
554
+ }
555
+ return null;
556
+ }
550
557
  addBreakContext(ctx) {
551
558
  this.log('add break context');
552
559
  this.scope.breakStack.push(ctx);
560
+ this.indexedStack.set(ctx, {
561
+ index: 0,
562
+ funcCallIndex: new Map(),
563
+ });
564
+ }
565
+ setBreakContextIndex(index) {
566
+ const latestCtx = this.scope.breakStack[this.scope.breakStack.length - 1];
567
+ if (latestCtx) {
568
+ const current = this.indexedStack.get(latestCtx);
569
+ this.indexedStack.set(latestCtx, {
570
+ ...current,
571
+ index,
572
+ });
573
+ }
574
+ }
575
+ resetBreakContextFunctionCalls() {
576
+ const latestCtx = this.scope.breakStack[this.scope.breakStack.length - 1];
577
+ if (latestCtx) {
578
+ const current = this.indexedStack.get(latestCtx);
579
+ this.indexedStack.set(latestCtx, {
580
+ index: current.index,
581
+ funcCallIndex: new Map(),
582
+ });
583
+ }
553
584
  }
554
585
  popBreakContext() {
555
586
  this.log('pop break context');
@@ -672,9 +703,18 @@ export class ExecutionContext {
672
703
  __runFunc = this.__functionCache.get(functionName);
673
704
  }
674
705
  if (__runFunc !== null) {
706
+ let functionCallIndex = -1;
707
+ if (!this.scope.functionCounter.has(__runFunc)) {
708
+ this.scope.functionCounter.set(__runFunc, 0);
709
+ functionCallIndex = 0;
710
+ }
711
+ else {
712
+ functionCallIndex = this.scope.functionCounter.get(__runFunc);
713
+ }
714
+ this.scope.functionCounter.set(__runFunc, functionCallIndex + 1);
675
715
  this.log(`call function '${functionName}'`);
676
716
  this.log(`net namespace: ${netNamespace}`);
677
- const functionResult = __runFunc(functionParams, { netNamespace });
717
+ const functionResult = __runFunc(functionParams, { netNamespace, functionCallIndex });
678
718
  this.log(`done call function '${functionName}'`);
679
719
  return functionResult;
680
720
  }
@@ -687,6 +727,7 @@ export class ExecutionContext {
687
727
  const { currentComponent, currentPin, currentWireId } = this.scope;
688
728
  const tmpInstances = childScope.instances;
689
729
  const tmpNets = childScope.getNets();
730
+ const mergedInstances = [];
690
731
  for (const [instanceName, component] of tmpInstances) {
691
732
  const newInstanceName = `${namespace}.${instanceName}`;
692
733
  component.instanceName = newInstanceName;
@@ -699,6 +740,7 @@ export class ExecutionContext {
699
740
  else {
700
741
  throw "Invalid instance name to merge into parent scope!";
701
742
  }
743
+ mergedInstances.push(component);
702
744
  }
703
745
  const childScopeUniqueNets = new Set(tmpNets.map(([, , net]) => net));
704
746
  childScopeUniqueNets.forEach(net => {
@@ -772,6 +814,7 @@ export class ExecutionContext {
772
814
  return accum;
773
815
  }, []);
774
816
  this.log('-- done merging scope --');
817
+ return mergedInstances;
775
818
  }
776
819
  addWire(segments) {
777
820
  if (this.scope.currentComponent === null) {
@@ -895,7 +938,7 @@ export class ExecutionContext {
895
938
  idName = this.scope.currentComponent.instanceName;
896
939
  if (this.scope.instances.has(idName)) {
897
940
  const component = this.scope.instances.get(idName);
898
- component.parameters.set(paramName, value);
941
+ component.setParam(paramName, value);
899
942
  }
900
943
  else if (this.scope.variables.has(idName)) {
901
944
  throw "Not implemented yet!";
package/dist/esm/graph.js CHANGED
@@ -26,6 +26,7 @@ export class NetGraph {
26
26
  const baseFrame = new RenderFrame(new Frame(FixedFrameIds.BaseFrame));
27
27
  const frameStack = [baseFrame];
28
28
  const containerFrames = [baseFrame];
29
+ const nodeFrames = new Map();
29
30
  sequence.forEach((sequenceStep, index) => {
30
31
  const action = sequenceStep[0];
31
32
  let tmpComponent;
@@ -35,6 +36,10 @@ export class NetGraph {
35
36
  this.print(...sequenceStep);
36
37
  const [, component, pin] = sequenceStep;
37
38
  const tmpInstanceName = component.instanceName;
39
+ if (action === SequenceAction.At) {
40
+ previousNode = null;
41
+ previousPin = null;
42
+ }
38
43
  if (!graph.hasNode(tmpInstanceName)) {
39
44
  this.print('create instance', tmpInstanceName);
40
45
  const { displayProp = null } = component;
@@ -58,8 +63,15 @@ export class NetGraph {
58
63
  tmpComponent = new RenderComponent(component, useWidth, useHeight);
59
64
  tmpComponent.symbol = tmpSymbol;
60
65
  graph.setNode(tmpInstanceName, [RenderItemType.Component, tmpComponent, index]);
61
- const currentFrame = frameStack[frameStack.length - 1];
62
- currentFrame && currentFrame.innerItems.push(tmpComponent);
66
+ let useFrame = frameStack[frameStack.length - 1];
67
+ if (nodeFrames.has(previousNode)) {
68
+ const previousNodeFrame = nodeFrames.get(previousNode);
69
+ if (previousNodeFrame !== useFrame) {
70
+ useFrame = previousNodeFrame;
71
+ }
72
+ }
73
+ useFrame && useFrame.innerItems.push(tmpComponent);
74
+ nodeFrames.set(tmpInstanceName, useFrame);
63
75
  }
64
76
  if (action === SequenceAction.To && previousNode && previousPin) {
65
77
  this.setGraphEdge(graph, previousNode, tmpInstanceName, makeEdgeValue(previousNode, previousPin, tmpInstanceName, pin, index));
@@ -91,6 +103,7 @@ export class NetGraph {
91
103
  wire.netName = useNet.toString();
92
104
  const wireName = getWireName(wire.id);
93
105
  graph.setNode(wireName, [RenderItemType.Wire, wire, index]);
106
+ let tmpPreviousNode = previousNode;
94
107
  this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, index));
95
108
  previousNode = wireName;
96
109
  previousPin = 1;
@@ -107,6 +120,14 @@ export class NetGraph {
107
120
  }
108
121
  return tmp;
109
122
  });
123
+ let useFrame = frameStack[frameStack.length - 1];
124
+ if (nodeFrames.has(tmpPreviousNode)) {
125
+ const previousNodeFrame = nodeFrames.get(tmpPreviousNode);
126
+ if (previousNodeFrame !== useFrame) {
127
+ useFrame = previousNodeFrame;
128
+ }
129
+ }
130
+ nodeFrames.set(wireName, useFrame);
110
131
  this.print(SequenceAction.Wire, wireId, JSON.stringify(wireSegmentsInfo));
111
132
  break;
112
133
  }
@@ -18,6 +18,7 @@ import { FrameParamKeys } from "./objects/Frame.js";
18
18
  import Big from "big.js";
19
19
  import { Logger } from "./logger.js";
20
20
  import { NetGraph } from "./graph.js";
21
+ import { RefdesAnnotationVisitor } from "./RefdesAnnotationVisitor.js";
21
22
  export var JSModuleType;
22
23
  (function (JSModuleType) {
23
24
  JSModuleType["CommonJs"] = "cjs";
@@ -154,7 +155,7 @@ export async function renderScript(scriptData, outputPath, options) {
154
155
  return renderScriptCustom(scriptData, outputPath, options, parseHandlers);
155
156
  }
156
157
  export async function renderScriptCustom(scriptData, outputPath, options, parseHandlers) {
157
- const { dumpNets = false, dumpData = false, showStats = false, environment } = options;
158
+ const { dumpNets = false, dumpData = false, showStats = false, environment, inputPath = null, updateSource = false, saveAnnotatedCopy = undefined, } = options;
158
159
  const errors = [];
159
160
  const onErrorHandler = (message, context, error) => {
160
161
  if (error && error instanceof RuntimeExecutionError) {
@@ -198,7 +199,7 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
198
199
  mkdirSync(dumpDirectory);
199
200
  }
200
201
  }
201
- const { tree, parser, parserTimeTaken, lexerTimeTaken, throwError } = await parseFileWithVisitor(visitor, scriptData);
202
+ const { tree, parser, tokens, parserTimeTaken, lexerTimeTaken, throwError } = await parseFileWithVisitor(visitor, scriptData);
202
203
  printWarnings(visitor.getWarnings());
203
204
  showStats && console.log('Lexing took:', lexerTimeTaken);
204
205
  showStats && console.log('Parsing took:', parserTimeTaken);
@@ -208,6 +209,22 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
208
209
  catch (err) {
209
210
  throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
210
211
  }
212
+ const componentLinks = visitor.getComponentCtxLinks();
213
+ const refdesVisitor = new RefdesAnnotationVisitor(true, scriptData, tokens, componentLinks);
214
+ await refdesVisitor.visitAsync(tree);
215
+ if (inputPath && (updateSource || saveAnnotatedCopy !== undefined)) {
216
+ let usePath = inputPath;
217
+ if (saveAnnotatedCopy === true) {
218
+ const dir = path.dirname(inputPath);
219
+ const ext = path.extname(inputPath);
220
+ const basename = path.basename(inputPath, ext);
221
+ usePath = path.join(dir, `${basename}.annotated${ext}`);
222
+ }
223
+ else if (typeof saveAnnotatedCopy === 'string') {
224
+ usePath = saveAnnotatedCopy;
225
+ }
226
+ writeFileSync(usePath, refdesVisitor.getOutput());
227
+ }
211
228
  if (dumpNets) {
212
229
  const nets = visitor.dumpNets();
213
230
  nets.forEach(item => console.log(item.join(" | ")));
@@ -326,8 +343,8 @@ export class ParseOutputHandler {
326
343
  afterRender = false;
327
344
  }
328
345
  export class KiCadNetListOutputHandler extends ParseOutputHandler {
329
- beforeRender = true;
330
- parse(visitor, outputPath, fileExtension) {
346
+ afterRender = true;
347
+ parse(visitor, outputPath, fileExtension, extra = null) {
331
348
  if (outputPath !== null && fileExtension === "net") {
332
349
  const { tree: kiCadNetList, missingFootprints } = generateKiCadNetList(visitor.getNetList());
333
350
  missingFootprints.forEach(entry => {
@@ -1219,6 +1219,7 @@ export class RenderText extends RenderObject {
1219
1219
  }
1220
1220
  }
1221
1221
  export class RenderFrame extends RenderObject {
1222
+ static FrameIdCounter = 0;
1222
1223
  bounds = null;
1223
1224
  frame;
1224
1225
  innerItems = [];
@@ -1233,10 +1234,13 @@ export class RenderFrame extends RenderObject {
1233
1234
  subgraphId = "";
1234
1235
  renderType;
1235
1236
  containsTitle = false;
1237
+ frameId;
1236
1238
  constructor(frame, type = RenderFrameType.Container) {
1237
1239
  super();
1238
1240
  this.frame = frame;
1239
1241
  this.renderType = type;
1242
+ this.frameId = RenderFrame.FrameIdCounter;
1243
+ RenderFrame.FrameIdCounter++;
1240
1244
  }
1241
1245
  toString() {
1242
1246
  let name = "";
package/dist/esm/lexer.js CHANGED
@@ -26,12 +26,14 @@ export class MainLexer extends CircuitScriptLexer {
26
26
  this.tokens = this.tokens.filter(function (val) {
27
27
  return val.type !== CircuitScriptParser.EOF;
28
28
  });
29
- this.emitToken(this.commonToken(CircuitScriptParser.NEWLINE, "\n"));
29
+ const fillerNewLine = this.commonToken(CircuitScriptParser.NEWLINE, "");
30
+ this.emitToken(fillerNewLine);
31
+ fillerNewLine.__skip = true;
30
32
  while (this.indents.length) {
31
33
  this.emitToken(this.createDedent());
32
34
  this.indents.pop();
33
35
  }
34
- this.emitToken(this.commonToken(CircuitScriptParser.EOF, "<EOF>"));
36
+ this.emitToken(this.commonToken(CircuitScriptParser.EOF, ""));
35
37
  }
36
38
  const next = super.nextToken();
37
39
  return this.tokens.length ? this.tokens.shift() : next;
@@ -42,16 +44,24 @@ export class MainLexer extends CircuitScriptLexer {
42
44
  getCharIndex() {
43
45
  return this.inputStream.index;
44
46
  }
45
- commonToken(type, text) {
46
- const stop = this.getCharIndex() - 1;
47
- const start = text.length ? stop - text.length + 1 : stop;
47
+ commonToken(type, text, start = -1, stop = -1) {
48
+ if (start === -1 && stop === -1) {
49
+ stop = this.getCharIndex() - 1;
50
+ start = text.length ? stop - text.length + 1 : stop;
51
+ }
48
52
  const token = CommonToken.fromSource([this, this.inputStream], type, 0, start, stop);
49
53
  let tokenTypeString = null;
50
54
  if (type === CircuitScriptParser.INDENT) {
51
- tokenTypeString = "indent";
55
+ tokenTypeString = 'indent';
52
56
  }
53
57
  else if (type === CircuitScriptParser.DEDENT) {
54
- tokenTypeString = "dedent";
58
+ tokenTypeString = 'dedent';
59
+ }
60
+ else if (type === CircuitScriptParser.NEWLINE) {
61
+ tokenTypeString = 'newline';
62
+ }
63
+ else if (type === CircuitScriptParser.EOF) {
64
+ tokenTypeString = 'EOF';
55
65
  }
56
66
  if (tokenTypeString !== null) {
57
67
  token.text = tokenTypeString;
@@ -89,7 +99,9 @@ export class MainLexer extends CircuitScriptLexer {
89
99
  this.skip();
90
100
  }
91
101
  else {
92
- this.emitToken(this.commonToken(CircuitScriptParser.NEWLINE, newLine));
102
+ const start = this.getCharIndex() - this.text.length;
103
+ const stop = this.getCharIndex() - 1;
104
+ this.emitToken(this.commonToken(CircuitScriptParser.NEWLINE, newLine, start, start));
93
105
  const indent = this.getIndentationCount(spaces);
94
106
  const previous = this.indents.length ? this.indents[this.indents.length - 1] : 0;
95
107
  if (indent === previous) {
@@ -97,7 +109,7 @@ export class MainLexer extends CircuitScriptLexer {
97
109
  }
98
110
  else if (indent > previous) {
99
111
  this.indents.push(indent);
100
- this.emitToken(this.commonToken(CircuitScriptParser.INDENT, spaces));
112
+ this.emitToken(this.commonToken(CircuitScriptParser.INDENT, spaces, start + 1, stop));
101
113
  }
102
114
  else {
103
115
  while (this.indents.length && this.indents[this.indents.length - 1] > indent) {
package/dist/esm/main.js CHANGED
@@ -15,6 +15,8 @@ export default async function main() {
15
15
  .argument('[output path]', 'Output path')
16
16
  .option('-i, --input text <input text>', 'Input text directly')
17
17
  .option('-c, --current-directory <path>', 'Set current directory')
18
+ .option('-u, --update-source', 'Update source file with refdes annotation')
19
+ .option('-j, --annotated-path [file-path]', 'Save annotated source file at given path')
18
20
  .option('-w, --watch', 'Watch for file changes')
19
21
  .option('-n, --dump-nets', 'Dump out net information')
20
22
  .option('-d, --dump-data', 'Dump data during parsing')
@@ -62,11 +64,22 @@ export default async function main() {
62
64
  console.error("Error: No input provided");
63
65
  return;
64
66
  }
67
+ let updateSource = false;
68
+ if (options.updateSource !== undefined) {
69
+ updateSource = options.updateSource;
70
+ }
71
+ let saveAnnotatedCopyPath = undefined;
72
+ if (options.annotatedPath !== undefined) {
73
+ saveAnnotatedCopyPath = options.annotatedPath;
74
+ }
65
75
  const scriptOptions = {
66
76
  dumpNets,
67
77
  dumpData,
68
78
  showStats: options.stats,
69
79
  environment: env,
80
+ inputPath: inputFilePath,
81
+ updateSource,
82
+ saveAnnotatedCopy: saveAnnotatedCopyPath,
70
83
  };
71
84
  let outputPath = null;
72
85
  if (args.length > 0 && args[1]) {
@@ -29,6 +29,9 @@ export class ClassComponent {
29
29
  useWireOrientationAngle = true;
30
30
  didSetWireOrientationAngle = false;
31
31
  assignedRefDes = null;
32
+ placeHolderRefDes = null;
33
+ ctxReferences = [];
34
+ _creationIndex = -1;
32
35
  constructor(instanceName, numPins) {
33
36
  this.instanceName = instanceName;
34
37
  this.numPins = numPins;
@@ -108,7 +111,7 @@ export class ClassComponent {
108
111
  return this.parameters.get(key);
109
112
  }
110
113
  else {
111
- throw 'Invalid parameter key';
114
+ throw 'Invalid parameter key: ' + key;
112
115
  }
113
116
  }
114
117
  toString() {
@@ -6,6 +6,7 @@ export class ExecutionScope {
6
6
  nets = [];
7
7
  instances = new Map();
8
8
  functions = new Map();
9
+ functionCounter = new Map();
9
10
  variables = new Map();
10
11
  symbols = new Map();
11
12
  blockStack = new Map();
@@ -35,6 +35,7 @@ export async function parseFileWithVisitor(visitor, data) {
35
35
  const parserTimeTaken = parserTimer.lap();
36
36
  return {
37
37
  tree, parser,
38
+ tokens,
38
39
  hasParseError: false,
39
40
  hasError: false,
40
41
  parserTimeTaken,