/**
 * Generated by parsegen_code.js from parsegen JSON tables. Do not edit.
 */
import {
  newToken,
  newASTNode,
  newASTNodeTerminal,
  AST,
  TOKEN_TYPE_EOF,
  TOKEN_TYPE_ERROR,
} from "../../../generators/js/runtime/index.js";

const ActionKind = { SHIFT: 0, REDUCE: 1, ACCEPT: 2 };

class Action {
  constructor(kind, target) {
    this.kind = kind;
    this.target = target;
  }
}

const pgpg_JSONParser_NO_AST_SENTINEL = { token: null, type: "", children: [] };

const ACTIONS = {
  0: {
    "false": new Action(ActionKind.SHIFT, 5),
    "lbracket": new Action(ActionKind.SHIFT, 6),
    "lcurly": new Action(ActionKind.SHIFT, 7),
    "null": new Action(ActionKind.SHIFT, 8),
    "number": new Action(ActionKind.SHIFT, 9),
    "string": new Action(ActionKind.SHIFT, 10),
    "true": new Action(ActionKind.SHIFT, 11)
  },
  1: {
    "EOF": new Action(ActionKind.REDUCE, 3)
  },
  2: {
    "EOF": new Action(ActionKind.ACCEPT, 0)
  },
  3: {
    "EOF": new Action(ActionKind.REDUCE, 2)
  },
  4: {
    "EOF": new Action(ActionKind.REDUCE, 1)
  },
  5: {
    "EOF": new Action(ActionKind.REDUCE, 7)
  },
  6: {
    "false": new Action(ActionKind.SHIFT, 16),
    "lbracket": new Action(ActionKind.SHIFT, 17),
    "lcurly": new Action(ActionKind.SHIFT, 18),
    "null": new Action(ActionKind.SHIFT, 19),
    "number": new Action(ActionKind.SHIFT, 20),
    "rbracket": new Action(ActionKind.SHIFT, 21),
    "string": new Action(ActionKind.SHIFT, 22),
    "true": new Action(ActionKind.SHIFT, 23)
  },
  7: {
    "rcurly": new Action(ActionKind.SHIFT, 26),
    "string": new Action(ActionKind.SHIFT, 27)
  },
  8: {
    "EOF": new Action(ActionKind.REDUCE, 8)
  },
  9: {
    "EOF": new Action(ActionKind.REDUCE, 5)
  },
  10: {
    "EOF": new Action(ActionKind.REDUCE, 4)
  },
  11: {
    "EOF": new Action(ActionKind.REDUCE, 6)
  },
  12: {
    "comma": new Action(ActionKind.REDUCE, 3),
    "rbracket": new Action(ActionKind.REDUCE, 3)
  },
  13: {
    "comma": new Action(ActionKind.SHIFT, 28),
    "rbracket": new Action(ActionKind.SHIFT, 29)
  },
  14: {
    "comma": new Action(ActionKind.REDUCE, 2),
    "rbracket": new Action(ActionKind.REDUCE, 2)
  },
  15: {
    "comma": new Action(ActionKind.REDUCE, 16),
    "rbracket": new Action(ActionKind.REDUCE, 16)
  },
  16: {
    "comma": new Action(ActionKind.REDUCE, 7),
    "rbracket": new Action(ActionKind.REDUCE, 7)
  },
  17: {
    "false": new Action(ActionKind.SHIFT, 16),
    "lbracket": new Action(ActionKind.SHIFT, 17),
    "lcurly": new Action(ActionKind.SHIFT, 18),
    "null": new Action(ActionKind.SHIFT, 19),
    "number": new Action(ActionKind.SHIFT, 20),
    "rbracket": new Action(ActionKind.SHIFT, 31),
    "string": new Action(ActionKind.SHIFT, 22),
    "true": new Action(ActionKind.SHIFT, 23)
  },
  18: {
    "rcurly": new Action(ActionKind.SHIFT, 33),
    "string": new Action(ActionKind.SHIFT, 27)
  },
  19: {
    "comma": new Action(ActionKind.REDUCE, 8),
    "rbracket": new Action(ActionKind.REDUCE, 8)
  },
  20: {
    "comma": new Action(ActionKind.REDUCE, 5),
    "rbracket": new Action(ActionKind.REDUCE, 5)
  },
  21: {
    "EOF": new Action(ActionKind.REDUCE, 14)
  },
  22: {
    "comma": new Action(ActionKind.REDUCE, 4),
    "rbracket": new Action(ActionKind.REDUCE, 4)
  },
  23: {
    "comma": new Action(ActionKind.REDUCE, 6),
    "rbracket": new Action(ActionKind.REDUCE, 6)
  },
  24: {
    "comma": new Action(ActionKind.REDUCE, 11),
    "rcurly": new Action(ActionKind.REDUCE, 11)
  },
  25: {
    "comma": new Action(ActionKind.SHIFT, 34),
    "rcurly": new Action(ActionKind.SHIFT, 35)
  },
  26: {
    "EOF": new Action(ActionKind.REDUCE, 9)
  },
  27: {
    "colon": new Action(ActionKind.SHIFT, 36)
  },
  28: {
    "false": new Action(ActionKind.SHIFT, 16),
    "lbracket": new Action(ActionKind.SHIFT, 17),
    "lcurly": new Action(ActionKind.SHIFT, 18),
    "null": new Action(ActionKind.SHIFT, 19),
    "number": new Action(ActionKind.SHIFT, 20),
    "string": new Action(ActionKind.SHIFT, 22),
    "true": new Action(ActionKind.SHIFT, 23)
  },
  29: {
    "EOF": new Action(ActionKind.REDUCE, 15)
  },
  30: {
    "comma": new Action(ActionKind.SHIFT, 28),
    "rbracket": new Action(ActionKind.SHIFT, 38)
  },
  31: {
    "comma": new Action(ActionKind.REDUCE, 14),
    "rbracket": new Action(ActionKind.REDUCE, 14)
  },
  32: {
    "comma": new Action(ActionKind.SHIFT, 34),
    "rcurly": new Action(ActionKind.SHIFT, 39)
  },
  33: {
    "comma": new Action(ActionKind.REDUCE, 9),
    "rbracket": new Action(ActionKind.REDUCE, 9)
  },
  34: {
    "string": new Action(ActionKind.SHIFT, 27)
  },
  35: {
    "EOF": new Action(ActionKind.REDUCE, 10)
  },
  36: {
    "false": new Action(ActionKind.SHIFT, 44),
    "lbracket": new Action(ActionKind.SHIFT, 45),
    "lcurly": new Action(ActionKind.SHIFT, 46),
    "null": new Action(ActionKind.SHIFT, 47),
    "number": new Action(ActionKind.SHIFT, 48),
    "string": new Action(ActionKind.SHIFT, 49),
    "true": new Action(ActionKind.SHIFT, 50)
  },
  37: {
    "comma": new Action(ActionKind.REDUCE, 17),
    "rbracket": new Action(ActionKind.REDUCE, 17)
  },
  38: {
    "comma": new Action(ActionKind.REDUCE, 15),
    "rbracket": new Action(ActionKind.REDUCE, 15)
  },
  39: {
    "comma": new Action(ActionKind.REDUCE, 10),
    "rbracket": new Action(ActionKind.REDUCE, 10)
  },
  40: {
    "comma": new Action(ActionKind.REDUCE, 12),
    "rcurly": new Action(ActionKind.REDUCE, 12)
  },
  41: {
    "comma": new Action(ActionKind.REDUCE, 3),
    "rcurly": new Action(ActionKind.REDUCE, 3)
  },
  42: {
    "comma": new Action(ActionKind.REDUCE, 2),
    "rcurly": new Action(ActionKind.REDUCE, 2)
  },
  43: {
    "comma": new Action(ActionKind.REDUCE, 13),
    "rcurly": new Action(ActionKind.REDUCE, 13)
  },
  44: {
    "comma": new Action(ActionKind.REDUCE, 7),
    "rcurly": new Action(ActionKind.REDUCE, 7)
  },
  45: {
    "false": new Action(ActionKind.SHIFT, 16),
    "lbracket": new Action(ActionKind.SHIFT, 17),
    "lcurly": new Action(ActionKind.SHIFT, 18),
    "null": new Action(ActionKind.SHIFT, 19),
    "number": new Action(ActionKind.SHIFT, 20),
    "rbracket": new Action(ActionKind.SHIFT, 52),
    "string": new Action(ActionKind.SHIFT, 22),
    "true": new Action(ActionKind.SHIFT, 23)
  },
  46: {
    "rcurly": new Action(ActionKind.SHIFT, 54),
    "string": new Action(ActionKind.SHIFT, 27)
  },
  47: {
    "comma": new Action(ActionKind.REDUCE, 8),
    "rcurly": new Action(ActionKind.REDUCE, 8)
  },
  48: {
    "comma": new Action(ActionKind.REDUCE, 5),
    "rcurly": new Action(ActionKind.REDUCE, 5)
  },
  49: {
    "comma": new Action(ActionKind.REDUCE, 4),
    "rcurly": new Action(ActionKind.REDUCE, 4)
  },
  50: {
    "comma": new Action(ActionKind.REDUCE, 6),
    "rcurly": new Action(ActionKind.REDUCE, 6)
  },
  51: {
    "comma": new Action(ActionKind.SHIFT, 28),
    "rbracket": new Action(ActionKind.SHIFT, 55)
  },
  52: {
    "comma": new Action(ActionKind.REDUCE, 14),
    "rcurly": new Action(ActionKind.REDUCE, 14)
  },
  53: {
    "comma": new Action(ActionKind.SHIFT, 34),
    "rcurly": new Action(ActionKind.SHIFT, 56)
  },
  54: {
    "comma": new Action(ActionKind.REDUCE, 9),
    "rcurly": new Action(ActionKind.REDUCE, 9)
  },
  55: {
    "comma": new Action(ActionKind.REDUCE, 15),
    "rcurly": new Action(ActionKind.REDUCE, 15)
  },
  56: {
    "comma": new Action(ActionKind.REDUCE, 10),
    "rcurly": new Action(ActionKind.REDUCE, 10)
  }
};

