circuitscript 0.1.15 → 0.1.16

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.
@@ -32,6 +32,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
32
32
  visitProperty_set_expr;
33
33
  visitDouble_dot_property_set_expr;
34
34
  visitArrayExpr;
35
+ visitArrayIndexExpr;
35
36
  visitFunctionCallExpr;
36
37
  visitAdditionExpr;
37
38
  visitMultiplyExpr;
@@ -49,6 +50,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
49
50
  visitFunction_args_expr;
50
51
  visitAtom_expr;
51
52
  visitTrailer_expr;
53
+ visitTrailer_expr2;
52
54
  visitFunction_call_expr;
53
55
  visitNet_namespace_expr;
54
56
  visitFunction_return_expr;
@@ -1,5 +1,6 @@
1
1
  import Big from "big.js";
2
2
  import { numeric, NumericValue } from "./objects/ParamDefinition.js";
3
+ import { CFunctionEntry } from "./objects/types.js";
3
4
  import { unwrapValue, resolveToNumericValue, RuntimeExecutionError } from "./utils.js";
4
5
  const builtInMethods = [
5
6
  ['enumerate', enumerate],
@@ -144,8 +145,17 @@ function toString(obj) {
144
145
  else if (obj instanceof NumericValue) {
145
146
  return obj.toBigNumber().toString();
146
147
  }
148
+ else if (obj instanceof CFunctionEntry) {
149
+ return obj.toString();
150
+ }
147
151
  else {
148
- if (obj.toDisplayString) {
152
+ if (obj === undefined) {
153
+ return 'undefined';
154
+ }
155
+ else if (obj === null) {
156
+ return 'null';
157
+ }
158
+ else if (obj.toDisplayString) {
149
159
  return obj.toDisplayString();
150
160
  }
151
161
  else if (obj.toString) {
@@ -4,7 +4,7 @@ import { ActiveObject, ExecutionScope, FrameAction, SequenceAction } from './obj
4
4
  import { Net } from './objects/Net.js';
5
5
  import { numeric, NumericValue } from './objects/ParamDefinition.js';
6
6
  import { PortSide } from './objects/PinDefinition.js';
7
- import { AnyReference, DeclaredReference, Direction } from './objects/types.js';
7
+ import { AnyReference, CFunctionEntry, DeclaredReference, Direction } from './objects/types.js';
8
8
  import { Wire } from './objects/Wire.js';
9
9
  import { Frame } from './objects/Frame.js';
10
10
  import { CalculatePinPositions } from './layout.js';
@@ -24,7 +24,7 @@ export class ExecutionContext {
24
24
  returnValue = null;
25
25
  silent = false;
26
26
  logger;
27
- __functionCache = {};
27
+ __functionCache = new Map();
28
28
  parentContext;
29
29
  componentAngleFollowsWire = true;
30
30
  warnings = [];
@@ -538,9 +538,9 @@ export class ExecutionContext {
538
538
  getBreakContext() {
539
539
  return this.scope.breakStack[this.scope.breakStack.length - 1];
540
540
  }
541
- createFunction(functionName, __runFunc) {
542
- this.scope.functions.set(functionName, __runFunc);
543
- this.__functionCache[functionName] = __runFunc;
541
+ createFunction(functionName, __runFunc, source, uniqueId) {
542
+ this.scope.functions.set(functionName, new CFunctionEntry(functionName, __runFunc, source, uniqueId));
543
+ this.__functionCache.set(functionName, __runFunc);
544
544
  this.log(`defined new function '${functionName}'`);
545
545
  }
546
546
  hasFunction(functionName) {
@@ -609,12 +609,17 @@ export class ExecutionContext {
609
609
  }
610
610
  }
611
611
  else {
612
- useValue = parentValue.parameters.get(trailersPath);
612
+ useValue = parentValue
613
+ .parameters.get(trailersPath);
613
614
  }
614
615
  }
615
616
  }
617
+ let found = false;
618
+ if (parentValue !== undefined && useValue !== undefined) {
619
+ found = true;
620
+ }
616
621
  return new AnyReference({
617
- found: true,
622
+ found,
618
623
  type: type,
619
624
  parentValue,
620
625
  trailers,
@@ -623,26 +628,28 @@ export class ExecutionContext {
623
628
  }
624
629
  callFunction(functionName, functionParams, executionStack, netNamespace) {
625
630
  let __runFunc = null;
626
- if (this.__functionCache[functionName] === undefined) {
631
+ if (!this.__functionCache.has(functionName)) {
627
632
  if (this.hasFunction(functionName)) {
628
- __runFunc = this.getFunction(functionName);
633
+ const entry = this.getFunction(functionName);
634
+ __runFunc = entry.execute;
629
635
  }
630
636
  if (__runFunc === null) {
631
637
  this.log(`searching for function ${functionName} in upper context`);
632
638
  const tmpResolveResult = this.resolveVariable(executionStack, functionName);
633
639
  if (tmpResolveResult.found) {
634
- __runFunc = tmpResolveResult.value;
640
+ const entry = tmpResolveResult.value;
641
+ __runFunc = entry.execute;
635
642
  }
636
643
  else {
637
644
  throw `Invalid function ${functionName}`;
638
645
  }
639
646
  }
640
647
  this.log('save function to cache:', functionName);
641
- this.__functionCache[functionName] = __runFunc;
648
+ this.__functionCache.set(functionName, __runFunc);
642
649
  }
643
650
  else {
644
651
  this.log('found function in cache:', functionName);
645
- __runFunc = this.__functionCache[functionName];
652
+ __runFunc = this.__functionCache.get(functionName);
646
653
  }
647
654
  if (__runFunc !== null) {
648
655
  this.log(`call function '${functionName}'`);
@@ -92,6 +92,7 @@ export var ReferenceTypes;
92
92
  ReferenceTypes["variable"] = "variable";
93
93
  ReferenceTypes["instance"] = "instance";
94
94
  ReferenceTypes["pinType"] = "pinType";
95
+ ReferenceTypes["unknown"] = "unknown";
95
96
  })(ReferenceTypes || (ReferenceTypes = {}));
96
97
  export var BlockTypes;
97
98
  (function (BlockTypes) {
@@ -123,3 +124,4 @@ export const RenderFlags = {
123
124
  ShowLabelOrigin: false,
124
125
  };
125
126
  export const SymbolValidatorContext = '_sym';
127
+ export const TrailerArrayIndex = 'index';
@@ -0,0 +1,293 @@
1
+ import { Graph } from "@dagrejs/graphlib";
2
+ import { SymbolDrawing, SymbolPlaceholder, SymbolCustomModule, SymbolCustom } from "./draw_symbols.js";
3
+ import { ComponentTypes } from "./globals.js";
4
+ import { milsToMM } from "./helpers.js";
5
+ import { RenderFrame, RenderComponent, applyComponentParamsToSymbol, RenderWire } from "./layout.js";
6
+ import { SequenceAction, FrameAction } from "./objects/ExecutionScope.js";
7
+ import { Frame, FixedFrameIds, FrameParamKeys } from "./objects/Frame.js";
8
+ import { numeric, NumericValue } from "./objects/ParamDefinition.js";
9
+ export class NetGraph {
10
+ logger;
11
+ constructor(logger) {
12
+ this.logger = logger;
13
+ }
14
+ generateLayoutGraph(sequence, nets) {
15
+ this.print('===== creating graph and populating with nodes =====');
16
+ let previousNode = null;
17
+ let previousPin = null;
18
+ const graph = new Graph({
19
+ directed: true,
20
+ compound: true,
21
+ });
22
+ this.print('sequence length:', sequence.length);
23
+ const baseFrame = new RenderFrame(new Frame(FixedFrameIds.BaseFrame));
24
+ const frameStack = [baseFrame];
25
+ const containerFrames = [baseFrame];
26
+ sequence.forEach((sequenceStep, index) => {
27
+ const action = sequenceStep[0];
28
+ let tmpComponent;
29
+ switch (action) {
30
+ case SequenceAction.To:
31
+ case SequenceAction.At: {
32
+ this.print(...sequenceStep);
33
+ const [, component, pin] = sequenceStep;
34
+ const tmpInstanceName = component.instanceName;
35
+ if (!graph.hasNode(tmpInstanceName)) {
36
+ this.print('create instance', tmpInstanceName);
37
+ const { displayProp = null } = component;
38
+ let tmpSymbol;
39
+ if (displayProp instanceof SymbolDrawing) {
40
+ tmpSymbol = new SymbolPlaceholder(displayProp);
41
+ tmpSymbol.drawing.logger = this.logger;
42
+ }
43
+ else {
44
+ const symbolPinDefinitions = generateLayoutPinDefinition(component);
45
+ if (component.typeProp === ComponentTypes.module) {
46
+ tmpSymbol = new SymbolCustomModule(symbolPinDefinitions, component.pinsMaxPositions);
47
+ }
48
+ else {
49
+ tmpSymbol = new SymbolCustom(symbolPinDefinitions, component.pinsMaxPositions);
50
+ }
51
+ }
52
+ applyComponentParamsToSymbol(component, tmpSymbol);
53
+ tmpSymbol.refreshDrawing();
54
+ const { width: useWidth, height: useHeight } = tmpSymbol.size();
55
+ tmpComponent = new RenderComponent(component, useWidth, useHeight);
56
+ tmpComponent.symbol = tmpSymbol;
57
+ graph.setNode(tmpInstanceName, [RenderItemType.Component, tmpComponent, index]);
58
+ const currentFrame = frameStack[frameStack.length - 1];
59
+ currentFrame && currentFrame.innerItems.push(tmpComponent);
60
+ }
61
+ if (action === SequenceAction.To && previousNode && previousPin) {
62
+ this.setGraphEdge(graph, previousNode, tmpInstanceName, makeEdgeValue(previousNode, previousPin, tmpInstanceName, pin, index));
63
+ }
64
+ previousNode = tmpInstanceName;
65
+ previousPin = pin;
66
+ break;
67
+ }
68
+ case SequenceAction.Wire: {
69
+ const [, wireId, wireSegments] = sequenceStep;
70
+ let useNet;
71
+ if (previousNode !== null) {
72
+ const [prevNodeType, prevNodeItem] = graph.node(previousNode);
73
+ if (prevNodeType === RenderItemType.Component) {
74
+ const matchingItem = nets.find(([comp, pin]) => {
75
+ return comp.instanceName === previousNode
76
+ && pin === previousPin;
77
+ });
78
+ if (matchingItem !== undefined) {
79
+ useNet = matchingItem[2];
80
+ }
81
+ }
82
+ else if (prevNodeType === RenderItemType.Wire) {
83
+ useNet = prevNodeItem.net;
84
+ }
85
+ }
86
+ const wire = new RenderWire(useNet, numeric(0), numeric(0), wireSegments);
87
+ wire.id = wireId;
88
+ wire.netName = useNet.toString();
89
+ const wireName = getWireName(wire.id);
90
+ graph.setNode(wireName, [RenderItemType.Wire, wire, index]);
91
+ this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, index));
92
+ previousNode = wireName;
93
+ previousPin = 1;
94
+ const wireSegmentsInfo = wireSegments.map(item => {
95
+ const tmp = {
96
+ direction: item.direction,
97
+ value: item.value,
98
+ };
99
+ if (item.valueXY) {
100
+ tmp.valueXY = item.valueXY;
101
+ }
102
+ if (item.until) {
103
+ tmp.until = [item.until[0].toString(), item.until[1]];
104
+ }
105
+ return tmp;
106
+ });
107
+ this.print(SequenceAction.Wire, wireId, JSON.stringify(wireSegmentsInfo));
108
+ break;
109
+ }
110
+ case SequenceAction.WireJump: {
111
+ this.print(...sequenceStep);
112
+ const wireId = sequenceStep[1];
113
+ const wireName = getWireName(wireId);
114
+ let wirePin = 1;
115
+ if (sequenceStep.length === 3) {
116
+ wirePin = sequenceStep[2];
117
+ }
118
+ previousNode = wireName;
119
+ previousPin = wirePin;
120
+ break;
121
+ }
122
+ case SequenceAction.Frame: {
123
+ const [, frameObject, frameAction] = sequenceStep;
124
+ if (frameAction === FrameAction.Enter) {
125
+ const prevFrame = frameStack[frameStack.length - 1];
126
+ const newFrame = new RenderFrame(frameObject);
127
+ if (frameObject.parameters.has(FrameParamKeys.Direction)) {
128
+ newFrame.direction =
129
+ frameObject.parameters.get(FrameParamKeys.Direction);
130
+ }
131
+ if (frameObject.parameters.has(FrameParamKeys.Padding)) {
132
+ newFrame.padding = milsToMM(frameObject.parameters.get(FrameParamKeys.Padding));
133
+ }
134
+ if (frameObject.parameters.has(FrameParamKeys.Border)) {
135
+ newFrame.borderWidth =
136
+ frameObject.parameters.get(FrameParamKeys.Border);
137
+ }
138
+ if (frameObject.parameters.has(FrameParamKeys.Width)) {
139
+ newFrame.width = milsToMM(frameObject.parameters.get(FrameParamKeys.Width));
140
+ }
141
+ if (frameObject.parameters.has(FrameParamKeys.Height)) {
142
+ newFrame.height = milsToMM(frameObject.parameters.get(FrameParamKeys.Height));
143
+ }
144
+ containerFrames.push(newFrame);
145
+ frameStack.push(newFrame);
146
+ prevFrame && prevFrame.innerItems.push(newFrame);
147
+ }
148
+ else if (frameAction === FrameAction.Exit) {
149
+ frameStack.pop();
150
+ }
151
+ break;
152
+ }
153
+ }
154
+ });
155
+ this.print('===== done populating graph =====');
156
+ this.print('');
157
+ const logNodesAndEdges = true;
158
+ if (logNodesAndEdges) {
159
+ this.print('===== graph edges =====');
160
+ const allEdges = graph.edges();
161
+ allEdges.forEach(edge => {
162
+ const [nodeId1, pin1, nodeId2, pin2] = graph.edge(edge);
163
+ this.print(nodeId1, 'pin', pin1, '-----', nodeId2, 'pin', pin2);
164
+ });
165
+ this.print('===== end edges =====');
166
+ this.print();
167
+ this.print('===== graph nodes =====');
168
+ const nodes = graph.nodes();
169
+ nodes.forEach(node => {
170
+ this.print(`name:${node}, value:${graph.node(node)}`);
171
+ });
172
+ this.print('===== end nodes =====');
173
+ this.print('');
174
+ }
175
+ return {
176
+ graph,
177
+ containerFrames,
178
+ };
179
+ }
180
+ setGraphEdge(graph, node1, node2, edgeValue) {
181
+ if (!graph.isDirected && graph.hasEdge(node1, node2)) {
182
+ this.print(`Warning: edge already exists ${node1} ${node2}`);
183
+ }
184
+ graph.setEdge(node1, node2, edgeValue);
185
+ this.print(`created edge: node1:${node1} node2:${node2} edgeValue:${edgeValue}`);
186
+ }
187
+ print(...params) {
188
+ this.logger.add(params.join(' '));
189
+ }
190
+ generateNetGraph(nets) {
191
+ const graph = new Graph({
192
+ directed: false
193
+ });
194
+ nets.forEach(item => {
195
+ const [component, pin, net] = item;
196
+ const netNodeName = this.getNetNodeName(net);
197
+ if (!graph.hasNode(netNodeName)) {
198
+ graph.setNode(netNodeName, net);
199
+ }
200
+ const componentNodeName = this.getComponentName(component);
201
+ if (!graph.hasNode(componentNodeName)) {
202
+ graph.setNode(componentNodeName, component);
203
+ }
204
+ graph.setEdge(netNodeName, componentNodeName, [component, pin, net]);
205
+ });
206
+ }
207
+ findNodePaths(graph, startNode, endNode, seenNodes = []) {
208
+ const edges = graph.nodeEdges(startNode);
209
+ const paths = [];
210
+ for (let i = 0; i < edges.length; i++) {
211
+ const edge = edges[i];
212
+ const node1 = edge.v;
213
+ const node2 = edge.w;
214
+ let nextNode = "";
215
+ if (node1 === startNode) {
216
+ nextNode = node2;
217
+ }
218
+ else {
219
+ nextNode = node1;
220
+ }
221
+ if (nextNode === endNode) {
222
+ paths.push([startNode, endNode]);
223
+ continue;
224
+ }
225
+ else if (seenNodes.indexOf(nextNode) !== -1) {
226
+ continue;
227
+ }
228
+ seenNodes.push(startNode);
229
+ const routes = this.findNodePaths(graph, nextNode, endNode, seenNodes);
230
+ for (let j = 0; j < routes.length; j++) {
231
+ paths.push([startNode, ...routes[j]]);
232
+ }
233
+ }
234
+ return paths;
235
+ }
236
+ getNetNodeName(net) {
237
+ return 'net:' + net.toString();
238
+ }
239
+ getComponentName(component) {
240
+ return 'component:' + component.instanceName;
241
+ }
242
+ }
243
+ function makeEdgeValue(instanceName1, instancePin1, instanceName2, instancePin2, priority) {
244
+ return [instanceName1, instancePin1, instanceName2, instancePin2, priority];
245
+ }
246
+ export function getWireName(wireId) {
247
+ return 'wire:' + wireId;
248
+ }
249
+ export function generateLayoutPinDefinition(component) {
250
+ const pins = component.pins;
251
+ const symbolPinDefinitions = [];
252
+ const existingPinIds = Array.from(pins.keys());
253
+ const arrangeProps = component.arrangeProps ?? [];
254
+ const addedPins = [];
255
+ for (const [key, items] of arrangeProps) {
256
+ let useItems;
257
+ if (!Array.isArray(items)) {
258
+ useItems = [items];
259
+ }
260
+ else {
261
+ useItems = [...items];
262
+ }
263
+ useItems.forEach(pinId => {
264
+ if (pinId instanceof NumericValue) {
265
+ const pinIdValue = pinId.toNumber();
266
+ if (existingPinIds.indexOf(pinIdValue) !== -1) {
267
+ const pin = pins.get(pinIdValue);
268
+ symbolPinDefinitions.push({
269
+ side: key,
270
+ pinId: pinIdValue,
271
+ text: pin.name,
272
+ position: pin.position,
273
+ pinType: pin.pinType,
274
+ });
275
+ addedPins.push(pinIdValue);
276
+ }
277
+ }
278
+ });
279
+ }
280
+ const unplacedPins = existingPinIds.filter(pinId => {
281
+ return addedPins.indexOf(pinId) === -1;
282
+ });
283
+ if (unplacedPins.length > 0) {
284
+ component._unplacedPins = unplacedPins;
285
+ console.warn("Warning: There are unplaced pins: " + unplacedPins);
286
+ }
287
+ return symbolPinDefinitions;
288
+ }
289
+ export var RenderItemType;
290
+ (function (RenderItemType) {
291
+ RenderItemType["Wire"] = "wire";
292
+ RenderItemType["Component"] = "component";
293
+ })(RenderItemType || (RenderItemType = {}));
@@ -17,6 +17,7 @@ import { defaultPageMarginMM, defaultZoomScale, LengthUnit, MilsToMM, PxToMM } f
17
17
  import { FrameParamKeys } from "./objects/Frame.js";
18
18
  import Big from "big.js";
19
19
  import { Logger } from "./logger.js";
20
+ import { NetGraph } from "./graph.js";
20
21
  export var JSModuleType;
21
22
  (function (JSModuleType) {
22
23
  JSModuleType["CommonJs"] = "cjs";
@@ -237,11 +238,14 @@ export async function renderScript(scriptData, outputPath, options) {
237
238
  errors,
238
239
  };
239
240
  }
240
- const layoutEngine = new LayoutEngine();
241
+ const logger = new Logger();
242
+ const graphEngine = new NetGraph(logger);
243
+ const layoutEngine = new LayoutEngine(logger);
241
244
  const layoutTimer = new SimpleStopwatch();
242
245
  let sheetFrames;
243
246
  try {
244
- sheetFrames = layoutEngine.runLayout(sequence, nets);
247
+ const { graph, containerFrames } = graphEngine.generateLayoutGraph(sequence, nets);
248
+ sheetFrames = layoutEngine.runLayout(graph, containerFrames, nets);
245
249
  }
246
250
  catch (err) {
247
251
  throw new RenderError(`Error during layout generation: ${err}`, 'layout');