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/utils.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RenderError = exports.RuntimeExecutionError = exports.ParseError = exports.ParseSyntaxError = exports.BaseError = exports.getBlockTypeString = exports.generateDebugSequenceAction = exports.sequenceActionString = exports.areasOverlap = exports.isPointWithinArea = exports.resolveToNumericValue = exports.getNumberExponentialText = exports.getNumberExponential = exports.combineMaps = exports.throwWithTokenRange = exports.throwWithToken = exports.throwWithContext = exports.roundValue = exports.getPortType = exports.getBoundsSize = exports.toNearestGrid = exports.resizeToNearestGrid = exports.printBounds = exports.resizeBounds = exports.SimpleStopwatch = void 0;
3
+ exports.printWarnings = exports.RenderError = exports.RuntimeExecutionError = exports.ParseError = exports.ParseSyntaxError = exports.getLinePositionAsString = exports.BaseError = exports.getBlockTypeString = exports.generateDebugSequenceAction = exports.sequenceActionString = exports.areasOverlap = exports.isPointWithinArea = exports.resolveToNumericValue = exports.getNumberExponentialText = exports.getNumberExponential = exports.combineMaps = exports.throwWithTokenRange = exports.throwWithToken = exports.throwWithContext = exports.roundValue = exports.getPortType = exports.getBoundsSize = exports.toNearestGrid = exports.resizeToNearestGrid = exports.printBounds = exports.resizeBounds = exports.SimpleStopwatch = void 0;
4
4
  const big_js_1 = require("big.js");
5
+ const antlr4ng_1 = require("antlr4ng");
5
6
  const ClassComponent_js_1 = require("./objects/ClassComponent.js");
6
7
  const ParamDefinition_js_1 = require("./objects/ParamDefinition.js");
7
8
  const ExecutionScope_js_1 = require("./objects/ExecutionScope.js");
@@ -260,32 +261,55 @@ function getBlockTypeString(type) {
260
261
  }
261
262
  exports.getBlockTypeString = getBlockTypeString;
