circuitscript 0.5.7 → 0.6.1

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 (48) hide show
  1. package/dist/cjs/BaseVisitor.js +1 -0
  2. package/dist/cjs/annotate/ComponentAnnotater.js +6 -12
  3. package/dist/cjs/annotate/RefdesAnnotationVisitor.js +1 -3
  4. package/dist/cjs/antlr/CircuitScriptParser.js +1105 -845
  5. package/dist/cjs/cache/serializer.js +1 -1
  6. package/dist/cjs/errors.js +6 -3
  7. package/dist/cjs/execute.js +16 -10
  8. package/dist/cjs/objects/BlockTypes.js +1 -0
  9. package/dist/cjs/objects/ClassComponent.js +3 -3
  10. package/dist/cjs/objects/Frame.js +4 -0
  11. package/dist/cjs/regenerate-tests.js +4 -1
  12. package/dist/cjs/render/draw_symbols.js +51 -12
  13. package/dist/cjs/render/geometry.js +2 -2
  14. package/dist/cjs/render/layout.js +26 -2
  15. package/dist/cjs/sizing.js +3 -2
  16. package/dist/cjs/visitor.js +126 -32
  17. package/dist/esm/BaseVisitor.js +1 -0
  18. package/dist/esm/annotate/ComponentAnnotater.js +6 -12
  19. package/dist/esm/annotate/RefdesAnnotationVisitor.js +1 -3
  20. package/dist/esm/antlr/CircuitScriptParser.js +1098 -840
  21. package/dist/esm/antlr/CircuitScriptParserVisitor.js +2 -0
  22. package/dist/esm/cache/serializer.js +1 -1
  23. package/dist/esm/errors.js +6 -3
  24. package/dist/esm/execute.js +16 -10
  25. package/dist/esm/objects/BlockTypes.js +1 -0
  26. package/dist/esm/objects/ClassComponent.js +3 -3
  27. package/dist/esm/objects/Frame.js +4 -0
  28. package/dist/esm/regenerate-tests.js +4 -1
  29. package/dist/esm/render/draw_symbols.js +51 -12
  30. package/dist/esm/render/geometry.js +2 -2
  31. package/dist/esm/render/layout.js +26 -2
  32. package/dist/esm/sizing.js +3 -2
  33. package/dist/esm/visitor.js +127 -33
  34. package/dist/libs/std.cst +518 -15
  35. package/dist/types/BaseVisitor.d.ts +2 -2
  36. package/dist/types/antlr/CircuitScriptParser.d.ts +86 -64
  37. package/dist/types/antlr/CircuitScriptParserVisitor.d.ts +4 -0
  38. package/dist/types/execute.d.ts +2 -1
  39. package/dist/types/objects/BlockTypes.d.ts +2 -1
  40. package/dist/types/objects/ClassComponent.d.ts +1 -1
  41. package/dist/types/objects/Frame.d.ts +4 -0
  42. package/dist/types/render/draw_symbols.d.ts +5 -3
  43. package/dist/types/render/geometry.d.ts +1 -0
  44. package/dist/types/render/layout.d.ts +6 -0
  45. package/dist/types/sizing.d.ts +1 -1
  46. package/dist/types/visitor.d.ts +2 -1
  47. package/libs/std.cst +518 -15
  48. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { AbstractParseTreeVisitor } from "antlr4ng";
