circuitscript 0.1.29 → 0.1.32

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 (71) hide show
  1. package/dist/cjs/BaseVisitor.js +185 -22
  2. package/dist/cjs/RefdesAnnotationVisitor.js +27 -10
  3. package/dist/cjs/antlr/CircuitScriptLexer.js +241 -236
  4. package/dist/cjs/antlr/CircuitScriptParser.js +1197 -901
  5. package/dist/cjs/builtinMethods.js +6 -2
  6. package/dist/cjs/draw_symbols.js +38 -34
  7. package/dist/cjs/environment.js +28 -4
  8. package/dist/cjs/execute.js +195 -125
  9. package/dist/cjs/globals.js +6 -1
  10. package/dist/cjs/graph.js +14 -12
  11. package/dist/cjs/helpers.js +90 -17
  12. package/dist/cjs/layout.js +50 -25
  13. package/dist/cjs/main.js +16 -14
  14. package/dist/cjs/objects/ClassComponent.js +199 -30
  15. package/dist/cjs/objects/ExecutionScope.js +9 -0
  16. package/dist/cjs/objects/types.js +25 -2
  17. package/dist/cjs/parser.js +6 -2
  18. package/dist/cjs/regenerate-tests.js +3 -3
  19. package/dist/cjs/render.js +5 -3
  20. package/dist/cjs/rules-check/no-connect-on-connected-pin.js +9 -8
  21. package/dist/cjs/rules-check/rules.js +7 -2
  22. package/dist/cjs/rules-check/unconnected-pins.js +10 -8
  23. package/dist/cjs/utils.js +2 -1
  24. package/dist/cjs/validate/SymbolTable.js +7 -1
  25. package/dist/cjs/validate/SymbolValidatorVisitor.js +54 -17
  26. package/dist/cjs/visitor.js +299 -238
  27. package/dist/esm/BaseVisitor.js +187 -24
  28. package/dist/esm/RefdesAnnotationVisitor.js +27 -10
  29. package/dist/esm/antlr/CircuitScriptLexer.js +241 -236
  30. package/dist/esm/antlr/CircuitScriptParser.js +1196 -899
  31. package/dist/esm/antlr/CircuitScriptVisitor.js +4 -1
  32. package/dist/esm/builtinMethods.js +7 -3
  33. package/dist/esm/draw_symbols.js +38 -34
  34. package/dist/esm/environment.js +25 -1
  35. package/dist/esm/execute.js +197 -127
  36. package/dist/esm/globals.js +4 -0
  37. package/dist/esm/graph.js +14 -12
  38. package/dist/esm/helpers.js +91 -18
  39. package/dist/esm/layout.js +51 -26
  40. package/dist/esm/main.js +16 -14
  41. package/dist/esm/objects/ClassComponent.js +201 -30
  42. package/dist/esm/objects/ExecutionScope.js +9 -0
  43. package/dist/esm/objects/types.js +33 -1
  44. package/dist/esm/parser.js +6 -2
  45. package/dist/esm/regenerate-tests.js +3 -3
  46. package/dist/esm/render.js +5 -3
  47. package/dist/esm/rules-check/no-connect-on-connected-pin.js +9 -8
  48. package/dist/esm/rules-check/rules.js +7 -2
  49. package/dist/esm/rules-check/unconnected-pins.js +10 -8
  50. package/dist/esm/utils.js +2 -1
  51. package/dist/esm/validate/SymbolTable.js +5 -0
  52. package/dist/esm/validate/SymbolValidatorVisitor.js +53 -16
  53. package/dist/esm/visitor.js +201 -137
  54. package/dist/types/BaseVisitor.d.ts +27 -10
  55. package/dist/types/RefdesAnnotationVisitor.d.ts +2 -0
  56. package/dist/types/antlr/CircuitScriptLexer.d.ts +43 -42
  57. package/dist/types/antlr/CircuitScriptParser.d.ts +102 -58
  58. package/dist/types/antlr/CircuitScriptVisitor.d.ts +8 -2
  59. package/dist/types/environment.d.ts +8 -1
  60. package/dist/types/execute.d.ts +6 -3
  61. package/dist/types/globals.d.ts +4 -0
  62. package/dist/types/graph.d.ts +2 -2
  63. package/dist/types/helpers.d.ts +2 -1
  64. package/dist/types/layout.d.ts +5 -4
  65. package/dist/types/objects/ClassComponent.d.ts +34 -9
  66. package/dist/types/objects/ExecutionScope.d.ts +3 -1
  67. package/dist/types/objects/types.d.ts +40 -3
  68. package/dist/types/validate/SymbolTable.d.ts +1 -0
  69. package/dist/types/validate/SymbolValidatorVisitor.d.ts +6 -6
  70. package/dist/types/visitor.d.ts +10 -2
  71. package/package.json +4 -1
