@malloydata/malloy 0.0.191-dev240925183459 → 0.0.191-dev240927163326

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 (90) hide show
  1. package/dist/lang/ast/expressions/constant-expression.js +4 -1
  2. package/dist/lang/ast/expressions/expr-aggregate-function.js +25 -14
  3. package/dist/lang/ast/expressions/expr-alternation-tree.js +1 -3
  4. package/dist/lang/ast/expressions/expr-cast.js +1 -1
  5. package/dist/lang/ast/expressions/expr-coalesce.js +1 -1
  6. package/dist/lang/ast/expressions/expr-func.js +20 -31
  7. package/dist/lang/ast/expressions/expr-granular-time.js +1 -1
  8. package/dist/lang/ast/expressions/expr-id-reference.js +1 -3
  9. package/dist/lang/ast/expressions/expr-props.js +8 -8
  10. package/dist/lang/ast/expressions/expr-time-extract.js +7 -13
  11. package/dist/lang/ast/expressions/expr-ungroup.js +4 -8
  12. package/dist/lang/ast/expressions/for-range.js +2 -3
  13. package/dist/lang/ast/expressions/function-ordering.js +6 -6
  14. package/dist/lang/ast/expressions/partial-compare.js +1 -3
  15. package/dist/lang/ast/expressions/pick-when.js +30 -20
  16. package/dist/lang/ast/expressions/range.js +1 -1
  17. package/dist/lang/ast/expressions/top-by.js +1 -1
  18. package/dist/lang/ast/field-space/dynamic-space.js +1 -1
  19. package/dist/lang/ast/field-space/index-field-space.js +6 -6
  20. package/dist/lang/ast/field-space/parameter-space.js +14 -3
  21. package/dist/lang/ast/field-space/project-field-space.js +1 -1
  22. package/dist/lang/ast/field-space/query-spaces.d.ts +2 -1
  23. package/dist/lang/ast/field-space/query-spaces.js +7 -6
  24. package/dist/lang/ast/field-space/reference-field.js +1 -1
  25. package/dist/lang/ast/field-space/refined-space.js +3 -3
  26. package/dist/lang/ast/field-space/static-space.js +11 -2
  27. package/dist/lang/ast/parameters/has-parameter.js +4 -4
  28. package/dist/lang/ast/query-builders/index-builder.js +4 -4
  29. package/dist/lang/ast/query-builders/project-builder.js +2 -2
  30. package/dist/lang/ast/query-builders/reduce-builder.js +5 -5
  31. package/dist/lang/ast/query-elements/anonymous-query.js +1 -1
  32. package/dist/lang/ast/query-elements/query-reference.js +2 -2
  33. package/dist/lang/ast/query-items/field-declaration.js +7 -4
  34. package/dist/lang/ast/query-items/field-references.js +1 -1
  35. package/dist/lang/ast/query-items/typecheck_utils.js +31 -11
  36. package/dist/lang/ast/query-properties/filters.js +4 -4
  37. package/dist/lang/ast/query-properties/ordering.js +3 -3
  38. package/dist/lang/ast/query-properties/qop-desc.js +2 -2
  39. package/dist/lang/ast/query-properties/top.js +5 -5
  40. package/dist/lang/ast/query-utils.js +1 -1
  41. package/dist/lang/ast/source-elements/named-source.d.ts +2 -2
  42. package/dist/lang/ast/source-elements/named-source.js +12 -13
  43. package/dist/lang/ast/source-elements/refined-source.js +9 -7
  44. package/dist/lang/ast/source-elements/sql-source.js +5 -5
  45. package/dist/lang/ast/source-elements/table-source.js +2 -2
  46. package/dist/lang/ast/source-properties/joins.js +6 -6
  47. package/dist/lang/ast/source-properties/renames.js +3 -3
  48. package/dist/lang/ast/source-query-elements/source-query-element.d.ts +2 -1
  49. package/dist/lang/ast/source-query-elements/source-query-element.js +3 -2
  50. package/dist/lang/ast/source-query-elements/sq-arrow.js +2 -2
  51. package/dist/lang/ast/source-query-elements/sq-extend.js +1 -1
  52. package/dist/lang/ast/source-query-elements/sq-reference.js +5 -5
  53. package/dist/lang/ast/source-query-elements/sq-refine.js +2 -2
  54. package/dist/lang/ast/source-query-elements/sq-source.js +1 -1
  55. package/dist/lang/ast/sql-elements/sql-string.js +2 -2
  56. package/dist/lang/ast/statements/define-query.js +2 -2
  57. package/dist/lang/ast/statements/define-source.js +3 -3
  58. package/dist/lang/ast/statements/import-statement.js +7 -7
  59. package/dist/lang/ast/struct-utils.js +1 -1
  60. package/dist/lang/ast/types/expression-def.js +21 -22
  61. package/dist/lang/ast/types/lookup-result.d.ts +5 -1
  62. package/dist/lang/ast/types/malloy-element.d.ts +8 -5
  63. package/dist/lang/ast/types/malloy-element.js +33 -27
  64. package/dist/lang/ast/view-elements/qop-desc-view.js +3 -3
  65. package/dist/lang/ast/view-elements/reference-view.js +6 -6
  66. package/dist/lang/ast/view-elements/refine-utils.js +6 -6
  67. package/dist/lang/ast/view-elements/view-arrow.js +1 -1
  68. package/dist/lang/ast/view-elements/view-refine.js +1 -1
  69. package/dist/lang/malloy-to-ast.d.ts +7 -7
  70. package/dist/lang/malloy-to-ast.js +56 -55
  71. package/dist/lang/parse-log.d.ts +323 -6
  72. package/dist/lang/parse-log.js +62 -16
  73. package/dist/lang/parse-malloy.d.ts +5 -3
  74. package/dist/lang/parse-malloy.js +22 -31
  75. package/dist/lang/test/annotation.spec.js +4 -4
  76. package/dist/lang/test/expressions.spec.js +93 -74
  77. package/dist/lang/test/imports.spec.js +5 -5
  78. package/dist/lang/test/lenses.spec.js +18 -18
  79. package/dist/lang/test/literals.spec.js +1 -1
  80. package/dist/lang/test/locations.spec.js +5 -5
  81. package/dist/lang/test/parameters.spec.js +34 -34
  82. package/dist/lang/test/parse-expects.d.ts +10 -28
  83. package/dist/lang/test/parse-expects.js +38 -33
  84. package/dist/lang/test/parse.spec.js +49 -49
  85. package/dist/lang/test/query.spec.js +82 -82
  86. package/dist/lang/test/source.spec.js +6 -6
  87. package/dist/lang/test/test-translator.d.ts +19 -0
  88. package/dist/lang/test/test-translator.js +20 -1
  89. package/dist/tags.js +4 -2
  90. package/package.json +1 -1
