// ===========================================================================
// This file has been generated by
// Rats! Parser Generator, version 1.14.2,
// (C) 2004-2008 Robert Grimm,
// on Tuesday, October 14, 2008 at 8:48:57 AM.
// Edit at your own risk.
// ===========================================================================

package xtc.lang;

import java.io.Reader;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

import xtc.util.Action;
import xtc.util.Pair;

import xtc.tree.Node;
import xtc.tree.GNode;
import xtc.tree.Printer;

import xtc.parser.ParserBase;
import xtc.parser.Column;
import xtc.parser.Result;
import xtc.parser.SemanticValue;
import xtc.parser.ParseError;

/**
 * Packrat parser for grammar <code>xtc.lang.TypedLambda</code>.
 *
 * <p />This class has been generated by the <i>Rats!</i> parser
 * generator, version 1.14.2, (C) 2004-2008 Robert Grimm.
 */
public final class TypedLambdaParser extends ParserBase {

  // =========================================================================

  /** Memoization table column. */
  static final class TypedLambdaParserColumn extends Column {
    Result fApplication;
    Result fBasicExpression;
    Result fIdentifier;
    Result fFunctionType;
    Result fBasicType;
    Result fOPEN;
    Result fCLOSE;
  }

  // =========================================================================

  /**
   * Create a new packrat parser.
   *
   * @param reader The reader.
   * @param file The file name.
   */
  public TypedLambdaParser(final Reader reader, final String file) {
    super(reader, file);
  }

  /**
   * Create a new packrat parser.
   *
   * @param reader The file reader.
   * @param file The file name.
   * @param size The file size.
   */
  public TypedLambdaParser(final Reader reader, final String file, final int size) {
    super(reader, file, size);
  }

  // =========================================================================