@@ -16,8 +16,8 @@ const Frame_js_1 = require("./objects/Frame.js");
16
16
  const ComponentAnnotater_js_1 = require("./ComponentAnnotater.js");
17
17
  const ComponentMatchConditions_js_1 = require("./ComponentMatchConditions.js");
18
18
  class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
19
- constructor() {
20
- super(...arguments);
19
+ constructor(silent = false, onErrorHandler = null, environment) {
20
+ super(silent, onErrorHandler, environment);
21
21
  this.componentCreationIndex = 0;
22
22
  this.creationCtx = new Map();
23
23
  this.visitKeyword_assignment_expr = (ctx) => {
@@ -167,137 +167,20 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
167
167
  if (ctxNotPathBlock) {
168
168
  this.visit(ctxNotPathBlock);
169
169
  }
170
+ if (ctx.start && ctx.stop) {
171
+ const startToken = ctx.start;
172
+ const stopToken = ctx.stop;
173
+ const annotationKey = this.getRefdesFileAnnotation(this.getCurrentFile(), startToken.line, startToken.column, stopToken.line, stopToken.column);
174
+ if (this.refdesFileAnnotations.has(annotationKey)) {
175
+ let refdesValue = this.refdesFileAnnotations.get(annotationKey);
176
+ refdesValue = refdesValue.split(',')[0];
177
+ this.setCurrentComponentRefdes(refdesValue, true);
178
+ }
179
+ }
170
180
  };
171
181
  this.visitCreate_component_expr = (ctx) => {
172
182
  const scope = this.getScope();
173
- const definedPinIds = [];
174
- const arrangedPinIds = [];
175
- const checkPinExistsAndNotDuplicated = (pinId, ctx) => {
176
- if (definedPinIds.indexOf(pinId) === -1) {
177
- this.warnings.push({
178
- message: `Invalid pin ${pinId}`, ctx
179
- });
180
- }
181
- if (arrangedPinIds.indexOf(pinId) !== -1) {
182
- this.warnings.push({
183
- message: `Pin ${pinId} specified more than once`,
184
- ctx,
185
- });
186
- }
187
- arrangedPinIds.push(pinId);
188
- };
189
- let didDefineArrangeProp = false;
190
- let didDefineDisplayProp = false;
191
- scope.setOnPropertyHandler((path, value, ctx) => {
192
- if (path.length === 1) {
193
- const [, keyName] = path[0];
194
- switch (keyName) {
195
- case 'type':
196
- this.validateString(value, ctx);
197
- break;
198
- case 'angle':
199
- case 'width':
200
- case 'height':
201
- this.validateNumeric(value, ctx);
202
- break;
203
- case 'display':
204
- if (didDefineArrangeProp) {
205
- throw new utils_js_2.RuntimeExecutionError("arrange property has already been defined", ctx);
206
- }
207
- didDefineDisplayProp = true;
208
- break;
209
- case 'arrange':
210
- if (didDefineDisplayProp) {
211
- throw new utils_js_2.RuntimeExecutionError("display property already defined", ctx);
212
- }
213
- didDefineArrangeProp = true;
214
- break;
215
- case 'pins':
216
- if (!(value instanceof Map)) {
217
- this.validateNumeric(value, ctx);
218
- const numPins = value.toNumber();
219
- for (let i = 0; i < numPins; i++) {
220
- definedPinIds.push(i + 1);
221
- }
222
- }
223
- break;
224
- case 'copy':
225
- if (value instanceof ParamDefinition_js_1.NumericValue) {
226
- this.validateNumeric(value, ctx);
227
- }
228
- else if (typeof value === 'boolean') {
229
- this.validateBoolean(value, ctx);
230
- }
231
- else {
232
- throw new utils_js_2.RuntimeExecutionError("Invalid value for 'copy' property", ctx);
233
- }
234
- break;
235
- }
236
- }
237
- else {
238
- const [, keyName] = path[0];
239
- if (keyName === 'arrange') {
240
- const [sideKeyCtx, sideKeyName] = path[1];
241
- if (globals_js_1.ValidPinSides.indexOf(sideKeyName) === -1) {
242
- throw new utils_js_2.RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx);
243
- }
244
- else {
245
- if (path.length === 2 && value instanceof ParamDefinition_js_1.NumericValue) {
246
- checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
247
- }
248
- else if (path.length > 2 && path[2][0] === 'index') {
249
- if (Array.isArray(value)) {
250
- const goodBlank = value.length === 1 &&
251
- value[0] instanceof ParamDefinition_js_1.NumericValue;
252
- if (!goodBlank) {
253
- throw new utils_js_2.RuntimeExecutionError(`Invalid blank specifier`, ctx);
254
- }
255
- }
256
- else {
257
- if (!(value instanceof ParamDefinition_js_1.NumericValue) && !(typeof value === 'string')) {
258
- throw new utils_js_2.RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx);
259
- }
260
- else {
261
- let useValue;
262
- if (value instanceof ParamDefinition_js_1.NumericValue) {
263
- useValue = value.toNumber();
264
- }
265
- else if (typeof value === 'string') {
266
- useValue = value;
267
- }
268
- value && checkPinExistsAndNotDuplicated(useValue, ctx);
269
- }
270
- }
271
- }
272
- }
273
- }
274
- else if (keyName === 'params') {
275
- const [, subKeyName] = path[1];
276
- switch (subKeyName) {
277
- case 'mpn':
278
- case 'refdes':
279
- case 'footprint':
280
- this.validateString(value, ctx);
281
- break;
282
- case 'place':
283
- this.validateBoolean(value, ctx);
284
- break;
285
- }
286
- }
287
- else if (keyName === 'pins') {
288
- if (path.length === 2) {
289
- const idName = path[1][1];
290
- definedPinIds.push(idName);
291
- if (value.length === 2) {
292
- const [pinType,] = value;
293
- if (pinType instanceof types_js_1.UndeclaredReference) {
294
- throw new utils_js_2.RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx);
295
- }
296
- }
297
- }
298
- }
299
- }
300
- });
183
+ scope.setOnPropertyHandler(this.createComponentPropertyValidator());
301
184
  scope.enterContext(ctx);
