@malloydata/malloy 0.0.415 → 0.0.417

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.
@@ -216,6 +216,8 @@ import { GroupedByStatementContext } from "./MalloyParser";
216
216
  import { OrderByStatementContext } from "./MalloyParser";
217
217
  import { OrderingContext } from "./MalloyParser";
218
218
  import { OrderBySpecContext } from "./MalloyParser";
219
+ import { PossibleBadPathContext } from "./MalloyParser";
220
+ import { BadWordContext } from "./MalloyParser";
219
221
  import { LimitStatementContext } from "./MalloyParser";
220
222
  import { BySpecContext } from "./MalloyParser";
221
223
  import { TopStatementContext } from "./MalloyParser";
@@ -2632,6 +2634,26 @@ export interface MalloyParserListener extends ParseTreeListener {
2632
2634
  * @param ctx the parse tree
2633
2635
  */
2634
2636
  exitOrderBySpec?: (ctx: OrderBySpecContext) => void;
2637
+ /**
2638
+ * Enter a parse tree produced by `MalloyParser.possibleBadPath`.
2639
+ * @param ctx the parse tree
2640
+ */
2641
+ enterPossibleBadPath?: (ctx: PossibleBadPathContext) => void;
2642
+ /**
2643
+ * Exit a parse tree produced by `MalloyParser.possibleBadPath`.
2644
+ * @param ctx the parse tree
2645
+ */
2646
+ exitPossibleBadPath?: (ctx: PossibleBadPathContext) => void;
2647
+ /**
2648
+ * Enter a parse tree produced by `MalloyParser.badWord`.
2649
+ * @param ctx the parse tree
2650
+ */
2651
+ enterBadWord?: (ctx: BadWordContext) => void;
2652
+ /**
2653
+ * Exit a parse tree produced by `MalloyParser.badWord`.
2654
+ * @param ctx the parse tree
2655
+ */
2656
+ exitBadWord?: (ctx: BadWordContext) => void;
2635
2657
  /**
2636
2658
  * Enter a parse tree produced by `MalloyParser.limitStatement`.
2637
2659
  * @param ctx the parse tree
@@ -216,6 +216,8 @@ import { GroupedByStatementContext } from "./MalloyParser";
216
216
  import { OrderByStatementContext } from "./MalloyParser";
217
217
  import { OrderingContext } from "./MalloyParser";
218
218
  import { OrderBySpecContext } from "./MalloyParser";
219
+ import { PossibleBadPathContext } from "./MalloyParser";
220
+ import { BadWordContext } from "./MalloyParser";
219
221
  import { LimitStatementContext } from "./MalloyParser";
220
222
  import { BySpecContext } from "./MalloyParser";
221
223
  import { TopStatementContext } from "./MalloyParser";
@@ -1676,6 +1678,18 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
1676
1678
  * @return the visitor result
1677
1679
  */
1678
1680
  visitOrderBySpec?: (ctx: OrderBySpecContext) => Result;
1681
+ /**
1682
+ * Visit a parse tree produced by `MalloyParser.possibleBadPath`.
1683
+ * @param ctx the parse tree
1684
+ * @return the visitor result
1685
+ */
1686
+ visitPossibleBadPath?: (ctx: PossibleBadPathContext) => Result;
1687
+ /**
1688
+ * Visit a parse tree produced by `MalloyParser.badWord`.
1689
+ * @param ctx the parse tree
1690
+ * @return the visitor result
1691
+ */
1692
+ visitBadWord?: (ctx: BadWordContext) => Result;
1679
1693
  /**
1680
1694
  * Visit a parse tree produced by `MalloyParser.limitStatement`.
1681
1695
  * @param ctx the parse tree
@@ -0,0 +1 @@
1
+ export declare const KEYWORD_DISPLAY_NAMES: Record<string, string>;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.KEYWORD_DISPLAY_NAMES = void 0;
8
+ // GENERATED by src/lang/grammar/build_token_names.js from the
9
+ // KEYWORDS-BEGIN..KEYWORDS-END section of MalloyLexer.g4. Do not edit by hand.
10
+ // Maps a keyword token's symbolic name to the spelling a user types (including
11
+ // the trailing colon for statement keywords), for parser error messages.
12
+ // Run `npm run codegen` to regenerate.
13
+ exports.KEYWORD_DISPLAY_NAMES = {
14
+ ACCEPT: "accept:",
15
+ AGGREGATE: "aggregate:",
16
+ ALL: "all",
17
+ AND: "and",
18
+ AS: "as",
19
+ ASC: "asc",
20
+ AVG: "avg",
21
+ BOOLEAN: "boolean",
22
+ BY: "by",
23
+ CALCULATE: "calculate:",
24
+ CALCULATION: "calculation:",
25
+ CASE: "case",
26
+ CAST: "cast",
27
+ COMPOSE: "compose",
28
+ CONNECTION: "connection:",
29
+ COUNT: "count",
30
+ DATE: "date",
31
+ DAY: "day",
32
+ DECLARE: "declare:",
33
+ DESC: "desc",
34
+ DIMENSION: "dimension:",
35
+ DISTINCT: "distinct",
36
+ DRILL: "drill:",
37
+ ELSE: "else",
38
+ END: "end",
39
+ EXCEPT: "except:",
40
+ EXCLUDE: "exclude",
41
+ EXPORT: "export",
42
+ EXTEND: "extend",
43
+ EXTENDQ: "extend:",
44
+ FALSE: "false",
45
+ FILTER: "filter",
46
+ FOR: "for",
47
+ FROM: "from",
48
+ FULL: "full",
49
+ GIVEN: "given:",
50
+ GROUPED_BY: "grouped_by:",
51
+ GROUP_BY: "group_by:",
52
+ HAS: "has",
53
+ HAVING: "having:",
54
+ HOUR: "hour",
55
+ IMPORT: "import",
56
+ IN: "in",
57
+ INCLUDE: "include",
58
+ INDEX: "index:",
59
+ INNER: "inner",
60
+ INTERNAL: "internal:",
61
+ INTERNAL_KW: "internal",
62
+ IS: "is",
63
+ JOIN_CROSS: "join_cross:",
64
+ JOIN_MANY: "join_many:",
65
+ JOIN_ONE: "join_one:",
66
+ JSON: "json",
67
+ LEFT: "left",
68
+ LIKE: "like",
69
+ LIMIT: "limit:",
70
+ MAX: "max",
71
+ MEASURE: "measure:",
72
+ MIN: "min",
73
+ MINUTE: "minute",
74
+ MONTH: "month",
75
+ NEST: "nest:",
76
+ NOT: "not",
77
+ NOW: "now",
78
+ NULL: "null",
79
+ NUMBER: "number",
80
+ ON: "on",
81
+ OR: "or",
82
+ ORDER_BY: "order_by:",
83
+ PARTITION_BY: "partition_by:",
84
+ PICK: "pick",
85
+ PRIMARY_KEY: "primary_key:",
86
+ PRIVATE: "private:",
87
+ PRIVATE_KW: "private",
88
+ PUBLIC: "public:",
89
+ PUBLIC_KW: "public",
90
+ QUARTER: "quarter",
91
+ QUERY: "query:",
92
+ RENAME: "rename:",
93
+ RIGHT: "right",
94
+ RUN: "run:",
95
+ SAMPLE: "sample:",
96
+ SECOND: "second",
97
+ SELECT: "select:",
98
+ SOURCE: "source:",
99
+ SOURCE_KW: "source",
100
+ SQL: "sql",
101
+ STRING: "string",
102
+ SUM: "sum",
103
+ TABLE: "table",
104
+ THEN: "then",
105
+ THIS: "this",
106
+ TIMESTAMP: "timestamp",
107
+ TIMESTAMPTZ: "timestamptz",
108
+ TIMEZONE: "timezone:",
109
+ TO: "to",
110
+ TOP: "top:",
111
+ TRUE: "true",
112
+ TYPE: "type:",
113
+ VIEW: "view:",
114
+ VIRTUAL: "virtual",
115
+ WEEK: "week",
116
+ WHEN: "when",
117
+ WHERE: "where:",
118
+ WITH: "with",
119
+ YEAR: "year",
120
+ };
121
+ //# sourceMappingURL=keyword-display-names.js.map
@@ -207,7 +207,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
207
207
  visitExprString(pcx: parse.ExprStringContext): ast.ExprString;
208
208
  visitRawString(pcx: parse.RawStringContext): ast.ExprString;
209
209
  visitExprRegex(pcx: parse.ExprRegexContext): ast.ExprRegEx;
210
- visitExprNow(_pcx: parse.ExprNowContext): ast.ExprNow;
210
+ visitExprNow(pcx: parse.ExprNowContext): ast.ExprNow;
211
211
  visitExprNumber(pcx: parse.ExprNumberContext): ast.ExprNumber;
212
212
  visitExprFieldPath(pcx: parse.ExprFieldPathContext): ast.ExprIdReference;
213
213
  visitExprGivenRef(pcx: parse.ExprGivenRefContext): ast.GivenReference;
@@ -979,11 +979,33 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
979
979
  if (ncx) {
980
980
  return new ast.OrderBy(this.getNumber(ncx), dir);
981
981
  }
982
- const fieldCx = pcx.fieldName();
983
- if (fieldCx) {
984
- return new ast.OrderBy(this.getFieldName(fieldCx), dir);
985
- }
986
- throw this.internalError(pcx, "can't parse order_by specification");
982
+ const pathCx = pcx.possibleBadPath();
983
+ if (!pathCx) {
984
+ throw this.internalError(pcx, "can't parse order_by specification");
985
+ }
986
+ const words = pathCx.badWord();
987
+ const firstField = words[0].fieldName();
988
+ if (words.length === 1 && firstField) {
989
+ // A lone ordinary identifier -- the normal, valid order_by target.
990
+ return new ast.OrderBy(this.getFieldName(firstField), dir);
991
+ }
992
+ // Otherwise illegal: a dotted path, and/or a reserved-word segment that
993
+ // would have to be quoted. Logging an error here prevents translation, so
994
+ // the throwaway OrderBy below is never evaluated -- it only satisfies the
995
+ // visitor's contract.
996
+ const last = words[words.length - 1];
997
+ const lastFieldCx = last.fieldName();
998
+ const lastName = lastFieldCx ? lastFieldCx.text : '`' + last.text + '`';
999
+ const message = words.length > 1
1000
+ ? `order_by takes the name of a field in the query output, not a path ('${pathCx.text}'). ` +
1001
+ `To order by '${last.text}', make it an output field and order by its name` +
1002
+ (lastFieldCx === undefined
1003
+ ? `, quoting it because '${last.text}' is a reserved word: ${lastName}`
1004
+ : `: ${lastName}`) +
1005
+ '.'
1006
+ : `'${last.text}' is a reserved word, so to order by it you must quote it: ${lastName}`;
1007
+ this.contextError(pathCx, 'order-by-bad-reference', message);
1008
+ return new ast.OrderBy(new ast.FieldName('internal_error'), dir);
987
1009
  }
988
1010
  visitOrdering(pcx) {
989
1011
  const orderList = pcx.orderBySpec().map(o => this.visitOrderBySpec(o));
@@ -1135,7 +1157,11 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1135
1157
  const malloyRegex = pcx.HACKY_REGEX().text;
1136
1158
  return new ast.ExprRegEx(malloyRegex.slice(2, -1));
1137
1159
  }
1138
- visitExprNow(_pcx) {
1160
+ visitExprNow(pcx) {
1161
+ if (pcx.OPAREN()) {
1162
+ // `now` is a value, not a function; accept `now()`, warn, compile as `now`.
1163
+ this.contextError(pcx, 'now-is-not-a-function', "'now' is a value, not a function; the parentheses are unnecessary. Write 'now'.", { severity: 'warn' });
1164
+ }
1139
1165
  return new ast.ExprNow();
1140
1166
  }
1141
1167
  visitExprNumber(pcx) {
@@ -368,24 +368,28 @@ class MalloyToQuery extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor
368
368
  });
369
369
  }
370
370
  getOrderByStatement(obcx) {
371
+ var _a, _b;
371
372
  const specs = obcx.ordering().orderBySpec();
372
373
  const orders = [];
373
374
  for (const spec of specs) {
374
375
  if (spec.INTEGER_LITERAL()) {
375
376
  this.notAllowed(spec, 'Indexed order by statements');
377
+ continue;
376
378
  }
377
- else if (spec.fieldName()) {
378
- const fieldName = (0, parse_utils_1.getId)(spec.fieldName());
379
- const direction = spec.ASC() ? 'asc' : spec.DESC() ? 'desc' : undefined;
380
- orders.push({
381
- kind: 'order_by',
382
- direction,
383
- field_reference: { name: fieldName },
384
- });
385
- }
386
- else {
379
+ // A valid order_by target is a single ordinary name; a dotted path or a
380
+ // bare reserved word is not representable as a stable query.
381
+ const words = (_b = (_a = spec.possibleBadPath()) === null || _a === void 0 ? void 0 : _a.badWord()) !== null && _b !== void 0 ? _b : [];
382
+ const firstField = words.length === 1 ? words[0].fieldName() : undefined;
383
+ if (!firstField) {
387
384
  return null;
388
385
  }
386
+ const fieldName = (0, parse_utils_1.getId)(firstField);
387
+ const direction = spec.ASC() ? 'asc' : spec.DESC() ? 'desc' : undefined;
388
+ orders.push({
389
+ kind: 'order_by',
390
+ direction,
391
+ field_reference: { name: fieldName },
392
+ });
389
393
  }
390
394
  return orders;
391
395
  }
@@ -222,6 +222,8 @@ type MessageParameterTypes = {
222
222
  'aggregate-in-where': string;
223
223
  'order-by-not-found-in-output': string;
224
224
  'order-by-analytic': string;
225
+ 'order-by-bad-reference': string;
226
+ 'now-is-not-a-function': string;
225
227
  'illegal-index-operation': string;
226
228
  'illegal-project-operation': string;
227
229
  'illegal-grouping-operation': string;
@@ -1,12 +1,19 @@
1
+ import type { InputMismatchException, NoViableAltException, Parser } from 'antlr4ts';
1
2
  import { DefaultErrorStrategy } from 'antlr4ts';
2
3
  /**
3
- * Custom error strategy for the Malloy Parser.
4
+ * Overrides the DefaultErrorStrategy methods that paste the parser's
5
+ * expected-token set into the message: tokens are named the way the user types
6
+ * them (via describeExpected) and the set is dropped once too large to be a hint.
4
7
  *
5
- * This class does not currently override default ANTLR error handling.
8
+ * Each path also checks reservedNameMessage first, so a reserved word used where
9
+ * a name was expected (`group_by: year`) says "quote it".
6
10
  *
7
- * For more details, read the documentation in DefaultErrorStrategy.d.ts
8
- * or reference the superclass at:
9
- * https://github.com/tunnelvisionlabs/antlr4ts/blob/master/src/DefaultErrorStrategy.ts
11
+ * Fallback only MalloyParserErrorListener's custom-error cases run first and
12
+ * override these when they match.
10
13
  */
11
14
  export declare class MalloyErrorStrategy extends DefaultErrorStrategy {
15
+ protected reportInputMismatch(recognizer: Parser, e: InputMismatchException): void;
16
+ protected reportUnwantedToken(recognizer: Parser): void;
17
+ protected reportMissingToken(recognizer: Parser): void;
18
+ protected reportNoViableAlternative(recognizer: Parser, e: NoViableAltException): void;
12
19
  }
@@ -6,16 +6,85 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.MalloyErrorStrategy = void 0;
8
8
  const antlr4ts_1 = require("antlr4ts");
9
+ const token_names_1 = require("./token-names");
10
+ function unexpected(offending, clause) {
11
+ return clause
12
+ ? `unexpected ${offending}, expected ${clause}`
13
+ : `unexpected ${offending}`;
14
+ }
9
15
  /**
10
- * Custom error strategy for the Malloy Parser.
16
+ * Overrides the DefaultErrorStrategy methods that paste the parser's
17
+ * expected-token set into the message: tokens are named the way the user types
18
+ * them (via describeExpected) and the set is dropped once too large to be a hint.
11
19
  *
12
- * This class does not currently override default ANTLR error handling.
20
+ * Each path also checks reservedNameMessage first, so a reserved word used where
21
+ * a name was expected (`group_by: year`) says "quote it".
13
22
  *
14
- * For more details, read the documentation in DefaultErrorStrategy.d.ts
15
- * or reference the superclass at:
16
- * https://github.com/tunnelvisionlabs/antlr4ts/blob/master/src/DefaultErrorStrategy.ts
23
+ * Fallback only MalloyParserErrorListener's custom-error cases run first and
24
+ * override these when they match.
17
25
  */
18
26
  class MalloyErrorStrategy extends antlr4ts_1.DefaultErrorStrategy {
27
+ reportInputMismatch(recognizer, e) {
28
+ var _a, _b;
29
+ const offendingToken = e.getOffendingToken(recognizer);
30
+ const expected = (_b = (_a = e.expectedTokens) === null || _a === void 0 ? void 0 : _a.toArray()) !== null && _b !== void 0 ? _b : [];
31
+ const reserved = (0, token_names_1.reservedNameMessage)(offendingToken, expected, recognizer);
32
+ if (reserved) {
33
+ this.notifyErrorListeners(recognizer, reserved, e);
34
+ return;
35
+ }
36
+ const offending = this.getTokenErrorDisplay(offendingToken);
37
+ const clause = (0, token_names_1.describeExpected)(expected, recognizer.vocabulary);
38
+ this.notifyErrorListeners(recognizer, unexpected(offending, clause), e);
39
+ }
40
+ reportUnwantedToken(recognizer) {
41
+ if (this.inErrorRecoveryMode(recognizer)) {
42
+ return;
43
+ }
44
+ this.beginErrorCondition(recognizer);
45
+ const t = recognizer.currentToken;
46
+ const expected = this.getExpectedTokens(recognizer).toArray();
47
+ const reserved = (0, token_names_1.reservedNameMessage)(t, expected, recognizer);
48
+ if (reserved) {
49
+ recognizer.notifyErrorListeners(reserved, t, undefined);
50
+ return;
51
+ }
52
+ const offending = this.getTokenErrorDisplay(t);
53
+ const clause = (0, token_names_1.describeExpected)(expected, recognizer.vocabulary);
54
+ recognizer.notifyErrorListeners(unexpected(offending, clause), t, undefined);
55
+ }
56
+ reportMissingToken(recognizer) {
57
+ if (this.inErrorRecoveryMode(recognizer)) {
58
+ return;
59
+ }
60
+ this.beginErrorCondition(recognizer);
61
+ const t = recognizer.currentToken;
62
+ const expected = this.getExpectedTokens(recognizer).toArray();
63
+ const reserved = (0, token_names_1.reservedNameMessage)(t, expected, recognizer);
64
+ if (reserved) {
65
+ recognizer.notifyErrorListeners(reserved, t, undefined);
66
+ return;
67
+ }
68
+ const offending = this.getTokenErrorDisplay(t);
69
+ const clause = (0, token_names_1.describeExpected)(expected, recognizer.vocabulary);
70
+ const msg = clause
71
+ ? `missing ${clause} before ${offending}`
72
+ : `something is missing before ${offending}`;
73
+ recognizer.notifyErrorListeners(msg, t, undefined);
74
+ }
75
+ // Dispatched from reportError (already in error condition), unlike the inline-
76
+ // recovery methods above — an inErrorRecoveryMode guard here would swallow the
77
+ // error. Short-circuit to the reserved-word hint, else defer to super.
78
+ reportNoViableAlternative(recognizer, e) {
79
+ const t = recognizer.currentToken;
80
+ const expected = this.getExpectedTokens(recognizer).toArray();
81
+ const reserved = (0, token_names_1.reservedNameMessage)(t, expected, recognizer);
82
+ if (reserved) {
83
+ this.notifyErrorListeners(recognizer, reserved, e);
84
+ return;
85
+ }
86
+ super.reportNoViableAlternative(recognizer, e);
87
+ }
19
88
  }
20
89
  exports.MalloyErrorStrategy = MalloyErrorStrategy;
21
90
  //# sourceMappingURL=malloy-error-strategy.js.map
@@ -0,0 +1,5 @@
1
+ import type { Parser, Vocabulary } from 'antlr4ts';
2
+ import { Token } from 'antlr4ts';
3
+ export declare function describeToken(type: number, vocabulary: Vocabulary): string;
4
+ export declare function describeExpected(types: number[], vocabulary: Vocabulary): string | undefined;
5
+ export declare function reservedNameMessage(offending: Token | undefined, expected: number[], recognizer: Parser): string | undefined;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.describeToken = describeToken;
8
+ exports.describeExpected = describeExpected;
9
+ exports.reservedNameMessage = reservedNameMessage;
10
+ const antlr4ts_1 = require("antlr4ts");
11
+ const MalloyParser_1 = require("../lib/Malloy/MalloyParser");
12
+ const keyword_display_names_1 = require("../lib/Malloy/keyword-display-names");
13
+ // Pattern tokens have neither a literal nor a keyword spelling to show, so they
14
+ // get hand-written prose instead of their SHOUTING symbolic name.
15
+ const CLASS_TOKEN_DISPLAY_NAMES = {
16
+ IDENTIFIER: 'a name',
17
+ BQ_STRING: 'a `quoted` name',
18
+ SQ_STRING: 'a quoted string',
19
+ DQ_STRING: 'a quoted string',
20
+ NUMERIC_LITERAL: 'a number',
21
+ INTEGER_LITERAL: 'a number',
22
+ PERCENT_LITERAL: 'a percentage',
23
+ GIVEN_REF: 'a $given reference',
24
+ };
25
+ // Past this many alternatives the expected-set is the parser's follow-set, not
26
+ // a hint, so describeExpected drops it.
27
+ const MAX_EXPECTED_NAMED = 3;
28
+ function describeToken(type, vocabulary) {
29
+ if (type === antlr4ts_1.Token.EOF)
30
+ return 'end of input';
31
+ const symbolic = vocabulary.getSymbolicName(type);
32
+ if (symbolic !== undefined) {
33
+ const prose = CLASS_TOKEN_DISPLAY_NAMES[symbolic];
34
+ if (prose !== undefined)
35
+ return prose;
36
+ const keyword = keyword_display_names_1.KEYWORD_DISPLAY_NAMES[symbolic];
37
+ if (keyword !== undefined)
38
+ return `'${keyword}'`;
39
+ }
40
+ // Punctuation already carries a quoted literal name, e.g. "'{'".
41
+ const literal = vocabulary.getLiteralName(type);
42
+ if (literal !== undefined)
43
+ return literal;
44
+ return symbolic !== null && symbolic !== void 0 ? symbolic : `<token ${type}>`;
45
+ }
46
+ function joinOr(items) {
47
+ if (items.length === 1)
48
+ return items[0];
49
+ return `${items.slice(0, -1).join(', ')} or ${items[items.length - 1]}`;
50
+ }
51
+ function describeExpected(types, vocabulary) {
52
+ const displays = [];
53
+ const seen = new Set();
54
+ for (const type of types) {
55
+ if (type < antlr4ts_1.Token.MIN_USER_TOKEN_TYPE && type !== antlr4ts_1.Token.EOF)
56
+ continue;
57
+ const display = describeToken(type, vocabulary);
58
+ if (!seen.has(display)) {
59
+ seen.add(display);
60
+ displays.push(display);
61
+ }
62
+ }
63
+ if (displays.length === 0 || displays.length > MAX_EXPECTED_NAMED) {
64
+ return undefined;
65
+ }
66
+ return joinOr(displays);
67
+ }
68
+ // When a bare-word reserved token appears where a name (IDENTIFIER) was legal,
69
+ // the user meant it as a field name; return a "quote it" message. undefined
70
+ // otherwise, so the caller keeps its normal message.
71
+ function reservedNameMessage(offending, expected, recognizer) {
72
+ const text = offending === null || offending === void 0 ? void 0 : offending.text;
73
+ if (!text || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(text))
74
+ return undefined;
75
+ const symbolic = recognizer.vocabulary.getSymbolicName(offending.type);
76
+ if (symbolic === undefined || keyword_display_names_1.KEYWORD_DISPLAY_NAMES[symbolic] === undefined) {
77
+ return undefined;
78
+ }
79
+ if (!expected.includes(MalloyParser_1.MalloyParser.IDENTIFIER))
80
+ return undefined;
81
+ // A reserved word followed by '(' is a function call (count()), not a name.
82
+ // offending is the current token here, so LA(2) is the next on-channel token;
83
+ // LA fetches it lazily rather than pre-filling the stream.
84
+ if (recognizer.inputStream.LA(2) === MalloyParser_1.MalloyParser.OPAREN) {
85
+ return undefined;
86
+ }
87
+ return `'${text}' is a reserved word, so to use it as a name you must quote it: \`${text}\``;
88
+ }
89
+ //# sourceMappingURL=token-names.js.map
@@ -23,8 +23,8 @@ exports.caseGroup = caseGroup;
23
23
  exports.mkModelID = mkModelID;
24
24
  exports.mkModelDef = mkModelDef;
25
25
  const uuid_1 = require("uuid");
26
- const sha256_1 = require("@noble/hashes/sha256");
27
- const utils_1 = require("@noble/hashes/utils");
26
+ const sha2_js_1 = require("@noble/hashes/sha2.js");
27
+ const utils_js_1 = require("@noble/hashes/utils.js");
28
28
  const malloy_types_1 = require("./malloy_types");
29
29
  /**
30
30
  * Format a typeDef as user-readable Malloy type syntax. Used in error
@@ -155,7 +155,9 @@ function makeDigest(...parts) {
155
155
  const combined = parts
156
156
  .map(p => (p === undefined ? '{undefined}' : `${p.length}:${p}`))
157
157
  .join('/');
158
- return (0, utils_1.bytesToHex)((0, sha256_1.sha256)(combined));
158
+ // @noble/hashes v2 dropped implicit string hashing; v1 accepted a string and
159
+ // UTF-8 encoded it internally, so utf8ToBytes here yields the identical digest.
160
+ return (0, utils_js_1.bytesToHex)((0, sha2_js_1.sha256)((0, utils_js_1.utf8ToBytes)(combined)));
159
161
  }
160
162
  function joinWith(els, sep) {
161
163
  const result = [];
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.415";
1
+ export declare const MALLOY_VERSION = "0.0.417";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.415';
5
+ exports.MALLOY_VERSION = '0.0.417';
6
6
  //# sourceMappingURL=version.js.map
@@ -16,6 +16,16 @@ parser: {
16
16
  ]
17
17
  }
18
18
 
19
+ tokenNames: {
20
+ deps = [lexer]
21
+ inputs = [
22
+ "src/lang/grammar/MalloyLexer.g4",
23
+ "src/lang/grammar/build_token_names.js"
24
+ ]
25
+ outputs = ["src/lang/lib/Malloy/keyword-display-names.ts"]
26
+ commands = ["node src/lang/grammar/build_token_names.js"]
27
+ }
28
+
19
29
  codegen: {
20
- deps = [parser]
30
+ deps = [parser, tokenNames]
21
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.415",
3
+ "version": "0.0.417",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -51,22 +51,22 @@
51
51
  "generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
52
52
  },
53
53
  "dependencies": {
54
- "@malloydata/malloy-filter": "0.0.415",
55
- "@malloydata/malloy-interfaces": "0.0.415",
56
- "@malloydata/malloy-tag": "0.0.415",
57
- "@noble/hashes": "^1.8.0",
54
+ "@malloydata/malloy-filter": "0.0.417",
55
+ "@malloydata/malloy-interfaces": "0.0.417",
56
+ "@malloydata/malloy-tag": "0.0.417",
57
+ "@noble/hashes": "^2.2.0",
58
58
  "antlr4ts": "^0.5.0-alpha.4",
59
59
  "assert": "^2.0.0",
60
60
  "jaro-winkler": "^0.2.8",
61
- "jest-diff": "^29.6.2",
62
61
  "lodash": "^4.18.1",
63
- "luxon": "^3.5.0",
64
- "uuid": "^8.3.2"
62
+ "luxon": "^3.7.2",
63
+ "uuid": "^14.0.0"
65
64
  },
66
65
  "devDependencies": {
67
66
  "@types/jaro-winkler": "^0.2.3",
68
- "@types/lodash": "^4.14.165",
69
- "@types/luxon": "^3.5.0",
70
- "antlr4ts-cli": "^0.5.0-alpha.4"
67
+ "@types/lodash": "^4.17.24",
68
+ "@types/luxon": "^3.7.2",
69
+ "antlr4ts-cli": "^0.5.0-alpha.4",
70
+ "jest-diff": "^30.4.1"
71
71
  }
72
72
  }