/**
   * This function is supposed to be called directly only from PydmlSyntacticValidator when it
   * encounters 'import'
   *
   * @param fileName
   * @return null if atleast one error
   */
  public DMLProgram doParse(String fileName, String dmlScript, HashMap<String, String> argVals)
      throws ParseException {
    DMLProgram dmlPgm = null;

    ANTLRInputStream in;
    try {
      if (dmlScript == null) {
        dmlScript = DMLParserWrapper.readDMLScript(fileName);
      }

      InputStream stream = new ByteArrayInputStream(dmlScript.getBytes());
      in = new org.antlr.v4.runtime.ANTLRInputStream(stream);
      //			else {
      //				if(!(new File(fileName)).exists()) {
      //					throw new ParseException("ERROR: Cannot open file:" + fileName);
      //				}
      //				in = new ANTLRInputStream(new FileInputStream(fileName));
      //			}
    } catch (FileNotFoundException e) {
      throw new ParseException("ERROR: Cannot find file:" + fileName);
    } catch (IOException e) {
      throw new ParseException("ERROR: Cannot open file:" + fileName);
    } catch (LanguageException e) {
      throw new ParseException("ERROR: " + e.getMessage());
    }

    PmlprogramContext ast = null;
    CustomDmlErrorListener errorListener = new CustomDmlErrorListener();

    try {
      PydmlLexer lexer = new PydmlLexer(in);
      CommonTokenStream tokens = new CommonTokenStream(lexer);
      PydmlParser antlr4Parser = new PydmlParser(tokens);

      boolean tryOptimizedParsing =
          false; // For now no optimization, since it is not able to parse integer value.

      if (tryOptimizedParsing) {
        // Try faster and simpler SLL
        antlr4Parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
        antlr4Parser.removeErrorListeners();
        antlr4Parser.setErrorHandler(new BailErrorStrategy());
        try {
          ast = antlr4Parser.pmlprogram();
          // If successful, no need to try out full LL(*) ... SLL was enough
        } catch (ParseCancellationException ex) {
          // Error occurred, so now try full LL(*) for better error messages
          tokens.reset();
          antlr4Parser.reset();
          if (fileName != null) {
            errorListener.pushCurrentFileName(fileName);
          } else {
            errorListener.pushCurrentFileName("MAIN_SCRIPT");
          }
          // Set our custom error listener
          antlr4Parser.addErrorListener(errorListener);
          antlr4Parser.setErrorHandler(new DefaultErrorStrategy());
          antlr4Parser.getInterpreter().setPredictionMode(PredictionMode.LL);
          ast = antlr4Parser.pmlprogram();
        }
      } else {
        // Set our custom error listener
        antlr4Parser.removeErrorListeners();
        antlr4Parser.addErrorListener(errorListener);
        errorListener.pushCurrentFileName(fileName);

        // Now do the parsing
        ast = antlr4Parser.pmlprogram();
      }
    } catch (Exception e) {
      throw new ParseException("ERROR: Cannot parse the program:" + fileName);
    }

    try {
      // Now convert the parse tree into DMLProgram
      // Do syntactic validation while converting
      ParseTree tree = ast;
      // And also do syntactic validation
      ParseTreeWalker walker = new ParseTreeWalker();
      PydmlSyntacticValidatorHelper helper = new PydmlSyntacticValidatorHelper(errorListener);
      PydmlSyntacticValidator validator = new PydmlSyntacticValidator(helper, fileName, argVals);
      walker.walk(validator, tree);
      errorListener.popFileName();
      if (errorListener.isAtleastOneError()) {
        return null;
      }
      dmlPgm = createDMLProgram(ast);
    } catch (Exception e) {
      throw new ParseException(
          "ERROR: Cannot translate the parse tree into DMLProgram:" + e.getMessage());
    }

    return dmlPgm;
  }