/* Generated By:JavaCC: Do not edit this line. RSLParser.java */
/*
 * Copyright 1999-2006 University of Chicago
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.globus.rsl;

import java.io.StringReader;
import java.util.LinkedList;
import java.util.ListIterator;

/**
 * Parser for the <A HREF="http://www-fp.globus.org/gram/rsl_spec1.html">
 * Globus Resource Specification Language RSL v1.0. </A>
 * <BR>
 * Things that are not supported: <BR>
 * (1) User-specified delimiter for quoted literals.<BR>
 * (2) RSLs that only contain relations outside of 'spec-list'.<BR><BR>
 * Other notes: <BR>
 * (1) Implicit concatenation is not part of the 'simple value' relation
 * and is implemented by inspecting the white space between individual
 * values.
 */
public class RSLParser implements RSLParserConstants {

    private Class nodeClass = RslNode.class;

  public static void main(String argv[]) throws ParseException {
    if ((argv.length != 0) && (argv.length != 1)) {
      System.err.println("Usage: RSL [rsl string]");
      System.exit(1);
    }

    RSLParser parser = null;
    if (argv.length == 0) {
      parser = new RSLParser(System.in);
    } else {
      parser = new RSLParser(new StringReader(argv[0]));
    }

    parser.parse();
  }

  public static RslNode parse(String rsl) throws ParseException {
        return (RslNode)parse(RslNode.class, rsl);
  }

  public static AbstractRslNode parse(Class rslNodeClass, String rsl)
        throws ParseException {
        RSLParser parser = new RSLParser(new StringReader(rsl));
        parser.setRslNodeClass(rslNodeClass);
        return parser.parse();
  }

  public RSLParser(String rsl)
        throws ParseException {
        this(new StringReader(rsl));
  }

  public void setRslNodeClass(Class rslNodeClass) {
        nodeClass = rslNodeClass;
  }

  private String unQuotify(String str, char quoteChar) {
      char curChar;
      char nextChar;
      int size = str.length();
      StringBuffer buf = new StringBuffer(size-2);

      for (int i=1;i<size-1;i++) {
        curChar = str.charAt(i);
        if (curChar == quoteChar) {
          if (i+1 < size-1) {
            i++;
            nextChar = str.charAt(i);
            if (nextChar == quoteChar) {
              buf.append(quoteChar);
            } else {
              buf.append(nextChar);
            }
          }
        } else {
          buf.append(curChar);
        }
      }
      return buf.toString();
  }

  private Value concat(LinkedList tokenList) {
    ListIterator iter = tokenList.listIterator();

    Value value, pValue, firstValue;

    firstValue = (Value)iter.next();
    pValue = firstValue;

    while(iter.hasNext()) {
      value = (Value)iter.next();
      pValue.concat(value);
      pValue = value;
    }

    return firstValue;
  }

  private void updateValueList(Token tok, LinkedList valueList, LinkedList tokenList) {
        if (tok.specialToken != null && tokenList != null && tokenList.size() > 0) {
                valueList.add( concat(tokenList) );
                tokenList.clear();
        }
  }

  private String unQuotify(Token tok) {
        switch(tok.kind) {
                case DOUBLE_QUOTED_LITERAL:
                        return unQuotify(tok.image,'"');
                case SINGLE_QUOTED_LITERAL:
                        return unQuotify(tok.image,'\'');
                default:
                        return tok.image;
        }
  }

  final public AbstractRslNode parse() throws ParseException {
  AbstractRslNode tree;
    tree = subSpecification();
    jj_consume_token(0);
                {if (true) return tree;}
    throw new Error("Missing return statement in function");
  }

