@malloydata/malloy 0.0.1

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 (104) hide show
  1. package/README.md +39 -0
  2. package/dist/connection_utils.d.ts +1 -0
  3. package/dist/connection_utils.js +56 -0
  4. package/dist/dialect/dialect-map.d.ts +3 -0
  5. package/dist/dialect/dialect-map.js +33 -0
  6. package/dist/dialect/dialect.d.ts +64 -0
  7. package/dist/dialect/dialect.js +64 -0
  8. package/dist/dialect/dialect_map.d.ts +3 -0
  9. package/dist/dialect/dialect_map.js +35 -0
  10. package/dist/dialect/duckdb.d.ts +49 -0
  11. package/dist/dialect/duckdb.js +349 -0
  12. package/dist/dialect/index.d.ts +6 -0
  13. package/dist/dialect/index.js +27 -0
  14. package/dist/dialect/postgres.d.ts +49 -0
  15. package/dist/dialect/postgres.js +308 -0
  16. package/dist/dialect/standardsql.d.ts +46 -0
  17. package/dist/dialect/standardsql.js +361 -0
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.js +47 -0
  20. package/dist/lang/ast/apply-expr.d.ts +16 -0
  21. package/dist/lang/ast/apply-expr.js +215 -0
  22. package/dist/lang/ast/ast-expr.d.ts +291 -0
  23. package/dist/lang/ast/ast-expr.js +1056 -0
  24. package/dist/lang/ast/ast-main.d.ts +480 -0
  25. package/dist/lang/ast/ast-main.js +2096 -0
  26. package/dist/lang/ast/ast-time-expr.d.ts +109 -0
  27. package/dist/lang/ast/ast-time-expr.js +550 -0
  28. package/dist/lang/ast/ast-types.d.ts +83 -0
  29. package/dist/lang/ast/ast-types.js +215 -0
  30. package/dist/lang/ast/index.d.ts +5 -0
  31. package/dist/lang/ast/index.js +34 -0
  32. package/dist/lang/ast/time-utils.d.ts +8 -0
  33. package/dist/lang/ast/time-utils.js +83 -0
  34. package/dist/lang/field-space.d.ts +157 -0
  35. package/dist/lang/field-space.js +651 -0
  36. package/dist/lang/field-utils.d.ts +5 -0
  37. package/dist/lang/field-utils.js +33 -0
  38. package/dist/lang/index.d.ts +9 -0
  39. package/dist/lang/index.js +22 -0
  40. package/dist/lang/lib/Malloy/MalloyLexer.d.ts +156 -0
  41. package/dist/lang/lib/Malloy/MalloyLexer.js +1163 -0
  42. package/dist/lang/lib/Malloy/MalloyListener.d.ts +2026 -0
  43. package/dist/lang/lib/Malloy/MalloyListener.js +4 -0
  44. package/dist/lang/lib/Malloy/MalloyParser.d.ts +1920 -0
  45. package/dist/lang/lib/Malloy/MalloyParser.js +11790 -0
  46. package/dist/lang/lib/Malloy/MalloyVisitor.d.ts +1276 -0
  47. package/dist/lang/lib/Malloy/MalloyVisitor.js +4 -0
  48. package/dist/lang/parse-log.d.ts +27 -0
  49. package/dist/lang/parse-log.js +41 -0
  50. package/dist/lang/parse-malloy.d.ts +245 -0
  51. package/dist/lang/parse-malloy.js +729 -0
  52. package/dist/lang/parse-to-ast.d.ts +156 -0
  53. package/dist/lang/parse-to-ast.js +945 -0
  54. package/dist/lang/parse-tree-walkers/document-completion-walker.d.ts +10 -0
  55. package/dist/lang/parse-tree-walkers/document-completion-walker.js +136 -0
  56. package/dist/lang/parse-tree-walkers/document-help-context-walker.d.ts +9 -0
  57. package/dist/lang/parse-tree-walkers/document-help-context-walker.js +97 -0
  58. package/dist/lang/parse-tree-walkers/document-highlight-walker.d.ts +83 -0
  59. package/dist/lang/parse-tree-walkers/document-highlight-walker.js +375 -0
  60. package/dist/lang/parse-tree-walkers/document-symbol-walker.d.ts +11 -0
  61. package/dist/lang/parse-tree-walkers/document-symbol-walker.js +172 -0
  62. package/dist/lang/parse-tree-walkers/explore-query-walker.d.ts +34 -0
  63. package/dist/lang/parse-tree-walkers/explore-query-walker.js +64 -0
  64. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +11 -0
  65. package/dist/lang/parse-tree-walkers/find-external-references.js +51 -0
  66. package/dist/lang/reference-list.d.ts +10 -0
  67. package/dist/lang/reference-list.js +80 -0
  68. package/dist/lang/space-field.d.ts +119 -0
  69. package/dist/lang/space-field.js +339 -0
  70. package/dist/lang/test/document-help-context-walker.spec.d.ts +1 -0
  71. package/dist/lang/test/document-help-context-walker.spec.js +45 -0
  72. package/dist/lang/test/document-symbol-walker.spec.d.ts +1 -0
  73. package/dist/lang/test/document-symbol-walker.spec.js +100 -0
  74. package/dist/lang/test/field-symbols.spec.d.ts +1 -0
  75. package/dist/lang/test/field-symbols.spec.js +172 -0
  76. package/dist/lang/test/parse.spec.d.ts +12 -0
  77. package/dist/lang/test/parse.spec.js +1936 -0
  78. package/dist/lang/test/test-translator.d.ts +38 -0
  79. package/dist/lang/test/test-translator.js +334 -0
  80. package/dist/lang/zone.d.ts +57 -0
  81. package/dist/lang/zone.js +97 -0
  82. package/dist/malloy.d.ts +1134 -0
  83. package/dist/malloy.js +2354 -0
  84. package/dist/model/index.d.ts +2 -0
  85. package/dist/model/index.js +34 -0
  86. package/dist/model/malloy-query.d.ts +313 -0
  87. package/dist/model/malloy-query.js +2603 -0
  88. package/dist/model/malloy-types.d.ts +404 -0
  89. package/dist/model/malloy-types.js +242 -0
  90. package/dist/model/malloy_query.d.ts +353 -0
  91. package/dist/model/malloy_query.js +2990 -0
  92. package/dist/model/malloy_types.d.ts +502 -0
  93. package/dist/model/malloy_types.js +283 -0
  94. package/dist/model/sql-block.d.ts +11 -0
  95. package/dist/model/sql-block.js +38 -0
  96. package/dist/model/sql_block.d.ts +11 -0
  97. package/dist/model/sql_block.js +41 -0
  98. package/dist/model/utils.d.ts +21 -0
  99. package/dist/model/utils.js +84 -0
  100. package/dist/runtime-types.d.ts +116 -0
  101. package/dist/runtime-types.js +40 -0
  102. package/dist/runtime_types.d.ts +119 -0
  103. package/dist/runtime_types.js +15 -0
  104. package/package.json +36 -0
