Przeglądaj źródła

HUE-8763 [autocomplete] Add definitions to the autocomplete parse results

This adds a new property "definitions" that contain information about entities added with CREATE statements
Johan Ahlen 6 lat temu
rodzic
commit
f0d5737482

+ 22 - 7
desktop/core/src/desktop/js/parse/jison/sql_create.jison

@@ -60,6 +60,9 @@ CreateStatement_EDIT
 DatabaseDefinition
  : AnyCreate DatabaseOrSchema OptionalIfNotExists
  | AnyCreate DatabaseOrSchema OptionalIfNotExists RegularIdentifier DatabaseDefinitionOptionals
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
  ;
 
 DatabaseDefinition_EDIT
@@ -75,9 +78,16 @@ DatabaseDefinition_EDIT
      if (!$3) {
        parser.suggestKeywords(['IF NOT EXISTS']);
      }
+     parser.addNewDatabaseLocation(@5, [{ name: $5 }]);
    }
  | AnyCreate DatabaseOrSchema OptionalIfNotExists_EDIT RegularIdentifier
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
  | AnyCreate DatabaseOrSchema OptionalIfNotExists RegularIdentifier DatabaseDefinitionOptionals 'CURSOR'
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
  ;
 
 DatabaseDefinitionOptionals
@@ -303,7 +313,11 @@ TableDefinitionRightPart_EDIT
  ;
 
 TableIdentifierAndOptionalColumnSpecification
- : SchemaQualifiedIdentifier OptionalColumnSpecificationsOrLike  -> $2
+ : SchemaQualifiedIdentifier OptionalColumnSpecificationsOrLike
+   {
+     parser.addNewTableLocation(@1, $1, $2);
+     $$ = $2;
+   }
  ;
 
 TableIdentifierAndOptionalColumnSpecification_EDIT
@@ -314,8 +328,8 @@ TableIdentifierAndOptionalColumnSpecification_EDIT
 OptionalColumnSpecificationsOrLike
  :
  | ParenthesizedColumnSpecificationList
- | '<impala>LIKE_PARQUET' HdfsPath
- | 'LIKE' SchemaQualifiedTableIdentifier
+ | '<impala>LIKE_PARQUET' HdfsPath          -> []
+ | 'LIKE' SchemaQualifiedTableIdentifier    -> []
  ;
 
 OptionalColumnSpecificationsOrLike_EDIT
@@ -333,8 +347,8 @@ OptionalColumnSpecificationsOrLike_EDIT
  ;
 
 ParenthesizedColumnSpecificationList
- : '(' ColumnSpecificationList ')'
- | '(' ColumnSpecificationList ',' ConstraintSpecification ')'
+ : '(' ColumnSpecificationList ')'                              -> $2
+ | '(' ColumnSpecificationList ',' ConstraintSpecification ')'  -> $2
  ;
 
 ParenthesizedColumnSpecificationList_EDIT
@@ -351,8 +365,8 @@ ParenthesizedColumnSpecificationList_EDIT
  ;
 
 ColumnSpecificationList
- : ColumnSpecification
- | ColumnSpecificationList ',' ColumnSpecification                                        -> $3
+ : ColumnSpecification                              -> [$1]
+ | ColumnSpecificationList ',' ColumnSpecification  -> $1.concat($3)
  ;
 
 ColumnSpecificationList_EDIT
@@ -382,6 +396,7 @@ ColumnSpecification
  : ColumnIdentifier ColumnDataType OptionalColumnOptions
    {
      $$ = $1;
+     $$.type = $2;
      var keywords = [];
      if (parser.isImpala()) {
        if (!$3['primary']) {

+ 2 - 2
desktop/core/src/desktop/js/parse/jison/sql_main.jison

@@ -1347,8 +1347,8 @@ ImpalaField_EDIT
  ;
 
 SchemaQualifiedIdentifier
- : RegularOrBacktickedIdentifier
- | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier
+ : RegularOrBacktickedIdentifier                                       -> [{ name: $1 }]
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier  -> [{ name: $1 }, { name: $2 }]
  ;
 
 SchemaQualifiedIdentifier_EDIT

+ 73 - 1
desktop/core/src/desktop/js/parse/spec/sqlAutocompleteParser_Locations_Spec.js

@@ -32,7 +32,8 @@ describe('sqlAutocompleteParser.js locations', () => {
       afterCursor: options.afterCursor || '',
       locationsOnly: true,
       noErrors: true,
-      expectedLocations: options.expectedLocations
+      expectedLocations: options.expectedLocations,
+      expectedDefinitions: options.expectedDefinitions
     });
   };
 
@@ -1857,6 +1858,65 @@ describe('sqlAutocompleteParser.js locations', () => {
     });
   });
 
+  it('should report definitions for "CREATE DATABASE boo; |"', () => {
+    assertLocations({
+      dialect: 'impala',
+      beforeCursor: "CREATE DATABASE boo;",
+      expectedLocations: [
+        {
+          type: 'statement',
+          location: { first_line: 1, last_line: 1, first_column: 1, last_column: 20 }
+        }, {
+          type: 'statementType',
+          location: { first_line: 1, last_line: 1, first_column: 1, last_column: 7 },
+          identifier: 'CREATE DATABASE'
+        }
+      ],
+      expectedDefinitions: [{
+        type: 'database',
+        location: { first_line: 1, last_line: 1, first_column: 17, last_column: 20 },
+        identifierChain: [{ name: 'boo' }]
+      }]
+    });
+  });
+
+  it('should report definitions for "CREATE TABLE boo (id int, foo bigint, bar varchar); |"', () => {
+    assertLocations({
+      dialect: 'impala',
+      beforeCursor: "CREATE TABLE boo (id int, foo bigint, bar string);",
+      expectedLocations: [
+        {
+          type: 'statement',
+          location: { first_line: 1, last_line: 1, first_column: 1, last_column: 50 }
+        }, {
+          type: 'statementType',
+          location: { first_line: 1, last_line: 1, first_column: 1, last_column: 7 },
+          identifier: 'CREATE TABLE'
+        }
+      ],
+      expectedDefinitions: [
+        {
+          type: 'table',
+          location: { first_line: 1, last_line: 1, first_column: 14, last_column: 17 },
+          identifierChain: [{ name: 'boo' }],
+          columns: [{
+            identifierChain: [{ name: 'id' }],
+            type: 'int',
+            location: { first_line: 1, last_line: 1, first_column: 19, last_column: 21 }
+          }, {
+            identifierChain: [{ name: 'foo' }],
+            type: 'bigint',
+            location: { first_line: 1, last_line: 1, first_column: 27, last_column: 30 }
+          }, {
+            identifierChain: [{ name: 'bar' }],
+            type: 'string',
+            location: { first_line: 1, last_line: 1, first_column: 39, last_column: 42 }
+          }]
+        }
+      ]
+    });
+  });
+
   describe('File paths', () => {
     it('should report locations for "LOAD DATA LOCAL INPATH \'/some/path/file.ble\' OVERWRITE INTO TABLE bla; |"', () => {
       assertLocations({
@@ -1900,6 +1960,18 @@ describe('sqlAutocompleteParser.js locations', () => {
             location: { first_line: 1, last_line: 1, first_column: 37, last_column: 46 },
             path: '/bla/bla/'
           }
+        ],
+        expectedDefinitions: [
+          {
+            type: 'table',
+            location: { first_line: 1, last_line: 1, first_column: 14, last_column: 17 },
+            identifierChain: [{ name: 'bla' }],
+            columns: [{
+              identifierChain: [{ name: 'id' }],
+              type: 'INT',
+              location: { first_line: 1, last_line: 1, first_column: 19, last_column: 21 }
+            }]
+          }
         ]
       });
     });

+ 27 - 1
desktop/core/src/desktop/js/parse/spec/sqlTestUtils.js

@@ -36,7 +36,8 @@ const resultEquals = function(a, b) {
     }
     return true;
   } else {
-    return jasmine.matchersUtil.equals(a, b);
+    // TODO: Jasmine version?
+    return jasmine.jasmine.matchersUtil.equals(a, b);
   }
 };
 
@@ -96,6 +97,31 @@ const testUtils = {
             });
           }
 
+          if (testDefinition.expectedDefinitions) {
+            if (!resultEquals(actualResponse.definitions, testDefinition.expectedDefinitions)) {
+              return {
+                pass: false,
+                message:
+                  '\n        Statement: ' +
+                  testDefinition.beforeCursor +
+                  '|' +
+                  testDefinition.afterCursor +
+                  '\n' +
+                  '          Dialect: ' +
+                  testDefinition.dialect +
+                  '\n' +
+                  'Expected definitions: ' +
+                  jsonStringToJsString(JSON.stringify(testDefinition.expectedDefinitions)) +
+                  '\n' +
+                  '  Parser definitions: ' +
+                  jsonStringToJsString(JSON.stringify(actualResponse.definitions)) +
+                  '\n'
+              };
+            }
+          } else {
+            delete actualResponse.definitions;
+          }
+
           if (testDefinition.locationsOnly) {
             return {
               pass: resultEquals(actualResponse.locations, testDefinition.expectedLocations),

+ 39 - 7
desktop/core/src/desktop/js/parse/sqlAutocompleteParser.js

@@ -165,7 +165,7 @@ case 736:
      }
    
 break;
-case 809: case 812: case 917: case 958: case 1050: case 1292: case 1475: case 1587: case 1645: case 2826: case 2828: case 3329:
+case 809: case 812: case 917: case 958: case 1050: case 1292: case 1475: case 1587: case 1645: case 2375: case 2826: case 2828: case 3329:
 this.$ = $$[$0-1];
 break;
 case 810: case 813: case 959:
@@ -256,7 +256,7 @@ case 913:
      parser.suggestTables({ identifierChain: [{ name: $$[$0-3] }, { name: $$[$0-1] }].concat($$[$0]) });
    
 break;
-case 914: case 1092:
+case 914: case 1092: case 2380:
 this.$ = [$$[$0]];
 break;
 case 915:
@@ -264,7 +264,7 @@ case 915:
      $$[$0-1].push($$[$0]);
    
 break;
-case 916: case 919:
+case 916: case 919: case 2369: case 2370:
 this.$ = [];
 break;
 case 918: case 1052: case 1477:
@@ -273,6 +273,12 @@ break;
 case 920:
 this.$ = { name: $$[$0] };
 break;
+case 922:
+this.$ = [{ name: $$[$0] }];
+break;
+case 923:
+this.$ = [{ name: $$[$0-2] }, { name: $$[$0-1] }];
+break;
 case 924: case 1995: case 2228:
 
      parser.suggestDatabases({ appendDot: true });
@@ -701,7 +707,7 @@ case 1086:
      parser.selectListNoTableSuggest($$[$0-1], $$[$0-3]);
    
 break;
-case 1090: case 1166: case 1197: case 1210: case 1214: case 1252: case 1256: case 1284: case 1310: case 1311: case 1392: case 1394: case 1462: case 1472: case 1479: case 1491: case 1673: case 1873: case 1874: case 1899: case 1900: case 1901: case 2189: case 2364: case 2381: case 3349: case 3663:
+case 1090: case 1166: case 1197: case 1210: case 1214: case 1252: case 1256: case 1284: case 1310: case 1311: case 1392: case 1394: case 1462: case 1472: case 1479: case 1491: case 1673: case 1873: case 1874: case 1899: case 1900: case 1901: case 2189: case 3349: case 3663:
 this.$ = $$[$0];
 break;
 case 1093:
@@ -2979,6 +2985,17 @@ case 1913:
      if (!$$[$0-2]) {
        parser.suggestKeywords(['IF NOT EXISTS']);
      }
+     parser.addNewDatabaseLocation(_$[$0], [{ name: $$[$0] }]);
+   
+break;
+case 1914:
+
+     parser.addNewDatabaseLocation(_$[$0], [{ name: $$[$0] }]);
+   
+break;
+case 1915:
+
+     parser.addNewDatabaseLocation(_$[$0-2], [{ name: $$[$0-2] }]);
    
 break;
 case 1930:
@@ -3643,6 +3660,11 @@ case 2316:
        parser.suggestKeywords(['DATABASE', 'ROLE', 'SCHEMA', 'TABLE', 'VIEW']);
      }
    
+break;
+case 2318:
+
+     parser.addNewDatabaseLocation(_$[$0-1], [{ name: $$[$0-1] }]);
+   
 break;
 case 2319:
 
@@ -3733,6 +3755,12 @@ case 2363:
        parser.suggestKeywords(keywords);
      }
    
