@weborigami/language 0.5.5 → 0.5.7

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 (95) hide show
  1. package/index.ts +16 -6
  2. package/main.js +9 -4
  3. package/package.json +4 -3
  4. package/src/compiler/compile.js +10 -4
  5. package/src/compiler/optimize.js +115 -97
  6. package/src/compiler/origami.pegjs +1 -4
  7. package/src/compiler/parse.js +568 -588
  8. package/src/compiler/parserHelpers.js +2 -2
  9. package/src/handlers/css_handler.js +7 -0
  10. package/src/handlers/csv_handler.js +129 -0
  11. package/src/handlers/handlers.js +33 -0
  12. package/src/handlers/htm_handler.js +2 -0
  13. package/src/handlers/html_handler.js +7 -0
  14. package/src/handlers/jpeg_handler.js +62 -0
  15. package/src/handlers/jpg_handler.js +2 -0
  16. package/src/handlers/js_handler.js +51 -0
  17. package/src/handlers/json_handler.js +26 -0
  18. package/src/handlers/md_handler.js +7 -0
  19. package/src/handlers/mjs_handler.js +2 -0
  20. package/src/handlers/ori_handler.js +52 -0
  21. package/src/handlers/oridocument_handler.js +77 -0
  22. package/src/handlers/parseFrontMatter.js +16 -0
  23. package/src/handlers/ts_handler.js +1 -0
  24. package/src/handlers/txt_handler.js +108 -0
  25. package/src/handlers/wasm_handler.js +15 -0
  26. package/src/handlers/xhtml_handler.js +2 -0
  27. package/src/handlers/yaml_handler.js +33 -0
  28. package/src/handlers/yml_handler.js +2 -0
  29. package/src/project/builtins.js +5 -0
  30. package/src/project/coreGlobals.js +17 -0
  31. package/src/{runtime → project}/jsGlobals.js +3 -1
  32. package/src/project/projectConfig.js +36 -0
  33. package/src/project/projectGlobals.js +19 -0
  34. package/src/project/projectRoot.js +59 -0
  35. package/src/protocols/constructHref.js +20 -0
  36. package/src/protocols/constructSiteTree.js +26 -0
  37. package/src/protocols/explore.js +14 -0
  38. package/src/protocols/fetchAndHandleExtension.js +25 -0
  39. package/src/protocols/files.js +26 -0
  40. package/src/protocols/http.js +15 -0
  41. package/src/protocols/https.js +15 -0
  42. package/src/protocols/httpstree.js +14 -0
  43. package/src/protocols/httptree.js +14 -0
  44. package/src/protocols/node.js +13 -0
  45. package/src/protocols/package.js +67 -0
  46. package/src/protocols/protocolGlobals.js +12 -0
  47. package/src/protocols/protocols.js +8 -0
  48. package/src/runtime/EventTargetMixin.js +1 -1
  49. package/src/runtime/HandleExtensionsTransform.js +3 -12
  50. package/src/runtime/ImportModulesMixin.js +4 -10
  51. package/src/runtime/InvokeFunctionsTransform.js +1 -1
  52. package/src/runtime/evaluate.js +15 -8
  53. package/src/runtime/expressionFunction.js +5 -7
  54. package/src/runtime/expressionObject.js +10 -20
  55. package/src/runtime/functionResultsMap.js +1 -3
  56. package/src/runtime/{handlers.js → handleExtension.js} +13 -11
  57. package/src/runtime/mergeTrees.js +1 -8
  58. package/src/runtime/ops.js +83 -90
  59. package/test/compiler/compile.test.js +20 -19
  60. package/test/compiler/optimize.test.js +60 -25
  61. package/test/compiler/parse.test.js +4 -4
  62. package/test/generator/oriEval.js +4 -5
  63. package/test/handlers/csv.handler.test.js +36 -0
  64. package/test/handlers/fixtures/add.wasm +0 -0
  65. package/test/handlers/fixtures/exif.jpeg +0 -0
  66. package/test/handlers/fixtures/frontMatter.md +5 -0
  67. package/test/handlers/fixtures/list.js +4 -0
  68. package/test/handlers/fixtures/multiple.js +4 -0
  69. package/test/handlers/fixtures/obj.js +3 -0
  70. package/test/handlers/fixtures/site.ori +5 -0
  71. package/test/handlers/fixtures/string.js +1 -0
  72. package/test/handlers/fixtures/tag.yaml +5 -0
  73. package/test/handlers/fixtures/test.ori +9 -0
  74. package/test/handlers/jpeg.handler.test.js +18 -0
  75. package/test/handlers/js.handler.test.js +46 -0
  76. package/test/handlers/json.handler.test.js +14 -0
  77. package/test/handlers/ori.handler.test.js +87 -0
  78. package/test/handlers/oridocument.handler.test.js +68 -0
  79. package/test/handlers/txt.handler.test.js +41 -0
  80. package/test/handlers/wasm.handler.test.js +20 -0
  81. package/test/handlers/yaml.handler.test.js +17 -0
  82. package/test/project/fixtures/withConfig/config.ori +4 -0
  83. package/test/project/fixtures/withConfig/subfolder/greet.js +1 -0
  84. package/test/project/fixtures/withPackageJson/package.json +0 -0
  85. package/test/project/jsGlobals.test.js +21 -0
  86. package/test/project/projectConfig.test.js +28 -0
  87. package/test/project/projectRoot.test.js +40 -0
  88. package/test/protocols/package.test.js +11 -0
  89. package/test/runtime/evaluate.test.js +26 -42
  90. package/test/runtime/expressionObject.test.js +16 -20
  91. package/test/runtime/{handlers.test.js → handleExtension.test.js} +4 -20
  92. package/test/runtime/jsGlobals.test.js +4 -6
  93. package/test/runtime/mergeTrees.test.js +2 -4
  94. package/test/runtime/ops.test.js +66 -68
  95. package/src/runtime/getHandlers.js +0 -10
