antlr | test select jison on some quake 3 C code | antlr to html | Search

This code is designed to parse a directory structure for grammar files and extract language information for a parser generator tool, likely ANTLR. It utilizes two key functions: findGrammars(directory) to recursively extract language information from grammar files, and getParser(language) to search for corresponding parser files.

Run example

npm run import -- "get antlr tool"

get antlr tool

import fs from 'fs'
import path from 'path'

const PARSER_PATH = path.join(__dirname, '../Resources/Parsers')
const LANGUAGES = []
const GRAMMARS = []

function findGrammars(directory) {
    let grammars = fs.readdirSync(path.join(PARSER_PATH, directory))
    for(let j = 0; j < grammars.length; j++) {
        if(grammars[j][0] == '.' || grammars[j].match('examples')) {
            continue
        }
        if(grammars[j].endsWith('.g4')) {
            let language = path.basename(grammars[j], path.extname(grammars[j]))
                .replace('Lexer', '').replace('Parser', '')
            if(!LANGUAGES.includes(directory)) {
                LANGUAGES.push(directory)
            }
            if(!LANGUAGES.includes(language)) {
                LANGUAGES.push(language)
            }

            GRAMMARS.push(path.join(directory, grammars[j]))
        } else if (fs.statSync(path.join(PARSER_PATH, directory, grammars[j])).isDirectory()) {
            findGrammars(path.join(directory, grammars[j]))
        }
    }
}

let languages = fs.readdirSync(PARSER_PATH)
for(let i = 0; i < languages.length; i++) {
    if(languages[i][0] == '.') {
        continue
    }
    if(!fs.statSync(path.join(PARSER_PATH, languages[i])).isDirectory()) {
        continue
    }
    findGrammars(languages[i])
}

async function getParser(language) {
    for(let i = 0; i < GRAMMARS.length; i++) {
        if(GRAMMARS[i].match(language + '/') || GRAMMARS[i].match('/' + language)) {
            let lang = path.basename(GRAMMARS[i], path.extname(GRAMMARS[i]))
                .replace('Lexer', '').replace('Parser', '')
            let lexerPath = path.join(PARSER_PATH, path.dirname(GRAMMARS[i]), lang + 'Lexer.js')
            let parserPath = path.join(PARSER_PATH, path.dirname(GRAMMARS[i]), lang + 'Parser.js')
            let listenerPath = path.join(PARSER_PATH, path.dirname(GRAMMARS[i]), lang + 'Listener.js')
            if(!fs.existsSync(listenerPath)) {
                listenerPath = path.join(PARSER_PATH, path.dirname(GRAMMARS[i]), lang + 'ParserListener.js')
            }
            let hasListener = fs.existsSync(listenerPath)
            console.log(language, lexerPath, parserPath)
            if(!fs.existsSync(lexerPath) || !fs.existsSync(parserPath)) {
                continue
            }
            let codeCell = `
import antlr4 from 'antlr4'
import lexer from '${lexerPath}'
import parser from '${parserPath}'
${hasListener?('import listener from \''+listenerPath+'\''):''}
export default {antlr4, lexer, parser${hasListener?', listener':''}}
`
            let module = await importer.makeESModule(codeCell, __filename + '<inline>', global)
            return module
        }
    }
    return {}
}

export default getParser

What the code could have been:

import path from 'path';
import fs from 'fs';
import { importESModule } from 'import-ES-module';

const parserPath = path.join(__dirname, '../Resources/Parsers');
const languages = [];
const grammars = [];

/**
 * Recursively finds grammars in the given directory.
 * @param {string} directory The current directory to search.
 */
async function findGrammars(directory) {
  try {
    const files = await fs.promises.readdir(path.join(parserPath, directory));
    for (const file of files) {
      if (file.startsWith('.') || file.includes('examples')) {
        continue;
      }
      if (file.endsWith('.g4')) {
        const language = file.replace('Lexer', '').replace('Parser', '');
        if (!languages.includes(directory)) {
          languages.push(directory);
        }
        if (!languages.includes(language)) {
          languages.push(language);
        }

        grammars.push(path.join(directory, file));
      } else if ((await fs.promises.stat(path.join(parserPath, directory, file))).isDirectory()) {
        await findGrammars(path.join(directory, file));
      }
    }
  } catch (error) {
    console.error(`Error reading directory ${directory}:`, error);
  }
}

/**
 * Finds all grammars in the parser path.
 */
async function initializeGrammars() {
  try {
    const directories = await fs.promises.readdir(parserPath);
    for (const directory of directories) {
      if (directory.startsWith('.') ||!(await fs.promises.stat(path.join(parserPath, directory))).isDirectory()) {
        continue;
      }
      await findGrammars(directory);
    }
  } catch (error) {
    console.error(`Error reading parser path:`, error);
  }
}

/**
 * Gets the parser for the given language.
 * @param {string} language The language to get the parser for.
 * @returns {object} The parser object, or an empty object if not found.
 */
async function getParser(language) {
  try {
    for (const grammar of grammars) {
      if (grammar.includes(language + '/') || grammar.includes('/' + language)) {
        const lang = path.basename(grammar, path.extname(grammar)).replace('Lexer', '').replace('Parser', '');
        const lexerPath = path.join(parserPath, path.dirname(grammar), lang + 'Lexer.js');
        const parserPath = path.join(parserPath, path.dirname(grammar), lang + 'Parser.js');
        const listenerPath = path.join(parserPath, path.dirname(grammar), lang + 'Listener.js');
        const hasListener = await fs.promises.exists(listenerPath);
        if (!hasListener) {
          listenerPath = path.join(parserPath, path.dirname(grammar), lang + 'ParserListener.js');
        }
        const codeCell = `
import antlr4 from 'antlr4';
import lexer from '${lexerPath}';
import parser from '${parserPath}';
${hasListener? 'import listener from \'' + listenerPath + '\'' : ''}
export default { antlr4, lexer, parser${hasListener? ', listener' : ''} }
`;
        const module = await importESModule(codeCell, __filename + '', global);
        return module;
      }
    }
    return {};
  } catch (error) {
    console.error(`Error getting parser for language ${language}:`, error);
    return {};
  }
}

await initializeGrammars();

export default getParser;

Code Breakdown

Overview

This code is used to parse a directory structure for grammar files and extract language information. It appears to be designed for a parser generator tool, likely ANTLR.

Directory Structure

The code assumes the following directory structure:

Resources/
  Parsers/
    Language1/
      Language1.g4
      Language1Lexer.js
      Language1Parser.js
      Language1Listener.js
    Language2/
      Language2.g4
      Language2Lexer.js
      Language2Parser.js
      Language2Listener.js
   ...

Functions

findGrammars(directory)

This function recursively traverses the directory structure and extracts language information from grammar files (*.g4).

getParser(language)

This function searches for the parser files corresponding to the given language.

Main Logic

The code first reads the top-level Parsers directory and calls findGrammars(directory) for each subdirectory. Then, it calls getParser(language) for each language in the LANGUAGES array.