@@ -36,7 +36,10 @@ class ConstantFieldSpace {
36
36
  }
37
37
  lookup(_name) {
38
38
  return {
39
- error: 'Only constants allowed in parameter default values',
39
+ error: {
40
+ message: 'Only constants allowed in parameter default values',
41
+ code: 'illegal-reference-in-parameter-default',
42
+ },
40
43
  found: undefined,
41
44
  };
42
45
  }
@@ -49,7 +49,7 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
49
49
  return 'number';
50
50
  }
51
51
  getExpression(fs) {
52
- var _a, _b;
52
+ var _a, _b, _c;
53
53
  // It is never useful to use output fields in an aggregate expression
54
54
  // so we don't even allow them to be referenced at all
55
55
  const inputFS = fs.isQueryFieldSpace() ? fs.inputSpace() : fs;
@@ -88,23 +88,19 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
88
88
  }
89
89
  else {
90
90
  if (!(sourceFoot instanceof struct_space_field_base_1.StructSpaceFieldBase)) {
91
- this.log(`Aggregate source cannot be a ${footType.dataType}`);
92
- return (0, ast_utils_1.errorFor)(`Aggregate source cannot be a ${footType.dataType}`);
91
+ return this.loggedErrorExpr('invalid-aggregate-source', `Aggregate source cannot be a ${footType.dataType}`);
93
92
  }
94
93
  }
95
94
  }
96
95
  else {
97
- this.log(`Reference to undefined value ${this.source.refString}`);
98
- return (0, ast_utils_1.errorFor)(`Reference to undefined value ${this.source.refString}`);
96
+ return this.loggedErrorExpr('aggregate-source-not-found', `Reference to undefined value ${this.source.refString}`);
99
97
  }
100
98
  }
101
99
  if (exprVal === undefined) {
102
- this.log('Missing expression for aggregate function');
103
- return (0, ast_utils_1.errorFor)('agggregate without expression');
100
+ return this.loggedErrorExpr('missing-aggregate-expression', 'Missing expression for aggregate function');
104
101
  }
105
102
  if ((0, malloy_types_1.expressionIsAggregate)(exprVal.expressionType)) {
106
- this.log('Aggregate expression cannot be aggregate');
107
- return (0, ast_utils_1.errorFor)('reagggregate');
103
+ return this.loggedErrorExpr('aggregate-of-aggregate', 'Aggregate expression cannot be aggregate');
108
104
  }
109
105
  const isAnError = exprVal.dataType === 'error';
