circuitscript 0.0.24 → 0.0.25

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 (63) hide show
  1. package/dist/cjs/BaseVisitor.js +487 -0
  2. package/dist/cjs/SemanticTokenVisitor.js +218 -0
  3. package/dist/cjs/SymbolValidatorVisitor.js +233 -0
  4. package/dist/cjs/antlr/CircuitScriptLexer.js +209 -195
  5. package/dist/cjs/antlr/CircuitScriptParser.js +2310 -2087
  6. package/dist/cjs/antlr/CircuitScriptVisitor.js +4 -3
  7. package/dist/cjs/draw_symbols.js +67 -22
  8. package/dist/cjs/execute.js +51 -53
  9. package/dist/cjs/geometry.js +28 -8
  10. package/dist/cjs/helpers.js +175 -5
  11. package/dist/cjs/index.js +2 -0
  12. package/dist/cjs/layout.js +8 -0
  13. package/dist/cjs/lexer.js +19 -22
  14. package/dist/cjs/main.js +6 -11
  15. package/dist/cjs/objects/ClassComponent.js +3 -0
  16. package/dist/cjs/objects/ExecutionScope.js +1 -0
  17. package/dist/cjs/objects/types.js +7 -1
  18. package/dist/cjs/parser.js +29 -258
  19. package/dist/cjs/validate.js +81 -0
  20. package/dist/cjs/visitor.js +529 -820
  21. package/dist/esm/BaseVisitor.mjs +488 -0
  22. package/dist/esm/SemanticTokenVisitor.mjs +215 -0
  23. package/dist/esm/SymbolValidatorVisitor.mjs +222 -0
  24. package/dist/esm/antlr/CircuitScriptLexer.mjs +184 -194
  25. package/dist/esm/antlr/CircuitScriptParser.mjs +2279 -2084
  26. package/dist/esm/antlr/CircuitScriptVisitor.mjs +8 -3
  27. package/dist/esm/draw_symbols.mjs +67 -22
  28. package/dist/esm/execute.mjs +50 -52
  29. package/dist/esm/geometry.mjs +28 -8
  30. package/dist/esm/helpers.mjs +165 -6
  31. package/dist/esm/index.mjs +2 -0
  32. package/dist/esm/layout.mjs +8 -0
  33. package/dist/esm/lexer.mjs +10 -10
  34. package/dist/esm/main.mjs +7 -12
  35. package/dist/esm/objects/ClassComponent.mjs +3 -0
  36. package/dist/esm/objects/ExecutionScope.mjs +1 -0
  37. package/dist/esm/objects/types.mjs +6 -0
  38. package/dist/esm/parser.mjs +25 -230
  39. package/dist/esm/validate.mjs +74 -0
  40. package/dist/esm/visitor.mjs +343 -640
  41. package/dist/types/BaseVisitor.d.ts +69 -0
  42. package/dist/types/SemanticTokenVisitor.d.ts +36 -0
  43. package/dist/types/SymbolValidatorVisitor.d.ts +61 -0
  44. package/dist/types/antlr/CircuitScriptLexer.d.ts +8 -7
  45. package/dist/types/antlr/CircuitScriptParser.d.ts +513 -469
  46. package/dist/types/antlr/CircuitScriptVisitor.d.ts +69 -59
  47. package/dist/types/draw_symbols.d.ts +9 -0
  48. package/dist/types/execute.d.ts +5 -8
  49. package/dist/types/geometry.d.ts +4 -0
  50. package/dist/types/helpers.d.ts +32 -1
  51. package/dist/types/index.d.ts +2 -0
  52. package/dist/types/lexer.d.ts +2 -2
  53. package/dist/types/objects/ExecutionScope.d.ts +4 -1
  54. package/dist/types/objects/types.d.ts +5 -0
  55. package/dist/types/parser.d.ts +15 -28
  56. package/dist/types/validate.d.ts +2 -0
  57. package/dist/types/visitor.d.ts +40 -95
  58. package/fonts/Inter-Bold.ttf +0 -0
  59. package/fonts/Inter-Regular.ttf +0 -0
  60. package/fonts/OpenSans-Regular.ttf +0 -0
  61. package/fonts/Roboto-Regular.ttf +0 -0
  62. package/libs/lib.cst +183 -0
  63. package/package.json +11 -6
