if (opts == null) return true;
      for (; !opts.isNil(); opts = opts.tail()) {
        EObject opt = opts.head();
        // unicode | anchored | caseless | dollar_endonly | dotall |
        // extended
        // | firstline | multiline | no_auto_capture | dupnames |
        // ungreedy
        // | {newline, NLSpec}| bsr_anycrlf | bsr_unicode
        ETuple tup;
        ESmall off;
        if (opt == am_unicode) {
          unicode = true;
        } else if (opt == am_anchored) {
          anchored = true;
        } else if (opt == am_global) {
          global = true;
        } else if (opt == am_caseless) {
          flags |= Pattern.CASE_INSENSITIVE;
        } else if (opt == am_dollar_endonly) {
          throw new NotImplemented("regex option "+opt);
        } else if (opt == am_dotall) {
          flags |= Pattern.DOTALL;
        } else if (opt == am_extended) {
          flags |= Pattern.COMMENTS;
        } else if (opt == am_firstline) {
          throw new NotImplemented("regex option "+opt);
        } else if (opt == am_multiline) {
          flags |= Pattern.MULTILINE;
        } else if (opt == am_no_auto_capture) {
          throw new NotImplemented("regex option "+opt);
        } else if (opt == am_dupnames) {
          throw new NotImplemented("regex option "+opt);
        } else if (opt == am_ungreedy) {
          throw new NotImplemented("regex option "+opt);
        } else if (opt == am_bsr_anycrlf) {
          newline_cr = true;
          newline_crlf = true;
          newline_lf = true;
          newline_any = false;
        } else if (opt == am_bsr_unicode) {
          newline_any = true;
        } else if ((tup = opt.testTuple()) != null && tup.arity() == 2
            && tup.elm(1) == am_newline) {
          newline_cr = false;
          newline_crlf = false;
          newline_lf = false;
          newline_any = false;
          EObject val = tup.elm(2);
          if (val == am_cr) {
            newline_cr = true;
          } else if (val == am_lf) {
            newline_lf = true;
          } else if (val == am_crlf) {
            newline_crlf = true;
          } else if (val == am_anycrlf) {
            newline_cr = true;
            newline_lf = true;
            newline_crlf = true;
          } else if (val == am_any) {
            newline_any = true;
          } else {
            return false;
          }
          
        } else if (tup != null && tup.arity() == 2 && tup.elm(1) == am_capture) {
          this.capture_spec = tup.elm(2);
          this.capture_type = am_index;
        } else if (tup != null && tup.arity() == 3 && tup.elm(1) == am_capture) {
          this.capture_spec = tup.elm(2);
          this.capture_type = tup.elm(3);
        } else if (tup != null && tup.arity() == 2 
            && tup.elm(1) == am_offset
            && (off=tup.elm(2).testSmall()) != null) {
          this.offset = off.value;
        } else {
          return false;
        }
      }
      
      ESeq spec;
      if (capture_spec == am_all 
        || capture_spec == am_all_but_first
        || capture_spec == am_first
        || capture_spec == am_none
        ) {
        // ok
      } else if ((spec=capture_spec.testSeq()) != null) {
        
        // if it is a sequence, make sure elements are integers
        while (!spec.isNil()) {
          EObject val = spec.head();
          if (val.testSmall() == null && val.testString() == null && val.testAtom() == null)
            return false;
          spec = spec.tail();
        }
        
        // ok