circuitscript 0.1.31 → 0.1.33

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 (58) hide show
  1. package/dist/cjs/BaseVisitor.js +37 -3
  2. package/dist/cjs/RefdesAnnotationVisitor.js +27 -10
  3. package/dist/cjs/antlr/CircuitScriptParser.js +990 -831
  4. package/dist/cjs/draw_symbols.js +38 -34
  5. package/dist/cjs/environment.js +24 -4
  6. package/dist/cjs/execute.js +107 -68
  7. package/dist/cjs/globals.js +4 -2
  8. package/dist/cjs/graph.js +14 -12
  9. package/dist/cjs/helpers.js +85 -16
  10. package/dist/cjs/layout.js +50 -25
  11. package/dist/cjs/main.js +16 -18
  12. package/dist/cjs/objects/ClassComponent.js +199 -30
  13. package/dist/cjs/objects/types.js +5 -1
  14. package/dist/cjs/regenerate-tests.js +3 -3
  15. package/dist/cjs/render.js +5 -3
  16. package/dist/cjs/rules-check/no-connect-on-connected-pin.js +9 -8
  17. package/dist/cjs/rules-check/rules.js +7 -2
  18. package/dist/cjs/rules-check/unconnected-pins.js +10 -8
  19. package/dist/cjs/utils.js +2 -1
  20. package/dist/cjs/validate/SymbolValidatorVisitor.js +0 -10
  21. package/dist/cjs/visitor.js +284 -191
  22. package/dist/esm/BaseVisitor.js +37 -3
  23. package/dist/esm/RefdesAnnotationVisitor.js +27 -10
  24. package/dist/esm/antlr/CircuitScriptParser.js +989 -830
  25. package/dist/esm/antlr/CircuitScriptVisitor.js +1 -0
  26. package/dist/esm/draw_symbols.js +38 -34
  27. package/dist/esm/environment.js +21 -1
  28. package/dist/esm/execute.js +108 -69
  29. package/dist/esm/globals.js +2 -0
  30. package/dist/esm/graph.js +14 -12
  31. package/dist/esm/helpers.js +86 -17
  32. package/dist/esm/layout.js +51 -26
  33. package/dist/esm/main.js +16 -18
  34. package/dist/esm/objects/ClassComponent.js +201 -30
  35. package/dist/esm/objects/types.js +7 -1
  36. package/dist/esm/regenerate-tests.js +3 -3
  37. package/dist/esm/render.js +5 -3
  38. package/dist/esm/rules-check/no-connect-on-connected-pin.js +9 -8
  39. package/dist/esm/rules-check/rules.js +7 -2
  40. package/dist/esm/rules-check/unconnected-pins.js +10 -8
  41. package/dist/esm/utils.js +2 -1
  42. package/dist/esm/validate/SymbolValidatorVisitor.js +0 -10
  43. package/dist/esm/visitor.js +185 -92
  44. package/dist/types/BaseVisitor.d.ts +15 -5
  45. package/dist/types/RefdesAnnotationVisitor.d.ts +2 -0
  46. package/dist/types/antlr/CircuitScriptParser.d.ts +32 -14
  47. package/dist/types/antlr/CircuitScriptVisitor.d.ts +2 -0
  48. package/dist/types/environment.d.ts +7 -1
  49. package/dist/types/execute.d.ts +4 -1
  50. package/dist/types/globals.d.ts +2 -0
  51. package/dist/types/graph.d.ts +2 -2
  52. package/dist/types/helpers.d.ts +2 -1
  53. package/dist/types/layout.d.ts +5 -4
  54. package/dist/types/objects/ClassComponent.d.ts +34 -9
  55. package/dist/types/objects/types.d.ts +19 -3
  56. package/dist/types/validate/SymbolValidatorVisitor.d.ts +0 -4
  57. package/dist/types/visitor.d.ts +7 -1
  58. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import { renderScript } from './helpers.js';
3
3
  import { NodeScriptEnvironment } from "./environment.js";
4
- const mainDir = './__tests__/renderData/';
4
+ const mainDir = './__tests__/testData/renderData/';
5
5
  const env = new NodeScriptEnvironment();
6
6
  NodeScriptEnvironment.setInstance(env);