+break;
+case 2364:
+
+     this.$ = $$[$0];
+     parser.addNewTableLocation(_$[$0-1], $$[$0-1], $$[$0]);
+   
 break;
 case 2373:
 
@@ -3742,6 +3770,9 @@ case 2373:
        parser.suggestKeywords(['PARQUET']);
      }
    
+break;
+case 2376: case 2827: case 2829:
+this.$ = $$[$0-3];
 break;
 case 2379:
 
@@ -3751,6 +3782,9 @@ case 2379:
        parser.suggestKeywords([{ value: 'PRIMARY KEY', weight: 2 }, { value: 'CONSTRAINT', weight: 1 }]);
      }
    
+break;
+case 2381:
+this.$ = $$[$0-2].concat($$[$0]);
 break;
 case 2386: case 2388: case 2598:
 
@@ -3765,6 +3799,7 @@ break;
 case 2390:
 
      this.$ = $$[$0-2];
+     this.$.type = $$[$0-1];
      var keywords = [];
      if (parser.isImpala()) {
        if (!$$[$0]['primary']) {
@@ -4192,9 +4227,6 @@ case 2823:
        parser.suggestKeywords(['COMMENT']);
      }
    
-break;
-case 2827: case 2829:
-this.$ = $$[$0-3];
 break;
 case 2835:
 

+ 76 - 45
desktop/core/src/desktop/js/parse/sqlParseSupport.js

@@ -2170,6 +2170,33 @@ const initSqlParser = function(parser) {
     return loc;
   };
 
+  parser.addNewDatabaseLocation = function (location, identifierChain) {
+    parser.yy.definitions.push({
+      type: 'database',
+      location: adjustLocationForCursor(location),
+      identifierChain: identifierChain
+    })
+  };
+
+  parser.addNewTableLocation = function (location, identifierChain, colSpec) {
+    var columns = [];
+    if (colSpec) {
+      colSpec.forEach(function (col) {
+        columns.push({
+          identifierChain: [ col.identifier ], // TODO: Complex
+          type: col.type,
+          location: adjustLocationForCursor(col.location)
+        })
+      })
+    }
+    parser.yy.definitions.push({
+      type: 'table',
+      location: adjustLocationForCursor(location),
+      identifierChain: identifierChain,
+      columns: columns
+    });
+  };
+
   parser.addColRefToVariableIfExists = function(left, right) {
     if (
       left &&
@@ -2269,6 +2296,7 @@ const initSqlParser = function(parser) {
     parser.yy.result = { locations: [] };
     parser.yy.lowerCase = false;
     parser.yy.locations = [];
+    parser.yy.definitions = [];
     parser.yy.allLocations = [];
     parser.yy.subQueries = [];
     parser.yy.errors = [];
@@ -2388,6 +2416,7 @@ const initSqlParser = function(parser) {
       return b.type.localeCompare(a.type);
     });
     parser.yy.result.locations = parser.yy.allLocations;
+    parser.yy.result.definitions = parser.yy.definitions;
 
     parser.yy.result.locations.forEach(location => {
       delete location.linked;
@@ -2452,62 +2481,64 @@ const initSqlParser = function(parser) {
 };
 
 const SYNTAX_PARSER_NOOP_FUNCTIONS = [
-  'prepareNewStatement',
-  'addCommonTableExpressions',
-  'pushQueryState',
-  'popQueryState',
-  'suggestSelectListAliases',
-  'suggestValueExpressionKeywords',
-  'getSelectListKeywords',
-  'getValueExpressionKeywords',
+  'addAsteriskLocation',
+  'addClauseLocation',
   'addColRefIfExists',
-  'selectListNoTableSuggest',
-  'suggestJoinConditions',
-  'suggestJoins',
-  'valueExpressionSuggest',
-  'applyTypeToSuggestions',
+  'addColRefToVariableIfExists',
+  'addColumnAliasLocation',
+  'addColumnLocation',
+  'addCommonTableExpressions',
+  'addCteAliasLocation',
+  'addDatabaseLocation',
+  'addFileLocation',
+  'addFunctionLocation',
+  'addNewDatabaseLocation',
+  'addNewTableLocation',
+  'addStatementLocation',
+  'addStatementTypeLocation',
+  'addSubqueryAliasLocation',
+  'addTableAliasLocation',
+  'addTableLocation',
+  'addTablePrimary',
+  'addUnknownLocation',
+  'addVariableLocation',
   'applyArgumentTypesToSuggestions',
+  'applyTypeToSuggestions',
+  'checkForKeywords',
+  'checkForSelectListKeywords',
   'commitLocations',
-  'identifyPartials',
+  'firstDefined',
+  'getSelectListKeywords',
   'getSubQuery',
-  'addTablePrimary',
-  'suggestFileFormats',
-  'suggestDdlAndDmlKeywords',
-  'checkForSelectListKeywords',
-  'checkForKeywords',
-  'suggestKeywords',
-  'suggestColRefKeywords',
-  'suggestTablesOrColumns',
-  'suggestFunctions',
+  'getValueExpressionKeywords',
+  'identifyPartials',
+  'popQueryState',
+  'prepareNewStatement',
+  'pushQueryState',
+  'selectListNoTableSuggest',
   'suggestAggregateFunctions',
   'suggestAnalyticFunctions',
+  'suggestColRefKeywords',
   'suggestColumns',
+  'suggestDatabases',
+  'suggestDdlAndDmlKeywords',
+  'suggestFileFormats',
+  'suggestFilters',
+  'suggestFunctions',
   'suggestGroupBys',
+  'suggestHdfs',
   'suggestIdentifiers',
-  'suggestOrderBys',
-  'suggestFilters',
+  'suggestJoinConditions',
+  'suggestJoins',
   'suggestKeyValues',
+  'suggestKeywords',
+  'suggestOrderBys',
+  'suggestSelectListAliases',
   'suggestTables',
-  'addFunctionLocation',
-  'addStatementLocation',
-  'firstDefined',
-  'addClauseLocation',
-  'addStatementTypeLocation',
-  'addFileLocation',
-  'addDatabaseLocation',
-  'addColumnAliasLocation',
-  'addTableAliasLocation',
-  'addSubqueryAliasLocation',
-  'addTableLocation',
-  'addAsteriskLocation',
-  'addVariableLocation',
-  'addColumnLocation',
-  'addCteAliasLocation',
-  'addUnknownLocation',
-  'addColRefToVariableIfExists',
-  'suggestDatabases',
-  'suggestHdfs',
-  'suggestValues'
+  'suggestTablesOrColumns',
+  'suggestValueExpressionKeywords',
+  'suggestValues',
+  'valueExpressionSuggest'
 ];
 
 const SYNTAX_PARSER_NOOP = function() {};

+ 39 - 7
desktop/core/src/desktop/js/parse/sqlSyntaxParser.js

@@ -165,7 +165,7 @@ case 733:
      }
    
 break;
-case 806: case 809: case 914: case 955: case 1047: case 1254: case 1437: case 1546: case 1604: case 2764: case 2766: case 3267:
+case 806: case 809: case 914: case 955: case 1047: case 1254: case 1437: case 1546: case 1604: case 2313: case 2764: case 2766: case 3267:
 this.$ = $$[$0-1];
 break;
 case 807: case 810: case 956:
@@ -256,7 +256,7 @@ case 910:
      parser.suggestTables({ identifierChain: [{ name: $$[$0-3] }, { name: $$[$0-1] }].concat($$[$0]) });
    
 break;
-case 911: case 1085:
+case 911: case 1085: case 2318:
 this.$ = [$$[$0]];
 break;
 case 912:
@@ -264,7 +264,7 @@ case 912:
      $$[$0-1].push($$[$0]);
    
 break;
-case 913: case 916:
+case 913: case 916: case 2307: case 2308:
 this.$ = [];
 break;
 case 915: case 1049: case 1439:
@@ -273,6 +273,12 @@ break;
 case 917:
 this.$ = { name: $$[$0] };
 break;
+case 919:
+this.$ = [{ name: $$[$0] }];
+break;
+case 920:
+this.$ = [{ name: $$[$0-2] }, { name: $$[$0-1] }];
+break;
 case 921: case 1928: case 2161:
 
      parser.suggestDatabases({ appendDot: true });
@@ -696,7 +702,7 @@ case 1080:
      parser.suggestDatabases({ prependFrom: true, appendDot: true });
    
 break;
-case 1083: case 1128: case 1159: case 1172: case 1176: case 1214: case 1218: case 1246: case 1272: case 1273: case 1354: case 1356: case 1424: case 1434: case 1441: case 1453: case 1632: case 1828: case 1829: case 2122: case 2302: case 2319: case 3287: case 3603:
+case 1083: case 1128: case 1159: case 1172: case 1176: case 1214: case 1218: case 1246: case 1272: case 1273: case 1354: case 1356: case 1424: case 1434: case 1441: case 1453: case 1632: case 1828: case 1829: case 2122: case 3287: case 3603:
 this.$ = $$[$0];
 break;
 case 1086:
@@ -3543,6 +3549,11 @@ case 2249:
        parser.suggestKeywords(['DATABASE', 'ROLE', 'SCHEMA', 'TABLE', 'VIEW']);
      }
    
+break;
+case 2251:
+
+     parser.addNewDatabaseLocation(_$[$0-1], [{ name: $$[$0-1] }]);
+   
 break;
 case 2252: case 2285:
 
@@ -3556,6 +3567,17 @@ case 2254:
      if (!$$[$0-2]) {
        parser.suggestKeywords(['IF NOT EXISTS']);
      }
+     parser.addNewDatabaseLocation(_$[$0], [{ name: $$[$0] }]);
+   
+break;
+case 2255:
+
+     parser.addNewDatabaseLocation(_$[$0], [{ name: $$[$0] }]);
+   
+break;
+case 2256:
+
+     parser.addNewDatabaseLocation(_$[$0-2], [{ name: $$[$0-2] }]);
    
 break;
 case 2257:
@@ -3647,6 +3669,12 @@ case 2301:
        parser.suggestKeywords(keywords);
      }
    
+break;
+case 2302:
+
+     this.$ = $$[$0];
+     parser.addNewTableLocation(_$[$0-1], $$[$0-1], $$[$0]);
+   
 break;
 case 2311:
 
@@ -3656,6 +3684,9 @@ case 2311:
        parser.suggestKeywords(['PARQUET']);
      }
    
+break;
+case 2314: case 2765: case 2767:
+this.$ = $$[$0-3];
 break;
 case 2317:
 
@@ -3665,6 +3696,9 @@ case 2317:
        parser.suggestKeywords([{ value: 'PRIMARY KEY', weight: 2 }, { value: 'CONSTRAINT', weight: 1 }]);
      }
    
