circuitscript 0.1.20 → 0.1.23

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 +975 -833
  6. package/dist/cjs/environment.js +15 -1
  7. package/dist/cjs/execute.js +45 -2
  8. package/dist/cjs/helpers.js +20 -2
  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 +122 -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 +971 -831
  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 +20 -2
  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 +120 -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 +81 -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 +4 -1
  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,23 @@ 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
+ console.log('Annotations saved to ' + usePath);
227
+ writeFileSync(usePath, refdesVisitor.getOutput());
228
+ }
211
229
  if (dumpNets) {
212
230
  const nets = visitor.dumpNets();
213
231
  nets.forEach(item => console.log(item.join(" | ")));
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,21 @@ 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
+ ctx.annotation_comment_expr().forEach(ctx => {
994
+ this.visit(ctx);
995
+ });
996
+ };
922
997
  visitAt_block = (ctx) => {
923
998
  const executor = this.getExecutor();
924
999
  executor.log('entering at block');
925
- this.visit(ctx.at_component_expr());
1000
+ const ctxAtBlockComponent = ctx.at_block_header();
1001
+ this.visit(ctxAtBlockComponent);
926
1002
  const [currentComponent, currentPin] = executor.getCurrentPoint();
927
1003
  executor.scope.scopeLevel += 1;
928
1004
  ctx.at_block_expressions().forEach(expression => {
@@ -1082,10 +1158,14 @@ export class ParserVisitor extends BaseVisitor {
1082
1158
  const dataExpr = ctx.data_expr();
1083
1159
  let keepLooping = true;
1084
1160
  this.log('enter while loop');
1085
- this.getExecutor().addBreakContext(ctx);
1161
+ const executor = this.getExecutor();
1162
+ executor.addBreakContext(ctx);
1163
+ let counter = 0;
1086
1164
  while (keepLooping) {
1087
1165
  const result = this.visitResult(dataExpr);
1088
1166
  if (result) {
1167
+ executor.setBreakContextIndex(counter);
1168
+ executor.resetBreakContextFunctionCalls();
1089
1169
  this.visit(ctx.expressions_block());
1090
1170
  keepLooping = true;
1091
1171
  const currentResult = this.getResult(ctx) ?? {};
@@ -1100,6 +1180,7 @@ export class ParserVisitor extends BaseVisitor {
1100
1180
  continueSignal: false
1101
1181
  });
1102
1182
  }
1183
+ counter++;
1103
1184
  }
1104
1185
  else {
1105
1186
  keepLooping = false;
@@ -1113,7 +1194,8 @@ export class ParserVisitor extends BaseVisitor {
1113
1194
  const forVariableNames = ctx.ID().map(item => item.getText());
1114
1195
  let listItems = this.visitResult(ctx.data_expr());
1115
1196
  listItems = unwrapValue(listItems);
1116
- this.getExecutor().addBreakContext(ctx);
1197
+ const executor = this.getExecutor();
1198
+ executor.addBreakContext(ctx);
1117
1199
  let keepLooping = true;
1118
1200
  let counter = 0;
1119
1201
  while (keepLooping) {
@@ -1125,6 +1207,8 @@ export class ParserVisitor extends BaseVisitor {
1125
1207
  useValueArray.forEach((value, index) => {
1126
1208
  this.getScope().setVariable(forVariableNames[index], value);
1127
1209
  });
1210
+ executor.setBreakContextIndex(counter);
1211
+ executor.resetBreakContextFunctionCalls();
1128
1212
  this.visit(ctx.expressions_block());
1129
1213
  keepLooping = true;
1130
1214
  const currentResult = this.getResult(ctx) ?? {};
@@ -1146,7 +1230,19 @@ export class ParserVisitor extends BaseVisitor {
1146
1230
  keepLooping = false;
1147
1231
  }
1148
1232
  }
1149
- this.getExecutor().popBreakContext();
1233
+ executor.popBreakContext();
1234
+ };
1235
+ visitAnnotation_comment_expr = (ctx) => {
1236
+ const refdesID = ctx.ID().getText();
1237
+ const currentComponent = this.getScope().currentComponent;
1238
+ if (currentComponent !== null) {
1239
+ if (refdesID.indexOf('_') === -1) {
1240
+ currentComponent.setParam('refdes', refdesID);
1241
+ }
1242
+ else {
1243
+ currentComponent.placeHolderRefDes = refdesID;
1244
+ }
1245
+ }
1150
1246
  };
1151
1247
  resolveDataExpr(data_expr) {
1152
1248
  const value = this.visitResult(data_expr);
@@ -1349,8 +1445,8 @@ export class ParserVisitor extends BaseVisitor {
1349
1445
  continue;
1350
1446
  }
1351
1447
  if (instance.assignedRefDes === null) {
1352
- if (instance.parameters.has('refdes')) {
1353
- const refdes = instance.parameters.get('refdes');
1448
+ if (instance.hasParam('refdes')) {
1449
+ const refdes = instance.getParam('refdes');
1354
1450
  if (refdes) {
1355
1451
  instance.assignedRefDes = refdes;
1356
1452
  annotater.trackRefDes(refdes);
@@ -1362,10 +1458,7 @@ export class ParserVisitor extends BaseVisitor {
1362
1458
  }
1363
1459
  }
1364
1460
  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);
1461
+ const newRefDes = annotater.getAnnotation(instance);
1369
1462
  if (newRefDes !== null) {
1370
1463
  instance.assignedRefDes = newRefDes;
1371
1464
  this.log(newRefDes, '-', instance.instanceName);
@@ -1449,7 +1542,7 @@ export class ParserVisitor extends BaseVisitor {
1449
1542
  return this.warnings;
1450
1543
  }
1451
1544
  }
1452
- const ComponentRefDesPrefixes = {
1545
+ export const ComponentRefDesPrefixes = {
1453
1546
  res: 'R',
1454
1547
  cap: 'C',
1455
1548
  ind: 'L',
@@ -1460,48 +1553,6 @@ const ComponentRefDesPrefixes = {
1460
1553
  ic: 'U',
1461
1554
  '?': '?',
1462
1555
  };
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
1556
  export class VisitorExecutionException {
1506
1557
  errorMessage;
1507
1558
  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;
@@ -0,0 +1,16 @@
1
+ import { ParserRuleContext } from 'antlr4ng';
2
+ import { ClassComponent } from './objects/ClassComponent.js';
3
+ export declare class ComponentAnnotater {
4
+ counter: {
5
+ [key: string]: number;
6
+ };
7
+ indexedContextPrefix: Map<ParserRuleContext, string>;
8
+ existingRefDes: string[];
9
+ constructor();
10
+ getAnnotation(instance: ClassComponent): string | null;
11
+ getNextRefdesCounter(prefix: string, startingIndex: number): {
12
+ index: number;
13
+ proposedName: string;
14
+ };
15
+ trackRefDes(name: string): void;
16
+ }