import unittest

import rply.parser
from parameterized import parameterized

from .. import *
from ..transformer import unique_variables
from ..optimizer import pre_evaluation
from ..lexer import strip_comments
from ..ast import *

SAMPLE_CONTRACT = p = Program(
    version="0.0.1",
    term=Apply(
        Apply(
            Apply(
                Lambda(
                    var_name="p0",
                    term=Lambda(
                        var_name="p1",
                        term=Lambda(
                            var_name="p2",
                            term=Force(
                                term=Apply(
                                    f=Apply(
                                        f=Apply(
                                            f=Force(
                                                term=BuiltIn(
                                                    builtin=BuiltInFun.IfThenElse,
                                                    applied_forces=0,
                                                    bound_arguments=[],
                                                )
                                            ),
                                            x=Apply(
                                                f=Lambda(
                                                    var_name="s",
                                                    term=Apply(
                                                        f=Lambda(
                                                            var_name="g",
                                                            term=Apply(
                                                                f=Apply(
                                                                    f=Apply(
                                                                        f=Apply(
                                                                            f=Apply(
                                                                                f=Variable(
                                                                                    name="g"
                                                                                ),
                                                                                x=Variable(
                                                                                    name="g"
                                                                                ),
                                                                            ),
                                                                            x=Apply(
                                                                                f=BuiltIn(
                                                                                    builtin=BuiltInFun.UnIData,
                                                                                    applied_forces=0,
                                                                                    bound_arguments=[],
                                                                                ),
                                                                                x=Variable(
                                                                                    name="p0"
                                                                                ),
                                                                            ),
                                                                        ),
                                                                        x=Apply(
                                                                            f=BuiltIn(
                                                                                builtin=BuiltInFun.UnIData,
                                                                                applied_forces=0,
                                                                                bound_arguments=[],
                                                                            ),
                                                                            x=Variable(
                                                                                name="p1"
                                                                            ),
                                                                        ),
                                                                    ),
                                                                    x=Variable(
                                                                        name="p2"
                                                                    ),
                                                                ),
                                                                x=Variable(name="s"),
                                                            ),
                                                            state=frozendict.frozendict(
                                                                {}
                                                            ),
                                                        ),
                                                        x=Force(
                                                            term=Apply(
                                                                f=Apply(
                                                                    f=Apply(
                                                                        f=Lambda(
                                                                            var_name="s",
                                                                            term=Apply(
                                                                                f=Lambda(
                                                                                    var_name="s",
                                                                                    term=Lambda(
                                                                                        var_name="x",
                                                                                        term=Lambda(
                                                                                            var_name="def",
                                                                                            term=Force(
                                                                                                term=Apply(
                                                                                                    f=Apply(
                                                                                                        f=Apply(
                                                                                                            f=Force(
                                                                                                                term=BuiltIn(
                                                                                                                    builtin=BuiltInFun.IfThenElse,
                                                                                                                    applied_forces=0,
                                                                                                                    bound_arguments=[],
                                                                                                                )
                                                                                                            ),
                                                                                                            x=Apply(
                                                                                                                f=Apply(
                                                                                                                    f=BuiltIn(
                                                                                                                        builtin=BuiltInFun.EqualsByteString,
                                                                                                                        applied_forces=0,
                                                                                                                        bound_arguments=[],
                                                                                                                    ),
                                                                                                                    x=Variable(
                                                                                                                        name="x"
                                                                                                                    ),
                                                                                                                ),
                                                                                                                x=BuiltinByteString(
                                                                                                                    value=b"validator"
                                                                                                                ),
                                                                                                            ),
                                                                                                        ),
                                                                                                        x=Delay(
                                                                                                            term=Delay(
                                                                                                                term=Lambda(
                                                                                                                    var_name="f",
                                                                                                                    term=Lambda(
                                                                                                                        var_name="p0",
                                                                                                                        term=Lambda(
                                                                                                                            var_name="p1",
                                                                                                                            term=Lambda(
                                                                                                                                var_name="p2",
                                                                                                                                term=Lambda(
                                                                                                                                    var_name="s",
                                                                                                                                    term=Apply(
                                                                                                                                        f=Lambda(
                                                                                                                                            var_name="s",
                                                                                                                                            term=Apply(
                                                                                                                                                f=Apply(
                                                                                                                                                    f=BuiltIn(
                                                                                                                                                        builtin=BuiltInFun.EqualsInteger,
                                                                                                                                                        applied_forces=0,
                                                                                                                                                        bound_arguments=[],
                                                                                                                                                    ),
                                                                                                                                                    x=Apply(
                                                                                                                                                        f=Lambda(
                                                                                                                                                            var_name="s",
                                                                                                                                                            term=Apply(
                                                                                                                                                                f=Apply(
                                                                                                                                                                    f=BuiltIn(
                                                                                                                                                                        builtin=BuiltInFun.AddInteger,
                                                                                                                                                                        applied_forces=0,
                                                                                                                                                                        bound_arguments=[],
                                                                                                                                                                    ),
                                                                                                                                                                    x=Apply(
                                                                                                                                                                        f=Lambda(
                                                                                                                                                                            var_name="s",
                                                                                                                                                                            term=Force(
                                                                                                                                                                                term=Apply(
                                                                                                                                                                                    f=Apply(
                                                                                                                                                                                        f=Variable(
                                                                                                                                                                                            name="s"
                                                                                                                                                                                        ),
                                                                                                                                                                                        x=BuiltinByteString(
                                                                                                                                                                                            value=b"datum"
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                    x=Delay(
                                                                                                                                                                                        term=Apply(
                                                                                                                                                                                            f=Lambda(
                                                                                                                                                                                                var_name="_",
                                                                                                                                                                                                term=Error(),
                                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                                    {}
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                            x=Apply(
                                                                                                                                                                                                f=Apply(
                                                                                                                                                                                                    f=Force(
                                                                                                                                                                                                        term=BuiltIn(
                                                                                                                                                                                                            builtin=BuiltInFun.Trace,
                                                                                                                                                                                                            applied_forces=0,
                                                                                                                                                                                                            bound_arguments=[],
                                                                                                                                                                                                        )
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    x=BuiltinString(
                                                                                                                                                                                                        value="NameError"
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                                x=BuiltinUnit(),
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                            {}
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                )
                                                                                                                                                                            ),
                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                {}
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                        x=Variable(
                                                                                                                                                                            name="s"
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                                x=Apply(
                                                                                                                                                                    f=Lambda(
                                                                                                                                                                        var_name="s",
                                                                                                                                                                        term=Force(
                                                                                                                                                                            term=Apply(
                                                                                                                                                                                f=Apply(
                                                                                                                                                                                    f=Variable(
                                                                                                                                                                                        name="s"
                                                                                                                                                                                    ),
                                                                                                                                                                                    x=BuiltinByteString(
                                                                                                                                                                                        value=b"redeemer"
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                                x=Delay(
                                                                                                                                                                                    term=Apply(
                                                                                                                                                                                        f=Lambda(
                                                                                                                                                                                            var_name="_",
                                                                                                                                                                                            term=Error(),
                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                {}
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                        x=Apply(
                                                                                                                                                                                            f=Apply(
                                                                                                                                                                                                f=Force(
                                                                                                                                                                                                    term=BuiltIn(
                                                                                                                                                                                                        builtin=BuiltInFun.Trace,
                                                                                                                                                                                                        applied_forces=0,
                                                                                                                                                                                                        bound_arguments=[],
                                                                                                                                                                                                    )
                                                                                                                                                                                                ),
                                                                                                                                                                                                x=BuiltinString(
                                                                                                                                                                                                    value="NameError"
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                            x=BuiltinUnit(),
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                        {}
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                            )
                                                                                                                                                                        ),
                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                            {}
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                    x=Variable(
                                                                                                                                                                        name="s"
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                            ),
                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                {}
                                                                                                                                                            ),
                                                                                                                                                        ),
                                                                                                                                                        x=Variable(
                                                                                                                                                            name="s"
                                                                                                                                                        ),
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                                x=Apply(
                                                                                                                                                    f=Lambda(
                                                                                                                                                        var_name="s",
                                                                                                                                                        term=BuiltinInteger(
                                                                                                                                                            value=42
                                                                                                                                                        ),
                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                            {}
                                                                                                                                                        ),
                                                                                                                                                    ),
                                                                                                                                                    x=Variable(
                                                                                                                                                        name="s"
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                {}
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                        x=Apply(
                                                                                                                                            f=Lambda(
                                                                                                                                                var_name="s",
                                                                                                                                                term=Variable(
                                                                                                                                                    name="s"
                                                                                                                                                ),
                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                    {}
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                            x=Lambda(
                                                                                                                                                var_name="x",
                                                                                                                                                term=Lambda(
                                                                                                                                                    var_name="def",
                                                                                                                                                    term=Force(
                                                                                                                                                        term=Apply(
                                                                                                                                                            f=Apply(
                                                                                                                                                                f=Apply(
                                                                                                                                                                    f=Force(
                                                                                                                                                                        term=BuiltIn(
                                                                                                                                                                            builtin=BuiltInFun.IfThenElse,
                                                                                                                                                                            applied_forces=0,
                                                                                                                                                                            bound_arguments=[],
                                                                                                                                                                        )
                                                                                                                                                                    ),
                                                                                                                                                                    x=Apply(
                                                                                                                                                                        f=Apply(
                                                                                                                                                                            f=BuiltIn(
                                                                                                                                                                                builtin=BuiltInFun.EqualsByteString,
                                                                                                                                                                                applied_forces=0,
                                                                                                                                                                                bound_arguments=[],
                                                                                                                                                                            ),
                                                                                                                                                                            x=Variable(
                                                                                                                                                                                name="x"
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                        x=BuiltinByteString(
                                                                                                                                                                            value=b"context"
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                                x=Delay(
                                                                                                                                                                    term=Delay(
                                                                                                                                                                        term=Variable(
                                                                                                                                                                            name="p2"
                                                                                                                                                                        ),
                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                            {}
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                        {}
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                            ),
                                                                                                                                                            x=Delay(
                                                                                                                                                                term=Force(
                                                                                                                                                                    term=Apply(
                                                                                                                                                                        f=Apply(
                                                                                                                                                                            f=Apply(
                                                                                                                                                                                f=Force(
                                                                                                                                                                                    term=BuiltIn(
                                                                                                                                                                                        builtin=BuiltInFun.IfThenElse,
                                                                                                                                                                                        applied_forces=0,
                                                                                                                                                                                        bound_arguments=[],
                                                                                                                                                                                    )
                                                                                                                                                                                ),
                                                                                                                                                                                x=Apply(
                                                                                                                                                                                    f=Apply(
                                                                                                                                                                                        f=BuiltIn(
                                                                                                                                                                                            builtin=BuiltInFun.EqualsByteString,
                                                                                                                                                                                            applied_forces=0,
                                                                                                                                                                                            bound_arguments=[],
                                                                                                                                                                                        ),
                                                                                                                                                                                        x=Variable(
                                                                                                                                                                                            name="x"
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                    x=BuiltinByteString(
                                                                                                                                                                                        value=b"redeemer"
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                            ),
                                                                                                                                                                            x=Delay(
                                                                                                                                                                                term=Delay(
                                                                                                                                                                                    term=Variable(
                                                                                                                                                                                        name="p1"
                                                                                                                                                                                    ),
                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                        {}
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                    {}
                                                                                                                                                                                ),
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                        x=Delay(
                                                                                                                                                                            term=Force(
                                                                                                                                                                                term=Apply(
                                                                                                                                                                                    f=Apply(
                                                                                                                                                                                        f=Apply(
                                                                                                                                                                                            f=Force(
                                                                                                                                                                                                term=BuiltIn(
                                                                                                                                                                                                    builtin=BuiltInFun.IfThenElse,
                                                                                                                                                                                                    applied_forces=0,
                                                                                                                                                                                                    bound_arguments=[],
                                                                                                                                                                                                )
                                                                                                                                                                                            ),
                                                                                                                                                                                            x=Apply(
                                                                                                                                                                                                f=Apply(
                                                                                                                                                                                                    f=BuiltIn(
                                                                                                                                                                                                        builtin=BuiltInFun.EqualsByteString,
                                                                                                                                                                                                        applied_forces=0,
                                                                                                                                                                                                        bound_arguments=[],
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    x=Variable(
                                                                                                                                                                                                        name="x"
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                                x=BuiltinByteString(
                                                                                                                                                                                                    value=b"datum"
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                        x=Delay(
                                                                                                                                                                                            term=Delay(
                                                                                                                                                                                                term=Variable(
                                                                                                                                                                                                    name="p0"
                                                                                                                                                                                                ),
                                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                                    {}
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                {}
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                    x=Delay(
                                                                                                                                                                                        term=Force(
                                                                                                                                                                                            term=Apply(
                                                                                                                                                                                                f=Apply(
                                                                                                                                                                                                    f=Apply(
                                                                                                                                                                                                        f=Force(
                                                                                                                                                                                                            term=BuiltIn(
                                                                                                                                                                                                                builtin=BuiltInFun.IfThenElse,
                                                                                                                                                                                                                applied_forces=0,
                                                                                                                                                                                                                bound_arguments=[],
                                                                                                                                                                                                            )
                                                                                                                                                                                                        ),
                                                                                                                                                                                                        x=Apply(
                                                                                                                                                                                                            f=Apply(
                                                                                                                                                                                                                f=BuiltIn(
                                                                                                                                                                                                                    builtin=BuiltInFun.EqualsByteString,
                                                                                                                                                                                                                    applied_forces=0,
                                                                                                                                                                                                                    bound_arguments=[],
                                                                                                                                                                                                                ),
                                                                                                                                                                                                                x=Variable(
                                                                                                                                                                                                                    name="x"
                                                                                                                                                                                                                ),
                                                                                                                                                                                                            ),
                                                                                                                                                                                                            x=BuiltinByteString(
                                                                                                                                                                                                                value=b"validator"
                                                                                                                                                                                                            ),
                                                                                                                                                                                                        ),
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    x=Delay(
                                                                                                                                                                                                        term=Delay(
                                                                                                                                                                                                            term=Variable(
                                                                                                                                                                                                                name="f"
                                                                                                                                                                                                            ),
                                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                                {}
                                                                                                                                                                                                            ),
                                                                                                                                                                                                        ),
                                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                                            {}
                                                                                                                                                                                                        ),
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                                x=Delay(
                                                                                                                                                                                                    term=Apply(
                                                                                                                                                                                                        f=Apply(
                                                                                                                                                                                                            f=Variable(
                                                                                                                                                                                                                name="s"
                                                                                                                                                                                                            ),
                                                                                                                                                                                                            x=Variable(
                                                                                                                                                                                                                name="x"
                                                                                                                                                                                                            ),
                                                                                                                                                                                                        ),
                                                                                                                                                                                                        x=Variable(
                                                                                                                                                                                                            name="def"
                                                                                                                                                                                                        ),
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                                        {}
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                            )
                                                                                                                                                                                        ),
                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                            {}
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                )
                                                                                                                                                                            ),
                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                {}
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                    )
                                                                                                                                                                ),
                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                    {}
                                                                                                                                                                ),
                                                                                                                                                            ),
                                                                                                                                                        )
                                                                                                                                                    ),
                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                        {}
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                    {}
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                    ),
                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                        {}
                                                                                                                                    ),
                                                                                                                                ),
                                                                                                                                state=frozendict.frozendict(
                                                                                                                                    {}
                                                                                                                                ),
                                                                                                                            ),
                                                                                                                            state=frozendict.frozendict(
                                                                                                                                {}
                                                                                                                            ),
                                                                                                                        ),
                                                                                                                        state=frozendict.frozendict(
                                                                                                                            {}
                                                                                                                        ),
                                                                                                                    ),
                                                                                                                    state=frozendict.frozendict(
                                                                                                                        {}
                                                                                                                    ),
                                                                                                                ),
                                                                                                                state=frozendict.frozendict(
                                                                                                                    {}
                                                                                                                ),
                                                                                                            ),
                                                                                                            state=frozendict.frozendict(
                                                                                                                {}
                                                                                                            ),
                                                                                                        ),
                                                                                                    ),
                                                                                                    x=Delay(
                                                                                                        term=Apply(
                                                                                                            f=Apply(
                                                                                                                f=Variable(
                                                                                                                    name="s"
                                                                                                                ),
                                                                                                                x=Variable(
                                                                                                                    name="x"
                                                                                                                ),
                                                                                                            ),
                                                                                                            x=Variable(
                                                                                                                name="def"
                                                                                                            ),
                                                                                                        ),
                                                                                                        state=frozendict.frozendict(
                                                                                                            {}
                                                                                                        ),
                                                                                                    ),
                                                                                                )
                                                                                            ),
                                                                                            state=frozendict.frozendict(
                                                                                                {}
                                                                                            ),
                                                                                        ),
                                                                                        state=frozendict.frozendict(
                                                                                            {}
                                                                                        ),
                                                                                    ),
                                                                                    state=frozendict.frozendict(
                                                                                        {}
                                                                                    ),
                                                                                ),
                                                                                x=Apply(
                                                                                    f=Lambda(
                                                                                        var_name="s",
                                                                                        term=Variable(
                                                                                            name="s"
                                                                                        ),
                                                                                        state=frozendict.frozendict(
                                                                                            {}
                                                                                        ),
                                                                                    ),
                                                                                    x=Apply(
                                                                                        f=Lambda(
                                                                                            var_name="s",
                                                                                            term=Variable(
                                                                                                name="s"
                                                                                            ),
                                                                                            state=frozendict.frozendict(
                                                                                                {}
                                                                                            ),
                                                                                        ),
                                                                                        x=Apply(
                                                                                            f=Lambda(
                                                                                                var_name="s",
                                                                                                term=Variable(
                                                                                                    name="s"
                                                                                                ),
                                                                                                state=frozendict.frozendict(
                                                                                                    {}
                                                                                                ),
                                                                                            ),
                                                                                            x=Apply(
                                                                                                f=Lambda(
                                                                                                    var_name="s",
                                                                                                    term=Variable(
                                                                                                        name="s"
                                                                                                    ),
                                                                                                    state=frozendict.frozendict(
                                                                                                        {}
                                                                                                    ),
                                                                                                ),
                                                                                                x=Apply(
                                                                                                    f=Lambda(
                                                                                                        var_name="s",
                                                                                                        term=Variable(
                                                                                                            name="s"
                                                                                                        ),
                                                                                                        state=frozendict.frozendict(
                                                                                                            {}
                                                                                                        ),
                                                                                                    ),
                                                                                                    x=Apply(
                                                                                                        f=Lambda(
                                                                                                            var_name="s",
                                                                                                            term=Variable(
                                                                                                                name="s"
                                                                                                            ),
                                                                                                            state=frozendict.frozendict(
                                                                                                                {}
                                                                                                            ),
                                                                                                        ),
                                                                                                        x=Apply(
                                                                                                            f=Lambda(
                                                                                                                var_name="s",
                                                                                                                term=Variable(
                                                                                                                    name="s"
                                                                                                                ),
                                                                                                                state=frozendict.frozendict(
                                                                                                                    {}
                                                                                                                ),
                                                                                                            ),
                                                                                                            x=Apply(
                                                                                                                f=Lambda(
                                                                                                                    var_name="s",
                                                                                                                    term=Variable(
                                                                                                                        name="s"
                                                                                                                    ),
                                                                                                                    state=frozendict.frozendict(
                                                                                                                        {}
                                                                                                                    ),
                                                                                                                ),
                                                                                                                x=Apply(
                                                                                                                    f=Lambda(
                                                                                                                        var_name="s",
                                                                                                                        term=Variable(
                                                                                                                            name="s"
                                                                                                                        ),
                                                                                                                        state=frozendict.frozendict(
                                                                                                                            {}
                                                                                                                        ),
                                                                                                                    ),
                                                                                                                    x=Apply(
                                                                                                                        f=Lambda(
                                                                                                                            var_name="s",
                                                                                                                            term=Variable(
                                                                                                                                name="s"
                                                                                                                            ),
                                                                                                                            state=frozendict.frozendict(
                                                                                                                                {}
                                                                                                                            ),
                                                                                                                        ),
                                                                                                                        x=Apply(
                                                                                                                            f=Lambda(
                                                                                                                                var_name="s",
                                                                                                                                term=Variable(
                                                                                                                                    name="s"
                                                                                                                                ),
                                                                                                                                state=frozendict.frozendict(
                                                                                                                                    {}
                                                                                                                                ),
                                                                                                                            ),
                                                                                                                            x=Apply(
                                                                                                                                f=Lambda(
                                                                                                                                    var_name="s",
                                                                                                                                    term=Variable(
                                                                                                                                        name="s"
                                                                                                                                    ),
                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                        {}
                                                                                                                                    ),
                                                                                                                                ),
                                                                                                                                x=Apply(
                                                                                                                                    f=Lambda(
                                                                                                                                        var_name="s",
                                                                                                                                        term=Variable(
                                                                                                                                            name="s"
                                                                                                                                        ),
                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                            {}
                                                                                                                                        ),
                                                                                                                                    ),
                                                                                                                                    x=Apply(
                                                                                                                                        f=Lambda(
                                                                                                                                            var_name="s",
                                                                                                                                            term=Variable(
                                                                                                                                                name="s"
                                                                                                                                            ),
                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                {}
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                        x=Apply(
                                                                                                                                            f=Lambda(
                                                                                                                                                var_name="s",
                                                                                                                                                term=Variable(
                                                                                                                                                    name="s"
                                                                                                                                                ),
                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                    {}
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                            x=Apply(
                                                                                                                                                f=Lambda(
                                                                                                                                                    var_name="s",
                                                                                                                                                    term=Variable(
                                                                                                                                                        name="s"
                                                                                                                                                    ),
                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                        {}
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                                x=Apply(
                                                                                                                                                    f=Lambda(
                                                                                                                                                        var_name="s",
                                                                                                                                                        term=Variable(
                                                                                                                                                            name="s"
                                                                                                                                                        ),
                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                            {}
                                                                                                                                                        ),
                                                                                                                                                    ),
                                                                                                                                                    x=Apply(
                                                                                                                                                        f=Lambda(
                                                                                                                                                            var_name="s",
                                                                                                                                                            term=Variable(
                                                                                                                                                                name="s"
                                                                                                                                                            ),
                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                {}
                                                                                                                                                            ),
                                                                                                                                                        ),
                                                                                                                                                        x=Apply(
                                                                                                                                                            f=Lambda(
                                                                                                                                                                var_name="s",
                                                                                                                                                                term=Variable(
                                                                                                                                                                    name="s"
                                                                                                                                                                ),
                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                    {}
                                                                                                                                                                ),
                                                                                                                                                            ),
                                                                                                                                                            x=Apply(
                                                                                                                                                                f=Lambda(
                                                                                                                                                                    var_name="s",
                                                                                                                                                                    term=Variable(
                                                                                                                                                                        name="s"
                                                                                                                                                                    ),
                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                        {}
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                                x=Apply(
                                                                                                                                                                    f=Lambda(
                                                                                                                                                                        var_name="s",
                                                                                                                                                                        term=Variable(
                                                                                                                                                                            name="s"
                                                                                                                                                                        ),
                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                            {}
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                    x=Apply(
                                                                                                                                                                        f=Lambda(
                                                                                                                                                                            var_name="s",
                                                                                                                                                                            term=Variable(
                                                                                                                                                                                name="s"
                                                                                                                                                                            ),
                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                {}
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                        x=Apply(
                                                                                                                                                                            f=Lambda(
                                                                                                                                                                                var_name="s",
                                                                                                                                                                                term=Variable(
                                                                                                                                                                                    name="s"
                                                                                                                                                                                ),
                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                    {}
                                                                                                                                                                                ),
                                                                                                                                                                            ),
                                                                                                                                                                            x=Apply(
                                                                                                                                                                                f=Lambda(
                                                                                                                                                                                    var_name="s",
                                                                                                                                                                                    term=Variable(
                                                                                                                                                                                        name="s"
                                                                                                                                                                                    ),
                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                        {}
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                                x=Apply(
                                                                                                                                                                                    f=Lambda(
                                                                                                                                                                                        var_name="s",
                                                                                                                                                                                        term=Variable(
                                                                                                                                                                                            name="s"
                                                                                                                                                                                        ),
                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                            {}
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                    x=Apply(
                                                                                                                                                                                        f=Lambda(
                                                                                                                                                                                            var_name="s",
                                                                                                                                                                                            term=Variable(
                                                                                                                                                                                                name="s"
                                                                                                                                                                                            ),
                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                {}
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                        x=Apply(
                                                                                                                                                                                            f=Lambda(
                                                                                                                                                                                                var_name="s",
                                                                                                                                                                                                term=Variable(
                                                                                                                                                                                                    name="s"
                                                                                                                                                                                                ),
                                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                                    {}
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                            x=Apply(
                                                                                                                                                                                                f=Lambda(
                                                                                                                                                                                                    var_name="s",
                                                                                                                                                                                                    term=Variable(
                                                                                                                                                                                                        name="s"
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                                        {}
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                                x=Apply(
                                                                                                                                                                                                    f=Lambda(
                                                                                                                                                                                                        var_name="s",
                                                                                                                                                                                                        term=Variable(
                                                                                                                                                                                                            name="s"
                                                                                                                                                                                                        ),
                                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                                            {}
                                                                                                                                                                                                        ),
                                                                                                                                                                                                    ),
                                                                                                                                                                                                    x=Apply(
                                                                                                                                                                                                        f=Lambda(
                                                                                                                                                                                                            var_name="s",
                                                                                                                                                                                                            term=Variable(
                                                                                                                                                                                                                name="s"
                                                                                                                                                                                                            ),
                                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                                {}
                                                                                                                                                                                                            ),
                                                                                                                                                                                                        ),
                                                                                                                                                                                                        x=Apply(
                                                                                                                                                                                                            f=Lambda(
                                                                                                                                                                                                                var_name="s",
                                                                                                                                                                                                                term=Variable(
                                                                                                                                                                                                                    name="s"
                                                                                                                                                                                                                ),
                                                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                                                    {}
                                                                                                                                                                                                                ),
                                                                                                                                                                                                            ),
                                                                                                                                                                                                            x=Apply(
                                                                                                                                                                                                                f=Lambda(
                                                                                                                                                                                                                    var_name="s",
                                                                                                                                                                                                                    term=Variable(
                                                                                                                                                                                                                        name="s"
                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                                                        {}
                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                ),
                                                                                                                                                                                                                x=Apply(
                                                                                                                                                                                                                    f=Lambda(
                                                                                                                                                                                                                        var_name="s",
                                                                                                                                                                                                                        term=Variable(
                                                                                                                                                                                                                            name="s"
                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                                                            {}
                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                    x=Apply(
                                                                                                                                                                                                                        f=Lambda(
                                                                                                                                                                                                                            var_name="s",
                                                                                                                                                                                                                            term=Variable(
                                                                                                                                                                                                                                name="s"
                                                                                                                                                                                                                            ),
                                                                                                                                                                                                                            state=frozendict.frozendict(
                                                                                                                                                                                                                                {}
                                                                                                                                                                                                                            ),
                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                        x=Apply(
                                                                                                                                                                                                                            f=Lambda(
                                                                                                                                                                                                                                var_name="s",
                                                                                                                                                                                                                                term=Variable(
                                                                                                                                                                                                                                    name="s"
                                                                                                                                                                                                                                ),
                                                                                                                                                                                                                                state=frozendict.frozendict(
                                                                                                                                                                                                                                    {}
                                                                                                                                                                                                                                ),
                                                                                                                                                                                                                            ),
                                                                                                                                                                                                                            x=Apply(
                                                                                                                                                                                                                                f=Lambda(
                                                                                                                                                                                                                                    var_name="s",
                                                                                                                                                                                                                                    term=Variable(
                                                                                                                                                                                                                                        name="s"
                                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                                                                                                                        {}
                                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                                ),
                                                                                                                                                                                                                                x=Apply(
                                                                                                                                                                                                                                    f=Lambda(
                                                                                                                                                                                                                                        var_name="s",
                                                                                                                                                                                                                                        term=Variable(
                                                                                                                                                                                                                                            name="s"
                                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                                                                                                                            {}
                                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                                    x=Variable(
                                                                                                                                                                                                                                        name="s"
                                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                                ),
                                                                                                                                                                                                                            ),
                                                                                                                                                                                                                        ),
                                                                                                                                                                                                                    ),
                                                                                                                                                                                                                ),
                                                                                                                                                                                                            ),
                                                                                                                                                                                                        ),
                                                                                                                                                                                                    ),
                                                                                                                                                                                                ),
                                                                                                                                                                                            ),
                                                                                                                                                                                        ),
                                                                                                                                                                                    ),
                                                                                                                                                                                ),
                                                                                                                                                                            ),
                                                                                                                                                                        ),
                                                                                                                                                                    ),
                                                                                                                                                                ),
                                                                                                                                                            ),
                                                                                                                                                        ),
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                    ),
                                                                                                                                ),
                                                                                                                            ),
                                                                                                                        ),
                                                                                                                    ),
                                                                                                                ),
                                                                                                            ),
                                                                                                        ),
                                                                                                    ),
                                                                                                ),
                                                                                            ),
                                                                                        ),
                                                                                    ),
                                                                                ),
                                                                            ),
                                                                            state=frozendict.frozendict(
                                                                                {}
                                                                            ),
                                                                        ),
                                                                        x=Variable(
                                                                            name="s"
                                                                        ),
                                                                    ),
                                                                    x=BuiltinByteString(
                                                                        value=b"validator"
                                                                    ),
                                                                ),
                                                                x=Delay(
                                                                    term=Apply(
                                                                        f=Lambda(
                                                                            var_name="_",
                                                                            term=Error(),
                                                                            state=frozendict.frozendict(
                                                                                {}
                                                                            ),
                                                                        ),
                                                                        x=Apply(
                                                                            f=Apply(
                                                                                f=Force(
                                                                                    term=BuiltIn(
                                                                                        builtin=BuiltInFun.Trace,
                                                                                        applied_forces=0,
                                                                                        bound_arguments=[],
                                                                                    )
                                                                                ),
                                                                                x=BuiltinString(
                                                                                    value="NameError"
                                                                                ),
                                                                            ),
                                                                            x=BuiltinUnit(),
                                                                        ),
                                                                    ),
                                                                    state=frozendict.frozendict(
                                                                        {}
                                                                    ),
                                                                ),
                                                            )
                                                        ),
                                                    ),
                                                    state=frozendict.frozendict({}),
                                                ),
                                                x=Lambda(
                                                    var_name="x",
                                                    term=Lambda(
                                                        var_name="def",
                                                        term=Force(
                                                            term=Apply(
                                                                f=Apply(
                                                                    f=Apply(
                                                                        f=Force(
                                                                            term=BuiltIn(
                                                                                builtin=BuiltInFun.IfThenElse,
                                                                                applied_forces=0,
                                                                                bound_arguments=[],
                                                                            )
                                                                        ),
                                                                        x=Apply(
                                                                            f=Apply(
                                                                                f=BuiltIn(
                                                                                    builtin=BuiltInFun.EqualsByteString,
                                                                                    applied_forces=0,
                                                                                    bound_arguments=[],
                                                                                ),
                                                                                x=Variable(
                                                                                    name="x"
                                                                                ),
                                                                            ),
                                                                            x=BuiltinByteString(
                                                                                value=b"range"
                                                                            ),
                                                                        ),
                                                                    ),
                                                                    x=Delay(
                                                                        term=Delay(
                                                                            term=Lambda(
                                                                                var_name="f",
                                                                                term=Lambda(
                                                                                    var_name="limit",
                                                                                    term=Lambda(
                                                                                        var_name="s",
                                                                                        term=Apply(
                                                                                            f=Apply(
                                                                                                f=Apply(
                                                                                                    f=Lambda(
                                                                                                        var_name="limit",
                                                                                                        term=Lambda(
                                                                                                            var_name="step",
                                                                                                            term=Apply(
                                                                                                                f=Lambda(
                                                                                                                    var_name="g",
                                                                                                                    term=Apply(
                                                                                                                        f=Variable(
                                                                                                                            name="g"
                                                                                                                        ),
                                                                                                                        x=Variable(
                                                                                                                            name="g"
                                                                                                                        ),
                                                                                                                    ),
                                                                                                                    state=frozendict.frozendict(
                                                                                                                        {}
                                                                                                                    ),
                                                                                                                ),
                                                                                                                x=Lambda(
                                                                                                                    var_name="f",
                                                                                                                    term=Lambda(
                                                                                                                        var_name="cur",
                                                                                                                        term=Force(
                                                                                                                            term=Apply(
                                                                                                                                f=Apply(
                                                                                                                                    f=Apply(
                                                                                                                                        f=Force(
                                                                                                                                            term=BuiltIn(
                                                                                                                                                builtin=BuiltInFun.IfThenElse,
                                                                                                                                                applied_forces=0,
                                                                                                                                                bound_arguments=[],
                                                                                                                                            )
                                                                                                                                        ),
                                                                                                                                        x=Apply(
                                                                                                                                            f=Apply(
                                                                                                                                                f=BuiltIn(
                                                                                                                                                    builtin=BuiltInFun.LessThanInteger,
                                                                                                                                                    applied_forces=0,
                                                                                                                                                    bound_arguments=[],
                                                                                                                                                ),
                                                                                                                                                x=Variable(
                                                                                                                                                    name="cur"
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                            x=Variable(
                                                                                                                                                name="limit"
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                    ),
                                                                                                                                    x=Delay(
                                                                                                                                        term=Apply(
                                                                                                                                            f=Apply(
                                                                                                                                                f=Force(
                                                                                                                                                    term=BuiltIn(
                                                                                                                                                        builtin=BuiltInFun.MkCons,
                                                                                                                                                        applied_forces=0,
                                                                                                                                                        bound_arguments=[],
                                                                                                                                                    )
                                                                                                                                                ),
                                                                                                                                                x=Variable(
                                                                                                                                                    name="cur"
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                            x=Apply(
                                                                                                                                                f=Apply(
                                                                                                                                                    f=Variable(
                                                                                                                                                        name="f"
                                                                                                                                                    ),
                                                                                                                                                    x=Variable(
                                                                                                                                                        name="f"
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                                x=Apply(
                                                                                                                                                    f=Apply(
                                                                                                                                                        f=BuiltIn(
                                                                                                                                                            builtin=BuiltInFun.AddInteger,
                                                                                                                                                            applied_forces=0,
                                                                                                                                                            bound_arguments=[],
                                                                                                                                                        ),
                                                                                                                                                        x=Variable(
                                                                                                                                                            name="cur"
                                                                                                                                                        ),
                                                                                                                                                    ),
                                                                                                                                                    x=Variable(
                                                                                                                                                        name="step"
                                                                                                                                                    ),
                                                                                                                                                ),
                                                                                                                                            ),
                                                                                                                                        ),
                                                                                                                                        state=frozendict.frozendict(
                                                                                                                                            {}
                                                                                                                                        ),
                                                                                                                                    ),
                                                                                                                                ),
                                                                                                                                x=Delay(
                                                                                                                                    term=Apply(
                                                                                                                                        f=BuiltIn(
                                                                                                                                            builtin=BuiltInFun.MkNilData,
                                                                                                                                            applied_forces=0,
                                                                                                                                            bound_arguments=[],
                                                                                                                                        ),
                                                                                                                                        x=BuiltinUnit(),
                                                                                                                                    ),
                                                                                                                                    state=frozendict.frozendict(
                                                                                                                                        {}
                                                                                                                                    ),
                                                                                                                                ),
                                                                                                                            )
                                                                                                                        ),
                                                                                                                        state=frozendict.frozendict(
                                                                                                                            {}
                                                                                                                        ),
                                                                                                                    ),
                                                                                                                    state=frozendict.frozendict(
                                                                                                                        {}
                                                                                                                    ),
                                                                                                                ),
                                                                                                            ),
                                                                                                            state=frozendict.frozendict(
                                                                                                                {}
                                                                                                            ),
                                                                                                        ),
                                                                                                        state=frozendict.frozendict(
                                                                                                            {}
                                                                                                        ),
                                                                                                    ),
                                                                                                    x=Variable(
                                                                                                        name="limit"
                                                                                                    ),
                                                                                                ),
                                                                                                x=BuiltinInteger(
                                                                                                    value=1
                                                                                                ),
                                                                                            ),
                                                                                            x=BuiltinInteger(
                                                                                                value=0
                                                                                            ),
                                                                                        ),
                                                                                        state=frozendict.frozendict(
                                                                                            {}
                                                                                        ),
                                                                                    ),
                                                                                    state=frozendict.frozendict(
                                                                                        {}
                                                                                    ),
                                                                                ),
                                                                                state=frozendict.frozendict(
                                                                                    {}
                                                                                ),
                                                                            ),
                                                                            state=frozendict.frozendict(
                                                                                {}
                                                                            ),
                                                                        ),
                                                                        state=frozendict.frozendict(
                                                                            {}
                                                                        ),
                                                                    ),
                                                                ),
                                                                x=Delay(
                                                                    term=Force(
                                                                        term=Apply(
                                                                            f=Apply(
                                                                                f=Apply(
                                                                                    f=Force(
                                                                                        term=BuiltIn(
                                                                                            builtin=BuiltInFun.IfThenElse,
                                                                                            applied_forces=0,
                                                                                            bound_arguments=[],
                                                                                        )
                                                                                    ),
                                                                                    x=Apply(
                                                                                        f=Apply(
                                                                                            f=BuiltIn(
                                                                                                builtin=BuiltInFun.EqualsByteString,
                                                                                                applied_forces=0,
                                                                                                bound_arguments=[],
                                                                                            ),
                                                                                            x=Variable(
                                                                                                name="x"
                                                                                            ),
                                                                                        ),
                                                                                        x=BuiltinByteString(
                                                                                            value=b"print"
                                                                                        ),
                                                                                    ),
                                                                                ),
                                                                                x=Delay(
                                                                                    term=Delay(
                                                                                        term=Lambda(
                                                                                            var_name="f",
                                                                                            term=Lambda(
                                                                                                var_name="x",
                                                                                                term=Lambda(
                                                                                                    var_name="s",
                                                                                                    term=Apply(
                                                                                                        f=Apply(
                                                                                                            f=Force(
                                                                                                                term=BuiltIn(
                                                                                                                    builtin=BuiltInFun.Trace,
                                                                                                                    applied_forces=0,
                                                                                                                    bound_arguments=[],
                                                                                                                )
                                                                                                            ),
                                                                                                            x=Variable(
                                                                                                                name="x"
                                                                                                            ),
                                                                                                        ),
                                                                                                        x=Apply(
                                                                                                            f=Apply(
                                                                                                                f=BuiltIn(
                                                                                                                    builtin=BuiltInFun.ConstrData,
                                                                                                                    applied_forces=0,
                                                                                                                    bound_arguments=[],
                                                                                                                ),
                                                                                                                x=BuiltinInteger(
                                                                                                                    value=0
                                                                                                                ),
                                                                                                            ),
                                                                                                            x=Apply(
                                                                                                                f=BuiltIn(
                                                                                                                    builtin=BuiltInFun.MkNilData,
                                                                                                                    applied_forces=0,
                                                                                                                    bound_arguments=[],
                                                                                                                ),
                                                                                                                x=BuiltinUnit(),
                                                                                                            ),
                                                                                                        ),
                                                                                                    ),
                                                                                                    state=frozendict.frozendict(
                                                                                                        {}
                                                                                                    ),
                                                                                                ),
                                                                                                state=frozendict.frozendict(
                                                                                                    {}
                                                                                                ),
                                                                                            ),
                                                                                            state=frozendict.frozendict(
                                                                                                {}
                                                                                            ),
                                                                                        ),
                                                                                        state=frozendict.frozendict(
                                                                                            {}
                                                                                        ),
                                                                                    ),
                                                                                    state=frozendict.frozendict(
                                                                                        {}
                                                                                    ),
                                                                                ),
                                                                            ),
                                                                            x=Delay(
                                                                                term=Apply(
                                                                                    f=Apply(
                                                                                        f=Lambda(
                                                                                            var_name="x",
                                                                                            term=Lambda(
                                                                                                var_name="def",
                                                                                                term=Variable(
                                                                                                    name="def"
                                                                                                ),
                                                                                                state=frozendict.frozendict(
                                                                                                    {}
                                                                                                ),
                                                                                            ),
                                                                                            state=frozendict.frozendict(
                                                                                                {}
                                                                                            ),
                                                                                        ),
                                                                                        x=Variable(
                                                                                            name="x"
                                                                                        ),
                                                                                    ),
                                                                                    x=Variable(
                                                                                        name="def"
                                                                                    ),
                                                                                ),
                                                                                state=frozendict.frozendict(
                                                                                    {}
                                                                                ),
                                                                            ),
                                                                        )
                                                                    ),
                                                                    state=frozendict.frozendict(
                                                                        {}
                                                                    ),
                                                                ),
                                                            )
                                                        ),
                                                        state=frozendict.frozendict({}),
                                                    ),
                                                    state=frozendict.frozendict({}),
                                                ),
                                            ),
                                        ),
                                        x=Delay(
                                            term=BuiltinUnit(),
                                            state=frozendict.frozendict({}),
                                        ),
                                    ),
                                    x=Delay(
                                        term=Apply(
                                            f=Lambda(
                                                var_name="_",
                                                term=Error(),
                                                state=frozendict.frozendict({}),
                                            ),
                                            x=Apply(
                                                f=Apply(
                                                    f=Force(
                                                        term=BuiltIn(
                                                            builtin=BuiltInFun.Trace,
                                                            applied_forces=0,
                                                            bound_arguments=[],
                                                        )
                                                    ),
                                                    x=BuiltinString(
                                                        value="ValidationError"
                                                    ),
                                                ),
                                                x=BuiltinUnit(),
                                            ),
                                        ),
                                        state=frozendict.frozendict({}),
                                    ),
                                )
                            ),
                            state=frozendict.frozendict({}),
                        ),
                        state=frozendict.frozendict({}),
                    ),
                    state=frozendict.frozendict({}),
                ),
                PlutusInteger(20),
            ),
            PlutusInteger(22),
        ),
        BuiltinUnit(),
    ),
)


class MiscTest(unittest.TestCase):
    def test_simple_contract(self):
        p = SAMPLE_CONTRACT
        # should not raise
        d = dumps(p)
        # should not raise
        parse(d)
        # should not raise
        r = eval(p)
        self.assertEqual(r, BuiltinUnit())

    def test_unpack_plutus_data(self):
        p = Program(
            "0.0.1",
            Apply(
                BuiltIn(BuiltInFun.UnConstrData),
                data_from_cbor(
                    bytes.fromhex(
                        "d8799fd8799fd8799fd8799f581ce3a0254c00994f731550f81239f12a60c9fd3ce9b9b191543152ec22ffd8799fd8799fd8799f581cb1bec305ddc80189dac8b628ee0adfbe5245c53b84e678ed7ec23d75ffffffff581ce3a0254c00994f731550f81239f12a60c9fd3ce9b9b191543152ec221b0000018bcfe56800d8799fd8799f4040ffd8799f581cdda5fdb1002f7389b33e036b6afee82a8189becb6cba852e8b79b4fb480014df1047454e53ffffffd8799fd87a801a00989680ffff"
                    )
                ),
            ),
        )
        # should not raise anything
        d = dumps(p)
        # should not raise anything
        parse(d)
        r = eval(p)
        # should not raise anything
        r.dumps()
        self.assertEqual(
            r,
            BuiltinPair(
                l_value=BuiltinInteger(value=0),
                r_value=BuiltinList(
                    values=[
                        PlutusConstr(
                            constructor=0,
                            fields=[
                                PlutusConstr(
                                    constructor=0,
                                    fields=[
                                        PlutusConstr(
                                            constructor=0,
                                            fields=[
                                                PlutusByteString(
                                                    value=b'\xe3\xa0%L\x00\x99Os\x15P\xf8\x129\xf1*`\xc9\xfd<\xe9\xb9\xb1\x91T1R\xec"'
                                                )
                                            ],
                                        ),
                                        PlutusConstr(
                                            constructor=0,
                                            fields=[
                                                PlutusConstr(
                                                    constructor=0,
                                                    fields=[
                                                        PlutusConstr(
                                                            constructor=0,
                                                            fields=[
                                                                PlutusByteString(
                                                                    value=b"\xb1\xbe\xc3\x05\xdd\xc8\x01\x89\xda\xc8\xb6(\xee\n\xdf\xbeRE\xc5;\x84\xe6x\xed~\xc2=u"
                                                                )
                                                            ],
                                                        )
                                                    ],
                                                )
                                            ],
                                        ),
                                    ],
                                ),
                                PlutusByteString(
                                    value=b'\xe3\xa0%L\x00\x99Os\x15P\xf8\x129\xf1*`\xc9\xfd<\xe9\xb9\xb1\x91T1R\xec"'
                                ),
                                PlutusInteger(value=1700000000000),
                                PlutusConstr(
                                    constructor=0,
                                    fields=[
                                        PlutusConstr(
                                            constructor=0,
                                            fields=[
                                                PlutusByteString(value=b""),
                                                PlutusByteString(value=b""),
                                            ],
                                        ),
                                        PlutusConstr(
                                            constructor=0,
                                            fields=[
                                                PlutusByteString(
                                                    value=b"\xdd\xa5\xfd\xb1\x00/s\x89\xb3>\x03kj\xfe\xe8*\x81\x89\xbe\xcbl\xba\x85.\x8by\xb4\xfb"
                                                ),
                                                PlutusByteString(
                                                    value=b"\x00\x14\xdf\x10GENS"
                                                ),
                                            ],
                                        ),
                                    ],
                                ),
                            ],
                        ),
                        PlutusConstr(
                            constructor=0,
                            fields=[
                                PlutusConstr(constructor=1, fields=[]),
                                PlutusInteger(value=10000000),
                            ],
                        ),
                    ]
                ),
            ),
        )

    def test_parse(self):
        p = parse(
            """
(program
  1.0.0
  [ [ [ (force (delay [(lam i_0 (con integer 2)) (con bytestring #02)])) (builtin addInteger) ] (error) ] (con pair<list<integer>,unit> [[],()]) ]
)
        """
        )
        print(dumps(p))

    def test_parse_plutus(self):
        p = parse(
            """(program 1.0.0 (con (pair (list integer) bytestring) ([1], #01)))"""
        )
        print(dumps(p, dialect=UPLCDialect.Plutus))

    def test_simple_contract_rewrite(self):
        p = SAMPLE_CONTRACT
        # should not raise
        p = unique_variables.UniqueVariableTransformer().visit(p)
        # should not raise
        d = dumps(p)
        # should not raise
        parse(d)
        r = eval(p)
        self.assertEqual(r, BuiltinUnit())

    @parameterized.expand(
        [
            (
                "-- here is a comment \n and here is normal text",
                "\n and here is normal text",
            ),
            ("-- here is a comment ", ""),
        ]
    )
    def test_strip_comments(self, input, expected):
        self.assertEqual(strip_comments(input), expected)

    @parameterized.expand(
        [
            ("""(program 1.0.0 (con data 123)""",),
            ("""(program 1.0.0 (con data { ByteString #00})""",),
        ]
    )
    def test_parse_fail(self, i):
        try:
            parse(i)
            self.fail("Unexpextedly passed")
        except SyntaxError:
            pass

    def test_simple_contract_optimize(self):
        p = SAMPLE_CONTRACT
        # should not raise
        p = pre_evaluation.PreEvaluationOptimizer().visit(p)
        # should not raise
        d = dumps(p)
        # should not raise
        parse(d)
        r = eval(p)
        self.assertEqual(r, BuiltinUnit())
