circuitscript 0.1.7 → 0.1.9
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 +7 -6
- package/dist/cjs/draw_symbols.js +3 -0
- package/dist/cjs/execute.js +90 -2
- package/dist/cjs/export.js +0 -5
- package/dist/cjs/helpers.js +20 -2
- package/dist/cjs/layout.js +88 -82
- package/dist/cjs/objects/ClassComponent.js +1 -0
- package/dist/cjs/objects/ExecutionScope.js +5 -4
- package/dist/cjs/regenerate-tests.js +6 -5
- package/dist/cjs/utils.js +57 -14
- package/dist/cjs/validate.js +19 -0
- package/dist/cjs/visitor.js +84 -38
- package/dist/esm/BaseVisitor.js +7 -6
- package/dist/esm/draw_symbols.js +4 -1
- package/dist/esm/execute.js +91 -3
- package/dist/esm/export.js +1 -6
- package/dist/esm/helpers.js +21 -3
- package/dist/esm/layout.js +66 -80
- package/dist/esm/objects/ClassComponent.js +1 -0
- package/dist/esm/objects/ExecutionScope.js +5 -4
- package/dist/esm/regenerate-tests.js +6 -5
- package/dist/esm/utils.js +54 -13
- package/dist/esm/validate.js +19 -0
- package/dist/esm/visitor.js +85 -39
- package/dist/types/BaseVisitor.d.ts +3 -1
- package/dist/types/execute.d.ts +6 -1
- package/dist/types/layout.d.ts +148 -0
- package/dist/types/objects/ClassComponent.d.ts +1 -0
- package/dist/types/objects/ExecutionScope.d.ts +3 -2
- package/dist/types/utils.d.ts +9 -1
- package/dist/types/visitor.d.ts +2 -0
- package/package.json +2 -2
package/dist/esm/layout.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
const {
|
|
1
|
+
import graphlib, { Graph } from '@dagrejs/graphlib';
|
|
2
|
+
const { alg } = graphlib;
|
|
3
3
|
import { SymbolCustom, SymbolDrawing, SymbolCustomModule, SymbolPlaceholder, SymbolText, PlaceHolderCommands } from "./draw_symbols.js";
|
|
4
4
|
import { FrameAction, SequenceAction } from "./objects/ExecutionScope.js";
|
|
5
|
-
import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys,
|
|
5
|
+
import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys, WireAutoDirection } from './globals.js';
|
|
6
6
|
import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.js';
|
|
7
7
|
import { Logger } from './logger.js';
|
|
8
8
|
import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.js';
|
|
@@ -30,7 +30,7 @@ export class LayoutEngine {
|
|
|
30
30
|
return "[" + value + "]" + padding;
|
|
31
31
|
}
|
|
32
32
|
runLayout(sequence, nets) {
|
|
33
|
-
const logNodesAndEdges =
|
|
33
|
+
const logNodesAndEdges = true;
|
|
34
34
|
this.print('===== creating graph and populating with nodes =====');
|
|
35
35
|
const { graph, containerFrames } = this.generateLayoutGraph(sequence, nets);
|
|
36
36
|
this.print('===== done populating graph =====');
|
|
@@ -47,7 +47,7 @@ export class LayoutEngine {
|
|
|
47
47
|
this.print('===== graph nodes =====');
|
|
48
48
|
const nodes = graph.nodes();
|
|
49
49
|
nodes.forEach(node => {
|
|
50
|
-
this.print(node, graph.node(node));
|
|
50
|
+
this.print(`name:${node}, value:${graph.node(node)}`);
|
|
51
51
|
});
|
|
52
52
|
this.print('===== end nodes =====');
|
|
53
53
|
this.print('');
|
|
@@ -606,7 +606,7 @@ export class LayoutEngine {
|
|
|
606
606
|
let previousNode = null;
|
|
607
607
|
let previousPin = null;
|
|
608
608
|
const graph = new Graph({
|
|
609
|
-
directed:
|
|
609
|
+
directed: true,
|
|
610
610
|
compound: true,
|
|
611
611
|
});
|
|
612
612
|
this.print('sequence length:', sequence.length);
|
|
@@ -624,7 +624,7 @@ export class LayoutEngine {
|
|
|
624
624
|
const tmpInstanceName = component.instanceName;
|
|
625
625
|
if (!graph.hasNode(tmpInstanceName)) {
|
|
626
626
|
this.print('create instance', tmpInstanceName);
|
|
627
|
-
const { displayProp = null
|
|
627
|
+
const { displayProp = null } = component;
|
|
628
628
|
let tmpSymbol;
|
|
629
629
|
if (displayProp instanceof SymbolDrawing) {
|
|
630
630
|
tmpSymbol = new SymbolPlaceholder(displayProp);
|
|
@@ -640,26 +640,6 @@ export class LayoutEngine {
|
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
642
|
applyComponentParamsToSymbol(component, tmpSymbol);
|
|
643
|
-
if (component.parameters.has(ParamKeys.angle)) {
|
|
644
|
-
const value = component.parameters.get(ParamKeys.angle).toNumber();
|
|
645
|
-
tmpSymbol.angle = value;
|
|
646
|
-
}
|
|
647
|
-
if (component.parameters.has(ParamKeys.flipX)) {
|
|
648
|
-
tmpSymbol.flipX =
|
|
649
|
-
component.parameters.get(ParamKeys.flipX);
|
|
650
|
-
}
|
|
651
|
-
if (component.parameters.has(ParamKeys.flipY)) {
|
|
652
|
-
tmpSymbol.flipY =
|
|
653
|
-
component.parameters.get(ParamKeys.flipY);
|
|
654
|
-
}
|
|
655
|
-
if (tmpSymbol instanceof SymbolCustom) {
|
|
656
|
-
if (widthProp) {
|
|
657
|
-
tmpSymbol.bodyWidth = milsToMM(widthProp);
|
|
658
|
-
}
|
|
659
|
-
if (heightProp) {
|
|
660
|
-
tmpSymbol.bodyHeight = milsToMM(heightProp);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
643
|
tmpSymbol.refreshDrawing();
|
|
664
644
|
const { width: useWidth, height: useHeight } = tmpSymbol.size();
|
|
665
645
|
tmpComponent = new RenderComponent(component, useWidth, useHeight);
|
|
@@ -765,7 +745,11 @@ export class LayoutEngine {
|
|
|
765
745
|
};
|
|
766
746
|
}
|
|
767
747
|
setGraphEdge(graph, node1, node2, edgeValue) {
|
|
748
|
+
if (!graph.isDirected && graph.hasEdge(node1, node2)) {
|
|
749
|
+
this.print(`Warning: edge already exists ${node1} ${node2}`);
|
|
750
|
+
}
|
|
768
751
|
graph.setEdge(node1, node2, edgeValue);
|
|
752
|
+
this.print(`created edge: node1:${node1} node2:${node2} edgeValue:${edgeValue}`);
|
|
769
753
|
}
|
|
770
754
|
sizeSubGraphs(graph) {
|
|
771
755
|
const subGraphs = alg.components(graph);
|
|
@@ -822,7 +806,6 @@ export class LayoutEngine {
|
|
|
822
806
|
this.placeSubgraphV2(graph, firstNodeId, subgraphEdges);
|
|
823
807
|
}
|
|
824
808
|
placeSubgraphV2(graph, firstNodeId, subgraphEdges) {
|
|
825
|
-
let firstNodePlaced = false;
|
|
826
809
|
const originNodes = [];
|
|
827
810
|
const originNodeGroups = new Map();
|
|
828
811
|
function findOriginNode(node) {
|
|
@@ -848,14 +831,6 @@ export class LayoutEngine {
|
|
|
848
831
|
const [nodeId1, pin1, nodeId2, pin2] = graph.edge(edge);
|
|
849
832
|
const [, node1] = graph.node(nodeId1);
|
|
850
833
|
const [, node2] = graph.node(nodeId2);
|
|
851
|
-
if (nodeId1 === firstNodeId && !firstNodePlaced) {
|
|
852
|
-
this.print('first node placed at origin');
|
|
853
|
-
this.placeNodeAtPosition(numeric(0), numeric(0), node1, pin1);
|
|
854
|
-
firstNodePlaced = true;
|
|
855
|
-
node1.isFloating = false;
|
|
856
|
-
originNodes.push(node1);
|
|
857
|
-
originNodeGroups.set(node1.toString(), [node1]);
|
|
858
|
-
}
|
|
859
834
|
this.print('edge:', '[', node1, pin1, node1.isFloating, ']', '[', node2, pin2, node2.isFloating, ']');
|
|
860
835
|
if (!node1.isFloating && node2.isFloating) {
|
|
861
836
|
fixedNode = node1;
|
|
@@ -933,6 +908,7 @@ export class LayoutEngine {
|
|
|
933
908
|
this.print(`set wire auto end at: ${untilX} ${untilY}`);
|
|
934
909
|
}
|
|
935
910
|
});
|
|
911
|
+
this.print('----');
|
|
936
912
|
});
|
|
937
913
|
}
|
|
938
914
|
mergeOriginNodes(node1, pin1, node2, pin2, originNode1, originNode2, originNodes, originNodeGroups) {
|
|
@@ -1082,61 +1058,69 @@ function generateLayoutPinDefinition(component) {
|
|
|
1082
1058
|
const pins = component.pins;
|
|
1083
1059
|
const symbolPinDefinitions = [];
|
|
1084
1060
|
const existingPinIds = Array.from(pins.keys());
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
pinId: existingPinIds[i],
|
|
1092
|
-
text: pin.name,
|
|
1093
|
-
position: pinPosition,
|
|
1094
|
-
pinType: pin.pinType,
|
|
1095
|
-
});
|
|
1061
|
+
const arrangeProps = component.arrangeProps ?? [];
|
|
1062
|
+
const addedPins = [];
|
|
1063
|
+
for (const [key, items] of arrangeProps) {
|
|
1064
|
+
let useItems;
|
|
1065
|
+
if (!Array.isArray(items)) {
|
|
1066
|
+
useItems = [items];
|
|
1096
1067
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
const addedPins = [];
|
|
1100
|
-
for (const [key, items] of component.arrangeProps) {
|
|
1101
|
-
let useItems;
|
|
1102
|
-
if (!Array.isArray(items)) {
|
|
1103
|
-
useItems = [items];
|
|
1104
|
-
}
|
|
1105
|
-
else {
|
|
1106
|
-
useItems = [...items];
|
|
1107
|
-
}
|
|
1108
|
-
useItems.forEach(pinId => {
|
|
1109
|
-
if (pinId instanceof NumericValue) {
|
|
1110
|
-
const pinIdValue = pinId.toNumber();
|
|
1111
|
-
if (existingPinIds.indexOf(pinIdValue) !== -1) {
|
|
1112
|
-
const pin = pins.get(pinIdValue);
|
|
1113
|
-
symbolPinDefinitions.push({
|
|
1114
|
-
side: key,
|
|
1115
|
-
pinId: pinIdValue,
|
|
1116
|
-
text: pin.name,
|
|
1117
|
-
position: pin.position,
|
|
1118
|
-
pinType: pin.pinType,
|
|
1119
|
-
});
|
|
1120
|
-
addedPins.push(pinIdValue);
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
});
|
|
1068
|
+
else {
|
|
1069
|
+
useItems = [...items];
|
|
1124
1070
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1071
|
+
useItems.forEach(pinId => {
|
|
1072
|
+
if (pinId instanceof NumericValue) {
|
|
1073
|
+
const pinIdValue = pinId.toNumber();
|
|
1074
|
+
if (existingPinIds.indexOf(pinIdValue) !== -1) {
|
|
1075
|
+
const pin = pins.get(pinIdValue);
|
|
1076
|
+
symbolPinDefinitions.push({
|
|
1077
|
+
side: key,
|
|
1078
|
+
pinId: pinIdValue,
|
|
1079
|
+
text: pin.name,
|
|
1080
|
+
position: pin.position,
|
|
1081
|
+
pinType: pin.pinType,
|
|
1082
|
+
});
|
|
1083
|
+
addedPins.push(pinIdValue);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1127
1086
|
});
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1087
|
+
}
|
|
1088
|
+
const unplacedPins = existingPinIds.filter(pinId => {
|
|
1089
|
+
return addedPins.indexOf(pinId) === -1;
|
|
1090
|
+
});
|
|
1091
|
+
if (unplacedPins.length > 0) {
|
|
1092
|
+
component._unplacedPins = unplacedPins;
|
|
1093
|
+
console.warn("Warning: There are unplaced pins: " + unplacedPins);
|
|
1131
1094
|
}
|
|
1132
1095
|
return symbolPinDefinitions;
|
|
1133
1096
|
}
|
|
1134
1097
|
export function applyComponentParamsToSymbol(component, symbol) {
|
|
1098
|
+
const { widthProp = null, heightProp = null } = component;
|
|
1135
1099
|
const newMap = new Map(component.parameters);
|
|
1136
1100
|
if (!newMap.has('refdes')) {
|
|
1137
1101
|
newMap.set('refdes', component.assignedRefDes ?? "?");
|
|
1138
1102
|
}
|
|
1139
1103
|
symbol.drawing.variables = newMap;
|
|
1104
|
+
if (component.parameters.has(ParamKeys.angle)) {
|
|
1105
|
+
const value = component.parameters.get(ParamKeys.angle).toNumber();
|
|
1106
|
+
symbol.angle = value;
|
|
1107
|
+
}
|
|
1108
|
+
if (component.parameters.has(ParamKeys.flipX)) {
|
|
1109
|
+
symbol.flipX =
|
|
1110
|
+
component.parameters.get(ParamKeys.flipX);
|
|
1111
|
+
}
|
|
1112
|
+
if (component.parameters.has(ParamKeys.flipY)) {
|
|
1113
|
+
symbol.flipY =
|
|
1114
|
+
component.parameters.get(ParamKeys.flipY);
|
|
1115
|
+
}
|
|
1116
|
+
if (symbol instanceof SymbolCustom) {
|
|
1117
|
+
if (widthProp) {
|
|
1118
|
+
symbol.bodyWidth = milsToMM(widthProp);
|
|
1119
|
+
}
|
|
1120
|
+
if (heightProp) {
|
|
1121
|
+
symbol.bodyHeight = milsToMM(heightProp);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1140
1124
|
}
|
|
1141
1125
|
function calculateSymbolAngle(symbol, pin, direction) {
|
|
1142
1126
|
let directionVector = 0;
|
|
@@ -1464,7 +1448,9 @@ export function CalculatePinPositions(component) {
|
|
|
1464
1448
|
tmpSymbol.refreshDrawing();
|
|
1465
1449
|
const pins = component.pins;
|
|
1466
1450
|
pins.forEach((value, key) => {
|
|
1467
|
-
|
|
1451
|
+
if (component._unplacedPins.indexOf(key) === -1) {
|
|
1452
|
+
pinPositionMapping.set(key, tmpSymbol.pinPosition(key));
|
|
1453
|
+
}
|
|
1468
1454
|
});
|
|
1469
1455
|
return pinPositionMapping;
|
|
1470
1456
|
}
|
|
@@ -131,12 +131,13 @@ export class ExecutionScope {
|
|
|
131
131
|
exitContext() {
|
|
132
132
|
return this.contextStack.pop();
|
|
133
133
|
}
|
|
134
|
-
findPropertyKeyTree() {
|
|
134
|
+
findPropertyKeyTree(visitor) {
|
|
135
135
|
const keyNames = [];
|
|
136
136
|
for (let i = this.contextStack.length - 1; i >= 0; i--) {
|
|
137
137
|
const ctx = this.contextStack[i];
|
|
138
138
|
if (ctx instanceof Property_key_exprContext) {
|
|
139
|
-
|
|
139
|
+
const result = visitor.visitResult(ctx);
|
|
140
|
+
keyNames.push([ctx, result]);
|
|
140
141
|
}
|
|
141
142
|
else if (typeof ctx === 'number') {
|
|
142
143
|
keyNames.push(['index', ctx]);
|
|
@@ -150,9 +151,9 @@ export class ExecutionScope {
|
|
|
150
151
|
popOnPropertyHandler() {
|
|
151
152
|
return this.onPropertyHandler.pop();
|
|
152
153
|
}
|
|
153
|
-
triggerPropertyHandler(value, valueCtx) {
|
|
154
|
+
triggerPropertyHandler(visitor, value, valueCtx) {
|
|
154
155
|
const lastHandler = this.onPropertyHandler[this.onPropertyHandler.length - 1];
|
|
155
|
-
const propertyTree = this.findPropertyKeyTree();
|
|
156
|
+
const propertyTree = this.findPropertyKeyTree(visitor);
|
|
156
157
|
lastHandler && lastHandler(propertyTree, value, valueCtx);
|
|
157
158
|
}
|
|
158
159
|
}
|
|
@@ -5,7 +5,7 @@ const mainDir = './__tests__/renderData/';
|
|
|
5
5
|
const env = new NodeScriptEnvironment();
|
|
6
6
|
NodeScriptEnvironment.setInstance(env);
|
|
7
7
|
async function regenerateTests(extra = "") {
|
|
8
|
-
env.prepareSVGEnvironment();
|
|
8
|
+
await env.prepareSVGEnvironment();
|
|
9
9
|
const cstFiles = [];
|
|
10
10
|
const files = fs.readdirSync(mainDir);
|
|
11
11
|
files.forEach(file => {
|
|
@@ -13,19 +13,20 @@ async function regenerateTests(extra = "") {
|
|
|
13
13
|
cstFiles.push(file);
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
|
-
cstFiles.
|
|
16
|
+
for (let i = 0; i < cstFiles.length; i++) {
|
|
17
|
+
const file = cstFiles[i];
|
|
17
18
|
const inputPath = mainDir + file;
|
|
18
19
|
const scriptData = fs.readFileSync(inputPath, { encoding: 'utf-8' });
|
|
19
20
|
const outputPath = mainDir + 'svgs/' + file + extra + '.svg';
|
|
20
21
|
env.setModuleDirectory(mainDir);
|
|
21
|
-
|
|
22
|
+
env.setDefaultLibsPath(mainDir + '../../libs/');
|
|
23
|
+
await renderScript(scriptData, outputPath, {
|
|
22
24
|
dumpNets: false,
|
|
23
25
|
dumpData: false,
|
|
24
26
|
showStats: false,
|
|
25
27
|
environment: env,
|
|
26
28
|
});
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
+
}
|
|
29
30
|
return cstFiles;
|
|
30
31
|
}
|
|
31
32
|
(async () => {
|
package/dist/esm/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Big } from 'big.js';
|
|
2
|
+
import { ParserRuleContext } from "antlr4ng";
|
|
2
3
|
import { ClassComponent } from "./objects/ClassComponent.js";
|
|
3
4
|
import { NumericValue } from "./objects/ParamDefinition.js";
|
|
4
5
|
import { SequenceAction } from './objects/ExecutionScope.js';
|
|
@@ -243,30 +244,52 @@ export class BaseError extends Error {
|
|
|
243
244
|
startToken;
|
|
244
245
|
endToken;
|
|
245
246
|
filePath;
|
|
246
|
-
constructor(message,
|
|
247
|
+
constructor(message, startTokenOrCtx, endToken, filePath) {
|
|
247
248
|
super(message);
|
|
248
249
|
this.message = message;
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
if (startTokenOrCtx instanceof ParserRuleContext) {
|
|
251
|
+
this.startToken = startTokenOrCtx.start;
|
|
252
|
+
this.endToken = startTokenOrCtx.stop;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
this.startToken = startTokenOrCtx;
|
|
256
|
+
this.endToken = endToken;
|
|
257
|
+
}
|
|
251
258
|
this.filePath = filePath;
|
|
252
259
|
}
|
|
253
260
|
toString() {
|
|
254
261
|
const parts = [this.name];
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
parts.push(` at ${line}:${column}`);
|
|
264
|
-
}
|
|
262
|
+
const linePosition = getLinePositionAsString({
|
|
263
|
+
start: this.startToken,
|
|
264
|
+
stop: this.endToken
|
|
265
|
+
});
|
|
266
|
+
if (linePosition !== null) {
|
|
267
|
+
parts.push(linePosition);
|
|
265
268
|
}
|
|
266
269
|
parts.push(`: ${this.message}`);
|
|
267
270
|
return parts.join('');
|
|
268
271
|
}
|
|
269
272
|
}
|
|
273
|
+
export function getLinePositionAsString(ctx) {
|
|
274
|
+
if (ctx === null || ctx === undefined) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
const startToken = ctx.start;
|
|
278
|
+
const endToken = ctx.stop;
|
|
279
|
+
let result = null;
|
|
280
|
+
if (startToken) {
|
|
281
|
+
const { line, column } = startToken;
|
|
282
|
+
if (endToken && (endToken.line !== startToken.line || endToken.column !== startToken.column)) {
|
|
283
|
+
const endLine = endToken.line;
|
|
284
|
+
const endColumn = endToken.column + (endToken.stop - endToken.start);
|
|
285
|
+
result = ` at ${line}:${column}-${endLine}:${endColumn}`;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
result = ` at ${line}:${column}`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
270
293
|
export class ParseSyntaxError extends BaseError {
|
|
271
294
|
name = 'ParseSyntaxError';
|
|
272
295
|
}
|
|
@@ -284,3 +307,21 @@ export class RenderError extends Error {
|
|
|
284
307
|
this.stage = stage;
|
|
285
308
|
}
|
|
286
309
|
}
|
|
310
|
+
export function printWarnings(warnings) {
|
|
311
|
+
const warningMessages = [];
|
|
312
|
+
warnings.forEach(item => {
|
|
313
|
+
const { message } = item;
|
|
314
|
+
const linePosition = getLinePositionAsString(item.ctx);
|
|
315
|
+
const parts = [message];
|
|
316
|
+
if (linePosition !== null) {
|
|
317
|
+
parts.push(linePosition);
|
|
318
|
+
}
|
|
319
|
+
const finalMessage = parts.join('');
|
|
320
|
+
if (warningMessages.indexOf(finalMessage) === -1) {
|
|
321
|
+
warningMessages.push(finalMessage);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
warningMessages.forEach(message => {
|
|
325
|
+
console.log(`Warning: ${message}`);
|
|
326
|
+
});
|
|
327
|
+
}
|
package/dist/esm/validate.js
CHANGED
|
@@ -67,6 +67,7 @@ export default async function validate() {
|
|
|
67
67
|
};
|
|
68
68
|
const visitor = await validateScript(inputFilePath, scriptData, scriptOptions);
|
|
69
69
|
const symbols = visitor.getSymbols().getSymbols();
|
|
70
|
+
const undefinedSymbols = [];
|
|
70
71
|
symbols.forEach((value, key) => {
|
|
71
72
|
if (value.type !== ParseSymbolType.Undefined) {
|
|
72
73
|
value = value;
|
|
@@ -76,11 +77,29 @@ export default async function validate() {
|
|
|
76
77
|
console.log(" " + instance.line + ":" + instance.column + " " + instance.start);
|
|
77
78
|
});
|
|
78
79
|
}
|
|
80
|
+
else {
|
|
81
|
+
undefinedSymbols.push(value);
|
|
82
|
+
}
|
|
79
83
|
});
|
|
80
84
|
const { parsedTokens } = await getSemanticTokens(scriptData, scriptOptions);
|
|
81
85
|
parsedTokens.forEach(item => {
|
|
82
86
|
const { line, column, tokenType, tokenModifiers, textValue } = item;
|
|
83
87
|
console.log(`${line}:${column} - ${textValue} - ${tokenType} | ${tokenModifiers.join(',')}`);
|
|
84
88
|
});
|
|
89
|
+
console.log('--- undefined ---');
|
|
90
|
+
undefinedSymbols.forEach(symbol => {
|
|
91
|
+
const { token } = symbol;
|
|
92
|
+
const info = {
|
|
93
|
+
start: {
|
|
94
|
+
line: (token?.line || 1),
|
|
95
|
+
character: token?.column || 0
|
|
96
|
+
},
|
|
97
|
+
end: {
|
|
98
|
+
line: (token?.line || 1),
|
|
99
|
+
character: (token?.column || 0) + ((token?.stop || 0) - (token?.start || 0) + 1)
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
console.log(token.text, info);
|
|
103
|
+
});
|
|
85
104
|
}
|
|
86
105
|
validate();
|
package/dist/esm/visitor.js
CHANGED
|
@@ -47,7 +47,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
catch (err) {
|
|
50
|
-
throw new RuntimeExecutionError(err.message, ctx
|
|
50
|
+
throw new RuntimeExecutionError(err.message, ctx);
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
return this.getExecutor().getCurrentPoint();
|
|
@@ -115,6 +115,24 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
115
115
|
};
|
|
116
116
|
visitCreate_component_expr = (ctx) => {
|
|
117
117
|
const scope = this.getScope();
|
|
118
|
+
const definedPinIds = [];
|
|
119
|
+
const arrangedPinIds = [];
|
|
120
|
+
const checkPinExistsAndNotDuplicated = (pinId, ctx) => {
|
|
121
|
+
if (definedPinIds.indexOf(pinId) === -1) {
|
|
122
|
+
this.warnings.push({
|
|
123
|
+
message: `Invalid pin ${pinId}`, ctx
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (arrangedPinIds.indexOf(pinId) !== -1) {
|
|
127
|
+
this.warnings.push({
|
|
128
|
+
message: `Pin ${pinId} specified more than once`,
|
|
129
|
+
ctx,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
arrangedPinIds.push(pinId);
|
|
133
|
+
};
|
|
134
|
+
let didDefineArrangeProp = false;
|
|
135
|
+
let didDefineDisplayProp = false;
|
|
118
136
|
scope.setOnPropertyHandler((path, value, ctx) => {
|
|
119
137
|
if (path.length === 1) {
|
|
120
138
|
const [, keyName] = path[0];
|
|
@@ -127,9 +145,25 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
127
145
|
case 'height':
|
|
128
146
|
this.validateNumeric(value, ctx);
|
|
129
147
|
break;
|
|
148
|
+
case 'display':
|
|
149
|
+
if (didDefineArrangeProp) {
|
|
150
|
+
throw new RuntimeExecutionError("arrange property has already been defined", ctx);
|
|
151
|
+
}
|
|
152
|
+
didDefineDisplayProp = true;
|
|
153
|
+
break;
|
|
154
|
+
case 'arrange':
|
|
155
|
+
if (didDefineDisplayProp) {
|
|
156
|
+
throw new RuntimeExecutionError("display property already defined", ctx);
|
|
157
|
+
}
|
|
158
|
+
didDefineArrangeProp = true;
|
|
159
|
+
break;
|
|
130
160
|
case 'pins':
|
|
131
161
|
if (!(value instanceof Map)) {
|
|
132
162
|
this.validateNumeric(value, ctx);
|
|
163
|
+
const numPins = value.toNumber();
|
|
164
|
+
for (let i = 0; i < numPins; i++) {
|
|
165
|
+
definedPinIds.push(i + 1);
|
|
166
|
+
}
|
|
133
167
|
}
|
|
134
168
|
break;
|
|
135
169
|
case 'copy':
|
|
@@ -140,7 +174,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
140
174
|
this.validateBoolean(value, ctx);
|
|
141
175
|
}
|
|
142
176
|
else {
|
|
143
|
-
throw new RuntimeExecutionError("Invalid value for 'copy' property", ctx
|
|
177
|
+
throw new RuntimeExecutionError("Invalid value for 'copy' property", ctx);
|
|
144
178
|
}
|
|
145
179
|
break;
|
|
146
180
|
}
|
|
@@ -150,20 +184,26 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
150
184
|
if (keyName === 'arrange') {
|
|
151
185
|
const [sideKeyCtx, sideKeyName] = path[1];
|
|
152
186
|
if (ValidPinSides.indexOf(sideKeyName) === -1) {
|
|
153
|
-
throw new RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx
|
|
187
|
+
throw new RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx);
|
|
154
188
|
}
|
|
155
189
|
else {
|
|
156
|
-
if (path.length
|
|
190
|
+
if (path.length === 2 && value instanceof NumericValue) {
|
|
191
|
+
checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
|
|
192
|
+
}
|
|
193
|
+
else if (path.length > 2 && path[2][0] === 'index') {
|
|
157
194
|
if (Array.isArray(value)) {
|
|
158
195
|
const goodBlank = value.length === 1 &&
|
|
159
196
|
value[0] instanceof NumericValue;
|
|
160
197
|
if (!goodBlank) {
|
|
161
|
-
throw new RuntimeExecutionError(`Invalid blank specifier`, ctx
|
|
198
|
+
throw new RuntimeExecutionError(`Invalid blank specifier`, ctx);
|
|
162
199
|
}
|
|
163
200
|
}
|
|
164
201
|
else {
|
|
165
202
|
if (!(value instanceof NumericValue)) {
|
|
166
|
-
throw new RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx
|
|
203
|
+
throw new RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
|
|
167
207
|
}
|
|
168
208
|
}
|
|
169
209
|
}
|
|
@@ -184,10 +224,12 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
184
224
|
}
|
|
185
225
|
else if (keyName === 'pins') {
|
|
186
226
|
if (path.length === 2) {
|
|
227
|
+
const idName = path[1][1];
|
|
228
|
+
definedPinIds.push(idName);
|
|
187
229
|
if (value.length === 2) {
|
|
188
230
|
const [pinType,] = value;
|
|
189
231
|
if (pinType instanceof UndeclaredReference) {
|
|
190
|
-
throw new RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx
|
|
232
|
+
throw new RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx);
|
|
191
233
|
}
|
|
192
234
|
}
|
|
193
235
|
}
|
|
@@ -416,7 +458,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
416
458
|
this.getScope().enterContext(ctxValue);
|
|
417
459
|
const keyName = this.visitResult(ctxKey);
|
|
418
460
|
const value = this.visitResult(ctxValue);
|
|
419
|
-
scope.triggerPropertyHandler(value, ctxValue);
|
|
461
|
+
scope.triggerPropertyHandler(this, value, ctxValue);
|
|
420
462
|
this.getScope().exitContext();
|
|
421
463
|
this.getScope().exitContext();
|
|
422
464
|
if (value instanceof UndeclaredReference && (value.reference.parentValue === undefined
|
|
@@ -437,7 +479,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
437
479
|
value = ctx.data_expr().map((item, index) => {
|
|
438
480
|
this.getScope().enterContext(index);
|
|
439
481
|
const result = this.visitResult(item);
|
|
440
|
-
this.getScope().triggerPropertyHandler(result, item);
|
|
482
|
+
this.getScope().triggerPropertyHandler(this, result, item);
|
|
441
483
|
this.getScope().exitContext();
|
|
442
484
|
return result;
|
|
443
485
|
});
|
|
@@ -1063,45 +1105,46 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
1063
1105
|
parseCreateComponentPins(pinData) {
|
|
1064
1106
|
const pins = [];
|
|
1065
1107
|
if (pinData instanceof NumericValue) {
|
|
1108
|
+
const tmpMap = new Map();
|
|
1066
1109
|
const lastPin = pinData.toNumber();
|
|
1067
1110
|
for (let i = 0; i < lastPin; i++) {
|
|
1068
1111
|
const pinId = i + 1;
|
|
1069
|
-
|
|
1112
|
+
tmpMap.set(pinId, numeric(pinId));
|
|
1070
1113
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
else {
|
|
1093
|
-
pinName = pinDef[0];
|
|
1094
|
-
if (pinDef.length > 1) {
|
|
1095
|
-
altPinNames = pinDef.slice(1);
|
|
1096
|
-
}
|
|
1114
|
+
pinData = tmpMap;
|
|
1115
|
+
}
|
|
1116
|
+
pinData = pinData ?? [];
|
|
1117
|
+
for (const [pinId, pinDef] of pinData) {
|
|
1118
|
+
let pinIdType = PinIdType.Int;
|
|
1119
|
+
let pinType = PinTypes.Any;
|
|
1120
|
+
let pinName = null;
|
|
1121
|
+
let altPinNames = [];
|
|
1122
|
+
if (typeof pinId === 'string') {
|
|
1123
|
+
pinIdType = PinIdType.Str;
|
|
1124
|
+
}
|
|
1125
|
+
if (Array.isArray(pinDef)) {
|
|
1126
|
+
const firstValue = pinDef[0];
|
|
1127
|
+
if (firstValue.type
|
|
1128
|
+
&& firstValue.type === ReferenceTypes.pinType
|
|
1129
|
+
&& this.pinTypes.indexOf(firstValue.value) !== -1) {
|
|
1130
|
+
pinType = firstValue.value;
|
|
1131
|
+
pinName = pinDef[1];
|
|
1132
|
+
if (pinDef.length > 2) {
|
|
1133
|
+
altPinNames = pinDef.slice(2);
|
|
1097
1134
|
}
|
|
1098
1135
|
}
|
|
1099
1136
|
else {
|
|
1100
|
-
pinName = pinDef;
|
|
1137
|
+
pinName = pinDef[0];
|
|
1138
|
+
if (pinDef.length > 1) {
|
|
1139
|
+
altPinNames = pinDef.slice(1);
|
|
1140
|
+
}
|
|
1101
1141
|
}
|
|
1102
|
-
this.log('pins', pinId, pinIdType, pinName, pinType, altPinNames);
|
|
1103
|
-
pins.push(new PinDefinition(pinId, pinIdType, pinName, pinType, altPinNames));
|
|
1104
1142
|
}
|
|
1143
|
+
else {
|
|
1144
|
+
pinName = pinDef;
|
|
1145
|
+
}
|
|
1146
|
+
this.log('pins', pinId, pinIdType, pinName, pinType, altPinNames);
|
|
1147
|
+
pins.push(new PinDefinition(pinId, pinIdType, pinName, pinType, altPinNames));
|
|
1105
1148
|
}
|
|
1106
1149
|
return pins;
|
|
1107
1150
|
}
|
|
@@ -1310,6 +1353,9 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
1310
1353
|
});
|
|
1311
1354
|
return properties;
|
|
1312
1355
|
}
|
|
1356
|
+
getWarnings() {
|
|
1357
|
+
return this.warnings;
|
|
1358
|
+
}
|
|
1313
1359
|
}
|
|
1314
1360
|
const ComponentRefDesPrefixes = {
|
|
1315
1361
|
res: 'R',
|