content: // Copyright 2010 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Original Go source here:
  // http://code.google.com/p/go/source/browse/src/pkg/regexp/syntax/prog.go
  
  package com.github.aaronshan.functions.regexp.re2j;
  
  /**
   * A single instruction in the regular expression virtual machine.
   *
   * @see http://swtch.com/~rsc/regexp/regexp2.html
   */
  class Inst {
  
      Op op;
      int out;  // all but MATCH, FAIL
      int arg;  // ALT, ALT_MATCH, CAPTURE, EMPTY_WIDTH
      byte[] byteRanges; // length==1 => exact match. Otherwise a list of [lo,hi] pairs.  hi is *inclusive*.
      Inst(Op op) {
          this.op = op;
      }
  
      // op() returns i.Op but merges all the byte special cases into BYTE
      // Beware "op" is a public field.
      Op op() {
          switch (op) {
              case BYTE1:
                  return Op.BYTE;
              default:
                  return op;
          }
      }
  
      // MatchByte returns true if the instruction matches (and consumes) b.
      // It should only be called when op == InstByte.
      boolean matchByte(byte b) {
          // Special case: single-byte slice is from literal string, not byte range.
          if (byteRanges.length == 1) {
              int b0 = byteRanges[0];
              return b == b0;
          }
  
          // Search through all pairs.
          int byteInt = b & 0xff;
          for (int j = 0; j < byteRanges.length; j += 2) {
              if (byteInt < (byteRanges[j] & 0xff)) {
                  return false;
              }
              if (byteInt <= (byteRanges[j + 1] & 0xff)) {
                  return true;
              }
          }
  
          return false;
      }
  
      @Override
      public String toString() {
          switch (op) {
              case ALT:
                  return "alt -> " + out + ", " + arg;
              case ALT_MATCH:
                  return "altmatch -> " + out + ", " + arg;
              case CAPTURE:
                  return "cap " + arg + " -> " + out;
              case EMPTY_WIDTH:
                  return "empty " + arg + " -> " + out;
              case MATCH:
                  return "match";
              case FAIL:
                  return "fail";
              case NOP:
                  return "nop -> " + out;
              case BYTE:
                  return "byte " + appendBytes() + " -> " + out;
              case BYTE1:
                  return "byte1 " + appendBytes() + " -> " + out;
              default:
                  throw new IllegalStateException("unhandled case in Inst.toString");
          }
      }
  
      private String appendBytes() {
          StringBuilder out = new StringBuilder();
          if (byteRanges.length == 1) {
              out.append(byteRanges[0] & 0xff);
          } else {
              for (int i = 0; i < byteRanges.length; i += 2) {
                  out.append("[")
                          .append(byteRanges[i] & 0xff)
                          .append(",")
                          .append(byteRanges[i + 1] & 0xff)
                          .append("]");
                  if (i < byteRanges.length - 2) {
                      out.append(";");
                  }
              }
          }
          return out.toString();
      }
  
      enum Op {
          ALT,
          ALT_MATCH,
          CAPTURE,
          EMPTY_WIDTH,
          FAIL,
          MATCH,
          NOP,
          BYTE,
          BYTE1
      }
  }
  