@@ -1,15 +1,16 @@
1
- import { ParseTreeVisitor } from 'antlr4';
2
- export default class CircuitScriptVisitor extends ParseTreeVisitor {
1
+ import { AbstractParseTreeVisitor } from "antlr4ng";
2
+ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
3
3
  visitScript;
4
4
  visitExpression;
5
5
  visitPath_blocks;
6
6
  visitPath_block_inner;
7
7
  visitProperty_set_expr2;
8
8
  visitAssignment_expr2;
9
+ visitPin_select_expr;
10
+ visitComponent_modifier_expr;
9
11
  visitData_expr_with_assignment;
10
12
  visitAdd_component_expr;
11
13
  visitComponent_select_expr;
12
- visitPin_select_expr;
13
14
  visitPin_select_expr2;
14
15
  visitAt_component_expr;
15
16
  visitTo_component_expr;
@@ -27,6 +28,7 @@ export default class CircuitScriptVisitor extends ParseTreeVisitor {
27
28
  visitParameters;
28
29
  visitProperty_set_expr;
29
30
  visitDouble_dot_property_set_expr;
31
+ visitFunctionCallExpr;
30
32
  visitAdditionExpr;
31
33
  visitMultiplyExpr;
32
34
  visitDataExpr;
@@ -42,6 +44,7 @@ export default class CircuitScriptVisitor extends ParseTreeVisitor {
42
44
  visitFunction_args_expr;
43
45
  visitAtom_expr;
44
46
  visitTrailer_expr;
47
+ visitFunction_call_expr;
45
48
  visitNet_namespace_expr;
46
49
  visitFunction_return_expr;
47
50
  visitCreate_component_expr;
@@ -52,6 +55,8 @@ export default class CircuitScriptVisitor extends ParseTreeVisitor {
52
55
  visitNested_properties;
53
56
  visitSingle_line_property;
54
57
  visitBlank_expr;
58
+ visitWire_expr_direction_value;
59
+ visitWire_expr_direction_only;
55
60
  visitWire_expr;
56
61
  visitPoint_expr;
57
62
  visitImport_expr;
@@ -6,6 +6,8 @@ export class SymbolGraphic {
6
6
  displayBounds = true;
7
7
  drawing;
8
8
  _angle = 0;
9
+ _flipX = 0;
10
+ _flipY = 0;
9
11
  width;
10
12
  height;
11
13
  labelTexts = new Map();
@@ -15,6 +17,18 @@ export class SymbolGraphic {
15
17
  set angle(value) {
16
18
  this._angle = value;
17
19
  }
20
+ get flipX() {
21
+ return this._flipX;
22
+ }
23
+ set flipX(value) {
24
+ this._flipX = value;
25
+ }
26
+ get flipY() {
27
+ return this._flipY;
28
+ }
29
+ set flipY(value) {
30
+ this._flipY = value;
31
+ }
18
32
  refreshDrawing(calculateSize = true) {
19
33
  this.generateDrawing();
20
34
  calculateSize && this.calculateSize();
@@ -40,10 +54,11 @@ export class SymbolGraphic {
40
54
  drawPlaceRemove(group, extra) {
41
55
  if (extra && extra.place === false) {
42
56
  const { start, end } = this.drawing.getBoundingBox(true);
43
- group.path([
57
+ const path = Geometry.roundPathValues([
44
58
  "M", start[0], start[1], "L", end[0], end[1],
45
59
  "M", end[0], start[1], "L", start[0], end[1]
46
- ].join(" "))
60
+ ]);
61
+ group.path(path)
47
62
  .stroke({
48
63
  width: defaultSymbolLineWidth,
49
64
  color: 'red'
@@ -110,27 +125,33 @@ export class SymbolGraphic {
110
125
  }
111
126
  switch (useAnchor) {
112
127
  case HorizontalAlign.Left:
113
- anchorStyle = 'start';
128
+ anchorStyle = (this.flipX === 0) ? 'start' : 'end';
114
129
  break;
115
130
  case HorizontalAlign.Middle:
116
131
  anchorStyle = 'middle';
117
132
  break;
118
133
  case HorizontalAlign.Right:
119
- anchorStyle = 'end';
134
+ anchorStyle = (this.flipX === 0) ? 'end' : 'start';
120
135
  break;
121
136
  }
122
137
  switch (useDominantBaseline) {
123
138
  case VerticalAlign.Top:
124
- dominantBaseline = 'hanging';
139
+ dominantBaseline = (this.flipY === 0) ? 'hanging' : 'text-top';
125
140
  break;
126
141
  case VerticalAlign.Middle:
127
142
  dominantBaseline = 'middle';
128
143
  break;
129
144
  case VerticalAlign.Bottom:
130
- dominantBaseline = 'text-top';
145
+ dominantBaseline = (this.flipY === 0) ? 'text-top' : 'hanging';
131
146
  break;
132
147
  }
133
148
  const position = tmpLabel.getLabelPosition();
149
+ if (this.flipX !== 0) {
150
+ position[0] *= -1;
151
+ }
152
+ if (this.flipY !== 0) {
153
+ position[1] *= -1;
154
+ }
134
155
  const useFont = defaultFont;
135
156
  const textContainer = group.group();
136
157
  const text = textContainer.text(tmpLabel.text)
@@ -154,11 +175,26 @@ export class SymbolGraphic {
154
175
  translateY = position[1];
155
176
  useRotateAngle = this.angle;
156
177
  }
178
+ translateX = this.roundValues(translateX);
179
+ translateY = this.roundValues(translateY);
157
180
  text.rotate(labelAngle);
158
181
  textContainer.translate(translateX, translateY)
159
182
  .rotate(useRotateAngle, -translateX, -translateY);
183
+ const { a, b, c, d, e, f } = textContainer.matrix();
184
+ const newMatrix = {
185
+ a: this.roundValues(a),
186
+ b: this.roundValues(b),
187
+ c: this.roundValues(c),
188
+ d: this.roundValues(d),
189
+ e: this.roundValues(e),
190
+ f: this.roundValues(f),
191
+ };
192
+ textContainer.transform(newMatrix);
160
193
  });
161
194
  }
195
+ roundValues(value) {
196
+ return +value.toFixed(7);
197
+ }
162
198
  flipTextAnchor(value) {
163
199
  if (value === HorizontalAlign.Left) {
164
200
  return HorizontalAlign.Right;
@@ -229,6 +265,8 @@ export class SymbolPlaceholder extends SymbolGraphic {
229
265
  drawing.log("=== start generate drawing ===");
230
266
  drawing.clear();
231
267
  drawing.angle = this._angle;
268
+ drawing.flipX = this._flipX;
269
+ drawing.flipY = this._flipY;
232
270
  const commands = drawing.getCommands();
233
271
  drawing.log('id: ', drawing.id, 'angle: ', this._angle, "commands:", commands.length);
234
272
  commands.forEach(([commandName, positionParams, keywordParams]) => {
@@ -305,10 +343,9 @@ export class SymbolPlaceholder extends SymbolGraphic {
305
343
  drawing.log('add pin', ...positionParams);
306
344
  const keywordDisplayPinId = 'display_pin_id';
307
345
  let displayPinId = true;
308
- if (keywordParams.has(keywordDisplayPinId)) {
309
- if (keywordParams.get(keywordDisplayPinId) === 0) {
310
- displayPinId = false;
311
- }
346
+ if (keywordParams.has(keywordDisplayPinId)
347
+ && keywordParams.get(keywordDisplayPinId) === 0) {
348
+ displayPinId = false;
312
349
  }
313
350
  let pinNameParam = null;
314
351
  if (typeof positionParams[1] === 'string') {
@@ -338,8 +375,8 @@ export class SymbolPlaceholder extends SymbolGraphic {
338
375
  ];
339
376
  }
340
377
  drawing.addPin(...positionParams);
341
- const latestPin = this.drawing.pins[this.drawing.pins.length - 1];
342
- const [pinId, , angle] = latestPin;
378
+ const lastAddedPin = this.drawing.pins[this.drawing.pins.length - 1];
379
+ const [pinId, , angle] = lastAddedPin;
343
380
  const [, , , endX, endY] = positionParams;
344
381
  let pinNameAlignment = HorizontalAlign.Left;
345
382
  let pinNameOffsetX = 4;
@@ -433,6 +470,8 @@ export class SymbolCustom extends SymbolGraphic {
433
470
  const maxRightPins = Math.max(...rightPins.map(item => item.position)) + 1;
434
471
  const drawing = new SymbolDrawing();
435
472
  drawing.angle = this._angle;
473
+ drawing.flipX = this._flipX;
474
+ drawing.flipY = this._flipY;
436
475
  const bodyWidth = this.bodyWidth;
437
476
  const bodyHeight = (1 + Math.max(maxLeftPins, maxRightPins)) * this.pinSpacing;
438
477
  drawing.addRect(0, 0, bodyWidth, bodyHeight);
@@ -498,6 +537,8 @@ export class SymbolDrawing {
498
537
  items = [];
499
538
  pins = [];
500
539
  angle = 0;
540
+ flipX = 0;
541
+ flipY = 0;
501
542
  mainOrigin = [0, 0];
502
543
  logger = null;
503
544
  clear() {
@@ -676,8 +717,9 @@ export class SymbolDrawing {
676
717
  }
677
718
  }
678
719
  else {
679
- const rotatedPath = Geometry.groupRotate([item], this.angle, this.mainOrigin);
680
- const { path, isClosedPolygon } = this.featuresToPath(rotatedPath);
720
+ let tmpResult = Geometry.groupFlip([item], this.flipX, this.flipY);
721
+ tmpResult = Geometry.groupRotate(tmpResult, this.angle, this.mainOrigin);
722
+ const { path, isClosedPolygon } = this.featuresToPath(tmpResult);
681
723
  pathItems.push({
682
724
  path: path,
683
725
  lineWidth: currentLineWidth,
@@ -690,9 +732,10 @@ export class SymbolDrawing {
690
732
  return pathItems;
691
733
  }
692
734
  getPinsPath() {
693
- const features = this.pins.map(item => item[1]);
694
- const withAngle = Geometry.groupRotate(features, this.angle, this.mainOrigin);
695
- const { path } = this.featuresToPath(withAngle);
735
+ let features = this.pins.map(item => item[1]);
736
+ features = Geometry.groupFlip(features, this.flipX, this.flipY);
737
+ features = Geometry.groupRotate(features, this.angle, this.mainOrigin);
738
+ const { path } = this.featuresToPath(features);
696
739
  return path;
697
740
  }
698
741
  getLabels() {
@@ -713,9 +756,10 @@ export class SymbolDrawing {
713
756
  }
714
757
  return accum;
715
758
  }, []);
716
- const measureItems = [...drawingFeatures, ...pinFeatures];
717
- const withAngle = Geometry.groupRotate(measureItems, this.angle, this.mainOrigin);
718
- return Geometry.groupBounds(withAngle);
759
+ let features = [...drawingFeatures, ...pinFeatures];
760
+ features = Geometry.groupFlip(features, this.flipX, this.flipY);
761
+ features = Geometry.groupRotate(features, this.angle, this.mainOrigin);
762
+ return Geometry.groupBounds(features);
719
763
  }
720
764
  getPinPosition(pinId) {
721
765
  const pin = this.pins.find(item => {
@@ -723,8 +767,9 @@ export class SymbolDrawing {
723
767
  });
724
768
  if (pin) {
725
769
  const [, feature, angle] = pin;
726
- const withAngle = Geometry.rotateDegs(feature, this.angle, this.mainOrigin);
727
- const coords = Geometry.getCoords(withAngle);
770
+ let tmpFeature = Geometry.flip(feature, this.flipX, this.flipY);
771
+ tmpFeature = Geometry.rotateDegs(tmpFeature, this.angle, this.mainOrigin);
772
+ const coords = Geometry.getCoords(tmpFeature);
728
773
  return {
729
774
  start: coords[0],
730
775
  end: coords[1],
@@ -18,7 +18,8 @@ export class ExecutionContext {
18
18
  silent = false;
19
19
  logger;
20
20
  __functionCache = {};
21
- constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger) {
21
+ parentContext;
22
+ constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger, parent) {
22
23
  this.name = name;
23
24
  this.namespace = namespace;
24
25
  this.netNamespace = netNamespace;
@@ -27,10 +28,18 @@ export class ExecutionContext {
27
28
  this.scope = ExecutionScope.create();
28
29
  this.scope.indentLevel = indentLevel;
29
30
  this.setupRoot();
31
+ if (name === '__') {
32
+ this.scope.sequence.push([
33
+ SequenceAction.At,
34
+ this.scope.componentRoot,
35
+ this.scope.currentPin
36
+ ]);
37
+ }
30
38
  this.silent = silent;
31
- this.print('create new execution context', this.namespace, this.name, this.scope.indentLevel);
39
+ this.log('create new execution context', this.namespace, this.name, this.scope.indentLevel);
40
+ this.parentContext = parent;
32
41
  }
33
- print(...params) {
42
+ log(...params) {
34
43
  const indentOutput = ''.padStart(this.scope.indentLevel * 4, ' ');
35
44
  const indentLevelText = this.scope.indentLevel
36
45
  .toString()
@@ -44,18 +53,13 @@ export class ExecutionContext {
44
53
  }
45
54
  setupRoot() {
46
55
  const componentRoot = ClassComponent.simple(GlobalNames.__root, 1, '__root');
47
- componentRoot.typeProp = ComponentTypes.net;
56
+ componentRoot.typeProp = ComponentTypes.point;
57
+ componentRoot.displayProp = 'point';
48
58
  this.scope.instances.set(GlobalNames.__root, componentRoot);
49
59
  this.scope.currentComponent = componentRoot;
50
60
  this.scope.currentPin = componentRoot.getDefaultPin();
51
61
  this.scope.componentRoot = componentRoot;
52
62
  }
53
- instanceExists(instanceName) {
54
- return this.scope.instances.has(instanceName);
55
- }
56
- getComponent(instanceName) {
57
- return this.scope.instances.get(instanceName);
58
- }
59
63
  getUniqueInstanceName(className) {
60
64
  let extraPrefix = '';
61
65
  switch (className) {
@@ -90,7 +94,7 @@ export class ExecutionContext {
90
94
  const net2 = net2_exists
91
95
  ? this.scope.getNet(component2, component2Pin)
92
96
  : null;
93
- this.print('link nets', component1, component1Pin, net1, 'to', component2, component2Pin, net2);
97
+ this.log('link nets', component1, component1Pin, net1, 'to', component2, component2Pin, net2);
94
98
  let returnNet;
95
99
  if (net1 === null && net2 === null) {
96
100
  const tmpNet = new Net(this.netNamespace, this.getUniqueNetName());
@@ -152,14 +156,14 @@ export class ExecutionContext {
152
156
  let tmpNet;
153
157
  if (result.found) {
154
158
  tmpNet = result.net;
155
- this.print('net found', tmpNet.namespace, tmpNet.name);
159
+ this.log('net found', tmpNet.namespace, tmpNet.name);
156
160
  }
157
161
  else {
158
162
  tmpNet = new Net(this.netNamespace, netName, priority);
159
- this.print('net not found, added net instance', tmpNet.namespace, tmpNet.name);
163
+ this.log('net not found, added net instance', tmpNet.namespace, tmpNet.name);
160
164
  }
161
165
  this.scope.setNet(component, 1, tmpNet);
162
- this.print('set net', netName, 'component', component);
166
+ this.log('set net', netName, 'component', component);
163
167
  }
164
168
  const { arrange = null } = props;
165
169
  component.arrangeProps = arrange;
@@ -178,7 +182,7 @@ export class ExecutionContext {
178
182
  const pinsOutput = pins.map((pin) => {
179
183
  return pin.id + ':' + pin.name;
180
184
  });
181
- this.print('add symbol', instanceName, '[' + pinsOutput.join(', ') + ']');
185
+ this.log('add symbol', instanceName, '[' + pinsOutput.join(', ') + ']');
182
186
  return component;
183
187
  }
184
188
  printPoint(extra = '') {
@@ -188,7 +192,7 @@ export class ExecutionContext {
188
192
  .getNet(this.scope.currentComponent, this.scope.currentPin)
189
193
  .toString();
190
194
  }
191
- this.print((extra !== '' ? (extra + ' ') : '') + 'point: ' +
195
+ this.log((extra !== '' ? (extra + ' ') : '') + 'point: ' +
192
196
  this.scope.currentComponent.instanceName +
193
197
  ' ' +
194
198
  this.scope.currentPin + ' ' + netName);
@@ -197,7 +201,7 @@ export class ExecutionContext {
197
201
  const startPin = pin;
198
202
  const nextPin = component.getNextPinAfter(startPin);
199
203
  this.toComponent(component, startPin, { addSequence: true });
200
- this.print('move to next pin: ' + nextPin);
204
+ this.log('move to next pin: ' + nextPin);
201
205
  this.atComponent(component, nextPin, {
202
206
  addSequence: true
203
207
  });
@@ -205,11 +209,8 @@ export class ExecutionContext {
205
209
  return this.getCurrentPoint();
206
210
  }
207
211
  toComponent(component, pinId, options) {
208
- this.print('to component');
209
- const { addSequence = false, cloneNetComponent = false } = options ?? {};
210
- if (cloneNetComponent && this.isNetOnlyComponent(component)) {
211
- component = this.cloneComponent(component);
212
- }
212
+ this.log('to component');
213
+ const { addSequence = false } = options ?? {};
213
214
  if (!(component instanceof ClassComponent)) {
214
215
  throw "Not a valid component!";
215
216
  }
@@ -229,7 +230,7 @@ export class ExecutionContext {
229
230
  }
230
231
  }
231
232
  if (this.scope.hasNet(this.scope.currentComponent, this.scope.currentPin)) {
232
- this.print('net: ', this.scope
233
+ this.log('net: ', this.scope
233
234
  .getNet(this.scope.currentComponent, this.scope.currentPin)
234
235
  .toString());
235
236
  }
@@ -256,11 +257,8 @@ export class ExecutionContext {
256
257
  return this.getCurrentPoint();
257
258
  }
258
259
  atComponent(component, pinId, options) {
259
- this.print('at component');
260
- const { addSequence = false, cloneNetComponent = false } = options ?? {};
261
- if (cloneNetComponent && this.isNetOnlyComponent(component)) {
262
- component = this.cloneComponent(component);
263
- }
260
+ this.log('at component');
261
+ const { addSequence = false } = options ?? {};
264
262
  this.scope.currentComponent = component;
265
263
  let usePinId;
266
264
  if (pinId === null) {
@@ -285,9 +283,6 @@ export class ExecutionContext {
285
283
  this.printPoint();
286
284
  return this.getCurrentPoint();
287
285
  }
288
- isNetOnlyComponent(component) {
289
- return isNetComponent(component) && !isLabelComponent(component);
290
- }
291
286
  cloneComponent(component) {
292
287
  let clonedComponent = null;
293
288
  if (!this.scope.copyIDs.has(component.instanceName)) {
@@ -302,7 +297,7 @@ export class ExecutionContext {
302
297
  this.scope.instances.set(cloneInstanceName, clonedComponent);
303
298
  clonedComponent.instanceName = cloneInstanceName;
304
299
  this.linkComponentPinNet(component, 1, clonedComponent, 1);
305
- this.print('created clone of net component:', cloneInstanceName);
300
+ this.log('created clone of net component:', cloneInstanceName);
306
301
  return clonedComponent;
307
302
  }
308
303
  enterBlocks(blockType) {
@@ -324,7 +319,7 @@ export class ExecutionContext {
324
319
  current_index: null,
325
320
  type: blockType,
326
321
  });
327
- this.print('enter blocks');
322
+ this.log('enter blocks');
328
323
  }
329
324
  exitBlocks() {
330
325
  const stackRef = this.scope.blockStack.get(this.scope.indentLevel);
@@ -345,7 +340,7 @@ export class ExecutionContext {
345
340
  const { entered_at: [component, pin,] } = stackRef;
346
341
  this.atComponent(component, pin, { addSequence: true });
347
342
  }
348
- this.print('exit blocks');
343
+ this.log('exit blocks');
349
344
  }
350
345
  enterBlock(blockIndex) {
351
346
  const stackRef = this.scope.blockStack.get(this.scope.indentLevel);
@@ -364,7 +359,7 @@ export class ExecutionContext {
364
359
  const { entered_at: [component, pin,] } = stackRef;
365
360
  this.atComponent(component, pin, { addSequence: true });
366
361
  }
367
- this.print(`enter inner block of type (${blockType}) >>>`);
362
+ this.log(`enter inner block of type (${blockType}) >>>`);
368
363
  this.scope.indentLevel += 1;
369
364
  }
370
365
  exitBlock(blockIndex) {
@@ -378,7 +373,7 @@ export class ExecutionContext {
378
373
  ];
379
374
  stackRef['block_index'] = null;
380
375
  this.scope.indentLevel -= 1;
381
- this.print('exit inner block <<<');
376
+ this.log('exit inner block <<<');
382
377
  if (blockType === BlockTypes.Branch) {
383
378
  const { entered_at: [component, pin, wireId] } = stackRef;
384
379
  this.atComponent(component, pin, { addSequence: true });
@@ -417,7 +412,7 @@ export class ExecutionContext {
417
412
  });
418
413
  }
419
414
  getPointBlockLocation() {
420
- this.print('get block point');
415
+ this.log('get block point');
421
416
  for (let i = 0; i < this.scope.indentLevel; i++) {
422
417
  const stackRef = this.scope.blockStack.get(this.scope.indentLevel - 1 - i);
423
418
  const { entered_at } = stackRef;
@@ -426,11 +421,11 @@ export class ExecutionContext {
426
421
  return entered_at;
427
422
  }
428
423
  }
429
- this.print('did not find block point');
424
+ this.log('did not find block point');
430
425
  return null;
431
426
  }
432
427
  breakBranch() {
433
- this.print('break branch');
428
+ this.log('break branch');
434
429
  const branchesInfo = this.scope.blockStack.get(this.scope.indentLevel - 1);
435
430
  const branchIndex = branchesInfo['block_index'];
436
431
  const branchIndexRef = branchesInfo['inner_blocks'].get(branchIndex);
@@ -439,7 +434,7 @@ export class ExecutionContext {
439
434
  createFunction(functionName, __runFunc) {
440
435
  this.scope.functions.set(functionName, __runFunc);
441
436
  this.__functionCache[functionName] = __runFunc;
442
- this.print(`defined new function '${functionName}'`);
437
+ this.log(`defined new function '${functionName}'`);
443
438
  }
444
439
  hasFunction(functionName) {
445
440
  return this.scope.functions.has(functionName);
@@ -488,7 +483,7 @@ export class ExecutionContext {
488
483
  __runFunc = this.getFunction(functionName);
489
484
  }
490
485
  if (__runFunc === null) {
491
- this.print(`searching for function ${functionName} in upper context`);
486
+ this.log(`searching for function ${functionName} in upper context`);
492
487
  const tmpResolveResult = this.resolveVariable(executionStack, functionName);
493
488
  if (tmpResolveResult.found) {
494
489
  __runFunc = tmpResolveResult.value;
@@ -497,17 +492,17 @@ export class ExecutionContext {
497
492
  throw `Invalid function ${functionName}`;
498
493
  }
499
494
  }
500
- this.print('save function to cache:', functionName);
495
+ this.log('save function to cache:', functionName);
501
496
  this.__functionCache[functionName] = __runFunc;
502
497
  }
503
498
  else {
504
- this.print('found function in cache:', functionName);
499
+ this.log('found function in cache:', functionName);
505
500
  __runFunc = this.__functionCache[functionName];
506
501
  }
507
502
  if (__runFunc !== null) {
508
- this.print(`call function '${functionName}'`);
503
+ this.log(`call function '${functionName}'`);
509
504
  const functionResult = __runFunc(functionParams, { netNamespace });
510
- this.print(`done call function '${functionName}'`);
505
+ this.log(`done call function '${functionName}'`);
511
506
  return functionResult;
512
507
  }
513
508
  else {
@@ -515,7 +510,7 @@ export class ExecutionContext {
515
510
  }
516
511
  }
517
512
  mergeScope(childScope, namespace) {
518
- this.print('-- merging scope to parent --');
513
+ this.log('-- merging scope to parent --');
519
514
  const currentComponent = this.scope.currentComponent;
520
515
  const currentPin = this.scope.currentPin;
521
516
  const currentWireId = this.scope.currentWireId;
@@ -605,16 +600,16 @@ export class ExecutionContext {
605
600
  this.scope.currentWireId = childScope.currentWireId + wireIdOffset;
606
601
  }
607
602
  this.printPoint('resume at');
608
- this.print('-- nets --');
603
+ this.log('-- nets --');
609
604
  const currentNets = this.scope.getNets();
610
605
  currentNets.reduce((accum, [, , net]) => {
611
606
  if (accum.indexOf(net) === -1) {
612
607
  accum.push(net);
613
- this.print(`${net.namespace}${net.name} ${net.priority}`);
608
+ this.log(`${net.namespace}${net.name} ${net.priority}`);
614
609
  }
615
610
  return accum;
616
611
  }, []);
617
- this.print('-- done merging scope --');
612
+ this.log('-- done merging scope --');
618
613
  }
619
614
  addWire(segments) {
620
615
  if (this.scope.currentComponent === null) {
@@ -633,14 +628,14 @@ export class ExecutionContext {
633
628
  segments.forEach(item => {
634
629
  output.push(item.join(","));
635
630
  });
636
- this.print('add wire: ', output.join("|"));
631
+ this.log('add wire: ', output.join("|"));
637
632
  this.scope.setActive(ActiveObject.Wire, wireId);
638
633
  this.scope.sequence.push([SequenceAction.Wire, wireId, tmp]);
639
634
  this.scope.currentComponent.pinWires.set(this.scope.currentPin, tmp);
640
635
  }
641
636
  addPoint(pointId, userDefined = true) {
642
637
  if (this.scope.instances.has(pointId)) {
643
- this.print('Warning: ' + pointId + ' is being redefined');
638
+ this.log('Warning: ' + pointId + ' is being redefined');
644
639
  }
645
640
  const useName = userDefined ? 'point.' + pointId : pointId;
646
641
  const componentPoint = ClassComponent.simple(useName, 1, "point");
@@ -651,7 +646,7 @@ export class ExecutionContext {
651
646
  return this.getCurrentPoint();
652
647
  }
653
648
  setProperty(nameWithProp, value) {
654
- this.print('set property', nameWithProp, 'value', value);
649
+ this.log('set property', nameWithProp, 'value', value);
655
650
  let idName;
656
651
  let paramName;
657
652
  let useActive = false;
@@ -717,6 +712,9 @@ export function isNetComponent(component) {
717
712
  export function isLabelComponent(component) {
718
713
  return component.parameters.has(ParamKeys.__is_label);
719
714
  }
715
+ export function isNetOnlyComponent(component) {
716
+ return isNetComponent(component) && !isLabelComponent(component);
717
+ }
720
718
  export function getPortSide(pins, arrangeProps) {
721
719
  const result = [];
722
720
  if (arrangeProps === null) {
@@ -52,8 +52,12 @@ export class Label extends Flatten.Polygon {
52
52
  return new Label(id, useText, [x, y], polygon, style, box);
53
53
  }
54
54
  rotate(angle, origin) {
55
- const polygonRotate = super.rotate(angle, origin);
56
- return new Label(this.id, this.text, this.anchorPoint, polygonRotate, this.style, this.textMeasurementBounds);
55
+ const feature = super.rotate(angle, origin);
56
+ return new Label(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds);
57
+ }
58
+ transform(matrix) {
59
+ const feature = super.transform(matrix);
60
+ return new Label(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds);
57
61
  }
58
62
  getLabelPosition() {
59
63
  return this.anchorPoint;
@@ -103,6 +107,10 @@ export class Geometry {
103
107
  const angleRads = angleDegrees * Math.PI / 180;
104
108
  return feature.rotate(angleRads, Geometry.point(center[0], center[1]));
105
109
  }
110
+ static flip(feature, flipX, flipY) {
111
+ const flipMatrix = (new Flatten.Matrix()).scale(flipX === 0 ? 1 : -1, flipY == 0 ? 1 : -1);
112
+ return feature.transform(flipMatrix);
113
+ }
106
114
  static groupRotate(features, angle, center) {
107
115
  const angleRads = angle * Math.PI / 180;
108
116
  const rotateAboutPoint = Geometry.point(center[0], center[1]);
@@ -110,6 +118,12 @@ export class Geometry {
110
118
  return feature.rotate(angleRads, rotateAboutPoint);
111
119
  });
112
120
  }
121
+ static groupFlip(features, flipX, flipY) {
122
+ const flipMatrix = (new Flatten.Matrix()).scale(flipX === 0 ? 1 : -1, flipY == 0 ? 1 : -1);
123
+ return features.map(feature => {
124
+ return feature.transform(flipMatrix);
125
+ });
126
+ }
113
127
  static groupBounds(features) {
114
128
  let minX = Number.POSITIVE_INFINITY;
115
129
  let minY = Number.POSITIVE_INFINITY;
@@ -171,9 +185,7 @@ export class Geometry {
171
185
  }
172
186
  const startPoint = getArcPointRadians(x, y, radius, item.startAngle);
173
187
  const endPoint = getArcPointRadians(x, y, radius, useEndAngle);
174
- paths.push('M ' + startPoint[0] + ' ' + startPoint[1]
175
- + 'A ' + radius + ' ' + radius + ' 0 1 1 '
176
- + endPoint[0] + ' ' + endPoint[1] + extraEnd);
188
+ paths.push('M', startPoint[0], startPoint[1], 'A', radius, radius, 0, 1, 1, endPoint[0], endPoint[1], extraEnd);
177
189
  }
178
190
  else {
179
191
  const coords = Geometry.getCoords(item);
@@ -183,19 +195,27 @@ export class Geometry {
183
195
  for (let i = 0; i < coords.length; i++) {
184
196
  const [x, y] = coords[i];
185
197
  const command = (i === 0) ? 'M' : 'L';
186
- path.push(`${command} ${x} ${y}`);
198
+ path.push(`${command}`, x, y);
187
199
  }
188
200
  if (isClosedPolygon) {
189
201
  path.push('Z');
190
202
  }
191
- paths.push(path.join(' '));
203
+ paths.push(...path);
192
204
  }
193
205
  });
194
206
  return {
195
- path: paths.join(" "),
207
+ path: this.roundPathValues(paths),
196
208
  isClosedPolygon,
197
209
  };
198
210
  }
211
+ static roundPathValues(pathItems) {
212
+ return pathItems.map(item => {
213
+ if (typeof item === 'number') {
214
+ return (+item.toFixed(7)).toString();
215
+ }
216
+ return item;
217
+ }).join(" ");
218
+ }
199
219
  static angle(dx, dy) {
200
220
  const line = new Flatten.Segment(new Flatten.Point(0, 0), new Flatten.Point(dx, dy));
201
221
  return line.slope * 180 / Math.PI;