// Code generated by re2v, DO NOT EDIT.
//line "v/submatch/02_mtags.re":1
// re2v $INPUT -o $OUTPUT

import arrays

const mtag_root = -1
const tag_none = -1

// An m-tag tree is a way to store histories with an O(1) copy operation.
// Histories naturally form a tree, as they have common start and fork at some
// point. The tree is stored as an array of pairs (tag value, link to parent).
// An m-tag is represented with a single link in the tree (array index).
struct MtagElem {
    elem int
    pred int
}
type MtagTrie = []MtagElem

// Append a single value to an m-tag history.
fn add_mtag(mut trie &MtagTrie, mtag int, value int) int {
    trie = arrays.concat(trie, MtagElem{value, mtag})
    return trie.len - 1
}

// Recursively unwind tag histories and collect version components.
fn unwind(trie MtagTrie, x int, y int, str string) []int {
    // Reached the root of the m-tag tree, stop recursion.
    if x == mtag_root && y == mtag_root {
        return []
    }

    // Unwind history further.
    mut result := unwind(trie, trie[x].pred, trie[y].pred, str)

    // Get tag values. Tag histories must have equal length.
    if x == mtag_root || y == mtag_root {
        panic("tag histories have different length")
    }
    ex := trie[x].elem
    ey := trie[y].elem

    if ex != tag_none && ey != tag_none {
        // Both tags are valid string indices, extract component.
        result = arrays.concat(result, s2n(str[ex..ey]))
    } else if !(ex == tag_none && ey == tag_none) {
        panic("both tags should be tag_none")
    }
    return result
}

fn s2n(s string) int { // convert pre-parsed string to number
    mut n := 0
    for c in s { n = n * 10 + int(c - 48) }
    return n
}

fn parse(yyinput string) ?[]int {
    mut yycursor, mut yymarker := 0, 0
    mut trie := []MtagElem{}

    // Final tag variables available in semantic action.
    
//line "v/submatch/02_mtags.v":65
mut t1 := tag_none
mut t2 := tag_none
//line "v/submatch/02_mtags.re":61

    
//line "v/submatch/02_mtags.v":71
mut t3 := mtag_root
mut t4 := mtag_root
//line "v/submatch/02_mtags.re":62


    // Intermediate tag variables used by the lexer (must be autogenerated).
    
//line "v/submatch/02_mtags.v":79
mut yyt1 := tag_none
mut yyt2 := tag_none
//line "v/submatch/02_mtags.re":65

    
//line "v/submatch/02_mtags.v":85
mut yytm3 := mtag_root
mut yytm4 := mtag_root
//line "v/submatch/02_mtags.re":66


    
//line "v/submatch/02_mtags.v":92
    mut yych := 0
    yych = yyinput[yycursor]
    match yych {
        0x30...0x39 {
            yyt1 = yycursor
            unsafe { goto yy3 }
        }
        else { unsafe { goto yy1 } }
    }
yy1:
    yycursor += 1
yy2:
//line "v/submatch/02_mtags.re":82
    return none
//line "v/submatch/02_mtags.v":107
yy3:
    yycursor += 1
    yymarker = yycursor
    yych = yyinput[yycursor]
    match yych {
        0x00 {
            yytm4 = add_mtag(mut &trie, yytm4, tag_none)
            yytm3 = add_mtag(mut &trie, yytm3, tag_none)
            yyt2 = yycursor
            unsafe { goto yy4 }
        }
        0x2E {
            yyt2 = yycursor
            unsafe { goto yy5 }
        }
        0x30...0x39 { unsafe { goto yy7 } }
        else { unsafe { goto yy2 } }
    }
yy4:
    yycursor += 1
    t1 = yyt1
    t2 = yyt2
    t3 = yytm3
    t4 = yytm4
//line "v/submatch/02_mtags.re":76
    
            mut ver := []int{}
            ver = arrays.concat(ver, s2n(yyinput[t1..t2]))
            ver = arrays.append(ver, unwind(trie, t3, t4, yyinput))
            return ver

//line "v/submatch/02_mtags.v":139
yy5:
    yycursor += 1
    yych = yyinput[yycursor]
    match yych {
        0x30...0x39 {
            yytm3 = add_mtag(mut &trie, yytm3, yycursor)
            unsafe { goto yy8 }
        }
        else { unsafe { goto yy6 } }
    }
yy6:
    yycursor = yymarker
    unsafe { goto yy2 }
yy7:
    yycursor += 1
    yych = yyinput[yycursor]
    match yych {
        0x00 {
            yytm4 = add_mtag(mut &trie, yytm4, tag_none)
            yytm3 = add_mtag(mut &trie, yytm3, tag_none)
            yyt2 = yycursor
            unsafe { goto yy4 }
        }
        0x2E {
            yyt2 = yycursor
            unsafe { goto yy5 }
        }
        0x30...0x39 { unsafe { goto yy7 } }
        else { unsafe { goto yy6 } }
    }
yy8:
    yycursor += 1
    yych = yyinput[yycursor]
    match yych {
        0x00 {
            yytm4 = add_mtag(mut &trie, yytm4, yycursor)
            unsafe { goto yy4 }
        }
        0x2E {
            yytm4 = add_mtag(mut &trie, yytm4, yycursor)
            unsafe { goto yy5 }
        }
        0x30...0x39 { unsafe { goto yy8 } }
        else { unsafe { goto yy6 } }
    }
//line "v/submatch/02_mtags.re":83

}

fn main() {
    test := fn (result ?[]int, expect ?[]int) {
        if r := result {
            if e := expect { if r != e { panic("expected $e, got $r") } }
        } else {
            if _ := result { panic("expected none") }
        }
    }
    test(parse("1\0"), [1])
    test(parse("1.2.3.4.5.6.7\0"), [1, 2, 3, 4, 5, 6, 7])
    test(parse("1.\0"), none)
}