262
263
  class BaseError extends Error {
263
- constructor(message, startToken, endToken, filePath) {
264
+ constructor(message, startTokenOrCtx, endToken, filePath) {
264
265
  super(message);
265
266
  this.name = 'BaseError';
266
267
  this.message = message;
267
- this.startToken = startToken;
268
- this.endToken = endToken;
268
+ if (startTokenOrCtx instanceof antlr4ng_1.ParserRuleContext) {
269
+ this.startToken = startTokenOrCtx.start;
270
+ this.endToken = startTokenOrCtx.stop;
271
+ }
272
+ else {
273
+ this.startToken = startTokenOrCtx;
274
+ this.endToken = endToken;
275
+ }
269
276
  this.filePath = filePath;
270
277
  }
271
278
  toString() {
272
279
  const parts = [this.name];
273
- if (this.startToken) {
274
- const { line, column } = this.startToken;
275
- if (this.endToken && (this.endToken.line !== this.startToken.line || this.endToken.column !== this.startToken.column)) {
276
- const endLine = this.endToken.line;
277
- const endColumn = this.endToken.column + (this.endToken.stop - this.endToken.start);
278
- parts.push(` at ${line}:${column}-${endLine}:${endColumn}`);
279
- }
280
- else {
281
- parts.push(` at ${line}:${column}`);
282
- }
280
+ const linePosition = getLinePositionAsString({
281
+ start: this.startToken,
282
+ stop: this.endToken
283
+ });
284
+ if (linePosition !== null) {
285
+ parts.push(linePosition);
283
286
  }
284
287
  parts.push(`: ${this.message}`);
285
288
  return parts.join('');
286
289
  }
287
290
  }
288
291
  exports.BaseError = BaseError;
292
+ function getLinePositionAsString(ctx) {
293
+ if (ctx === null || ctx === undefined) {
294
+ return null;
295
+ }
296
+ const startToken = ctx.start;
297
+ const endToken = ctx.stop;
298
+ let result = null;
299
+ if (startToken) {
300
+ const { line, column } = startToken;
301
+ if (endToken && (endToken.line !== startToken.line || endToken.column !== startToken.column)) {
302
+ const endLine = endToken.line;
303
+ const endColumn = endToken.column + (endToken.stop - endToken.start);
304
+ result = ` at ${line}:${column}-${endLine}:${endColumn}`;
305
+ }
306
+ else {
307
+ result = ` at ${line}:${column}`;
308
+ }
309
+ }
310
+ return result;
311
+ }
312
+ exports.getLinePositionAsString = getLinePositionAsString;
289
313
  class ParseSyntaxError extends BaseError {
290
314
  constructor() {
291
315
  super(...arguments);
@@ -315,3 +339,22 @@ class RenderError extends Error {
315
339
  }
316
340
  }
317
341
  exports.RenderError = RenderError;
342
+ function printWarnings(warnings) {
343
+ const warningMessages = [];
344
+ warnings.forEach(item => {
345
+ const { message } = item;
346
+ const linePosition = getLinePositionAsString(item.ctx);
347
+ const parts = [message];
348
+ if (linePosition !== null) {
349
+ parts.push(linePosition);
350
+ }
351
+ const finalMessage = parts.join('');
352
+ if (warningMessages.indexOf(finalMessage) === -1) {
353
+ warningMessages.push(finalMessage);
354
+ }
355
+ });
356
+ warningMessages.forEach(message => {
357
+ console.log(`Warning: ${message}`);
358
+ });
359
+ }
360
+ exports.printWarnings = printWarnings;
@@ -69,6 +69,7 @@ async function validate() {
69
69
  };
70
70
  const visitor = await (0, helpers_js_1.validateScript)(inputFilePath, scriptData, scriptOptions);
71
71
  const symbols = visitor.getSymbols().getSymbols();
72
+ const undefinedSymbols = [];
72
73
  symbols.forEach((value, key) => {
73
74
  if (value.type !== types_js_1.ParseSymbolType.Undefined) {
74
75
  value = value;
@@ -78,12 +79,30 @@ async function validate() {
78
79
  console.log(" " + instance.line + ":" + instance.column + " " + instance.start);
79
80
  });
80
81
  }
82
+ else {
83
+ undefinedSymbols.push(value);
84
+ }
81
85
  });
82
86
  const { parsedTokens } = await (0, helpers_js_1.getSemanticTokens)(scriptData, scriptOptions);
83
87
  parsedTokens.forEach(item => {
84
88
  const { line, column, tokenType, tokenModifiers, textValue } = item;
85
89
  console.log(`${line}:${column} - ${textValue} - ${tokenType} | ${tokenModifiers.join(',')}`);
86
90
  });
91
+ console.log('--- undefined ---');
92
+ undefinedSymbols.forEach(symbol => {
93
+ const { token } = symbol;
94
+ const info = {
95
+ start: {
96
+ line: (token?.line || 1),
97
+ character: token?.column || 0
98
+ },
99
+ end: {
100
+ line: (token?.line || 1),
101
+ character: (token?.column || 0) + ((token?.stop || 0) - (token?.start || 0) + 1)
102
+ }
103
+ };
104
+ console.log(token.text, info);
105
+ });
87
106
  }
88
107
  exports.default = validate;
89
108
  validate();
@@ -52,7 +52,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
52
52
  });
53
53
  }
54
54
  catch (err) {
55
- throw new utils_js_1.RuntimeExecutionError(err.message, ctx.start, ctx.stop);
55
+ throw new utils_js_1.RuntimeExecutionError(err.message, ctx);
56
56
  }
57
57
  });
58
58
  return this.getExecutor().getCurrentPoint();
@@ -120,6 +120,24 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
120
120
  };
