@malloydata/malloy 0.0.96-dev231025212541 → 0.0.96-dev231025215721

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.
@@ -204,6 +204,7 @@ import { JustExprContext } from "./MalloyParser";
204
204
  import { SqlExploreNameRefContext } from "./MalloyParser";
205
205
  import { NameSQLBlockContext } from "./MalloyParser";
206
206
  import { ConnectionNameContext } from "./MalloyParser";
207
+ import { ExperimentalStatementForTestingContext } from "./MalloyParser";
207
208
  /**
208
209
  * This interface defines a complete listener for a parse tree produced by
209
210
  * `MalloyParser`.
@@ -2411,4 +2412,14 @@ export interface MalloyParserListener extends ParseTreeListener {
2411
2412
  * @param ctx the parse tree
2412
2413
  */
2413
2414
  exitConnectionName?: (ctx: ConnectionNameContext) => void;
2415
+ /**
2416
+ * Enter a parse tree produced by `MalloyParser.experimentalStatementForTesting`.
2417
+ * @param ctx the parse tree
2418
+ */
2419
+ enterExperimentalStatementForTesting?: (ctx: ExperimentalStatementForTestingContext) => void;
2420
+ /**
2421
+ * Exit a parse tree produced by `MalloyParser.experimentalStatementForTesting`.
2422
+ * @param ctx the parse tree
2423
+ */
2424
+ exitExperimentalStatementForTesting?: (ctx: ExperimentalStatementForTestingContext) => void;
2414
2425
  }
@@ -204,6 +204,7 @@ import { JustExprContext } from "./MalloyParser";
204
204
  import { SqlExploreNameRefContext } from "./MalloyParser";
205
205
  import { NameSQLBlockContext } from "./MalloyParser";
206
206
  import { ConnectionNameContext } from "./MalloyParser";
207
+ import { ExperimentalStatementForTestingContext } from "./MalloyParser";
207
208
  /**
208
209
  * This interface defines a complete generic visitor for a parse tree produced
209
210
  * by `MalloyParser`.
@@ -1518,4 +1519,10 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
1518
1519
  * @return the visitor result
1519
1520
  */
1520
1521
  visitConnectionName?: (ctx: ConnectionNameContext) => Result;
1522
+ /**
1523
+ * Visit a parse tree produced by `MalloyParser.experimentalStatementForTesting`.
1524
+ * @param ctx the parse tree
1525
+ * @return the visitor result
1526
+ */
1527
+ visitExperimentalStatementForTesting?: (ctx: ExperimentalStatementForTestingContext) => Result;
1521
1528
  }
@@ -30,7 +30,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
30
30
  readonly parseInfo: MalloyParseInfo;
31
31
  readonly msgLog: MessageLogger;
32
32
  compilerFlags: Tag;
33
- constructor(parseInfo: MalloyParseInfo, msgLog: MessageLogger);
33
+ constructor(parseInfo: MalloyParseInfo, msgLog: MessageLogger, compilerFlags: Tag);
34
34
  /**
35
35
  * Mostly used to flag a case where the grammar and the type system are
36
36
  * no longer in sync. A visitor was written based on a grammar which
@@ -49,6 +49,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
49
49
  * Log an error message relative to a parse node
50
50
  */
51
51
  protected contextError(cx: ParserRuleContext, msg: string, sev?: LogSeverity): void;
52
+ protected inExperiment(experimentID: string, cx: ParserRuleContext): boolean;
52
53
  protected m4Severity(): LogSeverity | false;
53
54
  protected m4advisory(cx: ParserRuleContext, msg: string): void;
54
55
  protected only<T extends ast.MalloyElement>(els: ast.MalloyElement[], isGood: (el: ast.MalloyElement) => T | false, desc: string): T[];
@@ -212,5 +213,6 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
212
213
  visitSQTable(pcx: parse.SQTableContext): ast.SQSourceWrapper | ErrorNode;
213
214
  visitSQLegacySQLBlock(pcx: parse.SQLegacySQLBlockContext): ast.SQSourceWrapper;
214
215
  visitSQSQL(pcx: parse.SQSQLContext): ast.SQSourceWrapper;
216
+ visitExperimentalStatementForTesting(pcx: parse.ExperimentalStatementForTestingContext): ast.ExperimentalExperiment;
215
217
  }
216
218
  export {};
@@ -73,11 +73,11 @@ const DEFAULT_COMPILER_FLAGS = ['##! m4warnings=error'];
73
73
  * AST from an ANTLR parse tree.
74
74
  */
75
75
  class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