2
2
  export class CircuitScriptParserVisitor extends AbstractParseTreeVisitor {
3
3
  visitScript;
4
4
  visitExpression;
5
+ visitNon_newline_expression;
5
6
  visitFlow_expressions;
6
7
  visitGraph_expressions;
7
8
  visitExpressions_block;
@@ -17,6 +18,7 @@ export class CircuitScriptParserVisitor extends AbstractParseTreeVisitor {
17
18
  visitAt_block_header;
18
19
  visitAt_block;
19
20
  visitAt_block_expressions;
21
+ visitAt_block_expressions_inner;
20
22
  visitAt_block_pin_expr;
21
23
  visitKeyword_assignment_expr;
22
24
  visitParameters;
@@ -62,7 +62,7 @@ export function serializeLibraryScope(importedLib, contentHash) {
62
62
  prevStopLine = null;
63
63
  };
64
64
  for (const exprCtx of tree.expression()) {
65
- if (exprCtx.function_def_expr() !== null) {
65
+ if (exprCtx.non_newline_expression()?.function_def_expr() !== null) {
66
66
  flushGroup();
67
67
  continue;
68
68
  }
@@ -111,9 +111,12 @@ export function collectErrorChain(error) {
111
111
  return items;
112
112
  }
113
113
  export function printErrorChain(error) {
114
- const errors = collectErrorChain(error);
115
- errors.reverse();
116
- for (const err of errors) {
114
+ let useErrors = collectErrorChain(error);
115
+ if (useErrors.length === 0) {
116
+ useErrors = [error];
117
+ }
118
+ useErrors.reverse();
119
+ for (const err of useErrors) {
117
120
  console.log(" " + err.toString());
118
121
  }
119
122
  }
@@ -553,9 +553,7 @@ export class ExecutionContext {
553
553
  }
554
554
  else if (blockType === BlockTypes.Join || blockType === BlockTypes.Parallel) {
555
555
  if (blockIndex === 0) {
556
- const pointIdName = `${Delimiter1}${getBlockTypeString(blockType)}`;
557
- this.addPoint(`${pointIdName}.${this.name}.${this.tmpPointId}`, false);
558
- this.tmpPointId += 1;
556
+ this.addPointForBlockType(blockType);
559
557
  stackRef.end_point = [
560
558
  this.scope.currentComponent,
561
559
  this.scope.currentPin,
@@ -569,6 +567,11 @@ export class ExecutionContext {
569
567
  }
570
568
  }
571
569
  }
570
+ addPointForBlockType(blockType) {
571
+ const pointIdName = `${Delimiter1}${getBlockTypeString(blockType)}`;
572
+ this.addPoint(`${pointIdName}.${this.name}.${this.tmpPointId}`, false);
573
+ this.tmpPointId += 1;
574
+ }
572
575
  atPointBlock() {
573
576
  const [component, pin,] = this.getPointBlockLocation();
574
577
  this.atComponent(component, pin, {
@@ -585,10 +588,12 @@ export class ExecutionContext {
585
588
  this.log('get block point');
586
589
  for (let i = 0; i < this.scope.scopeLevel; i++) {
587
590
  const stackRef = this.scope.blockStack.get(this.scope.scopeLevel - 1 - i);
588
- const { start_point } = stackRef;
589
- const component = start_point[0];
590
- if (component.instanceName.startsWith(`${Delimiter1}point.`)) {
591
- return start_point;
591
+ if (stackRef) {
592
+ const { start_point } = stackRef;
593
+ const component = start_point[0];
594
+ if (component.instanceName.startsWith(`${Delimiter1}point.`)) {
595
+ return start_point;
596
+ }
592
597
  }
593
598
  }
594
599
  this.log('did not find block point');
@@ -1023,7 +1028,8 @@ export class ExecutionContext {
1023
1028
  });
1024
1029
  }
1025
1030
  applyComponentAngleFromWire(component, pin, opposite = false) {
1026
- const targetUnit = component.getUnitForPin(pin);
1031
+ const usePin = component.getPin(pin);
1032
+ const targetUnit = component.getUnitForPin(usePin);
1027
1033
  if (this.componentAngleFollowsWire
1028
1034
  && targetUnit.followWireOrientationProp
1029
1035
  && targetUnit.useWireOrientationAngle
@@ -1035,8 +1041,8 @@ export class ExecutionContext {
1035
1041
  useSegment = currentWire.path[0];
1036
1042
  }
1037
1043
  const pinPositions = CalculatePinPositions(targetUnit);
1038
- if (pinPositions.has(pin)) {
1039
- const connectedPinPos = pinPositions.get(pin);
1044
+ if (pinPositions.has(usePin)) {
1045
+ const connectedPinPos = pinPositions.get(usePin);
1040
1046
  let targetAngle = null;
1041
1047
  let useDirection = useSegment.direction;
1042
1048
  if (opposite) {
@@ -4,4 +4,5 @@ export var BlockTypes;
4
4
  BlockTypes[BlockTypes["Join"] = 2] = "Join";
5
5
  BlockTypes[BlockTypes["Parallel"] = 3] = "Parallel";
6
6
  BlockTypes[BlockTypes["Point"] = 4] = "Point";
7
+ BlockTypes[BlockTypes["AtBlock"] = 5] = "AtBlock";
7
8
  })(BlockTypes || (BlockTypes = {}));
@@ -196,10 +196,10 @@ export class ClassComponent {
196
196
  }
197
197
  throw new RuntimeExecutionError(`Could not find pin '${pinId}' on component '${this.instanceName}'`);
198
198
  }
199
- getNextPinAfter(pinIndex) {
199
+ getNextPinAfter(pinId) {
200
200
  const pins = Array.from(this.pins.keys());
201
- pins.sort();
202
- const index = pins.findIndex(tmp => tmp.equals(pinIndex));
201
+ const foundPin = this.getPin(pinId);
202
+ const index = pins.findIndex(tmp => tmp.equals(foundPin));
203
203
  if (index + 1 < pins.length) {
204
204
  return pins[index + 1];
205
205
  }
@@ -35,6 +35,10 @@ export var FrameParamKeys;
35
35
  FrameParamKeys["TitleAlign"] = "title_align";
36
36
  FrameParamKeys["HorizontalAlign"] = "align";
37
37
  FrameParamKeys["VerticalAlign"] = "valign";
38
+ FrameParamKeys["FontSize"] = "font_size";
39
+ FrameParamKeys["Bold"] = "bold";
40
+ FrameParamKeys["Italic"] = "italic";
41
+ FrameParamKeys["Color"] = "color";
38
42
  FrameParamKeys["SheetNumber"] = "sheet_number";
39
43
  FrameParamKeys["SheetTotal"] = "sheet_total";
40
44
  })(FrameParamKeys || (FrameParamKeys = {}));
@@ -22,13 +22,16 @@ async function regenerateTests(extra = "", fileList = []) {
22
22
  const outputPath = mainDir + 'svgs/' + file + extra + '.svg';
23
23
  env.setModuleDirectory(mainDir);
24
24
  env.setDefaultLibsPath(mainDir + '../../../libs/');
25
- await renderScript(scriptData, outputPath, {
25
+ const { errors } = await renderScript(scriptData, outputPath, {
26
26
  inputPath,
27
27
  dumpNets: false,
28
28
  dumpData: false,
29
29
  showStats: false,
30
30
  environment: env,
31
31
  });
32
+ if (errors.length > 0) {
33
+ console.log(errors);
34
+ }
32
35
  }
33
36
  return cstFiles;
34
37
  }
@@ -139,7 +139,7 @@ export class SymbolGraphic {
139
139
  const labels = this.drawing.getLabels();
140
140
  for (const label of labels) {
141
141
  const tmpLabel = label;
142
- const { fontSize = numeric(50), anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', angle: tmpLabelAngle = numeric(0), textColor = "#333", } = tmpLabel.style ?? {};
142
+ const { fontSize = numeric(50), anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', fontStyle = 'normal', angle: tmpLabelAngle = numeric(0), textColor = "#333", } = tmpLabel.style ?? {};
143
143
  let anchorStyle = 'start';
144
144
  let dominantBaseline = 'auto';
145
145
  let useAnchor = anchor;
@@ -293,15 +293,19 @@ export class SymbolGraphic {
293
293
  if (isRotation180) {
294
294
  useLabelAngle = (labelAngle + 180) % 360;
295
295
  }
296
- textContainer.text(tmpLabel.text)
297
- .fill(textColor)
298
- .font({
296
+ const fontProperties = {
299
297
  family: useFont,
300
298
  size: fontSize.toNumber() * fontDisplayScale,
301
299
  anchor: anchorStyle,
302
300
  'dominant-baseline': dominantBaseline,
303
301
  weight: fontWeight,
304
- })
302
+ };
303
+ if (fontStyle !== 'normal') {
304
+ fontProperties.style = fontStyle;
305
+ }
306
+ textContainer.text(tmpLabel.text)
307
+ .fill(textColor)
308
+ .font(fontProperties)
305
309
  .attr("xml:space", "preserve")
306
310
  .rotate(useLabelAngle, 0, 0);
307
311
  const { a, b, c, d, e, f } = textContainer.matrix();
@@ -349,6 +353,8 @@ export class SymbolText extends SymbolGraphic {
349
353
  text;
350
354
  fontSize = numeric(40);
351
355
  fontWeight = 'regular';
356
+ fontStyle = 'normal';
357
+ color = undefined;
352
358
  constructor(text) {
353
359
  super();
354
360
  this.text = text;
@@ -360,6 +366,8 @@ export class SymbolText extends SymbolGraphic {
360
366
  fontSize: this.fontSize,
361
367
  anchor: HorizontalAlign.Center,
362
368
  fontWeight: this.fontWeight,
369
+ fontStyle: this.fontStyle,
370
+ textColor: this.color
363
371
  });
364
372
  this.drawing = drawing;
365
373
  }
@@ -447,6 +455,9 @@ export class SymbolPlaceholder extends SymbolGraphic {
447
455
  case PlaceHolderCommands.triangle:
448
456
  drawing.addTriangle(...positionParams);
449
457
  break;
458
+ case PlaceHolderCommands.arrow:
459
+ drawing.addArrow(...positionParams);
460
+ break;
450
461
  case PlaceHolderCommands.pin:
451
462
  case PlaceHolderCommands.hpin:
452
463
  case PlaceHolderCommands.vpin:
@@ -504,18 +515,16 @@ export class SymbolPlaceholder extends SymbolGraphic {
504
515
  }
505
516
  parseLabelStyle(keywordParams) {
506
517
  const keywords = ['fontSize', 'anchor', 'vanchor',
507
- 'angle', 'textColor', 'portType', 'bold'];
518
+ 'angle', 'textColor', 'portType', 'bold', 'italic'];
508
519
  const style = {};
509
520
  keywords.forEach(item => {
510
521
  if (keywordParams.has(item)) {
511
522
  style[item] = keywordParams.get(item);
512
523
  if (item === 'bold') {
513
- if (keywordParams.get(item) === true) {
514
- style['fontWeight'] = 'bold';
515
- }
516
- else {
517
- style['fontWeight'] = 'normal';
518
- }
524
+ style.fontWeight = keywordParams.get(item) === true ? 'bold' : 'regular';
525
+ }
526
+ else if (item === 'italic') {
527
+ style.fontStyle = keywordParams.get(item) === true ? 'italic' : 'normal';
519
528
  }
520
529
  }
521
530
  });
@@ -675,6 +684,7 @@ export var PlaceHolderCommands;
675
684
  PlaceHolderCommands["rect"] = "rect";
676
685
  PlaceHolderCommands["crect"] = "crect";
677
686
  PlaceHolderCommands["triangle"] = "triangle";
687
+ PlaceHolderCommands["arrow"] = "arrow";
678
688
  PlaceHolderCommands["pin"] = "pin";
679
689
  PlaceHolderCommands["hpin"] = "hpin";
680
690
  PlaceHolderCommands["vpin"] = "vpin";
@@ -1042,6 +1052,35 @@ export class SymbolDrawing {
1042
1052
  ]));
1043
1053
  return this;
1044
1054
  }
1055
+ addArrow(startX, startY, endX, endY, arrowLength = numeric(25), arrowWidth = numeric(25)) {
1056
+ startX = milsToMM(startX);
1057
+ startY = milsToMM(startY);
1058
+ endX = milsToMM(endX);
1059
+ endY = milsToMM(endY);
1060
+ arrowLength = milsToMM(arrowLength);
1061
+ arrowWidth = milsToMM(arrowWidth);
1062
+ const dxNum = endX.sub(startX).toNumber();
1063
+ const dyNum = endY.sub(startY).toNumber();
1064
+ const len = Math.sqrt(dxNum * dxNum + dyNum * dyNum);
1065
+ const unitDx = numeric(dxNum / len);
1066
+ const unitDy = numeric(dyNum / len);
1067
+ const arrowBaseX = endX.sub(unitDx.mul(arrowLength));
1068
+ const arrowBaseY = endY.sub(unitDy.mul(arrowLength));
1069
+ this.items.push(Geometry.segment([startX, startY], [arrowBaseX, arrowBaseY]));
1070
+ const perpX = numeric(-unitDy.toNumber());
1071
+ const perpY = numeric(unitDx.toNumber());
1072
+ const dx1 = perpX.mul(arrowWidth).half();
1073
+ const dy1 = perpY.mul(arrowWidth).half();
1074
+ const dx2 = perpX.mul(arrowWidth.neg()).half();
1075
+ const dy2 = perpY.mul(arrowWidth.neg()).half();
1076
+ this.items.push(Geometry.polygon([
1077
+ [dx1.add(arrowBaseX), dy1.add(arrowBaseY)],
1078
+ [dx2.add(arrowBaseX), dy2.add(arrowBaseY)],
1079
+ [endX, endY],
1080
+ [dx1.add(arrowBaseX), dy1.add(arrowBaseY)],
1081
+ ]));
1082
+ return this;
1083
+ }
1045
1084
  addLabel(x, y, textValue, style) {
1046
1085
  this.items.push(Geometry.label(null, x, y, textValue, style));
1047
1086
  return this;
@@ -44,8 +44,8 @@ export class Textbox extends Flatten.Polygon {
44
44
  else {
45
45
  throw 'Invalid string passed into textbox';
46
46
  }
47
- const { fontSize = numeric(50), anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', portType = null, } = style ?? {};
48
- const { box } = measureTextSize2(useText, defaultFont, fontSize.mul(fontDisplayScale).toNumber(), fontWeight, anchor, vanchor);
47
+ const { fontSize = numeric(50), anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', fontStyle = 'normal', portType = null, } = style ?? {};
48
+ const { box } = measureTextSize2(useText, defaultFont, fontSize.mul(fontDisplayScale).toNumber(), fontWeight, fontStyle, anchor, vanchor);
49
49
  let polygonCoords = [];
50
50
  let anchorOffsetX = 0;
51
51
  let anchorOffsetY = 0;
@@ -551,12 +551,20 @@ export class LayoutEngine {
551
551
  const isSheetFrame = frameObject.frameType === FrameType.Sheet;
552
552
  if (frameParams.has(FrameParamKeys.Title) && !isSheetFrame) {
553
553
  const title = frameParams.get(FrameParamKeys.Title);
554
+ const fontSize = frameParams.get(FrameParamKeys.FontSize) ?? numeric(defaultFrameTitleTextSize);
555
+ const isBold = frameParams.get(FrameParamKeys.Bold) ?? true;
556
+ const isItalic = frameParams.get(FrameParamKeys.Italic) ?? false;
557
+ const titleColor = frameParams.get(FrameParamKeys.Color) ?? null;
554
558
  const titleFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Elements);
555
559
  titleFrame.containsTitle = true;
556
560
  titleFrame.subgraphId = title.replace(/\s/g, "_");
557
561
  const textObject = new RenderText(title);
558
- textObject.fontSize = numeric(defaultFrameTitleTextSize);
559
- textObject.fontWeight = 'bold';
562
+ textObject.fontSize = fontSize;
563
+ textObject.fontWeight = isBold ? 'bold' : 'regular';
564
+ textObject.fontStyle = isItalic ? 'italic' : 'normal';
565
+ if (titleColor !== null) {
566
+ textObject.color = titleColor;
567
+ }
560
568
  textObject.x = numeric(0);
561
569
  textObject.y = numeric(0);
562
570
  textObject.symbol.refreshDrawing();
@@ -1212,6 +1220,8 @@ export class RenderText extends RenderObject {
1212
1220
  symbol;
1213
1221
  _fontSize = numeric(12);
1214
1222
  _fontWeight = 'regular';
1223
+ _fontStyle = 'normal';
1224
+ _color = undefined;
1215
1225
  get fontSize() {
1216
1226
  return this._fontSize;
1217
1227
  }
@@ -1226,6 +1236,20 @@ export class RenderText extends RenderObject {
1226
1236
  this._fontWeight = value;
1227
1237
  this.symbol.fontWeight = value;
1228
1238
  }
1239
+ get fontStyle() {
1240
+ return this._fontStyle;
1241
+ }
1242
+ set fontStyle(value) {
1243
+ this._fontStyle = value;
1244
+ this.symbol.fontStyle = value;
1245
+ }
1246
+ get color() {
1247
+ return this._color;
1248
+ }
1249
+ set color(value) {
1250
+ this._color = value;
1251
+ this.symbol.color = value;
1252
+ }
1229
1253
  constructor(text) {
1230
1254
  super();
1231
1255
  this.symbol = new SymbolText(text);
@@ -6,10 +6,10 @@ export function applyFontsToSVG(canvas) {
6
6
  }
7
7
  const measureTextSizeCache = {};
8
8
  const measureTextSizeCacheHits = {};
9
- export function measureTextSize2(text, fontFamily, fontSize, fontWeight = 'regular', anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom) {
9
+ export function measureTextSize2(text, fontFamily, fontSize, fontWeight = 'regular', fontStyle = 'normal', anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom) {
10
10
  const environment = NodeScriptEnvironment.getInstance();
11
11
  const mainCanvas = environment.getCanvasWindow();
12
- const key = `${text}-${fontFamily}-${fontSize}-${fontWeight}-${anchor}-${vanchor}`;
12
+ const key = `${text}-${fontFamily}-${fontSize}-${fontWeight}-${fontStyle}-${anchor}-${vanchor}`;
13
13
  if (measureTextSizeCache[key] === undefined) {
14
14
  let dominantBaseline = VerticalAlignProp.Hanging;
15
15
  switch (vanchor) {
@@ -42,6 +42,7 @@ export function measureTextSize2(text, fontFamily, fontSize, fontWeight = 'regul
42
42
  anchor: useAnchor,
43
43
  'dominant-baseline': dominantBaseline,
44
44
  weight: fontWeight,
45
+ style: fontStyle,
45
46
  })
46
47
  .attr("xml:space", "preserve")
47
48
  .fill('#333');
@@ -4,7 +4,7 @@ import { ParamDefinition } from "./objects/ParamDefinition.js";
4
4
  import { numeric } from "./objects/NumericValue.js";
5
5
  import { PinDefinition, PinId, PinIdType } from './objects/PinDefinition.js';
6
6
  import { PinTypes } from './objects/PinTypes.js';
7
- import { AnyReference, DeclaredReference, UndeclaredReference } from './objects/types.js';
7
+ import { AnyReference, DeclaredReference, Direction, UndeclaredReference } from './objects/types.js';
8
8
  import { ComponentTypes, Delimiter1, FrameType, GlobalDocumentName, ModuleContainsKeyword, NoNetText, ParamKeys, RefdesFileSuffix, ReferenceTypes, SymbolPinSide, ValidPinSides, WireAutoDirection } from './globals.js';
9
9
  import { BlockTypes } from "./objects/BlockTypes.js";
10
10
  import { unwrapValue } from "./utils.js";
@@ -80,7 +80,7 @@ export class ParserVisitor extends BaseVisitor {
80
80
  return this.getExecutor().getCurrentPoint();
81
81
  };
82
82
  visitTo_component_expr = (ctx) => {
83
- ctx.component_select_expr().forEach(item => {
83
+ for (const item of ctx.component_select_expr()) {
84
84
  let refComponent;
85
85
  const creationFlag = this.trackNewComponentCreated(() => {
86
86
  const [component, pin] = this.visitResult(item);
@@ -95,7 +95,7 @@ export class ParserVisitor extends BaseVisitor {
95
95
  }
96
96
  });
97
97
  this.linkComponentToCtx(item, refComponent, creationFlag);
98
- });
98
+ }
99
99
  return this.getExecutor().getCurrentPoint();
100
100
  };
101
101
  visitComponent_select_expr = (ctx) => {
@@ -154,7 +154,18 @@ export class ParserVisitor extends BaseVisitor {
154
154
  const blockStackEntry = scope.blockStack.get(scopeLevel);
155
155
  const { current_index } = blockStackEntry;
156
156
  executor.enterBlock(current_index);
157
- this.visit(ctx.expressions_block());
157
+ const ctxNonNewlineExpressions = ctx.non_newline_expression();
158
+ const ctxExpressionsBlock = ctx.expressions_block();
159
+ const ctxAtBlockExpressions = ctx.at_block_expressions();
160
+ if (ctxNonNewlineExpressions.length > 0) {
161
+ this.runExpressions(executor, ctxNonNewlineExpressions);
162
+ }
163
+ else if (ctxExpressionsBlock) {
164
+ this.visit(ctxExpressionsBlock);
165
+ }
166
+ else if (ctxAtBlockExpressions) {
167
+ this.visit(ctxAtBlockExpressions);
168
+ }
158
169
  executor.exitBlock(current_index);
159
170
  blockStackEntry.current_index++;
160
171
  };
@@ -226,6 +237,7 @@ export class ParserVisitor extends BaseVisitor {
226
237
  const suffix = properties.get('suffix') ?? null;
227
238
  let pins = [];
228
239
  if (display !== null && arrange === null && typeProp !== ComponentTypes.graphic) {
240
+ display.variables = properties.get('params') ?? new Map();
229
241
  const drawCommands = display.getCommands();
230
242
  drawCommands.forEach(command => {
231
243
  const [commandValue,] = command;
@@ -233,9 +245,11 @@ export class ParserVisitor extends BaseVisitor {
233
245
  || commandValue === PlaceHolderCommands.hpin
234
246
  || commandValue === PlaceHolderCommands.pin) {
235
247
  const id = PinId.from(command[1][0]);
236
- const pinType = id.getType();
237
- const pinName = id.toString();
238
- pins.push(new PinDefinition(id, pinType, pinName, PinTypes.Any));
248
+ let pinName = id.toString();
249
+ if (typeof command[1][1] === 'string') {
250
+ pinName = command[1][1];
251
+ }
252
+ pins.push(new PinDefinition(id, id.getType(), pinName, PinTypes.Any));
239
253
  }
240
254
  });
241
255
  }
@@ -689,14 +703,17 @@ export class ParserVisitor extends BaseVisitor {
689
703
  let shouldIgnoreWireOrientation = false;
690
704
  if (modifierText === ParamKeys.flip) {
691
705
  const flipValue = result.name;
706
+ let didSetX = false;
707
+ let didSetY = false;
692
708
  if (flipValue.indexOf('x') !== -1) {
693
709
  defaultUnit.setParam(ParamKeys.flipX, numeric(1));
694
- shouldIgnoreWireOrientation = true;
710
+ didSetX = true;
695
711
  }
696
712
  if (flipValue.indexOf('y') !== -1) {
697
713
  defaultUnit.setParam(ParamKeys.flipY, numeric(1));
698
- shouldIgnoreWireOrientation = true;
714
+ didSetY = true;
699
715
  }
716
+ shouldIgnoreWireOrientation = didSetX && didSetY;
700
717
  }
701
718
  else if (modifierText === ParamKeys.angle) {
702
719
  defaultUnit.setParam(ParamKeys.angle, result);
@@ -705,6 +722,9 @@ export class ParserVisitor extends BaseVisitor {
705
722
  else if (modifierText === 'anchor') {
706
723
  dataResult.setParam('anchor', result.name);
707
724
  }
725
+ else {
726
+ dataResult.setParam(modifierText, result);
727
+ }
708
728
  if (shouldIgnoreWireOrientation) {
709
729
  defaultUnit.useWireOrientationAngle = false;
710
730
  }
@@ -959,24 +979,63 @@ export class ParserVisitor extends BaseVisitor {
959
979
  };
960
980
  visitAt_block_pin_expr = (ctx) => {
961
981
  const executor = this.getExecutor();
962
- const [currentComponent, currentPin] = executor.getCurrentPoint();
982
+ const scope = this.getScope();
983
+ const scopeLevel = scope.scopeLevel;
984
+ const params = this.getResult(ctx);
985
+ const blockIndex = params.index;
986
+ let useComponent;
987
+ for (let i = scopeLevel - 1; i >= 0; i--) {
988
+ const blockStackEntry = scope.blockStack.get(i);
989
+ if (blockStackEntry.type === BlockTypes.AtBlock) {
990
+ useComponent = blockStackEntry.start_point[0];
991
+ break;
992
+ }
993
+ }
963
994
  executor.closeOpenPathBlocks();
964
995
  const propKey = this.visitResult(ctx.property_key_expr());
965
996
  const atPin = new PinId(propKey);
966
- executor.atComponent(currentComponent, atPin, {
997
+ executor.atComponent(useComponent, atPin, {
967
998
  addSequence: true
968
999
  });
969
- executor.log('at block pin expressions');
970
- const ctxExpression = ctx.expression();
1000
+ executor.log(`at block pin expressions, pin id: ${atPin}`);
1001
+ const ctxExpression = ctx.non_newline_expression();
971
1002
  const ctxExpressionsBlock = ctx.expressions_block();
972
- if (ctxExpression) {
973
- this.visit(ctxExpression);
1003
+ if (ctxExpression.length > 0) {
1004
+ this.runExpressions(executor, ctxExpression);
974
1005
  }
975
1006
  else if (ctxExpressionsBlock) {
976
1007
  this.visit(ctxExpressionsBlock);
977
1008
  }
978
- executor.log('end at block pin expressions');
979
- executor.atComponent(currentComponent, currentPin);
1009
+ const parentBlockStackEntry = scope.blockStack.get(scopeLevel - 1);
1010
+ if (parentBlockStackEntry.type === BlockTypes.Join) {
1011
+ if (blockIndex === 0 && parentBlockStackEntry.current_index === 0) {
1012
+ executor.addPointForBlockType(BlockTypes.Join);
1013
+ parentBlockStackEntry.end_point = [
1014
+ scope.currentComponent,
1015
+ scope.currentPin,
1016
+ scope.currentWireId
1017
+ ];
1018
+ }
1019
+ else {
1020
+ const { end_point: finalPoint } = parentBlockStackEntry;
1021
+ const [component, pin] = finalPoint;
1022
+ executor.toComponent(component, pin, { addSequence: true });
1023
+ }
1024
+ }
1025
+ };
1026
+ visitAt_block_expressions = (ctx) => {
1027
+ let atBlockPinIndex = 0;
1028
+ for (const tmpCtx of ctx.at_block_expressions_inner()) {
1029
+ const ctxAtBlockPin = tmpCtx.at_block_pin_expr();
1030
+ if (ctxAtBlockPin) {
1031
+ this.setResult(ctxAtBlockPin, { index: atBlockPinIndex });
1032
+ atBlockPinIndex++;
1033
+ this.visit(ctxAtBlockPin);
1034
+ }
1035
+ else {
1036
+ this.visit(tmpCtx.expression());
1037
+ }
1038
+ }
980
1039
  };
981
1040
  visitAt_block_header = (ctx) => {
982
1041
  const ctxAtComponent = ctx.at_component_expr();
@@ -990,33 +1049,65 @@ export class ParserVisitor extends BaseVisitor {
990
1049
  };
991
1050
  visitAt_block = (ctx) => {
992
1051
  const executor = this.getExecutor();
993
- executor.log('entering at block');
1052
+ const scope = this.getScope();
1053
+ const scopeLevel = scope.scopeLevel;
1054
+ if (scope.blockStack.has(scopeLevel)) {
1055
+ executor.exitBlocks();
1056
+ }
994
1057
  const ctxAtBlockComponent = ctx.at_block_header();
995
1058
  this.visit(ctxAtBlockComponent);
996
1059
  const [currentComponent, currentPin] = executor.getCurrentPoint();
997
- executor.scope.scopeLevel += 1;
998
- ctx.at_block_expressions().forEach(expression => {
999
- this.visit(expression);
1060
+ scope.blockStack.set(scopeLevel, {
1061
+ start_point: [
1062
+ scope.currentComponent,
1063
+ scope.currentPin,
1064
+ scope.currentWireId
1065
+ ],
1066
+ end_point: null,
1067
+ current_index: 0,
1068
+ type: BlockTypes.AtBlock,
1000
1069
  });
1070
+ executor.log('entering at block');
1071
+ executor.scope.scopeLevel += 1;
1072
+ this.visit(ctx.at_block_expressions());
1001
1073
  executor.scope.scopeLevel -= 1;
1002
1074
  executor.scope.setCurrent(currentComponent, currentPin);
1075
+ scope.blockStack.delete(scopeLevel);
1003
1076
  executor.log('leaving at block');
1004
1077
  };
1005
1078
  visitWire_expr = (ctx) => {
1006
1079
  const segments = [];
1007
1080
  ctx.ID().forEach((ctxId, index) => {
1008
- const value = ctxId.getText();
1081
+ const valueText = ctxId.getText();
1009
1082
  const ctxDataExpr = ctx.data_expr(index);
1010
- if ((value === WireAutoDirection.Auto || value === WireAutoDirection.Auto_) && ctxDataExpr === null) {
1011
- segments.push([value]);
1083
+ let value = null;
1084
+ switch (valueText) {
1085
+ case 'right':
1086
+ case 'rg':
1087
+ case 'r':
1088
+ value = Direction.Right;
1089
+ break;
1090
+ case 'left':
1091
+ case 'lf':
1092
+ case 'l':
1093
+ value = Direction.Left;
1094
+ break;
1095
+ case 'up':
1096
+ case 'u':
1097
+ value = Direction.Up;
1098
+ break;
1099
+ case 'down':
1100
+ case 'dw':
1101
+ case 'd':
1102
+ value = Direction.Down;
1103
+ break;
1104
+ }
1105
+ if ((valueText === WireAutoDirection.Auto || valueText === WireAutoDirection.Auto_) && ctxDataExpr === null) {
1106
+ segments.push([valueText]);
1012
1107
  }
1013
1108
  else if (this.acceptedDirections.indexOf(value) !== -1 && ctxDataExpr) {
1014
- let useValue = null;
1015
- useValue = this.visitResult(ctxDataExpr);
1016
- if (useValue instanceof NumericValue) {
1017
- useValue = useValue.toNumber();
1018
- }
1019
- segments.push([value, new UnitDimension(useValue)]);
1109
+ const useValue = this.visitResult(ctxDataExpr);
1110
+ segments.push([value, new UnitDimension(useValue.toNumber())]);
1020
1111
  }
1021
1112
  else {
1022
1113
  this.throwWithContext(ctx, "Invalid wire expression");
@@ -1072,9 +1163,12 @@ export class ParserVisitor extends BaseVisitor {
1072
1163
  if (ctx.Sheet()) {
1073
1164
  frameType = FrameType.Sheet;
1074
1165
  }
1075
- const frameId = this.getExecutor().enterFrame(frameType);
1076
- this.visit(ctx.expressions_block());
1077
- this.getExecutor().exitFrame(frameId);
1166
+ const ctxExpressionsBlock = ctx.expressions_block();
1167
+ if (ctxExpressionsBlock) {
1168
+ const frameId = this.getExecutor().enterFrame(frameType);
1169
+ this.visit(ctxExpressionsBlock);
1170
+ this.getExecutor().exitFrame(frameId);
1171
+ }
1078
1172
  };
1079
1173
  visitNet_namespace_expr = (ctx) => {
1080
1174
  let dataValue;