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

commonMain.org.antlr.v4.kotlinruntime.dfa.DFA.kt Maven / Gradle / Ivy

// 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.dfa

import com.strumenta.antlrkotlin.runtime.synchronized
import org.antlr.v4.kotlinruntime.Parser
import org.antlr.v4.kotlinruntime.Vocabulary
import org.antlr.v4.kotlinruntime.VocabularyImpl
import org.antlr.v4.kotlinruntime.atn.ATNConfigSet
import org.antlr.v4.kotlinruntime.atn.DecisionState
import org.antlr.v4.kotlinruntime.atn.StarLoopEntryState
import kotlin.concurrent.Volatile

public open class DFA(
  /**
   * From which ATN state did we create this DFA?
   */
  public val atnStartState: DecisionState,
  public val decision: Int = 0,
) {
  /**
   * A set of all DFA states.
   *
   * Use [Map] so we can get old state back ([Set] only allows you to see if it's there).
   */
  public val states: MutableMap = HashMap()

  @Volatile
  public var s0: DFAState? = null

  /**
   * Whether this DFA is a precedence DFA, or not.
   *
   * Precedence DFAs use a special start state [s0] which is not stored in [states].
   * The [DFAState.edges] array for this start state contains outgoing edges
   * supplying individual start states corresponding to specific precedence
   * values.
   *
   * @see Parser.precedence
   */
  public val isPrecedenceDfa: Boolean

  init {
    var isPrecedenceDfa = false

    if (atnStartState is StarLoopEntryState) {
      if (atnStartState.isPrecedenceDecision) {
        isPrecedenceDfa = true

        val precedenceState = DFAState(ATNConfigSet())
        precedenceState.edges = arrayOfNulls(0)
        precedenceState.isAcceptState = false
        precedenceState.requiresFullContext = false
        this.s0 = precedenceState
      }
    }

    this.isPrecedenceDfa = isPrecedenceDfa
  }

  /**
   * Get the start state for a specific precedence value.
   *
   * @param precedence The current precedence
   * @return The start state corresponding to the specified precedence,
   *   or `null` if no start state exists for the specified precedence
   *
   * @throws IllegalStateException If this is not a precedence DFA
   * @see isPrecedenceDfa
   */
  public fun getPrecedenceStartState(precedence: Int): DFAState? {
    if (!isPrecedenceDfa) {
      throw IllegalStateException("Only precedence DFAs may contain a precedence start state.")
    }

    // s0.edges is never null for a precedence DFA
    val edges = s0!!.edges!!
    return if (precedence < 0 || precedence >= edges.size) {
      null
    } else {
      edges[precedence]
    }
  }

  /**
   * Set the start state for a specific precedence value.
   *
   * @param precedence The current precedence
   * @param startState The start state corresponding to the specified precedence
   *
   * @throws IllegalStateException If this is not a precedence DFA
   * @see isPrecedenceDfa
   */
  public fun setPrecedenceStartState(precedence: Int, startState: DFAState) {
    if (!isPrecedenceDfa) {
      throw IllegalStateException("Only precedence DFAs may contain a precedence start state.")
    }

    if (precedence < 0) {
      return
    }

    // Synchronization on s0 here is ok. When the DFA is turned into a
    // precedence DFA, s0 will be initialized once and not updated again
    // s0.edges is never null for a precedence DFA
    val s0 = s0!!
    synchronized(s0) {
      if (precedence >= s0.edges!!.size) {
        s0.edges = s0.edges!!.copyOf(precedence + 1)
      }

      s0.edges!![precedence] = startState
    }
  }

  /**
   * Return a list of all states in this DFA, ordered by state number.
   */
  public fun getStates(): List {
    val result = ArrayList(states.keys)
    result.sortBy(DFAState::stateNumber)
    return result
  }

  override fun toString(): String =
    toString(VocabularyImpl.EMPTY_VOCABULARY)

  public fun toString(vocabulary: Vocabulary): String {
    if (s0 == null) {
      return ""
    }

    val serializer = DFASerializer(this, vocabulary)
    return serializer.toString()
  }

  public fun toLexerString(): String {
    if (s0 == null) {
      return ""
    }

    val serializer = LexerDFASerializer(this)
    return serializer.toString()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy