gt:         switch (ch) {
context: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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 eu.unitn.disi.db.command.util;
  
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.ARRAY;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.ASSIGN;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.CLOSURE;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.EXECUTION;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.NEWLINE;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.PIPE;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.SEMICOLON;
  import static eu.unitn.disi.db.command.util.Tokenizer.Type.WORD;
  import static java.lang.Character.isJavaIdentifierPart;
  import static java.lang.Integer.parseInt;
  import static java.lang.String.valueOf;
  import static java.lang.System.err;
  
  /**
   * Bash-like tokenizer.
   *
   * Single and double quotes are just like Bash - single quotes escape everything
   * (including backslashes), newlines are allowed in quotes. backslash-newline
   * indicates a line continuation and is removed.
   *
   * Variable expansion is just like Bash: $NAME or ${NAME[[:][-+=?WORD]}, except
   * it can yield any Object. Variables expanded within double-quotes, or adjacent
   * to a String are converted to String.
   *
   * Unlike bash, indirect variable expansion is supported using ${$NAME}.
   *
   * Only a single variable assignment is recognized, with '=' being the second
   * token. (Bash allows name1=value1 name2=value2 ... command args)
   *
   * Comments can only start where white space is allowed: # or // starts a line
   * comment, /* starts a block comment. The following common uses do NOT start
   * comments: ls http://example.com#anchor ls $dir/*.java
   *
   * @see http://wiki.bash-hackers.org/syntax/basicgrammar
   */
  public class Tokenizer {
  
      public enum Type {
  
          ASSIGN('='), PIPE('|'), SEMICOLON(';'), NEWLINE, ARRAY, CLOSURE, EXECUTION, WORD, EOT;
  
          private char c;
  
          Type() {
          }
  
          Type(char c) {
              this.c = c;
          }
  
          @Override
          public String toString() {
              return (c == 0 ? super.toString() : "'" + c + "'");
          }
      }
  
      private static final boolean DEBUG = false;
      private static final char EOT = (char) -1;
  
      private final CharSequence text;
      private final Evaluate evaluate;
      private final boolean inArray;
      private final boolean inQuote;
  
      private Type type = NEWLINE;
      private CharSequence value;
      private Token token;
  
      private short line;
      private short column;
      private char ch;
      private int index;
      private boolean firstWord;
  
      public Tokenizer(CharSequence text) {
          this(text, null, false);
      }
  
      public Tokenizer(CharSequence text, Evaluate evaluate, boolean inQuote) {
          this.text = text;
          this.evaluate = evaluate;
          this.inQuote = inQuote;
          index = 0;
          line = column = 1;
  
          boolean array = false;
  
          if (text instanceof Token) {
              Token t = (Token) text;
              line = t.line;
              column = t.column;
              array = (ARRAY == t.type);
          }
  
          inArray = array;
          getch();
  
          if (DEBUG) {
              if (inArray) {
                  err.println("Tokenizer[" + text + "]");
              } else {
                  err.println("Tokenizer<" + text + ">");
              }
          }
      }
  
      public Type type() {
          return type;
      }
  
      public CharSequence value() {
          return value;
      }
  
      public Token token() {
          return token;
      }
  
      public Type next() {
          final Type prevType = type;
          token = null;
          value = null;
  
          short tLine;
          short tColumn;
  
          while (true) {
              skipSpace();
              tLine = line;
              tColumn = column;
  
              switch (ch) {
                  case EOT:
                      type = Type.EOT;
                      break;
  
                  case '\n':
                      getch();
                      if (inArray) {
                          continue;
                      }
                      // only return NEWLINE once and not if not preceded by ; or |
                      switch (prevType) {
                          case PIPE:
                          case SEMICOLON:
                          case NEWLINE:
                              continue;
  
                          default:
                              type = NEWLINE;
                              break;
                      }
                      break;
  
                  case '{':
                  case '(':
                  case '[':
                      value = group();
                      getch();
                      break;
  
                  case ';':
                      getch();
                      type = SEMICOLON;
                      break;
  
                  case '|':
                      getch();
                      type = PIPE;
                      break;
  
                  case '=':
                      if (firstWord || inArray) {
                          getch();
                          type = ASSIGN;
                          break;
                      }
                  // fall through
                  default:
                      value = word();
                      type = WORD;
              }
  
              firstWord = (WORD == type && (WORD != prevType && ASSIGN != prevType));
              token = new Token(type, value, tLine, tColumn);
  
              if (DEBUG) {
                  err.print("<" + type + ">");
                  if (Type.EOT == type) {
                      err.println();
                  }
              }
  
              return type;
          }
      }
  
      private CharSequence word() {
          int start = index - 1;
          int skipCR = 0;
  
          do {
              switch (ch) {
                  case '\n':
                      if (index >= 2 && text.charAt(index - 2) == '\r') {
                          skipCR = 1;
                      }
                  // fall through
                  case '=':
                      if ((WORD == type || ASSIGN == type) && '=' == ch
                              && !inArray) {
                          continue;
                      }
                  // fall through
                  case ' ':
                  case '\t':
                  case '|':
                  case ';':
                      return text.subSequence(start, index - 1 - skipCR);
  
                  case '{':
                      group();
                      break;
  
                  case '\\':
                      escape();
                      break;
  
                  case '\'':
                  case '"':
                      skipQuote();
                      break;
              }
          } while (getch() != EOT);
  
          return text.subSequence(start, index - 1);
      }
  
      private CharSequence group() {
          final char push = ch;
          final char pop;
  
  