Module hebi.typed_ast

Expand source code
import typing
from ast import *
from dataclasses import dataclass

from frozenlist import FrozenList

import pluthon as plt
import uplc.ast as uplc


def distinct(xs: list):
    """Returns true iff the list consists of distinct elements"""
    return len(xs) == len(set(xs))


def FrozenFrozenList(l: list):
    fl = FrozenList(l)
    fl.freeze()
    return fl


class Type:
    def constr_type(self) -> "InstanceType":
        """The type of the constructor for this class"""
        raise TypeInferenceError(
            f"Object of type {self.__class__} does not have a constructor"
        )

    def constr(self) -> plt.AST:
        """The constructor for this class"""
        raise NotImplementedError(f"Constructor of {self.__class__} not implemented")

    def attribute_type(self, attr) -> "Type":
        """The types of the named attributes of this class"""
        raise TypeInferenceError(
            f"Object of type {self.__class__} does not have attribute {attr}"
        )

    def attribute(self, attr) -> plt.AST:
        """The attributes of this class. Needs to be a lambda that expects as first argument the object itself"""
        raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        raise NotImplementedError(
            f"Comparison {type(op).__name__} for {self.__class__.__name__} and {o.__class__.__name__} is not implemented. This is likely intended because it would always evaluate to False."
        )


@dataclass(frozen=True, unsafe_hash=True)
class Record:
    name: str
    constructor: int
    fields: typing.Union[typing.List[typing.Tuple[str, Type]], FrozenList]


@dataclass(frozen=True, unsafe_hash=True)
class ClassType(Type):
    def __ge__(self, other):
        raise NotImplementedError("Comparison between raw classtypes impossible")


@dataclass(frozen=True, unsafe_hash=True)
class AnyType(ClassType):
    """The top element in the partial order on types"""

    def __ge__(self, other):
        return True


@dataclass(frozen=True, unsafe_hash=True)
class AtomicType(ClassType):
    def __ge__(self, other):
        # Can only substitute for its own type (also subtypes)
        return isinstance(other, self.__class__)


