# Many qualities of this transpiler are inspired by V
import textwrap, sys

def pattern(rest, datas):
    name = rest[0]
    rest = rest[1:]
    if name.isupper():
        out = [name]
        for _ in range(datas[name]):
            pat, rest = pattern(rest, datas)
            out.append(pat)
        return out, rest
    elif name.islower():
        return name, rest
    elif name == "_":
        return None, rest
    else:
        raise SyntaxError

def expr(rest, datas, stack):
    call = []
    while rest:
        c = rest[0]
        rest = rest[1:]
        match c:
            case ")":
                assert stack.pop() == "("
                break
            case "]":
                assert stack.pop() == "["
                break
            case "|":
                rest = "|" + rest
                break
            case "(":
                stack.append("(")
                e, rest = expr(rest, datas, stack)
                call.append(e)
            case "[":
                stack.append("[")
                f, rest = func(rest, datas, stack)
                call.append(f)
            case _:
                call.append(c)
    return call, rest

def func(rest, datas, stack):
    count = int(rest[0])
    return branch(rest[1:], datas, count, stack)

def branch(rest, datas, count, stack):
    branches = []
    start = True
    while start or (rest and rest[0] == "|"):
        if not start:
            rest = rest[1:]
        patterns = []
        for _ in range(count):
            p, rest = pattern(rest, datas)
            patterns.append(p)
        e, rest = expr(rest, datas, stack)
        branches.append((patterns, e))
        start = False
    return {'':branches}, rest

def transpile(code):
    if len(code) > 100:
        raise SystemExit("golf it!")
    lines = sorted(filter(None, code.replace("\n",";").replace(" ","").replace("\t","").split(";")))
    datas = {}
    fns = {}
    for line in lines:
        name = line[0]
        rest = line[1:]
        if name.isupper():
            for branch in rest.split("|"):
                tag = branch[0]
                count = len(branch) - 1
                datas[tag] = count
        else:
            if name == "^":
                name = "main"
            fn, rest = func(rest, datas, [])
            fns[name] = fn
    return write_header() + write_datas(datas) + write_fns(fns) + write_footer(datas)

def write_header():
    return textwrap.dedent('''
    # generated by the TFLite transpiler version {}
    import enum, re
    class Data(list):
        # todo: static typing
        def __call__(self, arg):
            return Data(self + [arg])
    def output(value):
        if isinstance(value, Data):
            if len(value) == 1:
                return output(value[0])
            return "".join(f"({output(x)})" for x in value)
        elif isinstance(value, _data):
            return value.name
        return value.__name__
    '''[1:])

def write_datas(datas):
    members = "\n".join(f"    {c}=object()" for c in datas) if datas else "    pass"
    kind = f"class _data(enum.Enum):\n{members}\n"
    constants = "\n".join(f"{c}=Data([_data.{c}])" for c in datas)
    return kind + constants + "\n"

def write_fns(fns):
    return "\n".join(write_fn(name, fn) for name, fn in fns.items())

def write_pattern(pattern):
    return f"[{', '.join('_' if p is None else (f'_data.{p}' if p.isupper() else p) if isinstance(p, str) else write_pattern(p) for p in pattern)}]"

def find_anons(expr, anons):
    for e in expr:
        if isinstance(e, dict):
            anons.append(e)
            for (_, branch) in e['']:
                find_anons(branch, anons)
        elif isinstance(e, list):
            find_anons(e, anons)
    return anons

def write_expr(expr, anons, ids):
    out = ""
    for e in expr:
        e = "main" if e == "^" else e
        if isinstance(e, str):
            out+=f"({e})"
        elif isinstance(e, list):
            out +=f"({write_expr(e, anons, ids)})"
        elif isinstance(e, dict):
            out +=f"(anon_{ids[anons.index(e)]})"
    return out

def write_fn(name, fn):
    fn = fn['']
    out = ""
    n = len(fn[0][0])
    if n == 0:
        expr = fn[0][1]
        anons = find_anons(expr, [])
        ids = [(abs(hash(str((i, anon, fn))))) for i, anon in enumerate(anons)]
        for id, anon in zip(ids, anons):
            out += textwrap.indent(write_fn(f"anon_{id}", anon), n*'    ')
        out += f"{name}={write_expr(expr, anons, ids)}\n"
    else:
        for i in range(n):out+=f"{i*'    '}def {name}{i*'_'}(_{i}):\n"
        out+=f"{n*'    '}match [{', '.join(f'_{i}'for i in range(n))}]:\n"

        for pattern, expr in fn:
            out += f"{(n + 1)*'    '}case {write_pattern(pattern)}:\n"
            anons = find_anons(expr, [])
            ids = [(abs(hash(str((i, anon, fn))))) for i, anon in enumerate(anons)]
            for id, anon in zip(ids, anons):
                out += textwrap.indent(write_fn(f"anon_{id}", anon), (n + 2) * '    ')
            out += f"{(n +2)*'    '}return {write_expr(expr, anons, ids)}\n"
        out += f"{(n + 1)*'    '}case _: raise RuntimeError('Bad arguments')\n"

        for i in range(n - 1): out += f"{(n-i-1)*'    '}return {name}{(n-i-1)*'_'}\n"

    return out

def write_footer(datas):
    chars = "".join(datas)
    return textwrap.dedent(f'''
    if __name__ == "__main__":
        args = []
        for arg in open(0):
            arg = re.sub("\\\\s", "", arg)
            assert len(re.findall("[\\\\(\\\\){chars}]", arg)) == len(arg), "Bad character"
            assert not re.findall("\\\\(\\\\)", arg), "Bad format"
            try:
                args.append(eval(arg))
            except SyntaxError as e:
                raise SyntaxError("Bad format") from e
            except Exception as e:
                raise RuntimeError("Bad input") from e
        try:
            value = main
            for arg in args:
                value = value(arg)
            print(output(value))
        except Exception as e:
            raise RuntimeError("Bad program") from e
    '''[1:])

print(transpile(sys.stdin.read()))