76
- constructor(parseInfo, msgLog) {
76
+ constructor(parseInfo, msgLog, compilerFlags) {
77
77
  super();
78
78
  this.parseInfo = parseInfo;
79
79
  this.msgLog = msgLog;
80
- this.compilerFlags = new tags_1.Tag();
80
+ this.compilerFlags = compilerFlags;
81
81
  for (const flag of DEFAULT_COMPILER_FLAGS) {
82
82
  const withNewTag = tags_1.Tag.fromTagline(flag, this.compilerFlags);
83
83
  this.compilerFlags = withNewTag.tag;
@@ -118,6 +118,14 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
118
118
  severity: sev,
119
119
  });
120
120
  }
121
+ inExperiment(experimentID, cx) {
122
+ const experimental = this.compilerFlags.tag('experimental');
123
+ if (experimental) {
124
+ return experimental.bare() || experimental.has(experimentID);
125
+ }
126
+ this.contextError(cx, `Experimental flag '${experimentID}' required to enable this feature`);
127
+ return false;
128
+ }
121
129
  m4Severity() {
122
130
  const m4severityTag = this.compilerFlags.tag('m4warnings');
123
131
  if (m4severityTag) {
@@ -1339,6 +1347,10 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1339
1347
  const sqExpr = new ast.SQSourceWrapper(this.visitSqlSource(pcx.sqlSource()));
1340
1348
  return this.astAt(sqExpr, pcx);
1341
1349
  }
1350
+ visitExperimentalStatementForTesting(pcx) {
1351
+ this.inExperiment('compilerTestExperimentParse', pcx);
1352
+ return this.astAt(new ast.ExperimentalExperiment('compilerTestExperimentTranslate'), pcx);
1353
+ }
1342
1354
  }
1343
1355
  exports.MalloyToAST = MalloyToAST;
1344
1356
  //# sourceMappingURL=malloy-to-ast.js.map