const GOTOS = {
  0: {
    "Array": 1,
    "Json": 2,
    "Object": 3,
    "Value": 4
  },
  6: {
    "Array": 12,
    "Elements": 13,
    "Object": 14,
    "Value": 15
  },
  7: {
    "Member": 24,
    "Members": 25
  },
  17: {
    "Array": 12,
    "Elements": 30,
    "Object": 14,
    "Value": 15
  },
  18: {
    "Member": 24,
    "Members": 32
  },
  28: {
    "Array": 12,
    "Object": 14,
    "Value": 37
  },
  34: {
    "Member": 40
  },
  36: {
    "Array": 41,
    "Object": 42,
    "Value": 43
  },
  45: {
    "Array": 12,
    "Elements": 51,
    "Object": 14,
    "Value": 15
  },
  46: {
    "Member": 24,
    "Members": 53
  }
};

const PRODUCTIONS = [
  { lhs: "__pgpg_start_1", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Json", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Value", rhsCount: 1, hasHint: false, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Object", rhsCount: 2, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "{}", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "object" },
  { lhs: "Object", rhsCount: 3, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: true, parentIndex: 0, passthroughIndex: 0, parentLiteral: "{}", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [1], nodeType: "object" },
  { lhs: "Members", rhsCount: 1, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "{temp}", childIndices: [0], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Members", rhsCount: 3, hasHint: true, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: true, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [2], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Member", rhsCount: 3, hasHint: true, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 1, passthroughIndex: 0, parentLiteral: "", childIndices: [0,2], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Array", rhsCount: 2, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "[]", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "array" },
  { lhs: "Array", rhsCount: 3, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: true, parentIndex: 0, passthroughIndex: 0, parentLiteral: "[]", childIndices: [], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [1], nodeType: "array" },
  { lhs: "Elements", rhsCount: 1, hasHint: true, hasPassthrough: false, hasParentLiteral: true, hasWithAppendedChildren: false, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "[temp]", childIndices: [0], withAppendedChildren: [], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" },
  { lhs: "Elements", rhsCount: 3, hasHint: true, hasPassthrough: false, hasParentLiteral: false, hasWithAppendedChildren: true, hasWithPrependedChildren: false, hasWithAdoptedGrandchildren: false, parentIndex: 0, passthroughIndex: 0, parentLiteral: "", childIndices: [], withAppendedChildren: [2], withPrependedChildren: [], withAdoptedGrandchildren: [], nodeType: "" }
];

export class TraceHooks {
  constructor() {
    this.onToken = null;
    this.onAction = null;
    this.onStack = null;
  }
}

export class pgpg_JSONParser {
  constructor() {
    this.trace = null;
  }

  parse(lexer, astMode = "") {
    if (lexer == null) throw new Error("parser: nil lexer");
    const stateStack = [0];
    const nodeStack = [];
    let lookahead = lexer.scan();
    if (this.trace?.onToken && lookahead) this.trace.onToken(lookahead);
    for (;;) {
      if (lookahead == null) throw new Error("parser: lexer returned null token");
      if (lookahead.type === TOKEN_TYPE_ERROR) throw new Error(`lexer error: ${lookahead.lexeme}`);
      const state = stateStack[stateStack.length - 1];
      const stateActions = ACTIONS[state];
      const action = stateActions?.[lookahead.type];
      if (action == null)
        throw new Error(`parse error: unexpected ${lookahead.type} (${lookahead.lexeme})`);
      if (this.trace?.onAction) this.trace.onAction(state, action, lookahead);
      if (action.kind === ActionKind.SHIFT) {
        if (astMode === "noast") nodeStack.push(pgpg_JSONParser_NO_AST_SENTINEL);
        else nodeStack.push(newASTNodeTerminal(lookahead, lookahead.type));
        stateStack.push(action.target);
        lookahead = lexer.scan();
        if (this.trace?.onToken && lookahead) this.trace.onToken(lookahead);
        if (this.trace?.onStack) this.trace.onStack(stateStack, nodeStack);
      } else if (action.kind === ActionKind.REDUCE) {
        const prod = PRODUCTIONS[action.target];
        const rhsNodes = Array(prod.rhsCount);
        for (let i = prod.rhsCount - 1; i >= 0; i--) {
          stateStack.pop();
          rhsNodes[i] = nodeStack.pop();
        }
        if (astMode === "noast") nodeStack.push(pgpg_JSONParser_NO_AST_SENTINEL);
        else nodeStack.push(reduce(prod, rhsNodes, astMode));
        const nextState = GOTOS[stateStack[stateStack.length - 1]]?.[prod.lhs];
        if (nextState == null) throw new Error(`parse error: missing goto for ${prod.lhs}`);
        stateStack.push(nextState);
        if (this.trace?.onStack) this.trace.onStack(stateStack, nodeStack);
      } else {
        if (nodeStack.length !== 1) throw new Error(`parse error: unexpected parse stack size ${nodeStack.length}`);
        if (this.trace?.onStack) this.trace.onStack(stateStack, nodeStack);
        if (astMode === "noast") return null;
        return new AST(nodeStack[0]);
      }
    }
  }

  attachCLITrace(traceTokens = false, traceStates = false, traceStack = false) {
    if (!traceTokens && !traceStates && !traceStack) return;
    this.trace = new TraceHooks();
    if (traceTokens) this.trace.onToken = (tok) => { if (tok) console.error(`TOK type=${tok.type} lexeme=${tok.lexeme}`); };
    if (traceStates) this.trace.onAction = (state, action, lookahead) => { console.error(`STATE ${state} ${action.kind === ActionKind.SHIFT ? "shift" : action.kind === ActionKind.REDUCE ? "reduce" : "accept"} on ${lookahead?.type}(${lookahead?.lexeme})`); };
    if (traceStack) this.trace.onStack = (stateStack, nodeStack) => { console.error(`STACK states=[${stateStack.join(" ")}] nodes=[${nodeStack.map((n) => n.type).join(" ")}]`); };
  }
}

function reduce(prod, rhsNodes, astMode) {
  const useFullTree = astMode === "fullast";

    if (!useFullTree && prod.hasPassthrough) {
      return rhsNodes[prod.passthroughIndex];
    }
    if (!useFullTree && prod.hasWithAppendedChildren) {
      let parent = null;
      let parentToken = null;
      let parentType = null;
      if (prod.hasParentLiteral) {
        parentToken = newToken(prod.parentLiteral, prod.parentLiteral);
        parentType = prod.parentLiteral;
      } else {
        parent = rhsNodes[prod.parentIndex];
        parentToken = parent.token;
        parentType = parent.type;
      }
      const nodeType = prod.nodeType || parentType;
      const newChildren = [];
      if (parent != null && parent.children?.length) newChildren.push(...parent.children);
      for (const ci of prod.withAppendedChildren) newChildren.push(rhsNodes[ci]);
      return newASTNode(parentToken, nodeType, newChildren);
    }
    if (!useFullTree && prod.hasWithPrependedChildren) {
      let parent = null;
      let parentToken = null;
      let parentType = null;
      if (prod.hasParentLiteral) {
        parentToken = newToken(prod.parentLiteral, prod.parentLiteral);
        parentType = prod.parentLiteral;
      } else {
        parent = rhsNodes[prod.parentIndex];
        parentToken = parent.token;
        parentType = parent.type;
      }
      const nodeType = prod.nodeType || parentType;
      const newChildren = [];
      for (const ci of prod.withPrependedChildren) newChildren.push(rhsNodes[ci]);
      if (parent != null && parent.children?.length) newChildren.push(...parent.children);
      return newASTNode(parentToken, nodeType, newChildren);
    }
    if (!useFullTree && prod.hasWithAdoptedGrandchildren) {
      let parent = null;
      let parentToken = null;
      let parentType = null;
      if (prod.hasParentLiteral) {
        parentToken = newToken(prod.parentLiteral, prod.parentLiteral);
        parentType = prod.parentLiteral;
      } else {
        parent = rhsNodes[prod.parentIndex];
        parentToken = parent.token;
        parentType = parent.type;
      }
      const nodeType = prod.nodeType || parentType;
      const newChildren = [];
      for (const ci of prod.withAdoptedGrandchildren) {
        const childNode = rhsNodes[ci];
        if (childNode?.children?.length) newChildren.push(...childNode.children);
      }
      return newASTNode(parentToken, nodeType, newChildren);
    }
    if (!useFullTree && prod.hasHint) {
      const nodeType = prod.nodeType || prod.lhs;
      let parentToken = null;
      if (prod.hasParentLiteral) parentToken = newToken(prod.parentLiteral, prod.parentLiteral);
      else if (prod.parentIndex >= 0 && rhsNodes[prod.parentIndex]?.token) parentToken = rhsNodes[prod.parentIndex].token;
      const hintChildren = prod.childIndices.map((ci) => rhsNodes[ci]);
      return newASTNode(parentToken, nodeType, hintChildren);
    }
    if (prod.rhsCount === 1) return rhsNodes[0];
    if (prod.rhsCount === 0) return newASTNode(null, prod.lhs, []);
    return newASTNode(null, prod.lhs, rhsNodes);

}