7
7
  async function regenerateTests(extra = "") {
@@ -9,7 +9,7 @@ async function regenerateTests(extra = "") {
9
9
  const cstFiles = [];
10
10
  const files = fs.readdirSync(mainDir);
11
11
  files.forEach(file => {
12
- if (file.endsWith('.cst')) {
12
+ if (file.endsWith('.cst') && file.startsWith('script')) {
13
13
  cstFiles.push(file);
14
14
  }
15
15
  });
@@ -19,7 +19,7 @@ async function regenerateTests(extra = "") {
19
19
  const scriptData = fs.readFileSync(inputPath, { encoding: 'utf-8' });
20
20
  const outputPath = mainDir + 'svgs/' + file + extra + '.svg';
21
21
  env.setModuleDirectory(mainDir);
22
- env.setDefaultLibsPath(mainDir + '../../libs/');
22
+ env.setDefaultLibsPath(mainDir + '../../../libs/');
23
23
  await renderScript(scriptData, outputPath, {
24
24
  dumpNets: false,
25
25
  dumpData: false,
@@ -36,10 +36,11 @@ export function renderSheetsToSVG(sheetFrames, logger) {
36
36
  const frameComponent = sheet.frame.frame.parameters
37
37
  .get(FrameParamKeys.SheetType);
38
38
  if (frameComponent) {
39
- if (frameComponent.displayProp === null) {
39
+ const frameComponentUnit = frameComponent.getUnit();
40
+ if (frameComponentUnit.displayProp === null) {
40
41
  throw 'Invalid graphic object for sheet frame';
41
42
  }
42
- const frameRects = ExtractDrawingRects(frameComponent.displayProp) ?? [];
43
+ const frameRects = ExtractDrawingRects(frameComponentUnit.displayProp) ?? [];
43
44
  let originalWidthMM = numeric(0);
44
45
  let originalHeightMM = numeric(0);
45
46
  let widthMM = numeric(0);
@@ -325,7 +326,8 @@ function drawSheetFrameBorder(frameGroup, frame) {
325
326
  const frameParams = frame.frame.parameters;
326
327
  if (frameParams.has(FrameParamKeys.SheetType)) {
327
328
  const frameComponent = frameParams.get(FrameParamKeys.SheetType);
328
- const { displayProp = null } = frameComponent ?? {};
329
+ const frameComponentUnit = frameComponent.getUnit();
330
+ const { displayProp = null } = frameComponentUnit ?? {};
329
331
  if (displayProp) {
330
332
  const sheetFrameGroup = frameGroup.group();
331
333
  const symbol = new SymbolPlaceholder(displayProp);
@@ -8,25 +8,26 @@ export function RuleCheck_NoConnectOnConnectedPin(graph, nets) {
8
8
  const makeComponentPinHash = (instanceName, pin) => {
9
9
  return instanceName + '-' + pin.getHashValue();
10
10
  };
11
- nets.forEach(item => {
12
- const [component, pin, net] = item;
11
+ for (const [component, pin, net] of nets) {
13
12
  if (!netComponentPins.has(net)) {
14
13
  netComponentPins.set(net, []);
15
14
  }
16
15
  const items = netComponentPins.get(net);
16
+ const unit = component.getUnitForPin(pin);
17
17
  items.push([
18
- component.instanceName,
18
+ unit.instanceName,
19
19
  pin
20
20
  ]);
21
21
  netComponentPins.set(net, items);
22
- pinMapping.set(makeComponentPinHash(component.instanceName, pin), net);
23
- });
24
- allNodes.forEach(node => {
22
+ pinMapping.set(makeComponentPinHash(unit.instanceName, pin), net);
23
+ }
24
+ ;
25
+ for (const node of allNodes) {
25
26
  const nodeInfo = graph.node(node);
26
27
  if (nodeInfo[0] === RenderItemType.Component) {
27
28
  const { component } = nodeInfo[1];
28
29
  if (component.hasParam('no_connect')) {
29
- const instanceName = component.instanceName;
30
+ const instanceName = component.getUnit().instanceName;
30
31
  const edges = graph.nodeEdges(node);
31
32
  const otherNodes = [];
32
33
  edges.forEach(edge => {
@@ -72,6 +73,6 @@ export function RuleCheck_NoConnectOnConnectedPin(graph, nets) {
72
73
  });
73
74
  }
74
75
  }
75
- });
76
+ }
76
77
  return items;
77
78
  }
@@ -22,7 +22,7 @@ export function EvaluateERCRules(visitor, graph, nets) {
22
22
  reportItems.push({
23
23
  type,
24
24
  start: token,
25
- message: `Unconnected pin ${item.pin} for component`
25
+ message: `Unconnected pin: ${instance.assignedRefDes} pin ${item.pin}`
26
26
  });
27
27
  }
28
28
  }
@@ -44,12 +44,17 @@ export function EvaluateERCRules(visitor, graph, nets) {
44
44
  case ERC_Rules.NoConnectOnConnectedPin:
45
45
  {
46
46
  const instance = item.instance;
47
+ const { instance: targetComponent, pin: targetPin } = item.target;
48
+ let extra = '';
49
+ if (targetComponent && targetComponent.assignedRefDes) {
50
+ extra = `: ${targetComponent.assignedRefDes} pin ${targetPin}`;
51
+ }
47
52
  const token = getComponentFirstCtxToken(instance);
48
53
  if (token) {
49
54
  reportItems.push({
50
55
  type,
51
56
  start: token,
52
- message: `No connect on connected pin`
57
+ message: `No connect on connected pin${extra}`
53
58
  });
54
59
  }
55
60
  }
@@ -3,13 +3,15 @@ import { ERC_Rules } from "./rules.js";
3
3
  export function RuleCheck_UnconnectedPinsWires(graph) {
4
4
  const items = [];
5
5
  const allNodes = graph.nodes();
6
- allNodes.forEach(node => {
6
+ for (const node of allNodes) {
7
7
  const nodeInfo = graph.node(node);
8
8
  if (nodeInfo[0] === RenderItemType.Component) {
9
- const { component } = nodeInfo[1];
9
+ const renderComponent = nodeInfo[1];
10
+ const { component, unitId } = renderComponent;
10
11
  const edges = graph.nodeEdges(node);
11
- const instanceName = component.instanceName;
12
- const connectedPins = [];
12
+ const componentUnit = component.getUnit(unitId);
13
+ const instanceName = componentUnit.instanceName;
14
+ const connectedUnitPins = [];
13
15
  edges.forEach(edge => {
14
16
  const edgeInfo = graph.edge(edge.v, edge.w);
15
17
  let pin;
@@ -19,12 +21,12 @@ export function RuleCheck_UnconnectedPinsWires(graph) {
19
21
  else if (edge.w === instanceName) {
20
22
  pin = edgeInfo[3];
21
23
  }
22
- connectedPins.push(pin.getHashValue());
24
+ connectedUnitPins.push(pin.getHashValue());
23
25
  });
24
- const pinIds = Array.from(component.pins.keys());
26
+ const pinIds = Array.from(componentUnit.pins.keys());
25
27
  pinIds.forEach(pinId => {
26
28
  const hashValue = pinId.getHashValue();
27
- if (connectedPins.indexOf(hashValue) === -1) {
29
+ if (connectedUnitPins.indexOf(hashValue) === -1) {
28
30
  items.push({
29
31
  type: ERC_Rules.UnconnectedPin,
30
32
  instance: component,
@@ -43,6 +45,6 @@ export function RuleCheck_UnconnectedPinsWires(graph) {
43
45
  });
44
46
  }
45
47
  }
46
- });
48
+ }
47
49
  return items;
48
50
  }
package/dist/esm/utils.js CHANGED
@@ -58,7 +58,8 @@ export function getBoundsSize(bounds) {
58
58
  };
59
59
  }
60
60
  export function getPortType(component) {
61
- const drawingCommands = component.displayProp;
61
+ const targetUnit = component.getUnit();
62
+ const drawingCommands = targetUnit.displayProp;
62
63
  let foundPinType = null;
63
64
  const commands = drawingCommands.getCommands();
64
65
  commands.some(item => {
@@ -7,16 +7,6 @@ import { BaseVisitor } from "../BaseVisitor.js";
7
7
  import { BaseNamespace, SymbolValidatorContext } from "../globals.js";
8
8
  export class SymbolValidatorVisitor extends BaseVisitor {
9
9
  symbolTable = new SymbolTable();
10
- filePathStack = [];
11
- enterFile(filePath) {
12
- this.filePathStack.push(filePath);
13
- }
14
- exitFile() {
15
- this.filePathStack.pop();
16
- }
17
- getCurrentFile() {
18
- return this.filePathStack[this.filePathStack.length - 1];
19
- }
20
10
  addSymbolVariable(token, name, value, executor = null) {
21
11
  const useExecutor = executor === null ? this.getExecutor() : executor;
22
12
  this.symbolTable.addVariable(token, this.getCurrentFile(), useExecutor, name, value);
@@ -3,7 +3,7 @@ import { NumberOperator, numeric, NumericValue, ParamDefinition } from './object
3
3
  import { PinDefinition, PinId, PinIdType } from './objects/PinDefinition.js';
4
4
  import { PinTypes } from './objects/PinTypes.js';
5
5
  import { AnyReference, DeclaredReference, TypeProps, UndeclaredReference } from './objects/types.js';
6
- import { BlockTypes, ComponentTypes, Delimiter1, FrameType, GlobalDocumentName, ModuleContainsKeyword, NoNetText, ParamKeys, ReferenceTypes, SymbolPinSide, ValidPinSides, WireAutoDirection } from './globals.js';
6
+ import { BlockTypes, ComponentTypes, Delimiter1, FrameType, GlobalDocumentName, ModuleContainsKeyword, NoNetText, ParamKeys, RefdesFileSuffix, ReferenceTypes, SymbolPinSide, ValidPinSides, WireAutoDirection } from './globals.js';
7
7
  import { unwrapValue } from "./utils.js";
8
8
  import { PlaceHolderCommands, SymbolDrawingCommands } from './draw_symbols.js';
9
9
  import { BaseVisitor } from './BaseVisitor.js';
@@ -172,11 +172,117 @@ export class ParserVisitor extends BaseVisitor {
172
172
  if (ctxNotPathBlock) {
173
173
  this.visit(ctxNotPathBlock);
174
174
  }
175
+ if (ctx.start && ctx.stop) {
176
+ const startToken = ctx.start;
177
+ const stopToken = ctx.stop;
178
+ const annotationKey = this.getRefdesFileAnnotation(this.getCurrentFile(), startToken.line, startToken.column, stopToken.line, stopToken.column);
179
+ if (this.refdesFileAnnotations.has(annotationKey)) {
180
+ let refdesValue = this.refdesFileAnnotations.get(annotationKey);
181
+ refdesValue = refdesValue.split(',')[0];
182
+ this.setCurrentComponentRefdes(refdesValue, true);
183
+ }
184
+ }
175
185
  };
176
186
  visitCreate_component_expr = (ctx) => {
177
187
  const scope = this.getScope();
188
+ scope.setOnPropertyHandler(this.createComponentPropertyValidator());
189
+ scope.enterContext(ctx);
190
+ ctx.property_expr().forEach(item => {
191
+ this.visitResult(item);
192
+ });
193
+ scope.exitContext();
194
+ scope.popOnPropertyHandler();
195
+ const properties = this.getPropertyExprList(ctx.property_expr());
196
+ let instanceName = this.getExecutor().getUniqueInstanceName();
197
+ const propParams = properties.get('params');
198
+ const params = this.parseCreateComponentParams(propParams);
199
+ if (params.length > 0) {
200
+ const firstParam = params[0];
201
+ const paramValue = firstParam.paramValue;
202
+ let appendValue = paramValue.toString();
203
+ if (paramValue instanceof NumericValue) {
204
+ appendValue = paramValue.value;
205
+ }
206
+ instanceName += `${Delimiter1}${appendValue}`;
207
+ }
208
+ const typeProp = properties.get('type') ?? null;
209
+ const copy = properties.get('copy') ?? false;
210
+ const unitDefinitions = this.extractComponentUnitProperties(properties, typeProp);
211
+ const props = {
212
+ type: typeProp,
213
+ copy,
214
+ units: unitDefinitions
215
+ };
216
+ try {
217
+ const createdComponent = this.getExecutor().createComponent(instanceName, [], params, props);
218
+ this.setResult(ctx, createdComponent);
219
+ createdComponent._creationIndex = this.componentCreationIndex++;
220
+ }
221
+ catch (error) {
222
+ this.throwWithContext(ctx, error.message);
223
+ }
224
+ };
225
+ extractComponentUnitDefinition(properties, typeProp = null, lastNumericPinId = 0) {
226
+ const width = properties.get('width') ?? null;
227
+ const height = properties.get('height') ?? null;
228
+ const angle = properties.get(ParamKeys.angle) ?? null;
229
+ const followWireOrientation = properties.get('followWireOrientation') ?? true;
230
+ const arrange = properties.get('arrange') ?? null;
231
+ const display = properties.get('display') ?? null;
232
+ const suffix = properties.get('suffix') ?? null;
233
+ let pins = [];
234
+ if (display !== null && arrange === null && typeProp !== TypeProps.Graphic) {
235
+ const drawCommands = display.getCommands();
236
+ drawCommands.forEach(command => {
237
+ const [commandValue,] = command;
238
+ if (commandValue === PlaceHolderCommands.vpin
239
+ || commandValue === PlaceHolderCommands.hpin
240
+ || commandValue === PlaceHolderCommands.pin) {
241
+ const id = PinId.from(command[1][0]);
242
+ const pinType = id.getType();
243
+ const pinName = id.toString();
244
+ pins.push(new PinDefinition(id, pinType, pinName, PinTypes.Any));
245
+ }
246
+ });
247
+ }
248
+ else {
249
+ pins = this.extractPinDefintion(properties.get('pins'), lastNumericPinId);
250
+ }
251
+ return {
252
+ width,
253
+ height,
254
+ angle,
255
+ followWireOrientation,
256
+ display, arrange,
257
+ pins,
258
+ suffix
259
+ };
260
+ }
261
+ extractComponentUnitProperties(properties, typeProp) {
262
+ let lastNumericPinId = 0;
263
+ const unitsProperties = [];
264
+ for (const [key, value] of properties) {
265
+ if (key.split(':')[0] === 'unit') {
266
+ const unitDef = this.extractComponentUnitDefinition(value, typeProp, lastNumericPinId);
267
+ unitDef.pins.forEach(pin => {
268
+ if (pin.id.isNumeric()) {
269
+ lastNumericPinId = Math.max(lastNumericPinId, pin.id.getValue());
270
+ }
271
+ });
272
+ unitsProperties.push([key, unitDef]);
273
+ }
274
+ }
275
+ if (unitsProperties.length === 0) {
276
+ unitsProperties.push(['unit',
277
+ this.extractComponentUnitDefinition(properties, typeProp)]);
278
+ }
279
+ return unitsProperties;
280
+ }
281
+ createComponentPropertyValidator() {
178
282
  const definedPinIds = [];
179
283
  const arrangedPinIds = [];
284
+ let didDefineArrangeProp = false;
285
+ let didDefineDisplayProp = false;
180
286
  const checkPinExistsAndNotDuplicated = (pinId, ctx) => {
181
287
  if (definedPinIds.indexOf(pinId) === -1) {
182
288
  this.warnings.push({
@@ -191,9 +297,7 @@ export class ParserVisitor extends BaseVisitor {
191
297
  }
192
298
  arrangedPinIds.push(pinId);
193
299
  };
194
- let didDefineArrangeProp = false;
195
- let didDefineDisplayProp = false;
196
- scope.setOnPropertyHandler((path, value, ctx) => {
300
+ return (path, value, ctx) => {
197
301
  if (path.length === 1) {
198
302
  const [, keyName] = path[0];
199
303
  switch (keyName) {
@@ -302,76 +406,8 @@ export class ParserVisitor extends BaseVisitor {
302
406
  }
303
407
  }
304
408
  }
305
- });
306
- scope.enterContext(ctx);
307
- ctx.property_expr().forEach(item => {
308
- this.visitResult(item);
309
- });
310
- scope.exitContext();
311
- scope.popOnPropertyHandler();
312
- const properties = this.getPropertyExprList(ctx.property_expr());
313
- let instanceName = this.getExecutor().getUniqueInstanceName();
314
- const propParams = properties.get('params');
315
- const params = this.parseCreateComponentParams(propParams);
316
- if (params.length > 0) {
317
- const firstParam = params[0];
318
- const paramValue = firstParam.paramValue;
319
- let appendValue = paramValue.toString();
320
- if (paramValue instanceof NumericValue) {
321
- appendValue = paramValue.value;
322
- }
323
- instanceName += `${Delimiter1}${appendValue}`;
324
- }
325
- const arrangeProp = properties.has('arrange') ?
326
- properties.get('arrange') : null;
327
- const displayProp = properties.has('display') ?
328
- properties.get('display') : null;
329
- const typeProp = properties.has('type') ?
330
- properties.get('type') : null;
331
- const copy = properties.has('copy') ?
332
- properties.get('copy') : false;
333
- const width = properties.has('width') ?
334
- properties.get('width') : null;
335
- const height = properties.has('height') ?
336
- properties.get('height') : null;
337
- const angle = properties.has(ParamKeys.angle) ?
338
- properties.get(ParamKeys.angle) : null;
339
- const followWireOrientation = properties.has('followWireOrientation') ?
340
- properties.get('followWireOrientation') : true;
341
- let pins = [];
342
- if (displayProp !== null && arrangeProp === null
343
- && typeProp !== TypeProps.Graphic) {
344
- const drawCommands = displayProp.getCommands();
345
- drawCommands.forEach(command => {
346
- const [commandValue,] = command;
347
- if (commandValue === PlaceHolderCommands.vpin
348
- || commandValue === PlaceHolderCommands.hpin
349
- || commandValue === PlaceHolderCommands.pin) {
350
- const id = PinId.from(command[1][0]);
351
- const pinType = id.getType();
352
- const pinName = id.toString();
353
- pins.push(new PinDefinition(id, pinType, pinName, PinTypes.Any));
354
- }
355
- });
356
- }
357
- else {
358
- pins = this.parseCreateComponentPins(properties.get('pins'));
359
- }
360
- const props = {
361
- arrange: arrangeProp,
362
- display: displayProp,
363
- type: typeProp, width, height, copy,
364
- angle, followWireOrientation
365
409
  };
366
- try {
367
- const createdComponent = this.getExecutor().createComponent(instanceName, pins, params, props);
368
- this.setResult(ctx, createdComponent);
369
- createdComponent._creationIndex = this.componentCreationIndex++;
370
- }
371
- catch (error) {
372
- this.throwWithContext(ctx, error.message);
373
- }
374
- };
410
+ }
375
411
  visitCreate_graphic_expr = (ctx) => {
376
412
  const ctxId = ctx.ID();
377
413
  const paramIds = [];
@@ -506,19 +542,18 @@ export class ParserVisitor extends BaseVisitor {
506
542
  return new PinDefinition(index + 1, PinIdType.Int, portName, PinTypes.Any);
507
543
  });
508
544
  const arrange = this.getArrangePropFromModulePorts(modulePorts, nameToPinId);
509
- const width = properties.has('width') ?
510
- properties.get('width') : null;
511
- const height = properties.has('height') ?
512
- properties.get('height') : null;
545
+ const unitProperties = this.extractComponentUnitProperties(properties, TypeProps.Module);
546
+ const firstUnitDef = unitProperties[0][1];
547
+ firstUnitDef.pins = tmpPorts;
548
+ firstUnitDef.arrange = arrange;
513
549
  const blankParams = [];
514
550
  const props = {
515
- arrange, width, height,
516
551
  copy: false,
517
- followWireOrientation: true,
552
+ units: unitProperties,
518
553
  };
519
554
  const moduleInstanceName = this.getExecutor().getUniqueInstanceName();
520
555
  const moduleComponent = this.getExecutor().createComponent(moduleInstanceName, tmpPorts, blankParams, props, true);
521
- moduleComponent.typeProp = ComponentTypes.module;
556
+ moduleComponent.typeProp = TypeProps.Module;
522
557
  const ctxPropertyBlock = ctx.property_block_expr();
523
558
  if (ctxPropertyBlock) {
524
559
  const [firstBlock] = ctxPropertyBlock;
@@ -541,6 +576,10 @@ export class ParserVisitor extends BaseVisitor {
541
576
  visitProperty_expr = (ctx) => {
542
577
  const ctxKey = ctx.property_key_expr();
543
578
  const ctxValue = ctx.property_value_expr();
579
+ const extraValue = ctx._extra;
580
+ if (extraValue) {
581
+ console.log('extra', extraValue.text);
582
+ }
544
583
  const scope = this.getScope();
545
584
  this.getScope().enterContext(ctxKey);
546
585
  this.getScope().enterContext(ctxValue);
@@ -635,6 +674,7 @@ export class ParserVisitor extends BaseVisitor {
635
674
  dataResult = this.getExecutor().copyComponent(dataResult);
636
675
  }
637
676
  if (dataResult && dataResult instanceof ClassComponent) {
677
+ const defaultUnit = dataResult.getUnit();
638
678
  const modifiers = ctx.component_modifier_expr();
639
679
  modifiers.forEach(modifier => {
640
680
  const modifierText = modifier.ID(0).getText();
@@ -651,23 +691,23 @@ export class ParserVisitor extends BaseVisitor {
651
691
  if (modifierText === ParamKeys.flip) {
652
692
  const flipValue = result;
653
693
  if (flipValue.indexOf('x') !== -1) {
654
- dataResult.setParam(ParamKeys.flipX, 1);
694
+ defaultUnit.setParam(ParamKeys.flipX, numeric(1));
655
695
  shouldIgnoreWireOrientation = true;
656
696
  }
657
697
  if (flipValue.indexOf('y') !== -1) {
658
- dataResult.setParam(ParamKeys.flipY, 1);
698
+ defaultUnit.setParam(ParamKeys.flipY, numeric(1));
659
699
  shouldIgnoreWireOrientation = true;
660
700
  }
661
701
  }
662
702
  else if (modifierText === ParamKeys.angle) {
663
- dataResult.setParam(ParamKeys.angle, result);
703
+ defaultUnit.setParam(ParamKeys.angle, result);
664
704
  shouldIgnoreWireOrientation = true;
665
705
  }
666
706
  else if (modifierText === 'anchor') {
667
707
  dataResult.setParam('anchor', result);
668
708
  }
669
709
  if (shouldIgnoreWireOrientation) {
670
- dataResult.useWireOrientationAngle = false;
710
+ defaultUnit.useWireOrientationAngle = false;
671
711
  }
672
712
  });
673
713
  }
@@ -1206,17 +1246,21 @@ export class ParserVisitor extends BaseVisitor {
1206
1246
  }
1207
1247
  executor.popBreakContext();
1208
1248
  };
1209
- visitAnnotation_comment_expr = (ctx) => {
1210
- const refdesID = ctx.ID().getText();
1249
+ setCurrentComponentRefdes(refdesValue, forceSave = false) {
1211
1250
  const currentComponent = this.getScope().currentComponent;
1212
1251
  if (currentComponent !== null) {
1213
- if (refdesID.indexOf('_') === -1) {
1214
- currentComponent.setParam('refdes', refdesID);
1252
+ if (refdesValue.indexOf('_') === -1) {
1253
+ currentComponent.setParam('refdes', refdesValue);
1215
1254
  }
1216
1255
  else {
1217
- currentComponent.placeHolderRefDes = refdesID;
1256
+ currentComponent.placeHolderRefDes = refdesValue;
1218
1257
  }
1258
+ currentComponent.forceSaveRefdesAnnotation = forceSave;
1219
1259
  }
1260
+ }
1261
+ visitAnnotation_comment_expr = (ctx) => {
1262
+ const refdesID = ctx.ID().getText();
1263
+ this.setCurrentComponentRefdes(refdesID);
1220
1264
  };
1221
1265
  visitPart_set_expr = (ctx) => {
1222
1266
  const paramKeys = ctx.data_expr().map(ctx => {
@@ -1331,6 +1375,28 @@ export class ParserVisitor extends BaseVisitor {
1331
1375
  children,
1332
1376
  });
1333
1377
  };
1378
+ async checkModuleHasRefdesFile(filePath) {
1379
+ const dir = this.environment.dirname(filePath);
1380
+ const ext = this.environment.extname(filePath);
1381
+ const basename = this.environment.basename(filePath, ext);
1382
+ const annotatedFilePath = this.environment.join(dir, `${basename}${RefdesFileSuffix}`);
1383
+ const exists = await this.environment.exists(annotatedFilePath);
1384
+ if (exists) {
1385
+ this.log(`Import has refdes file: ${annotatedFilePath}`);
1386
+ const fileData = await this.environment.readFile(annotatedFilePath);
1387
+ const jsonData = JSON.parse(fileData);
1388
+ const baseFilePath = this.environment.getAbsolutePath(this.filePathStack[0]);
1389
+ const basePathDirectory = this.environment.dirname(baseFilePath);
1390
+ const { file, items } = jsonData;
1391
+ for (const item of items) {
1392
+ const parts = item.split(':');
1393
+ const refdes = parts[4];
1394
+ const useFilePath = this.environment.join(basePathDirectory, file);
1395
+ const key = this.getRefdesFileAnnotation(useFilePath, Number(parts[0]), Number(parts[1]), Number(parts[2]), Number(parts[3]));
1396
+ this.refdesFileAnnotations.set(key, refdes);
1397
+ }
1398
+ }
1399
+ }
1334
1400
  resolveDataExpr(data_expr) {
1335
1401
  const value = this.visitResult(data_expr);
1336
1402
  if (value instanceof UndeclaredReference) {
@@ -1357,13 +1423,13 @@ export class ParserVisitor extends BaseVisitor {
1357
1423
  PinTypes.Output,
1358
1424
  PinTypes.Power,
1359
1425
  ];
1360
- parseCreateComponentPins(pinData) {
1426
+ extractPinDefintion(pinData, lastNumericPinId = 0) {
1361
1427
  const pins = [];
1362
1428
  if (pinData instanceof NumericValue) {
1363
1429
  const tmpMap = new Map();
1364
1430
  const lastPin = pinData.toNumber();
1365
1431
  for (let i = 0; i < lastPin; i++) {
1366
- const pinId = i + 1;
1432
+ const pinId = lastNumericPinId + i + 1;
1367
1433
  tmpMap.set(pinId, numeric(pinId));
1368
1434
  }
1369
1435
  pinData = tmpMap;
@@ -1536,6 +1602,7 @@ export class ParserVisitor extends BaseVisitor {
1536
1602
  const refdes = instance.getParam('refdes');
1537
1603
  if (refdes) {
1538
1604
  instance.assignedRefDes = refdes;
1605
+ this.setComponentUnitRefdesSuffix(instance);
1539
1606
  annotater.trackRefDes(refdes);
1540
1607
  this.log(refdes, '-', instance.instanceName);
1541
1608
  continue;
@@ -1549,6 +1616,7 @@ export class ParserVisitor extends BaseVisitor {
1549
1616
  if (newRefDes !== null) {
1550
1617
  instance.assignedRefDes = newRefDes;
1551
1618
  this.log(newRefDes, '-', instance.instanceName);
1619
+ this.setComponentUnitRefdesSuffix(instance);
1552
1620
  }
1553
1621
  else {
1554
1622
  this.log('Failed to annotate:', instance.instanceName);
@@ -1559,6 +1627,24 @@ export class ParserVisitor extends BaseVisitor {
1559
1627
  this.renameNetsWithRefdes();
1560
1628
  this.log('===== rename nets done =====');
1561
1629
  }
1630
+ setComponentUnitRefdesSuffix(instance) {
1631
+ if (instance.assignedRefDes) {
1632
+ const { units } = instance;
1633
+ if (units.length > 1) {
1634
+ units.forEach((unit, index) => {
1635
+ let useRefdes = String.fromCharCode("A".charCodeAt(0) + index);
1636
+ if (unit.suffix !== null) {
1637
+ useRefdes = unit.suffix;
1638
+ }
1639
+ unit.refdesSuffix = useRefdes;
1640
+ });
1641
+ }
1642
+ else {
1643
+ const [firstUnit] = units;
1644
+ firstUnit.refdesSuffix = '';
1645
+ }
1646
+ }
1647
+ }
1562
1648
  renameNetsWithRefdes() {
1563
1649
  const nets = this.getScope().getNets();
1564
1650
  const seenNets = [];
@@ -1617,10 +1703,17 @@ export class ParserVisitor extends BaseVisitor {
1617
1703
  }
1618
1704
  getPropertyExprList(items) {
1619
1705
  const properties = new Map();
1706
+ const keyCounter = new Map();
1620
1707
  items.forEach((item) => {
1621
1708
  const result = this.visitResult(item);
1622
1709
  for (const [key, value] of result) {
1623
- properties.set(key, value);
1710
+ let useKey = key;
1711
+ const counterValue = keyCounter.get(key) ?? 0;
1712
+ keyCounter.set(key, counterValue + 1);
1713
+ if (counterValue > 0) {
1714
+ useKey = key + ':' + counterValue;
1715
+ }
1716
+ properties.set(useKey, value);
1624
1717
  }
1625
1718
  });
1626
1719
  return properties;
@@ -5,7 +5,7 @@ import { Logger } from "./logger.js";
5
5
  import { ClassComponent } from "./objects/ClassComponent.js";
6
6
  import { Net } from "./objects/Net.js";
7
7
  import { CallableParameter, ComplexType, Direction, FunctionDefinedParameter, AnyReference, ImportedModule, NewContextOptions, ImportFunctionHandling as ImportFunctionHandling } from "./objects/types.js";
8
- import { ParserRuleContext } from 'antlr4ng';
8
+ import { CommonTokenStream, ParserRuleContext } from 'antlr4ng';
9
9
  import { ExecutionWarning } from "./utils.js";
10
10
  import { BaseError } from './utils.js';
11
11
  import { ExecutionScope } from './objects/ExecutionScope.js';
@@ -14,6 +14,7 @@ import { PinId } from './objects/PinDefinition.js';
14
14
  export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyReference | any> {
15
15
  startingContext: ExecutionContext;
16
16
  executionStack: ExecutionContext[];
17
+ filePathStack: string[];
17
18
  silent: boolean;
18
19
  logger: Logger;
19
20
  printStream: string[];
@@ -27,10 +28,8 @@ export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyR
27
28
  environment: NodeScriptEnvironment;
28
29
  protected importedFiles: ImportFile[];
29
30
  protected warnings: ExecutionWarning[];
30
- onImportFile: (visitor: BaseVisitor, filePath: string, fileData: string, onErrorHandler: OnErrorHandler) => Promise<{
31
- hasError: boolean;
32
- hasParseError: boolean;
33
- }>;
31
+ onImportFile: (visitor: BaseVisitor, filePath: string, fileData: string, onErrorHandler: OnErrorHandler) => Promise<ImportFileResult>;
32
+ refdesFileAnnotations: Map<string, string>;
34
33
  constructor(silent: boolean | undefined, onErrorHandler: OnErrorHandler | null | undefined, environment: NodeScriptEnvironment);
35
34
  getExecutor(): ExecutionContext;
36
35
  getScope(): ExecutionScope;
@@ -75,6 +74,8 @@ export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyR
75
74
  getComponentCtxLinks(): Map<ParserRuleContext, ClassComponent>;
76
75
  visitResult(ctx: ParserRuleContext): any;
77
76
  protected handleImportFile(name: string, importHandling: ImportFunctionHandling, throwErrors?: boolean, ctx?: ParserRuleContext | null, specificImports?: string[]): Promise<ImportFile>;
77
+ checkModuleHasRefdesFile(filePath: string): Promise<void>;
78
+ getRefdesFileAnnotation(filePath: string, startLine: number, startColumn: number, stopLine: number, stopColumn: number): string;
78
79
  visitRoundedBracketsExpr: (ctx: RoundedBracketsExprContext) => void;
79
80
  protected setupDefinedParameters(funcDefinedParameters: FunctionDefinedParameter[], passedInParameters: CallableParameter[], executor: ExecutionContext): void;
80
81
  protected runExpressions(executor: ExecutionContext, expressions: ExpressionContext[] | Function_exprContext[]): ComplexType;
@@ -88,6 +89,9 @@ export declare class BaseVisitor extends CircuitScriptVisitor<ComplexType | AnyR
88
89
  protected validateString(value: any, context: ParserRuleContext): void;
89
90
  protected validateBoolean(value: any, context: ParserRuleContext): void;
90
91
  protected validateNumeric(value: any, context: ParserRuleContext): void;
92
+ enterFile(filePath: string): void;
93
+ exitFile(): void;
94
+ getCurrentFile(): string;
91
95
  }
92
96
  export type OnErrorHandler = (message: string, context: ParserRuleContext, e?: any) => void;
93
97
  type ImportFile = {
@@ -97,4 +101,10 @@ type ImportFile = {
97
101
  pathExists: boolean;
98
102
  importedModule: ImportedModule;
99
103
  };
104
+ export type ImportFileResult = {
105
+ hasError: boolean;
106
+ hasParseError: boolean;
107
+ tree: ScriptContext;
108
+ tokens: CommonTokenStream;
109
+ };
100
110
  export {};