@malloydata/malloy 0.0.190 → 0.0.191-dev240925232958

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
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.PickWhen = exports.Pick = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
- const ast_utils_1 = require("../ast-utils");
28
27
  const fragtype_utils_1 = require("../fragtype-utils");
29
28
  const expression_def_1 = require("../types/expression-def");
30
29
  const malloy_element_1 = require("../types/malloy-element");
@@ -81,9 +80,10 @@ class Pick extends expression_def_1.ExpressionDef {
81
80
  anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(whenExpr.expressionType, thenExpr.expressionType));
82
81
  anyEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(anyEvalSpace, whenExpr.evalSpace, thenExpr.evalSpace);
83
82
  if (returnType && !fragtype_utils_1.FT.typeEq(returnType, thenExpr, true)) {
84
- const whenType = fragtype_utils_1.FT.inspect(thenExpr);
85
- this.log(`pick type '${whenType}', expected '${returnType.dataType}'[pick-values-must-match]`);
86
- return (0, ast_utils_1.errorFor)('pick when type');
83
+ return this.loggedErrorExpr('pick-type-does-not-match', {
84
+ pickType: thenExpr.dataType,
85
+ returnType: returnType.dataType,
86
+ });
87
87
  }
88
88
  returnType = typeCoalesce(returnType, thenExpr);
89
89
  caseValue.kids.pickWhen.push(whenExpr.value);