302
185
  ctx.property_expr().forEach(item => {
303
186
  this.visitResult(item);
@@ -317,49 +200,16 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
317
200
  }
318
201
  instanceName += `${globals_js_1.Delimiter1}${appendValue}`;
319
202
  }
320
- const arrangeProp = properties.has('arrange') ?
321
- properties.get('arrange') : null;
322
- const displayProp = properties.has('display') ?
323
- properties.get('display') : null;
324
- const typeProp = properties.has('type') ?
325
- properties.get('type') : null;
326
- const copy = properties.has('copy') ?
327
- properties.get('copy') : false;
328
- const width = properties.has('width') ?
329
- properties.get('width') : null;
330
- const height = properties.has('height') ?
331
- properties.get('height') : null;
332
- const angle = properties.has(globals_js_1.ParamKeys.angle) ?
333
- properties.get(globals_js_1.ParamKeys.angle) : null;
334
- const followWireOrientation = properties.has('followWireOrientation') ?
335
- properties.get('followWireOrientation') : true;
336
- let pins = [];
337
- if (displayProp !== null && arrangeProp === null
338
- && typeProp !== types_js_1.TypeProps.Graphic) {
339
- const drawCommands = displayProp.getCommands();
340
- drawCommands.forEach(command => {
341
- const [commandValue,] = command;
342
- if (commandValue === draw_symbols_js_1.PlaceHolderCommands.vpin
343
- || commandValue === draw_symbols_js_1.PlaceHolderCommands.hpin
344
- || commandValue === draw_symbols_js_1.PlaceHolderCommands.pin) {
345
- const id = PinDefinition_js_1.PinId.from(command[1][0]);
346
- const pinType = id.getType();
347
- const pinName = id.toString();
348
- pins.push(new PinDefinition_js_1.PinDefinition(id, pinType, pinName, PinTypes_js_1.PinTypes.Any));
349
- }
350
- });
351
- }
352
- else {
353
- pins = this.parseCreateComponentPins(properties.get('pins'));
354
- }
203
+ const typeProp = properties.get('type') ?? null;
204
+ const copy = properties.get('copy') ?? false;
205
+ const unitDefinitions = this.extractComponentUnitProperties(properties, typeProp);
355
206
  const props = {
356
- arrange: arrangeProp,
357
- display: displayProp,
358
- type: typeProp, width, height, copy,
359
- angle, followWireOrientation
207
+ type: typeProp,
208
+ copy,
209
+ units: unitDefinitions
360
210
  };
361
211
  try {
362
- const createdComponent = this.getExecutor().createComponent(instanceName, pins, params, props);
212
+ const createdComponent = this.getExecutor().createComponent(instanceName, [], params, props);
363
213
  this.setResult(ctx, createdComponent);
364
214
  createdComponent._creationIndex = this.componentCreationIndex++;
365
215
  }
@@ -501,19 +351,18 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
501
351
  return new PinDefinition_js_1.PinDefinition(index + 1, PinDefinition_js_1.PinIdType.Int, portName, PinTypes_js_1.PinTypes.Any);
502
352
  });
503
353
  const arrange = this.getArrangePropFromModulePorts(modulePorts, nameToPinId);
504
- const width = properties.has('width') ?
505
- properties.get('width') : null;
506
- const height = properties.has('height') ?
507
- properties.get('height') : null;
354
+ const unitProperties = this.extractComponentUnitProperties(properties, types_js_1.TypeProps.Module);
355
+ const firstUnitDef = unitProperties[0][1];
356
+ firstUnitDef.pins = tmpPorts;
357
+ firstUnitDef.arrange = arrange;
508
358
  const blankParams = [];
509
359
  const props = {
510
- arrange, width, height,
511
360
  copy: false,
512
- followWireOrientation: true,
361
+ units: unitProperties,
513
362
  };
514
363
  const moduleInstanceName = this.getExecutor().getUniqueInstanceName();
515
364
  const moduleComponent = this.getExecutor().createComponent(moduleInstanceName, tmpPorts, blankParams, props, true);
516
- moduleComponent.typeProp = globals_js_1.ComponentTypes.module;
365
+ moduleComponent.typeProp = types_js_1.TypeProps.Module;
517
366
  const ctxPropertyBlock = ctx.property_block_expr();
518
367
  if (ctxPropertyBlock) {
519
368
  const [firstBlock] = ctxPropertyBlock;
@@ -536,6 +385,10 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
536
385
  this.visitProperty_expr = (ctx) => {
537
386
  const ctxKey = ctx.property_key_expr();
538
387
  const ctxValue = ctx.property_value_expr();
388
+ const extraValue = ctx._extra;
389
+ if (extraValue) {
390
+ console.log('extra', extraValue.text);
391
+ }
539
392
  const scope = this.getScope();
540
393
  this.getScope().enterContext(ctxKey);
541
394
  this.getScope().enterContext(ctxValue);
@@ -630,6 +483,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
630
483
  dataResult = this.getExecutor().copyComponent(dataResult);
631
484
  }
632
485
  if (dataResult && dataResult instanceof ClassComponent_js_1.ClassComponent) {
486
+ const defaultUnit = dataResult.getUnit();
633
487
  const modifiers = ctx.component_modifier_expr();
634
488
  modifiers.forEach(modifier => {
635
489
  const modifierText = modifier.ID(0).getText();
@@ -646,23 +500,23 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
646
500
  if (modifierText === globals_js_1.ParamKeys.flip) {
647
501
  const flipValue = result;
648
502
  if (flipValue.indexOf('x') !== -1) {
649
- dataResult.setParam(globals_js_1.ParamKeys.flipX, 1);
503
+ defaultUnit.setParam(globals_js_1.ParamKeys.flipX, (0, ParamDefinition_js_1.numeric)(1));
650
504
  shouldIgnoreWireOrientation = true;
651
505
  }
652
506
  if (flipValue.indexOf('y') !== -1) {
653
- dataResult.setParam(globals_js_1.ParamKeys.flipY, 1);
507
+ defaultUnit.setParam(globals_js_1.ParamKeys.flipY, (0, ParamDefinition_js_1.numeric)(1));
654
508
  shouldIgnoreWireOrientation = true;
655
509
  }
656
510
  }
657
511
  else if (modifierText === globals_js_1.ParamKeys.angle) {
658
- dataResult.setParam(globals_js_1.ParamKeys.angle, result);
512
+ defaultUnit.setParam(globals_js_1.ParamKeys.angle, result);
659
513
  shouldIgnoreWireOrientation = true;
660
514
  }
661
515
  else if (modifierText === 'anchor') {
662
516
  dataResult.setParam('anchor', result);
663
517
  }
664
518
  if (shouldIgnoreWireOrientation) {
665
- dataResult.useWireOrientationAngle = false;
519
+ defaultUnit.useWireOrientationAngle = false;
666
520
  }
667
521
  });
668
522
  }
@@ -841,7 +695,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
841
695
  this.visitFunction_def_expr = (ctx) => {
842
696
  const functionName = ctx.ID().getText();
843
697
  const uniqueFunctionID = '__._' + ctx.start.line + '_'
844
- + ctx.start.column + '_' + functionName + '_' + ctx.getText();
698
+ + ctx.start.column + '_' + functionName + '_' + this.environment.hashStringSHA256(ctx.getText());
845
699
  let funcDefinedParameters = [];
846
700
  const ctxFunctionArgsExpr = ctx.function_args_expr();
847
701
  if (ctxFunctionArgsExpr) {
@@ -853,54 +707,17 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
853
707
  const resolveComponentPinNet = this.createComponentPinNetResolver(this.executionStack);
854
708
  const __runFunc = (passedInParameters, options) => {
855
709
  const executor = this.getExecutor();
856
- const parentBreakContext = executor.getParentBreakContext();
857
- executor.addBreakContext(ctx);
858
- let useIndex = -1;
859
- if (parentBreakContext === null) {
860
- useIndex = options.functionCallIndex;
861
- }
862
- else {
863
- const parentEntry = executor.indexedStack.get(parentBreakContext);
864
- const { funcCallIndex } = parentEntry;
865
- if (!funcCallIndex.has(ctx)) {
866
- funcCallIndex.set(ctx, 0);
867
- useIndex = 0;
868
- }
869
- else {
870
- useIndex = funcCallIndex.get(ctx) + 1;
871
- funcCallIndex.set(ctx, useIndex);
872
- }
873
- }
874
- executor.setBreakContextIndex(useIndex);
875
710
  const functionCounterIndex = functionCounter['counter'];
876
- const executionContextName = `${functionName}-${functionCounterIndex}`;
877
- const newExecutor = this.enterNewChildContext(executionStack, this.getExecutor(), executionContextName, options, funcDefinedParameters, passedInParameters);
878
711
  functionCounter['counter'] += 1;
712
+ const executionContextName = `${functionName}-${functionCounterIndex}`;
713
+ const newExecutor = this.handleEnterContext(executor, executionStack, executionContextName, ctx, options, funcDefinedParameters, passedInParameters);
879
714
  newExecutor.resolveNet = resolveNet;
880
715
  newExecutor.resolveComponentPinNet = resolveComponentPinNet;
881
716
  const returnValue = this.runExpressions(newExecutor, ctx.function_expr());
882
- const lastExecution = executionStack.pop();
883
- const nextLastExecution = executionStack[executionStack.length - 1];
884
- const mergedComponents = nextLastExecution.mergeScope(lastExecution.scope, executionContextName);
885
- const scope = this.getScope();
886
- const indexedStack = [];
887
- if (scope.breakStack.length > 0) {
888
- const executor = this.getExecutor();
889
- scope.breakStack.forEach(stackCtx => {
890
- const entry = executor.indexedStack.get(stackCtx);
891
- const { index } = entry;
892
- indexedStack.push([stackCtx, index]);
893
- });
894
- mergedComponents.forEach(component => {
895
- component.ctxReferences.forEach(ref => {
896
- ref.indexedStack = [...indexedStack, ...ref.indexedStack];
897
- });
898
- });
899
- }
900
- executor.popBreakContext();
717
+ const lastExecution = this.handlePopContext(executor, executionStack, executionContextName);
901
718
  return [lastExecution, returnValue];
902
719
  };
903
- this.getExecutor().createFunction(functionName, __runFunc, ctx, uniqueFunctionID);
720
+ this.getExecutor().createFunction(this.getExecutor().namespace, functionName, __runFunc, ctx, uniqueFunctionID);
904
721
  };
905
722
  this.visitPin_select_expr2 = (ctx) => {
906
723
  const ctxStringValue = ctx.STRING_VALUE();
@@ -1192,15 +1009,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1192
1009
  };
1193
1010
  this.visitAnnotation_comment_expr = (ctx) => {
1194
1011
  const refdesID = ctx.ID().getText();
1195
- const currentComponent = this.getScope().currentComponent;
1196
- if (currentComponent !== null) {
1197
- if (refdesID.indexOf('_') === -1) {
1198
- currentComponent.setParam('refdes', refdesID);
1199
- }
1200
- else {
1201
- currentComponent.placeHolderRefDes = refdesID;
1202
- }
1203
- }
1012
+ this.setCurrentComponentRefdes(refdesID);
1204
1013
  };
1205
1014
  this.visitPart_set_expr = (ctx) => {
1206
1015
  const paramKeys = ctx.data_expr().map(ctx => {
@@ -1322,6 +1131,199 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1322
1131
  PinTypes_js_1.PinTypes.Output,
1323
1132
  PinTypes_js_1.PinTypes.Power,
1324
1133
  ];
1134
+ if (environment) {
1135
+ this.log('-- Environment --');
1136
+ this.log('Module directory: ' + environment.getModuleDirectory());
1137
+ this.log('Default libs path: ' + environment.getDefaultLibsPath());
1138
+ this.log('Current file: ' + environment.getCurrentFile());
1139
+ this.log('-----------------');
1140
+ }
1141
+ }
1142
+ extractComponentUnitDefinition(properties, typeProp = null, lastNumericPinId = 0) {
1143
+ const width = properties.get('width') ?? null;
1144
+ const height = properties.get('height') ?? null;
1145
+ const angle = properties.get(globals_js_1.ParamKeys.angle) ?? null;
1146
+ const followWireOrientation = properties.get('followWireOrientation') ?? true;
1147
+ const arrange = properties.get('arrange') ?? null;
1148
+ const display = properties.get('display') ?? null;
1149
+ const suffix = properties.get('suffix') ?? null;
1150
+ let pins = [];
1151
+ if (display !== null && arrange === null && typeProp !== types_js_1.TypeProps.Graphic) {
1152
+ const drawCommands = display.getCommands();
1153
+ drawCommands.forEach(command => {
1154
+ const [commandValue,] = command;
1155
+ if (commandValue === draw_symbols_js_1.PlaceHolderCommands.vpin
1156
+ || commandValue === draw_symbols_js_1.PlaceHolderCommands.hpin
1157
+ || commandValue === draw_symbols_js_1.PlaceHolderCommands.pin) {
1158
+ const id = PinDefinition_js_1.PinId.from(command[1][0]);
1159
+ const pinType = id.getType();
1160
+ const pinName = id.toString();
1161
+ pins.push(new PinDefinition_js_1.PinDefinition(id, pinType, pinName, PinTypes_js_1.PinTypes.Any));
1162
+ }
1163
+ });
1164
+ }
1165
+ else {
1166
+ pins = this.extractPinDefintion(properties.get('pins'), lastNumericPinId);
1167
+ }
1168
+ return {
1169
+ width,
1170
+ height,
1171
+ angle,
1172
+ followWireOrientation,
1173
+ display, arrange,
1174
+ pins,
1175
+ suffix
1176
+ };
1177
+ }
1178
+ extractComponentUnitProperties(properties, typeProp) {
1179
+ let lastNumericPinId = 0;
1180
+ const unitsProperties = [];
1181
+ for (const [key, value] of properties) {
1182
+ if (key.split(':')[0] === 'unit') {
1183
+ const unitDef = this.extractComponentUnitDefinition(value, typeProp, lastNumericPinId);
1184
+ unitDef.pins.forEach(pin => {
1185
+ if (pin.id.isNumeric()) {
1186
+ lastNumericPinId = Math.max(lastNumericPinId, pin.id.getValue());
1187
+ }
1188
+ });
1189
+ unitsProperties.push([key, unitDef]);
1190
+ }
1191
+ }
1192
+ if (unitsProperties.length === 0) {
1193
+ unitsProperties.push(['unit',
1194
+ this.extractComponentUnitDefinition(properties, typeProp)]);
1195
+ }
1196
+ return unitsProperties;
1197
+ }
1198
+ createComponentPropertyValidator() {
1199
+ const definedPinIds = [];
1200
+ const arrangedPinIds = [];
1201
+ let didDefineArrangeProp = false;
1202
+ let didDefineDisplayProp = false;
1203
+ const checkPinExistsAndNotDuplicated = (pinId, ctx) => {
1204
+ if (definedPinIds.indexOf(pinId) === -1) {
1205
+ this.warnings.push({
1206
+ message: `Invalid pin ${pinId}`, ctx
1207
+ });
1208
+ }
1209
+ if (arrangedPinIds.indexOf(pinId) !== -1) {
1210
+ this.warnings.push({
1211
+ message: `Pin ${pinId} specified more than once`,
1212
+ ctx,
1213
+ });
1214
+ }
1215
+ arrangedPinIds.push(pinId);
1216
+ };
1217
+ return (path, value, ctx) => {
1218
+ if (path.length === 1) {
1219
+ const [, keyName] = path[0];
1220
+ switch (keyName) {
1221
+ case 'type':
1222
+ this.validateString(value, ctx);
1223
+ break;
1224
+ case 'angle':
1225
+ case 'width':
1226
+ case 'height':
1227
+ this.validateNumeric(value, ctx);
1228
+ break;
1229
+ case 'display':
1230
+ if (didDefineArrangeProp) {
1231
+ throw new utils_js_2.RuntimeExecutionError("arrange property has already been defined", ctx);
1232
+ }
1233
+ didDefineDisplayProp = true;
1234
+ break;
1235
+ case 'arrange':
1236
+ if (didDefineDisplayProp) {
1237
+ throw new utils_js_2.RuntimeExecutionError("display property already defined", ctx);
1238
+ }
1239
+ didDefineArrangeProp = true;
1240
+ break;
1241
+ case 'pins':
1242
+ if (!(value instanceof Map)) {
1243
+ this.validateNumeric(value, ctx);
1244
+ const numPins = value.toNumber();
1245
+ for (let i = 0; i < numPins; i++) {
1246
+ definedPinIds.push(i + 1);
1247
+ }
1248
+ }
1249
+ break;
1250
+ case 'copy':
1251
+ if (value instanceof ParamDefinition_js_1.NumericValue) {
1252
+ this.validateNumeric(value, ctx);
1253
+ }
1254
+ else if (typeof value === 'boolean') {
1255
+ this.validateBoolean(value, ctx);
1256
+ }
1257
+ else {
1258
+ throw new utils_js_2.RuntimeExecutionError("Invalid value for 'copy' property", ctx);
1259
+ }
1260
+ break;
1261
+ }
1262
+ }
1263
+ else {
1264
+ const [, keyName] = path[0];
1265
+ if (keyName === 'arrange') {
1266
+ const [sideKeyCtx, sideKeyName] = path[1];
1267
+ if (globals_js_1.ValidPinSides.indexOf(sideKeyName) === -1) {
1268
+ throw new utils_js_2.RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx);
1269
+ }
1270
+ else {
1271
+ if (path.length === 2 && value instanceof ParamDefinition_js_1.NumericValue) {
1272
+ checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
1273
+ }
1274
+ else if (path.length > 2 && path[2][0] === 'index') {
1275
+ if (Array.isArray(value)) {
1276
+ const goodBlank = value.length === 1 &&
1277
+ value[0] instanceof ParamDefinition_js_1.NumericValue;
1278
+ if (!goodBlank) {
1279
+ throw new utils_js_2.RuntimeExecutionError(`Invalid blank specifier`, ctx);
1280
+ }
1281
+ }
1282
+ else {
1283
+ if (!(value instanceof ParamDefinition_js_1.NumericValue) && !(typeof value === 'string')) {
1284
+ throw new utils_js_2.RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx);
1285
+ }
1286
+ else {
1287
+ let useValue;
1288
+ if (value instanceof ParamDefinition_js_1.NumericValue) {
1289
+ useValue = value.toNumber();
1290
+ }
1291
+ else if (typeof value === 'string') {
1292
+ useValue = value;
1293
+ }
1294
+ value && checkPinExistsAndNotDuplicated(useValue, ctx);
1295
+ }
1296
+ }
1297
+ }
1298
+ }
1299
+ }
1300
+ else if (keyName === 'params') {
1301
+ const [, subKeyName] = path[1];
1302
+ switch (subKeyName) {
1303
+ case 'mpn':
1304
+ case 'refdes':
1305
+ case 'footprint':
1306
+ this.validateString(value, ctx);
1307
+ break;
1308
+ case 'place':
1309
+ this.validateBoolean(value, ctx);
1310
+ break;
1311
+ }
1312
+ }
1313
+ else if (keyName === 'pins') {
1314
+ if (path.length === 2) {
1315
+ const idName = path[1][1];
1316
+ definedPinIds.push(idName);
1317
+ if (value.length === 2) {
1318
+ const [pinType,] = value;
1319
+ if (pinType instanceof types_js_1.UndeclaredReference) {
1320
+ throw new utils_js_2.RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx);
1321
+ }
1322
+ }
1323
+ }
1324
+ }
1325
+ }
1326
+ };
1325
1327
  }
