ParensIndex() private method

Get start of parenthesis capture contents, -1 for empty.
Get start of parenthesis capture contents, -1 for empty.
private ParensIndex ( int i ) : int
i int
return int
Example #1
0
		private static bool ExecuteREBytecode(REGlobalData gData, string input, int end)
		{
			int pc = 0;
			byte[] program = gData.regexp.program;
			int continuationOp = REOP_END;
			int continuationPc = 0;
			bool result = false;
			int op = program[pc++];
			if (gData.regexp.anchorCh < 0 && ReopIsSimple(op))
			{
				bool anchor = false;
				while (gData.cp <= end)
				{
					int match = SimpleMatch(gData, input, op, program, pc, end, true);
					if (match >= 0)
					{
						anchor = true;
						pc = match;
						op = program[pc++];
						break;
					}
					gData.skipped++;
					gData.cp++;
				}
				if (!anchor)
				{
					return false;
				}
			}
			for (; ; )
			{
				if (ReopIsSimple(op))
				{
					int match = SimpleMatch(gData, input, op, program, pc, end, true);
					result = match >= 0;
					if (result)
					{
						pc = match;
					}
				}
				else
				{
					switch (op)
					{
						case REOP_ALTPREREQ:
						case REOP_ALTPREREQi:
						case REOP_ALTPREREQ2:
						{
							char matchCh1 = (char)GetIndex(program, pc);
							pc += INDEX_LEN;
							char matchCh2 = (char)GetIndex(program, pc);
							pc += INDEX_LEN;
							if (gData.cp == end)
							{
								result = false;
								break;
							}
							char c = input[gData.cp];
							if (op == REOP_ALTPREREQ2)
							{
								if (c != matchCh1 && !ClassMatcher(gData, gData.regexp.classList[matchCh2], c))
								{
									result = false;
									break;
								}
							}
							else
							{
								if (op == REOP_ALTPREREQi)
								{
									c = Upcase(c);
								}
								if (c != matchCh1 && c != matchCh2)
								{
									result = false;
									break;
								}
							}
							goto case REOP_ALT;
						}

						case REOP_ALT:
						{
							int nextpc = pc + GetOffset(program, pc);
							pc += INDEX_LEN;
							op = program[pc++];
							int startcp = gData.cp;
							if (ReopIsSimple(op))
							{
								int match = SimpleMatch(gData, input, op, program, pc, end, true);
								if (match < 0)
								{
									op = program[nextpc++];
									pc = nextpc;
									continue;
								}
								result = true;
								pc = match;
								op = program[pc++];
							}
							byte nextop = program[nextpc++];
							PushBackTrackState(gData, nextop, nextpc, startcp, continuationOp, continuationPc);
							continue;
						}

						case REOP_JUMP:
						{
							int offset = GetOffset(program, pc);
							pc += offset;
							op = program[pc++];
							continue;
						}

						case REOP_LPAREN:
						{
							int parenIndex = GetIndex(program, pc);
							pc += INDEX_LEN;
							gData.SetParens(parenIndex, gData.cp, 0);
							op = program[pc++];
							continue;
						}

						case REOP_RPAREN:
						{
							int parenIndex = GetIndex(program, pc);
							pc += INDEX_LEN;
							int cap_index = gData.ParensIndex(parenIndex);
							gData.SetParens(parenIndex, cap_index, gData.cp - cap_index);
							op = program[pc++];
							continue;
						}

						case REOP_ASSERT:
						{
							int nextpc = pc + GetIndex(program, pc);
							pc += INDEX_LEN;
							op = program[pc++];
							if (ReopIsSimple(op) && SimpleMatch(gData, input, op, program, pc, end, false) < 0)
							{
								result = false;
								break;
							}
							PushProgState(gData, 0, 0, gData.cp, gData.backTrackStackTop, continuationOp, continuationPc);
							PushBackTrackState(gData, REOP_ASSERTTEST, nextpc);
							continue;
						}

						case REOP_ASSERT_NOT:
						{
							int nextpc = pc + GetIndex(program, pc);
							pc += INDEX_LEN;
							op = program[pc++];
							if (ReopIsSimple(op))
							{
								int match = SimpleMatch(gData, input, op, program, pc, end, false);
								if (match >= 0 && program[match] == REOP_ASSERTNOTTEST)
								{
									result = false;
									break;
								}
							}
							PushProgState(gData, 0, 0, gData.cp, gData.backTrackStackTop, continuationOp, continuationPc);
							PushBackTrackState(gData, REOP_ASSERTNOTTEST, nextpc);
							continue;
						}

						case REOP_ASSERTTEST:
						case REOP_ASSERTNOTTEST:
						{
							REProgState state = PopProgState(gData);
							gData.cp = state.index;
							gData.backTrackStackTop = state.backTrack;
							continuationPc = state.continuationPc;
							continuationOp = state.continuationOp;
							if (op == REOP_ASSERTNOTTEST)
							{
								result = !result;
							}
							break;
						}

						case REOP_STAR:
						case REOP_PLUS:
						case REOP_OPT:
						case REOP_QUANT:
						case REOP_MINIMALSTAR:
						case REOP_MINIMALPLUS:
						case REOP_MINIMALOPT:
						case REOP_MINIMALQUANT:
						{
							int min;
							int max;
							bool greedy = false;
							switch (op)
							{
								case REOP_STAR:
								{
									greedy = true;
									goto case REOP_MINIMALSTAR;
								}

								case REOP_MINIMALSTAR:
								{
									// fallthrough
									min = 0;
									max = -1;
									break;
								}

								case REOP_PLUS:
								{
									greedy = true;
									goto case REOP_MINIMALPLUS;
								}

								case REOP_MINIMALPLUS:
								{
									// fallthrough
									min = 1;
									max = -1;
									break;
								}

								case REOP_OPT:
								{
									greedy = true;
									goto case REOP_MINIMALOPT;
								}

								case REOP_MINIMALOPT:
								{
									// fallthrough
									min = 0;
									max = 1;
									break;
								}

								case REOP_QUANT:
								{
									greedy = true;
									goto case REOP_MINIMALQUANT;
								}

								case REOP_MINIMALQUANT:
								{
									// fallthrough
									min = GetOffset(program, pc);
									pc += INDEX_LEN;
									// See comments in emitREBytecode for " - 1" reason
									max = GetOffset(program, pc) - 1;
									pc += INDEX_LEN;
									break;
								}

								default:
								{
									throw Kit.CodeBug();
								}
							}
							PushProgState(gData, min, max, gData.cp, null, continuationOp, continuationPc);
							if (greedy)
							{
								PushBackTrackState(gData, REOP_REPEAT, pc);
								continuationOp = REOP_REPEAT;
								continuationPc = pc;
								pc += 3 * INDEX_LEN;
								op = program[pc++];
							}
							else
							{
								if (min != 0)
								{
									continuationOp = REOP_MINIMALREPEAT;
									continuationPc = pc;
									pc += 3 * INDEX_LEN;
									op = program[pc++];
								}
								else
								{
									PushBackTrackState(gData, REOP_MINIMALREPEAT, pc);
									PopProgState(gData);
									pc += 2 * INDEX_LEN;
									// <parencount> & <parenindex>
									pc = pc + GetOffset(program, pc);
									op = program[pc++];
								}
							}
							continue;
						}

						case REOP_ENDCHILD:
						{
							// If we have not gotten a result here, it is because of an
							// empty match.  Do the same thing REOP_EMPTY would do.
							result = true;
							// Use the current continuation.
							pc = continuationPc;
							op = continuationOp;
							continue;
						}

						case REOP_REPEAT:
						{
							int nextpc;
							int nextop;
							do
							{
								REProgState state = PopProgState(gData);
								if (!result)
								{
									// Failed, see if we have enough children.
									if (state.min == 0)
									{
										result = true;
									}
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									pc += 2 * INDEX_LEN;
									pc += GetOffset(program, pc);
									goto switchStatement_break;
								}
								if (state.min == 0 && gData.cp == state.index)
								{
									// matched an empty string, that'll get us nowhere
									result = false;
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									pc += 2 * INDEX_LEN;
									pc += GetOffset(program, pc);
									goto switchStatement_break;
								}
								int new_min = state.min;
								int new_max = state.max;
								if (new_min != 0)
								{
									new_min--;
								}
								if (new_max != -1)
								{
									new_max--;
								}
								if (new_max == 0)
								{
									result = true;
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									pc += 2 * INDEX_LEN;
									pc += GetOffset(program, pc);
									goto switchStatement_break;
								}
								nextpc = pc + 3 * INDEX_LEN;
								nextop = program[nextpc];
								int startcp = gData.cp;
								if (ReopIsSimple(nextop))
								{
									nextpc++;
									int match = SimpleMatch(gData, input, nextop, program, nextpc, end, true);
									if (match < 0)
									{
										result = (new_min == 0);
										continuationPc = state.continuationPc;
										continuationOp = state.continuationOp;
										pc += 2 * INDEX_LEN;
										pc += GetOffset(program, pc);
										goto switchStatement_break;
									}
									result = true;
									nextpc = match;
								}
								continuationOp = REOP_REPEAT;
								continuationPc = pc;
								PushProgState(gData, new_min, new_max, startcp, null, state.continuationOp, state.continuationPc);
								if (new_min == 0)
								{
									PushBackTrackState(gData, REOP_REPEAT, pc, startcp, state.continuationOp, state.continuationPc);
									int parenCount = GetIndex(program, pc);
									int parenIndex = GetIndex(program, pc + INDEX_LEN);
									for (int k = 0; k < parenCount; k++)
									{
										gData.SetParens(parenIndex + k, -1, 0);
									}
								}
							}
							while (program[nextpc] == REOP_ENDCHILD);
							pc = nextpc;
							op = program[pc++];
							continue;
						}

						case REOP_MINIMALREPEAT:
						{
							REProgState state = PopProgState(gData);
							if (!result)
							{
								//
								// Non-greedy failure - try to consume another child.
								//
								if (state.max == -1 || state.max > 0)
								{
									PushProgState(gData, state.min, state.max, gData.cp, null, state.continuationOp, state.continuationPc);
									continuationOp = REOP_MINIMALREPEAT;
									continuationPc = pc;
									int parenCount = GetIndex(program, pc);
									pc += INDEX_LEN;
									int parenIndex = GetIndex(program, pc);
									pc += 2 * INDEX_LEN;
									for (int k = 0; k < parenCount; k++)
									{
										gData.SetParens(parenIndex + k, -1, 0);
									}
									op = program[pc++];
									continue;
								}
								else
								{
									// Don't need to adjust pc since we're going to pop.
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									break;
								}
							}
							else
							{
								if (state.min == 0 && gData.cp == state.index)
								{
									// Matched an empty string, that'll get us nowhere.
									result = false;
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									break;
								}
								int new_min = state.min;
								int new_max = state.max;
								if (new_min != 0)
								{
									new_min--;
								}
								if (new_max != -1)
								{
									new_max--;
								}
								PushProgState(gData, new_min, new_max, gData.cp, null, state.continuationOp, state.continuationPc);
								if (new_min != 0)
								{
									continuationOp = REOP_MINIMALREPEAT;
									continuationPc = pc;
									int parenCount = GetIndex(program, pc);
									pc += INDEX_LEN;
									int parenIndex = GetIndex(program, pc);
									pc += 2 * INDEX_LEN;
									for (int k = 0; k < parenCount; k++)
									{
										gData.SetParens(parenIndex + k, -1, 0);
									}
									op = program[pc++];
								}
								else
								{
									continuationPc = state.continuationPc;
									continuationOp = state.continuationOp;
									PushBackTrackState(gData, REOP_MINIMALREPEAT, pc);
									PopProgState(gData);
									pc += 2 * INDEX_LEN;
									pc = pc + GetOffset(program, pc);
									op = program[pc++];
								}
								continue;
							}
							goto case REOP_END;
						}

						case REOP_END:
						{
							return true;
						}

						default:
						{
							throw Kit.CodeBug("invalid bytecode");
						}
					}
switchStatement_break: ;
				}
				if (!result)
				{
					REBackTrackData backTrackData = gData.backTrackStackTop;
					if (backTrackData != null)
					{
						gData.backTrackStackTop = backTrackData.previous;
						gData.parens = backTrackData.parens;
						gData.cp = backTrackData.cp;
						gData.stateStackTop = backTrackData.stateStackTop;
						continuationOp = backTrackData.continuationOp;
						continuationPc = backTrackData.continuationPc;
						pc = backTrackData.pc;
						op = backTrackData.op;
						continue;
					}
					else
					{
						return false;
					}
				}
				op = program[pc++];
			}
		}
Example #2
0
		internal virtual object ExecuteRegExp(Context cx, Scriptable scope, RegExpImpl res, string str, int[] indexp, int matchType)
		{
			REGlobalData gData = new REGlobalData();
			int start = indexp[0];
			int end = str.Length;
			if (start > end)
			{
				start = end;
			}
			//
			// Call the recursive matcher to do the real work.
			//
			bool matches = MatchRegExp(gData, re, str, start, end, res.multiline);
			if (!matches)
			{
				if (matchType != PREFIX)
				{
					return null;
				}
				return Undefined.instance;
			}
			int index = gData.cp;
			int ep = indexp[0] = index;
			int matchlen = ep - (start + gData.skipped);
			index -= matchlen;
			object result;
			Scriptable obj;
			if (matchType == TEST)
			{
				result = true;
				obj = null;
			}
			else
			{
				result = cx.NewArray(scope, 0);
				obj = (Scriptable)result;
				string matchstr = Sharpen.Runtime.Substring(str, index, index + matchlen);
				obj.Put(0, obj, matchstr);
			}
			if (re.parenCount == 0)
			{
				res.parens = null;
				res.lastParen = SubString.emptySubString;
			}
			else
			{
				SubString parsub = null;
				int num;
				res.parens = new SubString[re.parenCount];
				for (num = 0; num < re.parenCount; num++)
				{
					int cap_index = gData.ParensIndex(num);
					string parstr;
					if (cap_index != -1)
					{
						int cap_length = gData.ParensLength(num);
						parsub = new SubString(str, cap_index, cap_length);
						res.parens[num] = parsub;
						if (matchType != TEST)
						{
							obj.Put(num + 1, obj, parsub.ToString());
						}
					}
					else
					{
						if (matchType != TEST)
						{
							obj.Put(num + 1, obj, Undefined.instance);
						}
					}
				}
				res.lastParen = parsub;
			}
			if (!(matchType == TEST))
			{
				obj.Put("index", obj, Sharpen.Extensions.ValueOf(start + gData.skipped));
				obj.Put("input", obj, str);
			}
			if (res.lastMatch == null)
			{
				res.lastMatch = new SubString();
				res.leftContext = new SubString();
				res.rightContext = new SubString();
			}
			res.lastMatch.str = str;
			res.lastMatch.index = index;
			res.lastMatch.length = matchlen;
			res.leftContext.str = str;
			if (cx.GetLanguageVersion() == Context.VERSION_1_2)
			{
				res.leftContext.index = start;
				res.leftContext.length = gData.skipped;
			}
			else
			{
				res.leftContext.index = 0;
				res.leftContext.length = start + gData.skipped;
			}
			res.rightContext.str = str;
			res.rightContext.index = ep;
			res.rightContext.length = end - ep;
			return result;
		}
Example #3
0
		private static bool BackrefMatcher(REGlobalData gData, int parenIndex, string input, int end)
		{
			int len;
			int i;
			if (gData.parens == null || parenIndex >= gData.parens.Length)
			{
				return false;
			}
			int parenContent = gData.ParensIndex(parenIndex);
			if (parenContent == -1)
			{
				return true;
			}
			len = gData.ParensLength(parenIndex);
			if ((gData.cp + len) > end)
			{
				return false;
			}
			if ((gData.regexp.flags & JSREG_FOLD) != 0)
			{
				for (i = 0; i < len; i++)
				{
					char c1 = input[parenContent + i];
					char c2 = input[gData.cp + i];
					if (c1 != c2 && Upcase(c1) != Upcase(c2))
					{
						return false;
					}
				}
			}
			else
			{
				if (!input.RegionMatches(parenContent, input, gData.cp, len))
				{
					return false;
				}
			}
			gData.cp += len;
			return true;
		}