circuitscript 0.1.5 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/cjs/BaseVisitor.js +127 -73
  2. package/dist/cjs/SemanticTokenVisitor.js +19 -13
  3. package/dist/cjs/antlr/CircuitScriptParser.js +711 -671
  4. package/dist/cjs/builtinMethods.js +29 -25
  5. package/dist/cjs/environment.js +118 -0
  6. package/dist/cjs/execute.js +53 -12
  7. package/dist/cjs/export.js +0 -5
  8. package/dist/cjs/geometry.js +1 -0
  9. package/dist/cjs/globals.js +11 -6
  10. package/dist/cjs/helpers.js +152 -127
  11. package/dist/cjs/index.js +5 -0
  12. package/dist/cjs/layout.js +86 -44
  13. package/dist/cjs/main.js +31 -19
  14. package/dist/cjs/objects/ExecutionScope.js +33 -0
  15. package/dist/cjs/objects/ParamDefinition.js +15 -15
  16. package/dist/cjs/parser.js +27 -21
  17. package/dist/cjs/regenerate-tests.js +14 -10
  18. package/dist/cjs/render.js +3 -1
  19. package/dist/cjs/sizing.js +5 -58
  20. package/dist/cjs/utils.js +85 -30
  21. package/dist/cjs/validate/SymbolTable.js +96 -0
  22. package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
  23. package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
  24. package/dist/cjs/validate.js +71 -44
  25. package/dist/cjs/visitor.js +140 -24
  26. package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +98 -45
  27. package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
  28. package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
  29. package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +20 -16
  30. package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +7 -7
  31. package/dist/esm/environment.js +110 -0
  32. package/dist/esm/{execute.mjs → execute.js} +66 -25
  33. package/dist/esm/{export.mjs → export.js} +2 -7
  34. package/dist/esm/{geometry.mjs → geometry.js} +6 -5
  35. package/dist/esm/{globals.mjs → globals.js} +6 -1
  36. package/dist/esm/helpers.js +394 -0
  37. package/dist/esm/index.js +20 -0
  38. package/dist/esm/{layout.mjs → layout.js} +72 -53
  39. package/dist/esm/{lexer.mjs → lexer.js} +2 -2
  40. package/dist/esm/{main.mjs → main.js} +33 -21
  41. package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +5 -4
  42. package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +33 -0
  43. package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
  44. package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
  45. package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
  46. package/dist/esm/parser.js +71 -0
  47. package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +15 -11
  48. package/dist/esm/{render.mjs → render.js} +11 -9
  49. package/dist/esm/{sizing.mjs → sizing.js} +6 -34
  50. package/dist/esm/{utils.mjs → utils.js} +61 -17
  51. package/dist/esm/validate/SymbolTable.js +90 -0
  52. package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
  53. package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
  54. package/dist/esm/validate.js +105 -0
  55. package/dist/esm/{visitor.mjs → visitor.js} +151 -35
  56. package/dist/fonts/Arial.ttf +0 -0
  57. package/dist/fonts/Inter-Bold.ttf +0 -0
  58. package/dist/fonts/Inter-Regular.ttf +0 -0
  59. package/dist/fonts/OpenSans-Regular.ttf +0 -0
  60. package/dist/fonts/Roboto-Regular.ttf +0 -0
  61. package/dist/libs/lib.cst +423 -0
  62. package/dist/types/BaseVisitor.d.ts +34 -21
  63. package/dist/types/SemanticTokenVisitor.d.ts +6 -5
  64. package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
  65. package/dist/types/builtinMethods.d.ts +3 -2
  66. package/dist/types/environment.d.ts +31 -0
  67. package/dist/types/globals.d.ts +4 -1
  68. package/dist/types/helpers.d.ts +12 -14
  69. package/dist/types/index.d.ts +5 -0
  70. package/dist/types/layout.d.ts +2 -2
  71. package/dist/types/objects/ClassComponent.d.ts +1 -0
  72. package/dist/types/objects/ExecutionScope.d.ts +11 -0
  73. package/dist/types/objects/types.d.ts +6 -1
  74. package/dist/types/parser.d.ts +7 -11
  75. package/dist/types/sizing.d.ts +0 -3
  76. package/dist/types/utils.d.ts +30 -6
  77. package/dist/types/validate/SymbolTable.d.ts +40 -0
  78. package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
  79. package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
  80. package/dist/types/validate.d.ts +1 -1
  81. package/package.json +15 -14
  82. package/dist/cjs/SymbolValidatorVisitor.js +0 -233
  83. package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
  84. package/dist/esm/helpers.mjs +0 -364
  85. package/dist/esm/index.mjs +0 -15
  86. package/dist/esm/parser.mjs +0 -64
  87. package/dist/esm/validate.mjs +0 -74
  88. package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
  89. /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
  90. /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
  91. /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
  92. /package/dist/esm/{logger.mjs → logger.js} +0 -0
  93. /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
  94. /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
  95. /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
  96. /package/dist/esm/objects/{types.mjs → types.js} +0 -0
  97. /package/dist/esm/{server.mjs → server.js} +0 -0
