/* * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.joni; import org.jcodings.Encoding; import org.joni.ast.CClassNode; import org.joni.constants.Arguments; import org.joni.constants.OPCode; import org.joni.constants.OPSize; import org.joni.exception.InternalException; class ByteCodePrinter { int[]code; int codeLength; Object[]operands; int operantCount; Encoding enc; WarnCallback warnings; public ByteCodePrinter(Regex regex) { code = regex.code; codeLength = regex.codeLength; operands = regex.operands; operantCount = regex.operandLength; enc = regex.enc; warnings = regex.warnings; } public String byteCodeListToString() { return compiledByteCodeListToString(); } private void pString(StringBuilder sb, int len, int s) { sb.append(":"); while (len-- > 0) sb.append(new String(new byte[]{(byte)code[s++]})); } private void pLenString(StringBuilder sb, int len, int mbLen, int s) { int x = len * mbLen; sb.append(":" + len + ":"); while (x-- > 0) sb.append(new String(new byte[]{(byte)code[s++]})); } public int compiledByteCodeToString(StringBuilder sb, int bp) { int len, n, mem, addr, scn, cod; BitSet bs; CClassNode cc; sb.append("[" + OPCode.OpCodeNames[code[bp]]); int argType = OPCode.OpCodeArgTypes[code[bp]]; int ip = bp; if (argType != Arguments.SPECIAL) { bp++; switch (argType) { case Arguments.NON: break; case Arguments.RELADDR: sb.append(":(" + code[bp] + ")"); bp += OPSize.RELADDR; break; case Arguments.ABSADDR: sb.append(":(" + code[bp] + ")"); bp += OPSize.ABSADDR; break; case Arguments.LENGTH: sb.append(":" + code[bp]); bp += OPSize.LENGTH; break; case Arguments.MEMNUM: sb.append(":" + code[bp]); bp += OPSize.MEMNUM; break; case Arguments.OPTION: sb.append(":" + code[bp]); bp += OPSize.OPTION; break; case Arguments.STATE_CHECK: sb.append(":" + code[bp]); bp += OPSize.STATE_CHECK; break; } } else { switch (code[bp++]) { case OPCode.EXACT1: case OPCode.ANYCHAR_STAR_PEEK_NEXT: case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT: case OPCode.ANYCHAR_STAR_PEEK_NEXT_SB: case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT_SB: pString(sb, 1, bp++); break; case OPCode.EXACT2: pString(sb, 2, bp); bp += 2; break; case OPCode.EXACT3: pString(sb, 3, bp); bp += 3; break; case OPCode.EXACT4: pString(sb, 4, bp); bp += 4; break; case OPCode.EXACT5: pString(sb, 5, bp); bp += 5; break; case OPCode.EXACTN: len = code[bp]; bp += OPSize.LENGTH; pLenString(sb, len, 1, bp); bp += len; break; case OPCode.EXACTMB2N1: pString(sb, 2, bp); bp += 2; break; case OPCode.EXACTMB2N2: pString(sb, 4, bp); bp += 4; break; case OPCode.EXACTMB2N3: pString(sb, 6, bp); bp += 6; break; case OPCode.EXACTMB2N: len = code[bp]; bp += OPSize.LENGTH; pLenString(sb, len, 2, bp); bp += len * 2; break; case OPCode.EXACTMB3N: len = code[bp]; bp += OPSize.LENGTH; pLenString(sb, len, 3, bp); bp += len * 3; break; case OPCode.EXACTMBN: int mbLen = code[bp]; bp += OPSize.LENGTH; len = code[bp]; bp += OPSize.LENGTH; sb.append(":" + mbLen + ":" + len + ":"); n = len * mbLen; while (n-- > 0) sb.append(new String(new byte[]{(byte)code[bp++]})); break; case OPCode.EXACT1_IC: case OPCode.EXACT1_IC_SB: final int MAX_CHAR_LENGTH = 6; byte[]bytes = new byte[MAX_CHAR_LENGTH]; for (int i = 0; bp + i < code.length && i < MAX_CHAR_LENGTH; i++) bytes[i] = (byte)code[bp + i]; len = enc.length(bytes, 0, MAX_CHAR_LENGTH); pString(sb, len, bp); bp += len; break; case OPCode.EXACTN_IC: case OPCode.EXACTN_IC_SB: len = code[bp]; bp += OPSize.LENGTH; pLenString(sb, len, 1, bp); bp += len; break; case OPCode.CCLASS: case OPCode.CCLASS_SB: bs = new BitSet(); System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE); n = bs.numOn(); bp += BitSet.BITSET_SIZE; sb.append(":" + n); break; case OPCode.CCLASS_NOT: case OPCode.CCLASS_NOT_SB: bs = new BitSet(); System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE); n = bs.numOn(); bp += BitSet.BITSET_SIZE; sb.append(":" + n); break; case OPCode.CCLASS_MB: case OPCode.CCLASS_MB_NOT: len = code[bp]; bp += OPSize.LENGTH; cod = code[bp]; //bp += OPSize.CODE_POINT; bp += len; sb.append(":" + cod + ":" + len); break; case OPCode.CCLASS_MIX: case OPCode.CCLASS_MIX_NOT: bs = new BitSet(); System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE); n = bs.numOn(); bp += BitSet.BITSET_SIZE; len = code[bp]; bp += OPSize.LENGTH; cod = code[bp]; //bp += OPSize.CODE_POINT; bp += len; sb.append(":" + n + ":" + cod + ":" + len); break; case OPCode.CCLASS_NODE: cc = (CClassNode)operands[code[bp]]; bp += OPSize.POINTER; n = cc.bs.numOn(); sb.append(":" + cc + ":" + n); break; case OPCode.BACKREFN_IC: mem = code[bp]; bp += OPSize.MEMNUM; sb.append(":" + mem); break; case OPCode.BACKREF_MULTI_IC: case OPCode.BACKREF_MULTI: sb.append(" "); len = code[bp]; bp += OPSize.LENGTH; for (int i=0; i 0) sb.append(", "); sb.append(mem); } break; case OPCode.BACKREF_WITH_LEVEL: { int option = code[bp]; bp += OPSize.OPTION; sb.append(":" + option); int level = code[bp]; bp += OPSize.LENGTH; sb.append(":" + level); sb.append(" "); len = code[bp]; bp += OPSize.LENGTH; for (int i=0; i 0) sb.append(", "); sb.append(mem); } break; } case OPCode.REPEAT: case OPCode.REPEAT_NG: mem = code[bp]; bp += OPSize.MEMNUM; addr = code[bp]; bp += OPSize.RELADDR; sb.append(":" + mem + ":" + addr); break; case OPCode.PUSH_OR_JUMP_EXACT1: case OPCode.PUSH_IF_PEEK_NEXT: addr = code[bp]; bp += OPSize.RELADDR; sb.append(":(" + addr + ")"); pString(sb, 1, bp); bp++; break; case OPCode.LOOK_BEHIND: case OPCode.LOOK_BEHIND_SB: len = code[bp]; bp += OPSize.LENGTH; sb.append(":" + len); break; case OPCode.PUSH_LOOK_BEHIND_NOT: addr = code[bp]; bp += OPSize.RELADDR; len = code[bp]; bp += OPSize.LENGTH; sb.append(":" + len + ":(" + addr + ")"); break; case OPCode.STATE_CHECK_PUSH: case OPCode.STATE_CHECK_PUSH_OR_JUMP: scn = code[bp]; bp += OPSize.STATE_CHECK_NUM; addr = code[bp]; bp += OPSize.RELADDR; sb.append(":" + scn + ":(" + addr + ")"); break; default: throw new InternalException("undefined code: " + code[--bp]); } } sb.append("]"); // @opcode_address(opcode_size) if (Config.DEBUG_COMPILE_BYTE_CODE_INFO) sb.append("@" + ip + "(" + (bp - ip) + ")"); return bp; } private String compiledByteCodeListToString() { StringBuilder sb = new StringBuilder(); sb.append("code length: " + codeLength + "\n"); int ncode = 0; int bp = 0; int end = codeLength; while (bp < end) { ncode++; if (bp > 0) sb.append(ncode % 5 == 0 ? "\n" : " "); bp = compiledByteCodeToString(sb, bp); } sb.append("\n"); return sb.toString(); } }