@@ -93,9 +93,18 @@ class Pick extends expression_def_1.ExpressionDef {
93
93
  const elseVal = elsePart.getExpression(fs);
94
94
  returnType = typeCoalesce(returnType, elseVal);
95
95
  if (!fragtype_utils_1.FT.typeEq(returnType, elseVal, true)) {
96
- const errSrc = this.elsePick ? 'else' : 'pick default';
97
- this.log(`${errSrc} type '${fragtype_utils_1.FT.inspect(elseVal)}', expected '${returnType.dataType}'[pick-values-must-match]`);
98
- return (0, ast_utils_1.errorFor)('pick else type');
96
+ if (this.elsePick) {
97
+ return this.loggedErrorExpr('pick-else-type-does-not-match', {
98
+ elseType: elseVal.dataType,
99
+ returnType: returnType.dataType,
100
+ });
101
+ }
102
+ else {
103
+ return this.loggedErrorExpr('pick-default-type-does-not-match', {
104
+ defaultType: elseVal.dataType,
105
+ returnType: returnType.dataType,
106
+ });
107
+ }
99
108
  }
100
109
  caseValue.kids.pickElse = elseVal.value;
101
110
  return {
@@ -115,19 +124,16 @@ class Pick extends expression_def_1.ExpressionDef {
115
124
  },
116
125
  };
117
126
  if (this.elsePick === undefined) {
118
- this.log("pick incomplete, missing 'else'");
119
- return (0, ast_utils_1.errorFor)('no value for partial pick');
127
+ return this.loggedErrorExpr('pick-missing-else', "pick incomplete, missing 'else'");
120
128
  }
121
129
  const choiceValues = [];
122
130
  for (const c of this.choices) {
123
131
  if (c.pick === undefined) {
124
- this.log('pick with no value can only be used with apply');
125
- return (0, ast_utils_1.errorFor)('no value for partial pick');
132
+ return this.loggedErrorExpr('pick-missing-value', 'pick with no value can only be used with apply');
126
133
  }
127
134
  const pickWhen = c.when.requestExpression(fs);
128
135
  if (pickWhen === undefined) {
129
- this.log('pick with partial when can only be used with apply');
130
- return (0, ast_utils_1.errorFor)('partial when');
136
+ this.loggedErrorExpr('pick-illegal-partial', 'pick with partial when can only be used with apply');
131
137
  }
132
138
  choiceValues.push({
133
139
  pick: c.pick.getExpression(fs),
@@ -139,13 +145,15 @@ class Pick extends expression_def_1.ExpressionDef {
139
145
  let anyEvalSpace = 'constant';
140
146
  for (const aChoice of choiceValues) {
141
147
  if (!fragtype_utils_1.FT.typeEq(aChoice.when, fragtype_utils_1.FT.boolT)) {
142
- this.log(`when expression must be boolean, not '${fragtype_utils_1.FT.inspect(aChoice.when)}`);
143
- return (0, ast_utils_1.errorFor)('pick when type');
148
+ return this.loggedErrorExpr('pick-when-must-be-boolean', {
149
+ whenType: aChoice.when.dataType,
150
+ });
144
151
  }
145
152
  if (returnType && !fragtype_utils_1.FT.typeEq(returnType, aChoice.pick, true)) {
146
- const whenType = fragtype_utils_1.FT.inspect(aChoice.pick);
147
- this.log(`pick type '${whenType}', expected '${returnType.dataType}'[pick-values-must-match]`);
148
- return (0, ast_utils_1.errorFor)('pick value type');
153
+ return this.loggedErrorExpr('pick-type-does-not-match', {
154
+ pickType: aChoice.pick.dataType,
155
+ returnType: returnType.dataType,
156
+ });
149
157
  }
150
158
  returnType = typeCoalesce(returnType, aChoice.pick);
151
159
  anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(aChoice.pick.expressionType, aChoice.when.expressionType));
@@ -158,8 +166,10 @@ class Pick extends expression_def_1.ExpressionDef {
158
166
  anyEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(anyEvalSpace, defVal.evalSpace);
159
167
  returnType = typeCoalesce(returnType, defVal);
160
168
  if (!fragtype_utils_1.FT.typeEq(returnType, defVal, true)) {
161
- this.elsePick.log(`else type '${fragtype_utils_1.FT.inspect(defVal)}', expected '${returnType.dataType}'[pick-values-must-match]`);
162
- return (0, ast_utils_1.errorFor)('pick value type mismatch');
169
+ return this.elsePick.loggedErrorExpr('pick-else-type-does-not-match', {
170
+ elseType: defVal.dataType,
171
+ returnType: returnType.dataType,
172
+ });
163
173
  }
164
174
  pick.kids.pickElse = defVal.value;
165
175
  return {
@@ -76,7 +76,7 @@ class Range extends expression_def_1.ExpressionDef {
76
76
  return undefined;
77
77
  }
78
78
  getExpression(_fs) {
79
- this.log('A Range is not a value');
79
+ this.logError('range-as-value', 'A Range is not a value');
80
80
  return (0, ast_utils_1.errorFor)('a range is not a value');
81
81
  }
82
82
  }
@@ -39,7 +39,7 @@ class TopBy extends malloy_element_1.MalloyElement {
39
39
  if (this.by instanceof expression_def_1.ExpressionDef) {
40
40
  const byExpr = this.by.getExpression(fs);
41
41
  if (!(0, malloy_types_1.expressionIsAggregate)(byExpr.expressionType)) {
42
- this.log('top by expression must be an aggregate');
42
+ this.logError('top-by-non-aggregate', 'top by expression must be an aggregate');
43
43
  }
44
44
  return { by: 'expression', e: byExpr.value };
45
45
  }
@@ -66,7 +66,7 @@ class DynamicSpace extends static_space_1.StaticSpace {
66
66
  }
67
67
  newEntry(name, logTo, entry) {
68
68
  if (this.entry(name)) {
69
- logTo.log(`Cannot redefine '${name}'`);
69
+ logTo.logError('definition-name-conflict', `Cannot redefine '${name}'`);
70
70
  return;
71
71
  }
72
72
  this.setEntry(name, entry);
@@ -43,13 +43,13 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
43
43
  this.addWild(indexField);
44
44
  }
45
45
  else {
46
- indexField.log('Internal error, not expected in index query');
46
+ indexField.logError('invalid-field-in-index-query', 'Internal error, not expected in index query');
47
47
  }
48
48
  }
49
49
  }
50
50
  getPipeSegment(refineIndex) {
51
51
  if (refineIndex) {
52
- this.log('index query operations cannot be refined');
52
+ this.logError('refinement-of-index-segment', 'index query operations cannot be refined');
53
53
  return { type: 'index', indexFields: [] };
54
54
  }
55
55
  const indexFields = [];
@@ -65,7 +65,7 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
65
65
  const fieldRef = field.fieldRef;
66
66
  const check = fieldRef.getField(this.exprSpace);
67
67
  if (check.error) {
68
- fieldRef.log(check.error);
68
+ fieldRef.logError(check.error.code, check.error.message);
69
69
  }
70
70
  else {
71
71
  indexFields.push(fieldRef.refToField);
@@ -91,12 +91,12 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
91
91
  current = ent.fieldSpace;
92
92
  }
93
93
  else {
94
- pathPart.log(`Field '${part}' does not contain rows and cannot be expanded with '*'`);
94
+ pathPart.logError('invalid-wildcard-source', `Field '${part}' does not contain rows and cannot be expanded with '*'`);
95
95
  return;
96
96
  }
97
97
  }
98
98
  else {
99
- pathPart.log(`No such field as '${part}'`);
99
+ pathPart.logError('wildcard-source-not-found', `No such field as '${part}'`);
100
100
  return;
101
101
  }
102
102
  }
@@ -116,7 +116,7 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
116
116
  ]);
117
117
  if (this.entry(indexName)) {
118
118
  const conflict = (_a = this.expandedWild[indexName]) === null || _a === void 0 ? void 0 : _a.join('.');
119
- wild.log(`Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
119
+ wild.logError('name-conflict-in-wildcard-expansion', `Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
120
120
  }
121
121
  else {
122
122
  const eType = entry.typeDesc();
@@ -29,20 +29,31 @@ class ParameterSpace {
29
29
  const name = symbol[0];
30
30
  if (name === undefined) {
31
31
  return {
32
- error: 'Invalid reference',
32
+ error: {
33
+ message: 'Invalid reference',
34
+ code: 'invalid-parameter-reference',
35
+ },
33
36
  found: undefined,
34
37
  };
35
38
  }
36
39
  const entry = this.entry(name.refString);
37
40
  if (entry === undefined) {
38
41
  return {
39
- error: `\`${name}\` is not defined`,
42
+ error: {
43
+ message: `\`${name}\` is not defined`,
44
+ code: 'parameter-not-found',
45
+ },
40
46
  found: undefined,
41
47
  };
42
48
  }
43
49
  if (symbol.length > 1) {
44
50
  return {
45
- error: `\`${name}\` cannot contain a \`${symbol.slice(1).join('.')}\``,
51
+ error: {
52
+ message: `\`${name}\` cannot contain a \`${symbol
53
+ .slice(1)
54
+ .join('.')}\``,
55
+ code: 'invalid-parameter-reference',
56
+ },
46
57
  found: undefined,
47
58
  };
48
59
  }
@@ -40,7 +40,7 @@ class ProjectFieldSpace extends query_spaces_1.QuerySpace {
40
40
  // rather than the whole query.
41
41
  if ((0, malloy_types_1.expressionInvolvesAggregate)(typeDesc.expressionType) &&
42
42
  (0, malloy_types_1.expressionIsAnalytic)(typeDesc.expressionType)) {
43
- this.log('Cannot add aggregate analyics to project');
43
+ this.logError('aggregate-analytic-in-select', 'Cannot add aggregate analyics to select');
44
44
  return false;
45
45
  }
46
46
  return true;
@@ -5,6 +5,7 @@ import { WildcardFieldReference } from '../query-items/field-references';
5
5
  import { RefinedSpace } from './refined-space';
6
6
  import { LookupResult } from '../types/lookup-result';
7
7
  import { QueryInputSpace } from './query-input-space';
8
+ import { LogMessageOptions, MessageCode, MessageParameterType } from '../../parse-log';
8
9
  /**
9
10
  * The output space of a query operation. It is not named "QueryOutputSpace"
10
11
  * because this is the namespace of the Query which is a layer of an output and
@@ -20,7 +21,7 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
20
21
  expandedWild: Record<string, string[]>;
21
22
  constructor(queryInputSpace: FieldSpace, refineThis: model.PipeSegment | undefined, nestParent: QueryOperationSpace | undefined, astEl: MalloyElement);
22
23
  abstract addRefineFromFields(refineThis: model.PipeSegment): void;
23
- log(s: string): void;
24
+ logError<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): T;
24
25
  inputSpace(): QueryInputSpace;
25
26
  outputSpace(): QueryOperationSpace;
26
27
  protected addWild(wild: WildcardFieldReference): void;
@@ -72,10 +72,11 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
72
72
  if (refineThis)
73
73
  this.addRefineFromFields(refineThis);
74
74
  }
75
- log(s) {
75
+ logError(code, parameters, options) {
76
76
  if (this.astEl) {
77
- this.astEl.log(s);
77
+ this.astEl.logError(code, parameters, options);
78
78
  }
79
+ return code;
79
80
  }
80
81
  inputSpace() {
81
82
  return this.exprSpace;
@@ -98,12 +99,12 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
98
99
  current = ent.fieldSpace;
99
100
  }
100
101
  else {
101
- pathPart.log(`Field '${part}' does not contain rows and cannot be expanded with '*'`);
102
+ pathPart.logError('invalid-wildcard-source', `Field '${part}' does not contain rows and cannot be expanded with '*'`);
102
103
  return;
103
104
  }
104
105
  }
105
106
  else {
106
- pathPart.log(`No such field as '${part}'`);
107
+ pathPart.logError('wildcard-source-not-defined', `No such field as '${part}'`);
107
108
  return;
108
109
  }
109
110
  }
@@ -119,7 +120,7 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
119
120
  }
120
121
  if (this.entry(name)) {
121
122
  const conflict = (_a = this.expandedWild[name]) === null || _a === void 0 ? void 0 : _a.join('.');
122
- wild.log(`Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
123
+ wild.logError('name-conflict-in-wildcard-expansion', `Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
123
124
  }
124
125
  else {
125
126
  const eType = entry.typeDesc();
@@ -217,7 +218,7 @@ class QuerySpace extends QueryOperationSpace {
217
218
  getPipeSegment(refineFrom) {
218
219
  if (this.segmentType === 'index') {
219
220
  // come coding error made this "impossible" thing happen
220
- this.log('internal error generating index segment from non index query');
221
+ this.logError('unexpected-index-segment', 'internal error generating index segment from non index query');
221
222
  return { type: 'reduce', queryFields: [] };
222
223
  }
223
224
  if (refineFrom === null || refineFrom === void 0 ? void 0 : refineFrom.extendSource) {
@@ -43,7 +43,7 @@ class ReferenceField extends space_field_1.SpaceField {
43
43
  if (!this.queryFieldDef) {
44
44
  const check = this.fieldRef.getField(fs);
45
45
  if (check.error) {
46
- this.fieldRef.log(check.error);
46
+ this.fieldRef.logError(check.error.code, check.error.message);
47
47
  }
48
48
  // TODO investigate removing 'fieldref' as a type, as it obscures the
49
49
  // actual type of the field and is redundant with the slightly
@@ -40,10 +40,10 @@ class RefinedSpace extends dynamic_space_1.DynamicSpace {
40
40
  const existing = oldMap.find(([symb]) => symb === name.refString);
41
41
  if (existing === undefined) {
42
42
  if (parameters === null || parameters === void 0 ? void 0 : parameters.entry(name.refString)) {
43
- name.log(`Illegal \`${choose.edit}:\` of parameter`);
43
+ name.logError(`${choose.edit}-parameter`, `Illegal \`${choose.edit}:\` of parameter`);
44
44
  }
45
45
  else {
46
- name.log(`\`${name.refString}\` is not defined`);
46
+ name.logError('field-list-edit-not-found', `\`${name.refString}\` is not defined`);
47
47
  }
48
48
  }
49
49
  }
@@ -64,7 +64,7 @@ class RefinedSpace extends dynamic_space_1.DynamicSpace {
64
64
  me.makeEntry(this);
65
65
  }
66
66
  else {
67
- me.log(`Internal error, ${me.elementType} not expected in this context`);
67
+ me.logError('unexpected-element-type', `Internal error, ${me.elementType} not expected in this context`);
68
68
  }
69
69
  }
70
70
  }
@@ -96,7 +96,13 @@ class StaticSpace {
96
96
  const rest = path.slice(1);
97
97
  const found = this.entry(head.refString);
98
98
  if (!found) {
99
- return { error: `'${head}' is not defined`, found };
99
+ return {
100
+ error: {
101
+ message: `'${head}' is not defined`,
102
+ code: 'field-not-found',
103
+ },
104
+ found,
105
+ };
100
106
  }
101
107
  if (found instanceof space_field_1.SpaceField) {
102
108
  const definition = found.fieldDef();
@@ -133,7 +139,10 @@ class StaticSpace {
133
139
  }
134
140
  }
135
141
  return {
136
- error: `'${head}' cannot contain a '${rest[0]}'`,
142
+ error: {
143
+ message: `'${head}' cannot contain a '${rest[0]}'`,
144
+ code: 'invalid-property-access-in-field-reference',
145
+ },
137
146
  found: undefined,
138
147
  };
139
148
  }
@@ -46,7 +46,7 @@ class HasParameter extends malloy_element_1.MalloyElement {
46
46
  this.type !== constant.dataType &&
47
47
  constant.dataType !== 'null' &&
48
48
  constant.dataType !== 'error') {
49
- this.default.log(`Default value for parameter does not match declared type \`${this.type}\``);
49
+ this.default.logError('parameter-default-does-not-match-declared-type', `Default value for parameter does not match declared type \`${this.type}\``);
50
50
  }
51
51
  if (constant.dataType === 'null') {
52
52
  if (this.type) {
@@ -57,7 +57,7 @@ class HasParameter extends malloy_element_1.MalloyElement {
57
57
  };
58
58
  }
59
59
  else {
60
- this.default.log('Default value cannot have type `null` unless parameter type is also specified');
60
+ this.default.logError('parameter-null-default-without-declared-type', 'Default value cannot have type `null` unless parameter type is also specified');
61
61
  return {
62
62
  value: constant.value,
63
63
  name: this.name,
@@ -66,7 +66,7 @@ class HasParameter extends malloy_element_1.MalloyElement {
66
66
  }
67
67
  }
68
68
  if (!(0, malloy_types_1.isCastType)(constant.dataType) && constant.dataType !== 'error') {
69
- this.default.log(`Default value cannot have type \`${constant.dataType}\``);
69
+ this.default.logError('parameter-illegal-default-type', `Default value cannot have type \`${constant.dataType}\``);
70
70
  return {
71
71
  value: constant.value,
72
72
  name: this.name,
@@ -80,7 +80,7 @@ class HasParameter extends malloy_element_1.MalloyElement {
80
80
  };
81
81
  }
82
82
  if (this.type === undefined) {
83
- this.log('Parameter must have default value or declared type');
83
+ this.logError('parameter-missing-default-or-type', 'Parameter must have default value or declared type');
84
84
  }
85
85
  return {
86
86
  value: null,
@@ -43,7 +43,7 @@ class IndexBuilder {
43
43
  }
44
44
  else if (qp instanceof limit_1.Limit) {
45
45
  if (this.limit) {
46
- this.limit.log('Ignored, too many limit: statements');
46
+ this.limit.logError('index-limit-already-specified', 'Ignored, too many limit: statements');
47
47
  }
48
48
  this.limit = qp;
49
49
  }
@@ -51,7 +51,7 @@ class IndexBuilder {
51
51
  this.resultFS.pushFields(...qp.fields.list);
52
52
  if (qp.weightBy) {
53
53
  if (this.indexOn) {
54
- this.indexOn.log('Ignoring previous BY');
54
+ this.indexOn.logError('index-by-already-specified', 'Ignoring previous BY');
55
55
  }
56
56
  this.indexOn = qp.weightBy;
57
57
  }
@@ -60,12 +60,12 @@ class IndexBuilder {
60
60
  this.sample = qp.sampling();
61
61
  }
62
62
  else {
63
- qp.log('Not legal in an index query operation');
63
+ qp.logError('illegal-operation-for-index', 'Not legal in an index query operation');
64
64
  }
65
65
  }
66
66
  finalize(from) {
67
67
  if (from && !(0, malloy_types_1.isIndexSegment)(from) && !(0, malloy_types_1.isPartialSegment)(from)) {
68
- this.resultFS.log(`Can't refine index with ${from.type}`);
68
+ this.resultFS.logError('refinement-of-index-segment', `Can't refine index with ${from.type}`);
69
69
  return error_factory_1.ErrorFactory.indexSegment;
70
70
  }
71
71
  const indexSegment = this.resultFS.getPipeSegment(from);
@@ -37,7 +37,7 @@ class ProjectBuilder extends reduce_builder_1.QuerySegmentBuilder {
37
37
  }
38
38
  execute(qp) {
39
39
  if (qp.elementType === 'having' || qp instanceof group_by_1.GroupBy) {
40
- qp.log('Illegal statement in a select query operation');
40
+ qp.logError('illegal-operation-in-select-segment', 'Illegal statement in a select query operation');
41
41
  }
42
42
  else {
43
43
  super.execute(qp);
@@ -50,7 +50,7 @@ class ProjectBuilder extends reduce_builder_1.QuerySegmentBuilder {
50
50
  from = fromSeg;
51
51
  }
52
52
  else {
53
- this.resultFS.log(`Can't refine select with ${fromSeg.type}`);
53
+ this.resultFS.logError('incompatible-segment-for-select-refinement', `Can't refine select with ${fromSeg.type}`);
54
54
  return error_factory_1.ErrorFactory.projectSegment;
55
55
  }
56
56
  }
@@ -49,14 +49,14 @@ class QuerySegmentBuilder {
49
49
  }
50
50
  else if (qp instanceof top_1.Top) {
51
51
  if (this.limit) {
52
- qp.log('Query operation already limited');
52
+ qp.logError('limit-already-specified', 'Query operation already limited');
53
53
  }
54
54
  else {
55
55
  this.limit = qp.limit;
56
56
  }
57
57
  if (qp.by) {
58
58
  if (this.order) {
59
- qp.log('Query operation is already sorted');
59
+ qp.logError('ordering-already-specified', 'Query operation is already sorted');
60
60
  }
61
61
  else {
62
62
  this.order = qp;
@@ -65,7 +65,7 @@ class QuerySegmentBuilder {
65
65
  }
66
66
  else if (qp instanceof limit_1.Limit) {
67
67
  if (this.limit) {
68
- qp.log('Query operation already limited');
68
+ qp.logError('limit-already-specified', 'Query operation already limited');
69
69
  }
70
70
  else {
71
71
  this.limit = qp.limit;
@@ -73,7 +73,7 @@ class QuerySegmentBuilder {
73
73
  }
74
74
  else if (qp instanceof ordering_1.Ordering) {
75
75
  if (this.order) {
76
- qp.log('Query operation already sorted');
76
+ qp.logError('ordering-already-specified', 'Query operation already sorted');
77
77
  }
78
78
  else {
79
79
  this.order = qp;
@@ -130,7 +130,7 @@ class ReduceBuilder extends QuerySegmentBuilder {
130
130
  from = fromSeg;
131
131
  }
132
132
  else {
133
- this.resultFS.log(`Can't refine reduce with ${fromSeg.type}`);
133
+ this.resultFS.logError('incompatible-segment-for-reduce-refinement', `Can't refine reduce with ${fromSeg.type}`);
134
134
  return error_factory_1.ErrorFactory.reduceSegment;
135
135
  }
136
136
  }
@@ -37,7 +37,7 @@ class AnonymousQuery extends malloy_element_1.MalloyElement {
37
37
  execute(doc) {
38
38
  const queryObj = this.queryExpr.getQuery();
39
39
  if (!queryObj) {
40
- this.queryExpr.sqLog('Cannot run this object as a query');
40
+ this.queryExpr.sqLog('non-query-used-as-query', 'Cannot run this object as a query');
41
41
  return;
42
42
  }
43
43
  const modelQuery = { ...queryObj.query() };
@@ -50,7 +50,7 @@ class QueryReference extends malloy_element_1.MalloyElement {
50
50
  };
51
51
  };
52
52
  if (!query) {
53
- this.log(`Reference to undefined query '${this.name.refString}'`);
53
+ this.logError('query-reference-not-found', `Reference to undefined query '${this.name.refString}'`);
54
54
  return oops();
55
55
  }
56
56
  if (query.type === 'query') {
@@ -69,7 +69,7 @@ class QueryReference extends malloy_element_1.MalloyElement {
69
69
  inputStruct,
70
70
  };
71
71
  }
72
- this.log(`Illegal reference to '${this.name}', query expected`);
72
+ this.logError('non-query-used-as-query', `Illegal reference to '${this.name}', query expected`);
73
73
  return oops();
74
74
  }
75
75
  query() {
@@ -67,7 +67,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
67
67
  exprValue = this.expr.getExpression(fs);
68
68
  }
69
69
  catch (error) {
70
- this.log(`Cannot define '${exprName}', ${error.message}`);
70
+ this.logError('failed-field-definition', `Cannot define '${exprName}', ${error.message}`);
71
71
  return {
72
72
  name: exprName,
73
73
  type: 'error',
@@ -75,7 +75,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
75
75
  }
76
76
  let retType = exprValue.dataType;
77
77
  if (retType === 'null') {
78
- this.expr.log('null value defaults to type number, use "null::TYPE" to specify correct type', 'warn');
78
+ this.expr.logWarning('null-typed-field-definition', 'null value defaults to type number, use "null::TYPE" to specify correct type');
79
79
  retType = 'number';
80
80
  }
81
81
  if ((0, malloy_types_1.isAtomicFieldType)(retType) && retType !== 'error') {
@@ -105,7 +105,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
105
105
  if (!circularDef) {
106
106
  if (exprValue.dataType !== 'error') {
107
107
  const badType = fragtype_utils_1.FT.inspect(exprValue);
108
- this.log(`Cannot define '${exprName}', unexpected type: ${badType}`);
108
+ this.logError('invalid-type-for-field-definition', `Cannot define '${exprName}', unexpected type: ${badType}`);
109
109
  }
110
110
  }
111
111
  return {
@@ -214,7 +214,10 @@ class DefSpace {
214
214
  if (symbol[0] && symbol[0].refString === this.circular.defineName) {
215
215
  this.foundCircle = true;
216
216
  return {
217
- error: `Circular reference to '${this.circular.defineName}' in definition`,
217
+ error: {
218
+ message: `Circular reference to '${this.circular.defineName}' in definition`,
219
+ code: 'circular-reference-in-field-definition',
220
+ },
218
221
  found: undefined,
219
222
  };
220
223
  }
@@ -37,7 +37,7 @@ class FieldReference extends malloy_element_1.ListOf {
37
37
  makeEntry(fs) {
38
38
  const refName = this.outputName;
39
39
  if (fs.entry(refName)) {
40
- this.log(`Output already has a field named '${refName}'`);
40
+ this.logError('output-name-conflict', `Output already has a field named '${refName}'`);
41
41
  }
42
42
  else {
43
43
  // In a QuerySpace, this needs to be able to find the thing to which it refers