@@ -46,9 +46,14 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
46
46
  this.visitTo_component_expr = (ctx) => {
47
47
  ctx.component_select_expr().forEach(item => {
48
48
  const [component, pin] = this.visitResult(item);
49
- this.getExecutor().toComponent(component, pin, {
50
- addSequence: true
51
- });
49
+ try {
50
+ this.getExecutor().toComponent(component, pin, {
51
+ addSequence: true
52
+ });
53
+ }
54
+ catch (err) {
55
+ throw new utils_js_1.RuntimeExecutionError(err.message, ctx.start, ctx.stop);
56
+ }
52
57
  });
53
58
  return this.getExecutor().getCurrentPoint();
54
59
  };
@@ -63,7 +68,10 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
63
68
  componentPin = this.visitResult(ctxDataExprWithAssigment);
64
69
  }
65
70
  else {
66
- const component = this.getExecutor().scope.currentComponent;
71
+ let component = this.getScope().currentComponent;
72
+ if (component._pointLinkComponent) {
73
+ component = component._pointLinkComponent;
74
+ }
67
75
  let pinId = null;
68
76
  const ctxPinSelectExpr = ctx.pin_select_expr();
69
77
  if (ctxPinSelectExpr) {
@@ -111,6 +119,92 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
111
119
  return this.getExecutor().getCurrentPoint();
112
120
  };
113
121
  this.visitCreate_component_expr = (ctx) => {
122
+ const scope = this.getScope();
123
+ scope.setOnPropertyHandler((path, value, ctx) => {
124
+ if (path.length === 1) {
125
+ const [, keyName] = path[0];
126
+ switch (keyName) {
127
+ case 'type':
128
+ this.validateString(value, ctx);
129
+ break;
130
+ case 'angle':
131
+ case 'width':
132
+ case 'height':
133
+ this.validateNumeric(value, ctx);
134
+ break;
135
+ case 'pins':
136
+ if (!(value instanceof Map)) {
137
+ this.validateNumeric(value, ctx);
138
+ }
139
+ break;
140
+ case 'copy':
141
+ if (value instanceof ParamDefinition_js_1.NumericValue) {
142
+ this.validateNumeric(value, ctx);
143
+ }
144
+ else if (typeof value === 'boolean') {
145
+ this.validateBoolean(value, ctx);
146
+ }
147
+ else {
148
+ throw new utils_js_1.RuntimeExecutionError("Invalid value for 'copy' property", ctx.start, ctx.end);
149
+ }
150
+ break;
151
+ }
152
+ }
153
+ else {
154
+ const [, keyName] = path[0];
155
+ if (keyName === 'arrange') {
156
+ const [sideKeyCtx, sideKeyName] = path[1];
157
+ if (globals_js_1.ValidPinSides.indexOf(sideKeyName) === -1) {
158
+ throw new utils_js_1.RuntimeExecutionError(`Invalid side ${sideKeyName} in arrange`, sideKeyCtx.start, sideKeyCtx.stop);
159
+ }
160
+ else {
161
+ if (path.length > 2 && path[2][0] === 'index') {
162
+ if (Array.isArray(value)) {
163
+ const goodBlank = value.length === 1 &&
164
+ value[0] instanceof ParamDefinition_js_1.NumericValue;
165
+ if (!goodBlank) {
166
+ throw new utils_js_1.RuntimeExecutionError(`Invalid blank specifier`, ctx.start, ctx.stop);
167
+ }
168
+ }
169
+ else {
170
+ if (!(value instanceof ParamDefinition_js_1.NumericValue)) {
171
+ throw new utils_js_1.RuntimeExecutionError(`Invalid numeric value for arrange.${sideKeyName}`, ctx.start, ctx.stop);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ else if (keyName === 'params') {
178
+ const [, subKeyName] = path[1];
179
+ switch (subKeyName) {
180
+ case 'mpn':
181
+ case 'refdes':
182
+ case 'footprint':
183
+ this.validateString(value, ctx);
184
+ break;
185
+ case 'place':
186
+ this.validateBoolean(value, ctx);
187
+ break;
188
+ }
189
+ }
190
+ else if (keyName === 'pins') {
191
+ if (path.length === 2) {
192
+ if (value.length === 2) {
193
+ const [pinType,] = value;
194
+ if (pinType instanceof types_js_1.UndeclaredReference) {
195
+ throw new utils_js_1.RuntimeExecutionError(`Invalid pin type: ${pinType.reference.name}`, ctx.start, ctx.end);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ });
202
+ scope.enterContext(ctx);
203
+ ctx.property_expr().forEach(item => {
204
+ this.visitResult(item);
205
+ });
206
+ scope.exitContext();
207
+ scope.popOnPropertyHandler();
114
208
  const properties = this.getPropertyExprList(ctx.property_expr());
115
209
  const pins = this.parseCreateComponentPins(properties.get('pins'));
116
210
  let instanceName = this.getExecutor().getUniqueInstanceName();
@@ -145,8 +239,13 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
145
239
  arrange, display, type, width, height, copy,
146
240
  angle, followWireOrientation
147
241
  };
148
- const createdComponent = this.getExecutor().createComponent(instanceName, pins, params, props);
149
- this.setResult(ctx, createdComponent);
242
+ try {
243
+ const createdComponent = this.getExecutor().createComponent(instanceName, pins, params, props);
244
+ this.setResult(ctx, createdComponent);
245
+ }
246
+ catch (error) {
247
+ this.throwWithContext(ctx, error.message);
248
+ }
150
249
  };
151
250
  this.visitCreate_graphic_expr = (ctx) => {
152
251
  const ctxId = ctx.ID();
@@ -154,7 +253,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
154
253
  if (ctxId !== null) {
155
254
  const varName = ctxId.getText();
156
255
  paramIds.push(varName);
157
- this.getExecutor().scope.variables.set(varName, {});
256
+ this.getScope().variables.set(varName, {});
158
257
  }
159
258
  const executor = this.getExecutor();
160
259
  const stack = [...this.executionStack];
@@ -256,7 +355,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
256
355
  useValueArray = [useValueArray];
257
356
  }
258
357
  useValueArray.forEach((value, index) => {
259
- this.getExecutor().scope.variables.set(forVariableNames[index], value);
358
+ this.getScope().variables.set(forVariableNames[index], value);
260
359
  });
261
360
  const commands = this.visitResult(ctx.graphic_expressions_block());
262
361
  allCommands = allCommands.concat(commands);
@@ -315,8 +414,16 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
315
414
  this.setResult(ctx, [keyName, expressionsBlock]);
316
415
  };
317
416
  this.visitProperty_expr = (ctx) => {
318
- const keyName = this.visitResult(ctx.property_key_expr());
319
- const value = this.visitResult(ctx.property_value_expr());
417
+ const ctxKey = ctx.property_key_expr();
418
+ const ctxValue = ctx.property_value_expr();
419
+ const scope = this.getScope();
420
+ this.getScope().enterContext(ctxKey);
421
+ this.getScope().enterContext(ctxValue);
422
+ const keyName = this.visitResult(ctxKey);
423
+ const value = this.visitResult(ctxValue);
424
+ scope.triggerPropertyHandler(value, ctxValue);
425
+ this.getScope().exitContext();
426
+ this.getScope().exitContext();
320
427
  if (value instanceof types_js_1.UndeclaredReference && (value.reference.parentValue === undefined
321
428
  && value.reference.value === undefined)) {
322
429
  throw value.throwMessage();
@@ -326,15 +433,21 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
326
433
  this.setResult(ctx, map);
327
434
  };
328
435
  this.visitSingle_line_property = (ctx) => {
436
+ this.getScope().enterContext(ctx);
329
437
  let value;
330
438
  if (ctx.data_expr().length === 1) {
331
439
  value = this.visitResult(ctx.data_expr(0));
332
440
  }
333
441
  else {
334
- value = ctx.data_expr().map(item => {
335
- return this.visitResult(item);
442
+ value = ctx.data_expr().map((item, index) => {
443
+ this.getScope().enterContext(index);
444
+ const result = this.visitResult(item);
445
+ this.getScope().triggerPropertyHandler(result, item);
446
+ this.getScope().exitContext();
447
+ return result;
336
448
  });
337
449
  }
450
+ this.getScope().exitContext();
338
451
  this.setResult(ctx, value);
339
452
  };
340
453
  this.visitNested_properties_inner = (ctx) => {
@@ -707,6 +820,9 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
707
820
  }
708
821
  else if (ctxDataExpr) {
709
822
  useValue = this.visitResult(ctxDataExpr);
823
+ if (useValue instanceof ParamDefinition_js_1.NumericValue) {
824
+ useValue = useValue.toNumber();
825
+ }
710
826
  }
711
827
  if (useValue !== null) {
712
828
  this.setResult(ctx, [direction, new helpers_js_1.UnitDimension(useValue)]);
@@ -848,7 +964,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
848
964
  useValueArray = [useValueArray];
849
965
  }
850
966
  useValueArray.forEach((value, index) => {
851
- this.getExecutor().scope.variables.set(forVariableNames[index], value);
967
+ this.getScope().variables.set(forVariableNames[index], value);
852
968
  });
853
969
  this.visit(ctx.expressions_block());
854
970
  keepLooping = true;
@@ -1043,32 +1159,32 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1043
1159
  return result;
1044
1160
  }
1045
1161
  printNets() {
1046
- this.getExecutor().scope.printNets();
1162
+ this.getScope().printNets();
1047
1163
  }
1048
1164
  dumpNets() {
1049
- return this.getExecutor().scope.dumpNets();
1165
+ return this.getScope().dumpNets();
1050
1166
  }
1051
1167
  dumpUniqueNets() {
1052
- const nets = this.getExecutor().scope.getNets();
1168
+ const nets = this.getScope().getNets();
1053
1169
  return nets.reduce((accum, [, , net]) => {
1054
1170
  accum.push(net);
1055
1171
  return accum;
1056
1172
  }, []);
1057
1173
  }
1058
1174
  dumpVariables() {
1059
- return this.getExecutor().scope.variables;
1175
+ return this.getScope().variables;
1060
1176
  }
1061
1177
  dumpInstances() {
1062
- return this.getExecutor().scope.instances;
1178
+ return this.getScope().instances;
1063
1179
  }
1064
1180
  dump2() {
1065
- const instances = this.getExecutor().scope.instances;
1181
+ const instances = this.getScope().instances;
1066
1182
  const items = [];
1067
1183
  for (const [instanceName, instance] of instances) {
1068
1184
  if (instance.assignedRefDes === null) {
1069
1185
  continue;
1070
1186
  }
1071
- const pinNets = this.resolveNets(this.getExecutor().scope, instance);
1187
+ const pinNets = this.resolveNets(this.getScope(), instance);
1072
1188
  const componentItem = {
1073
1189
  name: instanceName,
1074
1190
  refdes: instance.assignedRefDes,
@@ -1083,9 +1199,9 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1083
1199
  }
1084
1200
  getNetList() {
1085
1201
  const netlist = [];
1086
- const instances = this.getExecutor().scope.instances;
1202
+ const instances = this.getScope().instances;
1087
1203
  for (const [instanceName, instance] of instances) {
1088
- const pinNets = this.resolveNets(this.getExecutor().scope, instance);
1204
+ const pinNets = this.resolveNets(this.getScope(), instance);
1089
1205
  const componentItem = {
1090
1206
  instanceName,
1091
1207
  instance,
@@ -1116,7 +1232,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1116
1232
  annotateComponents() {
1117
1233
  this.log('===== annotate components =====');
1118
1234
  const annotater = new ComponentAnnotater();
1119
- const instances = this.getExecutor().scope.instances;
1235
+ const instances = this.getScope().instances;
1120
1236
  const toAnnotate = [];
1121
1237
  for (const [, instance] of instances) {
1122
1238
  if (instance.typeProp === globals_js_1.ComponentTypes.net
@@ -1153,7 +1269,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1153
1269
  this.log('');
1154
1270
  }
1155
1271
  applySheetFrameComponent() {
1156
- const baseScope = this.getExecutor().scope;
1272
+ const baseScope = this.getScope();
1157
1273
  const document = baseScope.variables.get(globals_js_1.GlobalDocumentName);
1158
1274
  let frameComponent = null;
1159
1275
  if (document && document[Frame_js_1.FrameParamKeys.SheetType]) {
@@ -1,26 +1,22 @@
1
- import { readFileSync } from 'fs';
2
- import { join } from 'path';
3
1
  import { Big } from 'big.js';
4
- import { ExpressionContext } from "./antlr/CircuitScriptParser";
5
- import { CircuitScriptVisitor } from "./antlr/CircuitScriptVisitor";
6
- import { ExecutionContext } from "./execute";
7
- import { Logger } from "./logger";
8
- import { ClassComponent } from "./objects/ClassComponent";
9
- import { NumberOperator, NumericValue, PercentageValue } from "./objects/ParamDefinition";
10
- import { PinTypes } from "./objects/PinTypes";
11
- import { Direction, UndeclaredReference } from "./objects/types";
12
- import { DoubleDelimiter1, GlobalDocumentName, ReferenceTypes } from './globals';
13
- import { linkBuiltInMethods } from './builtinMethods';
14
- import { resolveToNumericValue, throwWithContext } from './utils';
15
- import { SequenceAction } from './objects/ExecutionScope';
2
+ import { ExpressionContext } from "./antlr/CircuitScriptParser.js";
3
+ import { CircuitScriptVisitor } from "./antlr/CircuitScriptVisitor.js";
4
+ import { ExecutionContext } from "./execute.js";
5
+ import { Logger } from "./logger.js";
6
+ import { ClassComponent } from "./objects/ClassComponent.js";
7
+ import { NumberOperator, NumericValue, PercentageValue } from "./objects/ParamDefinition.js";
8
+ import { PinTypes } from "./objects/PinTypes.js";
9
+ import { Direction, UndeclaredReference } from "./objects/types.js";
10
+ import { DoubleDelimiter1, GlobalDocumentName, ReferenceTypes } from './globals.js';
11
+ import { linkBuiltInMethods } from './builtinMethods.js';
12
+ import { resolveToNumericValue, RuntimeExecutionError, throwWithContext } from './utils.js';
13
+ import { SequenceAction } from './objects/ExecutionScope.js';
16
14
  export class BaseVisitor extends CircuitScriptVisitor {
17
15
  indentLevel = 0;
18
16
  startingContext;
19
17
  executionStack;
20
18
  silent = false;
21
19
  logger;
22
- currentDirectory;
23
- defaultLibsPath;
24
20
  printStream = [];
25
21
  printToConsole = true;
26
22
  acceptedDirections = [Direction.Up, Direction.Down,
@@ -34,14 +30,17 @@ export class BaseVisitor extends CircuitScriptVisitor {
34
30
  PinTypes.IO,
35
31
  PinTypes.Power,
36
32
  ];
37
- onErrorCallbackHandler = null;
38
- onImportFile = (visitor, filePath) => {
33
+ onErrorHandler = null;
34
+ environment;
35
+ importedFiles = [];
36
+ onImportFile = async (visitor, filePath, fileData, onErrorHandler) => {
39
37
  throw "Import file not implemented";
40
38
  };
41
- constructor(silent = false, onErrorHandler = null, currentDirectory, defaultLibsPath) {
39
+ constructor(silent = false, onErrorHandler = null, environment) {
42
40
  super();
43
41
  this.logger = new Logger();
44
- this.onErrorCallbackHandler = onErrorHandler;
42
+ this.onErrorHandler = onErrorHandler;
43
+ this.environment = environment;
45
44
  this.startingContext = new ExecutionContext(DoubleDelimiter1, `${DoubleDelimiter1}.`, '/', 0, 0, silent, this.logger, null);
46
45
  const scope = this.startingContext.scope;
47
46
  scope.sequence.push([
@@ -55,12 +54,16 @@ export class BaseVisitor extends CircuitScriptVisitor {
55
54
  this.startingContext.resolveComponentPinNet =
56
55
  this.createComponentPinNetResolver(this.executionStack);
57
56
  this.silent = silent;
58
- this.currentDirectory = currentDirectory;
59
- this.defaultLibsPath = defaultLibsPath;
60
57
  }
61
58
  getExecutor() {
62
59
  return this.executionStack[this.executionStack.length - 1];
63
60
  }
61
+ getScope() {
62
+ return this.getExecutor().scope;
63
+ }
64
+ getRootExecutor() {
65
+ return this.executionStack[0];
66
+ }
64
67
  setupBuiltInFunctions(context) {
65
68
  linkBuiltInMethods(context, this);
66
69
  }
@@ -109,11 +112,21 @@ export class BaseVisitor extends CircuitScriptVisitor {
109
112
  log2(message) {
110
113
  this.getExecutor().log(message);
111
114
  }
112
- visitScript = (ctx) => {
115
+ async visitAsync(ctx) {
116
+ const result = await ctx.accept(this);
117
+ return result;
118
+ }
119
+ visitScript = async (ctx) => {
113
120
  this.log('===', 'start', '===');
114
- const result = this.visitChildren(ctx);
121
+ const imports = ctx.import_expr();
122
+ for (let i = 0; i < imports.length; i++) {
123
+ const ctxImport = imports[i];
124
+ const ID = ctxImport.ID().toString();
125
+ await this.handleImportFile(ID, true, ctxImport);
126
+ }
127
+ const result = this.runExpressions(this.getExecutor(), ctx.expression());
128
+ this.setResult(ctx, result);
115
129
  this.log('===', 'end', '===');
116
- return result;
117
130
  };
118
131
  visitAssignment_expr = (ctx) => {
119
132
  const reference = this.getReference(ctx.atom_expr());
@@ -385,10 +398,10 @@ export class BaseVisitor extends CircuitScriptVisitor {
385
398
  const tmpCtx = defaultValuesProvided[index - boundary];
386
399
  this.visit(tmpCtx);
387
400
  const defaultValue = this.getResult(tmpCtx);
388
- return [idText, defaultValue];
401
+ return [idText, tmpCtx.start, defaultValue];
389
402
  }
390
403
  else {
391
- return [idText];
404
+ return [idText, id.getSymbol()];
392
405
  }
393
406
  });
394
407
  this.setResult(ctx, result);
@@ -410,10 +423,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
410
423
  this.setResult(ctx, returnList);
411
424
  };
412
425
  visitImport_expr = (ctx) => {
413
- const ID = ctx.ID().toString();
414
- this.log('import', ID);
415
- this.handleImportFile(ID, true, ctx);
416
- this.log('done import', ID);
426
+ throw new RuntimeExecutionError("Cannot parse imports here", ctx.start, ctx.stop);
417
427
  };
418
428
  visitFunction_return_expr = (ctx) => {
419
429
  const executor = this.getExecutor();
@@ -463,15 +473,24 @@ export class BaseVisitor extends CircuitScriptVisitor {
463
473
  this.visit(ctx);
464
474
  return this.getResult(ctx);
465
475
  }
466
- handleImportFile(name, throwErrors = true, ctx = null) {
476
+ async handleImportFile(name, throwErrors = true, ctx = null) {
477
+ name = name.trim();
478
+ const importAlready = this.importedFiles.find(item => {
479
+ return item.id === name;
480
+ });
481
+ if (importAlready) {
482
+ return importAlready;
483
+ }
467
484
  let hasError = false;
468
485
  let hasParseError = false;
469
486
  let pathExists = false;
470
- const tmpFilePath = join(this.currentDirectory, name + ".cst");
487
+ const tmpFilePath = this.environment.getRelativeToModule(name + ".cst");
471
488
  this.log('importing path:', tmpFilePath);
472
489
  let fileData = null;
490
+ let filePathUsed = null;
473
491
  try {
474
- fileData = readFileSync(tmpFilePath, { encoding: 'utf8' });
492
+ filePathUsed = tmpFilePath;
493
+ fileData = await this.environment.readFile(tmpFilePath, { encoding: 'utf8' });
475
494
  pathExists = true;
476
495
  }
477
496
  catch (err) {
@@ -479,8 +498,9 @@ export class BaseVisitor extends CircuitScriptVisitor {
479
498
  }
480
499
  if (!pathExists) {
481
500
  try {
482
- const tmpFilePath2 = join(this.defaultLibsPath, name + ".cst");
483
- fileData = readFileSync(tmpFilePath2, { encoding: 'utf8' });
501
+ const tmpFilePath2 = this.environment.getRelativeToDefaultLibs(name + ".cst");
502
+ filePathUsed = tmpFilePath2;
503
+ fileData = await this.environment.readFile(tmpFilePath2, { encoding: 'utf8' });
484
504
  pathExists = true;
485
505
  }
486
506
  catch (err) {
@@ -490,31 +510,39 @@ export class BaseVisitor extends CircuitScriptVisitor {
490
510
  try {
491
511
  if (pathExists) {
492
512
  this.log('done reading imported file data');
493
- const importResult = this.onImportFile(this, fileData, this.onErrorCallbackHandler);
513
+ const importResult = await this.onImportFile(this, filePathUsed, fileData, this.onErrorHandler);
494
514
  hasError = importResult.hasError;
495
515
  hasParseError = importResult.hasParseError;
496
516
  }
497
517
  }
498
518
  catch (err) {
499
- this.log('Failed to import file: ', err.message);
519
+ if (ctx != null) {
520
+ throw new RuntimeExecutionError("An error occurred while importing file", ctx.start, ctx.stop);
521
+ }
522
+ else {
523
+ this.log('An error occurred while importing file:', err.message);
524
+ }
500
525
  }
501
526
  let errorMessage = null;
502
527
  if (throwErrors && (hasError || hasParseError || !pathExists)) {
503
528
  if (!pathExists) {
504
- errorMessage = `File does not exist: ${name}`;
529
+ errorMessage = `File does not exist: ${name} (${filePathUsed})`;
505
530
  }
506
531
  else {
507
532
  errorMessage = `Failed to import: ${name}`;
508
533
  }
509
534
  }
510
535
  if (errorMessage !== null && ctx) {
511
- this.throwWithContext(ctx, errorMessage);
536
+ throw new RuntimeExecutionError(errorMessage, ctx.start, ctx.end);
512
537
  }
513
- return {
538
+ const newImportedFile = {
539
+ id: name.trim(),
514
540
  hasError,
515
541
  hasParseError,
516
542
  pathExists,
517
543
  };
544
+ this.importedFiles.push(newImportedFile);
545
+ return newImportedFile;
518
546
  }
519
547
  visitRoundedBracketsExpr = (ctx) => {
520
548
  const ctxDataExpr = ctx.data_expr();
@@ -544,9 +572,9 @@ export class BaseVisitor extends CircuitScriptVisitor {
544
572
  executor.scope.variables.set(variableName, tmpPassedInArgs[2]);
545
573
  }
546
574
  }
547
- else if (tmpFuncArg.length === 2) {
575
+ else if (tmpFuncArg.length === 3) {
548
576
  const variableName = tmpFuncArg[0];
549
- const defaultValue = tmpFuncArg[1];
577
+ const defaultValue = tmpFuncArg[2];
550
578
  executor.log('set variable in scope, var name: ', variableName);
551
579
  executor.scope.variables.set(variableName, defaultValue);
552
580
  }
@@ -617,7 +645,32 @@ export class BaseVisitor extends CircuitScriptVisitor {
617
645
  prepareStringValue(value) {
618
646
  return value.slice(1, value.length - 1);
619
647
  }
620
- throwWithContext(context, message) {
621
- throwWithContext(context, message);
648
+ throwWithContext(context, messageOrError) {
649
+ throwWithContext(context, messageOrError);
650
+ }
651
+ validateType(value, context, validateFunction, expectedType) {
652
+ if (value === undefined) {
653
+ return false;
654
+ }
655
+ const result = validateFunction(value);
656
+ if (!result) {
657
+ throw new RuntimeExecutionError(`Invalid ${expectedType}`, context.start, context.stop);
658
+ }
659
+ return result;
660
+ }
661
+ validateString(value, context) {
662
+ this.validateType(value, context, (val) => {
663
+ return typeof val === 'string';
664
+ }, 'string');
665
+ }
666
+ validateBoolean(value, context) {
667
+ this.validateType(value, context, (val) => {
668
+ return typeof val === 'boolean';
669
+ }, 'boolean');
670
+ }
671
+ validateNumeric(value, context) {
672
+ this.validateType(value, context, (val) => {
673
+ return (val instanceof NumericValue);
674
+ }, 'numeric value');
622
675
  }
623
676
  }
@@ -1,12 +1,14 @@
1
- import { Assignment_exprContext } from "./antlr/CircuitScriptParser";
2
- import { BaseVisitor } from "./BaseVisitor";
1
+ import { Assignment_exprContext } from "./antlr/CircuitScriptParser.js";
2
+ import { BaseVisitor } from "./BaseVisitor.js";
3
+ import { buildInMethodNamesList } from "./builtinMethods.js";
4
+ import { SymbolValidatorContext } from "./globals.js";
3
5
  export class SemanticTokensVisitor extends BaseVisitor {
4
6
  parsedTokens = [];
5
7
  lexer;
6
8
  script;
7
9
  semanticTokens = new Map();
8
- constructor(silent = false, onErrorHandler = null, currentDirectory, defaultsLibsPath, lexer, script) {
9
- super(silent, onErrorHandler, currentDirectory, defaultsLibsPath);
10
+ constructor(silent = false, onErrorHandler = null, environment, lexer, script) {
11
+ super(silent, onErrorHandler, environment);
10
12
  this.lexer = lexer;
11
13
  this.script = script;
12
14
  }
@@ -17,7 +19,11 @@ export class SemanticTokensVisitor extends BaseVisitor {
17
19
  });
18
20
  };
19
21
  visitFunction_call_expr = (ctx) => {
20
- this.addSemanticToken(ctx.ID(), [], 'function');
22
+ const modifiers = [];
23
+ if (buildInMethodNamesList.indexOf(ctx.ID().getText()) !== -1) {
24
+ modifiers.push('defaultLibrary');
25
+ }
26
+ this.addSemanticToken(ctx.ID(), modifiers, 'function');
21
27
  };
22
28
  visitFunction_def_expr = (ctx) => {
23
29
  const functionName = ctx.ID().getText();
@@ -26,7 +32,7 @@ export class SemanticTokensVisitor extends BaseVisitor {
26
32
  if (ctxFunctionArgsExpr) {
27
33
  this.visit(ctxFunctionArgsExpr);
28
34
  }
29
- const executionContextName = functionName + '_validate';
35
+ const executionContextName = functionName + SymbolValidatorContext;
30
36
  const newExecutor = this.enterNewChildContext(this.executionStack, this.getExecutor(), executionContextName, { netNamespace: "" }, [], []);
31
37
  this.runExpressions(newExecutor, ctx.function_expr());
32
38
  this.executionStack.pop();
@@ -39,9 +45,8 @@ export class SemanticTokensVisitor extends BaseVisitor {
39
45
  };
40
46
  visitCreate_graphic_expr = (ctx) => {
41
47
  this.addSemanticToken(ctx.Create(), ['defaultLibrary'], 'function');
42
- ctx.graphic_expr().forEach(graphic_expr => {
43
- this.visit(graphic_expr);
44
- });
48
+ const graphicsExpressionsCtx = ctx.graphic_expressions_block();
49
+ this.visitResult(graphicsExpressionsCtx);
45
50
  };
46
51
  visitProperty_key_expr = (ctx) => {
47
52
  let useValue = null;
@@ -61,7 +66,7 @@ export class SemanticTokensVisitor extends BaseVisitor {
61
66
  this.addSemanticToken(useValue, [], 'property');
62
67
  }
63
68
  };
64
- visitGraphic_expr = (ctx) => {
69
+ visitGraphicCommandExpr = (ctx) => {
65
70
  let useValue = null;
66
71
  const ctxId = ctx.ID();
67
72
  const ctxPin = ctx.Pin();
@@ -179,7 +184,7 @@ const languageKeywords = [
179
184
  'break', 'branch', 'create', 'component',
180
185
  'graphic', 'wire', 'pin', 'add', 'at', 'to',
181
186
  'point', 'join', 'parallel', 'return', 'def', 'import',
182
- 'true', 'false', 'nc', 'frame',
187
+ 'true', 'false', 'nc', 'sheet', 'frame', 'if', 'for',
183
188
  ];
184
189
  const operatorKeywords = [
185
190
  'at', 'to', 'wire', 'add', 'frame', 'join', 'parallel', 'point'
@@ -203,6 +208,7 @@ function resolveTokenType(tokenType) {
203
208
  case 'ID':
204
209
  return 'variable';
205
210
  case 'Define':
211
+ case 'BOOLEAN_VALUE':
206
212
  return 'keyword';
207
213
  case 'COMMENT':
208
214
  return 'comment';