package/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { UnpackFunction } from "@weborigami/async-tree";
2
+ import { AsyncTree } from "@weborigami/types";
2
3
 
3
4
  export * from "./main.js";
4
5
 
@@ -38,12 +39,6 @@ export type ExtensionHandler = {
38
39
  unpack?: UnpackFunction;
39
40
  }
40
41
 
41
- export type Position = {
42
- column: number;
43
- line: number;
44
- offset: number;
45
- }
46
-
47
42
  /**
48
43
  * A mixin is a function that takes an existing class and returns a new class.
49
44
  *
@@ -56,6 +51,21 @@ export type Mixin<MixinMembers> = <T>(
56
51
  Base: Constructor<T>
57
52
  ) => Constructor<T & MixinMembers>;
58
53
 
54
+ export type Position = {
55
+ column: number;
56
+ line: number;
57
+ offset: number;
58
+ }
59
+
60
+ export type RuntimeState = {
61
+ /** The container (e.g., file system) that holds the code */
62
+ container?: AsyncTree | null;
63
+ /** The object to which this code is attached */
64
+ object?: AsyncTree | null;
65
+ /** The current stack of function parameter assignments */
66
+ stack?: Array<Record<string, any>>;
67
+ }
68
+
59
69
  /**
60
70
  * Source code representation used by the parser.
61
71
  */
package/main.js CHANGED
@@ -2,17 +2,22 @@ export * from "./src/runtime/internal.js";
2
2
 
3
3
  export * as compile from "./src/compiler/compile.js";
4
4
  export { default as isOrigamiFrontMatter } from "./src/compiler/isOrigamiFrontMatter.js";
5
- export * from "./src/runtime/errors.js";
5
+ export * as Handlers from "./src/handlers/handlers.js";
6
+ export { default as builtins } from "./src/project/builtins.js";
7
+ export { default as jsGlobals } from "./src/project/jsGlobals.js";
8
+ export { default as projectGlobals } from "./src/project/projectGlobals.js";
9
+ export { default as projectRoot } from "./src/project/projectRoot.js";
10
+ export * as Protocols from "./src/protocols/protocols.js";
11
+ export { formatError } from "./src/runtime/errors.js";
6
12
  export { default as evaluate } from "./src/runtime/evaluate.js";
7
13
  export { default as EventTargetMixin } from "./src/runtime/EventTargetMixin.js";
8
14
  export * as expressionFunction from "./src/runtime/expressionFunction.js";
9
15
  export { default as functionResultsMap } from "./src/runtime/functionResultsMap.js";
10
- export { default as getHandlers } from "./src/runtime/getHandlers.js";
16
+ export * from "./src/runtime/handleExtension.js";
17
+ export { default as handleExtension } from "./src/runtime/handleExtension.js";
11
18
  export { default as HandleExtensionsTransform } from "./src/runtime/HandleExtensionsTransform.js";