1326
1328
  expandModuleContains(component, netNamespace) {
1327
1329
  this.getExecutor().log('expanding module `contains`');
@@ -1331,10 +1333,8 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1331
1333
  + component.instanceName
1332
1334
  + globals_js_1.Delimiter1 + component.moduleCounter;
1333
1335
  const tmpNamespace = this.getNetNamespace(netNamespace, "+/" + component.instanceName + globals_js_1.Delimiter1 + component.moduleCounter);
1334
- const newExecutor = this.enterNewChildContext(executionStack, executor, executionContextName, { netNamespace: tmpNamespace }, [], []);
1336
+ this.enterNewChildContext(executionStack, executor, executionContextName, { netNamespace: tmpNamespace }, [], []);
1335
1337
  component.moduleCounter += 1;
1336
- newExecutor.resolveNet = this.createNetResolver(executionStack);
1337
- newExecutor.resolveComponentPinNet = this.createComponentPinNetResolver(executionStack);
1338
1338
  this.visit(component.moduleContainsExpressions);
1339
1339
  const executionContext = executionStack.pop();
1340
1340
  component.moduleExecutionContext = executionContext;
@@ -1373,6 +1373,40 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1373
1373
  }
1374
1374
  }
1375
1375
  }
1376
+ setCurrentComponentRefdes(refdesValue, forceSave = false) {
1377
+ const currentComponent = this.getScope().currentComponent;
1378
+ if (currentComponent !== null) {
1379
+ if (refdesValue.indexOf('_') === -1) {
1380
+ currentComponent.setParam('refdes', refdesValue);
1381
+ }
1382
+ else {
1383
+ currentComponent.placeHolderRefDes = refdesValue;
1384
+ }
1385
+ currentComponent.forceSaveRefdesAnnotation = forceSave;
1386
+ }
1387
+ }
1388
+ async checkModuleHasRefdesFile(filePath) {
1389
+ const dir = this.environment.dirname(filePath);
1390
+ const ext = this.environment.extname(filePath);
1391
+ const basename = this.environment.basename(filePath, ext);
1392
+ const annotatedFilePath = this.environment.join(dir, `${basename}${globals_js_1.RefdesFileSuffix}`);
1393
+ const exists = await this.environment.exists(annotatedFilePath);
1394
+ if (exists) {
1395
+ this.log(`Import has refdes file: ${annotatedFilePath}`);
1396
+ const fileData = await this.environment.readFile(annotatedFilePath);
1397
+ const jsonData = JSON.parse(fileData);
1398
+ const baseFilePath = this.environment.getAbsolutePath(this.filePathStack[0]);
1399
+ const basePathDirectory = this.environment.dirname(baseFilePath);
1400
+ const { file, items } = jsonData;
1401
+ for (const item of items) {
1402
+ const parts = item.split(':');
1403
+ const refdes = parts[4];
1404
+ const useFilePath = this.environment.join(basePathDirectory, file);
1405
+ const key = this.getRefdesFileAnnotation(useFilePath, Number(parts[0]), Number(parts[1]), Number(parts[2]), Number(parts[3]));
1406
+ this.refdesFileAnnotations.set(key, refdes);
1407
+ }
1408
+ }
1409
+ }
1376
1410
  resolveDataExpr(data_expr) {
1377
1411
  const value = this.visitResult(data_expr);
1378
1412
  if (value instanceof types_js_1.UndeclaredReference) {
@@ -1392,13 +1426,13 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1392
1426
  return value;
1393
1427
  }
1394
1428
  }
