Created
September 21, 2023 11:18
-
-
Save H4ad/b1a52769425d1e738c1ecdada398c1b8 to your computer and use it in GitHub Desktop.
I tried to convert the C# generated code to Javascript, and it failed :/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
/// <summary>Provides the runner that contains the custom logic implementing the specified regular expression.</summary> | |
class Runner extends superRunner { | |
/// <summary>Scan the <paramref name="inputSpan"/> starting from super.runtextstart for the next match.</summary> | |
/// <param name="inputSpan">The text being scanned by the regular expression.</param> | |
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; | |
} | |
} | |
/// <summary>Search <paramref name="inputSpan"/> starting from super.runtextpos for the next location a match could possibly start.</summary> | |
/// <param name="inputSpan">The text being scanned by the regular expression.</param> | |
/// <returns>true if a possible match was found; false if no more matches are possible.</returns> | |
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; | |
} | |
/// <summary>Determine whether <paramref name="inputSpan"/> at super.runtextpos is a match for the regular expression.</summary> | |
/// <param name="inputSpan">The text being scanned by the regular expression.</param> | |
/// <returns>true if the regular expression matches at the current position; otherwise, false.</returns> | |
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")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment