All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.antlr.v4.kotlinruntime.tree.Trees.kt Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0.
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause.

package org.antlr.v4.kotlinruntime.tree

import org.antlr.v4.kotlinruntime.*
import org.antlr.v4.kotlinruntime.atn.ATN
import org.antlr.v4.kotlinruntime.misc.Predicate
import org.antlr.v4.kotlinruntime.misc.Utils
import org.antlr.v4.kotlinruntime.tree.Trees.getNodeText

/**
 * A set of utility routines useful for all kinds of ANTLR trees.
 */
@Suppress("MemberVisibilityCanBePrivate")
public object Trees {
  /**
   * Print out a whole tree in LISP form.
   *
   * [getNodeText] is used on the node payloads to get the text for the nodes.
   * Detect parse trees and extract data appropriately.
   */
  public fun toStringTree(t: Tree, recog: Parser?): String {
    val ruleNames = recog?.ruleNames
    val ruleNamesList = if (ruleNames != null) {
      listOf(*ruleNames)
    } else {
      null
    }

    return toStringTree(t, ruleNamesList)
  }

  /**
   * Print out a whole tree in LISP form.
   *
   * [getNodeText] is used on the node payloads to get the text for the nodes.
   */
  public fun toStringTree(t: Tree, ruleNames: List? = null): String {
    val s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false)

    if (t.childCount == 0) {
      return s
    }

    val buf = StringBuilder()
    buf.append("(")
    buf.append(Utils.escapeWhitespace(getNodeText(t, ruleNames), false))
    buf.append(" ")

    for (i in 0.. 0) {
        buf.append(" ")
      }

      buf.append(toStringTree(t.getChild(i)!!, ruleNames))
    }

    buf.append(")")
    return buf.toString()
  }

  public fun getNodeText(t: Tree, recog: Parser?): String {
    val ruleNames = recog?.ruleNames
    val ruleNamesList = if (ruleNames != null) {
      listOf(*ruleNames)
    } else {
      null
    }

    return getNodeText(t, ruleNamesList)
  }

  public fun getNodeText(t: Tree, ruleNames: List?): String {
    if (ruleNames != null) {
      when (t) {
        is RuleContext -> {
          val ruleIndex = t.ruleContext.ruleIndex
          val ruleName = ruleNames[ruleIndex]
          val altNumber = t.altNumber
          return if (altNumber != ATN.INVALID_ALT_NUMBER) {
            "$ruleName:$altNumber"
          } else {
            ruleName
          }
        }
        is ErrorNode -> {
          return t.toString()
        }
        is TerminalNode -> {
          val text = t.symbol.text
          return text ?: throw IllegalStateException("Symbol text should not be null")
        }
      }
    }

    // No recog for rule names
    val payload = t.payload

    return if (payload is Token) {
      payload.text!!
    } else {
      t.payload.toString()
    }
  }

  /**
   * Return ordered list of all children of this node.
   */
  public fun getChildren(t: Tree): List {
    val kids = ArrayList()

    for (i in 0.. {
    if (t.getParent() == null) {
      return emptyList()
    }

    val ancestors = ArrayList()
    var t1 = t.getParent()

    while (t1 != null) {
      // Insert at start
      ancestors.add(0, t1)
      t1 = t1.getParent()
    }

    return ancestors
  }

  /**
   * Return true if [t] is [u]'s parent or a node on path to root from [u].
   *
   * @since 4.5.1
   */
  public fun isAncestorOf(t: Tree?, u: Tree?): Boolean {
    if (t == null || u == null || t.getParent() == null) {
      return false
    }

    var p = u.getParent()

    while (p != null) {
      // Keep reference equality!
      if (t === p) {
        return true
      }

      p = p.getParent()
    }

    return false
  }

  public fun findAllTokenNodes(t: ParseTree, ttype: Int): Collection =
    findAllNodes(t, ttype, true)

  public fun findAllRuleNodes(t: ParseTree, ruleIndex: Int): Collection =
    findAllNodes(t, ruleIndex, false)

  public fun findAllNodes(t: ParseTree, index: Int, findTokens: Boolean): List {
    val nodes = ArrayList()
    _findAllNodes(t, index, findTokens, nodes)
    return nodes
  }

  @Suppress("FunctionName")
  public fun _findAllNodes(
    t: ParseTree,
    index: Int,
    findTokens: Boolean,
    nodes: MutableList,
  ) {
    // Check this node (the root) first
    if (findTokens && t is TerminalNode) {
      if (t.symbol.type == index) {
        nodes.add(t)
      }
    } else if (!findTokens && t is ParserRuleContext) {
      if (t.ruleIndex == index) {
        nodes.add(t)
      }
    }

    // Check children
    for (i in 0.. {
    val nodes = ArrayList()
    nodes.add(t)

    val n = t.childCount

    for (i in 0..= t.start!!.tokenIndex &&
        // Is range fully contained in t?
        (t.stop == null || stopTokenIndex <= t.stop!!.tokenIndex)
      ) {
        // note: r.getStop()==null likely implies that we bailed out of parser and there's nothing to the right
        return t
      }
    }

    return null
  }

  /**
   * Replace any subtree siblings of root that are completely to left
   * or right of lookahead range with a `CommonToken(Token.INVALID_TYPE, "...")` node.
   * The source interval for [t] is not altered to suit smaller range!
   *
   * WARNING: destructive to [t].
   *
   * @since 4.5.1
   */
  public fun stripChildrenOutOfRange(
    t: ParserRuleContext?,
    root: ParserRuleContext,
    startIndex: Int,
    stopIndex: Int,
  ) {
    if (t == null) {
      return
    }

    for (i in 0.. stopIndex)) {
        // Replace only if subtree doesn't have displayed root
        if (isAncestorOf(child, root)) {
          val abbrev = CommonToken(Token.INVALID_TYPE, "...")
          t.children!![i] = TerminalNodeImpl(abbrev)
        }
      }
    }
  }

  /**
   * Return first node satisfying the [pred].
   *
   * @since 4.5.1
   */
  public fun findNodeSuchThat(t: Tree?, pred: Predicate): Tree? {
    if (pred.test(t)) {
      return t
    }

    if (t == null) {
      return null
    }

    val n = t.childCount

    for (i in 0..




© 2015 - 2024 Weber Informatics LLC | Privacy Policy