110
106
  if (!isAnError) {
@@ -118,11 +114,17 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
118
114
  const usagePaths = getJoinUsagePaths(sourceRelationship, joinUsage);
119
115
  const joinError = validateUsagePaths(this.elementType, usagePaths);
120
116
  const message = sourceSpecified
121
- ? joinError
117
+ ? joinError === null || joinError === void 0 ? void 0 : joinError.message
122
118
  : 'Join path is required for this calculation';
123
119
  if (message) {
124
120
  const errorWithSuggestion = suggestNewVersion(message, joinUsage, expr, this.elementType);
125
- this.log(errorWithSuggestion, joinError ? 'error' : 'warn');
121
+ const code = (_c = joinError === null || joinError === void 0 ? void 0 : joinError.code) !== null && _c !== void 0 ? _c : 'bad-join-usage';
122
+ if (joinError) {
123
+ this.logError(code, errorWithSuggestion);
124
+ }
125
+ else {
126
+ this.logWarning(code, errorWithSuggestion);
127
+ }
126
128
  }
127
129
  }
128
130
  }
@@ -269,13 +271,22 @@ function validateUsagePaths(functionName, usagePaths) {
269
271
  for (const path of usagePaths) {
270
272
  for (const step of path) {
271
273
  if (step.structRelationship.type === 'cross') {
272
- return `Cannot compute \`${functionName}\` across \`join_cross\` relationship \`${step.name}\``;
274
+ return {
275
+ code: 'aggregate-traverses-join-cross',
276
+ message: `Cannot compute \`${functionName}\` across \`join_cross\` relationship \`${step.name}\``,
277
+ };
273
278
  }
274
279
  else if (step.structRelationship.type === 'many' && !step.reverse) {
275
- return `Cannot compute \`${functionName}\` across \`join_many\` relationship \`${step.name}\``;
280
+ return {
281
+ code: 'aggregate-traverses-join-many',
282
+ message: `Cannot compute \`${functionName}\` across \`join_many\` relationship \`${step.name}\``,
283
+ };
276
284
  }
277
285
  else if (step.structRelationship.type === 'nested' && !step.reverse) {
278
- return `Cannot compute \`${functionName}\` across repeated relationship \`${step.name}\``;
286
+ return {
287
+ code: 'aggregate-traverses-repeated-relationship',
288
+ message: `Cannot compute \`${functionName}\` across repeated relationship \`${step.name}\``,
289
+ };
279
290
  }
280
291
  }
281
292
  }
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ExprAlternationTree = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
- const ast_utils_1 = require("../ast-utils");
28
27
  const expression_def_1 = require("../types/expression-def");
29
28
  class ExprAlternationTree extends expression_def_1.ExpressionDef {
30
29
  constructor(left, op, right) {
@@ -52,8 +51,7 @@ class ExprAlternationTree extends expression_def_1.ExpressionDef {
52
51
  return undefined;
53
52
  }
54
53
  getExpression(_fs) {
55
- this.log('Alternation tree has no value');
56
- return (0, ast_utils_1.errorFor)('no value from alternation tree');
54
+ return this.loggedErrorExpr('alternation-as-value', 'Alternation tree has no value');
57
55
  }
58
56
  }
59
57
  exports.ExprAlternationTree = ExprAlternationTree;
@@ -50,7 +50,7 @@ class ExprCast extends expression_def_1.ExpressionDef {
50
50
  (_c = (_b = (_a = fs.dialectObj()) === null || _a === void 0 ? void 0 : _a.sqlTypeToMalloyType(this.castType.raw)) === null || _b === void 0 ? void 0 : _b.type) !== null && _c !== void 0 ? _c : 'sql native';
51
51
  }
52
52
  else {
53
- this.log(`Cast type \`${this.castType.raw}\` is invalid for ${dialect.name} dialect`);
53
+ this.logError('invalid-sql-native-type', `Cast type \`${this.castType.raw}\` is invalid for ${dialect.name} dialect`);
54
54
  }
55
55
  }
56
56
  }
@@ -49,7 +49,7 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
49
49
  * trees" rewrite happens.
50
50
  */
51
51
  if (!fragtype_utils_1.FT.typeEq(maybeNull, whenNull)) {
52
- this.log(`Mismatched types for coalesce (${maybeNull.dataType}, ${whenNull.dataType})`);
52
+ this.logError('mismatched-coalesce-types', `Mismatched types for coalesce (${maybeNull.dataType}, ${whenNull.dataType})`);
53
53
  }
