class superRunner { runtextpos = 0; runstack = new Array(16); } const isBetween05 = new Map([ ['0', true] ['1', true] ['2', true] ['3', true] ['4', true] ['5', true] ]) const isBetween19 = new Map([ ['0', true] ['1', true] ['2', true] ['3', true] ['4', true] ['5', true] ['6', true] ['7', true] ['8', true] ['9', true] ]) const sign = 1 << 31; function isAsciiDigit(x) { x = x.charCodeAt(0) let upperBound = ~(sign | 0x39); /*if > 0x39 is added, result goes negative*/ let lowerBound = ~0x30;/*when < 0x30 is added, result is negative*/ /*now add x and check the sign bit for each*/ upperBound = sign & (upperBound + x) >> 31; lowerBound = sign & (lowerBound + 1 + x) >> 31; /*if either result is negative, it is not in desired range*/ return !(upperBound | lowerBound); } /// Provides the runner that contains the custom logic implementing the specified regular expression. class Runner extends superRunner { /// Scan the starting from super.runtextstart for the next match. /// The text being scanned by the regular expression. Scan(inputSpan) { // The pattern is anchored. Validate the current position and try to match at it only. if (TryFindNextPossibleStartingPosition(inputSpan) && !TryMatchAtCurrentPosition(inputSpan)) { super.runtextpos = inputSpan.length; } } /// Search starting from super.runtextpos for the next location a match could possibly start. /// The text being scanned by the regular expression. /// true if a possible match was found; false if no more matches are possible. TryFindNextPossibleStartingPosition(inputSpan) { const pos = super.runtextpos; // Any possible match is at least 10 characters. if (pos <= inputSpan.length - 10) { // The pattern leads with a beginning (\A) anchor. if (pos == 0) { return true; } } // No match found. super.runtextpos = inputSpan.length; return false; } /// Determine whether at super.runtextpos is a match for the regular expression. /// The text being scanned by the regular expression. /// true if the regular expression matches at the current position; otherwise, false. TryMatchAtCurrentPosition(inputSpan) { let pos = super.runtextpos; let matchStart = pos; let alternation_branch = 0; let alternation_starting_pos1 = 0; let loop_iteration = 0; let stackpos = 0; let slice = inputSpan.slice(pos); while (true) { // Match if at the beginning of the string. if (pos != 0) { return false; // The input didn't match. } // Loop exactly 3 times. //{ loop_iteration = 0; LoopBody: super.runstack[stackpos] = pos; stackpos++; // Utilities.StackPush(ref super.runstack!, ref stackpos, pos); loop_iteration++; // Match with 4 alternative expressions. //{ let alternation_starting_pos = pos; // Branch 0 //{ // Match '2'. if (slice.IsEmpty || slice[0] != '2') { break AlternationBranch; } // Match with 2 alternative expressions. //{ if (slice.length < 2) { break AlternationBranch; } switch (slice[1]) { case '5': // Match a character in the set [0-5]. if (slice.length < 3 || !isBetween05.has(slice[2])) { break AlternationBranch; } pos += 3; slice = inputSpan.slice(pos); break; case '0': case '1': case '2': case '3': case '4': // Match '0' through '9'. if (slice.length < 3 || !isAsciiDigit(slice[2])) { break AlternationBranch; } pos += 3; slice = inputSpan.slice(pos); break; default: break AlternationBranch; } //} super.runstack[stackpos] = 0; super.runstack[stackpos + 1] = alternation_starting_pos; stackpos += 2; // Utilities.StackPush(ref super.runstack!, ref stackpos, 0, alternation_starting_pos); break AlternationMatch; AlternationBranch: pos = alternation_starting_pos; slice = inputSpan.slice(pos); //} // Branch 1 //{ if (slice.length < 3 || slice[0] != '1' || // Match '1'. !isAsciiDigit(slice[1]) || // Match '0' through '9' exactly 2 times. !isAsciiDigit(slice[2])) { break AlternationBranch1; } super.runstack[stackpos] = 1; super.runstack[stackpos + 1] = alternation_starting_pos; stackpos += 2; // Utilities.StackPush(ref super.runstack!, ref stackpos, 1, alternation_starting_pos); pos += 3; slice = inputSpan.slice(pos); break AlternationMatch; AlternationBranch1: pos = alternation_starting_pos; slice = inputSpan.slice(pos); //} // Branch 2 //{ if (slice.length < 2 || !isBetween19.has(slice[0]) || // Match a character in the set [1-9]. !isAsciiDigit(slice[1])) // Match '0' through '9'. { break AlternationBranch2; } super.runstack[stackpos] = 2; super.runstack[stackpos + 1] = alternation_starting_pos; stackpos += 2; // Utilities.StackPush(ref super.runstack!, ref stackpos, 2, alternation_starting_pos); pos += 2; slice = inputSpan.slice(pos); break AlternationMatch; AlternationBranch2: pos = alternation_starting_pos; slice = inputSpan.slice(pos); //} // Branch 3 //{ // Match '0' through '9'. if (slice.IsEmpty || !isAsciiDigit(slice[0])) { break LoopIterationNoMatch; } super.runstack[stackpos] = 3; super.runstack[stackpos + 1] = alternation_starting_pos; stackpos += 2; // Utilities.StackPush(ref super.runstack!, ref stackpos, 3, alternation_starting_pos); pos++; slice = inputSpan.slice(pos); break AlternationMatch; //} AlternationBacktrack: super.CheckTimeout(); alternation_starting_pos = super.runstack[--stackpos]; switch (super.runstack[--stackpos]) { case 0: break AlternationBranch; case 1: break AlternationBranch1; case 2: break AlternationBranch2; case 3: break LoopIterationNoMatch; } AlternationMatch: ; //} if (slice.length < 2 || slice[0] != '\\' || // Match '\\'. slice[1] == '\n') // Match any character other than '\n'. { break AlternationBacktrack; } pos += 2; slice = inputSpan.slice(pos); // The loop has an upper bound of 3. Continue iterating greedily if it hasn't yet been reached. if (loop_iteration < 3) { break LoopBody; } break LoopEnd; // The loop iteration failed. Put state back to the way it was before the iteration. LoopIterationNoMatch: if (--loop_iteration < 0) { // Unable to match the remainder of the expression after exhausting the loop. return false; // The input didn't match. } pos = super.runstack[--stackpos]; slice = inputSpan.slice(pos); if (loop_iteration == 0) { // No iterations have been matched to backtrack leto. Fail the loop. return false; // The input didn't match. } if (loop_iteration < 3) { // All possible iterations have matched, but it's below the required minimum of 3. // Backtrack leto the prior iteration. break AlternationBacktrack; } break LoopEnd; LoopBacktrack: // super.CheckTimeout(); if (loop_iteration == 0) { // No iterations of the loop remain to backtrack leto. Fail the loop. return false; // The input didn't match. } break AlternationBacktrack; LoopEnd: ; //} // Match with 4 alternative expressions. //{ alternation_starting_pos1 = pos; // Branch 0 //{ // Match '2'. if (slice.IsEmpty || slice[0] != '2') { break AlternationBranch3; } // Match with 2 alternative expressions. //{ if (slice.length < 2) { break AlternationBranch3; } switch (slice[1]) { case '5': // Match a character in the set [0-5]. if (slice.length < 3 || !isBetween05.has(slice[2])) { break AlternationBranch3; } pos += 3; slice = inputSpan.slice(pos); break; case '0': case '1': case '2': case '3': case '4': // Match '0' through '9'. if (slice.length < 3 || !isAsciiDigit(slice[2])) { break AlternationBranch3; } pos += 3; slice = inputSpan.slice(pos); break; default: break AlternationBranch3; } //} alternation_branch = 0; break AlternationMatch1; AlternationBranch3: pos = alternation_starting_pos1; slice = inputSpan.slice(pos); //} // Branch 1 //{ if (slice.length < 3 || slice[0] != '1' || // Match '1'. !isAsciiDigit(slice[1]) || // Match '0' through '9' exactly 2 times. !isAsciiDigit(slice[2])) { break AlternationBranch4; } alternation_branch = 1; pos += 3; slice = inputSpan.slice(pos); break AlternationMatch1; AlternationBranch4: pos = alternation_starting_pos1; slice = inputSpan.slice(pos); //} // Branch 2 //{ if (slice.length < 2 || !isBetween19.has(slice[0]) || // Match a character in the set [1-9]. !isAsciiDigit(slice[1])) // Match '0' through '9'. { break AlternationBranch5; } alternation_branch = 2; pos += 2; slice = inputSpan.slice(pos); break AlternationMatch1; AlternationBranch5: pos = alternation_starting_pos1; slice = inputSpan.slice(pos); //} // Branch 3 //{ // Match '0' through '9'. if (slice.IsEmpty || !isAsciiDigit(slice[0])) { break LoopBacktrack; } alternation_branch = 3; pos++; slice = inputSpan.slice(pos); break AlternationMatch1; //} AlternationBacktrack1: // super.CheckTimeout(); switch (alternation_branch) { case 0: break AlternationBranch3; case 1: break AlternationBranch4; case 2: break AlternationBranch5; case 3: break LoopBacktrack; } AlternationMatch1: //} // Match if at the end of the string or if before an ending newline. if (pos < inputSpan.length - 1 || (pos < inputSpan.length && inputSpan[pos] != '\n')) { break AlternationBacktrack1; } // The input matched. super.runtextpos = pos; // super.Capture(0, matchStart, pos); return true; } } } const runner = new Runner(); console.log(runner.Scan("0.0.0.0"));