antlr | antlr to html | Cell 6 | Search

This code defines four functions for working with Abstract Syntax Trees (ASTs) generated by the ANTLR4TS parser generator, including functions for converting object types to strings, creating generic tokens and contexts, and generating generic visitors. The code exports a module containing a generic visitor function.

Run example

npm run import -- "antlr tree visitor"

antlr tree visitor

var {Interval} = require('antlr4ts/misc')

function typeToString(node) {
    if(node === 'object' && node) {
        return Object.getPrototypeOf(node).constructor.name;
    } else {
        return typeof node;
    }
}

function getGenericToken(parser, token) {
    if(!token) return
    return {
        type: 'TerminalNode',
    //    type2: parser.ruleNames[child._stop._type],
        value: token.source.stream.getText(Interval.of(token.start, token.stop)),
        range: [token.start, token.stop]
    }
}

function getGenericContext(ctx) {
    var exclude = [
        'constructor',
        'ruleIndex',
        'enterRule',
        'exitRule',
        'accept'
    ]
    var allTokens = Object.getOwnPropertyNames(Object.getPrototypeOf(ctx))
        .filter(t => exclude.indexOf(t) === -1)
    return allTokens.reduce((obj, cur) => {
        obj[cur] = ctx[cur]()
        return obj
    }, {})
}


function getGenericVisitor({parser, visitor}) {
    function GenericVisitor() {
    //    visitor.apply(this, arguments)
    }
    GenericVisitor.prototype = Object.create(visitor.prototype)
    GenericVisitor.prototype.constructor = GenericVisitor
    GenericVisitor.prototype.defaultResult = function () {
        return {children: []}
    }
    GenericVisitor.prototype.aggregateResult = (ctx, child) => {
        if(!Array.isArray(ctx)) ctx = ctx.children
        ctx[ctx.length] = child
        return ctx
    }
    GenericVisitor.prototype.visit = function (tree) {
        return tree.accept(this)
    }
    // TODO: combine range with return valuess
    GenericVisitor.prototype.visitTerminal = function (node) {
        return getGenericToken(parser, node._symbol)
    }
    GenericVisitor.prototype.visitChildren = function (ctx) {
        var result = visitor.prototype.visitChildren.apply(this, [ctx])
        return {
            type: Object.getPrototypeOf(ctx).constructor.name,
            children: result
        }
    }
    return {
        GenericVisitor
    }
}

module.exports = getGenericVisitor

What the code could have been:

const { Interval } = require('antlr4ts/misc');

/**
 * Returns the string representation of the provided node type.
 * If the node is an object, it returns the constructor name of the object's prototype.
 * Otherwise, it returns the type of the node.
 *
 * @param {object|string} node - The node to get the type string for.
 * @returns {string} The type string of the node.
 */
function typeToString(node) {
  return Object.prototype.toString.call(node).replace(/\[object\s/, '').replace(/\]/, '');
}

/**
 * Returns a generic token object from the provided parser and token.
 * If the token is null or undefined, it returns null.
 *
 * @param {object} parser - The parser to get the token from.
 * @param {object} token - The token to get the generic token object for.
 * @returns {object|null} The generic token object, or null if the token is null or undefined.
 */
function getGenericToken(parser, token) {
  if (!token) return null;
  return {
    type: 'TerminalNode',
    value: token.source.stream.getText(Interval.of(token.start, token.stop)),
    range: [token.start, token.stop]
  };
}

/**
 * Returns a generic context object from the provided context.
 * The generic context object includes all properties of the context that are not excluded.
 *
 * @param {object} ctx - The context to get the generic context object for.
 * @returns {object} The generic context object.
 */
function getGenericContext(ctx) {
  const exclude = [
    'constructor',
    'ruleIndex',
    'enterRule',
    'exitRule',
    'accept'
  ];
  return Object.getOwnPropertyNames(Object.getPrototypeOf(ctx))
   .filter((property) => exclude.indexOf(property) === -1)
   .reduce((obj, property) => {
      obj[property] = ctx[property] && typeof ctx[property] === 'function'? ctx[property]() : ctx[property];
      return obj;
    }, {});
}

/**
 * Returns a generic visitor object from the provided parser and visitor.
 * The generic visitor object includes a visit method that calls the accept method on the provided tree,
 * and a visitTerminal method that returns a generic token object.
 *
 * @param {object} options - The options object with parser and visitor properties.
 * @param {object} options.parser - The parser to get the generic token object from.
 * @param {object} options.visitor - The visitor to create a generic visitor from.
 * @returns {object} The generic visitor object.
 */
function getGenericVisitor({ parser, visitor }) {
  class GenericVisitor extends visitor.constructor {
    constructor(...args) {
      super(...args);
    }

    defaultResult() {
      return { children: [] };
    }

    aggregateResult(ctx, child) {
      if (!Array.isArray(ctx)) ctx = ctx.children;
      ctx.push(child);
      return ctx;
    }

    visit(tree) {
      return tree.accept(this);
    }

    visitTerminal(node) {
      return getGenericToken(parser, node._symbol);
    }

    visitChildren(ctx) {
      const result = visitor.constructor.prototype.visitChildren.apply(this, [ctx]);
      return {
        type: Object.prototype.toString.call(ctx).replace(/\[object\s/, '').replace(/\]/, ''),
        children: result
      };
    }
  }

  return { GenericVisitor };
}

module.exports = getGenericVisitor;

Overview

This code defines several functions for working with Abstract Syntax Trees (ASTs) generated by the ANTLR4TS parser generator.

Function 1: typeToString

This function takes an object as input and returns its type as a string. If the input is an object, it returns the name of the constructor it inherits from. Otherwise, it returns the type of the input using typeof.

Function 2: getGenericToken

This function takes a parser and a token as input and returns a generic token object. If the token is null or undefined, it returns null. Otherwise, it returns an object with the following properties:

Function 3: getGenericContext

This function takes a context object as input and returns an object with all its properties. It excludes certain properties (e.g., constructor, ruleIndex) from the output.

Function 4: getGenericVisitor

This function takes an object with parser and visitor properties as input and returns a generic visitor object. The visitor object has several methods:

The getGenericVisitor function returns an object with the generic visitor as its only property.

Export

The code exports the getGenericVisitor function as a module.