54
54
  return {
55
55
  ...whenNull,
@@ -62,15 +62,15 @@ class ExprFunc extends expression_def_1.ExpressionDef {
62
62
  : undefined;
63
63
  const func = dialectFunc !== null && dialectFunc !== void 0 ? dialectFunc : (_c = this.modelEntry(normalizedName)) === null || _c === void 0 ? void 0 : _c.entry;
64
64
  if (func === undefined) {
65
- this.log(`Unknown function '${this.name}'. Use '${this.name}!(...)' to call a SQL function directly.`);
65
+ this.logError('function-not-found', `Unknown function '${this.name}'. Use '${this.name}!(...)' to call a SQL function directly.`);
66
66
  return { found: undefined, error: 'unknown function' };
67
67
  }
68
68
  else if (func.type !== 'function') {
69
- this.log(`Cannot call '${this.name}', which is of type ${func.type}`);
69
+ this.logError(`${func.type}-not-callable`, `Cannot call '${this.name}', which is of type ${func.type}`);
70
70
  return { found: undefined, error: 'called non function' };
71
71
  }
72
72
  if (func.name !== this.name) {
73
- this.log(`Case insensitivity for function names is deprecated, use '${func.name}' instead`, 'warn');
73
+ this.logWarning('case-insensitive-function', `Case insensitivity for function names is deprecated, use '${func.name}' instead`);
74
74
  }
75
75
  return { found: func, error: undefined };
76
76
  }
@@ -124,16 +124,12 @@ class ExprFunc extends expression_def_1.ExpressionDef {
124
124
  }
125
125
  else {
126
126
  if (!(sourceFoot instanceof struct_space_field_base_1.StructSpaceFieldBase)) {
127
- const message = `Aggregate source cannot be a ${footType.dataType}`;
128
- this.log(message);
129
- return (0, ast_utils_1.errorFor)(message);
127
+ return this.loggedErrorExpr('invalid-aggregate-source', `Aggregate source cannot be a ${footType.dataType}`);
130
128
  }
131
129
  }
132
130
  }
133
131
  else {
134
- const message = `Reference to undefined value ${this.source.refString}`;
135
- this.log(message);
136
- return (0, ast_utils_1.errorFor)(message);
132
+ this.loggedErrorExpr('aggregate-source-not-found', `Reference to undefined value ${this.source.refString}`);
137
133
  }
138
134
  }
139
135
  // Construct the full args list including the implicit arg.
@@ -143,10 +139,9 @@ class ExprFunc extends expression_def_1.ExpressionDef {
143
139
  ];
144
140
  const result = findOverload(func, argExprs);
145
141
  if (result === undefined) {
146
- this.log(`No matching overload for function ${this.name}(${argExprs
142
+ return this.loggedErrorExpr('no-matching-function-overload', `No matching overload for function ${this.name}(${argExprs
147
143
  .map(e => e.dataType)
148
144
  .join(', ')})`);
149
- return (0, ast_utils_1.errorFor)('no matching overload');
150
145
  }
151
146
  const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors } = result;
152
147
  // Report errors for expression type mismatch
@@ -156,7 +151,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
156
151
  ? 'scalar'
157
152
  : 'scalar or aggregate';
158
153
  const arg = this.args[adjustedIndex];
159
- arg.log(`Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualExpressionType}`);
154
+ arg.logError('invalid-function-argument-expression-type', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualExpressionType}`);
160
155
  }
161
156
  // Report errors for eval space mismatch
162
157
  for (const error of evalSpaceErrors) {
@@ -167,13 +162,13 @@ class ExprFunc extends expression_def_1.ExpressionDef {
167
162
  ? 'literal or constant'
168
163
  : 'literal, constant or output';
169
164
  const arg = this.args[adjustedIndex];
170
- arg.log(`Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualEvalSpace}`);
165
+ arg.logError('invalid-function-argument-evaluation-space', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualEvalSpace}`);
171
166
  }
172
167
  // Report nullability errors
173
168
  for (const error of nullabilityErrors) {
174
169
  const adjustedIndex = error.argIndex - (implicitExpr ? 1 : 0);
175
170
  const arg = this.args[adjustedIndex];
176
- arg.log(`Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must not be a literal null`);
171
+ arg.logError('literal-null-function-argument', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must not be a literal null`);
177
172
  }
178
173
  const type = overload.returnType;
179
174
  const expressionType = (0, malloy_types_1.maxOfExpressionTypes)([
@@ -182,10 +177,9 @@ class ExprFunc extends expression_def_1.ExpressionDef {
182
177
  ]);
183
178
  if (!(0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
184
179
  this.source !== undefined) {
185
- this.log(`Cannot call function ${this.name}(${argExprs
180
+ return this.loggedErrorExpr('non-aggregate-function-with-source', `Cannot call function ${this.name}(${argExprs
186
181
  .map(e => e.dataType)
187
182
  .join(', ')}) with source`);
188
- return (0, ast_utils_1.errorFor)('cannot call with source');
189
183
  }
190
184
  const frag = {
191
185
  node: 'function_call',
@@ -203,7 +197,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
203
197
  const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(overload.returnType.expressionType);
204
198
  if (!isAnalytic) {
205
199
  if (!this.inExperiment('aggregate_order_by', true)) {
206
- props.orderBys[0].log('Enable experiment `aggregate_order_by` to use `order_by` with an aggregate function');
200
+ props.orderBys[0].logError('aggregate-order-by-experiment-not-enabled', 'Enable experiment `aggregate_order_by` to use `order_by` with an aggregate function');
207
201
  }
208
202
  }
209
203
  if (overload.supportsOrderBy || isAnalytic) {
@@ -214,7 +208,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
214
208
  frag.kids.orderBy = allObs;
215
209
  }
216
210
  else {
217
- props.orderBys[0].log(`Function \`${this.name}\` does not support \`order_by\``);
211
+ props.orderBys[0].logError('function-does-not-support-order-by', `Function \`${this.name}\` does not support \`order_by\``);
218
212
  }
219
213
  }
220
214
  if ((props === null || props === void 0 ? void 0 : props.limit) !== undefined) {
@@ -222,7 +216,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
222
216
  frag.limit = props.limit.limit;
223
217
  }
224
218
  else {
225
- this.log(`Function ${this.name} does not support limit`);
219
+ this.logError('function-does-not-support-limit', `Function ${this.name} does not support limit`);
226
220
  }
227
221
  }
