private boolean compileLeft() {
   cleft = new ArrayList<Construct>();
   if (label != null && label.startsWith("!")) {
     if (label.length() > 1) {
       label = label.substring(1);
     }
     nolog = true;
   }
   for (int i = 0; i < left.size(); i++) {
     Token t = left.get(i);
     if (t.value.startsWith("/")) {
       cleft.add(new Command(t.val(), t.target));
     } else if (t.type == Token.TType.VARIABLE) {
       cleft.add(new Variable(t.val(), null, t.target));
     } else if (t.type.equals(TType.FINAL_VAR)) {
       Variable v = new Variable(t.val(), null, t.target);
       v.setFinal(true);
       cleft.add(v);
     } else if (t.type.equals(TType.LSQUARE_BRACKET)) {
       if (i + 2 < left.size() && left.get(i + 2).type.equals(TType.OPT_VAR_ASSIGN)) {
         Variable v = new Variable(left.get(i + 1).val(), left.get(i + 3).val(), t.target);
         v.setOptional(true);
         if (left.get(i + 1).type.equals(TType.FINAL_VAR)) {
           v.setFinal(true);
         }
         cleft.add(v);
         i += 4;
       } else {
         t = left.get(i + 1);
         Variable v = new Variable(t.val(), null, t.target);
         v.setOptional(true);
         if (t.val().equals("$")) {
           v.setFinal(true);
         }
         cleft.add(v);
         i += 2;
       }
     } else {
       cleft.add(new CString(t.val(), t.getTarget()));
     }
   }
   return true;
 }
  private boolean verifyLeft() throws ConfigCompileException {
    boolean inside_opt_var = false;
    boolean after_no_def_opt_var = false;
    String lastVar = null;
    // Go through our token list and readjust non-spaced symbols. Any time we combine a symbol,
    // the token becomes a string
    List<Token> tempLeft = new ArrayList<Token>();
    for (int i = 0; i < left.size(); i++) {
      Token t = left.get(i);
      if (i == 0 && t.type == TType.NEWLINE) {
        continue;
      }
      if (t.type.isSymbol() && left.size() - 1 > i && left.get(i + 1).type != TType.WHITESPACE) {
        StringBuilder b = new StringBuilder();
        b.append(t.value);
        i++;
        Token m = left.get(i);
        while (m.type.isSymbol() && m.type != TType.WHITESPACE) {
          b.append(m.value);
          i++;
          m = left.get(i);
        }

        if (m.type != TType.WHITESPACE && m.type != TType.LABEL) {
          b.append(m.value);
        }
        t = new Token(TType.STRING, b.toString(), t.target);
        if (m.type == TType.LABEL) {
          tempLeft.add(t);
          tempLeft.add(m);
          continue;
        }
      }
      // Go ahead and toString the other symbols too
      if (t.type.isSymbol()) {
        t = new Token(TType.STRING, t.value, t.target);
      }
      if (t.type != TType.WHITESPACE) {
        tempLeft.add(t);
      }
    }
    // Look through and concatenate all tokens before the label, if such exists.
    boolean hasLabel = false;
    for (int i = 0; i < tempLeft.size(); i++) {
      if (tempLeft.get(i).type == TType.LABEL) {
        hasLabel = true;
        break;
      }
    }
    if (hasLabel) {
      StringBuilder b = new StringBuilder();
      int count = 0;
      while (tempLeft.get(count).type != TType.LABEL) {
        b.append(tempLeft.get(count).val());
        count++;
      }
      tempLeft.set(0, new Token(TType.STRING, b.toString(), Target.UNKNOWN));
      for (int i = 0; i < count - 1; i++) {
        tempLeft.remove(1);
      }
    }
    left = tempLeft;
    for (int j = 0; j < left.size(); j++) {
      Token t = left.get(j);
      // Token prev_token = j - 2 >= 0?c.tokens.get(j - 2):new Token(TType.UNKNOWN, "", t.line_num);
      Token last_token = j - 1 >= 0 ? left.get(j - 1) : new Token(TType.UNKNOWN, "", t.getTarget());
      Token next_token =
          j + 1 < left.size() ? left.get(j + 1) : new Token(TType.UNKNOWN, "", t.getTarget());
      Token after_token =
          j + 2 < left.size() ? left.get(j + 2) : new Token(TType.UNKNOWN, "", t.getTarget());

      if (j == 0) {
        if (next_token.type == TType.LABEL) {
          this.label = t.val();
          j--;
          left.remove(0);
          left.remove(0);
          continue;
        }
      }

      if (t.type == TType.LABEL) {
        continue;
      }

      if (t.type.equals(TType.FINAL_VAR) && left.size() - j >= 5) {
        throw new ConfigCompileException(
            "FINAL_VAR must be the last argument in the alias", t.target);
      }
      if (t.type.equals(TType.VARIABLE) || t.type.equals(TType.FINAL_VAR)) {
        Variable v = new Variable(t.val(), null, t.target);
        lastVar = t.val();
        v.setOptional(last_token.type.equals(TType.LSQUARE_BRACKET));
        left_vars.put(t.val(), v);
        if (v.isOptional()) {
          after_no_def_opt_var = true;
        } else {
          v.setDefault("");
        }
      }
      // We're looking for a command up front
      if (j == 0 && !t.value.startsWith("/")) {
        if (!(next_token.type == TType.LABEL && after_token.type == TType.COMMAND)) {
          throw new ConfigCompileException(
              "Expected command (/command) at start of alias."
                  + " Instead, found "
                  + t.type
                  + " ("
                  + t.val()
                  + ")",
              t.target);
        }
      }
      if (last_token.type.equals(TType.LSQUARE_BRACKET)) {
        inside_opt_var = true;
        if (!(t.type.equals(TType.FINAL_VAR) || t.type.equals(TType.VARIABLE))) {
          throw new ConfigCompileException(
              "Unexpected "
                  + t.type.toString()
                  + " ("
                  + t.val()
                  + "), was expecting"
                  + " a $variable",
              t.target);
        }
      }
      if (after_no_def_opt_var && !inside_opt_var) {
        if (t.type.equals(TType.VARIABLE) || t.type.equals(TType.FINAL_VAR)) {
          throw new ConfigCompileException(
              "You cannot have anything other than optional arguments after your"
                  + " first optional argument.",
              t.target);
        }
      }
      if (!t.type.equals(TType.LSQUARE_BRACKET)
          && !t.type.equals(TType.OPT_VAR_ASSIGN)
          && !t.type.equals(TType.RSQUARE_BRACKET)
          && !t.type.equals(TType.VARIABLE)
          && !t.type.equals(TType.LIT)
          && !t.type.equals(TType.COMMAND)
          && !t.type.equals(TType.FINAL_VAR)) {
        if (j - 1 > 0
            && !(
            /*t.type.equals(TType.STRING) &&*/ left.get(j - 1).type.equals(TType.OPT_VAR_ASSIGN))) {
          throw new ConfigCompileException("Unexpected " + t.type + " (" + t.val() + ")", t.target);
        }
      }
      if (last_token.type.equals(TType.COMMAND)) {
        if (!(t.type.equals(TType.VARIABLE)
            || t.type.equals(TType.LSQUARE_BRACKET)
            || t.type.equals(TType.FINAL_VAR)
            || t.type.equals(TType.LIT))) {
          throw new ConfigCompileException(
              "Unexpected " + t.type + " (" + t.val() + ") after command", t.target);
        }
      }
      if (inside_opt_var && t.type.equals(TType.OPT_VAR_ASSIGN)) {
        if (!((next_token.type.equals(TType.STRING) || next_token.type.equals(TType.LIT))
                && after_token.type.equals(TType.RSQUARE_BRACKET)
            || (next_token.type.equals(TType.RSQUARE_BRACKET)))) {
          throw new ConfigCompileException("Unexpected token in optional variable", t.target);
        } else if (next_token.type.equals(TType.STRING) || next_token.type.equals(TType.LIT)) {
          left_vars.get(lastVar).setDefault(next_token.val());
        }
      }
      if (t.type.equals(TType.RSQUARE_BRACKET)) {
        if (!inside_opt_var) {
          throw new ConfigCompileException("Unexpected " + t.type.toString(), t.target);
        }
        inside_opt_var = false;
        //                if (last_token.type.equals(TType.VARIABLE)
        //                        || last_token.type.equals(TType.FINAL_VAR)) {
        //                    after_no_def_opt_var = true;
        //                }
      }
    }

    return true;
  }