diff --git a/docs/index.js b/docs/index.js index a11cdaa1..ca1f6220 100644 --- a/docs/index.js +++ b/docs/index.js @@ -2326,6 +2326,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_misc.MiscTest.test_id_map_equals_pycardano", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops", "url":9, "doc":"" @@ -4372,6 +4378,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.FunctionType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.TypeInferenceError", "url":24, "doc":"Assertion failed." @@ -4448,6 +4460,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.Type.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.Record", "url":24, "doc":"Record(name: str, orig_name: str, constructor: int, fields: Union[List[Tuple[str, opshin.types.Type , frozenlist2.frozenlist])" @@ -4544,11 +4562,23 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.ClassType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.AnyType", "url":24, "doc":"The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)" }, { +"ref":"opshin.types.AnyType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.AnyType.attribute_type", "url":24, "doc":"The types of the named attributes of this class", @@ -4686,6 +4716,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.AtomicType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.RecordType", "url":24, "doc":"RecordType(record: opshin.types.Record)" @@ -4696,6 +4732,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.RecordType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.RecordType.constr_type", "url":24, "doc":"The type of the constructor for this class", @@ -4772,6 +4814,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.UnionType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.UnionType.attribute_type", "url":24, "doc":"The types of the named attributes of this class", @@ -4914,6 +4962,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.TupleType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.PairType", "url":24, "doc":"An internal type representing built-in PlutusData pairs" @@ -4995,6 +5049,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.PairType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.ListType", "url":24, "doc":"ListType(typ: opshin.types.Type)" @@ -5005,6 +5065,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.ListType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.ListType.attribute_type", "url":24, "doc":"The types of the named attributes of this class", @@ -5086,6 +5152,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.DictType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.DictType.attribute_type", "url":24, "doc":"The types of the named attributes of this class", @@ -5162,6 +5234,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.InstanceType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.InstanceType.constr_type", "url":24, "doc":"The type of the constructor for this class", @@ -5233,6 +5311,12 @@ INDEX=[ "doc":"IntegerType()" }, { +"ref":"opshin.types.IntegerType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.IntegerType.constr_type", "url":24, "doc":"The type of the constructor for this class", @@ -5370,11 +5454,23 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.StringType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.ByteStringType", "url":24, "doc":"ByteStringType()" }, { +"ref":"opshin.types.ByteStringType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.ByteStringType.constr_type", "url":24, "doc":"The type of the constructor for this class", @@ -5512,6 +5608,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.BoolType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.UnitType", "url":24, "doc":"UnitType()" @@ -5583,6 +5685,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.UnitType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.InaccessibleType", "url":24, "doc":"A type that blocks overwriting of a function" @@ -5654,6 +5762,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.InaccessibleType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.repeated_addition", "url":24, "doc":"", @@ -5839,6 +5953,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.PolymorphicFunctionType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.PolymorphicFunctionInstanceType", "url":24, "doc":"PolymorphicFunctionInstanceType(typ: opshin.types.FunctionType, polymorphic_function: opshin.types.PolymorphicFunction)" @@ -5854,6 +5974,12 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.PolymorphicFunctionInstanceType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.types.PolymorphicFunctionInstanceType.constr_type", "url":24, "doc":"The type of the constructor for this class", @@ -7347,6 +7473,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.id_map", +"url":24, +"doc":"Returns a map from the constructor id to a descriptive typestring", +"func":1 +}, +{ "ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib", "url":48, "doc":"An enumeration." diff --git a/docs/opshin/ledger/api_v2.html b/docs/opshin/ledger/api_v2.html index f6af7493..76281421 100644 --- a/docs/opshin/ledger/api_v2.html +++ b/docs/opshin/ledger/api_v2.html @@ -592,7 +592,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -629,7 +629,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -662,7 +662,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -696,7 +696,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -733,7 +733,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -764,7 +764,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -791,7 +791,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -821,7 +821,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -859,7 +859,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -903,7 +903,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -936,7 +936,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -974,7 +974,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1015,7 +1015,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1050,7 +1050,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1081,7 +1081,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1112,7 +1112,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1145,7 +1145,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1180,7 +1180,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1219,7 +1219,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1255,7 +1255,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1288,7 +1288,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1326,7 +1326,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1370,7 +1370,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1407,7 +1407,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1444,7 +1444,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1481,7 +1481,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1518,7 +1518,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1557,7 +1557,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1596,7 +1596,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1633,7 +1633,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1680,7 +1680,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1728,7 +1728,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1765,7 +1765,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1804,7 +1804,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1858,7 +1858,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -1951,7 +1951,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -2002,7 +2002,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -2044,7 +2044,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
diff --git a/docs/opshin/prelude.html b/docs/opshin/prelude.html index ab932684..aebe67e9 100644 --- a/docs/opshin/prelude.html +++ b/docs/opshin/prelude.html @@ -468,7 +468,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -503,7 +503,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
@@ -537,7 +537,7 @@

Ancestors

Class variables

-
var CONSTR_ID : ClassVar[int]
+
var CONSTR_ID
diff --git a/docs/opshin/rewrite/rewrite_import_hashlib.html b/docs/opshin/rewrite/rewrite_import_hashlib.html index 06e752bb..5bc23953 100644 --- a/docs/opshin/rewrite/rewrite_import_hashlib.html +++ b/docs/opshin/rewrite/rewrite_import_hashlib.html @@ -309,6 +309,16 @@

Methods

Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

+
+def id_map(self, skip_constructor: bool = False) ‑> str +
+
+

+Inherited from: +ClassType.id_map +

+

Returns a map from the constructor id to a descriptive typestring

+
def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
@@ -582,6 +592,7 @@

constr
  • constr_type
  • copy_only_attributes
  • +
  • id_map
  • stringify
  • unop
  • unop_type
  • diff --git a/docs/opshin/std/fractions.html b/docs/opshin/std/fractions.html index 01978977..f65caf85 100644 --- a/docs/opshin/std/fractions.html +++ b/docs/opshin/std/fractions.html @@ -421,7 +421,7 @@

    Ancestors

    Class variables

    -
    var CONSTR_ID : ClassVar[int]
    +
    var CONSTR_ID
    diff --git a/docs/opshin/tests/test_misc.html b/docs/opshin/tests/test_misc.html index 48908f1e..1bac34cf 100644 --- a/docs/opshin/tests/test_misc.html +++ b/docs/opshin/tests/test_misc.html @@ -70,6 +70,7 @@

    Module opshin.tests.test_misc

    import os
     
    +import pycardano
     import sys
     
     import subprocess
    @@ -83,6 +84,7 @@ 

    Module opshin.tests.test_misc

    import hypothesis from hypothesis import given from hypothesis import strategies as st +from opshin import IndefiniteList from parameterized import parameterized from uplc import ast as uplc, eval as uplc_eval @@ -96,7 +98,7 @@

    Module opshin.tests.test_misc

    # these imports are required to eval the result of script context dumps from ..ledger.api_v2 import * -from pycardano import RawPlutusData +from pycardano import RawPlutusData, RawCBOR from cbor2 import CBORTag ALL_EXAMPLES = [ @@ -844,11 +846,7 @@

    Module opshin.tests.test_misc

    x = ( A(x) if isinstance(x, SomeOutputDatumHash) - else B(x) - if y == 1 - else C(0, x) - if y == 2 - else D(0, 0, x) + else B(x) if y == 1 else C(0, x) if y == 2 else D(0, 0, x) ) ret = eval_uplc(source_code, x) @@ -2965,7 +2963,7 @@

    Module opshin.tests.test_misc

    @dataclass class A(PlutusData): - CONSTR_ID = 15 + CONSTR_ID = 0 a: int b: bytes d: List[int] @@ -2993,7 +2991,63 @@

    Module opshin.tests.test_misc

    """ res = eval_uplc_value(source_code, Unit()) - self.assertEqual(15, res, "Invalid constr id")
    + self.assertEqual(15, res, "Invalid constr id") + + def test_id_map_equals_pycardano(self): + @dataclass + class A(PlutusData): + CONSTR_ID = 0 + a: int + b: bytes + d: List[int] + + @dataclass + class C(PlutusData): + z: Anything + + @dataclass + class B(PlutusData): + a: int + c: A + d: Dict[bytes, C] + e: Union[A, C] + + source_code = """ +from dataclasses import dataclass +from pycardano import Datum as Anything, PlutusData +from typing import Dict, List, Union + +@dataclass +class Nothing(PlutusData): + CONSTR_ID = 0 + + +@dataclass +class A(PlutusData): + CONSTR_ID = 0 + a: int + b: bytes + d: List[int] + +@dataclass +class C(PlutusData): + z: Anything + +@dataclass +class B(PlutusData): + a: int + c: A + d: Dict[bytes, C] + e: Union[A, C] + +def validator(_: None) -> int: + return B(1, A(1, b"", [1, 2]), {b"": C(Nothing())}, C(Nothing())).CONSTR_ID + """ + res = eval_uplc_value(source_code, Unit()) + + self.assertEqual( + B.CONSTR_ID, res, "Invalid constr id generation (does not match pycardano)" + )
    @@ -3047,7 +3101,7 @@

    Ancestors

    Class variables

    -
    var CONSTR_ID : ClassVar[int]
    +
    var CONSTR_ID
    @@ -3081,7 +3135,7 @@

    Ancestors

    Class variables

    -
    var CONSTR_ID : ClassVar[int]
    +
    var CONSTR_ID
    @@ -3845,11 +3899,7 @@

    Class variables

    x = ( A(x) if isinstance(x, SomeOutputDatumHash) - else B(x) - if y == 1 - else C(0, x) - if y == 2 - else D(0, 0, x) + else B(x) if y == 1 else C(0, x) if y == 2 else D(0, 0, x) ) ret = eval_uplc(source_code, x) @@ -5966,7 +6016,7 @@

    Class variables

    @dataclass class A(PlutusData): - CONSTR_ID = 15 + CONSTR_ID = 0 a: int b: bytes d: List[int] @@ -5994,7 +6044,63 @@

    Class variables

    """ res = eval_uplc_value(source_code, Unit()) - self.assertEqual(15, res, "Invalid constr id") + self.assertEqual(15, res, "Invalid constr id") + + def test_id_map_equals_pycardano(self): + @dataclass + class A(PlutusData): + CONSTR_ID = 0 + a: int + b: bytes + d: List[int] + + @dataclass + class C(PlutusData): + z: Anything + + @dataclass + class B(PlutusData): + a: int + c: A + d: Dict[bytes, C] + e: Union[A, C] + + source_code = """ +from dataclasses import dataclass +from pycardano import Datum as Anything, PlutusData +from typing import Dict, List, Union + +@dataclass +class Nothing(PlutusData): + CONSTR_ID = 0 + + +@dataclass +class A(PlutusData): + CONSTR_ID = 0 + a: int + b: bytes + d: List[int] + +@dataclass +class C(PlutusData): + z: Anything + +@dataclass +class B(PlutusData): + a: int + c: A + d: Dict[bytes, C] + e: Union[A, C] + +def validator(_: None) -> int: + return B(1, A(1, b"", [1, 2]), {b"": C(Nothing())}, C(Nothing())).CONSTR_ID + """ + res = eval_uplc_value(source_code, Unit()) + + self.assertEqual( + B.CONSTR_ID, res, "Invalid constr id generation (does not match pycardano)" + )

    Ancestors

      @@ -6299,7 +6405,7 @@

      Methods

      @dataclass class A(PlutusData): - CONSTR_ID = 15 + CONSTR_ID = 0 a: int b: bytes d: List[int] @@ -8220,6 +8326,72 @@

      Methods

      ret = eval_uplc(source_code, Unit()) +
      +def test_id_map_equals_pycardano(self) +
      +
      +
      +
      + +Expand source code + +
          def test_id_map_equals_pycardano(self):
      +        @dataclass
      +        class A(PlutusData):
      +            CONSTR_ID = 0
      +            a: int
      +            b: bytes
      +            d: List[int]
      +
      +        @dataclass
      +        class C(PlutusData):
      +            z: Anything
      +
      +        @dataclass
      +        class B(PlutusData):
      +            a: int
      +            c: A
      +            d: Dict[bytes, C]
      +            e: Union[A, C]
      +
      +        source_code = """
      +from dataclasses import dataclass
      +from pycardano import Datum as Anything, PlutusData
      +from typing import Dict, List, Union
      +
      +@dataclass
      +class Nothing(PlutusData):
      +    CONSTR_ID = 0
      +    
      +
      +@dataclass
      +class A(PlutusData):
      +    CONSTR_ID = 0
      +    a: int
      +    b: bytes
      +    d: List[int]
      +
      +@dataclass
      +class C(PlutusData):
      +    z: Anything
      +
      +@dataclass
      +class B(PlutusData):
      +    a: int
      +    c: A
      +    d: Dict[bytes, C]
      +    e: Union[A, C]
      +
      +def validator(_: None) -> int:
      +    return B(1, A(1, b"", [1, 2]), {b"": C(Nothing())}, C(Nothing())).CONSTR_ID
      +    """
      +        res = eval_uplc_value(source_code, Unit())
      +
      +        self.assertEqual(
      +            B.CONSTR_ID, res, "Invalid constr id generation (does not match pycardano)"
      +        )
      +
      +
      def test_if_no_retype_no_plutusdata(self)
      @@ -10644,11 +10816,7 @@

      Methods

      x = ( A(x) if isinstance(x, SomeOutputDatumHash) - else B(x) - if y == 1 - else C(0, x) - if y == 2 - else D(0, 0, x) + else B(x) if y == 1 else C(0, x) if y == 2 else D(0, 0, x) ) ret = eval_uplc(source_code, x) @@ -11289,6 +11457,7 @@

      test_gift_contract_fail
    • test_gift_contract_succeed
    • test_hello_world
    • +
    • test_id_map_equals_pycardano
    • test_if_no_retype_no_plutusdata
    • test_illegal_bind
    • test_illegal_function_retype
    • diff --git a/docs/opshin/tests/test_ops.html b/docs/opshin/tests/test_ops.html index 97556fb1..dcb7d890 100644 --- a/docs/opshin/tests/test_ops.html +++ b/docs/opshin/tests/test_ops.html @@ -902,6 +902,9 @@

      Module opshin.tests.test_ops

      @given(x=uplc_data) @example(PlutusByteString(b"")) @example(PlutusConstr(0, [PlutusByteString(b"'")])) + @example( + PlutusMap({PlutusInteger(1): PlutusMap({}), PlutusInteger(0): PlutusMap({})}) + ) def test_fmt_any(self, x): x_cbor = uplc.plutus_cbor_dumps(x) x_data = pycardano.RawPlutusData(cbor2.loads(x_cbor)) @@ -909,8 +912,8 @@

      Module opshin.tests.test_ops

      def validator(x: Anything) -> str: return f"{x}" """ - # UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying - exp = f"{x_data}" + # NOTE: this is technically a deviation from the semantics of pycardano but I expect the pycardano semantics to change soon + exp = f"RawPlutusData(data={repr(x_data.data)})" ret = eval_uplc_value(source_code, pycardano.RawCBOR(x_cbor)).decode("utf8") if "\\'" in ret: RawPlutusData = pycardano.RawPlutusData @@ -1800,6 +1803,9 @@

      Classes

      @given(x=uplc_data) @example(PlutusByteString(b"")) @example(PlutusConstr(0, [PlutusByteString(b"'")])) + @example( + PlutusMap({PlutusInteger(1): PlutusMap({}), PlutusInteger(0): PlutusMap({})}) + ) def test_fmt_any(self, x): x_cbor = uplc.plutus_cbor_dumps(x) x_data = pycardano.RawPlutusData(cbor2.loads(x_cbor)) @@ -1807,8 +1813,8 @@

      Classes

      def validator(x: Anything) -> str: return f"{x}" """ - # UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying - exp = f"{x_data}" + # NOTE: this is technically a deviation from the semantics of pycardano but I expect the pycardano semantics to change soon + exp = f"RawPlutusData(data={repr(x_data.data)})" ret = eval_uplc_value(source_code, pycardano.RawCBOR(x_cbor)).decode("utf8") if "\\'" in ret: RawPlutusData = pycardano.RawPlutusData @@ -2091,6 +2097,9 @@

      Methods

          @given(x=uplc_data)
           @example(PlutusByteString(b""))
           @example(PlutusConstr(0, [PlutusByteString(b"'")]))
      +    @example(
      +        PlutusMap({PlutusInteger(1): PlutusMap({}), PlutusInteger(0): PlutusMap({})})
      +    )
           def test_fmt_any(self, x):
               x_cbor = uplc.plutus_cbor_dumps(x)
               x_data = pycardano.RawPlutusData(cbor2.loads(x_cbor))
      @@ -2098,8 +2107,8 @@ 

      Methods

      def validator(x: Anything) -> str: return f"{x}" """ - # UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying - exp = f"{x_data}" + # NOTE: this is technically a deviation from the semantics of pycardano but I expect the pycardano semantics to change soon + exp = f"RawPlutusData(data={repr(x_data.data)})" ret = eval_uplc_value(source_code, pycardano.RawCBOR(x_cbor)).decode("utf8") if "\\'" in ret: RawPlutusData = pycardano.RawPlutusData diff --git a/docs/opshin/tests/utils.html b/docs/opshin/tests/utils.html index d350fb64..e845c7a9 100644 --- a/docs/opshin/tests/utils.html +++ b/docs/opshin/tests/utils.html @@ -234,7 +234,7 @@

      Ancestors

    Class variables

    -
    var CONSTR_ID : ClassVar[int]
    +
    var CONSTR_ID
    diff --git a/docs/opshin/type_inference.html b/docs/opshin/type_inference.html index cefc44a1..7ca046bc 100644 --- a/docs/opshin/type_inference.html +++ b/docs/opshin/type_inference.html @@ -1045,12 +1045,12 @@

    Module opshin.type_inference

    class RecordReader(NodeVisitor): name: str orig_name: str - constructor: int + constructor: typing.Optional[int] attributes: typing.List[typing.Tuple[str, Type]] _type_inferencer: AggressiveTypeInferencer def __init__(self, type_inferencer: AggressiveTypeInferencer): - self.constructor = 0 + self.constructor = None self.attributes = [] self._type_inferencer = type_inferencer @@ -1058,6 +1058,12 @@

    Module opshin.type_inference

    def extract(cls, c: ClassDef, type_inferencer: AggressiveTypeInferencer) -> Record: f = cls(type_inferencer) f.visit(c) + if f.constructor is None: + det_string = RecordType( + Record(f.name, f.orig_name, 0, frozenlist(f.attributes)) + ).id_map(skip_constructor=True) + det_hash = sha256(str(det_string).encode("utf8")).hexdigest() + f.constructor = int(det_hash, 16) % 2**32 return Record(f.name, f.orig_name, f.constructor, frozenlist(f.attributes)) def visit_AnnAssign(self, node: AnnAssign) -> None: @@ -3317,12 +3323,12 @@

    Methods

    class RecordReader(NodeVisitor):
         name: str
         orig_name: str
    -    constructor: int
    +    constructor: typing.Optional[int]
         attributes: typing.List[typing.Tuple[str, Type]]
         _type_inferencer: AggressiveTypeInferencer
     
         def __init__(self, type_inferencer: AggressiveTypeInferencer):
    -        self.constructor = 0
    +        self.constructor = None
             self.attributes = []
             self._type_inferencer = type_inferencer
     
    @@ -3330,6 +3336,12 @@ 

    Methods

    def extract(cls, c: ClassDef, type_inferencer: AggressiveTypeInferencer) -> Record: f = cls(type_inferencer) f.visit(c) + if f.constructor is None: + det_string = RecordType( + Record(f.name, f.orig_name, 0, frozenlist(f.attributes)) + ).id_map(skip_constructor=True) + det_hash = sha256(str(det_string).encode("utf8")).hexdigest() + f.constructor = int(det_hash, 16) % 2**32 return Record(f.name, f.orig_name, f.constructor, frozenlist(f.attributes)) def visit_AnnAssign(self, node: AnnAssign) -> None: @@ -3403,7 +3415,7 @@

    Class variables

    -
    var constructor : int
    +
    var constructor : Optional[int]
    @@ -3431,6 +3443,12 @@

    Static methods

    def extract(cls, c: ClassDef, type_inferencer: AggressiveTypeInferencer) -> Record: f = cls(type_inferencer) f.visit(c) + if f.constructor is None: + det_string = RecordType( + Record(f.name, f.orig_name, 0, frozenlist(f.attributes)) + ).id_map(skip_constructor=True) + det_hash = sha256(str(det_string).encode("utf8")).hexdigest() + f.constructor = int(det_hash, 16) % 2**32 return Record(f.name, f.orig_name, f.constructor, frozenlist(f.attributes))
    diff --git a/docs/opshin/types.html b/docs/opshin/types.html index fd55b6de..548d522a 100644 --- a/docs/opshin/types.html +++ b/docs/opshin/types.html @@ -211,6 +211,12 @@

    Module opshin.types

    f"{type(self).__name__} can not be used with operation {unop.__class__.__name__}" ) + def id_map(self, skip_constructor: bool = False) -> str: + """ + Returns a map from the constructor id to a descriptive typestring + """ + raise NotImplementedError(f"Type {type(self).__name__} does not have a id map") + @dataclass(frozen=True, unsafe_hash=True) class Record: @@ -257,6 +263,9 @@

    Module opshin.types

    class AnyType(ClassType): """The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)""" + def id_map(self, skip_constructor: bool = False) -> str: + return "any" + def attribute_type(self, attr: str) -> Type: """The types of the named attributes of this class""" if attr == "CONSTR_ID": @@ -517,6 +526,17 @@

    Module opshin.types

    class RecordType(ClassType): record: Record + def id_map(self, skip_constructor: bool = False) -> str: + return ( + "cons[" + + self.record.orig_name + + "](" + + (str(self.record.constructor) if not skip_constructor else "_") + + ";" + + ",".join(name + ":" + type.id_map() for name, type in self.record.fields) + + ")" + ) + def constr_type(self) -> "InstanceType": return InstanceType( FunctionType( @@ -713,6 +733,9 @@

    Module opshin.types

    def __post_init__(self): object.__setattr__(self, "typs", frozenlist(self.typs)) + def id_map(self, skip_constructor: bool = False) -> str: + return "union<" + ",".join(t.id_map() for t in self.typs) + ">" + def attribute_type(self, attr) -> "Type": if attr == "CONSTR_ID": return IntegerInstanceType @@ -986,6 +1009,9 @@

    Module opshin.types

    def __ge__(self, other): return isinstance(other, ListType) and self.typ >= other.typ + def id_map(self, skip_constructor: bool = False) -> str: + return "list<" + self.typ.id_map() + ">" + def attribute_type(self, attr) -> "Type": if attr == "index": return InstanceType( @@ -1128,6 +1154,9 @@

    Module opshin.types

    key_typ: Type value_typ: Type + def id_map(self, skip_constructor: bool = False) -> str: + return "map<" + self.key_typ.id_map() + "," + self.value_typ.id_map() + ">" + def attribute_type(self, attr) -> "Type": if attr == "get": return InstanceType( @@ -1453,6 +1482,9 @@

    Module opshin.types

    class InstanceType(Type): typ: ClassType + def id_map(self, skip_constructor: bool = False) -> str: + return self.typ.id_map(skip_constructor=skip_constructor) + def constr_type(self) -> FunctionType: raise TypeInferenceError(f"Can not construct an instance {self}") @@ -1495,6 +1527,9 @@

    Module opshin.types

    @dataclass(frozen=True, unsafe_hash=True) class IntegerType(AtomicType): + def id_map(self, skip_constructor: bool = False) -> str: + return "int" + def constr_type(self) -> InstanceType: return InstanceType(PolymorphicFunctionType(IntImpl())) @@ -1768,6 +1803,9 @@

    Module opshin.types

    @dataclass(frozen=True, unsafe_hash=True) class ByteStringType(AtomicType): + def id_map(self, skip_constructor: bool = False) -> str: + return "bytes" + def constr_type(self) -> InstanceType: return InstanceType(PolymorphicFunctionType(BytesImpl())) @@ -3024,6 +3062,9 @@

    Classes

    class AnyType(ClassType): """The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)""" + def id_map(self, skip_constructor: bool = False) -> str: + return "any" + def attribute_type(self, attr: str) -> Type: """The types of the named attributes of this class""" if attr == "CONSTR_ID": @@ -3408,6 +3449,23 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return "any"
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -3756,6 +3814,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -4095,6 +4163,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +AtomicType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -4152,6 +4230,9 @@

    Methods

    @dataclass(frozen=True, unsafe_hash=True)
     class ByteStringType(AtomicType):
    +    def id_map(self, skip_constructor: bool = False) -> str:
    +        return "bytes"
    +
         def constr_type(self) -> InstanceType:
             return InstanceType(PolymorphicFunctionType(BytesImpl()))
     
    @@ -4772,6 +4853,23 @@ 

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +AtomicType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return "bytes"
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -5237,6 +5335,16 @@

    Methods

    return OLambda(["self"], OVar("self"))
    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +Type.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -5284,6 +5392,9 @@

    Methods

    key_typ: Type value_typ: Type + def id_map(self, skip_constructor: bool = False) -> str: + return "map<" + self.key_typ.id_map() + "," + self.value_typ.id_map() + ">" + def attribute_type(self, attr) -> "Type": if attr == "get": return InstanceType( @@ -5899,6 +6010,23 @@

    Methods

    return OLambda(["self"], mapped_attrs)
    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return "map<" + self.key_typ.id_map() + "," + self.value_typ.id_map() + ">"
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -6141,6 +6269,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -6282,6 +6420,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -6328,6 +6476,9 @@

    Methods

    class InstanceType(Type): typ: ClassType + def id_map(self, skip_constructor: bool = False) -> str: + return self.typ.id_map(skip_constructor=skip_constructor) + def constr_type(self) -> FunctionType: raise TypeInferenceError(f"Can not construct an instance {self}") @@ -6523,6 +6674,23 @@

    Methods

    return self.typ.copy_only_attributes() +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +Type.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return self.typ.id_map(skip_constructor=skip_constructor)
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -6928,6 +7096,9 @@

    Methods

    @dataclass(frozen=True, unsafe_hash=True)
     class IntegerType(AtomicType):
    +    def id_map(self, skip_constructor: bool = False) -> str:
    +        return "int"
    +
         def constr_type(self) -> InstanceType:
             return InstanceType(PolymorphicFunctionType(IntImpl()))
     
    @@ -7309,6 +7480,23 @@ 

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +AtomicType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return "int"
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -7428,6 +7616,9 @@

    Methods

    def __ge__(self, other): return isinstance(other, ListType) and self.typ >= other.typ + def id_map(self, skip_constructor: bool = False) -> str: + return "list<" + self.typ.id_map() + ">" + def attribute_type(self, attr) -> "Type": if attr == "index": return InstanceType( @@ -7729,6 +7920,23 @@

    Methods

    return OLambda(["self"], mapped_attrs)
    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return "list<" + self.typ.id_map() + ">"
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -7953,6 +8161,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -8187,6 +8405,16 @@

    Methods

    Pluthon function that returns a copy of only the attributes of the object

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +InstanceType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -8336,6 +8564,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -8431,6 +8669,17 @@

    Class variables

    class RecordType(ClassType): record: Record + def id_map(self, skip_constructor: bool = False) -> str: + return ( + "cons[" + + self.record.orig_name + + "](" + + (str(self.record.constructor) if not skip_constructor else "_") + + ";" + + ",".join(name + ":" + type.id_map() for name, type in self.record.fields) + + ")" + ) + def constr_type(self) -> "InstanceType": return InstanceType( FunctionType( @@ -8884,6 +9133,31 @@

    Methods

    ) +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    + +Expand source code + +
    def id_map(self, skip_constructor: bool = False) -> str:
    +    return (
    +        "cons["
    +        + self.record.orig_name
    +        + "]("
    +        + (str(self.record.constructor) if not skip_constructor else "_")
    +        + ";"
    +        + ",".join(name + ":" + type.id_map() for name, type in self.record.fields)
    +        + ")"
    +    )
    +
    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -9209,6 +9483,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +AtomicType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -9410,6 +9694,16 @@

    Methods

    Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …

    +
    +def id_map(self, skip_constructor: bool = False) ‑> str +
    +
    +

    +Inherited from: +ClassType.id_map +

    +

    Returns a map from the constructor id to a descriptive typestring

    +
    def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
    @@ -9612,7 +9906,13 @@

    Methods

    """ raise NotImplementedError( f"{type(self).__name__} can not be used with operation {unop.__class__.__name__}" - ) + ) + + def id_map(self, skip_constructor: bool = False) -> str: + """ + Returns a map from the constructor id to a descriptive typestring + """ + raise NotImplementedError(f"Type {type(self).__name__} does not have a id map")

    Subclasses