circuitscript 0.1.20 → 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 (45) 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/helpers.js +21 -4
  9. package/dist/cjs/lexer.js +21 -9
  10. package/dist/cjs/main.js +13 -0
  11. package/dist/cjs/objects/ClassComponent.js +4 -1
  12. package/dist/cjs/objects/ExecutionScope.js +1 -0
  13. package/dist/cjs/parser.js +1 -0
  14. package/dist/cjs/visitor.js +119 -71
  15. package/dist/esm/BaseVisitor.js +22 -0
  16. package/dist/esm/ComponentAnnotater.js +84 -0
  17. package/dist/esm/RefdesAnnotationVisitor.js +196 -0
  18. package/dist/esm/antlr/CircuitScriptLexer.js +202 -197
  19. package/dist/esm/antlr/CircuitScriptParser.js +960 -829
  20. package/dist/esm/antlr/CircuitScriptVisitor.js +2 -0
  21. package/dist/esm/environment.js +15 -1
  22. package/dist/esm/execute.js +45 -2
  23. package/dist/esm/helpers.js +21 -4
  24. package/dist/esm/lexer.js +21 -9
  25. package/dist/esm/main.js +13 -0
  26. package/dist/esm/objects/ClassComponent.js +4 -1
  27. package/dist/esm/objects/ExecutionScope.js +1 -0
  28. package/dist/esm/parser.js +1 -0
  29. package/dist/esm/visitor.js +117 -69
  30. package/dist/types/BaseVisitor.d.ts +3 -0
  31. package/dist/types/ComponentAnnotater.d.ts +16 -0
  32. package/dist/types/RefdesAnnotationVisitor.d.ts +35 -0
  33. package/dist/types/antlr/CircuitScriptLexer.d.ts +15 -14
  34. package/dist/types/antlr/CircuitScriptParser.d.ts +80 -60
  35. package/dist/types/antlr/CircuitScriptVisitor.d.ts +4 -0
  36. package/dist/types/environment.d.ts +1 -0
  37. package/dist/types/execute.d.ts +8 -1
  38. package/dist/types/helpers.d.ts +6 -3
  39. package/dist/types/lexer.d.ts +1 -1
  40. package/dist/types/objects/ClassComponent.d.ts +9 -0
  41. package/dist/types/objects/ExecutionScope.d.ts +2 -1
  42. package/dist/types/objects/types.d.ts +1 -0
  43. package/dist/types/parser.d.ts +2 -1
  44. package/dist/types/visitor.d.ts +8 -1
  45. 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!";
