Skip to content

Instantly share code, notes, and snippets.

@H4ad
Created September 21, 2023 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save H4ad/b1a52769425d1e738c1ecdada398c1b8 to your computer and use it in GitHub Desktop.
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 :/
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