  protected Column newColumn() {
    return new TypedLambdaParserColumn();
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.Expression.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  public Result pExpression(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyResult = pApplication(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      yyResult = pEndOfFile(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.Application.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pApplication(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fApplication) 
      yyColumn.fApplication = pApplication$1(yyStart);
    return yyColumn.fApplication;
  }

  /** Actually parse xtc.lang.TypedLambda.Application. */
  private Result pApplication$1(final int yyStart) throws IOException {
    Result             yyResult;
    int                yyRepetition1;
    Pair<Action<Node>> yyRepValue1;
    Node               yyValue;
    ParseError         yyError = ParseError.DUMMY;

    // Alternative <Base>.

    yyResult = pBasicExpression(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final Node v$g$3 = yyResult.semanticValue();

      yyRepetition1 = yyResult.index;
      yyRepValue1   = Pair.empty();
      while (true) {

        yyResult = pApplication$$Tail1(yyRepetition1);
        yyError  = yyResult.select(yyError, yyRepetition1);
        if (yyResult.hasValue()) {
          final Action<Node> v$4 = yyResult.semanticValue();

          yyRepetition1 = yyResult.index;
          yyRepValue1   = new Pair<Action<Node>>(v$4, yyRepValue1);
          continue;
        }
        break;
      }
      { // Start scope for v$5.
        final Pair<Action<Node>> v$5 = yyRepValue1.reverse();

        yyValue = apply(v$5, v$g$3, yyStart);

        return new SemanticValue(yyValue, yyRepetition1, yyError);
      } // End scope for v$5.
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse synthetic nonterminal xtc.lang.TypedLambda.Application$$Tail1.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pApplication$$Tail1(final int yyStart) throws IOException {
    Result       yyResult;
    Action<Node> yyValue;
    ParseError   yyError = ParseError.DUMMY;

    // Alternative <Recursion>.

    yyResult = pBasicExpression(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final Node v$g$2 = yyResult.semanticValue();

      yyValue = new Action<Node>() {
        public Node run(Node v$1) {
          return GNode.create("Application", v$1, v$g$2);
        }};

      return yyResult.createValue(yyValue, yyError);
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.BasicExpression.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pBasicExpression(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fBasicExpression) 
      yyColumn.fBasicExpression = pBasicExpression$1(yyStart);
    return yyColumn.fBasicExpression;
  }

  /** Actually parse xtc.lang.TypedLambda.BasicExpression. */
  private Result pBasicExpression$1(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative <Abstraction>.

    yyResult = pAbstraction(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      return yyResult.createValue(yyValue, yyError);
    }

    // Alternative <Identifier>.

    yyResult = pIdentifier(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      return yyResult.createValue(yyValue, yyError);
    }

    // Alternative <Integer>.

    yyResult = pIntegerConstant(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      return yyResult.createValue(yyValue, yyError);
    }

    // Alternative <String>.

    yyResult = pStringConstant(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      return yyResult.createValue(yyValue, yyError);
    }

    // Alternative <Parenthesized>.

    yyResult = pOPEN(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {

      yyResult = pApplication(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {
        yyValue = yyResult.semanticValue();

        yyResult = pCLOSE(yyResult.index);
        yyError  = yyResult.select(yyError);
        if (yyResult.hasValue()) {

          return yyResult.createValue(yyValue, yyError);
        }
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.Abstraction.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pAbstraction(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyResult = pLAMBDA(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {

      yyResult = pIdentifier(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {
        final Node v$g$1 = yyResult.semanticValue();

        yyResult = pCOLON(yyResult.index);
        yyError  = yyResult.select(yyError);
        if (yyResult.hasValue()) {

          yyResult = pFunctionType(yyResult.index);
          yyError  = yyResult.select(yyError);
          if (yyResult.hasValue()) {
            final Node v$g$2 = yyResult.semanticValue();

            yyResult = pDOT(yyResult.index);
            yyError  = yyResult.select(yyError);
            if (yyResult.hasValue()) {

              yyResult = pApplication(yyResult.index);
              yyError  = yyResult.select(yyError);
              if (yyResult.hasValue()) {
                final Node v$g$3 = yyResult.semanticValue();

                yyValue = GNode.create("Abstraction", v$g$1, v$g$2, v$g$3);
                yyValue.setLocation(location(yyStart));

                return yyResult.createValue(yyValue, yyError);
              }
            }
          }
        }
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.Identifier.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pIdentifier(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fIdentifier) 
      yyColumn.fIdentifier = pIdentifier$1(yyStart);
    return yyColumn.fIdentifier;
  }

  /** Actually parse xtc.lang.TypedLambda.Identifier. */
  private Result pIdentifier$1(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyResult = pIdentifierCharacters(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final String v$g$1 = yyResult.semanticValue();

      yyResult = pSpacing(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = GNode.create("Identifier", v$g$1);
        yyValue.setLocation(location(yyStart));

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.IdentifierCharacters.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pIdentifierCharacters(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    int        yyRepetition1;
    boolean    yyRepeated1;
    String     yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyRepetition1 = yyStart;
    yyRepeated1   = false;
    while (true) {

      yyC = character(yyRepetition1);
      if (-1 != yyC) {
        yyIndex = yyRepetition1 + 1;
        if ((('A' <= yyC) && (yyC <= 'Z')) ||
            (('a' <= yyC) && (yyC <= 'z'))) {

          yyRepetition1 = yyIndex;
          yyRepeated1   = true;
          continue;
        }
      }
      break;
    }

    if (yyRepeated1) {

      yyValue = difference(yyStart, yyRepetition1);

      return new SemanticValue(yyValue, yyRepetition1, yyError);
    }

    // Done.
    yyError = yyError.select("identifier characters expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.IntegerConstant.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pIntegerConstant(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyResult = pIntegerCharacters(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final String v$g$1 = yyResult.semanticValue();

      yyResult = pSpacing(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = GNode.create("IntegerConstant", v$g$1);
        yyValue.setLocation(location(yyStart));

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.IntegerCharacters.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pIntegerCharacters(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    int        yyRepetition1;
    String     yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if (-1 != yyC) {
      yyIndex = yyStart + 1;

      switch (yyC) {
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        {
          yyRepetition1 = yyIndex;
          while (true) {

            yyC = character(yyRepetition1);
            if (-1 != yyC) {
              yyIndex = yyRepetition1 + 1;

              switch (yyC) {
              case '0':
              case '1':
              case '2':
              case '3':
              case '4':
              case '5':
              case '6':
              case '7':
              case '8':
              case '9':
                {
                  yyRepetition1 = yyIndex;
                  continue;
                }

              default:
                /* No match. */
              }
            }
            break;
          }

          yyValue = difference(yyStart, yyRepetition1);

          return new SemanticValue(yyValue, yyRepetition1, yyError);
        }

      default:
        /* No match. */
      }
    }

    // Done.
    yyError = yyError.select("integer characters expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.StringConstant.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pStringConstant(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyResult = pStringCharacters(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final String v$g$1 = yyResult.semanticValue();

      yyResult = pSpacing(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = GNode.create("StringConstant", v$g$1);
        yyValue.setLocation(location(yyStart));

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.StringCharacters.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pStringCharacters(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    int        yyRepetition1;
    String     yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('\"' == yyC) {
      yyIndex = yyStart + 1;

      yyRepetition1 = yyIndex;
      while (true) {

        yyC = character(yyRepetition1);
        if (-1 != yyC) {
          yyIndex = yyRepetition1 + 1;
          if ('\"' != yyC) {

            yyRepetition1 = yyIndex;
            continue;
          }
        }
        break;
      }

      yyC = character(yyRepetition1);
      if ('\"' == yyC) {
        yyIndex = yyRepetition1 + 1;

        yyValue = difference(yyStart, yyIndex);

        return new SemanticValue(yyValue, yyIndex, yyError);
      }
    }

    // Done.
    yyError = yyError.select("string characters expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.FunctionType.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pFunctionType(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fFunctionType) 
      yyColumn.fFunctionType = pFunctionType$1(yyStart);
    return yyColumn.fFunctionType;
  }

  /** Actually parse xtc.lang.TypedLambda.FunctionType. */
  private Result pFunctionType$1(final int yyStart) throws IOException {
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative <Recursion>.

    yyResult = pBasicType(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      final Node v$g$1 = yyResult.semanticValue();

      yyResult = pARROW(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyResult = pFunctionType(yyResult.index);
        yyError  = yyResult.select(yyError);
        if (yyResult.hasValue()) {
          final Node v$g$2 = yyResult.semanticValue();

          yyValue = GNode.create("FunctionType", v$g$1, v$g$2);
          yyValue.setLocation(location(yyStart));

          return yyResult.createValue(yyValue, yyError);
        }
      }
    }

    // Alternative <Base>.

    yyResult = pBasicType(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {
      yyValue = yyResult.semanticValue();

      return yyResult.createValue(yyValue, yyError);
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.BasicType.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pBasicType(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fBasicType) 
      yyColumn.fBasicType = pBasicType$1(yyStart);
    return yyColumn.fBasicType;
  }

  /** Actually parse xtc.lang.TypedLambda.BasicType. */
  private Result pBasicType$1(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Node       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('i' == yyC) {
      yyIndex = yyStart + 1;

      yyC = character(yyIndex);
      if ('n' == yyC) {
        yyIndex = yyIndex + 1;

        yyC = character(yyIndex);
        if ('t' == yyC) {
          yyIndex = yyIndex + 1;

          yyResult = pSpacing(yyIndex);
          yyError  = yyResult.select(yyError);
          if (yyResult.hasValue()) {

            yyValue = GNode.create("IntegerType", false);
            yyValue.setLocation(location(yyStart));

            return yyResult.createValue(yyValue, yyError);
          }
        }
      }
    }

    // Alternative 2.

    yyC = character(yyStart);
    if ('s' == yyC) {
      yyIndex = yyStart + 1;

      yyC = character(yyIndex);
      if ('t' == yyC) {
        yyIndex = yyIndex + 1;

        yyC = character(yyIndex);
        if ('r' == yyC) {
          yyIndex = yyIndex + 1;

          yyC = character(yyIndex);
          if ('i' == yyC) {
            yyIndex = yyIndex + 1;

            yyC = character(yyIndex);
            if ('n' == yyC) {
              yyIndex = yyIndex + 1;

              yyC = character(yyIndex);
              if ('g' == yyC) {
                yyIndex = yyIndex + 1;

                yyResult = pSpacing(yyIndex);
                yyError  = yyResult.select(yyError);
                if (yyResult.hasValue()) {

                  yyValue = GNode.create("StringType", false);
                  yyValue.setLocation(location(yyStart));

                  return yyResult.createValue(yyValue, yyError);
                }
              }
            }
          }
        }
      }
    }

    // Alternative <Parenthesized>.

    yyResult = pOPEN(yyStart);
    yyError  = yyResult.select(yyError);
    if (yyResult.hasValue()) {

      yyResult = pFunctionType(yyResult.index);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {
        yyValue = yyResult.semanticValue();

        yyResult = pCLOSE(yyResult.index);
        yyError  = yyResult.select(yyError);
        if (yyResult.hasValue()) {

          return yyResult.createValue(yyValue, yyError);
        }
      }
    }

    // Done.
    yyError = yyError.select("basic type expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.LAMBDA.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pLAMBDA(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('\\' == yyC) {
      yyIndex = yyStart + 1;

      yyResult = pSpacing(yyIndex);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = null;

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    yyError = yyError.select("LAMBDA expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.COLON.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pCOLON(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if (':' == yyC) {
      yyIndex = yyStart + 1;

      yyResult = pSpacing(yyIndex);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = null;

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    yyError = yyError.select("COLON expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.DOT.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pDOT(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('.' == yyC) {
      yyIndex = yyStart + 1;

      yyResult = pSpacing(yyIndex);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = null;

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    yyError = yyError.select("DOT expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.ARROW.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pARROW(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('-' == yyC) {
      yyIndex = yyStart + 1;

      yyC = character(yyIndex);
      if ('>' == yyC) {
        yyIndex = yyIndex + 1;

        yyResult = pSpacing(yyIndex);
        yyError  = yyResult.select(yyError);
        if (yyResult.hasValue()) {

          yyValue = null;

          return yyResult.createValue(yyValue, yyError);
        }
      }
    }

    // Done.
    yyError = yyError.select("ARROW expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.OPEN.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pOPEN(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fOPEN) yyColumn.fOPEN = pOPEN$1(yyStart);
    return yyColumn.fOPEN;
  }

  /** Actually parse xtc.lang.TypedLambda.OPEN. */
  private Result pOPEN$1(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if ('(' == yyC) {
      yyIndex = yyStart + 1;

      yyResult = pSpacing(yyIndex);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = null;

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    yyError = yyError.select("OPEN expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.lang.TypedLambda.CLOSE.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pCLOSE(final int yyStart) throws IOException {
    TypedLambdaParserColumn yyColumn = (TypedLambdaParserColumn)column(yyStart);
    if (null == yyColumn.fCLOSE) yyColumn.fCLOSE = pCLOSE$1(yyStart);
    return yyColumn.fCLOSE;
  }

  /** Actually parse xtc.lang.TypedLambda.CLOSE. */
  private Result pCLOSE$1(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyResult;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyC = character(yyStart);
    if (')' == yyC) {
      yyIndex = yyStart + 1;

      yyResult = pSpacing(yyIndex);
      yyError  = yyResult.select(yyError);
      if (yyResult.hasValue()) {

        yyValue = null;

        return yyResult.createValue(yyValue, yyError);
      }
    }

    // Done.
    yyError = yyError.select("CLOSE expected", yyStart);
    return yyError;
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.util.Spacing.Spacing.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pSpacing(final int yyStart) throws IOException {
    int        yyC;
    int        yyIndex;
    Result     yyPredResult;
    boolean    yyPredMatched;
    int        yyBase;
    int        yyRepetition1;
    int        yyRepetition2;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyRepetition1 = yyStart;
    while (true) {

      final int yyChoice1 = yyRepetition1;

      // Nested alternative 1.

      yyC = character(yyChoice1);
      if (-1 != yyC) {
        yyIndex = yyChoice1 + 1;

        switch (yyC) {
        case ' ':
          {
            yyRepetition1 = yyIndex;
            continue;
          }

        case '\t':
          {
            yyRepetition1 = yyIndex;
            continue;
          }

        case '\f':
          {
            yyRepetition1 = yyIndex;
            continue;
          }

        case '\r':
          {
            final int yyChoice2 = yyIndex;

            // Nested alternative 1.

            yyC = character(yyChoice2);
            if ('\n' == yyC) {
              yyIndex = yyChoice2 + 1;

              yyRepetition1 = yyIndex;
              continue;
            }

            // Nested alternative 2.

            yyRepetition1 = yyChoice2;
            continue;
          }

        case '\n':
          {
            yyRepetition1 = yyIndex;
            continue;
          }

        case '/':
          {
            yyC = character(yyIndex);
            if (-1 != yyC) {
              yyIndex = yyIndex + 1;

              switch (yyC) {
              case '*':
                {
                  yyRepetition2 = yyIndex;
                  while (true) {

                    final int yyChoice2 = yyRepetition2;

                    // Nested alternative 1.

                    yyC = character(yyChoice2);
                    if (-1 != yyC) {
                      yyIndex = yyChoice2 + 1;

                      switch (yyC) {
                      case '*':
                        {
                          yyPredMatched = false;

                          yyC = character(yyIndex);
                          if ('/' == yyC) {

                            yyPredMatched = true;
                          }

                          if (! yyPredMatched) {

                            yyRepetition2 = yyIndex;
                            continue;
                          } else {
                            yyError = yyError.select("spacing expected", yyStart);
                          }
                        }
                        break;

                      default:
                        {
                          yyRepetition2 = yyIndex;
                          continue;
                        }
                      }
                    }
                    break;
                  }

                  yyBase = yyRepetition2;
                  yyC    = character(yyBase);
                  if ('*' == yyC) {
                    yyIndex = yyRepetition2 + 1;

                    yyC = character(yyIndex);
                    if ('/' == yyC) {
                      yyIndex = yyIndex + 1;

                      yyRepetition1 = yyIndex;
                      continue;
                    } else {
                      yyError = yyError.select("'*/' expected", yyBase);
                    }
                  } else {
                    yyError = yyError.select("'*/' expected", yyBase);
                  }
                }
                break;

              case '/':
                {
                  yyRepetition2 = yyIndex;
                  while (true) {

                    yyC = character(yyRepetition2);
                    if (-1 != yyC) {
                      yyIndex = yyRepetition2 + 1;

                      switch (yyC) {
                      case '\n':
                      case '\r':
                        /* No match. */
                        break;

                      default:
                        {
                          yyRepetition2 = yyIndex;
                          continue;
                        }
                      }
                    }
                    break;
                  }

                  final int yyChoice2 = yyRepetition2;

                  // Nested alternative 1.

                  yyC = character(yyChoice2);
                  if (-1 != yyC) {
                    yyIndex = yyChoice2 + 1;

                    switch (yyC) {
                    case '\r':
                      {
                        final int yyChoice3 = yyIndex;

                        // Nested alternative 1.

                        yyC = character(yyChoice3);
                        if ('\n' == yyC) {
                          yyIndex = yyChoice3 + 1;

                          yyRepetition1 = yyIndex;
                          continue;
                        }

                        // Nested alternative 2.

                        yyRepetition1 = yyChoice3;
                        continue;
                      }

                    case '\n':
                      {
                        yyRepetition1 = yyIndex;
                        continue;
                      }

                    default:
                      /* No match. */
                    }
                  }

                  // Nested alternative 2.

                  yyPredResult = pEndOfFile(yyChoice2);
                  yyError      = yyPredResult.select(yyError);
                  if (yyPredResult.hasValue()) {

                    yyRepetition1 = yyChoice2;
                    continue;
                  }
                }
                break;

              default:
                /* No match. */
              }
            }
          }
          break;

        default:
          /* No match. */
        }
      }
      break;
    }

    yyValue = null;

    return new SemanticValue(yyValue, yyRepetition1, yyError);
  }

  // =========================================================================

  /**
   * Parse nonterminal xtc.util.Spacing.EndOfFile.
   *
   * @param yyStart The index.
   * @return The result.
   * @throws IOException Signals an I/O error.
   */
  private Result pEndOfFile(final int yyStart) throws IOException {
    int        yyC;
    boolean    yyPredMatched;
    Void       yyValue;
    ParseError yyError = ParseError.DUMMY;

    // Alternative 1.

    yyPredMatched = false;

    yyC = character(yyStart);
    if (-1 != yyC) {

      yyPredMatched = true;
    }

    if (! yyPredMatched) {

      yyValue = null;

      return new SemanticValue(yyValue, yyStart, yyError);
    } else {
      yyError = yyError.select("end of file expected", yyStart);
    }

    // Done.
    return yyError;
  }

  // =========================================================================

  /**
   * Get the specified text.
   *
   * @param s The text.
   * @return The text.
   */
  protected static final String toText(String s) {
    return s;
  }

  // =========================================================================

  /**
   * Parse the specified files.
   *
   * @param args The file names.
   */
  public static void main(String[] args) {
    if ((null == args) || (0 == args.length)) {
      System.err.println("Usage: <file-name>+");

    } else {
      for (int i=0; i<args.length; i++) {
        System.err.println("Processing " + args[i] + " ...");

        Reader              in = null;
        try {
          in                   = new BufferedReader(new FileReader(args[i]));
          TypedLambdaParser p  = 
            new TypedLambdaParser(in, args[i], (int)new File(args[i]).length());
          Result            r  = p.pExpression(0);

          if (r.hasValue()) {
            SemanticValue v = (SemanticValue)r;

            if (v.value instanceof Node) {
              Printer ptr = new
                Printer(new BufferedWriter(new OutputStreamWriter(System.out)));
              ptr.format((Node)v.value).pln().flush();
            } else {
              System.out.println(v.value.toString());
            }

          } else {
            ParseError err = (ParseError)r;
            if (-1 == err.index) {
              System.err.println("  Parse error");
            } else {
              System.err.println("  " + p.location(err.index) + ": " + err.msg);
            }
          }

        } catch (Throwable x) {
          while (null != x.getCause()) {
            x = x.getCause();
          }
          x.printStackTrace();
        } finally {
          try {
            in.close();
          } catch (Throwable x) {
            /* Ignore. */
          }
        }
      }
    }
  }

}