@@ -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 => {
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,
@@ -10,7 +10,9 @@ import { BaseVisitor } from './BaseVisitor.js';
10
10
  import { getPortType, RuntimeExecutionError } from './utils.js';
11
11
  import { UnitDimension } from './helpers.js';
12
12
  import { FrameParamKeys } from './objects/Frame.js';
13
+ import { ComponentAnnotater } from './ComponentAnnotater.js';
13
14
  export class ParserVisitor extends BaseVisitor {
15
+ componentCreationIndex = 0;
14
16
  visitKeyword_assignment_expr = (ctx) => {
15
17
  const id = ctx.ID().getText();
16
18
  const value = this.visitResult(ctx.data_expr());
@@ -35,28 +37,53 @@ export class ParserVisitor extends BaseVisitor {
35
37
  }
36
38
  this.setResult(ctx, pinId);
37
39
  };
40
+ trackNewComponentCreated = (callback) => {
41
+ const preCreatedIndex = this.componentCreationIndex;
42
+ callback();
43
+ const postCreatedIndex = this.componentCreationIndex;
44
+ let creationFlag = false;
45
+ if (postCreatedIndex > preCreatedIndex) {
46
+ creationFlag = true;
47
+ }
48
+ return creationFlag;
49
+ };
38
50
  visitAdd_component_expr = (ctx) => {
39
- const [component, pinValue] = this.visitResult(ctx.data_expr_with_assignment());
40
- this.getExecutor().addComponentExisting(component, pinValue);
51
+ let refComponent;
52
+ const creationFlag = this.trackNewComponentCreated(() => {
53
+ const [component, pinValue] = this.visitResult(ctx.data_expr_with_assignment());
54
+ this.getExecutor().addComponentExisting(component, pinValue);
55
+ refComponent = component;
56
+ });
57
+ this.linkComponentToCtx(ctx, refComponent, creationFlag);
41
58
  };
42
59
  visitAt_component_expr = (ctx) => {
43
- const [component, pin] = this.visitResult(ctx.component_select_expr());
44
- this.getExecutor().atComponent(component, pin, {
45
- addSequence: true
60
+ let refComponent;
61
+ const creationFlag = this.trackNewComponentCreated(() => {
62
+ const [component, pin] = this.visitResult(ctx.component_select_expr());
63
+ this.getExecutor().atComponent(component, pin, {
64
+ addSequence: true
65
+ });
66
+ refComponent = component;
46
67
  });
68
+ this.linkComponentToCtx(ctx, refComponent, creationFlag);
47
69
  return this.getExecutor().getCurrentPoint();
48
70
  };
49
71
  visitTo_component_expr = (ctx) => {
50
72
  ctx.component_select_expr().forEach(item => {
51
- const [component, pin] = this.visitResult(item);
52
- try {
53
- this.getExecutor().toComponent(component, pin, {
54
- addSequence: true
55
- });
56
- }
57
- catch (err) {
58
- throw new RuntimeExecutionError(err.message, ctx);
59
- }
73
+ let refComponent;
74
+ const creationFlag = this.trackNewComponentCreated(() => {
75
+ const [component, pin] = this.visitResult(item);
76
+ try {
77
+ this.getExecutor().toComponent(component, pin, {
78
+ addSequence: true
79
+ });
80
+ refComponent = component;
81
+ }
82
+ catch (err) {
83
+ throw new RuntimeExecutionError(err.message, ctx);
84
+ }
85
+ });
86
+ this.linkComponentToCtx(item, refComponent, creationFlag);
60
87
  });
61
88
  return this.getExecutor().getCurrentPoint();
62
89
  };
@@ -327,6 +354,7 @@ export class ParserVisitor extends BaseVisitor {
327
354
  try {
328
355
  const createdComponent = this.getExecutor().createComponent(instanceName, pins, params, props);
329
356
  this.setResult(ctx, createdComponent);
357
+ createdComponent._creationIndex = this.componentCreationIndex++;
330
358
  }
331
359
  catch (error) {
332
360
  this.throwWithContext(ctx, error.message);
@@ -867,7 +895,28 @@ export class ParserVisitor extends BaseVisitor {
867
895
  const resolveNet = this.createNetResolver(this.executionStack);
868
896
  const resolveComponentPinNet = this.createComponentPinNetResolver(this.executionStack);
869
897
  const __runFunc = (passedInParameters, options) => {
870
- const executionContextName = `${functionName}-${functionCounter['counter']}`;
898
+ const executor = this.getExecutor();
899
+ const parentBreakContext = executor.getParentBreakContext();
900
+ executor.addBreakContext(ctx);
901
+ let useIndex = -1;
902
+ if (parentBreakContext === null) {
903
+ useIndex = options.functionCallIndex;
904
+ }
905
+ else {
906
+ const parentEntry = executor.indexedStack.get(parentBreakContext);
907
+ const { funcCallIndex } = parentEntry;
908
+ if (!funcCallIndex.has(ctx)) {
909
+ funcCallIndex.set(ctx, 0);
910
+ useIndex = 0;
911
+ }
912
+ else {
913
+ useIndex = funcCallIndex.get(ctx) + 1;
914
+ funcCallIndex.set(ctx, useIndex);
915
+ }
916
+ }
917
+ executor.setBreakContextIndex(useIndex);
918
+ const functionCounterIndex = functionCounter['counter'];
919
+ const executionContextName = `${functionName}-${functionCounterIndex}`;
871
920
  const newExecutor = this.enterNewChildContext(executionStack, this.getExecutor(), executionContextName, options, funcDefinedParameters, passedInParameters);
872
921
  functionCounter['counter'] += 1;
873
922
  newExecutor.resolveNet = resolveNet;
@@ -875,7 +924,23 @@ export class ParserVisitor extends BaseVisitor {
875
924
  const returnValue = this.runExpressions(newExecutor, ctx.function_expr());
876
925
  const lastExecution = executionStack.pop();
877
926
  const nextLastExecution = executionStack[executionStack.length - 1];
878
- nextLastExecution.mergeScope(lastExecution.scope, executionContextName);
927
+ const mergedComponents = nextLastExecution.mergeScope(lastExecution.scope, executionContextName);
928
+ const scope = this.getScope();
929
+ const indexedStack = [];
930
+ if (scope.breakStack.length > 0) {
931
+ const executor = this.getExecutor();
932
+ scope.breakStack.forEach(stackCtx => {
933
+ const entry = executor.indexedStack.get(stackCtx);
934
+ const { index } = entry;
935
+ indexedStack.push([stackCtx, index]);
936
+ });
937
+ mergedComponents.forEach(component => {
938
+ component.ctxReferences.forEach(ref => {
939
+ ref.indexedStack = [...indexedStack, ...ref.indexedStack];
940
+ });
941
+ });
942
+ }
943
+ executor.popBreakContext();
879
944
  return [lastExecution, returnValue];
880
945
  };
881
946
  this.getExecutor().createFunction(functionName, __runFunc, ctx, uniqueFunctionID);
@@ -919,10 +984,18 @@ export class ParserVisitor extends BaseVisitor {
919
984
  executor.log('end at block pin expressions');
920
985
  executor.atComponent(currentComponent, currentPin);
921
986
  };
987
+ visitAt_block_header = (ctx) => {
988
+ const ctxAtComponent = ctx.at_component_expr();
989
+ this.visit(ctxAtComponent);
990
+ const [currentComponent,] = this.getExecutor().getCurrentPoint();
991
+ this.componentCtxLinks.delete(ctxAtComponent);
992
+ this.componentCtxLinks.set(ctx, currentComponent);
993
+ };
922
994
  visitAt_block = (ctx) => {
923
995
  const executor = this.getExecutor();
924
996
  executor.log('entering at block');
925
- this.visit(ctx.at_component_expr());
997
+ const ctxAtBlockComponent = ctx.at_block_header();
998
+ this.visit(ctxAtBlockComponent);
926
999
  const [currentComponent, currentPin] = executor.getCurrentPoint();
927
1000
  executor.scope.scopeLevel += 1;
928
1001
  ctx.at_block_expressions().forEach(expression => {
@@ -1082,10 +1155,14 @@ export class ParserVisitor extends BaseVisitor {
1082
1155
  const dataExpr = ctx.data_expr();
1083
1156
  let keepLooping = true;
1084
1157
  this.log('enter while loop');
1085
- this.getExecutor().addBreakContext(ctx);
1158
+ const executor = this.getExecutor();
1159
+ executor.addBreakContext(ctx);
1160
+ let counter = 0;
1086
1161
  while (keepLooping) {
1087
1162
  const result = this.visitResult(dataExpr);
1088
1163
  if (result) {
1164
+ executor.setBreakContextIndex(counter);
1165
+ executor.resetBreakContextFunctionCalls();
1089
1166
  this.visit(ctx.expressions_block());
1090
1167
  keepLooping = true;
1091
1168
  const currentResult = this.getResult(ctx) ?? {};
@@ -1100,6 +1177,7 @@ export class ParserVisitor extends BaseVisitor {
1100
1177
  continueSignal: false
1101
1178
  });
1102
1179
  }
1180
+ counter++;
1103
1181
  }
1104
1182
  else {
1105
1183
  keepLooping = false;
@@ -1113,7 +1191,8 @@ export class ParserVisitor extends BaseVisitor {
1113
1191
  const forVariableNames = ctx.ID().map(item => item.getText());
1114
1192
  let listItems = this.visitResult(ctx.data_expr());
1115
1193
  listItems = unwrapValue(listItems);
1116
- this.getExecutor().addBreakContext(ctx);
1194
+ const executor = this.getExecutor();
1195
+ executor.addBreakContext(ctx);
1117
1196
  let keepLooping = true;
1118
1197
  let counter = 0;
1119
1198
  while (keepLooping) {
@@ -1125,6 +1204,8 @@ export class ParserVisitor extends BaseVisitor {
1125
1204
  useValueArray.forEach((value, index) => {
1126
1205
  this.getScope().setVariable(forVariableNames[index], value);
1127
1206
  });
1207
+ executor.setBreakContextIndex(counter);
1208
+ executor.resetBreakContextFunctionCalls();
1128
1209
  this.visit(ctx.expressions_block());
1129
1210
  keepLooping = true;
1130
1211
  const currentResult = this.getResult(ctx) ?? {};
@@ -1146,7 +1227,19 @@ export class ParserVisitor extends BaseVisitor {
1146
1227
  keepLooping = false;
1147
1228
  }
1148
1229
  }
1149
- this.getExecutor().popBreakContext();
1230
+ executor.popBreakContext();
1231
+ };
1232
+ visitAnnotation_comment_expr = (ctx) => {
1233
+ const refdesID = ctx.ID().getText();
1234
+ const currentComponent = this.getScope().currentComponent;
1235
+ if (currentComponent !== null) {
1236
+ if (refdesID.indexOf('_') === -1) {
1237
+ currentComponent.setParam('refdes', refdesID);
1238
+ }
1239
+ else {
1240
+ currentComponent.placeHolderRefDes = refdesID;
1241
+ }
1242
+ }
1150
1243
  };
1151
1244
  resolveDataExpr(data_expr) {
1152
1245
  const value = this.visitResult(data_expr);
@@ -1349,8 +1442,8 @@ export class ParserVisitor extends BaseVisitor {
1349
1442
  continue;
1350
1443
  }
1351
1444
  if (instance.assignedRefDes === null) {
1352
- if (instance.parameters.has('refdes')) {
1353
- const refdes = instance.parameters.get('refdes');
1445
+ if (instance.hasParam('refdes')) {
1446
+ const refdes = instance.getParam('refdes');
1354
1447
  if (refdes) {
1355
1448
  instance.assignedRefDes = refdes;
1356
1449
  annotater.trackRefDes(refdes);
@@ -1362,10 +1455,7 @@ export class ParserVisitor extends BaseVisitor {
1362
1455
  }
1363
1456
  }
1364
1457
  toAnnotate.forEach(instance => {
1365
- const useTypeProp = instance.typeProp ?? 'conn';
1366
- instance.typeProp === null
1367
- && this.log('Instance has no type:', instance.instanceName, ' assuming connector');
1368
- const newRefDes = annotater.getAnnotation(useTypeProp);
1458
+ const newRefDes = annotater.getAnnotation(instance);
1369
1459
  if (newRefDes !== null) {
1370
1460
  instance.assignedRefDes = newRefDes;
1371
1461
  this.log(newRefDes, '-', instance.instanceName);
@@ -1449,7 +1539,7 @@ export class ParserVisitor extends BaseVisitor {
1449
1539
  return this.warnings;
1450
1540
  }
1451
1541
  }
1452
- const ComponentRefDesPrefixes = {
1542
+ export const ComponentRefDesPrefixes = {
1453
1543
  res: 'R',
1454
1544
  cap: 'C',
1455
1545
  ind: 'L',
@@ -1460,48 +1550,6 @@ const ComponentRefDesPrefixes = {
1460
1550
  ic: 'U',
1461
1551
  '?': '?',
1462
1552
  };
1463
- class ComponentAnnotater {
1464
- counter = {};
1465
- existingRefDes = [];
1466
- constructor() {
1467
- for (const key in ComponentRefDesPrefixes) {
1468
- this.counter[key] = 1;
1469
- }
1470
- }
1471
- getAnnotation(type) {
1472
- if (this.counter[type] === undefined && type.length <= 2) {
1473
- for (const [, value] of Object.entries(ComponentRefDesPrefixes)) {
1474
- if (value === type) {
1475
- throw "Refdes prefix is already in use!";
1476
- }
1477
- }
1478
- if (ComponentRefDesPrefixes[type] === undefined) {
1479
- ComponentRefDesPrefixes[type] = type;
1480
- this.counter[type] = 1;
1481
- }
1482
- }
1483
- if (ComponentRefDesPrefixes[type] === undefined) {
1484
- return null;
1485
- }
1486
- let attempts = 100;
1487
- let proposedName = "";
1488
- while (attempts >= 0) {
1489
- proposedName = ComponentRefDesPrefixes[type] + this.counter[type];
1490
- this.counter[type]++;
1491
- if (this.existingRefDes.indexOf(proposedName) === -1) {
1492
- break;
1493
- }
1494
- attempts--;
1495
- }
1496
- if (attempts === 0) {
1497
- throw "Annotation failed!";
1498
- }
1499
- return proposedName;
1500
- }
1501
- trackRefDes(name) {
1502
- this.existingRefDes.push(name);
1503
- }
1504
- }
1505
1553
  export class VisitorExecutionException {
1506
1554
  errorMessage;
1507
1555
  context;
@@ -21,6 +21,7 @@ export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyR
21
21
  printToConsole: boolean;
22
22
  acceptedDirections: Direction[];
23
23
  protected resultData: Map<ParserRuleContext, any>;
24
+ protected componentCtxLinks: Map<ParserRuleContext, ClassComponent>;
24
25
  pinTypesList: string[];
25
26
  onErrorHandler: OnErrorHandler | null;
26
27
  environment: NodeScriptEnvironment;
@@ -64,6 +65,8 @@ export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyR
64
65
  visitArrayIndexExpr: (ctx: ArrayIndexExprContext) => void;
65
66
  protected setResult(ctx: ParserRuleContext, value: any): void;
66
67
  protected getResult(ctx: ParserRuleContext): any;
68
+ protected linkComponentToCtx(ctx: ParserRuleContext, instance: ClassComponent, creationFlag?: boolean): void;
69
+ getComponentCtxLinks(): Map<ParserRuleContext, ClassComponent>;
67
70
  visitResult(ctx: ParserRuleContext): any;
68
71
  protected handleImportFile(name: string, throwErrors?: boolean, ctx?: ParserRuleContext | null): Promise<ImportFile>;
69
72
  visitRoundedBracketsExpr: (ctx: RoundedBracketsExprContext) => void;