+break;
+case 2319:
+this.$ = $$[$0-2].concat($$[$0]);
 break;
 case 2324: case 2326: case 2536:
 
@@ -3679,6 +3713,7 @@ break;
 case 2328:
 
      this.$ = $$[$0-2];
+     this.$.type = $$[$0-1];
      var keywords = [];
      if (parser.isImpala()) {
        if (!$$[$0]['primary']) {
@@ -4106,9 +4141,6 @@ case 2761:
        parser.suggestKeywords(['COMMENT']);
      }
    
-break;
-case 2765: case 2767:
-this.$ = $$[$0-3];
 break;
 case 2773:
 

+ 2 - 1
desktop/core/src/desktop/js/spec/globalJsConstants.js

@@ -18,7 +18,8 @@ const globalVars = {
   LOGGED_USERNAME: 'foo',
   CACHEABLE_TTL: 1,
   HAS_OPTIMIZER: false,
-  AUTOCOMPLETE_TIMEOUT: 1
+  AUTOCOMPLETE_TIMEOUT: 1,
+  HUE_I18n: {}
 };
 
 Object.keys(globalVars).forEach(key => {

+ 5 - 2
tools/jison/generateParsers.js

@@ -123,7 +123,7 @@ const deleteFile = (path) => {
 const execCmd = (cmd) => new Promise((resolve, reject) => {
   exec(cmd, function(err, stdout, stderr) {
     if (err) {
-      reject();
+      reject(stderr);
     }
     resolve();
   });
@@ -217,7 +217,10 @@ const generateRecursive = () => {
     } else {
       console.log('Generating \'' + parserName + '\'...');
     }
-    generateParser(parserName).then(generateRecursive)
+    generateParser(parserName).then(generateRecursive).catch(error => {
+      console.log(error);
+      console.log('FAIL!');
+    })
   }
 };