12
- export * from "./src/runtime/handlers.js";
13
19
  export { default as ImportModulesMixin } from "./src/runtime/ImportModulesMixin.js";
14
20
  export { default as InvokeFunctionsTransform } from "./src/runtime/InvokeFunctionsTransform.js";
15
- export { default as jsGlobals } from "./src/runtime/jsGlobals.js";
16
21
  export * as moduleCache from "./src/runtime/moduleCache.js";
17
22
  export { default as OrigamiFiles } from "./src/runtime/OrigamiFiles.js";
18
23
  export * as symbols from "./src/runtime/symbols.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/language",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Web Origami expression language compiler and runtime",
5
5
  "type": "module",
6
6
  "main": "./main.js",
@@ -11,8 +11,9 @@
11
11
  "typescript": "5.9.2"
12
12
  },
13
13
  "dependencies": {
14
- "@weborigami/async-tree": "0.5.5",
15
- "@weborigami/types": "0.5.5",
14
+ "@weborigami/async-tree": "0.5.7",
15
+ "@weborigami/types": "0.5.7",
16
+ "exif-parser": "0.1.12",
16
17
  "watcher": "2.3.1",
17
18
  "yaml": "2.8.1"
18
19
  },
@@ -1,27 +1,33 @@
1
1
  import { createExpressionFunction } from "../runtime/expressionFunction.js";
2
- import jsGlobals from "../runtime/jsGlobals.js";
3
2
  import optimize from "./optimize.js";
4
3
  import { parse } from "./parse.js";
5
4
 
6
5
  function compile(source, options) {
7
- const { front, startRule } = options;
6
+ const { front, parent, startRule } = options;
8
7
  const mode = options.mode ?? "program";
9
- const globals = options.globals ?? jsGlobals;
8
+ const globals = options.globals ?? {};
10
9
  if (typeof source === "string") {
11
10
  source = { text: source };
12
11
  }
12
+
13
+ // Parse the code
13
14
  let code = parse(source.text, {
14
15
  front,
15
16
  grammarSource: source,
16
17
  mode,
17
18
  startRule,
18
19
  });
20
+
21
+ // Optimize the code
19
22
  const cache = mode === "program" ? {} : null;
20
23
  const optimized = optimize(code, {
21
24
  cache,
22
25
  globals,
26
+ parent,
23
27
  });
24
- const fn = createExpressionFunction(optimized);
28
+
29
+ // Create a function that executes the optimized code.
30
+ const fn = createExpressionFunction(optimized, parent);
25
31
  return fn;
26
32
  }
27
33
 
@@ -1,12 +1,13 @@
1
1
  import { pathFromKeys, trailingSlash } from "@weborigami/async-tree";
2
+ import jsGlobals from "../project/jsGlobals.js";
2
3
  import { entryKey } from "../runtime/expressionObject.js";
3
4
  import { ops } from "../runtime/internal.js";
4
- import jsGlobals from "../runtime/jsGlobals.js";
5
5
  import { annotate, markers } from "./parserHelpers.js";
6
6
 
7
- const REFERENCE_LOCAL = 1;
8
- const REFERENCE_GLOBAL = 2;
9
- const REFERENCE_EXTERNAL = 3;
7
+ export const REFERENCE_PARAM = 1;
8
+ export const REFERENCE_INHERITED = 2;
9
+ export const REFERENCE_GLOBAL = 3;
10
+ export const REFERENCE_EXTERNAL = 4;
10
11
 