1395
- parseCreateComponentPins(pinData) {
1429
+ extractPinDefintion(pinData, lastNumericPinId = 0) {
1396
1430
  const pins = [];
1397
1431
  if (pinData instanceof ParamDefinition_js_1.NumericValue) {
1398
1432
  const tmpMap = new Map();
1399
1433
  const lastPin = pinData.toNumber();
1400
1434
  for (let i = 0; i < lastPin; i++) {
1401
- const pinId = i + 1;
1435
+ const pinId = lastNumericPinId + i + 1;
1402
1436
  tmpMap.set(pinId, (0, ParamDefinition_js_1.numeric)(pinId));
1403
1437
  }
1404
1438
  pinData = tmpMap;
@@ -1571,6 +1605,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1571
1605
  const refdes = instance.getParam('refdes');
1572
1606
  if (refdes) {
1573
1607
  instance.assignedRefDes = refdes;
1608
+ this.setComponentUnitRefdesSuffix(instance);
1574
1609
  annotater.trackRefDes(refdes);
1575
1610
  this.log(refdes, '-', instance.instanceName);
1576
1611
  continue;
@@ -1584,6 +1619,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1584
1619
  if (newRefDes !== null) {
1585
1620
  instance.assignedRefDes = newRefDes;
1586
1621
  this.log(newRefDes, '-', instance.instanceName);
1622
+ this.setComponentUnitRefdesSuffix(instance);
1587
1623
  }
1588
1624
  else {
1589
1625
  this.log('Failed to annotate:', instance.instanceName);
@@ -1594,6 +1630,24 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1594
1630
  this.renameNetsWithRefdes();
1595
1631
  this.log('===== rename nets done =====');
1596
1632
  }
1633
+ setComponentUnitRefdesSuffix(instance) {
1634
+ if (instance.assignedRefDes) {
1635
+ const { units } = instance;
1636
+ if (units.length > 1) {
1637
+ units.forEach((unit, index) => {
1638
+ let useRefdes = String.fromCharCode("A".charCodeAt(0) + index);
1639
+ if (unit.suffix !== null) {
1640
+ useRefdes = unit.suffix;
1641
+ }
1642
+ unit.refdesSuffix = useRefdes;
1643
+ });
1644
+ }
1645
+ else {
1646
+ const [firstUnit] = units;
1647
+ firstUnit.refdesSuffix = '';
1648
+ }
1649
+ }
1650
+ }
1597
1651
  renameNetsWithRefdes() {
1598
1652
  const nets = this.getScope().getNets();
1599
1653
  const seenNets = [];
@@ -1652,10 +1706,17 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1652
1706
  }
1653
1707
  getPropertyExprList(items) {
1654
1708
  const properties = new Map();
1709
+ const keyCounter = new Map();
1655
1710
  items.forEach((item) => {
1656
1711
  const result = this.visitResult(item);
1657
1712
  for (const [key, value] of result) {
1658
- properties.set(key, value);
1713
+ let useKey = key;
1714
+ const counterValue = keyCounter.get(key) ?? 0;
1715
+ keyCounter.set(key, counterValue + 1);
1716
+ if (counterValue > 0) {
1717
+ useKey = key + ':' + counterValue;
1718
+ }
1719
+ properties.set(useKey, value);
1659
1720
  }
1660
1721
  });
1661
1722
  return properties;