@@ -86,6 +86,7 @@ declare class HelpContextStep implements TranslationStep {
86
86
  declare class TranslateStep implements TranslationStep {
87
87
  readonly astStep: ASTStep;
88
88
  response?: TranslateResponse;
89
+ importedFlags: boolean;
89
90
  constructor(astStep: ASTStep);
90
91
  step(that: MalloyTranslation, extendingModel?: ModelDef): TranslateResponse;
91
92
  }
@@ -100,6 +101,7 @@ export declare abstract class MalloyTranslation {
100
101
  sqlBlocks: SQLBlockStructDef[];
101
102
  modelDef: ModelDef;
102
103
  imports: ImportLocation[];
104
+ compilerFlags: Tag;
103
105
  readonly parseStep: ParseStep;
104
106
  readonly importsAndTablesStep: ImportsAndTablesStep;
105
107
  readonly astStep: ASTStep;
@@ -166,7 +168,6 @@ export declare class MalloyTranslator extends MalloyTranslation {
166
168
  importZone: Zone<string>;
167
169
  sqlQueryZone: Zone<SQLBlockStructDef>;
168
170
  logger: MessageLog;
169
- compilerFlags: Tag;
170
171
  readonly root: MalloyTranslator;
171
172
  constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null);
172
173
  update(dd: ParseUpdate): void;
@@ -291,9 +291,9 @@ class ASTStep {
291
291
  if (!parse) {
292
292
  throw new Error('TRANSLATOR INTERNAL ERROR: Translator parse response had no errors, but also no parser');
293
293
  }
294
- const secondPass = new malloy_to_ast_1.MalloyToAST(parse, that.root.logger);
294
+ const secondPass = new malloy_to_ast_1.MalloyToAST(parse, that.root.logger, that.compilerFlags);
295
295
  const newAst = secondPass.visit(parse.root);
296
- that.root.compilerFlags = secondPass.compilerFlags;
296
+ that.compilerFlags = secondPass.compilerFlags;
297
297
  if (that.root.logger.hasErrors()) {
298
298
  this.response = that.fatalResponse();
299
299
  return this.response;
@@ -450,11 +450,20 @@ class HelpContextStep {
450
450
  class TranslateStep {
451
451
  constructor(astStep) {
452
452
  this.astStep = astStep;
453
+ this.importedFlags = false;
453
454
  }
454
455
  step(that, extendingModel) {
455
456
  if (this.response) {
456
457
  return this.response;
457
458
  }
459
+ // begin with the compiler flags of the model we are extending
460
+ if (extendingModel && !this.importedFlags) {
461
+ const tagParse = tags_1.Tag.annotationToTag(extendingModel.annotation, {
462
+ prefix: /^##! /,
463
+ });
464
+ that.compilerFlags = tagParse.tag;
465
+ this.importedFlags = true;
466
+ }
458
467
  const astResponse = this.astStep.step(that);
459
468
  if ((0, translate_response_1.isNeedResponse)(astResponse)) {
460
469
  return astResponse;
@@ -513,6 +522,7 @@ class MalloyTranslation {
513
522
  this.queryList = [];
514
523
  this.sqlBlocks = [];
515
524
  this.imports = [];
525
+ this.compilerFlags = new tags_1.Tag();
516
526
  this.childTranslators = new Map();
517
527
  this.modelDef = {
518
528
  name: sourceURL,
@@ -767,7 +777,6 @@ class MalloyTranslator extends MalloyTranslation {
767
777
  this.importZone = new zone_1.Zone();
768
778
  this.sqlQueryZone = new zone_1.Zone();
769
779
  this.logger = new parse_log_1.MessageLog();
770
- this.compilerFlags = new tags_1.Tag();
771
780
  this.root = this;
772
781
  if (preload) {
773
782
  this.update(preload);
@@ -59,6 +59,18 @@ describe('model statements', () => {
59
59
  test('errors on redefinition of query', () => {
60
60
  expect('query: q1 is a -> { select: * }, q1 is a -> { select: * }').translationToFailWith("'q1' is already defined, cannot redefine");
61
61
  });
62
+ test('##! experimental enables all experiments', () => {
63
+ expect('##! experimental\n;;[ "x" ]').toTranslate();
64
+ });
65
+ test('experimental explicit enable', () => {
66
+ expect('##! experimental { compilerTestExperimentParse compilerTestExperimentTranslate }\n;;[ "x" ]').toTranslate();
67
+ });
68
+ test('experiment failures in parse are flagged', () => {
69
+ expect(';;[ "x" ]').translationToFailWith("Experimental flag 'compilerTestExperimentParse' required to enable this feature");
70
+ });
71
+ test('experiment failures in second pass are flagged', () => {
72
+ expect('##! experimental.compilerTestExperimentParse\n;;[ "x" ]').translationToFailWith("Experimental flag 'compilerTestExperimentTranslate' is not set, feature not available");
73
+ });
62
74
  });
63
75
  describe('error handling', () => {
64
76
  test('field and query with same name does not overflow', () => {
package/dist/tags.d.ts CHANGED
@@ -29,8 +29,9 @@ export interface Taggable {
29
29
  * tag.numeric(p?) => numeric value of tag.p or undefined
30
30
  * tag.textArray(p ?) => string[] value of elements in tag.p or undefined
31
31
  * tag.numericArray(p?) => string[] value of elements in tag.p or undefined
32
- * tag.tag(p) => Tag value of tag.p
33
- * tag.has(p) => boolean "tag contains tag.p"
32
+ * tag.tag(p?) => Tag value of tag.p
33
+ * tag.has(p?) => boolean "tag contains tag.p"
34
+ * tag.bare(p?) => tag.p exists and has no properties
34
35
  * tag.dict => Record<string,Tag> of tag properties
35
36
  * ```
36
37
  */
@@ -60,6 +61,7 @@ export declare class Tag implements TagInterface {
60
61
  has(...at: string[]): boolean;
61
62
  text(...at: string[]): string | undefined;
62
63
  numeric(...at: string[]): number | undefined;
64
+ bare(...at: string[]): boolean | undefined;
63
65
  get dict(): Record<string, Tag>;
64
66
  array(...at: string[]): Tag[] | undefined;
65
67
  textArray(...at: string[]): string[] | undefined;
package/dist/tags.js CHANGED
@@ -42,8 +42,9 @@ const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
42
42
  * tag.numeric(p?) => numeric value of tag.p or undefined
43
43
  * tag.textArray(p ?) => string[] value of elements in tag.p or undefined
44
44
  * tag.numericArray(p?) => string[] value of elements in tag.p or undefined
45
- * tag.tag(p) => Tag value of tag.p
46
- * tag.has(p) => boolean "tag contains tag.p"
45
+ * tag.tag(p?) => Tag value of tag.p
46
+ * tag.has(p?) => boolean "tag contains tag.p"
47
+ * tag.bare(p?) => tag.p exists and has no properties
47
48
  * tag.dict => Record<string,Tag> of tag properties
48
49
  * ```
49
50
  */
@@ -188,6 +189,13 @@ class Tag {
188
189
  }
189
190
  }
190
191
  }
192
+ bare(...at) {
193
+ const p = this.find(at);
194
+ if (p === undefined) {
195
+ return;
196
+ }
197
+ return (p.properties === undefined || Object.entries(p.properties).length === 0);
198
+ }
191
199
  get dict() {
192
200
  const newDict = {};
193
201
  if (this.properties) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.96-dev231025212541",
3
+ "version": "0.0.96-dev231025215721",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",