package main // match tries to match the regex represented by given start-state, with // the given string func match(start *State, str string) (startIdx int, endIdx int, matched bool) { currentStates := make([]*State, 0) tempStates := make([]*State, 0) // Used to store states that should be used in next loop iteration i := 0 // Index in string // Increment until we hit a character matching the start state if start.isEmpty == false { for i < len(str) && int(str[i]) != start.content { i++ } i++ // Advance to next character (if we aren't at a 0-state, which doesn't match anything), so that we can check for transitions. If we advance at a 0-state, we will never get a chance to match the first character } currentStates = append(currentStates, start) startIdx = i // Main loop for i < len(str) { // If there are any 0-transitions, take those // TODO: Maybe I need to keep taking 0-transitions until I don't have anymore. Needs to be tested for _, state := range currentStates { if len(state.transitions[EPSILON]) > 0 { tempStates = append(tempStates, state.transitions[EPSILON]...) } } copy(currentStates, tempStates) tempStates = nil // Take any transitions corresponding to current character for _, state := range currentStates { if len(state.transitions[int(str[i])]) > 0 { tempStates = append(tempStates, state.transitions[int(str[i])]...) } else { // This enables the 'greedy' behavior - last-state status is only checked if we can't match anything else if state.isLast { endIdx = i return startIdx, endIdx, true } } } copy(currentStates, tempStates) tempStates = nil i++ } // End-of-string reached. Go to any 0-states. Then check if any of our states are in the end position. for _, state := range currentStates { if len(state.transitions[EPSILON]) > 0 { tempStates = append(tempStates, state.transitions[EPSILON]...) } } copy(currentStates, tempStates) tempStates = nil for _, state := range currentStates { if state.isLast { endIdx = i return startIdx, endIdx, true } else { return -1, -1, false } } // Default return -1, -1, false }