circuitscript 0.1.23 → 0.1.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.
- package/dist/cjs/BaseVisitor.js +35 -23
- package/dist/cjs/BomGeneration.js +167 -0
- package/dist/cjs/ComponentMatchConditions.js +116 -0
- package/dist/cjs/antlr/CircuitScriptLexer.js +247 -244
- package/dist/cjs/antlr/CircuitScriptParser.js +1476 -825
- package/dist/cjs/builtinMethods.js +6 -1
- package/dist/cjs/execute.js +27 -16
- package/dist/cjs/graph.js +10 -9
- package/dist/cjs/helpers.js +43 -18
- package/dist/cjs/layout.js +14 -13
- package/dist/cjs/main.js +17 -1
- package/dist/cjs/objects/ExecutionScope.js +3 -0
- package/dist/cjs/objects/PinDefinition.js +11 -1
- package/dist/cjs/objects/types.js +6 -4
- package/dist/cjs/rules-check/no-connect-on-connected-pin.js +81 -0
- package/dist/cjs/rules-check/rules.js +74 -0
- package/dist/cjs/rules-check/unconnected-pins.js +52 -0
- package/dist/cjs/visitor.js +121 -5
- package/dist/esm/BaseVisitor.js +35 -23
- package/dist/esm/BomGeneration.js +137 -0
- package/dist/esm/ComponentMatchConditions.js +109 -0
- package/dist/esm/antlr/CircuitScriptLexer.js +247 -244
- package/dist/esm/antlr/CircuitScriptParser.js +1471 -824
- package/dist/esm/antlr/CircuitScriptVisitor.js +7 -0
- package/dist/esm/builtinMethods.js +6 -1
- package/dist/esm/execute.js +27 -16
- package/dist/esm/graph.js +11 -10
- package/dist/esm/helpers.js +43 -18
- package/dist/esm/layout.js +15 -13
- package/dist/esm/main.js +17 -1
- package/dist/esm/objects/ExecutionScope.js +3 -0
- package/dist/esm/objects/PinDefinition.js +11 -1
- package/dist/esm/objects/types.js +7 -5
- package/dist/esm/rules-check/no-connect-on-connected-pin.js +77 -0
- package/dist/esm/rules-check/rules.js +70 -0
- package/dist/esm/rules-check/unconnected-pins.js +48 -0
- package/dist/esm/visitor.js +121 -5
- package/dist/libs/std.cst +7 -3
- package/dist/types/BomGeneration.d.ts +13 -0
- package/dist/types/ComponentMatchConditions.d.ts +19 -0
- package/dist/types/antlr/CircuitScriptLexer.d.ts +60 -59
- package/dist/types/antlr/CircuitScriptParser.d.ts +146 -62
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +14 -0
- package/dist/types/execute.d.ts +2 -1
- package/dist/types/graph.d.ts +6 -1
- package/dist/types/helpers.d.ts +7 -2
- package/dist/types/layout.d.ts +3 -2
- package/dist/types/objects/ExecutionScope.d.ts +8 -2
- package/dist/types/objects/ParamDefinition.d.ts +1 -1
- package/dist/types/objects/PinDefinition.d.ts +1 -0
- package/dist/types/objects/types.d.ts +4 -2
- package/dist/types/rules-check/no-connect-on-connected-pin.d.ts +3 -0
- package/dist/types/rules-check/rules.d.ts +15 -0
- package/dist/types/rules-check/unconnected-pins.d.ts +2 -0
- package/dist/types/visitor.d.ts +10 -1
- package/libs/std.cst +7 -3
- package/package.json +2 -1
|
@@ -79,5 +79,12 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
79
79
|
visitElse_expr;
|
|
80
80
|
visitWhile_expr;
|
|
81
81
|
visitFor_expr;
|
|
82
|
+
visitPart_set_expr;
|
|
83
|
+
visitPart_set_key;
|
|
84
|
+
visitPart_match_block;
|
|
85
|
+
visitPart_sub_expr;
|
|
86
|
+
visitPart_condition_expr;
|
|
87
|
+
visitPart_condition_key_only_expr;
|
|
88
|
+
visitPart_value_expr;
|
|
82
89
|
visitAnnotation_comment_expr;
|
|
83
90
|
}
|
|
@@ -159,7 +159,12 @@ function toString(obj) {
|
|
|
159
159
|
return obj.toDisplayString();
|
|
160
160
|
}
|
|
161
161
|
else if (obj.toString) {
|
|
162
|
-
|
|
162
|
+
if (typeof obj === 'object') {
|
|
163
|
+
return JSON.stringify(obj);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return obj.toString();
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
else {
|
|
165
170
|
throw "Could not create string from object: " + obj;
|
package/dist/esm/execute.js
CHANGED
|
@@ -378,9 +378,9 @@ export class ExecutionContext {
|
|
|
378
378
|
+ pinId + ' in ' + component);
|
|
379
379
|
}
|
|
380
380
|
this.scope.setCurrent(component, usePinId);
|
|
381
|
-
if (!this.scope.hasNet(component,
|
|
381
|
+
if (!this.scope.hasNet(component, usePinId)) {
|
|
382
382
|
const tmpNet = new Net(this.netNamespace, this.getUniqueNetName());
|
|
383
|
-
this.scope.setNet(component,
|
|
383
|
+
this.scope.setNet(component, usePinId, tmpNet);
|
|
384
384
|
}
|
|
385
385
|
this.scope.clearActive();
|
|
386
386
|
if (addSequence) {
|
|
@@ -502,7 +502,9 @@ export class ExecutionContext {
|
|
|
502
502
|
const { start_point: [component, pin, wireId] } = stackRef;
|
|
503
503
|
this.atComponent(component, pin, { addSequence: true });
|
|
504
504
|
if (wireId !== -1) {
|
|
505
|
-
this.scope.
|
|
505
|
+
const wireObject = this.scope.wires[wireId];
|
|
506
|
+
this.scope.sequence.push([SequenceAction.WireJump,
|
|
507
|
+
wireId, PinId.from(1), wireObject]);
|
|
506
508
|
}
|
|
507
509
|
}
|
|
508
510
|
else if (blockType === BlockTypes.Join || blockType === BlockTypes.Parallel) {
|
|
@@ -628,7 +630,7 @@ export class ExecutionContext {
|
|
|
628
630
|
type: isVariable ? ReferenceTypes.variable
|
|
629
631
|
: ReferenceTypes.instance,
|
|
630
632
|
found: (tmpReference.value !== undefined),
|
|
631
|
-
|
|
633
|
+
rootValue: tmpReference.rootValue,
|
|
632
634
|
value: tmpReference.value,
|
|
633
635
|
name: idName,
|
|
634
636
|
trailers,
|
|
@@ -642,16 +644,19 @@ export class ExecutionContext {
|
|
|
642
644
|
});
|
|
643
645
|
}
|
|
644
646
|
resolveTrailers(type, item, trailers = []) {
|
|
645
|
-
let
|
|
647
|
+
let rootValue;
|
|
646
648
|
let useValue = item;
|
|
647
649
|
if (trailers.length > 0) {
|
|
648
|
-
|
|
650
|
+
rootValue = useValue;
|
|
649
651
|
const trailersPath = trailers.join(".");
|
|
650
652
|
if (type === ReferenceTypes.variable) {
|
|
651
|
-
useValue =
|
|
653
|
+
useValue = rootValue;
|
|
654
|
+
trailers.forEach(trailerPath => {
|
|
655
|
+
useValue = useValue[trailerPath];
|
|
656
|
+
});
|
|
652
657
|
}
|
|
653
658
|
else if (type === ReferenceTypes.instance) {
|
|
654
|
-
const tmpComponent =
|
|
659
|
+
const tmpComponent = rootValue;
|
|
655
660
|
if (tmpComponent.typeProp === ComponentTypes.net) {
|
|
656
661
|
const usedNet = this.scope.getNet(tmpComponent, new PinId(1));
|
|
657
662
|
if (usedNet) {
|
|
@@ -660,20 +665,21 @@ export class ExecutionContext {
|
|
|
660
665
|
}
|
|
661
666
|
}
|
|
662
667
|
else {
|
|
663
|
-
useValue =
|
|
668
|
+
useValue = rootValue
|
|
664
669
|
.parameters.get(trailersPath);
|
|
665
670
|
}
|
|
666
671
|
}
|
|
667
672
|
}
|
|
668
673
|
let found = false;
|
|
669
|
-
if (
|
|
674
|
+
if (rootValue !== undefined && useValue !== undefined) {
|
|
670
675
|
found = true;
|
|
671
676
|
}
|
|
672
677
|
return new AnyReference({
|
|
673
678
|
found,
|
|
674
679
|
type: type,
|
|
675
|
-
|
|
680
|
+
rootValue,
|
|
676
681
|
trailers,
|
|
682
|
+
trailerIndex: trailers.length,
|
|
677
683
|
value: useValue,
|
|
678
684
|
});
|
|
679
685
|
}
|
|
@@ -774,13 +780,16 @@ export class ExecutionContext {
|
|
|
774
780
|
childScope.sequence.forEach(sequenceAction => {
|
|
775
781
|
const [action] = sequenceAction;
|
|
776
782
|
if (action === SequenceAction.Wire) {
|
|
777
|
-
const [, innerWireId, segments] = sequenceAction;
|
|
778
|
-
this.scope.sequence.push([SequenceAction.Wire, wireIdOffset + innerWireId,
|
|
783
|
+
const [, innerWireId, segments, wire] = sequenceAction;
|
|
784
|
+
this.scope.sequence.push([SequenceAction.Wire, wireIdOffset + innerWireId,
|
|
785
|
+
segments, wire]);
|
|
779
786
|
this.scope.wires.push(new Wire(segments));
|
|
780
787
|
}
|
|
781
788
|
else if (action === SequenceAction.WireJump) {
|
|
782
789
|
const jumpWireId = wireIdOffset + sequenceAction[1];
|
|
783
|
-
this.scope.
|
|
790
|
+
const wireObject = this.scope.wires[jumpWireId];
|
|
791
|
+
this.scope.sequence.push([SequenceAction.WireJump, jumpWireId,
|
|
792
|
+
PinId.from(1), wireObject]);
|
|
784
793
|
}
|
|
785
794
|
else if (action === SequenceAction.At || action === SequenceAction.To) {
|
|
786
795
|
this.scope.sequence.push(sequenceAction);
|
|
@@ -828,7 +837,8 @@ export class ExecutionContext {
|
|
|
828
837
|
};
|
|
829
838
|
});
|
|
830
839
|
const wireId = this.scope.wires.length;
|
|
831
|
-
|
|
840
|
+
const newWire = new Wire(tmp);
|
|
841
|
+
this.scope.wires.push(newWire);
|
|
832
842
|
const output = [];
|
|
833
843
|
segments.forEach(item => {
|
|
834
844
|
const tmpArray = item.map(item2 => {
|
|
@@ -843,12 +853,13 @@ export class ExecutionContext {
|
|
|
843
853
|
});
|
|
844
854
|
this.log('add wire: ', output.join("|"));
|
|
845
855
|
this.scope.setActive(ActiveObject.Wire, wireId);
|
|
846
|
-
this.scope.sequence.push([SequenceAction.Wire, wireId, tmp]);
|
|
856
|
+
this.scope.sequence.push([SequenceAction.Wire, wireId, tmp, newWire]);
|
|
847
857
|
this.scope.currentComponent.pinWires.set(this.scope.currentPin, tmp);
|
|
848
858
|
if (!this.scope.currentComponent.didSetWireOrientationAngle) {
|
|
849
859
|
this.applyComponentAngleFromWire(this.scope.currentComponent, this.scope.currentPin, true);
|
|
850
860
|
this.scope.currentComponent.didSetWireOrientationAngle = true;
|
|
851
861
|
}
|
|
862
|
+
return newWire;
|
|
852
863
|
}
|
|
853
864
|
addPoint(pointId, userDefined = true) {
|
|
854
865
|
if (this.scope.instances.has(pointId)) {
|
package/dist/esm/graph.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Frame, FixedFrameIds, FrameParamKeys } from "./objects/Frame.js";
|
|
|
8
8
|
import { numeric } from "./objects/ParamDefinition.js";
|
|
9
9
|
import { NetTypes, TypeProps } from "./objects/types.js";
|
|
10
10
|
import Matrix, { solve } from "ml-matrix";
|
|
11
|
-
import { getPinDefinition } from "./objects/PinDefinition.js";
|
|
11
|
+
import { getPinDefinition, PinId } from "./objects/PinDefinition.js";
|
|
12
12
|
export class NetGraph {
|
|
13
13
|
logger;
|
|
14
14
|
constructor(logger) {
|
|
@@ -81,8 +81,9 @@ export class NetGraph {
|
|
|
81
81
|
break;
|
|
82
82
|
}
|
|
83
83
|
case SequenceAction.Wire: {
|
|
84
|
-
const [, wireId,
|
|
84
|
+
const [, wireId, , wire] = sequenceStep;
|
|
85
85
|
let useNet;
|
|
86
|
+
const wireSegments = wire.path;
|
|
86
87
|
if (previousNode !== null) {
|
|
87
88
|
const [prevNodeType, prevNodeItem] = graph.node(previousNode);
|
|
88
89
|
if (prevNodeType === RenderItemType.Component) {
|
|
@@ -98,15 +99,15 @@ export class NetGraph {
|
|
|
98
99
|
useNet = prevNodeItem.net;
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const wireName = getWireName(
|
|
105
|
-
graph.setNode(wireName, [RenderItemType.Wire,
|
|
102
|
+
const renderWire = new RenderWire(useNet, numeric(0), numeric(0), wireSegments, wire);
|
|
103
|
+
renderWire.id = wireId;
|
|
104
|
+
renderWire.netName = useNet.toString();
|
|
105
|
+
const wireName = getWireName(renderWire.id);
|
|
106
|
+
graph.setNode(wireName, [RenderItemType.Wire, renderWire, index]);
|
|
106
107
|
let tmpPreviousNode = previousNode;
|
|
107
|
-
this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, index));
|
|
108
|
+
this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, PinId.from(0), index));
|
|
108
109
|
previousNode = wireName;
|
|
109
|
-
previousPin = 1;
|
|
110
|
+
previousPin = PinId.from(1);
|
|
110
111
|
const wireSegmentsInfo = wireSegments.map(item => {
|
|
111
112
|
const tmp = {
|
|
112
113
|
direction: item.direction,
|
|
@@ -140,7 +141,7 @@ export class NetGraph {
|
|
|
140
141
|
wirePin = sequenceStep[2];
|
|
141
142
|
}
|
|
142
143
|
previousNode = wireName;
|
|
143
|
-
previousPin = wirePin;
|
|
144
|
+
previousPin = PinId.from(wirePin);
|
|
144
145
|
break;
|
|
145
146
|
}
|
|
146
147
|
case SequenceAction.Frame: {
|
package/dist/esm/helpers.js
CHANGED
|
@@ -19,6 +19,8 @@ import Big from "big.js";
|
|
|
19
19
|
import { Logger } from "./logger.js";
|
|
20
20
|
import { NetGraph } from "./graph.js";
|
|
21
21
|
import { RefdesAnnotationVisitor } from "./RefdesAnnotationVisitor.js";
|
|
22
|
+
import { EvaluateERCRules } from "./rules-check/rules.js";
|
|
23
|
+
import { generateBom, generateBomCSV, saveBomOutputCsv } from "./BomGeneration.js";
|
|
22
24
|
export var JSModuleType;
|
|
23
25
|
(function (JSModuleType) {
|
|
24
26
|
JSModuleType["CommonJs"] = "cjs";
|
|
@@ -148,14 +150,33 @@ export async function validateScript(filePath, scriptData, options) {
|
|
|
148
150
|
await visitorResolver.visitAsync(tree);
|
|
149
151
|
return visitorResolver;
|
|
150
152
|
}
|
|
153
|
+
async function DefaultPostAnnotationCallback(options, scriptData, tree, tokens, componentLinks) {
|
|
154
|
+
const { inputPath = null, updateSource = false, saveAnnotatedCopy = undefined, } = options;
|
|
155
|
+
if (inputPath && (updateSource || saveAnnotatedCopy !== undefined)) {
|
|
156
|
+
const refdesVisitor = new RefdesAnnotationVisitor(true, scriptData, tokens, componentLinks);
|
|
157
|
+
await refdesVisitor.visitAsync(tree);
|
|
158
|
+
let usePath = inputPath;
|
|
159
|
+
if (saveAnnotatedCopy === true) {
|
|
160
|
+
const dir = path.dirname(inputPath);
|
|
161
|
+
const ext = path.extname(inputPath);
|
|
162
|
+
const basename = path.basename(inputPath, ext);
|
|
163
|
+
usePath = path.join(dir, `${basename}.annotated${ext}`);
|
|
164
|
+
}
|
|
165
|
+
else if (typeof saveAnnotatedCopy === 'string') {
|
|
166
|
+
usePath = saveAnnotatedCopy;
|
|
167
|
+
}
|
|
168
|
+
console.log('Annotations saved to ' + usePath);
|
|
169
|
+
writeFileSync(usePath, refdesVisitor.getOutput());
|
|
170
|
+
}
|
|
171
|
+
}
|
|
151
172
|
export async function renderScript(scriptData, outputPath, options) {
|
|
152
173
|
const parseHandlers = [
|
|
153
174
|
new KiCadNetListOutputHandler(),
|
|
154
175
|
];
|
|
155
|
-
return renderScriptCustom(scriptData, outputPath, options, parseHandlers);
|
|
176
|
+
return renderScriptCustom(scriptData, outputPath, options, parseHandlers, [DefaultPostAnnotationCallback]);
|
|
156
177
|
}
|
|
157
|
-
export async function renderScriptCustom(scriptData, outputPath, options, parseHandlers) {
|
|
158
|
-
const { dumpNets = false, dumpData = false, showStats = false,
|
|
178
|
+
export async function renderScriptCustom(scriptData, outputPath, options, parseHandlers, postAnnotationCallbacks) {
|
|
179
|
+
const { dumpNets = false, dumpData = false, showStats = false, enableErc = false, enableBom = false, bomOutputPath = undefined, environment } = options;
|
|
159
180
|
const errors = [];
|
|
160
181
|
const onErrorHandler = (message, context, error) => {
|
|
161
182
|
if (error && error instanceof RuntimeExecutionError) {
|
|
@@ -210,21 +231,8 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
210
231
|
throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
|
|
211
232
|
}
|
|
212
233
|
const componentLinks = visitor.getComponentCtxLinks();
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (inputPath && (updateSource || saveAnnotatedCopy !== undefined)) {
|
|
216
|
-
let usePath = inputPath;
|
|
217
|
-
if (saveAnnotatedCopy === true) {
|
|
218
|
-
const dir = path.dirname(inputPath);
|
|
219
|
-
const ext = path.extname(inputPath);
|
|
220
|
-
const basename = path.basename(inputPath, ext);
|
|
221
|
-
usePath = path.join(dir, `${basename}.annotated${ext}`);
|
|
222
|
-
}
|
|
223
|
-
else if (typeof saveAnnotatedCopy === 'string') {
|
|
224
|
-
usePath = saveAnnotatedCopy;
|
|
225
|
-
}
|
|
226
|
-
console.log('Annotations saved to ' + usePath);
|
|
227
|
-
writeFileSync(usePath, refdesVisitor.getOutput());
|
|
234
|
+
for (let i = 0; i < postAnnotationCallbacks.length; i++) {
|
|
235
|
+
await postAnnotationCallbacks[i](options, scriptData, tree, tokens, componentLinks);
|
|
228
236
|
}
|
|
229
237
|
if (dumpNets) {
|
|
230
238
|
const nets = visitor.dumpNets();
|
|
@@ -239,6 +247,14 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
239
247
|
if (errors.length === 0) {
|
|
240
248
|
const { frameComponent } = visitor.applySheetFrameComponent();
|
|
241
249
|
const { sequence, nets } = visitor.getGraph();
|
|
250
|
+
if (enableBom && bomOutputPath) {
|
|
251
|
+
const documentVariable = visitor.getScope().variables.get('document');
|
|
252
|
+
const bomConfig = documentVariable.bom;
|
|
253
|
+
const bomData = generateBom(bomConfig, visitor.getScope().getInstances());
|
|
254
|
+
const bomCsvOutput = generateBomCSV(bomData);
|
|
255
|
+
await saveBomOutputCsv(bomCsvOutput, bomOutputPath);
|
|
256
|
+
console.log('Generated BOM file', bomOutputPath);
|
|
257
|
+
}
|
|
242
258
|
const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
|
|
243
259
|
dumpData && writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
|
|
244
260
|
try {
|
|
@@ -267,6 +283,15 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
267
283
|
try {
|
|
268
284
|
const { graph, containerFrames } = graphEngine.generateLayoutGraph(sequence, nets);
|
|
269
285
|
sheetFrames = layoutEngine.runLayout(graph, containerFrames, nets);
|
|
286
|
+
if (enableErc) {
|
|
287
|
+
const ercResults = EvaluateERCRules(visitor, graph, nets);
|
|
288
|
+
if (ercResults.length > 0) {
|
|
289
|
+
console.log(`ERC found ${ercResults.length} items:`);
|
|
290
|
+
ercResults.forEach((item, index) => {
|
|
291
|
+
console.log(`${(index + 1).toString().padStart(3)}. line ${item.start.line}, column ${item.start.column}: ${item.type} - ${item.message}`);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
270
295
|
}
|
|
271
296
|
catch (err) {
|
|
272
297
|
throw new RenderError(`Error during layout generation: ${err}`, 'layout');
|
package/dist/esm/layout.js
CHANGED
|
@@ -51,23 +51,23 @@ export class LayoutEngine {
|
|
|
51
51
|
const sheetFrameObjects = sheetFrames.map(sheet => {
|
|
52
52
|
const items = this.flattenFrameItems(sheet);
|
|
53
53
|
const components = items.filter(item => item instanceof RenderComponent);
|
|
54
|
-
const
|
|
54
|
+
const renderWires = items.filter(item => item instanceof RenderWire);
|
|
55
55
|
const textObjects = items.filter(item => item instanceof RenderText);
|
|
56
56
|
const frames = items.filter(item => item instanceof RenderFrame);
|
|
57
|
-
const
|
|
58
|
-
|
|
57
|
+
const renderWireGroups = new Map();
|
|
58
|
+
renderWires.forEach(wire => {
|
|
59
59
|
const { netName } = wire;
|
|
60
|
-
if (!
|
|
61
|
-
|
|
60
|
+
if (!renderWireGroups.has(netName)) {
|
|
61
|
+
renderWireGroups.set(netName, []);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
renderWireGroups.get(netName).push(wire);
|
|
64
64
|
});
|
|
65
|
-
const { junctions, mergedWires } = this.findJunctions(
|
|
65
|
+
const { junctions, mergedWires } = this.findJunctions(renderWireGroups, renderNets);
|
|
66
66
|
return {
|
|
67
67
|
frame: sheet,
|
|
68
68
|
frames,
|
|
69
69
|
components,
|
|
70
|
-
wires,
|
|
70
|
+
wires: renderWires,
|
|
71
71
|
textObjects,
|
|
72
72
|
junctions,
|
|
73
73
|
mergedWires
|
|
@@ -119,12 +119,12 @@ export class LayoutEngine {
|
|
|
119
119
|
});
|
|
120
120
|
return items;
|
|
121
121
|
}
|
|
122
|
-
findJunctions(
|
|
122
|
+
findJunctions(renderWireGroups, nets) {
|
|
123
123
|
const junctions = [];
|
|
124
124
|
const mergedWires = [];
|
|
125
125
|
const debugSegments = false;
|
|
126
|
-
for (const [netName,
|
|
127
|
-
const allLines =
|
|
126
|
+
for (const [netName, renderWires] of renderWireGroups) {
|
|
127
|
+
const allLines = renderWires.map(wire => {
|
|
128
128
|
return wire.points.map(pt => {
|
|
129
129
|
return {
|
|
130
130
|
x: wire.x.add(pt.x),
|
|
@@ -843,7 +843,7 @@ export class LayoutEngine {
|
|
|
843
843
|
item.y = fromY.sub(pinPosition.y);
|
|
844
844
|
}
|
|
845
845
|
else if (item instanceof RenderWire) {
|
|
846
|
-
if (pin === 0) {
|
|
846
|
+
if (pin.getValue() === 0) {
|
|
847
847
|
item.x = fromX;
|
|
848
848
|
item.y = fromY;
|
|
849
849
|
}
|
|
@@ -1017,12 +1017,14 @@ export class RenderWire extends RenderObject {
|
|
|
1017
1017
|
points = [];
|
|
1018
1018
|
netName;
|
|
1019
1019
|
net;
|
|
1020
|
-
|
|
1020
|
+
wire;
|
|
1021
|
+
constructor(net, x, y, segments, wire) {
|
|
1021
1022
|
super();
|
|
1022
1023
|
this.net = net;
|
|
1023
1024
|
this.x = x;
|
|
1024
1025
|
this.y = y;
|
|
1025
1026
|
this.segments = segments;
|
|
1027
|
+
this.wire = wire;
|
|
1026
1028
|
this.refreshPoints();
|
|
1027
1029
|
}
|
|
1028
1030
|
refreshPoints() {
|
package/dist/esm/main.js
CHANGED
|
@@ -21,7 +21,9 @@ export default async function main() {
|
|
|
21
21
|
.option('-n, --dump-nets', 'Dump out net information')
|
|
22
22
|
.option('-d, --dump-data', 'Dump data during parsing')
|
|
23
23
|
.option('-s, --stats', 'Show stats during generation')
|
|
24
|
-
.option('-x, --skip-output', 'Skip output generation')
|
|
24
|
+
.option('-x, --skip-output', 'Skip output generation')
|
|
25
|
+
.option('-e, --erc', 'Enable ERC output')
|
|
26
|
+
.option('-b, --bom [output-path]', 'Generate Bill of Materials in csv format');
|
|
25
27
|
program.addHelpText('before', figlet.textSync('circuitscript', {
|
|
26
28
|
font: 'Small Slant'
|
|
27
29
|
}));
|
|
@@ -34,6 +36,9 @@ export default async function main() {
|
|
|
34
36
|
const watchFileChanges = options.watch;
|
|
35
37
|
const dumpNets = options.dumpNets;
|
|
36
38
|
const dumpData = options.dumpData;
|
|
39
|
+
const enableErc = options.erc;
|
|
40
|
+
const enableBom = options.bom !== undefined;
|
|
41
|
+
let bomOutputPath = options.bom;
|
|
37
42
|
if (options.currentDirectory) {
|
|
38
43
|
throw "Parameter not supported yet";
|
|
39
44
|
}
|
|
@@ -72,10 +77,21 @@ export default async function main() {
|
|
|
72
77
|
if (options.annotatedPath !== undefined) {
|
|
73
78
|
saveAnnotatedCopyPath = options.annotatedPath;
|
|
74
79
|
}
|
|
80
|
+
if (enableBom && (bomOutputPath === true || bomOutputPath === undefined)) {
|
|
81
|
+
if (inputFilePath) {
|
|
82
|
+
bomOutputPath = inputFilePath + '.bom.csv';
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
bomOutputPath = 'output.bom.csv';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
75
88
|
const scriptOptions = {
|
|
76
89
|
dumpNets,
|
|
77
90
|
dumpData,
|
|
78
91
|
showStats: options.stats,
|
|
92
|
+
enableErc,
|
|
93
|
+
enableBom,
|
|
94
|
+
bomOutputPath,
|
|
79
95
|
environment: env,
|
|
80
96
|
inputPath: inputFilePath,
|
|
81
97
|
updateSource,
|
|
@@ -165,6 +165,9 @@ export class ExecutionScope {
|
|
|
165
165
|
const propertyTree = this.findPropertyKeyTree(visitor);
|
|
166
166
|
lastHandler && lastHandler(propertyTree, value, valueCtx);
|
|
167
167
|
}
|
|
168
|
+
getInstances() {
|
|
169
|
+
return Array.from(this.instances.values());
|
|
170
|
+
}
|
|
168
171
|
}
|
|
169
172
|
export var SequenceAction;
|
|
170
173
|
(function (SequenceAction) {
|
|
@@ -28,10 +28,20 @@ export class PinId {
|
|
|
28
28
|
}
|
|
29
29
|
equals(other) {
|
|
30
30
|
if (other instanceof PinId) {
|
|
31
|
-
return this.value === other.value
|
|
31
|
+
return this.value === other.value
|
|
32
|
+
&& this.getType() === other.getType();
|
|
32
33
|
}
|
|
33
34
|
return this.value === other;
|
|
34
35
|
}
|
|
36
|
+
getHashValue() {
|
|
37
|
+
if (this.type === PinIdType.Int) {
|
|
38
|
+
return 'int-' + this.value;
|
|
39
|
+
}
|
|
40
|
+
else if (this.type === PinIdType.Str) {
|
|
41
|
+
return 'str-' + this.value;
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
35
45
|
static from(value) {
|
|
36
46
|
if (value instanceof NumericValue) {
|
|
37
47
|
return new PinId(value.toNumber());
|
|
@@ -20,9 +20,10 @@ export class AnyReference {
|
|
|
20
20
|
found = false;
|
|
21
21
|
name;
|
|
22
22
|
trailers = [];
|
|
23
|
+
trailerIndex = -1;
|
|
23
24
|
type;
|
|
24
25
|
value;
|
|
25
|
-
|
|
26
|
+
rootValue;
|
|
26
27
|
referenceName = 'AnyReference';
|
|
27
28
|
constructor(refType) {
|
|
28
29
|
if (refType.value instanceof AnyReference
|
|
@@ -32,9 +33,10 @@ export class AnyReference {
|
|
|
32
33
|
this.found = refType.found;
|
|
33
34
|
this.name = refType.name;
|
|
34
35
|
this.trailers = refType.trailers;
|
|
36
|
+
this.trailerIndex = refType.trailerIndex;
|
|
35
37
|
this.type = refType.type ?? ReferenceTypes.unknown;
|
|
36
38
|
this.value = refType.value;
|
|
37
|
-
this.
|
|
39
|
+
this.rootValue = refType.rootValue;
|
|
38
40
|
}
|
|
39
41
|
toString() {
|
|
40
42
|
return `[${this.referenceName} name: ${this.name} trailers:${this.trailers} found: ${this.found}]`;
|
|
@@ -65,13 +67,13 @@ export class DeclaredReference extends AnyReference {
|
|
|
65
67
|
referenceName = 'DeclaredReference';
|
|
66
68
|
toDisplayString() {
|
|
67
69
|
let returnValue = undefined;
|
|
68
|
-
if (this.
|
|
70
|
+
if (this.rootValue) {
|
|
69
71
|
const trailersString = this.trailers.join(".");
|
|
70
72
|
if (this.type === 'instance') {
|
|
71
|
-
returnValue = this.
|
|
73
|
+
returnValue = this.rootValue.parameters.get(trailersString);
|
|
72
74
|
}
|
|
73
75
|
else if (this.type === 'variable') {
|
|
74
|
-
returnValue = this.
|
|
76
|
+
returnValue = this.rootValue[trailersString];
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
else {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { RenderItemType } from "../graph.js";
|
|
2
|
+
import { ERC_Rules } from "./rules.js";
|
|
3
|
+
export function RuleCheck_NoConnectOnConnectedPin(graph, nets) {
|
|
4
|
+
const allNodes = graph.nodes();
|
|
5
|
+
const items = [];
|
|
6
|
+
const netComponentPins = new Map();
|
|
7
|
+
const pinMapping = new Map();
|
|
8
|
+
const makeComponentPinHash = (instanceName, pin) => {
|
|
9
|
+
return instanceName + '-' + pin.getHashValue();
|
|
10
|
+
};
|
|
11
|
+
nets.forEach(item => {
|
|
12
|
+
const [component, pin, net] = item;
|
|
13
|
+
if (!netComponentPins.has(net)) {
|
|
14
|
+
netComponentPins.set(net, []);
|
|
15
|
+
}
|
|
16
|
+
const items = netComponentPins.get(net);
|
|
17
|
+
items.push([
|
|
18
|
+
component.instanceName,
|
|
19
|
+
pin
|
|
20
|
+
]);
|
|
21
|
+
netComponentPins.set(net, items);
|
|
22
|
+
pinMapping.set(makeComponentPinHash(component.instanceName, pin), net);
|
|
23
|
+
});
|
|
24
|
+
allNodes.forEach(node => {
|
|
25
|
+
const nodeInfo = graph.node(node);
|
|
26
|
+
if (nodeInfo[0] === RenderItemType.Component) {
|
|
27
|
+
const { component } = nodeInfo[1];
|
|
28
|
+
if (component.hasParam('no_connect')) {
|
|
29
|
+
const instanceName = component.instanceName;
|
|
30
|
+
const edges = graph.nodeEdges(node);
|
|
31
|
+
const otherNodes = [];
|
|
32
|
+
edges.forEach(edge => {
|
|
33
|
+
const edgeInfo = graph.edge(edge.v, edge.w);
|
|
34
|
+
let targetComponentName;
|
|
35
|
+
let targetPin;
|
|
36
|
+
if (edge.v === instanceName) {
|
|
37
|
+
otherNodes.push(edge.w);
|
|
38
|
+
targetComponentName = edge.w;
|
|
39
|
+
targetPin = edgeInfo[3];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
targetComponentName = edge.v;
|
|
43
|
+
targetPin = edgeInfo[1];
|
|
44
|
+
}
|
|
45
|
+
const componentPinHash = makeComponentPinHash(targetComponentName, targetPin);
|
|
46
|
+
if (pinMapping.has(componentPinHash)) {
|
|
47
|
+
const net = pinMapping.get(componentPinHash);
|
|
48
|
+
const tmpNetComponentPins = netComponentPins.get(net);
|
|
49
|
+
const remainingItems = tmpNetComponentPins.filter(item => {
|
|
50
|
+
if (item[0] === instanceName) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
else if (item[0] === targetComponentName
|
|
54
|
+
&& item[1].getHashValue() === targetPin.getHashValue()) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
if (remainingItems.length > 0) {
|
|
60
|
+
const targetInfo = graph.node(targetComponentName);
|
|
61
|
+
const tmpComponent = targetInfo[1];
|
|
62
|
+
items.push({
|
|
63
|
+
type: ERC_Rules.NoConnectOnConnectedPin,
|
|
64
|
+
instance: component,
|
|
65
|
+
target: {
|
|
66
|
+
instance: tmpComponent.component,
|
|
67
|
+
pin: targetPin
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return items;
|
|
77
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { RuleCheck_UnconnectedPinsWires } from "./unconnected-pins.js";
|
|
2
|
+
import { RuleCheck_NoConnectOnConnectedPin } from "./no-connect-on-connected-pin.js";
|
|
3
|
+
export var ERC_Rules;
|
|
4
|
+
(function (ERC_Rules) {
|
|
5
|
+
ERC_Rules["UnconnectedPin"] = "UNCONNECTED-PIN";
|
|
6
|
+
ERC_Rules["UnconnectedWire"] = "UNCONNECTED-WIRE";
|
|
7
|
+
ERC_Rules["NoConnectOnConnectedPin"] = "NO-CONNECT-ON-CONNECTED-PIN";
|
|
8
|
+
})(ERC_Rules || (ERC_Rules = {}));
|
|
9
|
+
export function EvaluateERCRules(visitor, graph, nets) {
|
|
10
|
+
const ruleCheckItems = [];
|
|
11
|
+
const creationCtx = visitor.creationCtx;
|
|
12
|
+
ruleCheckItems.push(...RuleCheck_UnconnectedPinsWires(graph), ...RuleCheck_NoConnectOnConnectedPin(graph, nets));
|
|
13
|
+
const reportItems = [];
|
|
14
|
+
ruleCheckItems.forEach(item => {
|
|
15
|
+
const { type } = item;
|
|
16
|
+
switch (type) {
|
|
17
|
+
case ERC_Rules.UnconnectedPin:
|
|
18
|
+
{
|
|
19
|
+
const instance = item.instance;
|
|
20
|
+
const token = getComponentFirstCtxToken(instance);
|
|
21
|
+
if (token) {
|
|
22
|
+
reportItems.push({
|
|
23
|
+
type,
|
|
24
|
+
start: token,
|
|
25
|
+
message: `Unconnected pin ${item.pin} for component`
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
case ERC_Rules.UnconnectedWire:
|
|
31
|
+
{
|
|
32
|
+
const wire = item.wire;
|
|
33
|
+
if (creationCtx.has(wire)) {
|
|
34
|
+
const tmpCtx = creationCtx.get(wire);
|
|
35
|
+
const startToken = tmpCtx.start;
|
|
36
|
+
reportItems.push({
|
|
37
|
+
type,
|
|
38
|
+
start: startToken,
|
|
39
|
+
message: `Unconnected wire end`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case ERC_Rules.NoConnectOnConnectedPin:
|
|
45
|
+
{
|
|
46
|
+
const instance = item.instance;
|
|
47
|
+
const token = getComponentFirstCtxToken(instance);
|
|
48
|
+
if (token) {
|
|
49
|
+
reportItems.push({
|
|
50
|
+
type,
|
|
51
|
+
start: token,
|
|
52
|
+
message: `No connect on connected pin`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const sortedReport = reportItems.toSorted((a, b) => {
|
|
60
|
+
return a.start.start - b.start.start;
|
|
61
|
+
});
|
|
62
|
+
return sortedReport;
|
|
63
|
+
}
|
|
64
|
+
function getComponentFirstCtxToken(instance) {
|
|
65
|
+
if (instance.ctxReferences.length > 0) {
|
|
66
|
+
const { ctx } = instance.ctxReferences[0];
|
|
67
|
+
return ctx.start;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|