228
222
  if ((props === null || props === void 0 ? void 0 : props.partitionBys) && props.partitionBys.length > 0) {
@@ -231,11 +225,11 @@ class ExprFunc extends expression_def_1.ExpressionDef {
231
225
  for (const partitionField of partitionBy.partitionFields) {
232
226
  const e = partitionField.getField(fs);
233
227
  if (e.found === undefined) {
234
- partitionField.log(`${partitionField.refString} is not defined`);
228
+ partitionField.logError('partition-by-not-found', `${partitionField.refString} is not defined`);
235
229
  }
236
230
  else if ((0, malloy_types_1.expressionIsAnalytic)(e.found.typeDesc().expressionType) ||
237
231
  (0, malloy_types_1.expressionIsUngroupedAggregate)(e.found.typeDesc().expressionType)) {
238
- partitionField.log('Partition expression must be scalar or aggregate');
232
+ partitionField.logError('non-scalar-or-aggregate-partition-by', 'Partition expression must be scalar or aggregate');
239
233
  }
240
234
  else {
241
235
  partitionByFields.push(partitionField.nameString);
@@ -252,13 +246,11 @@ class ExprFunc extends expression_def_1.ExpressionDef {
252
246
  'sql_boolean',
253
247
  ].includes(func.name)) {
254
248
  if (!this.inExperiment('sql_functions', true)) {
255
- const message = `Cannot use sql_function \`${func.name}\`; use \`sql_functions\` experiment to enable this behavior`;
256
- this.log(message);
257
- return (0, ast_utils_1.errorFor)('sql_function used without enabling');
249
+ return this.loggedErrorExpr('sql-functions-experiment-not-enabled', `Cannot use sql_function \`${func.name}\`; use \`sql_functions\` experiment to enable this behavior`);
258
250
  }
259
251
  const str = argExprs[0].value;
260
252
  if (str.node !== 'stringLiteral') {
261
- this.log(`Invalid string literal for \`${func.name}\``);
253
+ this.logError('invalid-sql-function-argument', `Invalid string literal for \`${func.name}\``);
262
254
  }
263
255
  else {
264
256
  const literal = str.literal;
@@ -272,8 +264,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
272
264
  const unsupportedInterpolationMsg = unsupportedInterpolations.length === 1
273
265
  ? `'.' paths are not yet supported in sql interpolations, found ${unsupportedInterpolations.at(0)}`
274
266
  : `'.' paths are not yet supported in sql interpolations, found (${unsupportedInterpolations.join(', ')})`;
275
- this.log(unsupportedInterpolationMsg);
276
- return (0, ast_utils_1.errorFor)(`${unsupportedInterpolationMsg}. See LookML \${...} documentation at https://cloud.google.com/looker/docs/reference/param-field-sql#sql_for_dimensions`);
267
+ return this.loggedErrorExpr('unsupported-sql-function-interpolation', unsupportedInterpolationMsg);
277
268
  }
278
269
  const expr = [];
279
270
  for (const part of parts) {
@@ -288,8 +279,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
288
279
  this.has({ name });
289
280
  const result = fs.lookup([name]);
290
281
  if (result.found === undefined) {
291
- this.log(`Invalid interpolation: ${result.error}`);
292
- return (0, ast_utils_1.errorFor)('invalid interpolated field');
282
+ return this.loggedErrorExpr('sql-function-interpolation-not-found', `Invalid interpolation: ${result.error.message}`);
293
283
  }
294
284
  if (result.found.refType === 'parameter') {
295
285
  expr.push({ node: 'parameter', path: [part.name] });
@@ -303,8 +293,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
303
293
  }
304
294
  }
305
295
  if (type.dataType === 'any') {
306
- this.log(`Invalid return type ${type.dataType} for function '${this.name}'`);
307
- return (0, ast_utils_1.errorFor)('invalid return type');
296
+ return this.loggedErrorExpr('function-returns-any', `Invalid return type ${type.dataType} for function '${this.name}'`);
308
297
  }
309
298
  const maxEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(...argExprs.map(e => e.evalSpace));
310
299
  // If the merged eval space of all args is constant, the result is constant.
@@ -68,7 +68,7 @@ class ExprGranularTime extends expression_def_1.ExpressionDef {
68
68
  return tsVal;
69
69
  }
70
70
  if (exprVal.dataType !== 'error') {
71
- this.log(`Cannot do time truncation on type '${exprVal.dataType}'`);
71
+ this.logError('unsupported-type-for-time-truncation', `Cannot do time truncation on type '${exprVal.dataType}'`);
72
72
  }
73
73
  const returnType = exprVal.dataType === 'error'
74
74
  ? (0, malloy_types_1.isDateUnit)(timeframe)
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ExprIdReference = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
- const ast_utils_1 = require("../ast-utils");
28
27
  const expression_def_1 = require("../types/expression-def");
29
28
  class ExprIdReference extends expression_def_1.ExpressionDef {
30
29
  constructor(fieldReference) {
@@ -54,8 +53,7 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
54
53
  : td.evalSpace;
55
54
  return { ...td, value, evalSpace };
56
55
  }
57
- this.log(def.error);
58
- return (0, ast_utils_1.errorFor)(def.error);
56
+ return this.loggedErrorExpr(def.error.code, def.error.message);
59
57
  }
60
58
  }
61
59
  exports.ExprIdReference = ExprIdReference;
@@ -42,14 +42,14 @@ class ExprProps extends expression_def_1.ExpressionDef {
42
42
  getFilteredExpression(fs, expr, wheres) {
43
43
  if (wheres.length > 0) {
44
44
  if (!this.expr.supportsWhere(expr)) {
45
- this.expr.log('Filtered expression requires an aggregate computation');
45
+ this.expr.logError('filter-of-non-aggregate', 'Filtered expression requires an aggregate computation');
46
46
  return expr;
47
47
  }
48
48
  const filterList = [];
49
49
  for (const where of wheres) {
50
50
  const testList = where.getFilterList(fs);
51
51
  if (testList.find(cond => (0, malloy_types_1.expressionIsCalculation)(cond.expressionType))) {
52
- where.log('Cannot filter an expresion with an aggregate or analytical computation');
52
+ where.logError('aggregate-filter-expression-not-scalar', 'Cannot filter an expresion with an aggregate or analytical computation');
53
53
  return expr;
54
54
  }
55
55
  filterList.push(...testList);
@@ -63,7 +63,7 @@ class ExprProps extends expression_def_1.ExpressionDef {
63
63
  },
64
64
  };
65
65
  }
66
- this.expr.log(`Cannot filter '${expr.dataType}' data`);
66
+ this.expr.logError('filter-of-non-aggregate', `Cannot filter '${expr.expressionType}' data`);
67
67
  return (0, ast_utils_1.errorFor)('cannot filter type');
68
68
  }
69
69
  return expr;
@@ -76,7 +76,7 @@ class ExprProps extends expression_def_1.ExpressionDef {
76
76
  for (const statement of this.statements) {
77
77
  if (statement instanceof partition_by_1.PartitionBy) {
78
78
  if (!this.expr.canSupportPartitionBy()) {
79
- statement.log('`partition_by` is not supported for this kind of expression');
79
+ statement.logError('partition-by-of-non-window-function', '`partition_by` is not supported for this kind of expression');
80
80
  }
81
81
  else {
82
82
  partitionBys.push(statement);
@@ -84,18 +84,18 @@ class ExprProps extends expression_def_1.ExpressionDef {
84
84
  }
85
85
  else if (statement instanceof limit_1.Limit) {
86
86
  if (limit) {
87
- statement.log('limit already specified');
87
+ statement.logError('expression-limit-already-specified', 'limit already specified');
88
88
  }
89
89
  else if (!this.expr.canSupportLimit()) {
90
- statement.log('`limit` is not supported for this kind of expression');
90
+ statement.logError('limit-of-non-aggregate-function', '`limit` is not supported for this kind of expression');
91
91
  }
92
92
  else {
93
93
  limit = statement;
94
94
  }
95
95
  }
96
96
  else if (statement instanceof function_ordering_1.FunctionOrdering) {
97
- if (!this.expr.canSupportPartitionBy()) {
98
- statement.log('`order_by` is not supported for this kind of expression');
97
+ if (!this.expr.canSupportOrderBy()) {
98
+ statement.logError('order-by-of-non-aggregate-function', '`order_by` is not supported for this kind of expression');
99
99
  }
100
100
  else {
101
101
  orderBys.push(statement);
@@ -47,8 +47,7 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
47
47
  const extractTo = ExprTimeExtract.extractor(this.extractText);
48
48
  if (extractTo) {
49
49
  if (this.args.length !== 1) {
50
- this.log(`Extraction function ${extractTo} requires one argument`);
51
- return (0, ast_utils_1.errorFor)('{this.name} arg count');
50
+ return this.loggedErrorExpr('too-many-arguments-for-time-extraction', `Extraction function ${extractTo} requires one argument`);
52
51
  }
53
52
  const from = this.args[0];
54
53
  if (from instanceof range_1.Range) {
@@ -65,12 +64,10 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
65
64
  };
66
65
  }
67
66
  if (!(0, malloy_types_1.isTimeFieldType)(first.dataType)) {
68
- from.first.log(`Can't extract ${extractTo} from '${first.dataType}'`);
69
- return (0, ast_utils_1.errorFor)(`${extractTo} bad type ${first.dataType}`);
67
+ return from.first.loggedErrorExpr('invalid-type-for-time-extraction', `Can't extract ${extractTo} from '${first.dataType}'`);
70
68
  }
71
69
  if (!(0, malloy_types_1.isTimeFieldType)(last.dataType)) {
72
- from.last.log(`Cannot extract ${extractTo} from '${last.dataType}'`);
73
- return (0, ast_utils_1.errorFor)(`${extractTo} bad type ${last.dataType}`);
70
+ return from.last.loggedErrorExpr('invalid-type-for-time-extraction', `Cannot extract ${extractTo} from '${last.dataType}'`);
74
71
  }
75
72
  let valueType = first.dataType;
76
73
  if (first.dataType !== last.dataType) {
@@ -91,17 +88,14 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
91
88
  }
92
89
  }
93
90
  if (cannotMeasure) {
94
- from.first.log(`Cannot measure from ${first.dataType} to ${last.dataType}`);
95
- return (0, ast_utils_1.errorFor)(`${extractTo} range mismatch`);
91
+ return from.first.loggedErrorExpr('invalid-types-for-time-measurement', `Cannot measure from ${first.dataType} to ${last.dataType}`);
96
92
  }
97
93
  }
98
94
  if (['week', 'month', 'quarter', 'year'].includes(extractTo)) {
99
- this.log(`Cannot measure interval using '${extractTo}'`);
100
- return (0, ast_utils_1.errorFor)(`${extractTo} civil extraction`);
95
+ return this.loggedErrorExpr('invalid-timeframe-for-time-measurement', `Cannot measure interval using '${extractTo}'`);
101
96
  }
102
97
  if (!(0, malloy_types_1.isTimestampUnit)(extractTo)) {
103
- this.log(`Cannot extract ${extractTo} from a range`);
104
- return (0, ast_utils_1.errorFor)(`${extractTo} bad extraction`);
98
+ return this.loggedErrorExpr('invalid-time-extraction-unit', `Cannot extract ${extractTo} from a range`);
105
99
  }
106
100
  return {
107
101
  dataType: 'number',
@@ -132,7 +126,7 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
132
126
  };
133
127
  }
134
128
  if (argV.dataType !== 'error') {
135
- this.log(`${this.extractText}() requires time type, not '${argV.dataType}'`);
129
+ this.logError('unsupported-type-for-time-extraction', `${this.extractText}() requires time type, not '${argV.dataType}'`);
136
130
  }
137
131
  return {
138
132
  dataType: 'number',
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ExprUngroup = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
- const ast_utils_1 = require("../ast-utils");
28
27
  const query_spaces_1 = require("../field-space/query-spaces");
29
28
  const fragtype_utils_1 = require("../fragtype-utils");
30
29
  const expression_def_1 = require("../types/expression-def");
@@ -43,12 +42,10 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
43
42
  getExpression(fs) {
44
43
  const exprVal = this.expr.getExpression(fs);
45
44
  if (!(0, malloy_types_1.expressionIsAggregate)(exprVal.expressionType)) {
46
- this.expr.log(`${this.control}() expression must be an aggregate`);
47
- return (0, ast_utils_1.errorFor)('ungrouped scalar');
45
+ return this.expr.loggedErrorExpr('ungroup-of-non-aggregate', `${this.control}() expression must be an aggregate`);
48
46
  }
49
47
  if ((0, malloy_types_1.expressionIsUngroupedAggregate)(exprVal.expressionType)) {
50
- this.expr.log(`${this.control}() expression must not already be ungrouped`);
51
- return (0, ast_utils_1.errorFor)('doubly-ungrouped aggregate');
48
+ return this.expr.loggedErrorExpr('ungroup-of-ungrouped-aggregate', `${this.control}() expression must not already be ungrouped`);
52
49
  }
53
50
  const ungroup = {
54
51
  node: this.control,
@@ -79,7 +76,7 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
79
76
  }
80
77
  if (notFound) {
81
78
  const uName = isExclude ? 'exclude()' : 'all()';
82
- mentionedField.log(`${uName} '${mentionedField.refString}' is missing from query output`);
79
+ mentionedField.logError('ungroup-field-not-in-output', `${uName} '${mentionedField.refString}' is missing from query output`);
83
80
  }
84
81
  }
85
82
  ungroup.fields = dstFields;
@@ -91,8 +88,7 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
91
88
  evalSpace: 'output',
92
89
  };
93
90
  }
94
- this.log(`${this.control}() incompatible type`);
95
- return (0, ast_utils_1.errorFor)('ungrouped type check');
91
+ return this.loggedErrorExpr('ungroup-with-non-scalar', `${this.control}() incompatible type`);
96
92
  }
97
93
  }
98
94
  exports.ExprUngroup = ExprUngroup;
@@ -48,7 +48,7 @@ class ForRange extends expression_def_1.ExpressionDef {
48
48
  const nV = this.duration.getExpression(fs);
49
49
  if (nV.dataType !== 'number') {
50
50
  if (nV.dataType !== 'error') {
51
- this.log(`FOR duration count must be a number, not '${nV.dataType}'`);
51
+ this.logError('invalid-duration-quantity', `FOR duration count must be a number, not '${nV.dataType}'`);
52
52
  }
53
53
  return {
54
54
  dataType: 'boolean',
@@ -96,8 +96,7 @@ class ForRange extends expression_def_1.ExpressionDef {
96
96
  return undefined;
97
97
  }
98
98
  getExpression(_fs) {
99
- this.log('A Range is not a value');
100
- return (0, ast_utils_1.errorFor)('range has no value');
99
+ return this.loggedErrorExpr('range-as-value', 'A Range is not a value');
101
100
  }
102
101
  }
103
102
  exports.ForRange = ForRange;
@@ -37,7 +37,7 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
37
37
  }
38
38
  getAnalyticOrderBy(fs) {
39
39
  if (!this.field) {
40
- this.log('analytic `order_by` must specify an aggregate expression or output field reference');
40
+ this.logError('analytic-order-by-missing-field', 'analytic `order_by` must specify an aggregate expression or output field reference');
41
41
  return { node: 'functionOrderBy', e: { node: 'error' }, dir: this.dir };
42
42
  }
43
43
  const expr = this.field.getExpression(fs);
@@ -47,11 +47,11 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
47
47
  else if ((0, malloy_types_1.expressionIsScalar)(expr.expressionType)) {
48
48
  if (!(this.field instanceof expr_id_reference_1.ExprIdReference) ||
49
49
  expr.evalSpace === 'input') {
50
- this.field.log('analytic `order_by` must be an aggregate or an output field reference');
50
+ this.field.logError('analytic-order-by-not-output', 'analytic `order_by` must be an aggregate or an output field reference');
51
51
  }
52
52
  }
53
53
  else {
54
- this.field.log('analytic `order_by` must be scalar or aggregate');
54
+ this.field.logError('analytic-order-by-not-aggregate-or-output', 'analytic `order_by` must be scalar or aggregate');
55
55
  }
56
56
  return { node: 'functionOrderBy', e: expr.value, dir: this.dir };
57
57
  }
@@ -59,17 +59,17 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
59
59
  if (this.field) {
60
60
  const expr = this.field.getExpression(fs);
61
61
  if (!(0, malloy_types_1.expressionIsScalar)(expr.expressionType)) {
62
- this.field.log('aggregate `order_by` must be scalar');
62
+ this.field.logError('aggregate-order-by-not-scalar', 'aggregate `order_by` must be scalar');
63
63
  }
64
64
  if (!allowExpression) {
65
- this.field.log('`order_by` must be only `asc` or `desc` with no expression');
65
+ this.field.logError('aggregate-order-by-expression-not-allowed', '`order_by` must be only `asc` or `desc` with no expression');
66
66
  }
67
67
  return { node: 'functionOrderBy', e: expr.value, dir: this.dir };
68
68
  }
69
69
  else {
70
70
  if (this.dir === undefined) {
71
71
  // This error should technically never happen because it can't parse this way
72
- this.log('field or order direction must be specified');
72
+ this.logError('aggregate-order-by-without-field-or-direction', 'field or order direction must be specified');
73
73
  return { node: 'functionDefaultOrderBy', dir: 'asc' };
74
74
  }
75
75
  return { node: 'functionDefaultOrderBy', dir: this.dir };
@@ -23,7 +23,6 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.PartialCompare = void 0;
26
- const ast_utils_1 = require("../ast-utils");
27
26
  const expression_def_1 = require("../types/expression-def");
28
27
  class PartialCompare extends expression_def_1.ExpressionDef {
29
28
  constructor(op, right) {
@@ -42,8 +41,7 @@ class PartialCompare extends expression_def_1.ExpressionDef {
42
41
  return undefined;
43
42
  }
44
43
  getExpression(_fs) {
45
- this.log('Partial comparison does not have a value');
46
- return (0, ast_utils_1.errorFor)('no value for partial compare');
44
+ return this.loggedErrorExpr('partial-as-value', 'Partial comparison does not have a value');
47
45
  }
48
46
  }
49
47
  exports.PartialCompare = PartialCompare;