  final public void specification(AbstractRslNode parentNode) throws ParseException {
  AbstractRslNode node;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case VARIABLES:
    case VARIABLES_DQUOTE:
    case VARIABLES_SQUOTE:
    case UNQUOTED_LITERAL:
    case DOUBLE_QUOTED_LITERAL:
    case SINGLE_QUOTED_LITERAL:
      relation(parentNode);

      break;
    case AND:
    case OR:
    case MULTI:
      node = subSpecification();
           parentNode.add(node);
      break;
    default:
      jj_la1[0] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public AbstractRslNode subSpecification() throws ParseException {
  AbstractRslNode node = null;
  try {
    node = (AbstractRslNode)nodeClass.newInstance();
  } catch(Exception e) {
    throw new ParseException("Failed to instantiate rsl node class: " + e.getMessage());
  }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case AND:
      jj_consume_token(AND);
      specList(node);
           node.setOperator(RslNode.AND);
           {if (true) return node;}
      break;
    case MULTI:
      jj_consume_token(MULTI);
      specList(node);
           node.setOperator(RslNode.MULTI);
           {if (true) return node;}
      break;
    case OR:
      jj_consume_token(OR);
      specList(node);
           node.setOperator(RslNode.OR);
           {if (true) return node;}
      break;
    default:
      jj_la1[1] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public void relation(AbstractRslNode node) throws ParseException {
  String attribute;
  int op;
  LinkedList values;
  Token tok;
  Bindings bd;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case VARIABLES:
      tok = jj_consume_token(VARIABLES);
      jj_consume_token(EQUAL);
      values = bindingSequence();
                bd = new Bindings(tok.image);
                bd.setValues(values);
                node.add(bd);
      break;
    case VARIABLES_DQUOTE:
      tok = jj_consume_token(VARIABLES_DQUOTE);
      jj_consume_token(EQUAL);
      values = bindingSequence();
                bd = new Bindings(unQuotify(tok.image,'"'));
                bd.setValues(values);
                node.add(bd);
      break;
    case VARIABLES_SQUOTE:
      tok = jj_consume_token(VARIABLES_SQUOTE);
      jj_consume_token(EQUAL);
      values = bindingSequence();
                bd = new Bindings(unQuotify(tok.image,'\''));
                bd.setValues(values);
                node.add(bd);
      break;
    case UNQUOTED_LITERAL:
    case DOUBLE_QUOTED_LITERAL:
    case SINGLE_QUOTED_LITERAL:
      attribute = attribute();
      op = op();
      values = valueSequence();
                NameOpValue nm = new NameOpValue(attribute, op);
                nm.setValues(values);
                node.add(nm);
      break;
    default:
      jj_la1[2] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void specList(AbstractRslNode node) throws ParseException {
    label_1:
    while (true) {
      jj_consume_token(RPAREN);
      specification(node);
      jj_consume_token(LPAREN);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case RPAREN:
        ;
        break;
      default:
        jj_la1[3] = jj_gen;
        break label_1;
      }
    }

  }

  final public int op() throws ParseException {
  Token tok;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case EQUAL:
      tok = jj_consume_token(EQUAL);
                {if (true) return NameOpValue.EQ;}
      break;
    case NOT_EQUAL:
      tok = jj_consume_token(NOT_EQUAL);
                {if (true) return NameOpValue.NEQ;}
      break;
    case GREATER_THAN:
      tok = jj_consume_token(GREATER_THAN);
                {if (true) return NameOpValue.GT;}
      break;
    case GREATER_THAN_EQUAL:
      tok = jj_consume_token(GREATER_THAN_EQUAL);
                {if (true) return NameOpValue.GTEQ;}
      break;
    case LESS_THAN:
      tok = jj_consume_token(LESS_THAN);
                {if (true) return NameOpValue.LT;}
      break;
    case LESS_THAN_EQUAL:
      tok = jj_consume_token(LESS_THAN_EQUAL);
                {if (true) return NameOpValue.LTEQ;}
      break;
    default:
      jj_la1[4] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public String attribute() throws ParseException {
  String name;
    name = stringLiteral();
      {if (true) return name;}
    throw new Error("Missing return statement in function");
  }

  final public LinkedList valueSequence() throws ParseException {
  LinkedList list = new LinkedList();
  LinkedList tokenList = new LinkedList();
    label_2:
    while (true) {
      value(list, tokenList);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case RPAREN:
      case VARSTART:
      case UNQUOTED_LITERAL:
      case DOUBLE_QUOTED_LITERAL:
      case SINGLE_QUOTED_LITERAL:
        ;
        break;
      default:
        jj_la1[5] = jj_gen;
        break label_2;
      }
    }
        if (tokenList.size() > 0) {
                list.add( concat(tokenList) );
        }
        {if (true) return list;}
    throw new Error("Missing return statement in function");
  }

  final public LinkedList bindingSequence() throws ParseException {
  LinkedList list = new LinkedList();
    label_3:
    while (true) {
      binding(list);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case RPAREN:
        ;
        break;
      default:
        jj_la1[6] = jj_gen;
        break label_3;
      }
    }
        {if (true) return list;}
    throw new Error("Missing return statement in function");
  }

  final public void binding(LinkedList list) throws ParseException {
 Value value;
 String name;
    jj_consume_token(RPAREN);
    name = stringLiteral();
    value = concatSimpleValue();
    jj_consume_token(LPAREN);
        Binding db = new Binding(name, value);
        list.add(db);
  }

  final public void value(LinkedList list, LinkedList tokenList) throws ParseException {
 Object value = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case RPAREN:
      jj_consume_token(RPAREN);
      value = valueSequence();
      jj_consume_token(LPAREN);
        list.add(value);
      break;
    case VARSTART:
    case UNQUOTED_LITERAL:
    case DOUBLE_QUOTED_LITERAL:
    case SINGLE_QUOTED_LITERAL:
      value = SimpleValue(list, tokenList);
        tokenList.add(value);
      break;
    default:
      jj_la1[7] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public Value SimpleValue(LinkedList valueList, LinkedList tokenList) throws ParseException {
 Token t1 = null;
 Value v1 = null;
 Value v2 = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case UNQUOTED_LITERAL:
    case DOUBLE_QUOTED_LITERAL:
    case SINGLE_QUOTED_LITERAL:
      t1 = stringToken();
      v2 = explicitConcat(valueList, tokenList);
                updateValueList(t1, valueList, tokenList);

                Value v = new Value( unQuotify(t1) );
                if (v2 != null) {
                        v.concat(v2);
                }
                {if (true) return v;}
      break;
    case VARSTART:
      v1 = variableReference(valueList, tokenList);
      v2 = explicitConcat(valueList, tokenList);
                if (v2 != null) {
                        v1.concat(v2);
                }
                {if (true) return v1;}
      break;
    default:
      jj_la1[8] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public Value variableReference(LinkedList valueList, LinkedList tokenList) throws ParseException {
 String name = null;
 Value value = null;
 Token t1;
    t1 = jj_consume_token(VARSTART);
    name = stringLiteral();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case VARSTART:
    case UNQUOTED_LITERAL:
    case DOUBLE_QUOTED_LITERAL:
    case SINGLE_QUOTED_LITERAL:
      value = concatSimpleValue();
      break;
    default:
      jj_la1[9] = jj_gen;
      ;
    }
    jj_consume_token(LPAREN);
                updateValueList(t1, valueList, tokenList);

                VarRef vr = new VarRef(name);
                if (value != null) vr.setDefaultValue(value);
                {if (true) return vr;}
    throw new Error("Missing return statement in function");
  }

  final public Value explicitConcat(LinkedList valueList, LinkedList tokenList) throws ParseException {
  Object v1 = null;
  Value v2 = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case 27:
      jj_consume_token(27);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case UNQUOTED_LITERAL:
      case DOUBLE_QUOTED_LITERAL:
      case SINGLE_QUOTED_LITERAL:
        v1 = stringLiteral();
        break;
      case VARSTART:
        v1 = variableReference(valueList, tokenList);
        break;
      default:
        jj_la1[10] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      v2 = explicitConcat(valueList, tokenList);
      break;
    default:
      jj_la1[11] = jj_gen;
      ;
    }
                Value v = null;
                if (v1 instanceof String) {
                        v = new Value( (String)v1);
                } else if (v1 instanceof Value) {
                        v = (Value)v1;
                }
                if (v2 != null) {
                        v.concat(v2);
                }
                {if (true) return v;}
    throw new Error("Missing return statement in function");
  }

  final public Token stringToken() throws ParseException {
  Token tok;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case UNQUOTED_LITERAL:
      tok = jj_consume_token(UNQUOTED_LITERAL);
      {if (true) return tok;}
      break;
    case DOUBLE_QUOTED_LITERAL:
      tok = jj_consume_token(DOUBLE_QUOTED_LITERAL);
      {if (true) return tok;}
      break;
    case SINGLE_QUOTED_LITERAL:
      tok = jj_consume_token(SINGLE_QUOTED_LITERAL);
      {if (true) return tok;}
      break;
    default:
      jj_la1[12] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public String stringLiteral() throws ParseException {
  Token tok;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case UNQUOTED_LITERAL:
      tok = jj_consume_token(UNQUOTED_LITERAL);
      {if (true) return tok.image;}
      break;
    case DOUBLE_QUOTED_LITERAL:
      tok = jj_consume_token(DOUBLE_QUOTED_LITERAL);
      {if (true) return unQuotify(tok.image,'"');}
      break;
    case SINGLE_QUOTED_LITERAL:
      tok = jj_consume_token(SINGLE_QUOTED_LITERAL);
      {if (true) return unQuotify(tok.image,'\'');}
      break;
    default:
      jj_la1[13] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

// -----------------------------------------------------
  final public Value concatSimpleValue() throws ParseException {
  LinkedList list = new LinkedList();
  LinkedList tokenList = new LinkedList();
    label_4:
    while (true) {
      concatSimpleValueSub(list, tokenList);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case VARSTART:
      case UNQUOTED_LITERAL:
      case DOUBLE_QUOTED_LITERAL:
      case SINGLE_QUOTED_LITERAL:
        ;
        break;
      default:
        jj_la1[14] = jj_gen;
        break label_4;
      }
    }
        if (tokenList.size() > 0) {
                list.add( concat(tokenList) );
        }
        if (list.size() == 1) {
                {if (true) return (Value)list.getFirst();}
        } else {
                {if (true) throw new ParseException("Encountered sequence instead of a single value.");}
        }
    throw new Error("Missing return statement in function");
  }

  final public void concatSimpleValueSub(LinkedList list, LinkedList tokenList) throws ParseException {
 Object value = null;
    value = SimpleValue(list, tokenList);
        tokenList.add(value);
  }

  public RSLParserTokenManager token_source;
  ASCII_CharStream jj_input_stream;
  public Token token, jj_nt;
  private int jj_ntk;
  private int jj_gen;
  final private int[] jj_la1 = new int[15];
  final private int[] jj_la1_0 = {0x71c7000,0x7000,0x71c0000,0x8000,0xfc0,0x7028000,0x8000,0x7028000,0x7020000,0x7020000,0x7020000,0x8000000,0x7000000,0x7000000,0x7020000,};

  public RSLParser(java.io.InputStream stream) {
    jj_input_stream = new ASCII_CharStream(stream, 1, 1);
    token_source = new RSLParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  public void ReInit(java.io.InputStream stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  public RSLParser(java.io.Reader stream) {
    jj_input_stream = new ASCII_CharStream(stream, 1, 1);
    token_source = new RSLParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  public RSLParser(RSLParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  public void ReInit(RSLParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 15; i++) jj_la1[i] = -1;
  }

  final private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }

  final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    jj_gen++;
    return token;
  }

  final public Token getToken(int index) {
    Token t = token;
    for (int i = 0; i < index; i++) {
      if (t.next != null) t = t.next;
      else t = t.next = token_source.getNextToken();
    }
    return t;
  }

  final private int jj_ntk() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  private java.util.Vector jj_expentries = new java.util.Vector();
  private int[] jj_expentry;
  private int jj_kind = -1;

  final public ParseException generateParseException() {
    jj_expentries.removeAllElements();
    boolean[] la1tokens = new boolean[28];
    for (int i = 0; i < 28; i++) {
      la1tokens[i] = false;
    }
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 15; i++) {
      if (jj_la1[i] == jj_gen) {
        for (int j = 0; j < 32; j++) {
          if ((jj_la1_0[i] & (1<<j)) != 0) {
            la1tokens[j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 28; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.addElement(jj_expentry);
      }
    }
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = (int[])jj_expentries.elementAt(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  final public void enable_tracing() {
  }

  final public void disable_tracing() {
  }

}
