i+=(numDigits-1)// I have to move back a step, so that I can add a concatenation operator if necessary, and so that the increment at the bottom of the loop works as intended
}elseifunicode.IsDigit(re_runes[i]){// Any other number - backreference
numDigits:=1
fori+numDigits<len(re_runes)&&unicode.IsDigit(re_runes[i+numDigits]){// Skip while we see a digit
parenIndices:=make([]Group,0)// I really shouldn't be using Group here, because that's strictly for matching purposes, but its a convenient way to store the indices of the opening and closing parens.
parenIndices=append(parenIndices,Group{0,0})// I append a weird value here, because the 0-th group doesn't have any parens. This way, the 1st group will be at index 1, 2nd at 2 ...
i+=numDigitsParsed-1// Shift forward by the number of digits that were parsed. Move back one character, because the loop increment will move us back to the next character automatically
returnnil,fmt.Errorf("not enough hex characters found in character class")
}
}elseifisOctal(re_postfix[i]){// Octal value
}elseifre_postfix[i]=='0'{// Octal value
varoctValint64
varoctValStrstring
numDigitsParsed:=0
for(i+numDigitsParsed)<len(re_postfix)-1&&isOctal(re_postfix[i+numDigitsParsed])&&numDigitsParsed<=3{// The '-1' exists, because even in the worst case (the character class extends till the end), the last character must be a closing bracket (and nothing else)
for(i+numDigitsParsed)<len(re_postfix)-1&&isOctal(re_postfix[i+numDigitsParsed])&&numDigitsParsed<=4{// The '-1' exists, because even in the worst case (the character class extends till the end), the last character must be a closing bracket (and nothing else)
currentStates,_=addStateToList(str,i,currentStates,*start,start.threadGroups,nil,preferLongest)// We can't go forward at the beginning, so I discard the second retval
}elseif!currentState.isAlternation&&!currentState.isKleene&&!currentState.isQuestion&&!currentState.groupBegin&&!currentState.groupEnd&¤tState.assert==noneAssert{// Normal character
groupEndbool// Whether or not the node ends a capturing group
groupNumint// Which capturing group the node starts / ends
// The following properties depend on the current match - I should think about resetting them for every match.
zeroMatchFoundbool// Whether or not the state has been used for a zero-length match - only relevant for zero states
threadGroups[]Group// Assuming that a state is part of a 'thread' in the matching process, this array stores the indices of capturing groups in the current thread. As matches are found for this state, its groups will be copied over.
isBackreferencebool// Whether or not current node is backreference
referredGroupint// If current node is a backreference, the node that it points to
threadBackrefint// If current node is a backreference, how many characters to look forward into the referred group
lookaroundSignint// ONLY USED WHEN nodetype == ASSERTION. Whether we have a positive or negative lookaround.
lookaroundDirint// Lookbehind or lookahead
nodeContents[]postfixNode// ONLY USED WHEN nodetype == CHARCLASS. Holds all the nodes inside the given CHARCLASS node.
referencedGroupint// ONLY USED WHEN nodetype == backreferenceNode. Holds the group which this one refers to. After parsing is done, the expression will be rewritten eg. (a)\1 will become (a)(a). So the return value of ShuntingYard() shouldn't contain a backreferenceNode.
}
// Converts the given list of postfixNodes to one node of type CHARCLASS.
// groupIncrement := 0 // If we have a backreference before the group its referring to, then the group its referring to will have its group number incremented.
// rtv = slices.Concat(rtv, nodes[parenIndices[node.referencedGroup].StartIdx:parenIndices[node.referencedGroup].EndIdx+1]) // Add all the nodes in the group to rtv
// numGroups += 1
// if i < parenIndices[node.referencedGroup].StartIdx {