@malloydata/malloy 0.0.43-dev230621212545 → 0.0.43-dev230622180905

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 (33) hide show
  1. package/dist/lang/ast/ast-utils.js +1 -1
  2. package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
  3. package/dist/lang/ast/expressions/expr-func.js +9 -34
  4. package/dist/lang/ast/expressions/expr-granular-time.js +14 -2
  5. package/dist/lang/ast/expressions/expr-minus.js +2 -2
  6. package/dist/lang/ast/expressions/expr-time-extract.js +22 -4
  7. package/dist/lang/ast/expressions/for-range.d.ts +1 -1
  8. package/dist/lang/ast/expressions/for-range.js +10 -2
  9. package/dist/lang/ast/expressions/pick-when.js +5 -1
  10. package/dist/lang/ast/field-space/query-spaces.js +3 -6
  11. package/dist/lang/ast/field-space/reference-field.js +1 -1
  12. package/dist/lang/ast/fragtype-utils.d.ts +1 -1
  13. package/dist/lang/ast/fragtype-utils.js +3 -2
  14. package/dist/lang/ast/parameters/constant-parameter.js +1 -1
  15. package/dist/lang/ast/query-items/field-declaration.js +5 -8
  16. package/dist/lang/ast/types/expression-def.js +29 -3
  17. package/dist/lang/ast/types/malloy-element.d.ts +2 -1
  18. package/dist/lang/ast/types/malloy-element.js +2 -10
  19. package/dist/lang/ast/types/space-param.js +1 -1
  20. package/dist/lang/parse-error-handler.js +1 -0
  21. package/dist/lang/parse-log.d.ts +1 -1
  22. package/dist/lang/parse-malloy.d.ts +13 -7
  23. package/dist/lang/parse-malloy.js +28 -17
  24. package/dist/lang/test/parse-expects.d.ts +21 -2
  25. package/dist/lang/test/parse-expects.js +97 -73
  26. package/dist/lang/test/parse.spec.js +269 -20
  27. package/dist/lang/test/sql-block.spec.js +1 -1
  28. package/dist/lang/test/test-translator.js +3 -0
  29. package/dist/lang/translate-response.d.ts +8 -8
  30. package/dist/malloy.d.ts +6 -4
  31. package/dist/malloy.js +14 -7
  32. package/dist/model/malloy_types.d.ts +6 -3
  33. package/package.json +1 -1
@@ -33,7 +33,7 @@ exports.errorFor = void 0;
33
33
  */