121
121
  this.visitCreate_component_expr = (ctx) => {
122
122
  const scope = this.getScope();
123
+ const definedPinIds = [];
124
+ const arrangedPinIds = [];
125
+ const checkPinExistsAndNotDuplicated = (pinId, ctx) => {
126
+ if (definedPinIds.indexOf(pinId) === -1) {
127
+ this.warnings.push({
128
+ message: `Invalid pin ${pinId}`, ctx
129
+ });
130
+ }
131
+ if (arrangedPinIds.indexOf(pinId) !== -1) {
132
+ this.warnings.push({
133
+ message: `Pin ${pinId} specified more than once`,
134
+ ctx,
135
+ });
136
+ }
137
+ arrangedPinIds.push(pinId);
138
+ };
139
+ let didDefineArrangeProp = false;
140
+ let didDefineDisplayProp = false;
123
141
  scope.setOnPropertyHandler((path, value, ctx) => {
124
142
  if (path.length === 1) {
125
143
  const [, keyName] = path[0];
@@ -132,9 +150,25 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
132
150
  case 'height':
133
151
  this.validateNumeric(value, ctx);
134
152
  break;
153
+ case 'display':
154
+ if (didDefineArrangeProp) {
155
+ throw new utils_js_1.RuntimeExecutionError("arrange property has already been defined", ctx);
156
+ }
157
+ didDefineDisplayProp = true;
158
+ break;
159
+ case 'arrange':
160
+ if (didDefineDisplayProp) {
161
+ throw new utils_js_1.RuntimeExecutionError("display property already defined", ctx);
162
+ }
163
+ didDefineArrangeProp = true;
164
+ break;
135
165
  case 'pins':
136
166
  if (!(value instanceof Map)) {
137
167
  this.validateNumeric(value, ctx);
168
+ const numPins = value.toNumber();
169
+ for (let i = 0; i < numPins; i++) {
170
+ definedPinIds.push(i + 1);
171
+ }
138
172
  }
139
173
  break;
140
174
  case 'copy':
@@ -145,7 +179,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
145
179
  this.validateBoolean(value, ctx);
146
180
  }
147
181
  else {
148
- throw new utils_js_1.RuntimeExecutionError("Invalid value for 'copy' property", ctx.start, ctx.end);
182
+ throw new utils_js_1.RuntimeExecutionError("Invalid value for 'copy' property", ctx);
149
183
  }
150
184
  break;
151
185
  }
@@ -155,20 +189,26 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
155
189
  if (keyName === 'arrange') {
156
190
  const [sideKeyCtx, sideKeyName] = path[1];
157
191
  if (globals_js_1.ValidPinSides.indexOf(sideKeyName) === -1) {
158
- throw new utils_js_1.RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx.start, sideKeyCtx.stop);
192
+ throw new utils_js_1.RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx);
159
193
  }
160
194
  else {
161
- if (path.length > 2 && path[2][0] === 'index') {
195
+ if (path.length === 2 && value instanceof ParamDefinition_js_1.NumericValue) {
196
+ checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
197
+ }
198
+ else if (path.length > 2 && path[2][0] === 'index') {
162
199
  if (Array.isArray(value)) {
163
200
  const goodBlank = value.length === 1 &&
164
201
  value[0] instanceof ParamDefinition_js_1.NumericValue;
165
202
  if (!goodBlank) {
166
- throw new utils_js_1.RuntimeExecutionError(`Invalid blank specifier`, ctx.start, ctx.stop);
203
+ throw new utils_js_1.RuntimeExecutionError(`Invalid blank specifier`, ctx);
167
204
  }
168
205
  }
169
206
  else {
170
207
  if (!(value instanceof ParamDefinition_js_1.NumericValue)) {
171
- throw new utils_js_1.RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx.start, ctx.stop);
208
+ throw new utils_js_1.RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx);
209
+ }
210
+ else {
211
+ checkPinExistsAndNotDuplicated(value.toNumber(), ctx);
172
212
  }
173
213
  }
174
214
  }
@@ -189,10 +229,12 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
189
229
  }
190
230
  else if (keyName === 'pins') {
191
231
  if (path.length === 2) {
232
+ const idName = path[1][1];
233
+ definedPinIds.push(idName);
192
234
  if (value.length === 2) {
193
235
  const [pinType,] = value;
194
236
  if (pinType instanceof types_js_1.UndeclaredReference) {
195
- throw new utils_js_1.RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx.start, ctx.end);
237
+ throw new utils_js_1.RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx);
196
238
  }
197
239
  }
