HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/vhost/disk-apps/pwa.sports-crowd.com/node_modules/chevrotain/src/parse/grammar/first.ts
import { uniq, map, flatten } from "../../utils/utils"
import { AbstractProduction, NonTerminal, Terminal } from "./gast/gast_public"
import { isBranchingProd, isOptionalProd, isSequenceProd } from "./gast/gast"
import { IProduction, TokenType } from "../../../api"

export function first(prod: IProduction): TokenType[] {
  /* istanbul ignore else */
  if (prod instanceof NonTerminal) {
    // this could in theory cause infinite loops if
    // (1) prod A refs prod B.
    // (2) prod B refs prod A
    // (3) AB can match the empty set
    // in other words a cycle where everything is optional so the first will keep
    // looking ahead for the next optional part and will never exit
    // currently there is no safeguard for this unique edge case because
    // (1) not sure a grammar in which this can happen is useful for anything (productive)
    return first((<NonTerminal>prod).referencedRule)
  } else if (prod instanceof Terminal) {
    return firstForTerminal(<Terminal>prod)
  } else if (isSequenceProd(prod)) {
    return firstForSequence(<AbstractProduction>prod)
  } else if (isBranchingProd(prod)) {
    return firstForBranching(<AbstractProduction>prod)
  } else {
    throw Error("non exhaustive match")
  }
}

export function firstForSequence(prod: AbstractProduction): TokenType[] {
  let firstSet: TokenType[] = []
  let seq = prod.definition
  let nextSubProdIdx = 0
  let hasInnerProdsRemaining = seq.length > nextSubProdIdx
  let currSubProd
  // so we enter the loop at least once (if the definition is not empty
  let isLastInnerProdOptional = true
  // scan a sequence until it's end or until we have found a NONE optional production in it
  while (hasInnerProdsRemaining && isLastInnerProdOptional) {
    currSubProd = seq[nextSubProdIdx]
    isLastInnerProdOptional = isOptionalProd(currSubProd)
    firstSet = firstSet.concat(first(currSubProd))
    nextSubProdIdx = nextSubProdIdx + 1
    hasInnerProdsRemaining = seq.length > nextSubProdIdx
  }

  return uniq(firstSet)
}

export function firstForBranching(prod: AbstractProduction): TokenType[] {
  let allAlternativesFirsts: TokenType[][] = map(
    prod.definition,
    (innerProd) => {
      return first(innerProd)
    }
  )
  return uniq(flatten<TokenType>(allAlternativesFirsts))
}

export function firstForTerminal(terminal: Terminal): TokenType[] {
  return [terminal.terminalType]
}