@dataclass(frozen=True, unsafe_hash=True)
class RecordType(ClassType):
    record: Record

    def constr_type(self) -> "InstanceType":
        return InstanceType(
            FunctionType([f[1] for f in self.record.fields], InstanceType(self))
        )

    def constr(self) -> plt.AST:
        # wrap all constructor values to PlutusData
        build_constr_params = plt.EmptyDataList()
        for n, t in reversed(self.record.fields):
            build_constr_params = plt.MkCons(
                transform_output_map(t)(plt.Var(n)), build_constr_params
            )
        # then build a constr type with this PlutusData
        return plt.Lambda(
            ["_"] + [n for n, _ in self.record.fields],
            plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
        )

    def attribute_type(self, attr: str) -> Type:
        """The types of the named attributes of this class"""
        if attr == "CONSTR_ID":
            return IntegerInstanceType
        for n, t in self.record.fields:
            if n == attr:
                return t
        raise TypeInferenceError(
            f"Type {self.record.name} does not have attribute {attr}"
        )

    def attribute(self, attr: str) -> plt.AST:
        """The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
        if attr == "CONSTR_ID":
            # access to constructor
            return plt.Lambda(
                ["self"],
                plt.Constructor(plt.Var("self")),
            )
        attr_typ = self.attribute_type(attr)
        pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
        # access to normal fields
        return plt.Lambda(
            ["self"],
            transform_ext_params_map(attr_typ)(
                plt.NthField(
                    plt.Var("self"),
                    plt.Integer(pos),
                ),
            ),
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        # this will reject comparisons that will always be false - most likely due to faults during programming
        if (isinstance(o, RecordType) and o.record == self.record) or (
            isinstance(o, UnionType) and self in o.typs
        ):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                            plt.Var("x"),
                            plt.Var("y"),
                        )
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and o.typ.typ >= self
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsData(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsData), plt.Var("x")
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.ConstrData(
                                plt.AddInteger(
                                    plt.Constructor(plt.Var("x")), plt.Integer(1)
                                ),
                                plt.MkNilData(plt.Unit()),
                            ),
                        ),
                    ),
                )
        return super().cmp(op, o)

    def __ge__(self, other):
        # Can only substitute for its own type, records need to be equal
        # if someone wants to be funny, they can implement <= to be true if all fields match up to some point
        return isinstance(other, self.__class__) and other.record == self.record


@dataclass(frozen=True, unsafe_hash=True)
class UnionType(ClassType):
    typs: typing.List[RecordType]

    def attribute_type(self, attr) -> "Type":
        if attr == "CONSTR_ID":
            return IntegerInstanceType
        # iterate through all names/types of the unioned records by position
        for attr_names, attr_types in map(
            lambda x: zip(*x), zip(*(t.record.fields for t in self.typs))
        ):
            # need to have a common field with the same name, in the same position!
            if any(attr_name != attr for attr_name in attr_names):
                continue
            for at in attr_types:
                # return the maximum element if there is one
                if all(at >= at2 for at2 in attr_types):
                    return at
            # return the union type of all possible instantiations if all possible values are record types
            if all(
                isinstance(at, InstanceType) and isinstance(at.typ, RecordType)
                for at in attr_types
            ) and distinct([at.typ.record.constructor for at in attr_types]):
                return InstanceType(
                    UnionType(FrozenFrozenList([at.typ for at in attr_types]))
                )
            # return Anytype
            return InstanceType(AnyType())
        raise TypeInferenceError(
            f"Can not access attribute {attr} of Union type. Cast to desired type with an 'if isinstance(_, _):' branch."
        )

    def attribute(self, attr: str) -> plt.AST:
        if attr == "CONSTR_ID":
            # access to constructor
            return plt.Lambda(
                ["self"],
                plt.Constructor(plt.Var("self")),
            )
        # iterate through all names/types of the unioned records by position
        attr_typ = self.attribute_type(attr)
        pos = next(
            i
            for i, (ns, _) in enumerate(
                map(lambda x: zip(*x), zip(*(t.record.fields for t in self.typs)))
            )
            if all(n == attr for n in ns)
        )
        # access to normal fields
        return plt.Lambda(
            ["self"],
            transform_ext_params_map(attr_typ)(
                plt.NthField(
                    plt.Var("self"),
                    plt.Integer(pos),
                ),
            ),
        )

    def __ge__(self, other):
        if isinstance(other, UnionType):
            return all(any(t >= ot for ot in other.typs) for t in self.typs)
        return any(t >= other for t in self.typs)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        # this will reject comparisons that will always be false - most likely due to faults during programming
        # note we require that there is an overlapt between the possible types for unions
        if (isinstance(o, RecordType) and o in self.typs) or (
            isinstance(o, UnionType) and set(self.typs).intersection(o.typs)
        ):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                            plt.Var("x"),
                            plt.Var("y"),
                        )
                    ),
                )
        raise NotImplementedError(
            f"Can not compare {o} and {self} with operation {op.__class__}. Note that comparisons that always return false are also rejected."
        )


@dataclass(frozen=True, unsafe_hash=True)
class TupleType(ClassType):
    typs: typing.List[Type]

    def __ge__(self, other):
        return isinstance(other, TupleType) and all(
            t >= ot for t, ot in zip(self.typs, other.typs)
        )


@dataclass(frozen=True, unsafe_hash=True)
class PairType(ClassType):
    """An internal type representing built-in PlutusData pairs"""

    l_typ: Type
    r_typ: Type

    def __ge__(self, other):
        return isinstance(other, PairType) and all(
            t >= ot
            for t, ot in zip((self.l_typ, self.r_typ), (other.l_typ, other.r_typ))
        )


@dataclass(frozen=True, unsafe_hash=True)
class ListType(ClassType):
    typ: Type

    def __ge__(self, other):
        return isinstance(other, ListType) and self.typ >= other.typ


@dataclass(frozen=True, unsafe_hash=True)
class DictType(ClassType):
    key_typ: Type
    value_typ: Type

    def attribute_type(self, attr) -> "Type":
        if attr == "get":
            return InstanceType(
                FunctionType([self.key_typ, self.value_typ], self.value_typ)
            )
        if attr == "keys":
            return InstanceType(FunctionType([], InstanceType(ListType(self.key_typ))))
        if attr == "values":
            return InstanceType(
                FunctionType([], InstanceType(ListType(self.value_typ)))
            )
        if attr == "items":
            return InstanceType(
                FunctionType(
                    [],
                    InstanceType(
                        ListType(InstanceType(PairType(self.key_typ, self.value_typ)))
                    ),
                )
            )
        raise TypeInferenceError(
            f"Type of attribute '{attr}' is unknown for type Dict."
        )

    def attribute(self, attr) -> plt.AST:
        if attr == "get":
            return plt.Lambda(
                ["self", "_", "key", "default"],
                transform_ext_params_map(self.value_typ)(
                    plt.SndPair(
                        plt.FindList(
                            plt.Var("self"),
                            plt.Lambda(
                                ["x"],
                                plt.EqualsData(
                                    transform_output_map(self.key_typ)(plt.Var("key")),
                                    plt.FstPair(plt.Var("x")),
                                ),
                            ),
                            # this is a bit ugly... we wrap - only to later unwrap again
                            plt.MkPairData(
                                transform_output_map(self.key_typ)(plt.Var("key")),
                                transform_output_map(self.value_typ)(
                                    plt.Var("default")
                                ),
                            ),
                        ),
                    ),
                ),
            )
        if attr == "keys":
            return plt.Lambda(
                ["self", "_"],
                plt.MapList(
                    plt.Var("self"),
                    plt.Lambda(
                        ["x"],
                        transform_ext_params_map(self.key_typ)(
                            plt.FstPair(plt.Var("x"))
                        ),
                    ),
                    empty_list(self.key_typ),
                ),
            )
        if attr == "values":
            return plt.Lambda(
                ["self", "_"],
                plt.MapList(
                    plt.Var("self"),
                    plt.Lambda(
                        ["x"],
                        transform_ext_params_map(self.value_typ)(
                            plt.SndPair(plt.Var("x"))
                        ),
                    ),
                    empty_list(self.value_typ),
                ),
            )
        if attr == "items":
            return plt.Lambda(
                ["self", "_"],
                plt.Var("self"),
            )
        raise NotImplementedError(f"Attribute '{attr}' of Dict is unknown.")

    def __ge__(self, other):
        return (
            isinstance(other, DictType)
            and self.key_typ >= other.key_typ
            and self.value_typ >= other.value_typ
        )


@dataclass(frozen=True, unsafe_hash=True)
class FunctionType(ClassType):
    argtyps: typing.List[Type]
    rettyp: Type

    def __ge__(self, other):
        return (
            isinstance(other, FunctionType)
            and all(a >= oa for a, oa in zip(self.argtyps, other.argtyps))
            and other.rettyp >= self.rettyp
        )


@dataclass(frozen=True, unsafe_hash=True)
class InstanceType(Type):
    typ: ClassType

    def constr_type(self) -> FunctionType:
        raise TypeInferenceError(f"Can not construct an instance {self}")

    def constr(self) -> plt.AST:
        raise NotImplementedError(f"Can not construct an instance {self}")

    def attribute_type(self, attr) -> Type:
        return self.typ.attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        return self.typ.attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        if isinstance(o, InstanceType):
            return self.typ.cmp(op, o.typ)
        return super().cmp(op, o)

    def __ge__(self, other):
        return isinstance(other, InstanceType) and self.typ >= other.typ


@dataclass(frozen=True, unsafe_hash=True)
class IntegerType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(FunctionType([StringInstanceType], InstanceType(self)))

    def constr(self) -> plt.AST:
        # TODO we need to strip the string implicitely before parsing it
        return plt.Lambda(
            ["_", "x"],
            plt.Let(
                [
                    ("e", plt.EncodeUtf8(plt.Var("x"))),
                    ("first_int", plt.IndexByteString(plt.Var("e"), plt.Integer(0))),
                    ("len", plt.LengthOfByteString(plt.Var("e"))),
                    (
                        "fold_start",
                        plt.Lambda(
                            ["start"],
                            plt.FoldList(
                                plt.Range(plt.Var("len"), plt.Var("start")),
                                plt.Lambda(
                                    ["s", "i"],
                                    plt.Let(
                                        [
                                            (
                                                "b",
                                                plt.IndexByteString(
                                                    plt.Var("e"), plt.Var("i")
                                                ),
                                            )
                                        ],
                                        plt.Ite(
                                            plt.EqualsInteger(
                                                plt.Var("b"), plt.Integer(ord("_"))
                                            ),
                                            plt.Var("s"),
                                            plt.Ite(
                                                plt.Or(
                                                    plt.LessThanInteger(
                                                        plt.Var("b"),
                                                        plt.Integer(ord("0")),
                                                    ),
                                                    plt.LessThanInteger(
                                                        plt.Integer(ord("9")),
                                                        plt.Var("b"),
                                                    ),
                                                ),
                                                plt.TraceError(
                                                    "ValueError: invalid literal for int() with base 10"
                                                ),
                                                plt.AddInteger(
                                                    plt.SubtractInteger(
                                                        plt.Var("b"),
                                                        plt.Integer(ord("0")),
                                                    ),
                                                    plt.MultiplyInteger(
                                                        plt.Var("s"), plt.Integer(10)
                                                    ),
                                                ),
                                            ),
                                        ),
                                    ),
                                ),
                                plt.Integer(0),
                            ),
                        ),
                    ),
                ],
                plt.Ite(
                    plt.Or(
                        plt.EqualsInteger(plt.Var("len"), plt.Integer(0)),
                        plt.EqualsInteger(
                            plt.Var("first_int"),
                            plt.Integer(ord("_")),
                        ),
                    ),
                    plt.TraceError(
                        "ValueError: invalid literal for int() with base 10"
                    ),
                    plt.Ite(
                        plt.EqualsInteger(
                            plt.Var("first_int"),
                            plt.Integer(ord("-")),
                        ),
                        plt.Negate(
                            plt.Apply(plt.Var("fold_start"), plt.Integer(1)),
                        ),
                        plt.Apply(plt.Var("fold_start"), plt.Integer(0)),
                    ),
                ),
            ),
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        if isinstance(o, BoolType):
            if isinstance(op, Eq):
                # 1 == True
                # 0 == False
                # all other comparisons are False
                return plt.Lambda(
                    ["x", "y"],
                    plt.Ite(
                        plt.Var("y"),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                    ),
                )
        if isinstance(o, IntegerType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsInteger)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsInteger),
                            plt.Var("y"),
                            plt.Var("x"),
                        )
                    ),
                )
            if isinstance(op, LtE):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger)
            if isinstance(op, Lt):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanInteger)
            if isinstance(op, Gt):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanInteger),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
            if isinstance(op, GtE):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and isinstance(o.typ.typ, IntegerType)
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsInteger(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsInteger), plt.Var("x")
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.AddInteger(plt.Var("x"), plt.Integer(1)),
                        ),
                    ),
                )
        return super().cmp(op, o)


@dataclass(frozen=True, unsafe_hash=True)
class StringType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(FunctionType([IntegerInstanceType], InstanceType(self)))

    def constr(self) -> plt.AST:
        # constructs a string representation of an integer
        return plt.Lambda(
            ["_", "x"],
            plt.DecodeUtf8(
                plt.Let(
                    [
                        (
                            "strlist",
                            plt.RecFun(
                                plt.Lambda(
                                    ["f", "i"],
                                    plt.Ite(
                                        plt.LessThanEqualsInteger(
                                            plt.Var("i"), plt.Integer(0)
                                        ),
                                        plt.EmptyIntegerList(),
                                        plt.MkCons(
                                            plt.AddInteger(
                                                plt.ModInteger(
                                                    plt.Var("i"), plt.Integer(10)
                                                ),
                                                plt.Integer(ord("0")),
                                            ),
                                            plt.Apply(
                                                plt.Var("f"),
                                                plt.Var("f"),
                                                plt.DivideInteger(
                                                    plt.Var("i"), plt.Integer(10)
                                                ),
                                            ),
                                        ),
                                    ),
                                ),
                            ),
                        ),
                        (
                            "mkstr",
                            plt.Lambda(
                                ["i"],
                                plt.FoldList(
                                    plt.Apply(plt.Var("strlist"), plt.Var("i")),
                                    plt.Lambda(
                                        ["b", "i"],
                                        plt.ConsByteString(plt.Var("i"), plt.Var("b")),
                                    ),
                                    plt.ByteString(b""),
                                ),
                            ),
                        ),
                    ],
                    plt.Ite(
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                        plt.ByteString(b"0"),
                        plt.Ite(
                            plt.LessThanInteger(plt.Var("x"), plt.Integer(0)),
                            plt.ConsByteString(
                                plt.Integer(ord("-")),
                                plt.Apply(plt.Var("mkstr"), plt.Negate(plt.Var("x"))),
                            ),
                            plt.Apply(plt.Var("mkstr"), plt.Var("x")),
                        ),
                    ),
                )
            ),
        )

    def attribute_type(self, attr) -> Type:
        if attr == "encode":
            return InstanceType(FunctionType([], ByteStringInstanceType))
        return super().attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        if attr == "encode":
            # No codec -> only the default (utf8) is allowed
            return plt.Lambda(["x", "_"], plt.EncodeUtf8(plt.Var("x")))
        return super().attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, StringType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsString)
        return super().cmp(op, o)


@dataclass(frozen=True, unsafe_hash=True)
class ByteStringType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(
            FunctionType(
                [InstanceType(ListType(IntegerInstanceType))], InstanceType(self)
            )
        )

    def constr(self) -> plt.AST:
        return plt.Lambda(
            ["_", "xs"],
            plt.RFoldList(
                plt.Var("xs"),
                plt.Lambda(["a", "x"], plt.ConsByteString(plt.Var("x"), plt.Var("a"))),
                plt.ByteString(b""),
            ),
        )

    def attribute_type(self, attr) -> Type:
        if attr == "decode":
            return InstanceType(FunctionType([], StringInstanceType))
        return super().attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        if attr == "decode":
            # No codec -> only the default (utf8) is allowed
            return plt.Lambda(["x", "_"], plt.DecodeUtf8(plt.Var("x")))
        return super().attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, ByteStringType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsByteString)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                            plt.Var("y"),
                            plt.Var("x"),
                        )
                    ),
                )
            if isinstance(op, Lt):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanByteString)
            if isinstance(op, LtE):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString)
            if isinstance(op, Gt):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanByteString),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
            if isinstance(op, GtE):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and isinstance(o.typ.typ, ByteStringType)
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsByteString(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                                plt.Var("x"),
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.ConsByteString(plt.Integer(0), plt.Var("x")),
                        ),
                    ),
                )
        return super().cmp(op, o)


@dataclass(frozen=True, unsafe_hash=True)
class BoolType(AtomicType):
    def constr_type(self) -> "InstanceType":
        return InstanceType(FunctionType([IntegerInstanceType], BoolInstanceType))

    def constr(self) -> plt.AST:
        # constructs a boolean from an integer
        return plt.Lambda(
            ["_", "x"], plt.Not(plt.EqualsInteger(plt.Var("x"), plt.Integer(0)))
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, IntegerType):
            if isinstance(op, Eq):
                # 1 == True
                # 0 == False
                # all other comparisons are False
                return plt.Lambda(
                    ["y", "x"],
                    plt.Ite(
                        plt.Var("y"),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                    ),
                )
        if isinstance(o, BoolType):
            if isinstance(op, Eq):
                return plt.Lambda(["x", "y"], plt.Iff(plt.Var("x"), plt.Var("y")))
        return super().cmp(op, o)


@dataclass(frozen=True, unsafe_hash=True)
class UnitType(AtomicType):
    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, UnitType):
            if isinstance(op, Eq):
                return plt.Lambda(["x", "y"], plt.Bool(True))
            if isinstance(op, NotEq):
                return plt.Lambda(["x", "y"], plt.Bool(False))
        return super().cmp(op, o)


IntegerInstanceType = InstanceType(IntegerType())
StringInstanceType = InstanceType(StringType())
ByteStringInstanceType = InstanceType(ByteStringType())
BoolInstanceType = InstanceType(BoolType())
UnitInstanceType = InstanceType(UnitType())

ATOMIC_TYPES = {
    int.__name__: IntegerType(),
    str.__name__: StringType(),
    bytes.__name__: ByteStringType(),
    "Unit": UnitType(),
    bool.__name__: BoolType(),
}


NoneInstanceType = UnitInstanceType


class InaccessibleType(ClassType):
    """A type that blocks overwriting of a function"""

    pass


class PolymorphicFunction:
    def type_from_args(self, args: typing.List[Type]) -> FunctionType:
        raise NotImplementedError()

    def impl_from_args(self, args: typing.List[Type]) -> plt.AST:
        raise NotImplementedError()


@dataclass(frozen=True, unsafe_hash=True)
class PolymorphicFunctionType(ClassType):
    """A special type of builtin that may act differently on different parameters"""

    polymorphic_function: PolymorphicFunction


@dataclass(frozen=True, unsafe_hash=True)
class PolymorphicFunctionInstanceType(InstanceType):
    typ: FunctionType
    polymorphic_function: PolymorphicFunction


class TypedAST(AST):
    typ: Type


class typedexpr(TypedAST, expr):
    pass


class typedstmt(TypedAST, stmt):
    # Statements always have type None
    typ = NoneInstanceType


class typedarg(TypedAST, arg):
    pass


class typedarguments(TypedAST, arguments):
    args: typing.List[typedarg]
    vararg: typing.Union[typedarg, None]
    kwonlyargs: typing.List[typedarg]
    kw_defaults: typing.List[typing.Union[typedexpr, None]]
    kwarg: typing.Union[typedarg, None]
    defaults: typing.List[typedexpr]


class TypedModule(typedstmt, Module):
    body: typing.List[typedstmt]


class TypedFunctionDef(typedstmt, FunctionDef):
    body: typing.List[typedstmt]
    args: arguments


class TypedIf(typedstmt, If):
    test: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]


class TypedReturn(typedstmt, Return):
    value: typedexpr


class TypedExpression(typedexpr, Expression):
    body: typedexpr


class TypedCall(typedexpr, Call):
    func: typedexpr
    args: typing.List[typedexpr]


class TypedExpr(typedstmt, Expr):
    value: typedexpr


class TypedAssign(typedstmt, Assign):
    targets: typing.List[typedexpr]
    value: typedexpr


class TypedClassDef(typedstmt, ClassDef):
    class_typ: Type


class TypedAnnAssign(typedstmt, AnnAssign):
    target: typedexpr
    annotation: Type
    value: typedexpr


class TypedWhile(typedstmt, While):
    test: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]


class TypedFor(typedstmt, For):
    target: typedexpr
    iter: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]


class TypedPass(typedstmt, Pass):
    pass


class TypedName(typedexpr, Name):
    pass


class TypedConstant(TypedAST, Constant):
    pass


class TypedTuple(typedexpr, Tuple):
    pass


class TypedList(typedexpr, List):
    pass


class typedcomprehension(typedexpr, comprehension):
    target: typedexpr
    iter: typedexpr
    ifs: typing.List[typedexpr]


class TypedListComp(typedexpr, ListComp):
    generators: typing.List[typedcomprehension]
    elt: typedexpr


class TypedDict(typedexpr, Dict):
    pass


class TypedIfExp(typedstmt, IfExp):
    test: typedexpr
    body: typedexpr
    orelse: typedexpr


class TypedCompare(typedexpr, Compare):
    left: typedexpr
    ops: typing.List[cmpop]
    comparators: typing.List[typedexpr]


class TypedBinOp(typedexpr, BinOp):
    left: typedexpr
    right: typedexpr


class TypedBoolOp(typedexpr, BoolOp):
    values: typing.List[typedexpr]


class TypedUnaryOp(typedexpr, UnaryOp):
    operand: typedexpr


class TypedSubscript(typedexpr, Subscript):
    value: typedexpr


class TypedAttribute(typedexpr, Attribute):
    value: typedexpr
    pos: int


class TypedAssert(typedstmt, Assert):
    test: typedexpr
    msg: typedexpr


class RawPlutoExpr(typedexpr):
    typ: Type
    expr: plt.AST


class TypeInferenceError(AssertionError):
    pass


EmptyListMap = {
    IntegerInstanceType: plt.EmptyIntegerList(),
    ByteStringInstanceType: plt.EmptyByteStringList(),
    StringInstanceType: plt.EmptyTextList(),
    UnitInstanceType: plt.EmptyUnitList(),
    BoolInstanceType: plt.EmptyBoolList(),
}


def empty_list(p: Type):
    if p in EmptyListMap:
        return EmptyListMap[p]
    assert isinstance(p, InstanceType), "Can only create lists of instances"
    if isinstance(p.typ, ListType):
        el = empty_list(p.typ.typ)
        return plt.EmptyListList(uplc.BuiltinList([], el.sample_value))
    if isinstance(p.typ, DictType):
        return plt.EmptyListList(
            uplc.BuiltinList(
                [],
                uplc.BuiltinPair(
                    uplc.PlutusConstr(0, FrozenList([])),
                    uplc.PlutusConstr(0, FrozenList([])),
                ),
            )
        )
    if isinstance(p.typ, RecordType) or isinstance(p.typ, AnyType):
        return plt.EmptyDataList()
    raise NotImplementedError(f"Empty lists of type {p} can't be constructed yet")


TransformExtParamsMap = {
    IntegerInstanceType: lambda x: plt.UnIData(x),
    ByteStringInstanceType: lambda x: plt.UnBData(x),
    StringInstanceType: lambda x: plt.DecodeUtf8(plt.UnBData(x)),
    UnitInstanceType: lambda x: plt.Apply(plt.Lambda(["_"], plt.Unit())),
    BoolInstanceType: lambda x: plt.NotEqualsInteger(plt.UnIData(x), plt.Integer(0)),
}


def transform_ext_params_map(p: Type):
    assert isinstance(
        p, InstanceType
    ), "Can only transform instances, not classes as input"
    if p in TransformExtParamsMap:
        return TransformExtParamsMap[p]
    if isinstance(p.typ, ListType):
        list_int_typ = p.typ.typ
        return lambda x: plt.MapList(
            plt.UnListData(x),
            plt.Lambda(["x"], transform_ext_params_map(list_int_typ)(plt.Var("x"))),
            empty_list(p.typ.typ),
        )
    if isinstance(p.typ, DictType):
        # there doesn't appear to be a constructor function to make Pair a b for any types
        # so pairs will always contain Data
        return lambda x: plt.UnMapData(x)
    return lambda x: x


TransformOutputMap = {
    StringInstanceType: lambda x: plt.BData(plt.EncodeUtf8(x)),
    IntegerInstanceType: lambda x: plt.IData(x),
    ByteStringInstanceType: lambda x: plt.BData(x),
    UnitInstanceType: lambda x: plt.Apply(
        plt.Lambda(["_"], plt.ConstrData(plt.Integer(0), plt.EmptyDataList())), x
    ),
    BoolInstanceType: lambda x: plt.IData(
        plt.IfThenElse(x, plt.Integer(1), plt.Integer(0))
    ),
}


def transform_output_map(p: Type):
    assert isinstance(
        p, InstanceType
    ), "Can only transform instances, not classes as input"
    if p in TransformOutputMap:
        return TransformOutputMap[p]
    if isinstance(p.typ, ListType):
        list_int_typ = p.typ.typ
        return lambda x: plt.ListData(
            plt.MapList(
                x,
                plt.Lambda(["x"], transform_output_map(list_int_typ)(plt.Var("x"))),
            ),
        )
    if isinstance(p.typ, DictType):
        # there doesn't appear to be a constructor function to make Pair a b for any types
        # so pairs will always contain Data
        return lambda x: plt.MapData(x)
    return lambda x: x


class TypedNodeTransformer(NodeTransformer):
    def visit(self, node):
        """Visit a node."""
        node_class_name = node.__class__.__name__
        if node_class_name.startswith("Typed"):
            node_class_name = node_class_name[len("Typed") :]
        method = "visit_" + node_class_name
        visitor = getattr(self, method, self.generic_visit)
        return visitor(node)


class TypedNodeVisitor(NodeVisitor):
    def visit(self, node):
        """Visit a node."""
        node_class_name = node.__class__.__name__
        if node_class_name.startswith("Typed"):
            node_class_name = node_class_name[len("Typed") :]
        method = "visit_" + node_class_name
        visitor = getattr(self, method, self.generic_visit)
        return visitor(node)

Functions

def FrozenFrozenList(l: list)
Expand source code
def FrozenFrozenList(l: list):
    fl = FrozenList(l)
    fl.freeze()
    return fl
def distinct(xs: list)

Returns true iff the list consists of distinct elements

Expand source code
def distinct(xs: list):
    """Returns true iff the list consists of distinct elements"""
    return len(xs) == len(set(xs))
def empty_list(p: Type)
Expand source code
def empty_list(p: Type):
    if p in EmptyListMap:
        return EmptyListMap[p]
    assert isinstance(p, InstanceType), "Can only create lists of instances"
    if isinstance(p.typ, ListType):
        el = empty_list(p.typ.typ)
        return plt.EmptyListList(uplc.BuiltinList([], el.sample_value))
    if isinstance(p.typ, DictType):
        return plt.EmptyListList(
            uplc.BuiltinList(
                [],
                uplc.BuiltinPair(
                    uplc.PlutusConstr(0, FrozenList([])),
                    uplc.PlutusConstr(0, FrozenList([])),
                ),
            )
        )
    if isinstance(p.typ, RecordType) or isinstance(p.typ, AnyType):
        return plt.EmptyDataList()
    raise NotImplementedError(f"Empty lists of type {p} can't be constructed yet")
def transform_ext_params_map(p: Type)
Expand source code
def transform_ext_params_map(p: Type):
    assert isinstance(
        p, InstanceType
    ), "Can only transform instances, not classes as input"
    if p in TransformExtParamsMap:
        return TransformExtParamsMap[p]
    if isinstance(p.typ, ListType):
        list_int_typ = p.typ.typ
        return lambda x: plt.MapList(
            plt.UnListData(x),
            plt.Lambda(["x"], transform_ext_params_map(list_int_typ)(plt.Var("x"))),
            empty_list(p.typ.typ),
        )
    if isinstance(p.typ, DictType):
        # there doesn't appear to be a constructor function to make Pair a b for any types
        # so pairs will always contain Data
        return lambda x: plt.UnMapData(x)
    return lambda x: x
def transform_output_map(p: Type)
Expand source code
def transform_output_map(p: Type):
    assert isinstance(
        p, InstanceType
    ), "Can only transform instances, not classes as input"
    if p in TransformOutputMap:
        return TransformOutputMap[p]
    if isinstance(p.typ, ListType):
        list_int_typ = p.typ.typ
        return lambda x: plt.ListData(
            plt.MapList(
                x,
                plt.Lambda(["x"], transform_output_map(list_int_typ)(plt.Var("x"))),
            ),
        )
    if isinstance(p.typ, DictType):
        # there doesn't appear to be a constructor function to make Pair a b for any types
        # so pairs will always contain Data
        return lambda x: plt.MapData(x)
    return lambda x: x

Classes

class AnyType

The top element in the partial order on types

Expand source code
class AnyType(ClassType):
    """The top element in the partial order on types"""

    def __ge__(self, other):
        return True

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class AtomicType

AtomicType()

Expand source code
class AtomicType(ClassType):
    def __ge__(self, other):
        # Can only substitute for its own type (also subtypes)
        return isinstance(other, self.__class__)

Ancestors

Subclasses

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class BoolType

BoolType()

Expand source code
class BoolType(AtomicType):
    def constr_type(self) -> "InstanceType":
        return InstanceType(FunctionType([IntegerInstanceType], BoolInstanceType))

    def constr(self) -> plt.AST:
        # constructs a boolean from an integer
        return plt.Lambda(
            ["_", "x"], plt.Not(plt.EqualsInteger(plt.Var("x"), plt.Integer(0)))
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, IntegerType):
            if isinstance(op, Eq):
                # 1 == True
                # 0 == False
                # all other comparisons are False
                return plt.Lambda(
                    ["y", "x"],
                    plt.Ite(
                        plt.Var("y"),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                    ),
                )
        if isinstance(o, BoolType):
            if isinstance(op, Eq):
                return plt.Lambda(["x", "y"], plt.Iff(plt.Var("x"), plt.Var("y")))
        return super().cmp(op, o)

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: AtomicType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    if isinstance(o, IntegerType):
        if isinstance(op, Eq):
            # 1 == True
            # 0 == False
            # all other comparisons are False
            return plt.Lambda(
                ["y", "x"],
                plt.Ite(
                    plt.Var("y"),
                    plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                    plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                ),
            )
    if isinstance(o, BoolType):
        if isinstance(op, Eq):
            return plt.Lambda(["x", "y"], plt.Iff(plt.Var("x"), plt.Var("y")))
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    # constructs a boolean from an integer
    return plt.Lambda(
        ["_", "x"], plt.Not(plt.EqualsInteger(plt.Var("x"), plt.Integer(0)))
    )
def constr_type(self) ‑> InstanceType

Inherited from: AtomicType.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> "InstanceType":
    return InstanceType(FunctionType([IntegerInstanceType], BoolInstanceType))
class ByteStringType

ByteStringType()

Expand source code
class ByteStringType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(
            FunctionType(
                [InstanceType(ListType(IntegerInstanceType))], InstanceType(self)
            )
        )

    def constr(self) -> plt.AST:
        return plt.Lambda(
            ["_", "xs"],
            plt.RFoldList(
                plt.Var("xs"),
                plt.Lambda(["a", "x"], plt.ConsByteString(plt.Var("x"), plt.Var("a"))),
                plt.ByteString(b""),
            ),
        )

    def attribute_type(self, attr) -> Type:
        if attr == "decode":
            return InstanceType(FunctionType([], StringInstanceType))
        return super().attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        if attr == "decode":
            # No codec -> only the default (utf8) is allowed
            return plt.Lambda(["x", "_"], plt.DecodeUtf8(plt.Var("x")))
        return super().attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, ByteStringType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsByteString)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                            plt.Var("y"),
                            plt.Var("x"),
                        )
                    ),
                )
            if isinstance(op, Lt):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanByteString)
            if isinstance(op, LtE):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString)
            if isinstance(op, Gt):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanByteString),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
            if isinstance(op, GtE):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and isinstance(o.typ.typ, ByteStringType)
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsByteString(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                                plt.Var("x"),
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.ConsByteString(plt.Integer(0), plt.Var("x")),
                        ),
                    ),
                )
        return super().cmp(op, o)

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr) -> plt.AST:
    if attr == "decode":
        # No codec -> only the default (utf8) is allowed
        return plt.Lambda(["x", "_"], plt.DecodeUtf8(plt.Var("x")))
    return super().attribute(attr)
def attribute_type(self, attr) ‑> Type

Inherited from: AtomicType.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> Type:
    if attr == "decode":
        return InstanceType(FunctionType([], StringInstanceType))
    return super().attribute_type(attr)
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    if isinstance(o, ByteStringType):
        if isinstance(op, Eq):
            return plt.BuiltIn(uplc.BuiltInFun.EqualsByteString)
        if isinstance(op, NotEq):
            return plt.Lambda(
                ["x", "y"],
                plt.Not(
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                        plt.Var("y"),
                        plt.Var("x"),
                    )
                ),
            )
        if isinstance(op, Lt):
            return plt.BuiltIn(uplc.BuiltInFun.LessThanByteString)
        if isinstance(op, LtE):
            return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString)
        if isinstance(op, Gt):
            return plt.Lambda(
                ["x", "y"],
                plt.Apply(
                    plt.BuiltIn(uplc.BuiltInFun.LessThanByteString),
                    plt.Var("y"),
                    plt.Var("x"),
                ),
            )
        if isinstance(op, GtE):
            return plt.Lambda(
                ["x", "y"],
                plt.Apply(
                    plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsByteString),
                    plt.Var("y"),
                    plt.Var("x"),
                ),
            )
    if (
        isinstance(o, ListType)
        and isinstance(o.typ, InstanceType)
        and isinstance(o.typ.typ, ByteStringType)
    ):
        if isinstance(op, In):
            return plt.Lambda(
                ["x", "y"],
                plt.EqualsByteString(
                    plt.Var("x"),
                    plt.FindList(
                        plt.Var("y"),
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsByteString),
                            plt.Var("x"),
                        ),
                        # this simply ensures the default is always unequal to the searched value
                        plt.ConsByteString(plt.Integer(0), plt.Var("x")),
                    ),
                ),
            )
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    return plt.Lambda(
        ["_", "xs"],
        plt.RFoldList(
            plt.Var("xs"),
            plt.Lambda(["a", "x"], plt.ConsByteString(plt.Var("x"), plt.Var("a"))),
            plt.ByteString(b""),
        ),
    )
def constr_type(self) ‑> InstanceType

Inherited from: AtomicType.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> InstanceType:
    return InstanceType(
        FunctionType(
            [InstanceType(ListType(IntegerInstanceType))], InstanceType(self)
        )
    )
class ClassType

ClassType()

Expand source code
class ClassType(Type):
    def __ge__(self, other):
        raise NotImplementedError("Comparison between raw classtypes impossible")

Ancestors

Subclasses

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: Type.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: Type.constr_type

The type of the constructor for this class

class DictType (key_typ: Type, value_typ: Type)

DictType(key_typ: hebi.typed_ast.Type, value_typ: hebi.typed_ast.Type)

Expand source code
class DictType(ClassType):
    key_typ: Type
    value_typ: Type

    def attribute_type(self, attr) -> "Type":
        if attr == "get":
            return InstanceType(
                FunctionType([self.key_typ, self.value_typ], self.value_typ)
            )
        if attr == "keys":
            return InstanceType(FunctionType([], InstanceType(ListType(self.key_typ))))
        if attr == "values":
            return InstanceType(
                FunctionType([], InstanceType(ListType(self.value_typ)))
            )
        if attr == "items":
            return InstanceType(
                FunctionType(
                    [],
                    InstanceType(
                        ListType(InstanceType(PairType(self.key_typ, self.value_typ)))
                    ),
                )
            )
        raise TypeInferenceError(
            f"Type of attribute '{attr}' is unknown for type Dict."
        )

    def attribute(self, attr) -> plt.AST:
        if attr == "get":
            return plt.Lambda(
                ["self", "_", "key", "default"],
                transform_ext_params_map(self.value_typ)(
                    plt.SndPair(
                        plt.FindList(
                            plt.Var("self"),
                            plt.Lambda(
                                ["x"],
                                plt.EqualsData(
                                    transform_output_map(self.key_typ)(plt.Var("key")),
                                    plt.FstPair(plt.Var("x")),
                                ),
                            ),
                            # this is a bit ugly... we wrap - only to later unwrap again
                            plt.MkPairData(
                                transform_output_map(self.key_typ)(plt.Var("key")),
                                transform_output_map(self.value_typ)(
                                    plt.Var("default")
                                ),
                            ),
                        ),
                    ),
                ),
            )
        if attr == "keys":
            return plt.Lambda(
                ["self", "_"],
                plt.MapList(
                    plt.Var("self"),
                    plt.Lambda(
                        ["x"],
                        transform_ext_params_map(self.key_typ)(
                            plt.FstPair(plt.Var("x"))
                        ),
                    ),
                    empty_list(self.key_typ),
                ),
            )
        if attr == "values":
            return plt.Lambda(
                ["self", "_"],
                plt.MapList(
                    plt.Var("self"),
                    plt.Lambda(
                        ["x"],
                        transform_ext_params_map(self.value_typ)(
                            plt.SndPair(plt.Var("x"))
                        ),
                    ),
                    empty_list(self.value_typ),
                ),
            )
        if attr == "items":
            return plt.Lambda(
                ["self", "_"],
                plt.Var("self"),
            )
        raise NotImplementedError(f"Attribute '{attr}' of Dict is unknown.")

    def __ge__(self, other):
        return (
            isinstance(other, DictType)
            and self.key_typ >= other.key_typ
            and self.value_typ >= other.value_typ
        )

Ancestors

Class variables

var key_typType
var value_typType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr) -> plt.AST:
    if attr == "get":
        return plt.Lambda(
            ["self", "_", "key", "default"],
            transform_ext_params_map(self.value_typ)(
                plt.SndPair(
                    plt.FindList(
                        plt.Var("self"),
                        plt.Lambda(
                            ["x"],
                            plt.EqualsData(
                                transform_output_map(self.key_typ)(plt.Var("key")),
                                plt.FstPair(plt.Var("x")),
                            ),
                        ),
                        # this is a bit ugly... we wrap - only to later unwrap again
                        plt.MkPairData(
                            transform_output_map(self.key_typ)(plt.Var("key")),
                            transform_output_map(self.value_typ)(
                                plt.Var("default")
                            ),
                        ),
                    ),
                ),
            ),
        )
    if attr == "keys":
        return plt.Lambda(
            ["self", "_"],
            plt.MapList(
                plt.Var("self"),
                plt.Lambda(
                    ["x"],
                    transform_ext_params_map(self.key_typ)(
                        plt.FstPair(plt.Var("x"))
                    ),
                ),
                empty_list(self.key_typ),
            ),
        )
    if attr == "values":
        return plt.Lambda(
            ["self", "_"],
            plt.MapList(
                plt.Var("self"),
                plt.Lambda(
                    ["x"],
                    transform_ext_params_map(self.value_typ)(
                        plt.SndPair(plt.Var("x"))
                    ),
                ),
                empty_list(self.value_typ),
            ),
        )
    if attr == "items":
        return plt.Lambda(
            ["self", "_"],
            plt.Var("self"),
        )
    raise NotImplementedError(f"Attribute '{attr}' of Dict is unknown.")
def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> "Type":
    if attr == "get":
        return InstanceType(
            FunctionType([self.key_typ, self.value_typ], self.value_typ)
        )
    if attr == "keys":
        return InstanceType(FunctionType([], InstanceType(ListType(self.key_typ))))
    if attr == "values":
        return InstanceType(
            FunctionType([], InstanceType(ListType(self.value_typ)))
        )
    if attr == "items":
        return InstanceType(
            FunctionType(
                [],
                InstanceType(
                    ListType(InstanceType(PairType(self.key_typ, self.value_typ)))
                ),
            )
        )
    raise TypeInferenceError(
        f"Type of attribute '{attr}' is unknown for type Dict."
    )
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class FunctionType (argtyps: List[Type], rettyp: Type)

FunctionType(argtyps: List[hebi.typed_ast.Type], rettyp: hebi.typed_ast.Type)

Expand source code
class FunctionType(ClassType):
    argtyps: typing.List[Type]
    rettyp: Type

    def __ge__(self, other):
        return (
            isinstance(other, FunctionType)
            and all(a >= oa for a, oa in zip(self.argtyps, other.argtyps))
            and other.rettyp >= self.rettyp
        )

Ancestors

Class variables

var argtyps : List[Type]
var rettypType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class InaccessibleType

A type that blocks overwriting of a function

Expand source code
class InaccessibleType(ClassType):
    """A type that blocks overwriting of a function"""

    pass

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class InstanceType (typ: ClassType)

InstanceType(typ: hebi.typed_ast.ClassType)

Expand source code
class InstanceType(Type):
    typ: ClassType

    def constr_type(self) -> FunctionType:
        raise TypeInferenceError(f"Can not construct an instance {self}")

    def constr(self) -> plt.AST:
        raise NotImplementedError(f"Can not construct an instance {self}")

    def attribute_type(self, attr) -> Type:
        return self.typ.attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        return self.typ.attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        if isinstance(o, InstanceType):
            return self.typ.cmp(op, o.typ)
        return super().cmp(op, o)

    def __ge__(self, other):
        return isinstance(other, InstanceType) and self.typ >= other.typ

Ancestors

Subclasses

Class variables

var typClassType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr) -> plt.AST:
    return self.typ.attribute(attr)
def attribute_type(self, attr) ‑> Type

Inherited from: Type.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> Type:
    return self.typ.attribute_type(attr)
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
    if isinstance(o, InstanceType):
        return self.typ.cmp(op, o.typ)
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: Type.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    raise NotImplementedError(f"Can not construct an instance {self}")
def constr_type(self) ‑> FunctionType

Inherited from: Type.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> FunctionType:
    raise TypeInferenceError(f"Can not construct an instance {self}")
class IntegerType

IntegerType()

Expand source code
class IntegerType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(FunctionType([StringInstanceType], InstanceType(self)))

    def constr(self) -> plt.AST:
        # TODO we need to strip the string implicitely before parsing it
        return plt.Lambda(
            ["_", "x"],
            plt.Let(
                [
                    ("e", plt.EncodeUtf8(plt.Var("x"))),
                    ("first_int", plt.IndexByteString(plt.Var("e"), plt.Integer(0))),
                    ("len", plt.LengthOfByteString(plt.Var("e"))),
                    (
                        "fold_start",
                        plt.Lambda(
                            ["start"],
                            plt.FoldList(
                                plt.Range(plt.Var("len"), plt.Var("start")),
                                plt.Lambda(
                                    ["s", "i"],
                                    plt.Let(
                                        [
                                            (
                                                "b",
                                                plt.IndexByteString(
                                                    plt.Var("e"), plt.Var("i")
                                                ),
                                            )
                                        ],
                                        plt.Ite(
                                            plt.EqualsInteger(
                                                plt.Var("b"), plt.Integer(ord("_"))
                                            ),
                                            plt.Var("s"),
                                            plt.Ite(
                                                plt.Or(
                                                    plt.LessThanInteger(
                                                        plt.Var("b"),
                                                        plt.Integer(ord("0")),
                                                    ),
                                                    plt.LessThanInteger(
                                                        plt.Integer(ord("9")),
                                                        plt.Var("b"),
                                                    ),
                                                ),
                                                plt.TraceError(
                                                    "ValueError: invalid literal for int() with base 10"
                                                ),
                                                plt.AddInteger(
                                                    plt.SubtractInteger(
                                                        plt.Var("b"),
                                                        plt.Integer(ord("0")),
                                                    ),
                                                    plt.MultiplyInteger(
                                                        plt.Var("s"), plt.Integer(10)
                                                    ),
                                                ),
                                            ),
                                        ),
                                    ),
                                ),
                                plt.Integer(0),
                            ),
                        ),
                    ),
                ],
                plt.Ite(
                    plt.Or(
                        plt.EqualsInteger(plt.Var("len"), plt.Integer(0)),
                        plt.EqualsInteger(
                            plt.Var("first_int"),
                            plt.Integer(ord("_")),
                        ),
                    ),
                    plt.TraceError(
                        "ValueError: invalid literal for int() with base 10"
                    ),
                    plt.Ite(
                        plt.EqualsInteger(
                            plt.Var("first_int"),
                            plt.Integer(ord("-")),
                        ),
                        plt.Negate(
                            plt.Apply(plt.Var("fold_start"), plt.Integer(1)),
                        ),
                        plt.Apply(plt.Var("fold_start"), plt.Integer(0)),
                    ),
                ),
            ),
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        if isinstance(o, BoolType):
            if isinstance(op, Eq):
                # 1 == True
                # 0 == False
                # all other comparisons are False
                return plt.Lambda(
                    ["x", "y"],
                    plt.Ite(
                        plt.Var("y"),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                    ),
                )
        if isinstance(o, IntegerType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsInteger)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsInteger),
                            plt.Var("y"),
                            plt.Var("x"),
                        )
                    ),
                )
            if isinstance(op, LtE):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger)
            if isinstance(op, Lt):
                return plt.BuiltIn(uplc.BuiltInFun.LessThanInteger)
            if isinstance(op, Gt):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanInteger),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
            if isinstance(op, GtE):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger),
                        plt.Var("y"),
                        plt.Var("x"),
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and isinstance(o.typ.typ, IntegerType)
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsInteger(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsInteger), plt.Var("x")
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.AddInteger(plt.Var("x"), plt.Integer(1)),
                        ),
                    ),
                )
        return super().cmp(op, o)

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: AtomicType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
    if isinstance(o, BoolType):
        if isinstance(op, Eq):
            # 1 == True
            # 0 == False
            # all other comparisons are False
            return plt.Lambda(
                ["x", "y"],
                plt.Ite(
                    plt.Var("y"),
                    plt.EqualsInteger(plt.Var("x"), plt.Integer(1)),
                    plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                ),
            )
    if isinstance(o, IntegerType):
        if isinstance(op, Eq):
            return plt.BuiltIn(uplc.BuiltInFun.EqualsInteger)
        if isinstance(op, NotEq):
            return plt.Lambda(
                ["x", "y"],
                plt.Not(
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.EqualsInteger),
                        plt.Var("y"),
                        plt.Var("x"),
                    )
                ),
            )
        if isinstance(op, LtE):
            return plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger)
        if isinstance(op, Lt):
            return plt.BuiltIn(uplc.BuiltInFun.LessThanInteger)
        if isinstance(op, Gt):
            return plt.Lambda(
                ["x", "y"],
                plt.Apply(
                    plt.BuiltIn(uplc.BuiltInFun.LessThanInteger),
                    plt.Var("y"),
                    plt.Var("x"),
                ),
            )
        if isinstance(op, GtE):
            return plt.Lambda(
                ["x", "y"],
                plt.Apply(
                    plt.BuiltIn(uplc.BuiltInFun.LessThanEqualsInteger),
                    plt.Var("y"),
                    plt.Var("x"),
                ),
            )
    if (
        isinstance(o, ListType)
        and isinstance(o.typ, InstanceType)
        and isinstance(o.typ.typ, IntegerType)
    ):
        if isinstance(op, In):
            return plt.Lambda(
                ["x", "y"],
                plt.EqualsInteger(
                    plt.Var("x"),
                    plt.FindList(
                        plt.Var("y"),
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsInteger), plt.Var("x")
                        ),
                        # this simply ensures the default is always unequal to the searched value
                        plt.AddInteger(plt.Var("x"), plt.Integer(1)),
                    ),
                ),
            )
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    # TODO we need to strip the string implicitely before parsing it
    return plt.Lambda(
        ["_", "x"],
        plt.Let(
            [
                ("e", plt.EncodeUtf8(plt.Var("x"))),
                ("first_int", plt.IndexByteString(plt.Var("e"), plt.Integer(0))),
                ("len", plt.LengthOfByteString(plt.Var("e"))),
                (
                    "fold_start",
                    plt.Lambda(
                        ["start"],
                        plt.FoldList(
                            plt.Range(plt.Var("len"), plt.Var("start")),
                            plt.Lambda(
                                ["s", "i"],
                                plt.Let(
                                    [
                                        (
                                            "b",
                                            plt.IndexByteString(
                                                plt.Var("e"), plt.Var("i")
                                            ),
                                        )
                                    ],
                                    plt.Ite(
                                        plt.EqualsInteger(
                                            plt.Var("b"), plt.Integer(ord("_"))
                                        ),
                                        plt.Var("s"),
                                        plt.Ite(
                                            plt.Or(
                                                plt.LessThanInteger(
                                                    plt.Var("b"),
                                                    plt.Integer(ord("0")),
                                                ),
                                                plt.LessThanInteger(
                                                    plt.Integer(ord("9")),
                                                    plt.Var("b"),
                                                ),
                                            ),
                                            plt.TraceError(
                                                "ValueError: invalid literal for int() with base 10"
                                            ),
                                            plt.AddInteger(
                                                plt.SubtractInteger(
                                                    plt.Var("b"),
                                                    plt.Integer(ord("0")),
                                                ),
                                                plt.MultiplyInteger(
                                                    plt.Var("s"), plt.Integer(10)
                                                ),
                                            ),
                                        ),
                                    ),
                                ),
                            ),
                            plt.Integer(0),
                        ),
                    ),
                ),
            ],
            plt.Ite(
                plt.Or(
                    plt.EqualsInteger(plt.Var("len"), plt.Integer(0)),
                    plt.EqualsInteger(
                        plt.Var("first_int"),
                        plt.Integer(ord("_")),
                    ),
                ),
                plt.TraceError(
                    "ValueError: invalid literal for int() with base 10"
                ),
                plt.Ite(
                    plt.EqualsInteger(
                        plt.Var("first_int"),
                        plt.Integer(ord("-")),
                    ),
                    plt.Negate(
                        plt.Apply(plt.Var("fold_start"), plt.Integer(1)),
                    ),
                    plt.Apply(plt.Var("fold_start"), plt.Integer(0)),
                ),
            ),
        ),
    )
def constr_type(self) ‑> InstanceType

Inherited from: AtomicType.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> InstanceType:
    return InstanceType(FunctionType([StringInstanceType], InstanceType(self)))
class ListType (typ: Type)

ListType(typ: hebi.typed_ast.Type)

Expand source code
class ListType(ClassType):
    typ: Type

    def __ge__(self, other):
        return isinstance(other, ListType) and self.typ >= other.typ

Ancestors

Class variables

var typType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class PairType (l_typ: Type, r_typ: Type)

An internal type representing built-in PlutusData pairs

Expand source code
class PairType(ClassType):
    """An internal type representing built-in PlutusData pairs"""

    l_typ: Type
    r_typ: Type

    def __ge__(self, other):
        return isinstance(other, PairType) and all(
            t >= ot
            for t, ot in zip((self.l_typ, self.r_typ), (other.l_typ, other.r_typ))
        )

Ancestors

Class variables

var l_typType
var r_typType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class PolymorphicFunction
Expand source code
class PolymorphicFunction:
    def type_from_args(self, args: typing.List[Type]) -> FunctionType:
        raise NotImplementedError()

    def impl_from_args(self, args: typing.List[Type]) -> plt.AST:
        raise NotImplementedError()

Subclasses

Methods

def impl_from_args(self, args: List[Type]) ‑> pluthon.pluthon_ast.AST
Expand source code
def impl_from_args(self, args: typing.List[Type]) -> plt.AST:
    raise NotImplementedError()
def type_from_args(self, args: List[Type]) ‑> FunctionType
Expand source code
def type_from_args(self, args: typing.List[Type]) -> FunctionType:
    raise NotImplementedError()
class PolymorphicFunctionInstanceType (typ: FunctionType, polymorphic_function: PolymorphicFunction)

PolymorphicFunctionInstanceType(typ: hebi.typed_ast.FunctionType, polymorphic_function: hebi.typed_ast.PolymorphicFunction)

Expand source code
class PolymorphicFunctionInstanceType(InstanceType):
    typ: FunctionType
    polymorphic_function: PolymorphicFunction

Ancestors

Class variables

var polymorphic_functionPolymorphicFunction
var typFunctionType

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: InstanceType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: InstanceType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: InstanceType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: InstanceType.constr

The constructor for this class

def constr_type(self) ‑> FunctionType

Inherited from: InstanceType.constr_type

The type of the constructor for this class

class PolymorphicFunctionType (polymorphic_function: PolymorphicFunction)

A special type of builtin that may act differently on different parameters

Expand source code
class PolymorphicFunctionType(ClassType):
    """A special type of builtin that may act differently on different parameters"""

    polymorphic_function: PolymorphicFunction

Ancestors

Class variables

var polymorphic_functionPolymorphicFunction

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class RawPlutoExpr (*args, **kwargs)
Expand source code
class RawPlutoExpr(typedexpr):
    typ: Type
    expr: plt.AST

Ancestors

Class variables

var expr : pluthon.pluthon_ast.AST
var typType
class Record (name: str, constructor: int, fields: Union[List[Tuple[str, Type]], frozenlist._frozenlist.FrozenList])

Record(name: str, constructor: int, fields: Union[List[Tuple[str, hebi.typed_ast.Type]], frozenlist._frozenlist.FrozenList])

Expand source code
class Record:
    name: str
    constructor: int
    fields: typing.Union[typing.List[typing.Tuple[str, Type]], FrozenList]

Class variables

var constructor : int
var fields : Union[List[Tuple[str, Type]], frozenlist._frozenlist.FrozenList]
var name : str
class RecordType (record: Record)

RecordType(record: hebi.typed_ast.Record)

Expand source code
class RecordType(ClassType):
    record: Record

    def constr_type(self) -> "InstanceType":
        return InstanceType(
            FunctionType([f[1] for f in self.record.fields], InstanceType(self))
        )

    def constr(self) -> plt.AST:
        # wrap all constructor values to PlutusData
        build_constr_params = plt.EmptyDataList()
        for n, t in reversed(self.record.fields):
            build_constr_params = plt.MkCons(
                transform_output_map(t)(plt.Var(n)), build_constr_params
            )
        # then build a constr type with this PlutusData
        return plt.Lambda(
            ["_"] + [n for n, _ in self.record.fields],
            plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
        )

    def attribute_type(self, attr: str) -> Type:
        """The types of the named attributes of this class"""
        if attr == "CONSTR_ID":
            return IntegerInstanceType
        for n, t in self.record.fields:
            if n == attr:
                return t
        raise TypeInferenceError(
            f"Type {self.record.name} does not have attribute {attr}"
        )

    def attribute(self, attr: str) -> plt.AST:
        """The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
        if attr == "CONSTR_ID":
            # access to constructor
            return plt.Lambda(
                ["self"],
                plt.Constructor(plt.Var("self")),
            )
        attr_typ = self.attribute_type(attr)
        pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
        # access to normal fields
        return plt.Lambda(
            ["self"],
            transform_ext_params_map(attr_typ)(
                plt.NthField(
                    plt.Var("self"),
                    plt.Integer(pos),
                ),
            ),
        )

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        # this will reject comparisons that will always be false - most likely due to faults during programming
        if (isinstance(o, RecordType) and o.record == self.record) or (
            isinstance(o, UnionType) and self in o.typs
        ):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                            plt.Var("x"),
                            plt.Var("y"),
                        )
                    ),
                )
        if (
            isinstance(o, ListType)
            and isinstance(o.typ, InstanceType)
            and o.typ.typ >= self
        ):
            if isinstance(op, In):
                return plt.Lambda(
                    ["x", "y"],
                    plt.EqualsData(
                        plt.Var("x"),
                        plt.FindList(
                            plt.Var("y"),
                            plt.Apply(
                                plt.BuiltIn(uplc.BuiltInFun.EqualsData), plt.Var("x")
                            ),
                            # this simply ensures the default is always unequal to the searched value
                            plt.ConstrData(
                                plt.AddInteger(
                                    plt.Constructor(plt.Var("x")), plt.Integer(1)
                                ),
                                plt.MkNilData(plt.Unit()),
                            ),
                        ),
                    ),
                )
        return super().cmp(op, o)

    def __ge__(self, other):
        # Can only substitute for its own type, records need to be equal
        # if someone wants to be funny, they can implement <= to be true if all fields match up to some point
        return isinstance(other, self.__class__) and other.record == self.record

Ancestors

Class variables

var recordRecord

Methods

def attribute(self, attr: str) ‑> pluthon.pluthon_ast.AST

The attributes of this class. Need to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr: str) -> plt.AST:
    """The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
    if attr == "CONSTR_ID":
        # access to constructor
        return plt.Lambda(
            ["self"],
            plt.Constructor(plt.Var("self")),
        )
    attr_typ = self.attribute_type(attr)
    pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
    # access to normal fields
    return plt.Lambda(
        ["self"],
        transform_ext_params_map(attr_typ)(
            plt.NthField(
                plt.Var("self"),
                plt.Integer(pos),
            ),
        ),
    )
def attribute_type(self, attr: str) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr: str) -> Type:
    """The types of the named attributes of this class"""
    if attr == "CONSTR_ID":
        return IntegerInstanceType
    for n, t in self.record.fields:
        if n == attr:
            return t
    raise TypeInferenceError(
        f"Type {self.record.name} does not have attribute {attr}"
    )
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
    # this will reject comparisons that will always be false - most likely due to faults during programming
    if (isinstance(o, RecordType) and o.record == self.record) or (
        isinstance(o, UnionType) and self in o.typs
    ):
        if isinstance(op, Eq):
            return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
        if isinstance(op, NotEq):
            return plt.Lambda(
                ["x", "y"],
                plt.Not(
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                        plt.Var("x"),
                        plt.Var("y"),
                    )
                ),
            )
    if (
        isinstance(o, ListType)
        and isinstance(o.typ, InstanceType)
        and o.typ.typ >= self
    ):
        if isinstance(op, In):
            return plt.Lambda(
                ["x", "y"],
                plt.EqualsData(
                    plt.Var("x"),
                    plt.FindList(
                        plt.Var("y"),
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsData), plt.Var("x")
                        ),
                        # this simply ensures the default is always unequal to the searched value
                        plt.ConstrData(
                            plt.AddInteger(
                                plt.Constructor(plt.Var("x")), plt.Integer(1)
                            ),
                            plt.MkNilData(plt.Unit()),
                        ),
                    ),
                ),
            )
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    # wrap all constructor values to PlutusData
    build_constr_params = plt.EmptyDataList()
    for n, t in reversed(self.record.fields):
        build_constr_params = plt.MkCons(
            transform_output_map(t)(plt.Var(n)), build_constr_params
        )
    # then build a constr type with this PlutusData
    return plt.Lambda(
        ["_"] + [n for n, _ in self.record.fields],
        plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
    )
def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> "InstanceType":
    return InstanceType(
        FunctionType([f[1] for f in self.record.fields], InstanceType(self))
    )
class StringType

StringType()

Expand source code
class StringType(AtomicType):
    def constr_type(self) -> InstanceType:
        return InstanceType(FunctionType([IntegerInstanceType], InstanceType(self)))

    def constr(self) -> plt.AST:
        # constructs a string representation of an integer
        return plt.Lambda(
            ["_", "x"],
            plt.DecodeUtf8(
                plt.Let(
                    [
                        (
                            "strlist",
                            plt.RecFun(
                                plt.Lambda(
                                    ["f", "i"],
                                    plt.Ite(
                                        plt.LessThanEqualsInteger(
                                            plt.Var("i"), plt.Integer(0)
                                        ),
                                        plt.EmptyIntegerList(),
                                        plt.MkCons(
                                            plt.AddInteger(
                                                plt.ModInteger(
                                                    plt.Var("i"), plt.Integer(10)
                                                ),
                                                plt.Integer(ord("0")),
                                            ),
                                            plt.Apply(
                                                plt.Var("f"),
                                                plt.Var("f"),
                                                plt.DivideInteger(
                                                    plt.Var("i"), plt.Integer(10)
                                                ),
                                            ),
                                        ),
                                    ),
                                ),
                            ),
                        ),
                        (
                            "mkstr",
                            plt.Lambda(
                                ["i"],
                                plt.FoldList(
                                    plt.Apply(plt.Var("strlist"), plt.Var("i")),
                                    plt.Lambda(
                                        ["b", "i"],
                                        plt.ConsByteString(plt.Var("i"), plt.Var("b")),
                                    ),
                                    plt.ByteString(b""),
                                ),
                            ),
                        ),
                    ],
                    plt.Ite(
                        plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                        plt.ByteString(b"0"),
                        plt.Ite(
                            plt.LessThanInteger(plt.Var("x"), plt.Integer(0)),
                            plt.ConsByteString(
                                plt.Integer(ord("-")),
                                plt.Apply(plt.Var("mkstr"), plt.Negate(plt.Var("x"))),
                            ),
                            plt.Apply(plt.Var("mkstr"), plt.Var("x")),
                        ),
                    ),
                )
            ),
        )

    def attribute_type(self, attr) -> Type:
        if attr == "encode":
            return InstanceType(FunctionType([], ByteStringInstanceType))
        return super().attribute_type(attr)

    def attribute(self, attr) -> plt.AST:
        if attr == "encode":
            # No codec -> only the default (utf8) is allowed
            return plt.Lambda(["x", "_"], plt.EncodeUtf8(plt.Var("x")))
        return super().attribute(attr)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, StringType):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsString)
        return super().cmp(op, o)

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr) -> plt.AST:
    if attr == "encode":
        # No codec -> only the default (utf8) is allowed
        return plt.Lambda(["x", "_"], plt.EncodeUtf8(plt.Var("x")))
    return super().attribute(attr)
def attribute_type(self, attr) ‑> Type

Inherited from: AtomicType.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> Type:
    if attr == "encode":
        return InstanceType(FunctionType([], ByteStringInstanceType))
    return super().attribute_type(attr)
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    if isinstance(o, StringType):
        if isinstance(op, Eq):
            return plt.BuiltIn(uplc.BuiltInFun.EqualsString)
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.constr

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    # constructs a string representation of an integer
    return plt.Lambda(
        ["_", "x"],
        plt.DecodeUtf8(
            plt.Let(
                [
                    (
                        "strlist",
                        plt.RecFun(
                            plt.Lambda(
                                ["f", "i"],
                                plt.Ite(
                                    plt.LessThanEqualsInteger(
                                        plt.Var("i"), plt.Integer(0)
                                    ),
                                    plt.EmptyIntegerList(),
                                    plt.MkCons(
                                        plt.AddInteger(
                                            plt.ModInteger(
                                                plt.Var("i"), plt.Integer(10)
                                            ),
                                            plt.Integer(ord("0")),
                                        ),
                                        plt.Apply(
                                            plt.Var("f"),
                                            plt.Var("f"),
                                            plt.DivideInteger(
                                                plt.Var("i"), plt.Integer(10)
                                            ),
                                        ),
                                    ),
                                ),
                            ),
                        ),
                    ),
                    (
                        "mkstr",
                        plt.Lambda(
                            ["i"],
                            plt.FoldList(
                                plt.Apply(plt.Var("strlist"), plt.Var("i")),
                                plt.Lambda(
                                    ["b", "i"],
                                    plt.ConsByteString(plt.Var("i"), plt.Var("b")),
                                ),
                                plt.ByteString(b""),
                            ),
                        ),
                    ),
                ],
                plt.Ite(
                    plt.EqualsInteger(plt.Var("x"), plt.Integer(0)),
                    plt.ByteString(b"0"),
                    plt.Ite(
                        plt.LessThanInteger(plt.Var("x"), plt.Integer(0)),
                        plt.ConsByteString(
                            plt.Integer(ord("-")),
                            plt.Apply(plt.Var("mkstr"), plt.Negate(plt.Var("x"))),
                        ),
                        plt.Apply(plt.Var("mkstr"), plt.Var("x")),
                    ),
                ),
            )
        ),
    )
def constr_type(self) ‑> InstanceType

Inherited from: AtomicType.constr_type

The type of the constructor for this class

Expand source code
def constr_type(self) -> InstanceType:
    return InstanceType(FunctionType([IntegerInstanceType], InstanceType(self)))
class TupleType (typs: List[Type])

TupleType(typs: List[hebi.typed_ast.Type])

Expand source code
class TupleType(ClassType):
    typs: typing.List[Type]

    def __ge__(self, other):
        return isinstance(other, TupleType) and all(
            t >= ot for t, ot in zip(self.typs, other.typs)
        )

Ancestors

Class variables

var typs : List[Type]

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class Type
Expand source code
class Type:
    def constr_type(self) -> "InstanceType":
        """The type of the constructor for this class"""
        raise TypeInferenceError(
            f"Object of type {self.__class__} does not have a constructor"
        )

    def constr(self) -> plt.AST:
        """The constructor for this class"""
        raise NotImplementedError(f"Constructor of {self.__class__} not implemented")

    def attribute_type(self, attr) -> "Type":
        """The types of the named attributes of this class"""
        raise TypeInferenceError(
            f"Object of type {self.__class__} does not have attribute {attr}"
        )

    def attribute(self, attr) -> plt.AST:
        """The attributes of this class. Needs to be a lambda that expects as first argument the object itself"""
        raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        raise NotImplementedError(
            f"Comparison {type(op).__name__} for {self.__class__.__name__} and {o.__class__.__name__} is not implemented. This is likely intended because it would always evaluate to False."
        )

Subclasses

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr) -> plt.AST:
    """The attributes of this class. Needs to be a lambda that expects as first argument the object itself"""
    raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")
def attribute_type(self, attr) ‑> Type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> "Type":
    """The types of the named attributes of this class"""
    raise TypeInferenceError(
        f"Object of type {self.__class__} does not have attribute {attr}"
    )
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison.

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
    raise NotImplementedError(
        f"Comparison {type(op).__name__} for {self.__class__.__name__} and {o.__class__.__name__} is not implemented. This is likely intended because it would always evaluate to False."
    )
def constr(self) ‑> pluthon.pluthon_ast.AST

The constructor for this class

Expand source code
def constr(self) -> plt.AST:
    """The constructor for this class"""
    raise NotImplementedError(f"Constructor of {self.__class__} not implemented")
def constr_type(self) ‑> InstanceType

The type of the constructor for this class

Expand source code
def constr_type(self) -> "InstanceType":
    """The type of the constructor for this class"""
    raise TypeInferenceError(
        f"Object of type {self.__class__} does not have a constructor"
    )
class TypeInferenceError (*args, **kwargs)

Assertion failed.

Expand source code
class TypeInferenceError(AssertionError):
    pass

Ancestors

  • builtins.AssertionError
  • builtins.Exception
  • builtins.BaseException
class TypedAST (*args, **kwargs)
Expand source code
class TypedAST(AST):
    typ: Type

Ancestors

  • _ast.AST

Subclasses

Class variables

var typType
class TypedAnnAssign (*args, **kwargs)
Expand source code
class TypedAnnAssign(typedstmt, AnnAssign):
    target: typedexpr
    annotation: Type
    value: typedexpr

Ancestors

Class variables

var annotationType
var targettypedexpr
var valuetypedexpr
class TypedAssert (*args, **kwargs)
Expand source code
class TypedAssert(typedstmt, Assert):
    test: typedexpr
    msg: typedexpr

Ancestors

Class variables

var msgtypedexpr
var testtypedexpr
class TypedAssign (*args, **kwargs)
Expand source code
class TypedAssign(typedstmt, Assign):
    targets: typing.List[typedexpr]
    value: typedexpr

Ancestors

Class variables

var targets : List[typedexpr]
var valuetypedexpr
class TypedAttribute (*args, **kwargs)
Expand source code
class TypedAttribute(typedexpr, Attribute):
    value: typedexpr
    pos: int

Ancestors

Class variables

var pos : int
var valuetypedexpr
class TypedBinOp (*args, **kwargs)
Expand source code
class TypedBinOp(typedexpr, BinOp):
    left: typedexpr
    right: typedexpr

Ancestors

Class variables

var lefttypedexpr
var righttypedexpr
class TypedBoolOp (*args, **kwargs)
Expand source code
class TypedBoolOp(typedexpr, BoolOp):
    values: typing.List[typedexpr]

Ancestors

Class variables

var values : List[typedexpr]
class TypedCall (*args, **kwargs)
Expand source code
class TypedCall(typedexpr, Call):
    func: typedexpr
    args: typing.List[typedexpr]

Ancestors

Class variables

var args : List[typedexpr]
var functypedexpr
class TypedClassDef (*args, **kwargs)
Expand source code
class TypedClassDef(typedstmt, ClassDef):
    class_typ: Type

Ancestors

Class variables

var class_typType
class TypedCompare (*args, **kwargs)
Expand source code
class TypedCompare(typedexpr, Compare):
    left: typedexpr
    ops: typing.List[cmpop]
    comparators: typing.List[typedexpr]

Ancestors

Class variables

var comparators : List[typedexpr]
var lefttypedexpr
var ops : List[_ast.cmpop]
class TypedConstant (*args, **kwargs)
Expand source code
class TypedConstant(TypedAST, Constant):
    pass

Ancestors

  • TypedAST
  • _ast.Constant
  • _ast.expr
  • _ast.AST

Class variables

var typType
class TypedDict (*args, **kwargs)
Expand source code
class TypedDict(typedexpr, Dict):
    pass

Ancestors

Class variables

var typType
class TypedExpr (*args, **kwargs)
Expand source code
class TypedExpr(typedstmt, Expr):
    value: typedexpr

Ancestors

Class variables

var valuetypedexpr
class TypedExpression (*args, **kwargs)
Expand source code
class TypedExpression(typedexpr, Expression):
    body: typedexpr

Ancestors

Class variables

var bodytypedexpr
class TypedFor (*args, **kwargs)
Expand source code
class TypedFor(typedstmt, For):
    target: typedexpr
    iter: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]

Ancestors

Class variables

var body : List[typedstmt]
var itertypedexpr
var orelse : List[typedstmt]
var targettypedexpr
class TypedFunctionDef (*args, **kwargs)
Expand source code
class TypedFunctionDef(typedstmt, FunctionDef):
    body: typing.List[typedstmt]
    args: arguments

Ancestors

Class variables

var args : _ast.arguments
var body : List[typedstmt]
class TypedIf (*args, **kwargs)
Expand source code
class TypedIf(typedstmt, If):
    test: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]

Ancestors

Class variables

var body : List[typedstmt]
var orelse : List[typedstmt]
var testtypedexpr
class TypedIfExp (*args, **kwargs)
Expand source code
class TypedIfExp(typedstmt, IfExp):
    test: typedexpr
    body: typedexpr
    orelse: typedexpr

Ancestors

Class variables

var bodytypedexpr
var orelsetypedexpr
var testtypedexpr
class TypedList (*args, **kwargs)
Expand source code
class TypedList(typedexpr, List):
    pass

Ancestors

Class variables

var typType
class TypedListComp (*args, **kwargs)
Expand source code
class TypedListComp(typedexpr, ListComp):
    generators: typing.List[typedcomprehension]
    elt: typedexpr

Ancestors

Class variables

var elttypedexpr
var generators : List[typedcomprehension]
class TypedModule (*args, **kwargs)
Expand source code
class TypedModule(typedstmt, Module):
    body: typing.List[typedstmt]

Ancestors

Class variables

var body : List[typedstmt]
class TypedName (*args, **kwargs)
Expand source code
class TypedName(typedexpr, Name):
    pass

Ancestors

Class variables

var typType
class TypedNodeTransformer

A :class:NodeVisitor subclass that walks the abstract syntax tree and allows modification of nodes.

The NodeTransformer will walk the AST and use the return value of the visitor methods to replace or remove the old node. If the return value of the visitor method is None, the node will be removed from its location, otherwise it is replaced with the return value. The return value may be the original node in which case no replacement takes place.

Here is an example transformer that rewrites all occurrences of name lookups (foo) to data['foo']::

class RewriteName(NodeTransformer):

   def visit_Name(self, node):
       return Subscript(
           value=Name(id='data', ctx=Load()),
           slice=Index(value=Str(s=node.id)),
           ctx=node.ctx
       )

Keep in mind that if the node you're operating on has child nodes you must either transform the child nodes yourself or call the :meth:generic_visit method for the node first.

For nodes that were part of a collection of statements (that applies to all statement nodes), the visitor may also return a list of nodes rather than just a single node.

Usually you use the transformer like this::

node = YourTransformer().visit(node)

Expand source code
class TypedNodeTransformer(NodeTransformer):
    def visit(self, node):
        """Visit a node."""
        node_class_name = node.__class__.__name__
        if node_class_name.startswith("Typed"):
            node_class_name = node_class_name[len("Typed") :]
        method = "visit_" + node_class_name
        visitor = getattr(self, method, self.generic_visit)
        return visitor(node)

Ancestors

  • ast.NodeTransformer
  • ast.NodeVisitor

Subclasses

Methods

def visit(self, node)

Visit a node.

Expand source code
def visit(self, node):
    """Visit a node."""
    node_class_name = node.__class__.__name__
    if node_class_name.startswith("Typed"):
        node_class_name = node_class_name[len("Typed") :]
    method = "visit_" + node_class_name
    visitor = getattr(self, method, self.generic_visit)
    return visitor(node)
class TypedNodeVisitor

A node visitor base class that walks the abstract syntax tree and calls a visitor function for every node found. This function may return a value which is forwarded by the visit method.

This class is meant to be subclassed, with the subclass adding visitor methods.

Per default the visitor functions for the nodes are 'visit_' + class name of the node. So a TryFinally node visit function would be visit_TryFinally. This behavior can be changed by overriding the visit method. If no visitor function exists for a node (return value None) the generic_visit visitor is used instead.

Don't use the NodeVisitor if you want to apply changes to nodes during traversing. For this a special visitor exists (NodeTransformer) that allows modifications.

Expand source code
class TypedNodeVisitor(NodeVisitor):
    def visit(self, node):
        """Visit a node."""
        node_class_name = node.__class__.__name__
        if node_class_name.startswith("Typed"):
            node_class_name = node_class_name[len("Typed") :]
        method = "visit_" + node_class_name
        visitor = getattr(self, method, self.generic_visit)
        return visitor(node)

Ancestors

  • ast.NodeVisitor

Subclasses

Methods

def visit(self, node)

Visit a node.

Expand source code
def visit(self, node):
    """Visit a node."""
    node_class_name = node.__class__.__name__
    if node_class_name.startswith("Typed"):
        node_class_name = node_class_name[len("Typed") :]
    method = "visit_" + node_class_name
    visitor = getattr(self, method, self.generic_visit)
    return visitor(node)
class TypedPass (*args, **kwargs)
Expand source code
class TypedPass(typedstmt, Pass):
    pass

Ancestors

Class variables

var typType
class TypedReturn (*args, **kwargs)
Expand source code
class TypedReturn(typedstmt, Return):
    value: typedexpr

Ancestors

Class variables

var valuetypedexpr
class TypedSubscript (*args, **kwargs)
Expand source code
class TypedSubscript(typedexpr, Subscript):
    value: typedexpr

Ancestors

Class variables

var valuetypedexpr
class TypedTuple (*args, **kwargs)
Expand source code
class TypedTuple(typedexpr, Tuple):
    pass

Ancestors

Class variables

var typType
class TypedUnaryOp (*args, **kwargs)
Expand source code
class TypedUnaryOp(typedexpr, UnaryOp):
    operand: typedexpr

Ancestors

Class variables

var operandtypedexpr
class TypedWhile (*args, **kwargs)
Expand source code
class TypedWhile(typedstmt, While):
    test: typedexpr
    body: typing.List[typedstmt]
    orelse: typing.List[typedstmt]

Ancestors

Class variables

var body : List[typedstmt]
var orelse : List[typedstmt]
var testtypedexpr
class UnionType (typs: List[RecordType])

UnionType(typs: List[hebi.typed_ast.RecordType])

Expand source code
class UnionType(ClassType):
    typs: typing.List[RecordType]

    def attribute_type(self, attr) -> "Type":
        if attr == "CONSTR_ID":
            return IntegerInstanceType
        # iterate through all names/types of the unioned records by position
        for attr_names, attr_types in map(
            lambda x: zip(*x), zip(*(t.record.fields for t in self.typs))
        ):
            # need to have a common field with the same name, in the same position!
            if any(attr_name != attr for attr_name in attr_names):
                continue
            for at in attr_types:
                # return the maximum element if there is one
                if all(at >= at2 for at2 in attr_types):
                    return at
            # return the union type of all possible instantiations if all possible values are record types
            if all(
                isinstance(at, InstanceType) and isinstance(at.typ, RecordType)
                for at in attr_types
            ) and distinct([at.typ.record.constructor for at in attr_types]):
                return InstanceType(
                    UnionType(FrozenFrozenList([at.typ for at in attr_types]))
                )
            # return Anytype
            return InstanceType(AnyType())
        raise TypeInferenceError(
            f"Can not access attribute {attr} of Union type. Cast to desired type with an 'if isinstance(_, _):' branch."
        )

    def attribute(self, attr: str) -> plt.AST:
        if attr == "CONSTR_ID":
            # access to constructor
            return plt.Lambda(
                ["self"],
                plt.Constructor(plt.Var("self")),
            )
        # iterate through all names/types of the unioned records by position
        attr_typ = self.attribute_type(attr)
        pos = next(
            i
            for i, (ns, _) in enumerate(
                map(lambda x: zip(*x), zip(*(t.record.fields for t in self.typs)))
            )
            if all(n == attr for n in ns)
        )
        # access to normal fields
        return plt.Lambda(
            ["self"],
            transform_ext_params_map(attr_typ)(
                plt.NthField(
                    plt.Var("self"),
                    plt.Integer(pos),
                ),
            ),
        )

    def __ge__(self, other):
        if isinstance(other, UnionType):
            return all(any(t >= ot for ot in other.typs) for t in self.typs)
        return any(t >= other for t in self.typs)

    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
        # this will reject comparisons that will always be false - most likely due to faults during programming
        # note we require that there is an overlapt between the possible types for unions
        if (isinstance(o, RecordType) and o in self.typs) or (
            isinstance(o, UnionType) and set(self.typs).intersection(o.typs)
        ):
            if isinstance(op, Eq):
                return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
            if isinstance(op, NotEq):
                return plt.Lambda(
                    ["x", "y"],
                    plt.Not(
                        plt.Apply(
                            plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                            plt.Var("x"),
                            plt.Var("y"),
                        )
                    ),
                )
        raise NotImplementedError(
            f"Can not compare {o} and {self} with operation {op.__class__}. Note that comparisons that always return false are also rejected."
        )

Ancestors

Class variables

var typs : List[RecordType]

Methods

def attribute(self, attr: str) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

Expand source code
def attribute(self, attr: str) -> plt.AST:
    if attr == "CONSTR_ID":
        # access to constructor
        return plt.Lambda(
            ["self"],
            plt.Constructor(plt.Var("self")),
        )
    # iterate through all names/types of the unioned records by position
    attr_typ = self.attribute_type(attr)
    pos = next(
        i
        for i, (ns, _) in enumerate(
            map(lambda x: zip(*x), zip(*(t.record.fields for t in self.typs)))
        )
        if all(n == attr for n in ns)
    )
    # access to normal fields
    return plt.Lambda(
        ["self"],
        transform_ext_params_map(attr_typ)(
            plt.NthField(
                plt.Var("self"),
                plt.Integer(pos),
            ),
        ),
    )
def attribute_type(self, attr) ‑> Type

Inherited from: ClassType.attribute_type

The types of the named attributes of this class

Expand source code
def attribute_type(self, attr) -> "Type":
    if attr == "CONSTR_ID":
        return IntegerInstanceType
    # iterate through all names/types of the unioned records by position
    for attr_names, attr_types in map(
        lambda x: zip(*x), zip(*(t.record.fields for t in self.typs))
    ):
        # need to have a common field with the same name, in the same position!
        if any(attr_name != attr for attr_name in attr_names):
            continue
        for at in attr_types:
            # return the maximum element if there is one
            if all(at >= at2 for at2 in attr_types):
                return at
        # return the union type of all possible instantiations if all possible values are record types
        if all(
            isinstance(at, InstanceType) and isinstance(at.typ, RecordType)
            for at in attr_types
        ) and distinct([at.typ.record.constructor for at in attr_types]):
            return InstanceType(
                UnionType(FrozenFrozenList([at.typ for at in attr_types]))
            )
        # return Anytype
        return InstanceType(AnyType())
    raise TypeInferenceError(
        f"Can not access attribute {attr} of Union type. Cast to desired type with an 'if isinstance(_, _):' branch."
    )
def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    """The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second the comparison."""
    # this will reject comparisons that will always be false - most likely due to faults during programming
    # note we require that there is an overlapt between the possible types for unions
    if (isinstance(o, RecordType) and o in self.typs) or (
        isinstance(o, UnionType) and set(self.typs).intersection(o.typs)
    ):
        if isinstance(op, Eq):
            return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
        if isinstance(op, NotEq):
            return plt.Lambda(
                ["x", "y"],
                plt.Not(
                    plt.Apply(
                        plt.BuiltIn(uplc.BuiltInFun.EqualsData),
                        plt.Var("x"),
                        plt.Var("y"),
                    )
                ),
            )
    raise NotImplementedError(
        f"Can not compare {o} and {self} with operation {op.__class__}. Note that comparisons that always return false are also rejected."
    )
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: ClassType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: ClassType.constr_type

The type of the constructor for this class

class UnitType

UnitType()

Expand source code
class UnitType(AtomicType):
    def cmp(self, op: cmpop, o: "Type") -> plt.AST:
        if isinstance(o, UnitType):
            if isinstance(op, Eq):
                return plt.Lambda(["x", "y"], plt.Bool(True))
            if isinstance(op, NotEq):
                return plt.Lambda(["x", "y"], plt.Bool(False))
        return super().cmp(op, o)

Ancestors

Methods

def attribute(self, attr) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.attribute

The attributes of this class. Needs to be a lambda that expects as first argument the object itself

def attribute_type(self, attr) ‑> Type

Inherited from: AtomicType.attribute_type

The types of the named attributes of this class

def cmp(self, op: _ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.cmp

The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …

Expand source code
def cmp(self, op: cmpop, o: "Type") -> plt.AST:
    if isinstance(o, UnitType):
        if isinstance(op, Eq):
            return plt.Lambda(["x", "y"], plt.Bool(True))
        if isinstance(op, NotEq):
            return plt.Lambda(["x", "y"], plt.Bool(False))
    return super().cmp(op, o)
def constr(self) ‑> pluthon.pluthon_ast.AST

Inherited from: AtomicType.constr

The constructor for this class

def constr_type(self) ‑> InstanceType

Inherited from: AtomicType.constr_type

The type of the constructor for this class

class typedarg (*args, **kwargs)
Expand source code
class typedarg(TypedAST, arg):
    pass

Ancestors

Class variables

var typType
class typedarguments (*args, **kwargs)
Expand source code
class typedarguments(TypedAST, arguments):
    args: typing.List[typedarg]
    vararg: typing.Union[typedarg, None]
    kwonlyargs: typing.List[typedarg]
    kw_defaults: typing.List[typing.Union[typedexpr, None]]
    kwarg: typing.Union[typedarg, None]
    defaults: typing.List[typedexpr]

Ancestors

Class variables

var args : List[typedarg]
var defaults : List[typedexpr]
var kw_defaults : List[Optional[typedexpr]]
var kwarg : Optional[typedarg]
var kwonlyargs : List[typedarg]
var vararg : Optional[typedarg]
class typedcomprehension (*args, **kwargs)
Expand source code
class typedcomprehension(typedexpr, comprehension):
    target: typedexpr
    iter: typedexpr
    ifs: typing.List[typedexpr]

Ancestors

Class variables

var ifs : List[typedexpr]
var itertypedexpr
var targettypedexpr
class typedexpr (*args, **kwargs)
Expand source code
class typedexpr(TypedAST, expr):
    pass

Ancestors

Subclasses

Class variables

var typType
class typedstmt (*args, **kwargs)
Expand source code
class typedstmt(TypedAST, stmt):
    # Statements always have type None
    typ = NoneInstanceType

Ancestors

Subclasses

Class variables

var typType