11
12
  /**
12
13
  * Optimize an Origami code instruction:
@@ -27,10 +28,12 @@ const REFERENCE_EXTERNAL = 3;
27
28
  export default function optimize(code, options = {}) {
28
29
  const globals = options.globals ?? jsGlobals;
29
30
  const cache = options.cache === undefined ? {} : options.cache;
31
+ const parent = options.parent ?? null;
30
32
 
31
33
  // The locals is an array, one item for each function or object context that
32
- // has been entered. The array grows to the right. The array items are
33
- // subarrays containing the names of local variables defined in that context.
34
+ // has been entered. The array grows to the right. Array items are objects
35
+ // { type, names }, where type is REFERENCE_PARAM or REFERENCE_INHERITED
36
+ // and names is an array of the variable names in that context.
34
37
  const locals = options.locals ? options.locals.slice() : [];
35
38
 
36
39
  // See if we can optimize this level of the code
@@ -41,13 +44,16 @@ export default function optimize(code, options = {}) {
41
44
  return globals[args[0]];
42
45
 
43
46
  case markers.traverse:
44
- return resolvePath(code, globals, locals, cache);
47
+ return resolvePath(code, globals, parent, locals, cache);
45
48
 
46
49
  case ops.lambda:
47
50
  const parameters = args[0];
48
51
  if (parameters.length > 0) {
49
- const names = parameters.map((param) => param[1]);
50
- locals.push(names);
52
+ const paramNames = parameters.map((param) => param[1]);
53
+ locals.push({
54
+ type: REFERENCE_PARAM,
55
+ names: paramNames,
56
+ });
51
57
  }
52
58
  break;
53
59
 
@@ -56,8 +62,11 @@ export default function optimize(code, options = {}) {
56
62
 
57
63
  case ops.object:
58
64
  const entries = args;
59
- const keys = entries.map((entry) => entryKey(entry));
60
- locals.push(keys);
65
+ const propertyNames = entries.map((entry) => entryKey(entry));
66
+ locals.push({
67
+ type: REFERENCE_INHERITED,
68
+ names: propertyNames,
69
+ });
61
70
  break;
62
71
  }
63
72
 
@@ -106,18 +115,29 @@ function avoidLocalRecursion(locals, key) {
106
115
  key = key.slice(1, -1);
107
116
  }
108
117
 
109
- const currentFrame = locals.length - 1;
110
- const matchingKeyIndex = locals[currentFrame].findIndex(
111
- (localKey) =>
118
+ const currentFrameIndex = locals.length - 1;
119
+ if (locals[currentFrameIndex]?.type !== REFERENCE_INHERITED) {
120
+ // Not an inherited context, nothing to do
121
+ return locals;
122
+ }
123
+
124
+ // See if the key matches any of the local variable names in the current
125
+ // context (ignoring trailing slashes)
126
+ const matchingKeyIndex = locals[currentFrameIndex].names.findIndex(
127
+ (name) =>
112
128
  // Ignore trailing slashes when comparing keys
113
- trailingSlash.remove(localKey) === trailingSlash.remove(key)
129
+ trailingSlash.remove(name) === trailingSlash.remove(key)
114
130
  );
115
131
 
116
132
  if (matchingKeyIndex >= 0) {
117
133
  // Remove the key from the current context's locals
118
134
  const adjustedLocals = locals.slice();
119
- adjustedLocals[currentFrame] = adjustedLocals[currentFrame].slice();
120
- adjustedLocals[currentFrame].splice(matchingKeyIndex, 1);
135
+ const adjustedNames = adjustedLocals[currentFrameIndex].names.slice();
136
+ adjustedNames.splice(matchingKeyIndex, 1);
137
+ adjustedLocals[currentFrameIndex] = {
138
+ type: REFERENCE_INHERITED,
139
+ names: adjustedNames,
140
+ };
121
141
  return adjustedLocals;
122
142
  } else {
123
143
  return locals;
@@ -135,49 +155,54 @@ function compoundReference(key, globals, locals, location) {
135
155
  const parts = key.split(".");
136
156
  if (parts.length === 1) {
137
157
  // Not a compound reference
138
- return { type: REFERENCE_EXTERNAL, result: null };
158
+ return null;
139
159
  }
140
160
 
141
161
  // Check first part to see if it's a global or local reference
142
162
  const [head, ...tail] = parts;
143
- const type = referenceType(head, globals, locals);
144
- let result;
145
- if (type === REFERENCE_GLOBAL) {
146
- result = globalReference(head, globals);
147
- } else if (type === REFERENCE_LOCAL) {
148
- result = localReference(head, locals, location);
149
- } else {
150
- // Not a compound reference
151
- return { type: REFERENCE_EXTERNAL, result: null };
163
+ const headReference = localOrGlobalReference(head, globals, locals, location);
164
+ if (headReference === null) {
165
+ // First part isn't global/local reference, so not a compound reference
166
+ return null;
152
167
  }
153
168
 
169
+ let result = headReference.result;
170
+
154
171
  // Process the remaining parts as property accesses
155
172
  while (tail.length > 0) {
156
173
  const part = tail.shift();
157
174
  result = annotate([ops.property, result, part], location);
158
175
  }
159
176
 
160
- return { type, result };
177
+ return { type: headReference.type, result };
161
178
  }
162
179
 
163
- function externalReference(key, locals, location) {
164
- const scope = scopeCall(locals, location);
180
+ function externalReference(key, parent, location) {
181
+ const scope = annotate([ops.scope, parent], location);
165
182
  const literal = annotate([ops.literal, key], location);
166
183
  return annotate([scope, literal], location);
167
184
  }
168
185
 
169
- // Determine how many contexts up we need to go for a local
170
- function getLocalReferenceDepth(locals, key) {
171
- const contextIndex = locals.findLastIndex((names) =>
172
- names.some(
173
- (name) => trailingSlash.remove(name) === trailingSlash.remove(key)
174
- )
175
- );
176
- if (contextIndex < 0) {
177
- return -1; // Not a local reference
186
+ function findLocalDetails(key, locals) {
187
+ const normalized = trailingSlash.remove(key);
188
+ let paramDepth = 0;
189
+ let inheritedDepth = 0;
190
+ for (let i = locals.length - 1; i >= 0; i--) {
191
+ const { type, names } = locals[i];
192
+ const local = names.find(
193
+ (name) => trailingSlash.remove(name) === normalized
194
+ );
195
+ if (local) {
196
+ const depth = type === REFERENCE_PARAM ? paramDepth : inheritedDepth;
197
+ return { type, depth };
198
+ }
199
+ if (type === REFERENCE_PARAM) {
200
+ paramDepth++;
201
+ } else {
202
+ inheritedDepth++;
203
+ }
178
204
  }
179
- const depth = locals.length - contextIndex - 1;
180
- return depth;
205
+ return null;
181
206
  }
182
207
 
183
208
  function globalReference(key, globals) {
@@ -185,25 +210,18 @@ function globalReference(key, globals) {
185
210
  return globals[normalized];
186
211
  }
187
212
 
213
+ function inheritedReference(key, depth, location) {
214
+ const literal = annotate([ops.literal, key], location);
215
+ const inherited = annotate([ops.inherited, depth], location);
216
+ return annotate([inherited, literal], location);
217
+ }
218
+
188
219
  function inlineLiteral(code) {
189
220
  // If the literal value is an array, it's likely the strings array
190
221
  // of a template literal, so return it as is.
191
222
  return code[0] === ops.literal && !Array.isArray(code[1]) ? code[1] : code;
192
223
  }
193
224
 
194
- function localReference(key, locals, location) {
195
- const normalized = trailingSlash.remove(key);
196
- const depth = getLocalReferenceDepth(locals, normalized);
197
- /** @type {any[]} */
198
- const context = [ops.context];
199
- if (depth > 0) {
200
- context.push(depth);
201
- }
202
- const contextCall = annotate(context, location);
203
- const literal = annotate([ops.literal, key], location);
204
- return annotate([contextCall, literal], location);
205
- }
206
-
207
225
  function keyFromCode(code) {
208
226
  const op = code instanceof Array ? code[0] : code;
209
227
  switch (op) {
@@ -224,7 +242,37 @@ function keyFromCode(code) {
224
242
  }
225
243
  }
226
244
 
227
- function reference(code, globals, locals) {
245
+ function localOrGlobalReference(key, globals, locals, location) {
246
+ // Is key a local?
247
+ const normalized = trailingSlash.remove(key);
248
+ const localDetails = findLocalDetails(normalized, locals);
249
+ if (localDetails) {
250
+ const { type, depth } = localDetails;
251
+ const result =
252
+ type === REFERENCE_PARAM
253
+ ? paramReference(key, depth, location)
254
+ : inheritedReference(key, depth, location);
255
+ return { type, result };
256
+ }
257
+
258
+ // Is key a global?
259
+ if (normalized in globals) {
260
+ return {
261
+ type: REFERENCE_GLOBAL,
262
+ result: globalReference(key, globals),
263
+ };
264
+ }
265
+
266
+ return null;
267
+ }
268
+
269
+ function paramReference(key, depth, location) {
270
+ const literal = annotate([ops.literal, key], location);
271
+ const params = annotate([ops.params, depth], location);
272
+ return annotate([params, literal], location);
273
+ }
274
+
275
+ function reference(code, globals, parent, locals) {
228
276
  const key = keyFromCode(code);
229
277
  const normalized = trailingSlash.remove(key);
230
278
  const location = code.location;
@@ -247,61 +295,43 @@ function reference(code, globals, locals) {
247
295
  // Explicit external reference
248
296
  return {
249
297
  type: REFERENCE_EXTERNAL,
250
- result: externalReference(key, locals, location),
298
+ result: externalReference(key, parent, location),
251
299
  };
252
300
  }
253
301
 
254
302
  // See if the whole key is a global or local variable
255
- let type = referenceType(key, globals, locals);
256
- if (type === REFERENCE_GLOBAL) {
257
- return {
258
- type,
259
- result: globalReference(key, globals),
260
- };
261
- } else if (type === REFERENCE_LOCAL) {
262
- return {
263
- type,
264
- result: localReference(key, locals, location),
265
- };
303
+ const whole = localOrGlobalReference(key, globals, locals, location);
304
+ if (whole) {
305
+ return whole;
266
306
  }
267
307
 
268
308
  // Try key as a compound reference x.y.z
269
309
  const compound = compoundReference(key, globals, locals, location);
270
- if (compound.type !== REFERENCE_EXTERNAL) {
310
+ if (compound) {
271
311
  return compound;
272
312
  }
273
313
 
274
- // Not a compound reference, must be external
314
+ // Must be external
275
315
  return {
276
316
  type: REFERENCE_EXTERNAL,
277
- result: externalReference(key, locals, location),
317
+ result: externalReference(key, parent, location),
278
318
  };
279
319
  }
280
320
 
281
- function referenceType(key, globals, locals) {
282
- // Check if the key is a global variable
283
- const normalized = trailingSlash.remove(key);
284
- if (getLocalReferenceDepth(locals, normalized) >= 0) {
285
- return REFERENCE_LOCAL;
286
- } else if (normalized in globals) {
287
- return REFERENCE_GLOBAL;
288
- } else {
289
- return REFERENCE_EXTERNAL;
290
- }
291
- }
292
-
293
- function resolvePath(code, globals, locals, cache) {
321
+ function resolvePath(code, globals, parent, locals, cache) {
294
322
  const args = code.slice(1);
295
323
  const [head, ...tail] = args;
296
324
 
297
- let { type, result } = reference(head, globals, locals);
325
+ let { type, result } = reference(head, globals, parent, locals);
298
326
 
299
327
  if (tail.length > 0) {
300
328
  // If the result is a traversal, we can safely extend it
301
329
  const extendResult =
302
330
  result instanceof Array &&
303
331
  result[0] instanceof Array &&
304
- (result[0][0] === ops.scope || result[0][0] === ops.context);
332
+ (result[0][0] === ops.scope ||
333
+ result[0][0] === ops.params ||
334
+ result[0][0] === ops.inherited);
305
335
  if (extendResult) {
306
336
  result.push(...tail);
307
337
  } else {
@@ -316,15 +346,3 @@ function resolvePath(code, globals, locals, cache) {
316
346
 
317
347
  return result;
318
348
  }
319
-
320
- function scopeCall(locals, location) {
321
- const depth = locals.length;
322
- /** @type {any[]} */
323
- const code = [ops.scope];
324
- if (depth > 0) {
325
- // Add context for appropriate depth to scope call
326
- const contextCode = annotate([ops.context, depth], location);
327
- code.push(contextCode);
328
- }
329
- return annotate(code, location);
330
- }
@@ -207,9 +207,6 @@ doubleQuoteStringChar
207
207
 
208
208
  ellipsis
209
209
  = "..."
210
- / "…" {
211
- console.warn("The use of the Unicode ellipsis character for an object spread is deprecated; use `...` (three periods) instead.");
212
- }
213
210
 
214
211
  equalityExpression
215
212
  = head:relationalExpression tail:(__ @equalityOperator __ @relationalExpression)* {
@@ -719,7 +716,7 @@ shorthandFunction "lambda function"
719
716
  // Avoid a following equal sign (for an equality)
720
717
  = (shellMode / programMode) "=" !"=" __ definition:implicitParenthesesCallExpression {
721
718
  if (options.mode === "program") {
722
- console.warn("Warning: the shorthand function syntax is deprecated in Origami programs. Use arrow syntax instead.");
719
+ throw new Error("Parse error: shorthand function syntax isn't allowed in Origami programs. Use arrow syntax instead.");
723
720
  }
724
721
  const lambdaParameters = annotate(
725
722
  [annotate([ops.literal, "_"], location())],