198
240
  }
@@ -421,7 +463,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
421
463
  this.getScope().enterContext(ctxValue);
422
464
  const keyName = this.visitResult(ctxKey);
423
465
  const value = this.visitResult(ctxValue);
424
- scope.triggerPropertyHandler(value, ctxValue);
466
+ scope.triggerPropertyHandler(this, value, ctxValue);
425
467
  this.getScope().exitContext();
426
468
  this.getScope().exitContext();
427
469
  if (value instanceof types_js_1.UndeclaredReference && (value.reference.parentValue === undefined
@@ -442,7 +484,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
442
484
  value = ctx.data_expr().map((item, index) => {
443
485
  this.getScope().enterContext(index);
444
486
  const result = this.visitResult(item);
445
- this.getScope().triggerPropertyHandler(result, item);
487
+ this.getScope().triggerPropertyHandler(this, result, item);
446
488
  this.getScope().exitContext();
447
489
  return result;
448
490
  });
@@ -1069,45 +1111,46 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1069
1111
  parseCreateComponentPins(pinData) {
1070
1112
  const pins = [];
1071
1113
  if (pinData instanceof ParamDefinition_js_1.NumericValue) {
1114
+ const tmpMap = new Map();
1072
1115
  const lastPin = pinData.toNumber();
1073
1116
  for (let i = 0; i < lastPin; i++) {
1074
1117
  const pinId = i + 1;
1075
- pins.push(new PinDefinition_js_1.PinDefinition(pinId, PinDefinition_js_1.PinIdType.Int, pinId.toString()));
1118
+ tmpMap.set(pinId, (0, ParamDefinition_js_1.numeric)(pinId));
1076
1119
  }
1120
+ pinData = tmpMap;
1077
1121
  }
1078
- else if (pinData instanceof Map) {
1079
- for (const [pinId, pinDef] of pinData) {
1080
- let pinIdType = PinDefinition_js_1.PinIdType.Int;
1081
- let pinType = PinTypes_js_1.PinTypes.Any;
1082
- let pinName = null;
1083
- let altPinNames = [];
1084
- if (typeof pinId === 'string') {
1085
- pinIdType = PinDefinition_js_1.PinIdType.Str;
1086
- }
1087
- if (Array.isArray(pinDef)) {
1088
- const firstValue = pinDef[0];
1089
- if (firstValue.type
1090
- && firstValue.type === globals_js_1.ReferenceTypes.pinType
1091
- && this.pinTypes.indexOf(firstValue.value) !== -1) {
1092
- pinType = firstValue.value;
1093
- pinName = pinDef[1];
1094
- if (pinDef.length > 2) {
1095
- altPinNames = pinDef.slice(2);
1096
- }
1097
- }
1098
- else {
1099
- pinName = pinDef[0];
1100
- if (pinDef.length > 1) {
1101
- altPinNames = pinDef.slice(1);
1102
- }
1122
+ pinData = pinData ?? [];
1123
+ for (const [pinId, pinDef] of pinData) {
1124
+ let pinIdType = PinDefinition_js_1.PinIdType.Int;
1125
+ let pinType = PinTypes_js_1.PinTypes.Any;
1126
+ let pinName = null;
1127
+ let altPinNames = [];
1128
+ if (typeof pinId === 'string') {
1129
+ pinIdType = PinDefinition_js_1.PinIdType.Str;
1130
+ }
1131
+ if (Array.isArray(pinDef)) {
1132
+ const firstValue = pinDef[0];
1133
+ if (firstValue.type
1134
+ && firstValue.type === globals_js_1.ReferenceTypes.pinType
1135
+ && this.pinTypes.indexOf(firstValue.value) !== -1) {
1136
+ pinType = firstValue.value;
1137
+ pinName = pinDef[1];
1138
+ if (pinDef.length > 2) {
1139
+ altPinNames = pinDef.slice(2);
1103
1140
  }
1104
1141
  }
1105
1142
  else {
1106
- pinName = pinDef;
1143
+ pinName = pinDef[0];
1144
+ if (pinDef.length > 1) {
1145
+ altPinNames = pinDef.slice(1);
1146
+ }
1107
1147
  }
1108
- this.log('pins', pinId, pinIdType, pinName, pinType, altPinNames);
1109
- pins.push(new PinDefinition_js_1.PinDefinition(pinId, pinIdType, pinName, pinType, altPinNames));
1110
1148
  }
1149
+ else {
1150
+ pinName = pinDef;
1151
+ }
1152
+ this.log('pins', pinId, pinIdType, pinName, pinType, altPinNames);
1153
+ pins.push(new PinDefinition_js_1.PinDefinition(pinId, pinIdType, pinName, pinType, altPinNames));
1111
1154
  }
1112
1155
  return pins;
1113
1156
  }
@@ -1316,6 +1359,9 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1316
1359
  });
1317
1360
  return properties;
1318
1361
  }
1362
+ getWarnings() {
1363
+ return this.warnings;
1364
+ }
1319
1365
  }
1320
1366
  exports.ParserVisitor = ParserVisitor;
1321
1367
  const ComponentRefDesPrefixes = {
@@ -33,6 +33,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
33
33
  onErrorHandler = null;
34
34
  environment;
35
35
  importedFiles = [];
36
+ warnings = [];
36
37
  onImportFile = async (visitor, filePath, fileData, onErrorHandler) => {
37
38
  throw "Import file not implemented";
38
39
  };
@@ -41,7 +42,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
41
42
  this.logger = new Logger();
42
43
  this.onErrorHandler = onErrorHandler;
43
44
  this.environment = environment;
44
- this.startingContext = new ExecutionContext(DoubleDelimiter1, `${DoubleDelimiter1}.`, '/', 0, 0, silent, this.logger, null);
45
+ this.startingContext = new ExecutionContext(DoubleDelimiter1, `${DoubleDelimiter1}.`, '/', 0, 0, silent, this.logger, this.warnings, null);
45
46
  const scope = this.startingContext.scope;
46
47
  scope.sequence.push([
47
48
  SequenceAction.At, scope.componentRoot, scope.currentPin
@@ -423,7 +424,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
423
424
  this.setResult(ctx, returnList);
424
425
  };
425
426
  visitImport_expr = (ctx) => {
426
- throw new RuntimeExecutionError("Cannot parse imports here", ctx.start, ctx.stop);
427
+ throw new RuntimeExecutionError("Cannot parse imports here", ctx);
427
428
  };
428
429
  visitFunction_return_expr = (ctx) => {
429
430
  const executor = this.getExecutor();
@@ -517,7 +518,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
517
518
  }
518
519
  catch (err) {
519
520
  if (ctx != null) {
520
- throw new RuntimeExecutionError("An error occurred while importing file", ctx.start, ctx.stop);
521
+ throw new RuntimeExecutionError("An error occurred while importing file", ctx);
521
522
  }
522
523
  else {
523
524
  this.log('An error occurred while importing file:', err.message);
@@ -533,7 +534,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
533
534
  }
534
535
  }
535
536
  if (errorMessage !== null && ctx) {
536
- throw new RuntimeExecutionError(errorMessage, ctx.start, ctx.end);
537
+ throw new RuntimeExecutionError(errorMessage, ctx);
537
538
  }
538
539
  const newImportedFile = {
539
540
  id: name.trim(),
@@ -637,7 +638,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
637
638
  const executionLevel = currentExecutionContext.executionLevel;
638
639
  const executionContextNamespace = currentExecutionContext.namespace
639
640
  + executionContextName + ".";
640
- const newExecutor = new ExecutionContext(executionContextName, executionContextNamespace, netNamespace, executionLevel + 1, this.getExecutor().scope.indentLevel + 1, currentExecutionContext.silent, currentExecutionContext.logger, parentContext);
641
+ const newExecutor = new ExecutionContext(executionContextName, executionContextNamespace, netNamespace, executionLevel + 1, this.getExecutor().scope.indentLevel + 1, currentExecutionContext.silent, currentExecutionContext.logger, currentExecutionContext.warnings, parentContext);
641
642
  executionStack.push(newExecutor);
642
643
  this.setupDefinedParameters(funcDefinedParameters, passedInParameters, newExecutor);
643
644
  return newExecutor;
@@ -654,7 +655,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
654
655
  }
655
656
  const result = validateFunction(value);
656
657
  if (!result) {
657
- throw new RuntimeExecutionError(`Invalid ${expectedType}`, context.start, context.stop);
658
+ throw new RuntimeExecutionError(`Invalid ${expectedType}`, context);
658
659
  }
659
660
  return result;
660
661
  }
@@ -2,7 +2,7 @@ import { milsToMM } from "./helpers.js";
2
2
  import { ColorScheme, CustomSymbolParamTextSize, CustomSymbolPinIdSize, CustomSymbolPinTextSize, CustomSymbolRefDesSize, PortArrowSize, PortPaddingHorizontal, PortPaddingVertical, ReferenceTypes, RenderFlags, SymbolPinSide, defaultFont, defaultPinIdTextSize, defaultPinNameTextSize, defaultSymbolLineWidth, fontDisplayScale } from "./globals.js";
3
3
  import { Geometry, GeometryProp, HorizontalAlign, HorizontalAlignProp, Textbox, VerticalAlign, VerticalAlignProp } from "./geometry.js";
4
4
  import { PinTypes } from "./objects/PinTypes.js";
5
- import { roundValue, throwWithContext } from "./utils.js";
5
+ import { roundValue, RuntimeExecutionError, throwWithContext } from "./utils.js";
6
6
  import { DeclaredReference, UndeclaredReference } from "./objects/types.js";
7
7
  import { numeric, NumericValue } from "./objects/ParamDefinition.js";
8
8
  export class SymbolGraphic {
@@ -81,6 +81,9 @@ export class SymbolGraphic {
81
81
  }
82
82
  pinPosition(id) {
83
83
  const pin = this.drawing.getPinPosition(id);
84
+ if (pin === null) {
85
+ throw new RuntimeExecutionError(`Could not determine pin ${id} position`);
86
+ }
84
87
  const [x, y] = pin.start;
85
88
  const useX = roundValue(x);
86
89
  const useY = roundValue(y);
@@ -2,7 +2,7 @@ import { BlockTypes, ComponentTypes, Delimiter1, GlobalNames, NoNetText, ParamKe
2
2
  import { ClassComponent, ModuleComponent } from './objects/ClassComponent.js';
3
3
  import { ActiveObject, ExecutionScope, FrameAction, SequenceAction } from './objects/ExecutionScope.js';
4
4
  import { Net } from './objects/Net.js';
5
- import { numeric } from './objects/ParamDefinition.js';
5
+ import { numeric, NumericValue } from './objects/ParamDefinition.js';
6
6
  import { PortSide } from './objects/PinDefinition.js';
7
7
  import { DeclaredReference, Direction } from './objects/types.js';
8
8
  import { Wire } from './objects/Wire.js';
@@ -27,7 +27,8 @@ export class ExecutionContext {
27
27
  __functionCache = {};
28
28
  parentContext;
29
29
  componentAngleFollowsWire = true;
30
- constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger, parent) {
30
+ warnings = [];
31
+ constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger, warnings, parent) {
31
32
  this.name = name;
32
33
  this.namespace = namespace;
33
34
  this.netNamespace = netNamespace;
@@ -39,6 +40,14 @@ export class ExecutionContext {
39
40
  this.silent = silent;
40
41
  this.log('create new execution context', this.namespace, this.name, this.scope.indentLevel);
41
42
  this.parentContext = parent;
43
+ this.warnings = warnings;
44
+ }
45
+ logWarning(message, context, fileName) {
46
+ this.warnings.push({
47
+ message,
48
+ ctx: context,
49
+ fileName,
50
+ });
42
51
  }
43
52
  log(...params) {
44
53
  const indentOutput = ''.padStart(this.scope.indentLevel * 4, ' ');
@@ -125,7 +134,6 @@ export class ExecutionContext {
125
134
  pins.forEach((pin) => {
126
135
  component.pins.set(pin.id, pin);
127
136
  });
128
- component.arrangeProps = props.arrange ?? null;
129
137
  component.displayProp = props.display ?? null;
130
138
  component.widthProp = props.width ?? null;
131
139
  component.heightProp = props.height ?? null;
@@ -138,6 +146,33 @@ export class ExecutionContext {
138
146
  useAngle += 360;
139
147
  }
140
148
  }
149
+ if (props.display === null && props.arrange === null) {
150
+ const tmpArrangeLeft = [];
151
+ const tmpArrangeRight = [];
152
+ pins.forEach((pin, index) => {
153
+ const useArray = (index % 2 === 0) ? tmpArrangeLeft : tmpArrangeRight;
154
+ useArray.push(numeric(pin.id));
155
+ });
156
+ const arrangeProp = new Map([
157
+ [SymbolPinSide.Left, tmpArrangeLeft],
158
+ [SymbolPinSide.Right, tmpArrangeRight]
159
+ ]);
160
+ props.arrange = arrangeProp;
161
+ }
162
+ if (props.arrange !== null) {
163
+ component.arrangeProps = this.removeArrangePropDuplicates(props.arrange);
164
+ const arrangePropPins = this.getArrangePropPins(component.arrangeProps).map(item => {
165
+ return item.toNumber();
166
+ });
167
+ pins.forEach(pin => {
168
+ if (arrangePropPins.indexOf(pin.id) === -1) {
169
+ this.logWarning(`Pin ${pin.id} is not specified in arrange property`);
170
+ }
171
+ });
172
+ }
173
+ else {
174
+ component.arrangeProps = null;
175
+ }
141
176
  component.angleProp = useAngle ?? 0;
142
177
  component.followWireOrientationProp = props.followWireOrientation;
143
178
  const paramsMap = new Map();
@@ -181,6 +216,59 @@ export class ExecutionContext {
181
216
  this.log('add symbol', instanceName, '[' + pinsOutput.join(', ') + ']');
182
217
  return component;
183
218
  }
219
+ removeArrangePropDuplicates(arrangeProp) {
220
+ const sides = [
221
+ SymbolPinSide.Left,
222
+ SymbolPinSide.Right,
223
+ SymbolPinSide.Top,
224
+ SymbolPinSide.Bottom
225
+ ];
226
+ const result = new Map();
227
+ const seenIds = [];
228
+ sides.forEach(side => {
229
+ let items = arrangeProp.get(side) ?? [];
230
+ if (!Array.isArray(items)) {
231
+ items = [items];
232
+ }
233
+ const uniqueItems = [];
234
+ items.forEach(item => {
235
+ if (item instanceof NumericValue) {
236
+ if (seenIds.indexOf(item.toNumber()) === -1) {
237
+ seenIds.push(item.toNumber());
238
+ uniqueItems.push(item);
239
+ }
240
+ else {
241
+ this.logWarning(`Pin ${item.toNumber()} specified more than once in arrange property`);
242
+ }
243
+ }
244
+ else {
245
+ uniqueItems.push(item);
246
+ }
247
+ });
248
+ result.set(side, uniqueItems);
249
+ });
250
+ return result;
251
+ }
252
+ getArrangePropPins(arrangeProps) {
253
+ const pins = [];
254
+ const sides = [
255
+ SymbolPinSide.Left,
256
+ SymbolPinSide.Right,
257
+ SymbolPinSide.Top,
258
+ SymbolPinSide.Bottom
259
+ ];
260
+ sides.forEach(side => {
261
+ const items = arrangeProps.get(side);
262
+ if (items) {
263
+ items.forEach(item => {
264
+ if (item instanceof NumericValue) {
265
+ pins.push(item);
266
+ }
267
+ });
268
+ }
269
+ });
270
+ return pins;
271
+ }
184
272
  printPoint(extra = '') {
185
273
  let netString = NoNetText;
186
274
  if (this.scope.currentComponent === null || this.scope.currentPin === null) {
@@ -1,4 +1,4 @@
1
- import { ComponentTypes, NoNetText } from "./globals.js";
1
+ import { NoNetText } from "./globals.js";
2
2
  import { NumericValue } from "./objects/ParamDefinition.js";
3
3
  export function generateKiCADNetList(netlist) {
4
4
  const componentsList = [];
@@ -47,11 +47,6 @@ export function generateKiCADNetList(netlist) {
47
47
  }
48
48
  }
49
49
  else {
50
- if (instance.typeProp !== ComponentTypes.net &&
51
- instance.typeProp !== ComponentTypes.graphic &&
52
- instance.typeProp !== null) {
53
- console.log('Skipping', instance.instanceName);
54
- }
55
50
  }
56
51
  });
57
52
  const netItems = [];
@@ -5,7 +5,7 @@ import { generateKiCADNetList, printTree } from "./export.js";
5
5
  import { LayoutEngine } from "./layout.js";
6
6
  import { parseFileWithVisitor } from "./parser.js";
7
7
  import { generatePdfOutput, generateSvgOutput, renderSheetsToSVG } from "./render.js";
8
- import { generateDebugSequenceAction, ParseError, ParseSyntaxError, RenderError, resolveToNumericValue, RuntimeExecutionError, sequenceActionString, SimpleStopwatch } from "./utils.js";
8
+ import { generateDebugSequenceAction, ParseError, ParseSyntaxError, printWarnings, RenderError, resolveToNumericValue, RuntimeExecutionError, sequenceActionString, SimpleStopwatch } from "./utils.js";
9
9
  import { ParserVisitor } from "./visitor.js";
10
10
  import { SymbolValidatorVisitor } from "./validate/SymbolValidatorVisitor.js";
11
11
  import { SymbolValidatorResolveVisitor } from "./validate/SymbolValidatorResolveVisitor.js";
@@ -154,7 +154,21 @@ export async function renderScript(scriptData, outputPath, options) {
154
154
  errors.push(error);
155
155
  }
156
156
  else if (error && error instanceof RecognitionException) {
157
- errors.push(new ParseSyntaxError(message, context.start, context.stop));
157
+ if (context !== null) {
158
+ errors.push(new ParseSyntaxError(message, context.start, context.stop));
159
+ }
160
+ else {
161
+ if (error.recognizer) {
162
+ const recognizer = error.recognizer;
163
+ errors.push(new ParseSyntaxError(message, {
164
+ line: recognizer.currentTokenStartLine,
165
+ column: recognizer.currentTokenColumn
166
+ }));
167
+ }
168
+ else {
169
+ errors.push(new ParseSyntaxError(message));
170
+ }
171
+ }
158
172
  }
159
173
  else {
160
174
  errors.push(new ParseError(message, context.start, context.stop));
@@ -171,6 +185,7 @@ export async function renderScript(scriptData, outputPath, options) {
171
185
  visitor.log('reading file');
172
186
  visitor.log('done reading file');
173
187
  const { tree, parser, parserTimeTaken, lexerTimeTaken } = await parseFileWithVisitor(visitor, scriptData);
188
+ printWarnings(visitor.getWarnings());
174
189
  showStats && console.log('Lexing took:', lexerTimeTaken);
175
190
  showStats && console.log('Parsing took:', parserTimeTaken);
176
191
  if (dumpNets) {
@@ -214,7 +229,10 @@ export async function renderScript(scriptData, outputPath, options) {
214
229
  });
215
230
  writeFileSync(outputPath, printTree(kicadNetList));
216
231
  console.log('Generated file', outputPath);
217
- return null;
232
+ return {
233
+ svgOutput: null,
234
+ errors,
235
+ };
218
236
  }
219
237
  const layoutEngine = new LayoutEngine();
220
238
  const layoutTimer = new SimpleStopwatch();