internal string DescribeInstruction(int opcodeOffset) { RegexOpcode opcode = (RegexOpcode)Codes[opcodeOffset]; var sb = new StringBuilder(); sb.Append($"{opcodeOffset:D6} "); sb.Append(OpcodeBacktracks(opcode & RegexOpcode.OperatorMask) ? '~' : ' '); sb.Append(opcode & RegexOpcode.OperatorMask); if ((opcode & RegexOpcode.CaseInsensitive) != 0) { sb.Append("-Ci"); } if ((opcode & RegexOpcode.RightToLeft) != 0) { sb.Append("-Rtl"); } if ((opcode & RegexOpcode.Backtracking) != 0) { sb.Append("-Back"); } if ((opcode & RegexOpcode.BacktrackingSecond) != 0) { sb.Append("-Back2"); } opcode &= RegexOpcode.OperatorMask; switch (opcode) { case RegexOpcode.One: case RegexOpcode.Onerep: case RegexOpcode.Oneloop: case RegexOpcode.Oneloopatomic: case RegexOpcode.Onelazy: case RegexOpcode.Notone: case RegexOpcode.Notonerep: case RegexOpcode.Notoneloop: case RegexOpcode.Notoneloopatomic: case RegexOpcode.Notonelazy: sb.Append(Indent()).Append('\'').Append(RegexCharClass.DescribeChar((char)Codes[opcodeOffset + 1])).Append('\''); break; case RegexOpcode.Set: case RegexOpcode.Setrep: case RegexOpcode.Setloop: case RegexOpcode.Setloopatomic: case RegexOpcode.Setlazy: sb.Append(Indent()).Append(RegexCharClass.DescribeSet(Strings[Codes[opcodeOffset + 1]])); break; case RegexOpcode.Multi: sb.Append(Indent()).Append('"').Append(Strings[Codes[opcodeOffset + 1]]).Append('"'); break; case RegexOpcode.Backreference: case RegexOpcode.TestBackreference: sb.Append(Indent()).Append("index = ").Append(Codes[opcodeOffset + 1]); break; case RegexOpcode.Capturemark: sb.Append(Indent()).Append("index = ").Append(Codes[opcodeOffset + 1]); if (Codes[opcodeOffset + 2] != -1) { sb.Append(", unindex = ").Append(Codes[opcodeOffset + 2]); } break; case RegexOpcode.Nullcount: case RegexOpcode.Setcount: sb.Append(Indent()).Append("value = ").Append(Codes[opcodeOffset + 1]); break; case RegexOpcode.Goto: case RegexOpcode.Lazybranch: case RegexOpcode.Branchmark: case RegexOpcode.Lazybranchmark: case RegexOpcode.Branchcount: case RegexOpcode.Lazybranchcount: sb.Append(Indent()).Append("addr = ").Append(Codes[opcodeOffset + 1]); break; } switch (opcode) { case RegexOpcode.Onerep: case RegexOpcode.Oneloop: case RegexOpcode.Oneloopatomic: case RegexOpcode.Onelazy: case RegexOpcode.Notonerep: case RegexOpcode.Notoneloop: case RegexOpcode.Notoneloopatomic: case RegexOpcode.Notonelazy: case RegexOpcode.Setrep: case RegexOpcode.Setloop: case RegexOpcode.Setloopatomic: case RegexOpcode.Setlazy: sb.Append(", rep = ").Append(Codes[opcodeOffset + 2] == int.MaxValue ? "inf" : Codes[opcodeOffset + 2]); break; case RegexOpcode.Branchcount: case RegexOpcode.Lazybranchcount: sb.Append(", limit = ").Append(Codes[opcodeOffset + 2] == int.MaxValue ? "inf" : Codes[opcodeOffset + 2]); break; } return(sb.ToString()); string Indent() => new string(' ', Math.Max(1, 25 - sb.Length)); }