34
34
  function errorFor(reason) {
35
35
  return {
36
- dataType: 'unknown',
36
+ dataType: 'error',
37
37
  expressionType: 'scalar',
38
38
  value: [`_ERROR_${reason.replace(/ /g, '_')}`],
39
39
  evalSpace: 'constant',
@@ -48,8 +48,12 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
48
48
  * SQL, but I decided that is will happen when the "expressions are true
49
49
  * trees" rewrite happens.
50
50
  */
51
+ if (!fragtype_utils_1.FT.typeEq(maybeNull, whenNull)) {
52
+ this.log(`Mismatched types for coalesce (${maybeNull.dataType}, ${whenNull.dataType})`);
53
+ }
51
54
  return {
52
55
  ...whenNull,
56
+ dataType: maybeNull.dataType === 'error' ? whenNull.dataType : maybeNull.dataType,
53
57
  expressionType: (0, model_1.maxExpressionType)(maybeNull.expressionType, whenNull.expressionType),
54
58
  value: (0, model_1.mkExpr) `COALESCE(${maybeNull.value},${whenNull.value})`,
55
59
  evalSpace: (0, model_1.mergeEvalSpaces)(maybeNull.evalSpace, whenNull.evalSpace),
@@ -70,21 +70,14 @@ class ExprFunc extends expression_def_1.ExpressionDef {
70
70
  const func = (_c = this.modelEntry(this.name.toLowerCase())) === null || _c === void 0 ? void 0 : _c.entry;
71
71
  if (func === undefined) {
72
72
  this.log(`Unknown function '${this.name}'. Use '${this.name}!(...)' to call a SQL function directly.`);
73
- return {
74
- dataType: 'unknown',
75
- expressionType: 'scalar',
76
- value: [],
77
- evalSpace: 'constant',
78
- };
73
+ return (0, ast_utils_1.errorFor)('unknown function');
79
74
  }
80
75
  else if (func.type !== 'function') {
81
76
  this.log(`Cannot call '${this.name}', which is of type ${func.type}`);
82
- return {
83
- dataType: 'unknown',
84
- expressionType: 'scalar',
85
- value: [],
86
- evalSpace: 'constant',
87
- };
77
+ return (0, ast_utils_1.errorFor)('called non function');
78
+ }
79
+ if (func.name !== this.name) {
80
+ this.log(`Case insensitivity for function names is deprecated, use '${func.name}' instead`, 'warn');
88
81
  }
89
82
  // Find the 'implicit argument' for aggregate functions called like `some_join.some_field.agg(...args)`
90
83
  // where the full arg list is `(some_field, ...args)`.
@@ -127,12 +120,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
127
120
  this.log(`No matching overload for function ${this.name}(${argExprs
128
121
  .map(e => e.dataType)
129
122
  .join(', ')})`);
130
- return {
131
- dataType: 'unknown',
132
- expressionType: 'scalar',
133
- value: [],
134
- evalSpace: 'constant',
135
- };
123
+ return (0, ast_utils_1.errorFor)('no matching overload');
136
124
  }
137
125
  const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors } = result;
138
126
  // Report errors for expression type mismatch
@@ -171,12 +159,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
171
159
  this.log(`Cannot call function ${this.name}(${argExprs
172
160
  .map(e => e.dataType)
173
161
  .join(', ')}) with source`);
174
- return {
175
- dataType: 'unknown',
176
- expressionType,
177
- value: [],
178
- evalSpace: 'constant',
179
- };
162
+ return (0, ast_utils_1.errorFor)('cannot call with source');
180
163
  }
181
164
  const funcCall = [
182
165
  {
@@ -189,12 +172,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
189
172
  ];
190
173
  if (type.dataType === 'any') {
191
174
  this.log(`Invalid return type ${type.dataType} for function '${this.name}'`);
192
- return {
193
- dataType: 'unknown',
194
- expressionType,
195
- value: [],
196
- evalSpace: 'constant',
197
- };
175
+ return (0, ast_utils_1.errorFor)('invalid return type');
198
176
  }
199
177
  const maxEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(...argExprs.map(e => e.evalSpace));
200
178
  // If the merged eval space of all args is constant, the result is constant.
@@ -240,10 +218,7 @@ function findOverload(func, args) {
240
218
  // does not make sense to limit function calls to not allow nulls, since have
241
219
  // so little control over nullability.
242
220
  arg.dataType === 'null' ||
243
- // TODO I've included this because it means that errors cascade a bit less...
244
- // I think we may want to add an `error` type for nodes generated from errors,
245
- // then make `error` propagate without generating more errors.
246
- arg.dataType === 'unknown';
221
+ arg.dataType === 'error';
247
222
  // Check expression type errors
248
223
  if (paramT.expressionType) {
249
224
  const expressionTypeMatch = (0, malloy_types_1.isExpressionTypeLEQ)(arg.expressionType, paramT.expressionType);
@@ -70,8 +70,20 @@ class ExprGranularTime extends expression_def_1.ExpressionDef {
70
70
  }
71
71
  return tsVal;
72
72
  }
73
- this.log(`Cannot do time truncation on type '${exprVal.dataType}'`);
74
- return (0, ast_utils_1.errorFor)('granularity typecheck');
73
+ if (exprVal.dataType !== 'error') {
74
+ this.log(`Cannot do time truncation on type '${exprVal.dataType}'`);
75
+ }
76
+ const returnType = exprVal.dataType === 'error'
77
+ ? (0, malloy_types_1.isDateUnit)(timeframe)
78
+ ? 'date'
79
+ : 'timestamp'
80
+ : exprVal.dataType;
81
+ return {
82
+ ...exprVal,
83
+ dataType: returnType,
84
+ value: (0, ast_utils_1.errorFor)('granularity typecheck').value,
85
+ evalSpace: 'constant',
86
+ };
75
87
  }
76
88
  apply(fs, op, left) {
77
89
  return this.getRange(fs).apply(fs, op, left);
@@ -37,9 +37,9 @@ class ExprMinus extends expression_def_1.ExpressionDef {
37
37
  const expr = this.expr.getExpression(fs);
38
38
  if (this.typeCheck(this.expr, expr)) {
39
39
  if (expr.value.length > 1) {
40
- return { ...expr, value: ['-(', ...expr.value, ')'] };
40
+ return { ...expr, dataType: 'number', value: ['-(', ...expr.value, ')'] };
41
41
  }
42
- return { ...expr, value: ['-', ...expr.value] };
42
+ return { ...expr, dataType: 'number', value: ['-', ...expr.value] };
43
43
  }
44
44
  return (0, ast_utils_1.errorFor)('negate requires number');
45
45
  }
@@ -54,6 +54,16 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
54
54
  if (from instanceof range_1.Range) {
55
55
  let first = from.first.getExpression(fs);
56
56
  let last = from.last.getExpression(fs);
57
+ const expressionType = (0, malloy_types_1.maxExpressionType)(first.expressionType, last.expressionType);
58
+ const evalSpace = (0, malloy_types_1.mergeEvalSpaces)(first.evalSpace, last.evalSpace);
59
+ if (first.dataType === 'error' || last.dataType === 'error') {
60
+ return {
61
+ dataType: 'number',
62
+ expressionType,
63
+ evalSpace,
64
+ value: (0, ast_utils_1.errorFor)('extract from error').value,
65
+ };
66
+ }
57
67
  if (!(0, malloy_types_1.isTimeFieldType)(first.dataType)) {
58
68
  from.first.log(`Can't extract ${extractTo} from '${first.dataType}'`);
59
69
  return (0, ast_utils_1.errorFor)(`${extractTo} bad type ${first.dataType}`);
@@ -95,8 +105,8 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
95
105
  }
96
106
  return {
97
107
  dataType: 'number',
98
- expressionType: (0, malloy_types_1.maxExpressionType)(first.expressionType, last.expressionType),
99
- evalSpace: (0, malloy_types_1.mergeEvalSpaces)(first.evalSpace, last.evalSpace),
108
+ expressionType,
109
+ evalSpace,
100
110
  value: [
101
111
  {
102
112
  type: 'dialect',
@@ -125,8 +135,16 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
125
135
  ],
126
136
  };
127
137
  }
128
- this.log(`${this.extractText}() requires time type, not '${argV.dataType}'`);
129
- return (0, ast_utils_1.errorFor)(`${this.extractText} bad type ${argV.dataType}`);
138
+ if (argV.dataType !== 'error') {
139
+ this.log(`${this.extractText}() requires time type, not '${argV.dataType}'`);
140
+ }
141
+ return {
142
+ dataType: 'number',
143
+ expressionType: argV.expressionType,
144
+ evalSpace: argV.evalSpace,
145
+ value: (0, ast_utils_1.errorFor)(`${this.extractText} bad type ${argV.dataType}`)
146
+ .value,
147
+ };
130
148
  }
131
149
  }
132
150
  throw this.internalError(`Illegal extraction unit '${this.extractText}'`);
@@ -7,7 +7,7 @@ export declare class ForRange extends ExpressionDef {
7
7
  readonly duration: ExpressionDef;
8
8
  readonly timeframe: Timeframe;
9
9
  elementType: string;
10
- legalChildTypes: import("../../..").TypeDesc[];
10
+ legalChildTypes: import("../../../model").TypeDesc[];
11
11
  constructor(from: ExpressionDef, duration: ExpressionDef, timeframe: Timeframe);
12
12
  apply(fs: FieldSpace, op: string, expr: ExpressionDef): ExprValue;
13
13
  requestExpression(_fs: FieldSpace): undefined;
@@ -23,6 +23,7 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ForRange = void 0;
26
+ const model_1 = require("../../../model");
26
27
  const ast_utils_1 = require("../ast-utils");
27
28
  const fragtype_utils_1 = require("../fragtype-utils");
28
29
  const time_utils_1 = require("../time-utils");
@@ -46,8 +47,15 @@ class ForRange extends expression_def_1.ExpressionDef {
46
47
  }
47
48
  const nV = this.duration.getExpression(fs);
48
49
  if (nV.dataType !== 'number') {
49
- this.log(`FOR duration count must be a number, not '${nV.dataType}'`);
50
- return (0, ast_utils_1.errorFor)('FOR not number');
50
+ if (nV.dataType !== 'error') {
51
+ this.log(`FOR duration count must be a number, not '${nV.dataType}'`);
52
+ }
53
+ return {
54
+ dataType: 'boolean',
55
+ evalSpace: (0, model_1.mergeEvalSpaces)(startV.evalSpace, checkV.evalSpace),
56
+ expressionType: (0, model_1.maxExpressionType)(startV.expressionType, checkV.expressionType),
57
+ value: (0, ast_utils_1.errorFor)('for not number').value,
58
+ };
51
59
  }
52
60
  const units = this.timeframe.text;
53
61
  // If the duration resolution is smaller than date, we have
@@ -30,7 +30,11 @@ const expression_def_1 = require("../types/expression-def");
30
30
  const malloy_element_1 = require("../types/malloy-element");
31
31
  const utils_1 = require("./utils");
32
32
  function typeCoalesce(ev1, ev2) {
33
- return ev1 === undefined || ev1.dataType === 'null' ? ev2 : ev1;
33
+ return ev1 === undefined ||
34
+ ev1.dataType === 'null' ||
35
+ ev1.dataType === 'error'
36
+ ? ev2
37
+ : ev1;
34
38
  }
35
39
  class Pick extends expression_def_1.ExpressionDef {
36
40
  constructor(choices, elsePick) {
@@ -292,14 +292,11 @@ class QuerySpace extends refined_space_1.RefinedSpace {
292
292
  }
293
293
  else {
294
294
  const typeDesc = field.typeDesc();
295
- // Filter out fields whose type is unknown, which means that a totally bad field
296
- // isn't sent to the compiler, where it will wig out. The downside is that in
297
- // subsequent stages of a query, the field is not in the input struct. But since
298
- // the error message says "Cannot define x which has unknown type", it makes sense
299
- // that it wouldn't be "defined" in later stages.
295
+ // Filter out fields whose type is 'error', which means that a totally bad field
296
+ // isn't sent to the compiler, where it will wig out.
300
297
  // TODO Figure out how to make errors generated by `canContain` go in the right place,
301
298
  // maybe by adding a logable element to SpaceFields.
302
- if (typeDesc.dataType !== 'unknown' && this.canContain(typeDesc)) {
299
+ if (typeDesc.dataType !== 'error' && this.canContain(typeDesc)) {
303
300
  fields.push(fieldQueryDef);
304
301
  }
305
302
  }
@@ -45,7 +45,7 @@ class ReferenceField extends space_field_1.SpaceField {
45
45
  if (this.res !== undefined && this.res.found) {
46
46
  return this.res.found.typeDesc();
47
47
  }
48
- return { dataType: 'unknown', expressionType: 'scalar', evalSpace: 'input' };
48
+ return { dataType: 'error', expressionType: 'scalar', evalSpace: 'input' };
49
49
  }
50
50
  }
51
51
  exports.ReferenceField = ReferenceField;
@@ -21,7 +21,7 @@ export declare class FT {
21
21
  * @param right Right type
22
22
  * @param nullOk True if a NULL is an acceptable match
23
23
  */
24
- static typeEq(left: TypeDesc, right: TypeDesc, nullOk?: boolean): boolean;
24
+ static typeEq(left: TypeDesc, right: TypeDesc, nullOk?: boolean, errorOk?: boolean): boolean;
25
25
  /**
26
26
  *
27
27
  * For error messages, returns a comma seperated list of readable names
@@ -59,10 +59,11 @@ class FT {
59
59
  * @param right Right type
60
60
  * @param nullOk True if a NULL is an acceptable match
61
61
  */
62
- static typeEq(left, right, nullOk = false) {
62
+ static typeEq(left, right, nullOk = false, errorOk = true) {
63
63
  const maybeEq = left.dataType === right.dataType;
64
64
  const nullEq = nullOk && (left.dataType === 'null' || right.dataType === 'null');
65
- return maybeEq || nullEq;
65
+ const errorEq = errorOk && (left.dataType === 'error' || right.dataType === 'error');
66
+ return maybeEq || nullEq || errorEq;
66
67
  }
67
68
  /**
68
69
  *
@@ -37,7 +37,7 @@ class ConstantParameter extends has_parameter_1.HasParameter {
37
37
  this.log(`Unexpected expression type '${cVal.dataType}'`);
38
38
  return {
39
39
  value: ['XXX-type-mismatch-error-XXX'],
40
- type: 'string',
40
+ type: 'error',
41
41
  name: this.name,
42
42
  constant: true,
43
43
  };
@@ -66,8 +66,8 @@ class FieldDeclaration extends malloy_element_1.MalloyElement {
66
66
  catch (error) {
67
67
  this.log(`Cannot define '${exprName}', ${error.message}`);
68
68
  return {
69
- name: `error_defining_${exprName}`,
70
- type: 'string',
69
+ name: exprName,
70
+ type: 'error',
71
71
  };
72
72
  }
73
73
  const compressValue = (0, utils_1.compressExpr)(exprValue.value);
@@ -96,17 +96,14 @@ class FieldDeclaration extends malloy_element_1.MalloyElement {
96
96
  }
97
97
  const circularDef = exprFS instanceof DefSpace && exprFS.foundCircle;
98
98
  if (!circularDef) {
99
- if (exprValue.dataType === 'unknown') {
100
- this.log(`Cannot define '${exprName}', value has unknown type`);
101
- }
102
- else {
99
+ if (exprValue.dataType !== 'error') {
103
100
  const badType = fragtype_utils_1.FT.inspect(exprValue);
104
101
  this.log(`Cannot define '${exprName}', unexpected type: ${badType}`);
105
102
  }
106
103
  }
107
104
  return {
108
- name: `error_defining_${exprName}`,
109
- type: 'string',
105
+ name: exprName,
106
+ type: 'error',
110
107
  };
111
108
  }
112
109
  }
@@ -67,7 +67,7 @@ class ExpressionDef extends malloy_element_1.MalloyElement {
67
67
  * @param eVal ...list of expressions that must match legalChildTypes
68
68
  */
69
69
  typeCheck(eNode, eVal) {
70
- if (!fragtype_utils_1.FT.in(eVal, this.legalChildTypes)) {
70
+ if (eVal.dataType !== 'error' && !fragtype_utils_1.FT.in(eVal, this.legalChildTypes)) {
71
71
  eNode.log(`'${this.elementType}' Can't use type ${fragtype_utils_1.FT.inspect(eVal)}`);
72
72
  return false;
73
73
  }
@@ -232,6 +232,9 @@ function nullCompare(left, op, right) {
232
232
  function equality(fs, left, op, right) {
233
233
  const lhs = left.getExpression(fs);
234
234
  const rhs = right.getExpression(fs);
235
+ const err = errorCascade('boolean', lhs, rhs);
236
+ if (err)
237
+ return err;
235
238
  // Unsupported types can be compare with null
236
239
  const checkUnsupport = lhs.dataType === 'unsupported' || rhs.dataType === 'unsupported';
237
240
  if (checkUnsupport) {
@@ -245,7 +248,7 @@ function equality(fs, left, op, right) {
245
248
  }
246
249
  }
247
250
  let value = timeCompare(left, lhs, op, rhs) || (0, utils_1.compose)(lhs.value, op, rhs.value);
248
- if (lhs.dataType !== 'unknown' && rhs.dataType !== 'unknown') {
251
+ if (lhs.dataType !== 'error' && rhs.dataType !== 'error') {
249
252
  switch (op) {
250
253
  case '~':
251
254
  case '!~': {
@@ -285,6 +288,9 @@ function equality(fs, left, op, right) {
285
288
  function compare(fs, left, op, right) {
286
289
  const lhs = left.getExpression(fs);
287
290
  const rhs = right.getExpression(fs);
291
+ const err = errorCascade('boolean', lhs, rhs);
292
+ if (err)
293
+ return err;
288
294
  const expressionType = (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType);
289
295
  const noCompare = unsupportError(left, lhs, right, rhs);
290
296
  if (noCompare) {
@@ -312,6 +318,9 @@ function allAre(oneType, ...values) {
312
318
  function numeric(fs, left, op, right) {
313
319
  const lhs = left.getExpression(fs);
314
320
  const rhs = right.getExpression(fs);
321
+ const err = errorCascade('number', lhs, rhs);
322
+ if (err)
323
+ return err;
315
324
  const noGo = unsupportError(left, lhs, right, rhs);
316
325
  if (noGo) {
317
326
  return noGo;
@@ -335,7 +344,11 @@ function delta(fs, left, op, right) {
335
344
  if (noGo) {
336
345
  return noGo;
337
346
  }
338
- if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType)) {
347
+ const timeLHS = (0, malloy_types_1.isTimeFieldType)(lhs.dataType);
348
+ const err = errorCascade(timeLHS ? 'error' : 'number', lhs, rhs);
349
+ if (err)
350
+ return err;
351
+ if (timeLHS) {
339
352
  let duration = right;
340
353
  if (rhs.dataType !== 'duration') {
341
354
  if ((0, granular_result_1.isGranularResult)(lhs)) {
@@ -385,6 +398,9 @@ function applyBinary(fs, left, op, right) {
385
398
  left.log('Cannot operate with unsupported type');
386
399
  return noGo;
387
400
  }
401
+ const err = errorCascade('number', num, denom);
402
+ if (err)
403
+ return err;
388
404
  if (num.dataType !== 'number') {
389
405
  left.log('Numerator for division must be a number');
390
406
  }
@@ -411,6 +427,16 @@ function applyBinary(fs, left, op, right) {
411
427
  return (0, ast_utils_1.errorFor)('applybinary bad operator');
412
428
  }
413
429
  exports.applyBinary = applyBinary;
430
+ function errorCascade(dataType, ...es) {
431
+ if (es.some(e => e.dataType === 'error')) {
432
+ return {
433
+ dataType,
434
+ expressionType: (0, malloy_types_1.maxOfExpressionTypes)(es.map(e => e.expressionType)),
435
+ value: ["'cascading error'"],
436
+ evalSpace: (0, malloy_types_1.mergeEvalSpaces)(...es.map(e => e.evalSpace)),
437
+ };
438
+ }
439
+ }
414
440
  /**
415
441
  * Return an error if a binary operation includes unsupported types.
416
442
  */
@@ -1,4 +1,5 @@
1
1
  import { DocumentLocation, DocumentReference, ModelDef, Query, SQLBlockStructDef } from '../../../model/malloy_types';
2
+ import { LogSeverity } from '../../parse-log';
2
3
  import { MalloyTranslation } from '../../parse-malloy';
3
4
  import { ModelDataRequest } from '../../translate-response';
4
5
  import { DocumentCompileResult } from './document-compile-result';
@@ -31,7 +32,7 @@ export declare abstract class MalloyElement {
31
32
  private get sourceURL();
32
33
  errorsExist(): boolean;
33
34
  private readonly logged;
34
- log(message: string): void;
35
+ log(message: string, severity?: LogSeverity): void;
35
36
  /**
36
37
  * Mostly for debugging / testing. A string-y version of this object which
37
38
  * is used to ask "are these two AST segments equal". Formatted so that
@@ -151,7 +151,7 @@ class MalloyElement {
151
151
  }
152
152
  return true;
153
153
  }
154
- log(message) {
154
+ log(message, severity = 'error') {
155
155
  if (this.codeLocation) {
156
156
  /*
157
157
  * If this element has a location, then don't report the same
@@ -163,7 +163,7 @@ class MalloyElement {
163
163
  this.logged.add(message);
164
164
  }
165
165
  const trans = this.translator();
166
- const msg = { at: this.location, message };
166
+ const msg = { at: this.location, message, severity };
167
167
  const logTo = trans === null || trans === void 0 ? void 0 : trans.root.logger;
168
168
  if (logTo) {
169
169
  logTo.log(msg);
@@ -297,14 +297,6 @@ class RunList extends ListOf {
297
297
  }
298
298
  executeList(doc) {
299
299
  while (this.execCursor < this.elements.length) {
300
- if (doc.errorsExist()) {
301
- // TODO make a better way to stop cascading errors -- this way means that if there are
302
- // actual different errors in multiple places, we only see the first one. A better way
303
- // might be to make things that have error pass all kinds of typechecks, which prevents
304
- // the real cascade.
305
- // This stops cascading errors
306
- return;
307
- }
308
300
  const el = this.elements[this.execCursor];
309
301
  if (isDocStatement(el)) {
310
302
  const resp = el.execute(doc);
@@ -40,7 +40,7 @@ class AbstractParameter extends SpaceParam {
40
40
  return this.astParam.parameter();
41
41
  }
42
42
  typeDesc() {
43
- const type = this.astParam.type || 'unknown';
43
+ const type = this.astParam.type || 'error';
44
44
  // TODO Not sure whether params are considered "input space". It seems like they
45
45
  // could be input or constant, depending on usage.
46
46
  return { dataType: type, expressionType: 'scalar', evalSpace: 'input' };
@@ -36,6 +36,7 @@ class MalloyParserErrorHandler {
36
36
  const error = {
37
37
  message: msg,
38
38
  at: { url: this.translator.sourceURL, range },
39
+ severity: 'error',
39
40
  };
40
41
  this.messages.log(error);
41
42
  }
@@ -6,7 +6,7 @@ export declare type LogSeverity = 'error' | 'warn' | 'debug';
6
6
  export interface LogMessage {
7
7
  message: string;
8
8
  at?: DocumentLocation;
9
- severity?: LogSeverity;
9
+ severity: LogSeverity;
10
10
  }
11
11
  export interface MessageLogger {
12
12
  log(logMsg: LogMessage): void;
@@ -1,10 +1,10 @@
1
1
  import { CodePointCharStream, CommonTokenStream, ParserRuleContext, Token } from 'antlr4ts';
2
2
  import { ParseTree } from 'antlr4ts/tree';
3
3
  import { DocumentLocation, DocumentPosition, DocumentRange, DocumentReference, ModelDef, NamedModelObject, Query, SQLBlockStructDef, StructDef } from '../model/malloy_types';
4
- import { MessageLog } from './parse-log';
4
+ import { LogMessage, MessageLog } from './parse-log';
5
5
  import { Zone, ZoneData } from './zone';
6
6
  import { ReferenceList } from './reference-list';
7
- import { ASTResponse, CompletionsResponse, DataRequestResponse, ErrorResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse } from './translate-response';
7
+ import { ASTResponse, CompletionsResponse, DataRequestResponse, ProblemResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse } from './translate-response';
8
8
  export declare type StepResponses = DataRequestResponse | ASTResponse | TranslateResponse | ParseResponse | MetadataResponse;
9
9
  /**
10
10
  * A Translation is a series of translation steps. Each step can depend
@@ -28,7 +28,7 @@ export interface MalloyParseRoot {
28
28
  subTranslator: MalloyTranslation;
29
29
  malloyVersion: string;
30
30
  }
31
- interface ParseData extends ErrorResponse, NeedURLData, FinalResponse {
31
+ interface ParseData extends ProblemResponse, NeedURLData, FinalResponse {
32
32
  parse: MalloyParseRoot;
33
33
  }
34
34
  export declare type ParseResponse = Partial<ParseData>;
@@ -116,12 +116,18 @@ export declare abstract class MalloyTranslation {
116
116
  addChild(url: string): void;
117
117
  addReference(reference: DocumentReference): void;
118
118
  referenceAt(position: DocumentPosition): DocumentReference | undefined;
119
- fatalErrors(): FatalResponse;
120
119
  /**
121
- * The error log can grow as progressively deeper questions are asked.
122
- * When returning "errors so far", make a snapshot.
120
+ * This returns a *final* response containing all problems, for when there are
121
+ * errors and the translation needs to stop and report errors. When doing so,
122
+ * it also reports warnings.
123
123
  */
124
- errors(): ErrorResponse;
124
+ fatalResponse(): FatalResponse;
125
+ /**
126
+ * The problem log can grow as progressively deeper questions are asked.
127
+ * When returning "problems so far", make a snapshot.
128
+ */
129
+ problemResponse(): ProblemResponse;
130
+ problems(): LogMessage[];
125
131
  getLineMap(url: string): string[] | undefined;
126
132
  prettyErrors(): string;
127
133
  childRequest(importURL: string): ModelDataRequest;