@@ -0,0 +1,729 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2021 Google LLC
4
+ *
5
+ * This program is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU General Public License
7
+ * version 2 as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.MalloyTranslator = exports.MalloyTranslation = exports.SQLExploreZone = void 0;
39
+ const antlr4ts_1 = require("antlr4ts");
40
+ const MalloyLexer_1 = require("./lib/Malloy/MalloyLexer");
41
+ const MalloyParser_1 = require("./lib/Malloy/MalloyParser");
42
+ const ast = __importStar(require("./ast"));
43
+ const parse_to_ast_1 = require("./parse-to-ast");
44
+ const parse_log_1 = require("./parse-log");
45
+ const find_external_references_1 = require("./parse-tree-walkers/find-external-references");
46
+ const zone_1 = require("./zone");
47
+ const document_symbol_walker_1 = require("./parse-tree-walkers/document-symbol-walker");
48
+ const document_highlight_walker_1 = require("./parse-tree-walkers/document-highlight-walker");
49
+ const document_completion_walker_1 = require("./parse-tree-walkers/document-completion-walker");
50
+ const document_help_context_walker_1 = require("./parse-tree-walkers/document-help-context-walker");
51
+ const reference_list_1 = require("./reference-list");
52
+ class MalloyParserErrorHandler {
53
+ constructor(translator, messages) {
54
+ this.translator = translator;
55
+ this.messages = messages;
56
+ }
57
+ syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, _e) {
58
+ const errAt = { line: line - 1, character: charPositionInLine };
59
+ const range = offendingSymbol
60
+ ? this.translator.rangeFromToken(offendingSymbol)
61
+ : { start: errAt, end: errAt };
62
+ const error = {
63
+ message: msg,
64
+ at: { url: this.translator.sourceURL, range },
65
+ };
66
+ this.messages.log(error);
67
+ }
68
+ }
69
+ /**
70
+ * An SQL Block contains a unique key inside it, and we use that to
71
+ * reference and define blocks, since Zone really wants keys to be strings.
72
+ *
73
+ * If I had SQLBlocks when Zones were defined, this would not be
74
+ * a one off class, it would be Zone<keyType,valueType>
75
+ */
76
+ class SQLExploreZone extends zone_1.Zone {
77
+ constructor() {
78
+ super(...arguments);
79
+ this.keyed = {};
80
+ }
81
+ referenceBlock(from, at) {
82
+ const sql = from.sqlBlock();
83
+ this.reference(sql.name, at);
84
+ this.keyed[sql.name] = sql;
85
+ }
86
+ getUndefinedBlocks() {
87
+ const blockRefs = this.getUndefined();
88
+ if (blockRefs) {
89
+ return blockRefs.map((ref) => this.keyed[ref]);
90
+ }
91
+ return undefined;
92
+ }
93
+ }
94
+ exports.SQLExploreZone = SQLExploreZone;
95
+ function isNeedResponse(dr) {
96
+ return !!dr && (dr.tables || dr.urls || dr.sqlStructs) != undefined;
97
+ }
98
+ class ParseStep {
99
+ step(that) {
100
+ if (this.response) {
101
+ return this.response;
102
+ }
103
+ if (that.urlIsFullPath === undefined) {
104
+ try {
105
+ const _checkFull = new URL(that.sourceURL);
106
+ that.urlIsFullPath = true;
107
+ }
108
+ catch (e) {
109
+ const msg = e instanceof Error ? e.message : "";
110
+ that.urlIsFullPath = false;
111
+ that.root.logger.log({
112
+ message: `Could not compute full path URL: ${msg}`,
113
+ });
114
+ }
115
+ }
116
+ if (!that.urlIsFullPath) {
117
+ return that.fatalErrors();
118
+ }
119
+ const srcEnt = that.root.importZone.getEntry(that.sourceURL);
120
+ if (srcEnt.status !== "present") {
121
+ if (srcEnt.status === "error") {
122
+ const message = srcEnt.message.includes(that.sourceURL)
123
+ ? `import error: ${srcEnt.message}`
124
+ : `import '${that.sourceURL}' error: ${srcEnt.message}`;
125
+ const at = srcEnt.firstReference || that.defaultLocation();
126
+ that.root.logger.log({ message, at });
127
+ this.response = that.fatalErrors();
128
+ return this.response;
129
+ }
130
+ return { urls: [that.sourceURL] };
131
+ }
132
+ const source = srcEnt.value == "" ? "\n" : srcEnt.value;
133
+ this.sourceInfo = this.getSourceInfo(source);
134
+ const parse = this.runParser(source, that);
135
+ if (that.root.logger.hasErrors()) {
136
+ this.response = {
137
+ parse,
138
+ ...that.fatalErrors(),
139
+ };
140
+ }
141
+ else {
142
+ this.response = { parse };
143
+ }
144
+ return this.response;
145
+ }
146
+ /**
147
+ * Split the source up into lines so we can correctly compute offset
148
+ * to the line/char positions favored by LSP and VSCode.
149
+ */
150
+ getSourceInfo(code) {
151
+ const eolRegex = /\r?\n/;
152
+ const info = {
153
+ at: [],
154
+ lines: [],
155
+ length: code.length,
156
+ };
157
+ let src = code;
158
+ let lineStart = 0;
159
+ while (src !== "") {
160
+ const eol = src.match(eolRegex);
161
+ if (eol && eol.index != undefined) {
162
+ // line text DOES NOT include the EOL
163
+ info.lines.push(src.slice(0, eol.index));
164
+ const lineLength = eol.index + eol[0].length;
165
+ info.at.push({
166
+ begin: lineStart,
167
+ end: lineStart + lineLength,
168
+ });
169
+ lineStart += lineLength;
170
+ src = src.slice(lineLength);
171
+ }
172
+ else {
173
+ // last line, does not have a line end
174
+ info.lines.push(src);
175
+ info.at.push({ begin: lineStart, end: lineStart + src.length });
176
+ break;
177
+ }
178
+ }
179
+ return info;
180
+ }
181
+ runParser(source, that) {
182
+ const inputStream = antlr4ts_1.CharStreams.fromString(source);
183
+ const lexer = new MalloyLexer_1.MalloyLexer(inputStream);
184
+ const tokenStream = new antlr4ts_1.CommonTokenStream(lexer);
185
+ const malloyParser = new MalloyParser_1.MalloyParser(tokenStream);
186
+ malloyParser.removeErrorListeners();
187
+ malloyParser.addErrorListener(new MalloyParserErrorHandler(that, that.root.logger));
188
+ // Admitted code smell here, testing likes to parse from an arbitrary
189
+ // node and this is the simplest way to allow that.
190
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
191
+ const parseFunc = malloyParser[that.grammarRule];
192
+ if (!parseFunc) {
193
+ throw new Error(`No such parse rule as ${that.grammarRule}`);
194
+ }
195
+ return {
196
+ root: parseFunc.call(malloyParser),
197
+ tokenStream: tokenStream,
198
+ sourceStream: inputStream,
199
+ // TODO put the real version here
200
+ malloyVersion: "?.?.?-????",
201
+ subTranslator: that,
202
+ };
203
+ }
204
+ }
205
+ class ImportsAndTablesStep {
206
+ constructor(parseStep) {
207
+ this.parseStep = parseStep;
208
+ this.alreadyLooked = false;
209
+ }
210
+ step(that) {
211
+ const parseReq = this.parseStep.step(that);
212
+ if (parseReq.parse == undefined) {
213
+ return parseReq;
214
+ }
215
+ if (!this.alreadyLooked) {
216
+ this.alreadyLooked = true;
217
+ const parseRefs = (0, find_external_references_1.findReferences)(that, parseReq.parse.tokenStream, parseReq.parse.root);
218
+ if (parseRefs === null || parseRefs === void 0 ? void 0 : parseRefs.tables) {
219
+ for (const ref in parseRefs.tables) {
220
+ that.root.schemaZone.reference(ref, {
221
+ url: that.sourceURL,
222
+ range: parseRefs.tables[ref],
223
+ });
224
+ }
225
+ }
226
+ if (parseRefs === null || parseRefs === void 0 ? void 0 : parseRefs.urls) {
227
+ for (const relativeRef in parseRefs.urls) {
228
+ const firstRef = parseRefs.urls[relativeRef];
229
+ try {
230
+ const ref = decodeURI(new URL(relativeRef, that.sourceURL).toString());
231
+ that.addChild(ref);
232
+ that.root.importZone.reference(ref, {
233
+ url: that.sourceURL,
234
+ range: firstRef,
235
+ });
236
+ }
237
+ catch (err) {
238
+ // This import spec is so bad the URL library threw up, this
239
+ // may be impossible, because it will append any garbage
240
+ // to the known good rootURL assuming it is relative
241
+ that.root.logger.log({
242
+ message: `Malformed URL '${relativeRef}'"`,
243
+ at: { url: that.sourceURL, range: firstRef },
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+ if (that.root.logger.hasErrors()) {
250
+ // Since we knew we parsed without errors, this would only be from
251
+ // having a malformed URL on an import reference.
252
+ return null;
253
+ }
254
+ let allMissing = {};
255
+ const missingTables = that.root.schemaZone.getUndefined();
256
+ if (missingTables) {
257
+ allMissing = { tables: missingTables };
258
+ }
259
+ const missingImports = that.root.importZone.getUndefined();
260
+ if (missingImports) {
261
+ allMissing = { ...allMissing, urls: missingImports };
262
+ }
263
+ if (isNeedResponse(allMissing)) {
264
+ return allMissing;
265
+ }
266
+ for (const child of that.childTranslators.values()) {
267
+ const kidNeeds = child.importsAndTablesStep.step(child);
268
+ if (isNeedResponse(kidNeeds)) {
269
+ return kidNeeds;
270
+ }
271
+ }
272
+ return null;
273
+ }
274
+ }
275
+ class ASTStep {
276
+ constructor(importStep) {
277
+ this.importStep = importStep;
278
+ this.walked = false;
279
+ }
280
+ step(that) {
281
+ if (this.response) {
282
+ return this.response;
283
+ }
284
+ const mustResolve = this.importStep.step(that);
285
+ if (mustResolve) {
286
+ return mustResolve;
287
+ }
288
+ const parseResponse = that.parseStep.response;
289
+ // Errors in self or children will show up here ..
290
+ if (that.root.logger.hasErrors()) {
291
+ this.response = that.fatalErrors();
292
+ return this.response;
293
+ }
294
+ const parse = parseResponse === null || parseResponse === void 0 ? void 0 : parseResponse.parse;
295
+ if (!parse) {
296
+ throw new Error("TRANSLATOR INTERNAL ERROR: Translator parse response had no errors, but also no parser");
297
+ }
298
+ const secondPass = new parse_to_ast_1.MalloyToAST(parse, that.root.logger);
299
+ const newAst = secondPass.visit(parse.root);
300
+ if (that.root.logger.hasErrors()) {
301
+ this.response = that.fatalErrors();
302
+ return this.response;
303
+ }
304
+ if (newAst.elementType === "unimplemented") {
305
+ throw new Error("TRANSLATOR INTERNAL ERROR: Unimplemented AST node");
306
+ }
307
+ // I kind of think table refs should probably also be collected here
308
+ // instead of in the parse step. Note to myself, do that someday.
309
+ const sqlExplores = {};
310
+ if (!this.walked) {
311
+ newAst.walk((walkedTo) => {
312
+ if (walkedTo instanceof ast.SQLSource) {
313
+ if (!sqlExplores[walkedTo.refName]) {
314
+ sqlExplores[walkedTo.refName] = {};
315
+ }
316
+ sqlExplores[walkedTo.refName].ref = walkedTo;
317
+ }
318
+ else if (walkedTo instanceof ast.SQLStatement && walkedTo.is) {
319
+ if (!sqlExplores[walkedTo.is]) {
320
+ sqlExplores[walkedTo.is] = {};
321
+ }
322
+ sqlExplores[walkedTo.is].def = walkedTo;
323
+ }
324
+ else if (walkedTo instanceof ast.Unimplemented) {
325
+ walkedTo.log("INTERNAL COMPILER ERROR: Untranslated parse node");
326
+ }
327
+ });
328
+ this.walked = true;
329
+ }
330
+ // If there is a partial ast ...
331
+ if (that.root.logger.hasErrors()) {
332
+ this.response = that.fatalErrors();
333
+ return this.response;
334
+ }
335
+ // Make sure there is a request/reference for all explored-sql entities
336
+ const sqlZone = that.root.sqlQueryZone;
337
+ for (const sqlExploreRef in sqlExplores) {
338
+ const sqlExplore = sqlExplores[sqlExploreRef];
339
+ if (sqlExplore.ref && sqlExplore.def) {
340
+ const sqlAt = {
341
+ url: that.sourceURL,
342
+ range: sqlExplore.def.location.range,
343
+ };
344
+ that.root.sqlQueryZone.referenceBlock(sqlExplore.def, sqlAt);
345
+ }
346
+ }
347
+ // Now make sure that every child also has all sql blocks resolved
348
+ for (const child of that.childTranslators.values()) {
349
+ const kidNeeds = child.astStep.step(child);
350
+ if (isNeedResponse(kidNeeds)) {
351
+ return kidNeeds;
352
+ }
353
+ }
354
+ // TODO report errors from here!
355
+ const missingSqlStructs = sqlZone.getUndefinedBlocks();
356
+ if (missingSqlStructs) {
357
+ return { sqlStructs: missingSqlStructs };
358
+ }
359
+ newAst.setTranslator(that);
360
+ this.response = {
361
+ ...that.errors(),
362
+ ast: newAst,
363
+ final: true,
364
+ };
365
+ return this.response;
366
+ }
367
+ }
368
+ class MetadataStep {
369
+ constructor(parseStep) {
370
+ this.parseStep = parseStep;
371
+ }
372
+ step(that) {
373
+ if (!this.response) {
374
+ const tryParse = this.parseStep.step(that);
375
+ if (!tryParse.parse) {
376
+ return tryParse;
377
+ }
378
+ else {
379
+ // Wrap the parse tree walker in a try block -- if the parse is bad, this walk
380
+ // could result in unexpected errors due to the parse tree not looking as expected.
381
+ // We still want to attempt to walk the tree, to preserve document symbols even
382
+ // when there's a bad parse, but we also want to be safe about it.
383
+ let symbols;
384
+ try {
385
+ symbols = (0, document_symbol_walker_1.walkForDocumentSymbols)(that, tryParse.parse.tokenStream, tryParse.parse.root);
386
+ }
387
+ catch {
388
+ // Do nothing, symbols already `undefined`
389
+ }
390
+ let walkHighlights;
391
+ try {
392
+ walkHighlights = (0, document_highlight_walker_1.walkForDocumentHighlights)(tryParse.parse.tokenStream, tryParse.parse.root);
393
+ }
394
+ catch {
395
+ walkHighlights = [];
396
+ }
397
+ this.response = {
398
+ symbols,
399
+ highlights: (0, document_highlight_walker_1.sortHighlights)([
400
+ ...(0, document_highlight_walker_1.passForHighlights)(tryParse.parse.tokenStream),
401
+ ...walkHighlights,
402
+ ]),
403
+ final: true,
404
+ };
405
+ }
406
+ }
407
+ return this.response;
408
+ }
409
+ }
410
+ class CompletionsStep {
411
+ constructor(parseStep) {
412
+ this.parseStep = parseStep;
413
+ }
414
+ step(that, position) {
415
+ const tryParse = this.parseStep.step(that);
416
+ if (!tryParse.parse) {
417
+ return tryParse;
418
+ }
419
+ else {
420
+ let completions = [];
421
+ if (position !== undefined) {
422
+ try {
423
+ completions = (0, document_completion_walker_1.walkForDocumentCompletions)(tryParse.parse.tokenStream, tryParse.parse.root, position);
424
+ }
425
+ catch {
426
+ /* Do nothing */
427
+ }
428
+ }
429
+ return {
430
+ ...tryParse,
431
+ completions,
432
+ };
433
+ }
434
+ }
435
+ }
436
+ class HelpContextStep {
437
+ constructor(parseStep) {
438
+ this.parseStep = parseStep;
439
+ }
440
+ step(that, position) {
441
+ const tryParse = this.parseStep.step(that);
442
+ if (!tryParse.parse) {
443
+ return tryParse;
444
+ }
445
+ else {
446
+ let helpContext;
447
+ if (position !== undefined) {
448
+ try {
449
+ helpContext = (0, document_help_context_walker_1.walkForDocumentHelpContext)(tryParse.parse.root, position);
450
+ }
451
+ catch {
452
+ /* Do nothing */
453
+ }
454
+ }
455
+ return {
456
+ ...tryParse,
457
+ helpContext,
458
+ };
459
+ }
460
+ }
461
+ }
462
+ class TranslateStep {
463
+ constructor(astStep) {
464
+ this.astStep = astStep;
465
+ }
466
+ step(that, extendingModel) {
467
+ if (this.response) {
468
+ return this.response;
469
+ }
470
+ const astResponse = this.astStep.step(that);
471
+ if (isNeedResponse(astResponse)) {
472
+ return astResponse;
473
+ }
474
+ if (!astResponse.ast) {
475
+ this.response = astResponse;
476
+ return this.response;
477
+ }
478
+ if (that.grammarRule === "malloyDocument") {
479
+ if (astResponse.ast instanceof ast.Document) {
480
+ const doc = astResponse.ast;
481
+ that.modelDef = doc.getModelDef(extendingModel);
482
+ that.queryList = doc.queryList;
483
+ that.sqlBlocks = doc.sqlBlocks;
484
+ }
485
+ else {
486
+ that.root.logger.log({
487
+ message: `'${that.sourceURL}' did not parse to malloy document`,
488
+ at: that.defaultLocation(),
489
+ });
490
+ }
491
+ }
492
+ if (that.root.logger.hasErrors()) {
493
+ this.response = that.fatalErrors();
494
+ }
495
+ else {
496
+ this.response = {
497
+ translated: {
498
+ modelDef: that.modelDef,
499
+ queryList: that.queryList,
500
+ sqlBlocks: that.sqlBlocks,
501
+ },
502
+ ...that.errors(),
503
+ final: true,
504
+ };
505
+ }
506
+ return this.response;
507
+ }
508
+ }
509
+ class MalloyTranslation {
510
+ constructor(sourceURL, grammarRule = "malloyDocument") {
511
+ this.sourceURL = sourceURL;
512
+ this.grammarRule = grammarRule;
513
+ this.queryList = [];
514
+ this.sqlBlocks = [];
515
+ this.childTranslators = new Map();
516
+ this.modelDef = {
517
+ name: sourceURL,
518
+ exports: [],
519
+ contents: {},
520
+ };
521
+ /**
522
+ * This is sort of the makefile for the translation, all the steps
523
+ * and the dependencies of the steps are declared here. Then when
524
+ * a translator method is called which needs the result of a step,
525
+ * it asks the step what it needs to complete, and all the right
526
+ * things will happen automatically.
527
+ */
528
+ this.parseStep = new ParseStep();
529
+ this.metadataStep = new MetadataStep(this.parseStep);
530
+ this.completionsStep = new CompletionsStep(this.parseStep);
531
+ this.helpContextStep = new HelpContextStep(this.parseStep);
532
+ this.importsAndTablesStep = new ImportsAndTablesStep(this.parseStep);
533
+ this.astStep = new ASTStep(this.importsAndTablesStep);
534
+ this.translateStep = new TranslateStep(this.astStep);
535
+ this.references = new reference_list_1.ReferenceList(sourceURL);
536
+ }
537
+ addChild(url) {
538
+ if (!this.childTranslators.get(url)) {
539
+ this.childTranslators.set(url, new MalloyChildTranslator(url, this.root));
540
+ }
541
+ }
542
+ addReference(reference) {
543
+ this.references.add(reference);
544
+ }
545
+ referenceAt(position) {
546
+ return this.references.find(position);
547
+ }
548
+ fatalErrors() {
549
+ return {
550
+ final: true,
551
+ errors: [...this.root.logger.getLog()],
552
+ };
553
+ }
554
+ /**
555
+ * The error log can grow as progressively deeper questions are asked.
556
+ * When returning "errors so far", make a snapshot.
557
+ */
558
+ errors() {
559
+ const errors = this.root.logger.getLog();
560
+ return { errors: [...errors] };
561
+ }
562
+ getLineMap(url) {
563
+ var _a, _b;
564
+ if (url == this.sourceURL) {
565
+ return (_a = this.parseStep.sourceInfo) === null || _a === void 0 ? void 0 : _a.lines;
566
+ }
567
+ const theChild = this.childTranslators.get(url);
568
+ if (theChild) {
569
+ return (_b = theChild.parseStep.sourceInfo) === null || _b === void 0 ? void 0 : _b.lines;
570
+ }
571
+ }
572
+ prettyErrors() {
573
+ let lovely = "";
574
+ let inFile = "";
575
+ for (const entry of this.root.logger.getLog()) {
576
+ let cooked = entry.message;
577
+ let errorURL = this.sourceURL;
578
+ if (entry.at) {
579
+ errorURL = entry.at.url;
580
+ const lineNo = entry.at.range.start.line;
581
+ const charFrom = entry.at.range.start.character;
582
+ const lines = this.getLineMap(entry.at.url);
583
+ if (lines) {
584
+ const errorLine = lines[lineNo];
585
+ cooked = `line ${lineNo + 1}: ${entry.message}\n | ${errorLine}`;
586
+ if (charFrom > 0) {
587
+ cooked = cooked + `\n | ${" ".repeat(charFrom)}^`;
588
+ }
589
+ }
590
+ else {
591
+ cooked = `line ${lineNo + 1}: char ${charFrom}: ${entry.message}`;
592
+ }
593
+ }
594
+ if (inFile !== errorURL) {
595
+ cooked = `FILE: ${errorURL}\n` + cooked;
596
+ inFile = errorURL;
597
+ }
598
+ if (lovely !== "") {
599
+ lovely = `${lovely}\n${cooked}`;
600
+ }
601
+ else {
602
+ lovely = cooked;
603
+ }
604
+ }
605
+ return lovely;
606
+ }
607
+ getChildExports(importURL) {
608
+ const exports = {};
609
+ const childURL = decodeURI(new URL(importURL, this.sourceURL).toString());
610
+ const child = this.childTranslators.get(childURL);
611
+ if (child) {
612
+ const did = child.translate();
613
+ if (did.translated) {
614
+ for (const fromChild of child.modelDef.exports) {
615
+ const modelEntry = child.modelDef.contents[fromChild];
616
+ if (modelEntry.type === "struct") {
617
+ exports[fromChild] = modelEntry;
618
+ }
619
+ }
620
+ }
621
+ // else nothing, assuming there are already errors in the log
622
+ }
623
+ return exports;
624
+ }
625
+ translate(extendingModel) {
626
+ if (this.finalAnswer) {
627
+ return this.finalAnswer;
628
+ }
629
+ const attempt = this.translateStep.step(this, extendingModel);
630
+ if (attempt.final) {
631
+ this.finalAnswer = attempt;
632
+ }
633
+ return attempt;
634
+ }
635
+ metadata() {
636
+ return this.metadataStep.step(this);
637
+ }
638
+ completions(position) {
639
+ return this.completionsStep.step(this, position);
640
+ }
641
+ helpContext(position) {
642
+ return this.helpContextStep.step(this, position);
643
+ }
644
+ defaultLocation() {
645
+ return {
646
+ url: this.sourceURL,
647
+ range: {
648
+ start: { line: 0, character: 0 },
649
+ end: { line: 0, character: 0 },
650
+ },
651
+ };
652
+ }
653
+ rangeFromContext(pcx) {
654
+ return this.rangeFromTokens(pcx.start, pcx.stop || pcx.start);
655
+ }
656
+ rangeFromTokens(startToken, stopToken) {
657
+ const start = {
658
+ line: startToken.line - 1,
659
+ character: startToken.charPositionInLine,
660
+ };
661
+ if (this.parseStep.sourceInfo && stopToken.stopIndex != -1) {
662
+ // Find the line which contains the stopIndex
663
+ const lastLine = this.parseStep.sourceInfo.lines.length - 1;
664
+ for (let lineNo = startToken.line - 1; lineNo <= lastLine; lineNo++) {
665
+ const at = this.parseStep.sourceInfo.at[lineNo];
666
+ if (stopToken.stopIndex >= at.begin && stopToken.stopIndex <= at.end) {
667
+ return {
668
+ start,
669
+ end: {
670
+ line: lineNo,
671
+ character: stopToken.stopIndex - at.begin + 1,
672
+ },
673
+ };
674
+ }
675
+ }
676
+ // Should be impossible to get here, but if we do ... return the last
677
+ // character of the last line of the file
678
+ return {
679
+ start,
680
+ end: {
681
+ line: lastLine,
682
+ character: this.parseStep.sourceInfo.lines[lastLine].length,
683
+ },
684
+ };
685
+ }
686
+ return { start, end: start };
687
+ }
688
+ rangeFromToken(token) {
689
+ return this.rangeFromTokens(token, token);
690
+ }
691
+ }
692
+ exports.MalloyTranslation = MalloyTranslation;
693
+ class MalloyChildTranslator extends MalloyTranslation {
694
+ constructor(rootURL, root) {
695
+ super(rootURL);
696
+ this.root = root;
697
+ }
698
+ }
699
+ /**
700
+ * The main interface to Malloy tranlsation. It has a call pattern
701
+ * similar to a server. Once a translator is instantiated
702
+ * you can request tralnsations repeatedly. Responses to that request
703
+ * will either be "NeedResponse" or "TranslateResponse" objects. The
704
+ * correct pattern is to call "translation" in a loop, calling
705
+ * "update" in response to each "NeedResponse" until a "TranslateResponse"
706
+ * is returned. If you get a response with "final:true", there is
707
+ * no need to call again, the translation is finished or error'd.
708
+ */
709
+ class MalloyTranslator extends MalloyTranslation {
710
+ constructor(rootURL, preload = null) {
711
+ super(rootURL);
712
+ this.schemaZone = new zone_1.Zone();
713
+ this.importZone = new zone_1.Zone();
714
+ this.sqlQueryZone = new SQLExploreZone();
715
+ this.logger = new parse_log_1.MessageLog();
716
+ this.root = this;
717
+ if (preload) {
718
+ this.update(preload);
719
+ }
720
+ }
721
+ update(dd) {
722
+ var _a, _b, _c;
723
+ this.schemaZone.updateFrom(dd.tables, (_a = dd.errors) === null || _a === void 0 ? void 0 : _a.tables);
724
+ this.importZone.updateFrom(dd.urls, (_b = dd.errors) === null || _b === void 0 ? void 0 : _b.urls);
725
+ this.sqlQueryZone.updateFrom(dd.sqlStructs, (_c = dd.errors) === null || _c === void 0 ? void 0 : _c.sqlStructs);
726
+ }
727
+ }
728
+ exports.MalloyTranslator = MalloyTranslator;
729
+ //# sourceMappingURL=parse-malloy.js.map