From 9e328e8491a53f30405470f23d21d911f0f3eeee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 31 Jan 2024 11:30:54 +0100 Subject: [PATCH] Update docs --- docs/index.js | 1120 ++++++++++++----- docs/opshin/compiler.html | 211 +++- docs/opshin/fun_impls.html | 106 +- .../optimize/optimize_const_folding.html | 6 +- docs/opshin/rewrite/index.html | 10 + docs/opshin/rewrite/rewrite_empty_dicts.html | 300 +++++ docs/opshin/rewrite/rewrite_empty_lists.html | 300 +++++ .../rewrite/rewrite_import_hashlib.html | 22 + docs/opshin/tests/test_builtins.html | 50 + docs/opshin/tests/test_misc.html | 563 +++++++-- docs/opshin/tests/test_ops.html | 449 ++++++- docs/opshin/tests/test_stdlib.html | 77 ++ docs/opshin/type_inference.html | 135 +- docs/opshin/typed_ast.html | 74 +- docs/opshin/types.html | 1015 ++++++++++++++- docs/opshin/util.html | 2 + 16 files changed, 3930 insertions(+), 510 deletions(-) create mode 100644 docs/opshin/rewrite/rewrite_empty_dicts.html create mode 100644 docs/opshin/rewrite/rewrite_empty_lists.html diff --git a/docs/index.js b/docs/index.js index 033fc648..02c416bd 100644 --- a/docs/index.js +++ b/docs/index.js @@ -37,7 +37,9 @@ URLS=[ "opshin/rewrite/rewrite_inject_builtin_constr.html", "opshin/rewrite/rewrite_import_dataclasses.html", "opshin/rewrite/rewrite_subscript38.html", +"opshin/rewrite/rewrite_empty_lists.html", "opshin/rewrite/rewrite_scoping.html", +"opshin/rewrite/rewrite_empty_dicts.html", "opshin/rewrite/rewrite_augassign.html", "opshin/rewrite/rewrite_import_integrity_check.html", "opshin/rewrite/rewrite_forbidden_overwrites.html", @@ -426,12 +428,12 @@ INDEX=[ "doc":"ListComp(expr elt, comprehension generators)" }, { -"ref":"opshin.typed_ast.TypedListComp.generators", +"ref":"opshin.typed_ast.TypedListComp.elt", "url":2, "doc":"" }, { -"ref":"opshin.typed_ast.TypedListComp.elt", +"ref":"opshin.typed_ast.TypedListComp.generators", "url":2, "doc":"" }, @@ -442,6 +444,32 @@ INDEX=[ "func":1 }, { +"ref":"opshin.typed_ast.TypedDictComp", +"url":2, +"doc":"DictComp(expr key, expr value, comprehension generators)" +}, +{ +"ref":"opshin.typed_ast.TypedDictComp.key", +"url":2, +"doc":"" +}, +{ +"ref":"opshin.typed_ast.TypedDictComp.value", +"url":2, +"doc":"" +}, +{ +"ref":"opshin.typed_ast.TypedDictComp.generators", +"url":2, +"doc":"" +}, +{ +"ref":"opshin.typed_ast.TypedDictComp.typechecks", +"url":2, +"doc":"Successful typechecks if this expression evaluates to True", +"func":1 +}, +{ "ref":"opshin.typed_ast.TypedFormattedValue", "url":2, "doc":"FormattedValue(expr value, int conversion, expr? format_spec)" @@ -790,6 +818,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_builtins.BuiltinTest.test_neg_pow", +"url":4, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_builtins.BuiltinTest.test_oct", "url":4, "doc":"", @@ -1227,6 +1261,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_misc.MiscTest.test_dict_comprehension_even", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_dict_comprehension_all", +"url":7, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_access_all_records", "url":7, "doc":"", @@ -1868,85 +1914,91 @@ INDEX=[ "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_08_examples_list_comprehensions_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_08_examples_dict_comprehensions_py", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_09_examples_list_comprehensions_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_09_examples_fib_rec_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_10_examples_fib_rec_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_10_examples_showcase_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_11_examples_showcase_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_11_examples_fib_iter_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_12_examples_fib_iter_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_12_examples_mult_while_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_13_examples_mult_while_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_13_examples_smart_contracts_dual_use_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_14_examples_smart_contracts_dual_use_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_14_examples_smart_contracts_simple_script_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_15_examples_smart_contracts_simple_script_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_15_examples_smart_contracts_parameterized_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_16_examples_smart_contracts_parameterized_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_16_examples_smart_contracts_gift_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_17_examples_smart_contracts_gift_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_17_examples_smart_contracts_wrapped_token_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_18_examples_smart_contracts_wrapped_token_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_18_examples_smart_contracts_always_true_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_19_examples_smart_contracts_always_true_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_19_examples_smart_contracts_micropayments_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_20_examples_smart_contracts_micropayments_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_20_examples_smart_contracts_marketplace_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_21_examples_smart_contracts_marketplace_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_21_examples_smart_contracts_assert_sum_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_22_examples_smart_contracts_assert_sum_py", "url":7, "doc":"", "func":1 @@ -2005,85 +2057,91 @@ INDEX=[ "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_08_examples_list_comprehensions_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_08_examples_dict_comprehensions_py", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_09_examples_list_comprehensions_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_09_examples_fib_rec_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_10_examples_fib_rec_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_10_examples_showcase_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_11_examples_showcase_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_11_examples_fib_iter_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_12_examples_fib_iter_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_12_examples_mult_while_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_13_examples_mult_while_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_13_examples_smart_contracts_dual_use_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_14_examples_smart_contracts_dual_use_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_14_examples_smart_contracts_simple_script_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_15_examples_smart_contracts_simple_script_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_15_examples_smart_contracts_parameterized_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_16_examples_smart_contracts_parameterized_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_16_examples_smart_contracts_gift_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_17_examples_smart_contracts_gift_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_17_examples_smart_contracts_wrapped_token_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_18_examples_smart_contracts_wrapped_token_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_18_examples_smart_contracts_always_true_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_19_examples_smart_contracts_always_true_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_19_examples_smart_contracts_micropayments_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_20_examples_smart_contracts_micropayments_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_20_examples_smart_contracts_marketplace_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_21_examples_smart_contracts_marketplace_py", "url":7, "doc":"", "func":1 }, { -"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_21_examples_smart_contracts_assert_sum_py", +"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_22_examples_smart_contracts_assert_sum_py", "url":7, "doc":"", "func":1 @@ -2160,6 +2218,42 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_misc.MiscTest.test_empty_list_int", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_empty_list_data", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_empty_list_int_constant_folding", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_empty_dict_int_int", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_empty_dict_int_int_constant_folding", +"url":7, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_misc.MiscTest.test_empty_dict_displaced_constant_folding", +"url":7, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops", "url":8, "doc":"" @@ -2206,6 +2300,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_uadd_int", +"url":8, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_ops.OpTest.test_not_int", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_add_int", "url":8, "doc":"", @@ -2242,6 +2348,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_neg_pow_int", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_add_bytes", "url":8, "doc":"", @@ -2326,12 +2438,24 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_not_list", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_eq_bytes", "url":8, "doc":"", "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_eq_int", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_eq_str", "url":8, "doc":"", @@ -2344,6 +2468,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_eq_data", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_mul_int_str", "url":8, "doc":"", @@ -2452,6 +2582,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_not_dict", +"url":8, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_ops.OpTest.test_index_dict", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ops.OpTest.test_fmt_dict_int", "url":8, "doc":"", @@ -2464,6 +2606,24 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_ops.OpTest.test_not_string", +"url":8, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_ops.OpTest.test_not_bytes", +"url":8, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.tests.test_ops.OpTest.test_not_unit", +"url":8, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_ledger", "url":9, "doc":"" @@ -2904,6 +3064,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.tests.test_stdlib.StdlibTest.test_list_index", +"url":17, +"doc":"", +"func":1 +}, +{ "ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_keys", "url":17, "doc":"", @@ -4111,6 +4277,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.FunctionType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.FunctionType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.TypeInferenceError", "url":23, "doc":"Assertion failed." @@ -4175,6 +4353,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.Type.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.Type.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.Record", "url":23, "doc":"Record(name: str, orig_name: str, constructor: int, fields: Union[List[Tuple[str, opshin.types.Type , frozenlist2.frozenlist])" @@ -4259,6 +4449,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.ClassType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.ClassType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.AnyType", "url":23, "doc":"The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)" @@ -4276,6 +4478,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.AnyType.cmp", +"url":23, +"doc":"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.", +"func":1 +}, +{ "ref":"opshin.types.AnyType.stringify", "url":23, "doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation", @@ -4300,12 +4508,6 @@ INDEX=[ "func":1 }, { -"ref":"opshin.types.AnyType.cmp", -"url":23, -"doc":"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.", -"func":1 -}, -{ "ref":"opshin.types.AnyType.binop_type", "url":23, "doc":"Type of a binary operation between self and other.", @@ -4318,6 +4520,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.AnyType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.AnyType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.AtomicType", "url":23, "doc":"AtomicType()" @@ -4377,6 +4591,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.AtomicType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.AtomicType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.RecordType", "url":23, "doc":"RecordType(record: opshin.types.Record)" @@ -4441,6 +4667,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.RecordType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.RecordType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.UnionType", "url":23, "doc":"UnionType(typs: List[opshin.types.RecordType])" @@ -4505,6 +4743,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.UnionType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.UnionType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.TupleType", "url":23, "doc":"TupleType(typs: List[opshin.types.Type])" @@ -4569,6 +4819,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.TupleType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.TupleType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.PairType", "url":23, "doc":"An internal type representing built-in PlutusData pairs" @@ -4638,6 +4900,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.PairType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.PairType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.ListType", "url":23, "doc":"ListType(typ: opshin.types.Type)" @@ -4648,6 +4922,18 @@ INDEX=[ "doc":"" }, { +"ref":"opshin.types.ListType.attribute_type", +"url":23, +"doc":"The types of the named attributes of this class", +"func":1 +}, +{ +"ref":"opshin.types.ListType.attribute", +"url":23, +"doc":"The attributes of this class. Needs to be a lambda that expects as first argument the object itself", +"func":1 +}, +{ "ref":"opshin.types.ListType.stringify", "url":23, "doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation", @@ -4672,33 +4958,33 @@ INDEX=[ "func":1 }, { -"ref":"opshin.types.ListType.attribute_type", +"ref":"opshin.types.ListType.cmp", "url":23, -"doc":"The types of the named attributes of this class", +"doc":"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.", "func":1 }, { -"ref":"opshin.types.ListType.attribute", +"ref":"opshin.types.ListType.binop_type", "url":23, -"doc":"The attributes of this class. Needs to be a lambda that expects as first argument the object itself", +"doc":"Type of a binary operation between self and other.", "func":1 }, { -"ref":"opshin.types.ListType.cmp", +"ref":"opshin.types.ListType.binop", "url":23, -"doc":"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.", +"doc":"Implements a binary operation between self and other", "func":1 }, { -"ref":"opshin.types.ListType.binop_type", +"ref":"opshin.types.ListType.unop_type", "url":23, -"doc":"Type of a binary operation between self and other.", +"doc":"Type of a unary operation on self.", "func":1 }, { -"ref":"opshin.types.ListType.binop", +"ref":"opshin.types.ListType.unop", "url":23, -"doc":"Implements a binary operation between self and other", +"doc":"Implements a unary operation on self", "func":1 }, { @@ -4771,14 +5057,26 @@ INDEX=[ "func":1 }, { -"ref":"opshin.types.InstanceType", +"ref":"opshin.types.DictType.unop_type", "url":23, -"doc":"InstanceType(typ: opshin.types.ClassType)" +"doc":"Type of a unary operation on self.", +"func":1 }, { -"ref":"opshin.types.InstanceType.typ", +"ref":"opshin.types.DictType.unop", "url":23, -"doc":"" +"doc":"Implements a unary operation on self", +"func":1 +}, +{ +"ref":"opshin.types.InstanceType", +"url":23, +"doc":"InstanceType(typ: opshin.types.ClassType)" +}, +{ +"ref":"opshin.types.InstanceType.typ", +"url":23, +"doc":"" }, { "ref":"opshin.types.InstanceType.constr_type", @@ -4835,6 +5133,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.InstanceType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.InstanceType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.IntegerType", "url":23, "doc":"IntegerType()" @@ -4894,6 +5204,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.IntegerType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.IntegerType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.StringType", "url":23, "doc":"StringType()" @@ -4953,6 +5275,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.StringType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.StringType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.ByteStringType", "url":23, "doc":"ByteStringType()" @@ -5012,6 +5346,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.ByteStringType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.ByteStringType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.BoolType", "url":23, "doc":"BoolType()" @@ -5071,6 +5417,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.BoolType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.BoolType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.UnitType", "url":23, "doc":"UnitType()" @@ -5130,6 +5488,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.UnitType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.UnitType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.InaccessibleType", "url":23, "doc":"A type that blocks overwriting of a function" @@ -5189,6 +5559,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.InaccessibleType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.InaccessibleType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.repeated_addition", "url":23, "doc":"", @@ -5362,6 +5744,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.PolymorphicFunctionType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.PolymorphicFunctionType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.PolymorphicFunctionInstanceType", "url":23, "doc":"PolymorphicFunctionInstanceType(typ: opshin.types.FunctionType, polymorphic_function: opshin.types.PolymorphicFunction)" @@ -5431,6 +5825,18 @@ INDEX=[ "func":1 }, { +"ref":"opshin.types.PolymorphicFunctionInstanceType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.types.PolymorphicFunctionInstanceType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.types.empty_list", "url":23, "doc":"", @@ -6124,6 +6530,12 @@ INDEX=[ "func":1 }, { +"ref":"opshin.compiler.PlutoCompiler.visit_DictComp", +"url":30, +"doc":"", +"func":1 +}, +{ "ref":"opshin.compiler.PlutoCompiler.visit_FormattedValue", "url":30, "doc":"", @@ -6373,35 +6785,68 @@ INDEX=[ "func":1 }, { -"ref":"opshin.rewrite.rewrite_scoping", +"ref":"opshin.rewrite.rewrite_empty_lists", "url":38, "doc":"" }, { -"ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector", +"ref":"opshin.rewrite.rewrite_empty_lists.RewriteEmptyLists", +"url":38, +"doc":"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=Constant(value=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)" +}, +{ +"ref":"opshin.rewrite.rewrite_empty_lists.RewriteEmptyLists.step", +"url":38, +"doc":"" +}, +{ +"ref":"opshin.rewrite.rewrite_empty_lists.RewriteEmptyLists.visit_List", +"url":38, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_empty_lists.RewriteEmptyLists.visit_Constant", "url":38, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_empty_lists.RewriteEmptyLists.visit", +"url":26, +"doc":"Visit a node.", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_scoping", +"url":39, +"doc":"" +}, +{ +"ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector", +"url":39, "doc":"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." }, { "ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector.step", -"url":38, +"url":39, "doc":"" }, { "ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector.visit_Name", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector.visit_ClassDef", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector.visit_FunctionDef", -"url":38, +"url":39, "doc":"", "func":1 }, @@ -6413,81 +6858,81 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping", -"url":38, +"url":39, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.latest_scope_id", -"url":38, +"url":39, "doc":"" }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.scopes", -"url":38, +"url":39, "doc":"" }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.step", -"url":38, +"url":39, "doc":"" }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.variable_scope_id", -"url":38, +"url":39, "doc":"find the id of the scope in which this variable is defined (closest to its usage)", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.enter_scope", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.exit_scope", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.set_variable_scope", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.map_name", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_Module", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_Name", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_ClassDef", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_FunctionDef", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_NoneType", -"url":38, +"url":39, "doc":"", "func":1 }, @@ -6499,45 +6944,78 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_scoping.RecordScoper", -"url":38, +"url":39, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_scoping.RecordScoper.scope", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RecordScoper.visit_ClassDef", -"url":38, +"url":39, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_scoping.RecordScoper.visit_AnnAssign", -"url":38, +"url":39, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_empty_dicts", +"url":40, +"doc":"" +}, +{ +"ref":"opshin.rewrite.rewrite_empty_dicts.RewriteEmptyDicts", +"url":40, +"doc":"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=Constant(value=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)" +}, +{ +"ref":"opshin.rewrite.rewrite_empty_dicts.RewriteEmptyDicts.step", +"url":40, +"doc":"" +}, +{ +"ref":"opshin.rewrite.rewrite_empty_dicts.RewriteEmptyDicts.visit_Dict", +"url":40, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_empty_dicts.RewriteEmptyDicts.visit_Constant", +"url":40, "doc":"", "func":1 }, { +"ref":"opshin.rewrite.rewrite_empty_dicts.RewriteEmptyDicts.visit", +"url":26, +"doc":"Visit a node.", +"func":1 +}, +{ "ref":"opshin.rewrite.rewrite_augassign", -"url":39, +"url":41, "doc":"" }, { "ref":"opshin.rewrite.rewrite_augassign.RewriteAugAssign", -"url":39, +"url":41, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_augassign.RewriteAugAssign.step", -"url":39, +"url":41, "doc":"" }, { "ref":"opshin.rewrite.rewrite_augassign.RewriteAugAssign.visit_AugAssign", -"url":39, +"url":41, "doc":"", "func":1 }, @@ -6549,39 +7027,39 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_import_integrity_check", -"url":40, +"url":42, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.IntegrityCheckImpl", -"url":40, +"url":42, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.IntegrityCheckImpl.type_from_args", -"url":40, +"url":42, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.IntegrityCheckImpl.impl_from_args", -"url":40, +"url":42, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.RewriteImportIntegrityCheck", -"url":40, +"url":42, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.RewriteImportIntegrityCheck.step", -"url":40, +"url":42, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_integrity_check.RewriteImportIntegrityCheck.visit_ImportFrom", -"url":40, +"url":42, "doc":"", "func":1 }, @@ -6593,27 +7071,27 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_forbidden_overwrites", -"url":41, +"url":43, "doc":"" }, { "ref":"opshin.rewrite.rewrite_forbidden_overwrites.ForbiddenOverwriteError", -"url":41, +"url":43, "doc":"Inappropriate argument value (of correct type)." }, { "ref":"opshin.rewrite.rewrite_forbidden_overwrites.RewriteForbiddenOverwrites", -"url":41, +"url":43, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_forbidden_overwrites.RewriteForbiddenOverwrites.step", -"url":41, +"url":43, "doc":"" }, { "ref":"opshin.rewrite.rewrite_forbidden_overwrites.RewriteForbiddenOverwrites.visit_Name", -"url":41, +"url":43, "doc":"", "func":1 }, @@ -6625,22 +7103,22 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_inject_builtins", -"url":42, +"url":44, "doc":"" }, { "ref":"opshin.rewrite.rewrite_inject_builtins.RewriteInjectBuiltins", -"url":42, +"url":44, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_inject_builtins.RewriteInjectBuiltins.step", -"url":42, +"url":44, "doc":"" }, { "ref":"opshin.rewrite.rewrite_inject_builtins.RewriteInjectBuiltins.visit_Module", -"url":42, +"url":44, "doc":"", "func":1 }, @@ -6652,33 +7130,33 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_import_plutusdata", -"url":43, +"url":45, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData", -"url":43, +"url":45, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData.step", -"url":43, +"url":45, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData.imports_plutus_data", -"url":43, +"url":45, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData.visit_ImportFrom", -"url":43, +"url":45, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData.visit_ClassDef", -"url":43, +"url":45, "doc":"", "func":1 }, @@ -6690,33 +7168,33 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins", -"url":44, +"url":46, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins", -"url":44, +"url":46, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins.step", -"url":44, +"url":46, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins.imports_uplc_builtins", -"url":44, +"url":46, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins.visit_ImportFrom", -"url":44, +"url":46, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins.visit_FunctionDef", -"url":44, +"url":46, "doc":"", "func":1 }, @@ -6728,23 +7206,23 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_import_hashlib", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.HashType", -"url":45, +"url":47, "doc":"A pseudo class that is the result of python hash functions that need a 'digest' call" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.HashType.attribute_type", -"url":45, +"url":47, "doc":"The types of the named attributes of this class", "func":1 }, { "ref":"opshin.rewrite.rewrite_import_hashlib.HashType.attribute", -"url":45, +"url":47, "doc":"The attributes of this class. Needs to be a lambda that expects as first argument the object itself", "func":1 }, @@ -6791,43 +7269,55 @@ INDEX=[ "func":1 }, { +"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.unop_type", +"url":23, +"doc":"Type of a unary operation on self.", +"func":1 +}, +{ +"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.unop", +"url":23, +"doc":"Implements a unary operation on self", +"func":1 +}, +{ "ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib", -"url":45, +"url":47, "doc":"An enumeration." }, { "ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib.sha256", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib.sha3_256", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib.blake2b", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.RewriteImportHashlib", -"url":45, +"url":47, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.RewriteImportHashlib.step", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.RewriteImportHashlib.imports_hashlib", -"url":45, +"url":47, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import_hashlib.RewriteImportHashlib.visit_ImportFrom", -"url":45, +"url":47, "doc":"", "func":1 }, @@ -6839,33 +7329,33 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_tuple_assign", -"url":46, +"url":48, "doc":"" }, { "ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign", -"url":46, +"url":48, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign.step", -"url":46, +"url":48, "doc":"" }, { "ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign.unique_id", -"url":46, +"url":48, "doc":"" }, { "ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign.visit_Assign", -"url":46, +"url":48, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign.visit_For", -"url":46, +"url":48, "doc":"", "func":1 }, @@ -6877,22 +7367,22 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_comparison_chaining", -"url":47, +"url":49, "doc":"" }, { "ref":"opshin.rewrite.rewrite_comparison_chaining.RewriteComparisonChaining", -"url":47, +"url":49, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_comparison_chaining.RewriteComparisonChaining.step", -"url":47, +"url":49, "doc":"" }, { "ref":"opshin.rewrite.rewrite_comparison_chaining.RewriteComparisonChaining.visit_Compare", -"url":47, +"url":49, "doc":"", "func":1 }, @@ -6904,28 +7394,28 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_forbidden_return", -"url":48, +"url":50, "doc":"" }, { "ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn", -"url":48, +"url":50, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.step", -"url":48, +"url":50, "doc":"" }, { "ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.visit_Return", -"url":48, +"url":50, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.visit_FunctionDef", -"url":48, +"url":50, "doc":"", "func":1 }, @@ -6937,39 +7427,39 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_import", -"url":49, +"url":51, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import.import_module", -"url":49, +"url":51, "doc":"An approximate implementation of import.", "func":1 }, { "ref":"opshin.rewrite.rewrite_import.RewriteLocation", -"url":49, +"url":51, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import.RewriteLocation.visit", -"url":49, +"url":51, "doc":"Visit a node.", "func":1 }, { "ref":"opshin.rewrite.rewrite_import.RewriteImport", -"url":49, +"url":51, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_import.RewriteImport.step", -"url":49, +"url":51, "doc":"" }, { "ref":"opshin.rewrite.rewrite_import.RewriteImport.visit_ImportFrom", -"url":49, +"url":51, "doc":"", "func":1 }, @@ -6981,40 +7471,40 @@ INDEX=[ }, { "ref":"opshin.rewrite.rewrite_orig_name", -"url":50, +"url":52, "doc":"" }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName", -"url":50, +"url":52, "doc":"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=Constant(value=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)" }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.step", -"url":50, +"url":52, "doc":"" }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_Name", -"url":50, +"url":52, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_ClassDef", -"url":50, +"url":52, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_NoneType", -"url":50, +"url":52, "doc":"", "func":1 }, { "ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_FunctionDef", -"url":50, +"url":52, "doc":"", "func":1 }, @@ -7026,468 +7516,468 @@ INDEX=[ }, { "ref":"opshin.std", -"url":51, +"url":53, "doc":"OpShin provides a few features in its standard libary. You can import modules from there (i.e. the fractions module) with from opshin.std.fractions import " }, { "ref":"opshin.std.integrity", -"url":52, +"url":54, "doc":"A special libary that gives access to a function that checks the integrity of PlutusDatum objects." }, { "ref":"opshin.std.integrity.check_integrity", -"url":52, +"url":54, "doc":"Checks the integrity of a PlutusDatum object. In particular, it takes an object of any type and checks that - the constructor id matches the id defined in the type - the fields specified in the type are present - no additional fields are present This has no equivalent in Python.", "func":1 }, { "ref":"opshin.std.builtins", -"url":53, +"url":55, "doc":"A special libary that gives direct access to UPLC built-ins It is valid code and parts of it may be copied if not all built-ins are required by the user." }, { "ref":"opshin.std.builtins.add_integer", -"url":53, +"url":55, "doc":"Adds two integers and returns the result.", "func":1 }, { "ref":"opshin.std.builtins.subtract_integer", -"url":53, +"url":55, "doc":"Subtract fist integer by second and return the result.", "func":1 }, { "ref":"opshin.std.builtins.multiply_integer", -"url":53, +"url":55, "doc":"Multiply 2 integers and return the result.", "func":1 }, { "ref":"opshin.std.builtins.divide_integer", -"url":53, +"url":55, "doc":"Divide first integer by second and return the result.", "func":1 }, { "ref":"opshin.std.builtins.quotient_integer", -"url":53, +"url":55, "doc":"Quotient of first integer by second and return the result.", "func":1 }, { "ref":"opshin.std.builtins.remainder_integer", -"url":53, +"url":55, "doc":"Remainder of first integer by second and return the result.", "func":1 }, { "ref":"opshin.std.builtins.mod_integer", -"url":53, +"url":55, "doc":"Modulus of first integer by second and return the result.", "func":1 }, { "ref":"opshin.std.builtins.equals_integer", -"url":53, +"url":55, "doc":"Equality between two integers.", "func":1 }, { "ref":"opshin.std.builtins.less_than_integer", -"url":53, +"url":55, "doc":"Returns x < y", "func":1 }, { "ref":"opshin.std.builtins.less_than_equals_integer", -"url":53, +"url":55, "doc":"Returns x <= y.", "func":1 }, { "ref":"opshin.std.builtins.append_byte_string", -"url":53, +"url":55, "doc":"Concatenate two bytestrings.", "func":1 }, { "ref":"opshin.std.builtins.cons_byte_string", -"url":53, +"url":55, "doc":"Prepend a byte, represented by a natural number (Integer), to a bytestring.", "func":1 }, { "ref":"opshin.std.builtins.slice_byte_string", -"url":53, +"url":55, "doc":"Slice a bytestring using given indices (inclusive on both ends). The resulting bytestring is z[x:x+y].", "func":1 }, { "ref":"opshin.std.builtins.length_of_byte_string", -"url":53, +"url":55, "doc":"Get the length of a bytestring.", "func":1 }, { "ref":"opshin.std.builtins.index_byte_string", -"url":53, +"url":55, "doc":"Get the byte at given index from a bytestring.", "func":1 }, { "ref":"opshin.std.builtins.equals_byte_string", -"url":53, +"url":55, "doc":"Returns x y.", "func":1 }, { "ref":"opshin.std.builtins.less_than_byte_string", -"url":53, +"url":55, "doc":"Returns x < y.", "func":1 }, { "ref":"opshin.std.builtins.less_than_equals_byte_string", -"url":53, +"url":55, "doc":"Returns x <= y.", "func":1 }, { "ref":"opshin.std.builtins.sha2_256", -"url":53, +"url":55, "doc":"Hash a bytestring using SHA-256.", "func":1 }, { "ref":"opshin.std.builtins.sha3_256", -"url":53, +"url":55, "doc":"Hash a bytestring using SHA3-256.", "func":1 }, { "ref":"opshin.std.builtins.blake2b_256", -"url":53, +"url":55, "doc":"Hash a bytestring using Blake2B-256.", "func":1 }, { "ref":"opshin.std.builtins.verify_ed25519_signature", -"url":53, +"url":55, "doc":"Given PubKey, Message, and Signature, verify the Ed25519 signature.", "func":1 }, { "ref":"opshin.std.builtins.verify_ecdsa_secp256k1_signature", -"url":53, +"url":55, "doc":"Given PubKey, Message, and Signature, verify the ECDSA signature.", "func":1 }, { "ref":"opshin.std.builtins.verify_schnorr_secp256k1_signature", -"url":53, +"url":55, "doc":"Given PubKey, Message, and Signature, verify the Schnorr signature.", "func":1 }, { "ref":"opshin.std.builtins.append_string", -"url":53, +"url":55, "doc":"Concatenate two strings/texts.", "func":1 }, { "ref":"opshin.std.builtins.equals_string", -"url":53, +"url":55, "doc":"Returns x y.", "func":1 }, { "ref":"opshin.std.builtins.encode_utf8", -"url":53, +"url":55, "doc":"Encode a string/text using UTF-8.", "func":1 }, { "ref":"opshin.std.builtins.decode_utf8", -"url":53, +"url":55, "doc":"Decode a string/text using UTF-8.", "func":1 }, { "ref":"opshin.std.builtins.constr_data", -"url":53, +"url":55, "doc":"Create a datum with constructor id x and fields y.", "func":1 }, { "ref":"opshin.std.builtins.equals_data", -"url":53, +"url":55, "doc":"Equality between two complex classes.", "func":1 }, { "ref":"opshin.std.builtins.serialise_data", -"url":53, +"url":55, "doc":"Serialize a datum into its CBOR representation.", "func":1 }, { "ref":"opshin.std.bitmap", -"url":54, +"url":56, "doc":"The BitMap library provides tools to interact with a highly efficient datastructure that stores boolean values with minimal overhead (1 bit per bool)" }, { "ref":"opshin.std.bitmap.init_bitmap", -"url":54, +"url":56, "doc":"Creates an empty bitmap with size bits", "func":1 }, { "ref":"opshin.std.bitmap.test_bitmap", -"url":54, +"url":56, "doc":"Tests if bit at position i has been set to 1", "func":1 }, { "ref":"opshin.std.bitmap.set_bitmap", -"url":54, +"url":56, "doc":"Sets a bit in the bitmap to 1", "func":1 }, { "ref":"opshin.std.bitmap.reset_bitmap", -"url":54, +"url":56, "doc":"Sets a bit in the bitmap to 0", "func":1 }, { "ref":"opshin.std.bitmap.flip_bitmap", -"url":54, +"url":56, "doc":"Flips a bit in the bitmap", "func":1 }, { "ref":"opshin.std.bitmap.size_bitmap", -"url":54, +"url":56, "doc":"Returns the size of the bitmap in bits", "func":1 }, { "ref":"opshin.std.bitmap.any_bitmap", -"url":54, +"url":56, "doc":"Returns whether any bit was set to 1", "func":1 }, { "ref":"opshin.std.bitmap.all_bitmap", -"url":54, +"url":56, "doc":"Returns whether all bits were set to 1", "func":1 }, { "ref":"opshin.std.bitmap.none_bitmap", -"url":54, +"url":56, "doc":"Returns whether no bits were set to 1", "func":1 }, { "ref":"opshin.std.math", -"url":55, +"url":57, "doc":"An implementation of some math operations in opshin" }, { "ref":"opshin.std.math.gcd", -"url":55, +"url":57, "doc":"", "func":1 }, { "ref":"opshin.std.math.sign", -"url":55, +"url":57, "doc":"", "func":1 }, { "ref":"opshin.std.math.unsigned_int_from_bytes_big", -"url":55, +"url":57, "doc":"Converts a bytestring into the corresponding integer, big/network byteorder, unsigned", "func":1 }, { "ref":"opshin.std.math.ceil", -"url":55, +"url":57, "doc":"Returns a divided by b rounded towards positive infinity", "func":1 }, { "ref":"opshin.std.math.floor", -"url":55, +"url":57, "doc":"Returns a divided by b rounded towards negative infinity", "func":1 }, { "ref":"opshin.std.hashlib", -"url":56, +"url":58, "doc":"A std library that imports all valid hash functions from the builtin python hashlib library: If you want to have all hash functions in scope, simply add from opshin.std.hashlib import to the top of you python file." }, { "ref":"opshin.std.fractions", -"url":57, +"url":59, "doc":"An implementation of fractions in opshin This does not maintain smallest possible notation invariants for the sake of efficiency - the user has full control over when to normalize the fractions and should do so using norm_fraction" }, { "ref":"opshin.std.fractions.Fraction", -"url":57, +"url":59, "doc":"Fraction(numerator: int, denominator: int)" }, { "ref":"opshin.std.fractions.Fraction.numerator", -"url":57, +"url":59, "doc":"" }, { "ref":"opshin.std.fractions.Fraction.denominator", -"url":57, +"url":59, "doc":"" }, { "ref":"opshin.std.fractions.Fraction.CONSTR_ID", -"url":57, +"url":59, "doc":"" }, { "ref":"opshin.std.fractions.add_fraction", -"url":57, +"url":59, "doc":"returns a + b", "func":1 }, { "ref":"opshin.std.fractions.neg_fraction", -"url":57, +"url":59, "doc":"returns -a", "func":1 }, { "ref":"opshin.std.fractions.sub_fraction", -"url":57, +"url":59, "doc":"returns a - b", "func":1 }, { "ref":"opshin.std.fractions.mul_fraction", -"url":57, +"url":59, "doc":"returns a b", "func":1 }, { "ref":"opshin.std.fractions.div_fraction", -"url":57, +"url":59, "doc":"returns a / b", "func":1 }, { "ref":"opshin.std.fractions.norm_fraction", -"url":57, +"url":59, "doc":"Restores the invariant that num/denom are in the smallest possible denomination and denominator > 0", "func":1 }, { "ref":"opshin.std.fractions.ge_fraction", -"url":57, +"url":59, "doc":"returns a >= b", "func":1 }, { "ref":"opshin.std.fractions.le_fraction", -"url":57, +"url":59, "doc":"returns a <= b", "func":1 }, { "ref":"opshin.std.fractions.eq_fraction", -"url":57, +"url":59, "doc":"returns a b", "func":1 }, { "ref":"opshin.std.fractions.lt_fraction", -"url":57, +"url":59, "doc":"returns a < b", "func":1 }, { "ref":"opshin.std.fractions.gt_fraction", -"url":57, +"url":59, "doc":"returns a > b", "func":1 }, { "ref":"opshin.std.fractions.floor_fraction", -"url":57, +"url":59, "doc":"", "func":1 }, { "ref":"opshin.std.fractions.ceil_fraction", -"url":57, +"url":59, "doc":"", "func":1 }, { "ref":"opshin.type_inference", -"url":58, +"url":60, "doc":"An aggressive type inference based on the work of Aycock [1]. It only allows a subset of legal python operations which allow us to infer the type of all involved variables statically. Using this we can resolve overloaded functions when translating Python into UPLC where there is no dynamic type checking. Additionally, this conveniently implements an additional layer of security into the Smart Contract by checking type correctness. [1]: https: legacy.python.org/workshops/2000-01/proceedings/papers/aycock/aycock.html" }, { "ref":"opshin.type_inference.record_from_plutusdata", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.constant_type", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.union_types", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.intersection_types", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.TypeCheckVisitor", -"url":58, +"url":60, "doc":"Generates the types to which objects are cast due to a boolean expression It returns a tuple of dictionaries which are a name -> type mapping for variable names that are assured to have a specific type if this expression is True/False respectively" }, { "ref":"opshin.type_inference.TypeCheckVisitor.generic_visit", -"url":58, +"url":60, "doc":"Called if no explicit visitor function exists for a node.", "func":1 }, { "ref":"opshin.type_inference.TypeCheckVisitor.visit_Call", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.TypeCheckVisitor.visit_BoolOp", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.TypeCheckVisitor.visit_UnaryOp", -"url":58, +"url":60, "doc":"", "func":1 }, @@ -7499,268 +7989,274 @@ INDEX=[ }, { "ref":"opshin.type_inference.merge_scope", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer", -"url":58, +"url":60, "doc":"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=Constant(value=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)" }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.step", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.scopes", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.variable_type", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.enter_scope", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.exit_scope", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.set_variable_type", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.implement_typechecks", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.type_from_annotation", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_sequence", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ClassDef", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Constant", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Tuple", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_List", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Dict", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Assign", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_AnnAssign", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_If", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_While", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_For", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Name", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Compare", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_arg", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_arguments", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_FunctionDef", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Module", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Expr", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_BinOp", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_BoolOp", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_UnaryOp", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Subscript", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Call", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Pass", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Return", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Attribute", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Assert", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_RawPlutoExpr", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_IfExp", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_comprehension", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ListComp", -"url":58, +"url":60, +"doc":"", +"func":1 +}, +{ +"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_DictComp", +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_FormattedValue", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_JoinedStr", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ImportFrom", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.AggressiveTypeInferencer.generic_visit", -"url":58, +"url":60, "doc":"Called if no explicit visitor function exists for a node.", "func":1 }, @@ -7772,121 +8268,121 @@ INDEX=[ }, { "ref":"opshin.type_inference.RecordReader", -"url":58, +"url":60, "doc":"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." }, { "ref":"opshin.type_inference.RecordReader.name", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.RecordReader.orig_name", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.RecordReader.constructor", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.RecordReader.attributes", -"url":58, +"url":60, "doc":"" }, { "ref":"opshin.type_inference.RecordReader.extract", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.visit_AnnAssign", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.visit_ClassDef", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.visit_Pass", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.visit_Assign", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.visit_Expr", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.RecordReader.generic_visit", -"url":58, +"url":60, "doc":"Called if no explicit visitor function exists for a node.", "func":1 }, { "ref":"opshin.type_inference.typed_ast", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.map_to_orig_name", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor", -"url":58, +"url":60, "doc":"Utility to check that all paths end in Return statements with the proper type Returns whether there is no remaining path" }, { "ref":"opshin.type_inference.ReturnExtractor.visit_sequence", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor.visit_If", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor.visit_For", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor.visit_While", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor.visit_Return", -"url":58, +"url":60, "doc":"", "func":1 }, { "ref":"opshin.type_inference.ReturnExtractor.check_fulfills", -"url":58, +"url":60, "doc":"", "func":1 }, @@ -8161,106 +8657,106 @@ INDEX=[ }, { "ref":"opshin.prelude", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.Nothing", -"url":59, +"url":61, "doc":"Nothing, can be used to signify non-importance of a parameter to a function Example value: Nothing()" }, { "ref":"opshin.prelude.Nothing.CONSTR_ID", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.Token", -"url":59, +"url":61, "doc":"A token, represented by policy id and token name" }, { "ref":"opshin.prelude.Token.policy_id", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.Token.token_name", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.Token.CONSTR_ID", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.Nothing", -"url":59, +"url":61, "doc":"Nothing, can be used to signify non-importance of a parameter to a function Example value: Nothing()" }, { "ref":"opshin.prelude.Nothing.CONSTR_ID", -"url":59, +"url":61, "doc":"" }, { "ref":"opshin.prelude.all_tokens_unlocked_from_address", -"url":59, +"url":61, "doc":"Returns how many tokens of specified type are unlocked from given address", "func":1 }, { "ref":"opshin.prelude.all_tokens_locked_at_address_with_datum", -"url":59, +"url":61, "doc":"Returns how many tokens of specified type are locked at then given address with the specified datum", "func":1 }, { "ref":"opshin.prelude.all_tokens_locked_at_address", -"url":59, +"url":61, "doc":"Returns how many tokens of specified type are locked at the given address", "func":1 }, { "ref":"opshin.prelude.resolve_spent_utxo", -"url":59, +"url":61, "doc":"Returns the UTxO whose spending should be validated", "func":1 }, { "ref":"opshin.prelude.resolve_datum_unsafe", -"url":59, +"url":61, "doc":"Returns the datum attached to a given transaction output, independent of whether it was inlined or embedded. Raises an exception if no datum was attached.", "func":1 }, { "ref":"opshin.prelude.resolve_datum", -"url":59, +"url":61, "doc":"Returns SomeOutputDatum with the datum attached to a given transaction output, independent of whether it was inlined or embedded, if there was an attached datum. Otherwise it returns NoOutputDatum.", "func":1 }, { "ref":"opshin.prelude.own_spent_utxo", -"url":59, +"url":61, "doc":"", "func":1 }, { "ref":"opshin.prelude.own_policy_id", -"url":59, +"url":61, "doc":"obtain the policy id for which this contract can validate minting/burning", "func":1 }, { "ref":"opshin.prelude.own_address", -"url":59, +"url":61, "doc":"Computes the spending script address corresponding to the given policy ID", "func":1 }, { "ref":"opshin.prelude.token_present_in_inputs", -"url":59, +"url":61, "doc":"Returns whether the given token is spent in one of the inputs of the transaction", "func":1 } diff --git a/docs/opshin/compiler.html b/docs/opshin/compiler.html index 61e5e99d..3d1a0023 100644 --- a/docs/opshin/compiler.html +++ b/docs/opshin/compiler.html @@ -76,6 +76,8 @@

Module opshin.compiler

from .rewrite.rewrite_augassign import RewriteAugAssign from .rewrite.rewrite_cast_condition import RewriteConditions from .rewrite.rewrite_comparison_chaining import RewriteComparisonChaining +from .rewrite.rewrite_empty_dicts import RewriteEmptyDicts +from .rewrite.rewrite_empty_lists import RewriteEmptyLists from .rewrite.rewrite_forbidden_overwrites import RewriteForbiddenOverwrites from .rewrite.rewrite_forbidden_return import RewriteForbiddenReturn from .rewrite.rewrite_import import RewriteImport @@ -113,11 +115,6 @@

Module opshin.compiler

Or: plt.Or, } -UnaryOpMap = { - Not: {BoolInstanceType: plt.Not}, - USub: {IntegerInstanceType: lambda x: plt.SubtractInteger(plt.Integer(0), x)}, -} - def rec_constant_map_data(c): if isinstance(c, bool): @@ -276,13 +273,11 @@

Module opshin.compiler

return ops def visit_UnaryOp(self, node: TypedUnaryOp) -> plt.AST: - opmap = UnaryOpMap.get(type(node.op)) - assert opmap is not None, f"Operator {type(node.op)} is not supported" - op = opmap.get(node.operand.typ) - assert ( - op is not None - ), f"Operator {type(node.op)} is not supported for type {node.operand.typ}" - return op(self.visit(node.operand)) + op = node.operand.typ.unop(node.op) + return plt.Apply( + op, + self.visit(node.operand), + ) def visit_Compare(self, node: TypedCompare) -> plt.AST: assert len(node.ops) == 1, "Only single comparisons are supported" @@ -1046,6 +1041,57 @@

Module opshin.compiler

empty_list_con, ) + def visit_DictComp(self, node: TypedDictComp) -> plt.AST: + assert len(node.generators) == 1, "Currently only one generator supported" + gen = node.generators[0] + assert isinstance(gen.iter.typ, InstanceType), "Only lists are valid generators" + assert isinstance(gen.iter.typ.typ, ListType), "Only lists are valid generators" + assert isinstance( + gen.target, Name + ), "Can only assign value to singleton element" + lst = self.visit(gen.iter) + ifs = None + for ifexpr in gen.ifs: + if ifs is None: + ifs = self.visit(ifexpr) + else: + ifs = plt.And(ifs, self.visit(ifexpr)) + map_fun = OLambda( + ["x"], + plt.Let( + [(gen.target.id, plt.Delay(OVar("x")))], + plt.MkPairData( + transform_output_map(node.key.typ)( + self.visit(node.key), + ), + transform_output_map(node.value.typ)( + self.visit(node.value), + ), + ), + ), + ) + empty_list_con = plt.EmptyDataPairList() + if ifs is not None: + filter_fun = OLambda( + ["x"], + plt.Let( + [(gen.target.id, plt.Delay(OVar("x")))], + ifs, + ), + ) + return plt.MapFilterList( + lst, + filter_fun, + map_fun, + empty_list_con, + ) + else: + return plt.MapList( + lst, + map_fun, + empty_list_con, + ) + def visit_FormattedValue(self, node: TypedFormattedValue) -> plt.AST: return plt.Apply( node.value.typ.stringify(), @@ -1095,6 +1141,8 @@

Module opshin.compiler

# The type inference needs to be run after complex python operations were rewritten AggressiveTypeInferencer(allow_isinstance_anything), # Rewrites that circumvent the type inference or use its results + RewriteEmptyLists(), + RewriteEmptyDicts(), RewriteImportUPLCBuiltins(), RewriteInjectBuiltinsConstr(), RewriteRemoveTypeStuff(), @@ -1166,6 +1214,8 @@

Functions

# The type inference needs to be run after complex python operations were rewritten AggressiveTypeInferencer(allow_isinstance_anything), # Rewrites that circumvent the type inference or use its results + RewriteEmptyLists(), + RewriteEmptyDicts(), RewriteImportUPLCBuiltins(), RewriteInjectBuiltinsConstr(), RewriteRemoveTypeStuff(), @@ -1443,13 +1493,11 @@

Methods

return ops def visit_UnaryOp(self, node: TypedUnaryOp) -> plt.AST: - opmap = UnaryOpMap.get(type(node.op)) - assert opmap is not None, f"Operator {type(node.op)} is not supported" - op = opmap.get(node.operand.typ) - assert ( - op is not None - ), f"Operator {type(node.op)} is not supported for type {node.operand.typ}" - return op(self.visit(node.operand)) + op = node.operand.typ.unop(node.op) + return plt.Apply( + op, + self.visit(node.operand), + ) def visit_Compare(self, node: TypedCompare) -> plt.AST: assert len(node.ops) == 1, "Only single comparisons are supported" @@ -2213,6 +2261,57 @@

Methods

empty_list_con, ) + def visit_DictComp(self, node: TypedDictComp) -> plt.AST: + assert len(node.generators) == 1, "Currently only one generator supported" + gen = node.generators[0] + assert isinstance(gen.iter.typ, InstanceType), "Only lists are valid generators" + assert isinstance(gen.iter.typ.typ, ListType), "Only lists are valid generators" + assert isinstance( + gen.target, Name + ), "Can only assign value to singleton element" + lst = self.visit(gen.iter) + ifs = None + for ifexpr in gen.ifs: + if ifs is None: + ifs = self.visit(ifexpr) + else: + ifs = plt.And(ifs, self.visit(ifexpr)) + map_fun = OLambda( + ["x"], + plt.Let( + [(gen.target.id, plt.Delay(OVar("x")))], + plt.MkPairData( + transform_output_map(node.key.typ)( + self.visit(node.key), + ), + transform_output_map(node.value.typ)( + self.visit(node.value), + ), + ), + ), + ) + empty_list_con = plt.EmptyDataPairList() + if ifs is not None: + filter_fun = OLambda( + ["x"], + plt.Let( + [(gen.target.id, plt.Delay(OVar("x")))], + ifs, + ), + ) + return plt.MapFilterList( + lst, + filter_fun, + map_fun, + empty_list_con, + ) + else: + return plt.MapList( + lst, + map_fun, + empty_list_con, + ) + def visit_FormattedValue(self, node: TypedFormattedValue) -> plt.AST: return plt.Apply( node.value.typ.stringify(), @@ -2549,6 +2648,67 @@

Methods

return l +
+def visit_DictComp(self, node: TypedDictComp) ‑> pluthon.pluthon_ast.AST +
+
+
+
+ +Expand source code + +
def visit_DictComp(self, node: TypedDictComp) -> plt.AST:
+    assert len(node.generators) == 1, "Currently only one generator supported"
+    gen = node.generators[0]
+    assert isinstance(gen.iter.typ, InstanceType), "Only lists are valid generators"
+    assert isinstance(gen.iter.typ.typ, ListType), "Only lists are valid generators"
+    assert isinstance(
+        gen.target, Name
+    ), "Can only assign value to singleton element"
+    lst = self.visit(gen.iter)
+    ifs = None
+    for ifexpr in gen.ifs:
+        if ifs is None:
+            ifs = self.visit(ifexpr)
+        else:
+            ifs = plt.And(ifs, self.visit(ifexpr))
+    map_fun = OLambda(
+        ["x"],
+        plt.Let(
+            [(gen.target.id, plt.Delay(OVar("x")))],
+            plt.MkPairData(
+                transform_output_map(node.key.typ)(
+                    self.visit(node.key),
+                ),
+                transform_output_map(node.value.typ)(
+                    self.visit(node.value),
+                ),
+            ),
+        ),
+    )
+    empty_list_con = plt.EmptyDataPairList()
+    if ifs is not None:
+        filter_fun = OLambda(
+            ["x"],
+            plt.Let(
+                [(gen.target.id, plt.Delay(OVar("x")))],
+                ifs,
+            ),
+        )
+        return plt.MapFilterList(
+            lst,
+            filter_fun,
+            map_fun,
+            empty_list_con,
+        )
+    else:
+        return plt.MapList(
+            lst,
+            map_fun,
+            empty_list_con,
+        )
+
+
def visit_Expr(self, node: TypedExpr) ‑> Callable[[pluthon.pluthon_ast.AST], pluthon.pluthon_ast.AST]
@@ -3312,13 +3472,11 @@

Methods

Expand source code
def visit_UnaryOp(self, node: TypedUnaryOp) -> plt.AST:
-    opmap = UnaryOpMap.get(type(node.op))
-    assert opmap is not None, f"Operator {type(node.op)} is not supported"
-    op = opmap.get(node.operand.typ)
-    assert (
-        op is not None
-    ), f"Operator {type(node.op)} is not supported for type {node.operand.typ}"
-    return op(self.visit(node.operand))
+ op = node.operand.typ.unop(node.op) + return plt.Apply( + op, + self.visit(node.operand), + )
@@ -3491,6 +3649,7 @@

visit_Compare
  • visit_Constant
  • visit_Dict
  • +
  • visit_DictComp
  • visit_Expr
  • visit_For
  • visit_FormattedValue
  • diff --git a/docs/opshin/fun_impls.html b/docs/opshin/fun_impls.html index c1f1d472..6a21a0d8 100644 --- a/docs/opshin/fun_impls.html +++ b/docs/opshin/fun_impls.html @@ -382,37 +382,52 @@

    Module opshin.fun_impls

    len = "len" max = OLambda( ["xs"], - plt.FoldList( - plt.TailList(OVar("xs")), - OLambda( - ["x", "a"], - plt.IfThenElse( - plt.LessThanInteger(OVar("a"), OVar("x")), - OVar("x"), - OVar("a"), + plt.IteNullList( + OVar("xs"), + plt.TraceError("ValueError: max() arg is an empty sequence"), + plt.FoldList( + plt.TailList(OVar("xs")), + OLambda( + ["x", "a"], + plt.IfThenElse( + plt.LessThanInteger(OVar("a"), OVar("x")), + OVar("x"), + OVar("a"), + ), ), + plt.HeadList(OVar("xs")), ), - plt.HeadList(OVar("xs")), ), ) min = OLambda( ["xs"], - plt.FoldList( - plt.TailList(OVar("xs")), - OLambda( - ["x", "a"], - plt.IfThenElse( - plt.LessThanInteger(OVar("a"), OVar("x")), - OVar("a"), - OVar("x"), + plt.IteNullList( + OVar("xs"), + plt.TraceError("ValueError: min() arg is an empty sequence"), + plt.FoldList( + plt.TailList(OVar("xs")), + OLambda( + ["x", "a"], + plt.IfThenElse( + plt.LessThanInteger(OVar("a"), OVar("x")), + OVar("a"), + OVar("x"), + ), ), + plt.HeadList(OVar("xs")), ), - plt.HeadList(OVar("xs")), ), ) print = "print" # NOTE: only correctly defined for positive y - pow = OLambda(["x", "y"], PowImpl(OVar("x"), OVar("y"))) + pow = OLambda( + ["x", "y"], + plt.Ite( + plt.LessThanInteger(OVar("y"), plt.Integer(0)), + plt.TraceError("Negative exponentiation is not supported"), + PowImpl(OVar("x"), OVar("y")), + ), + ) oct = OLambda( ["x"], plt.DecodeUtf8( @@ -996,37 +1011,52 @@

    Methods

    len = "len" max = OLambda( ["xs"], - plt.FoldList( - plt.TailList(OVar("xs")), - OLambda( - ["x", "a"], - plt.IfThenElse( - plt.LessThanInteger(OVar("a"), OVar("x")), - OVar("x"), - OVar("a"), + plt.IteNullList( + OVar("xs"), + plt.TraceError("ValueError: max() arg is an empty sequence"), + plt.FoldList( + plt.TailList(OVar("xs")), + OLambda( + ["x", "a"], + plt.IfThenElse( + plt.LessThanInteger(OVar("a"), OVar("x")), + OVar("x"), + OVar("a"), + ), ), + plt.HeadList(OVar("xs")), ), - plt.HeadList(OVar("xs")), ), ) min = OLambda( ["xs"], - plt.FoldList( - plt.TailList(OVar("xs")), - OLambda( - ["x", "a"], - plt.IfThenElse( - plt.LessThanInteger(OVar("a"), OVar("x")), - OVar("a"), - OVar("x"), + plt.IteNullList( + OVar("xs"), + plt.TraceError("ValueError: min() arg is an empty sequence"), + plt.FoldList( + plt.TailList(OVar("xs")), + OLambda( + ["x", "a"], + plt.IfThenElse( + plt.LessThanInteger(OVar("a"), OVar("x")), + OVar("a"), + OVar("x"), + ), ), + plt.HeadList(OVar("xs")), ), - plt.HeadList(OVar("xs")), ), ) print = "print" # NOTE: only correctly defined for positive y - pow = OLambda(["x", "y"], PowImpl(OVar("x"), OVar("y"))) + pow = OLambda( + ["x", "y"], + plt.Ite( + plt.LessThanInteger(OVar("y"), plt.Integer(0)), + plt.TraceError("Negative exponentiation is not supported"), + PowImpl(OVar("x"), OVar("y")), + ), + ) oct = OLambda( ["x"], plt.DecodeUtf8( diff --git a/docs/opshin/optimize/optimize_const_folding.html b/docs/opshin/optimize/optimize_const_folding.html index b2dffbaf..bb67a25f 100644 --- a/docs/opshin/optimize/optimize_const_folding.html +++ b/docs/opshin/optimize/optimize_const_folding.html @@ -407,7 +407,7 @@

    Module opshin.optimize.optimize_const_folding

    Methods if any( isinstance(node_eval, t) for t in ACCEPTED_ATOMIC_TYPES + [list, dict, PlutusData] - ): + ) and not (node_eval == [] or node_eval == {}): new_node = Constant(node_eval, None) copy_location(new_node, node) return new_node @@ -982,7 +982,7 @@

    Methods

    if any( isinstance(node_eval, t) for t in ACCEPTED_ATOMIC_TYPES + [list, dict, PlutusData] - ): + ) and not (node_eval == [] or node_eval == {}): new_node = Constant(node_eval, None) copy_location(new_node, node) return new_node diff --git a/docs/opshin/rewrite/index.html b/docs/opshin/rewrite/index.html index 3de0322c..9d0b3356 100644 --- a/docs/opshin/rewrite/index.html +++ b/docs/opshin/rewrite/index.html @@ -80,6 +80,14 @@

    Sub-modules

    +
    opshin.rewrite.rewrite_empty_dicts
    +
    +
    +
    +
    opshin.rewrite.rewrite_empty_lists
    +
    +
    +
    opshin.rewrite.rewrite_forbidden_overwrites
    @@ -222,6 +230,8 @@

    Index

  • opshin.rewrite.rewrite_augassign
  • opshin.rewrite.rewrite_cast_condition
  • opshin.rewrite.rewrite_comparison_chaining
  • +
  • opshin.rewrite.rewrite_empty_dicts
  • +
  • opshin.rewrite.rewrite_empty_lists
  • opshin.rewrite.rewrite_forbidden_overwrites
  • opshin.rewrite.rewrite_forbidden_return
  • opshin.rewrite.rewrite_import
  • diff --git a/docs/opshin/rewrite/rewrite_empty_dicts.html b/docs/opshin/rewrite/rewrite_empty_dicts.html new file mode 100644 index 00000000..682958b2 --- /dev/null +++ b/docs/opshin/rewrite/rewrite_empty_dicts.html @@ -0,0 +1,300 @@ + + + + + + + + +opshin.rewrite.rewrite_empty_dicts API documentation + + + + + + + + + + + +
    + + + + +
    +
    +

    Module opshin.rewrite.rewrite_empty_dicts

    +
    +
    +
    + +Expand source code + +
    import re
    +from copy import copy
    +from typing import Optional
    +from enum import Enum
    +
    +from ..util import CompilingNodeTransformer
    +from ..typed_ast import *
    +
    +"""
    +Replaces empty dicts with UPLC constants of empty data pairs
    +"""
    +
    +
    +class RewriteEmptyDicts(CompilingNodeTransformer):
    +    step = "Rewrite empty lists to uplc empty lists"
    +
    +    def visit_Dict(self, node: TypedDict):
    +        if node.keys or node.values:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +    def visit_Constant(self, node: TypedConstant):
    +        if node.value != {}:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Classes

    +
    +
    +class RewriteEmptyDicts +
    +
    +

    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=Constant(value=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 RewriteEmptyDicts(CompilingNodeTransformer):
    +    step = "Rewrite empty lists to uplc empty lists"
    +
    +    def visit_Dict(self, node: TypedDict):
    +        if node.keys or node.values:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +    def visit_Constant(self, node: TypedConstant):
    +        if node.value != {}:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var step
    +
    +
    +
    +
    +

    Methods

    +
    +
    +def visit(self, node) +
    +
    +

    +Inherited from: +CompilingNodeTransformer.visit +

    +

    Visit a node.

    +
    +
    +def visit_Constant(self, node: TypedConstant) +
    +
    +
    +
    + +Expand source code + +
    def visit_Constant(self, node: TypedConstant):
    +    if node.value != {}:
    +        return node
    +    return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +
    +
    +def visit_Dict(self, node: TypedDict) +
    +
    +
    +
    + +Expand source code + +
    def visit_Dict(self, node: TypedDict):
    +    if node.keys or node.values:
    +        return node
    +    return RawPlutoExpr(typ=node.typ, expr=plt.MkNilPairData(plt.Unit()))
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/docs/opshin/rewrite/rewrite_empty_lists.html b/docs/opshin/rewrite/rewrite_empty_lists.html new file mode 100644 index 00000000..8f692fee --- /dev/null +++ b/docs/opshin/rewrite/rewrite_empty_lists.html @@ -0,0 +1,300 @@ + + + + + + + + +opshin.rewrite.rewrite_empty_lists API documentation + + + + + + + + + + + +
    + + + + +
    +
    +

    Module opshin.rewrite.rewrite_empty_lists

    +
    +
    +
    + +Expand source code + +
    import re
    +from copy import copy
    +from typing import Optional
    +from enum import Enum
    +
    +from ..util import CompilingNodeTransformer
    +from ..typed_ast import *
    +
    +"""
    +Replaces empty lists with UPLC constants of empty lists
    +"""
    +
    +
    +class RewriteEmptyLists(CompilingNodeTransformer):
    +    step = "Rewrite empty lists to uplc empty lists"
    +
    +    def visit_List(self, node: TypedList):
    +        if node.elts:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +    def visit_Constant(self, node: TypedConstant):
    +        if node.value != []:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Classes

    +
    +
    +class RewriteEmptyLists +
    +
    +

    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=Constant(value=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 RewriteEmptyLists(CompilingNodeTransformer):
    +    step = "Rewrite empty lists to uplc empty lists"
    +
    +    def visit_List(self, node: TypedList):
    +        if node.elts:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +    def visit_Constant(self, node: TypedConstant):
    +        if node.value != []:
    +            return node
    +        return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var step
    +
    +
    +
    +
    +

    Methods

    +
    +
    +def visit(self, node) +
    +
    +

    +Inherited from: +CompilingNodeTransformer.visit +

    +

    Visit a node.

    +
    +
    +def visit_Constant(self, node: TypedConstant) +
    +
    +
    +
    + +Expand source code + +
    def visit_Constant(self, node: TypedConstant):
    +    if node.value != []:
    +        return node
    +    return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +
    +
    +def visit_List(self, node: TypedList) +
    +
    +
    +
    + +Expand source code + +
    def visit_List(self, node: TypedList):
    +    if node.elts:
    +        return node
    +    return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/docs/opshin/rewrite/rewrite_import_hashlib.html b/docs/opshin/rewrite/rewrite_import_hashlib.html index b6a3dbc4..06e752bb 100644 --- a/docs/opshin/rewrite/rewrite_import_hashlib.html +++ b/docs/opshin/rewrite/rewrite_import_hashlib.html @@ -319,6 +319,26 @@

    Methods

    Returns a stringified version of the object …

    +
    +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
    +
    +

    +Inherited from: +ClassType.unop +

    +

    Implements a unary operation on self

    +
    +
    +def unop_type(self, unop: ast.unaryop) ‑> Type +
    +
    +

    +Inherited from: +ClassType.unop_type +

    +

    Type of a unary operation on self.

    +
    @@ -563,6 +583,8 @@

    constr_type
  • copy_only_attributes
  • stringify
  • +
  • unop
  • +
  • unop_type
  • diff --git a/docs/opshin/tests/test_builtins.html b/docs/opshin/tests/test_builtins.html index 3096a4ec..fab5681f 100644 --- a/docs/opshin/tests/test_builtins.html +++ b/docs/opshin/tests/test_builtins.html @@ -338,6 +338,19 @@

    Module opshin.tests.test_builtins

    ret = None self.assertEqual(ret, exp, "pow returned wrong value") + @given(x=st.integers(), y=st.integers(min_value=-20, max_value=-1)) + def test_neg_pow(self, x: int, y: int): + source_code = """ +def validator(x: int, y: int) -> int: + return pow(x, y) % 10000000000 + """ + try: + eval_uplc_value(source_code, x, y) + fail = True + except Exception: + fail = False + self.assertFalse(fail, "pow worked on negative exponent") + @given(x=st.integers()) @example(0) @example(-1) @@ -778,6 +791,19 @@

    Classes

    ret = None self.assertEqual(ret, exp, "pow returned wrong value") + @given(x=st.integers(), y=st.integers(min_value=-20, max_value=-1)) + def test_neg_pow(self, x: int, y: int): + source_code = """ +def validator(x: int, y: int) -> int: + return pow(x, y) % 10000000000 + """ + try: + eval_uplc_value(source_code, x, y) + fail = True + except Exception: + fail = False + self.assertFalse(fail, "pow worked on negative exponent") + @given(x=st.integers()) @example(0) @example(-1) @@ -1463,6 +1489,29 @@

    Methods

    self.assertEqual(ret, exp, "min returned wrong value")
    +
    +def test_neg_pow(self) ‑> None +
    +
    +
    +
    + +Expand source code + +
        @given(x=st.integers(), y=st.integers(min_value=-20, max_value=-1))
    +    def test_neg_pow(self, x: int, y: int):
    +        source_code = """
    +def validator(x: int, y: int) -> int:
    +    return pow(x, y) % 10000000000
    +        """
    +        try:
    +            eval_uplc_value(source_code, x, y)
    +            fail = True
    +        except Exception:
    +            fail = False
    +        self.assertFalse(fail, "pow worked on negative exponent")
    +
    +
    def test_oct(self) ‑> None
    @@ -1729,6 +1778,7 @@

    test_len_tuples

  • test_max
  • test_min
  • +
  • test_neg_pow
  • test_oct
  • test_pow
  • test_print_compile
  • diff --git a/docs/opshin/tests/test_misc.html b/docs/opshin/tests/test_misc.html index 7f85af7c..9618e9de 100644 --- a/docs/opshin/tests/test_misc.html +++ b/docs/opshin/tests/test_misc.html @@ -728,6 +728,30 @@

    Module opshin.tests.test_misc

    "List comprehension incorrectly evaluated", ) + def test_dict_comprehension_even(self): + input_file = "examples/dict_comprehensions.py" + with open(input_file) as fp: + source_code = fp.read() + ret = eval_uplc_value(source_code, 8, 1) + ret = {x.value: y.value for x, y in ret.items()} + self.assertEqual( + ret, + {x: x * x for x in range(8) if x % 2 == 0}, + "Dict comprehension incorrectly evaluated", + ) + + def test_dict_comprehension_all(self): + input_file = "examples/dict_comprehensions.py" + with open(input_file) as fp: + source_code = fp.read() + ret = eval_uplc_value(source_code, 8, 0) + ret = {x.value: y.value for x, y in ret.items()} + self.assertEqual( + ret, + {x: x * x for x in range(8)}, + "Dict comprehension incorrectly evaluated", + ) + @hypothesis.given(some_output) def test_union_type_attr_access_all_records(self, x): source_code = """ @@ -2693,7 +2717,74 @@

    Module opshin.tests.test_misc

    return 0 """ res = eval_uplc_value(source_code, 1) - self.assertEqual(res, 0, "Invalid return")
    + self.assertEqual(res, 0, "Invalid return") + + def test_empty_list_int(self): + source_code = """ +def validator(_: None) -> List[int]: + a: List[int] = [] + return a + [1] +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual(res, [uplc.PlutusInteger(1)]) + + def test_empty_list_data(self): + source_code = """ +from opshin.prelude import * + +def validator(_: None) -> List[Token]: + a: List[Token] = [] + return a + [Token(b"", b"")] +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual( + res, + [ + uplc.PlutusConstr( + 0, [uplc.PlutusByteString(b""), uplc.PlutusByteString(b"")] + ) + ], + ) + + def test_empty_list_int_constant_folding(self): + source_code = """ +def validator(_: None) -> List[int]: + a: List[int] = [] + return a +""" + res = eval_uplc_value(source_code, Unit(), constant_folding=True) + self.assertEqual(res, []) + + def test_empty_dict_int_int(self): + source_code = """ +def validator(_: None) -> Dict[int, int]: + a: Dict[int, int] = {} + return a +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual(res, {}) + + def test_empty_dict_int_int_constant_folding(self): + source_code = """ +def validator(_: None) -> Dict[int, int]: + a: Dict[int, int] = {} + return a +""" + res = eval_uplc_value(source_code, Unit(), constant_folding=True) + self.assertEqual(res, {}) + + def test_empty_dict_displaced_constant_folding(self): + source_code = """ +from typing import Dict, List, Union + +VAR: Dict[bytes, int] = {} + +def validator(b: Dict[int, Dict[bytes, int]]) -> Dict[bytes, int]: + a = b.get(0, VAR) + return a + """ + res = eval_uplc_value(source_code, {1: {b"": 0}}, constant_folding=True) + self.assertEqual(res, {})
    @@ -3429,6 +3520,30 @@

    Class variables

    "List comprehension incorrectly evaluated", ) + def test_dict_comprehension_even(self): + input_file = "examples/dict_comprehensions.py" + with open(input_file) as fp: + source_code = fp.read() + ret = eval_uplc_value(source_code, 8, 1) + ret = {x.value: y.value for x, y in ret.items()} + self.assertEqual( + ret, + {x: x * x for x in range(8) if x % 2 == 0}, + "Dict comprehension incorrectly evaluated", + ) + + def test_dict_comprehension_all(self): + input_file = "examples/dict_comprehensions.py" + with open(input_file) as fp: + source_code = fp.read() + ret = eval_uplc_value(source_code, 8, 0) + ret = {x.value: y.value for x, y in ret.items()} + self.assertEqual( + ret, + {x: x * x for x in range(8)}, + "Dict comprehension incorrectly evaluated", + ) + @hypothesis.given(some_output) def test_union_type_attr_access_all_records(self, x): source_code = """ @@ -5394,7 +5509,74 @@

    Class variables

    return 0 """ res = eval_uplc_value(source_code, 1) - self.assertEqual(res, 0, "Invalid return") + self.assertEqual(res, 0, "Invalid return") + + def test_empty_list_int(self): + source_code = """ +def validator(_: None) -> List[int]: + a: List[int] = [] + return a + [1] +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual(res, [uplc.PlutusInteger(1)]) + + def test_empty_list_data(self): + source_code = """ +from opshin.prelude import * + +def validator(_: None) -> List[Token]: + a: List[Token] = [] + return a + [Token(b"", b"")] +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual( + res, + [ + uplc.PlutusConstr( + 0, [uplc.PlutusByteString(b""), uplc.PlutusByteString(b"")] + ) + ], + ) + + def test_empty_list_int_constant_folding(self): + source_code = """ +def validator(_: None) -> List[int]: + a: List[int] = [] + return a +""" + res = eval_uplc_value(source_code, Unit(), constant_folding=True) + self.assertEqual(res, []) + + def test_empty_dict_int_int(self): + source_code = """ +def validator(_: None) -> Dict[int, int]: + a: Dict[int, int] = {} + return a +""" + res = eval_uplc_value(source_code, Unit()) + self.assertEqual(res, {}) + + def test_empty_dict_int_int_constant_folding(self): + source_code = """ +def validator(_: None) -> Dict[int, int]: + a: Dict[int, int] = {} + return a +""" + res = eval_uplc_value(source_code, Unit(), constant_folding=True) + self.assertEqual(res, {}) + + def test_empty_dict_displaced_constant_folding(self): + source_code = """ +from typing import Dict, List, Union + +VAR: Dict[bytes, int] = {} + +def validator(b: Dict[int, Dict[bytes, int]]) -> Dict[bytes, int]: + a = b.get(0, VAR) + return a + """ + res = eval_uplc_value(source_code, {1: {b"": 0}}, constant_folding=True) + self.assertEqual(res, {})

    Ancestors

    @@ -977,6 +1080,24 @@

    Classes

    ret = eval_uplc_value(source_code, x) self.assertEqual(ret, -x, "not returned wrong value") + @given(x=st.integers()) + def test_uadd_int(self, x): + source_code = """ +def validator(x: int) -> int: + return +x + """ + ret = eval_uplc_value(source_code, x) + self.assertEqual(ret, +x, "not returned wrong value") + + @given(x=st.integers()) + def test_not_int(self, x): + source_code = """ +def validator(x: int) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, x) + self.assertEqual(bool(ret), not x, "not returned wrong value") + @given(x=st.integers(), y=st.integers()) def test_add_int(self, x, y): source_code = """ @@ -1045,6 +1166,19 @@

    Classes

    ret = eval_uplc_value(source_code, x, y) self.assertEqual(ret, x**y, "** returned wrong value") + @given(x=st.integers(), y=st.integers(min_value=-20, max_value=-1)) + def test_neg_pow_int(self, x, y): + source_code = """ +def validator(x: int, y: int) -> int: + return x ** y + """ + try: + eval_uplc_value(source_code, x, y) + fail = True + except Exception: + fail = False + self.assertFalse(fail, "** worked with negative exponent") + @given(x=st.binary(), y=st.binary()) def test_add_bytes(self, x, y): source_code = """ @@ -1317,6 +1451,15 @@

    Classes

    ret = eval_uplc_value(source_code, xs, y) self.assertEqual(ret, y in xs, "list in returned wrong value") + @given(x=st.lists(st.integers())) + def test_not_list(self, x): + source_code = """ +def validator(x: List[int]) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, x) + self.assertEqual(bool(ret), not x, "not returned wrong value") + @given(x=st.binary(), y=st.binary()) def test_eq_bytes(self, x, y): source_code = """ @@ -1327,7 +1470,7 @@

    Classes

    self.assertEqual(ret, x == y, "bytes eq returned wrong value") @given(x=st.integers(), y=st.integers()) - def test_eq_bytes(self, x, y): + def test_eq_int(self, x, y): source_code = """ def validator(x: int, y: int) -> bool: return x == y @@ -1353,6 +1496,17 @@

    Classes

    ret = eval_uplc_value(source_code, x, y) self.assertEqual(ret, x == y, "bool eq returned wrong value") + @given(x=uplc_data, y=uplc_data) + def test_eq_data(self, x, y): + source_code = """ +from opshin.prelude import * + +def validator(x: Anything, y: Anything) -> bool: + return x == y + """ + ret = eval_uplc_value(source_code, x, y) + self.assertEqual(ret, x == y, "any eq returned wrong value") + @given(x=st.integers(min_value=0, max_value=150), y=st.text()) def test_mul_int_str(self, x, y): source_code = """ @@ -1600,6 +1754,32 @@

    Classes

    ret, exp, "integer list string formatting returned wrong value" ) + @given(x=st.dictionaries(st.integers(), st.integers())) + def test_not_dict(self, x): + source_code = """ +def validator(x: Dict[int, int]) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, x) + self.assertEqual(bool(ret), not x, "not returned wrong value") + + @given(xs=st.dictionaries(st.integers(), st.integers()), y=st.integers()) + def test_index_dict(self, xs, y): + source_code = """ +from typing import Dict, List, Union +def validator(x: Dict[int, int], y: int) -> int: + return x[y] + """ + try: + exp = xs[y] + except KeyError: + exp = None + try: + ret = eval_uplc_value(source_code, xs, y) + except Exception as e: + ret = None + self.assertEqual(ret, exp, "list index returned wrong value") + @given(xs=st.dictionaries(formattable_text, st.integers())) @example(dict()) @example({"": 0}) @@ -1639,7 +1819,33 @@

    Classes

    else: self.assertEqual( ret, exp, "raw cbor string formatting returned wrong value" - ) + ) + + @given(x=st.text()) + def test_not_string(self, x): + source_code = """ +def validator(x: str) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, x.encode("utf8")) + self.assertEqual(bool(ret), not x, "not returned wrong value") + + @given(x=st.binary()) + def test_not_bytes(self, x): + source_code = """ +def validator(x: bytes) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, x) + self.assertEqual(bool(ret), not x, "not returned wrong value") + + def test_not_unit(self): + source_code = """ +def validator(x: None) -> bool: + return not x + """ + ret = eval_uplc_value(source_code, uplc.BuiltinUnit()) + self.assertEqual(bool(ret), not None, "not returned wrong value")

    Ancestors

      @@ -1804,9 +2010,49 @@

      Methods

      Expand source code -
          @given(x=st.integers(), y=st.integers())
      +
          @given(x=st.binary(), y=st.binary())
           def test_eq_bytes(self, x, y):
               source_code = """
      +def validator(x: bytes, y: bytes) -> bool:
      +    return x == y
      +            """
      +        ret = eval_uplc_value(source_code, x, y)
      +        self.assertEqual(ret, x == y, "bytes eq returned wrong value")
      + + +
      +def test_eq_data(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=uplc_data, y=uplc_data)
      +    def test_eq_data(self, x, y):
      +        source_code = """
      +from opshin.prelude import *
      +
      +def validator(x: Anything, y: Anything) -> bool:
      +    return x == y
      +            """
      +        ret = eval_uplc_value(source_code, x, y)
      +        self.assertEqual(ret, x == y, "any eq returned wrong value")
      +
      +
      +
      +def test_eq_int(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.integers(), y=st.integers())
      +    def test_eq_int(self, x, y):
      +        source_code = """
       def validator(x: int, y: int) -> bool:
           return x == y
                   """
      @@ -2291,6 +2537,33 @@ 

      Methods

      self.assertEqual(ret, exp, "byte index returned wrong value")
      +
      +def test_index_dict(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(xs=st.dictionaries(st.integers(), st.integers()), y=st.integers())
      +    def test_index_dict(self, xs, y):
      +        source_code = """
      +from typing import Dict, List, Union
      +def validator(x: Dict[int, int], y: int) -> int:
      +    return x[y]
      +            """
      +        try:
      +            exp = xs[y]
      +        except KeyError:
      +            exp = None
      +        try:
      +            ret = eval_uplc_value(source_code, xs, y)
      +        except Exception as e:
      +            ret = None
      +        self.assertEqual(ret, exp, "list index returned wrong value")
      +
      +
      def test_index_list(self) ‑> None
      @@ -2441,6 +2714,29 @@

      Methods

      self.assertEqual(ret.decode("utf8"), x * y, "* returned wrong value")
      +
      +def test_neg_pow_int(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.integers(), y=st.integers(min_value=-20, max_value=-1))
      +    def test_neg_pow_int(self, x, y):
      +        source_code = """
      +def validator(x: int, y: int) -> int:
      +    return x ** y
      +            """
      +        try:
      +            eval_uplc_value(source_code, x, y)
      +            fail = True
      +        except Exception:
      +            fail = False
      +        self.assertFalse(fail, "** worked with negative exponent")
      +
      +
      def test_not_bool(self) ‑> None
      @@ -2460,6 +2756,119 @@

      Methods

      self.assertEqual(bool(ret), not x, "not returned wrong value") +
      +def test_not_bytes(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.binary())
      +    def test_not_bytes(self, x):
      +        source_code = """
      +def validator(x: bytes) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, x)
      +        self.assertEqual(bool(ret), not x, "not returned wrong value")
      +
      +
      +
      +def test_not_dict(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.dictionaries(st.integers(), st.integers()))
      +    def test_not_dict(self, x):
      +        source_code = """
      +def validator(x: Dict[int, int]) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, x)
      +        self.assertEqual(bool(ret), not x, "not returned wrong value")
      +
      +
      +
      +def test_not_int(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.integers())
      +    def test_not_int(self, x):
      +        source_code = """
      +def validator(x: int) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, x)
      +        self.assertEqual(bool(ret), not x, "not returned wrong value")
      +
      +
      +
      +def test_not_list(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.lists(st.integers()))
      +    def test_not_list(self, x):
      +        source_code = """
      +def validator(x: List[int]) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, x)
      +        self.assertEqual(bool(ret), not x, "not returned wrong value")
      +
      +
      +
      +def test_not_string(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.text())
      +    def test_not_string(self, x):
      +        source_code = """
      +def validator(x: str) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, x.encode("utf8"))
      +        self.assertEqual(bool(ret), not x, "not returned wrong value")
      +
      +
      +
      +def test_not_unit(self) +
      +
      +
      +
      + +Expand source code + +
          def test_not_unit(self):
      +        source_code = """
      +def validator(x: None) -> bool:
      +    return not x
      +            """
      +        ret = eval_uplc_value(source_code, uplc.BuiltinUnit())
      +        self.assertEqual(bool(ret), not None, "not returned wrong value")
      +
      +
      def test_or_bool(self) ‑> None
      @@ -2789,6 +3198,25 @@

      Methods

      self.assertEqual(ret, x - y, "- returned wrong value") +
      +def test_uadd_int(self) ‑> None +
      +
      +
      +
      + +Expand source code + +
          @given(x=st.integers())
      +    def test_uadd_int(self, x):
      +        source_code = """
      +def validator(x: int) -> int:
      +    return +x
      +            """
      +        ret = eval_uplc_value(source_code, x)
      +        self.assertEqual(ret, +x, "not returned wrong value")
      +
      +
      def test_usub_int(self) ‑> None
      @@ -2896,6 +3324,8 @@

      test_div_int
    • test_eq_bool
    • test_eq_bytes
    • +
    • test_eq_data
    • +
    • test_eq_int
    • test_eq_str
    • test_fmt_any
    • test_fmt_bool
    • @@ -2915,6 +3345,7 @@

      test_in_list_bytes
    • test_in_list_int
    • test_index_bytes
    • +
    • test_index_dict
    • test_index_list
    • test_mod_int
    • test_mul_bytes_int
    • @@ -2922,7 +3353,14 @@

      test_mul_int_bytes
    • test_mul_int_str
    • test_mul_str_int
    • +
    • test_neg_pow_int
    • test_not_bool
    • +
    • test_not_bytes
    • +
    • test_not_dict
    • +
    • test_not_int
    • +
    • test_not_list
    • +
    • test_not_string
    • +
    • test_not_unit
    • test_or_bool
    • test_pow_int
    • test_slice_bytes
    • @@ -2934,6 +3372,7 @@

      test_slice_list_lower
    • test_slice_list_upper
    • test_sub_int
    • +
    • test_uadd_int
    • test_usub_int
    diff --git a/docs/opshin/tests/test_stdlib.html b/docs/opshin/tests/test_stdlib.html index 15671d6c..531f64cc 100644 --- a/docs/opshin/tests/test_stdlib.html +++ b/docs/opshin/tests/test_stdlib.html @@ -116,6 +116,28 @@

    Module opshin.tests.test_stdlib

    exp = None self.assertEqual(ret, exp, "dict[] returned wrong value") + @given(st.data()) + def test_list_index(self, data): + source_code = """ +def validator(x: List[int], z: int) -> int: + return x.index(z) + """ + xs = data.draw(st.lists(st.integers())) + z = data.draw( + st.one_of(st.sampled_from(xs), st.integers()) + if len(xs) > 0 + else st.integers() + ) + try: + ret = eval_uplc_value(source_code, xs, z) + except RuntimeError as e: + ret = None + try: + exp = xs.index(z) + except ValueError: + exp = None + self.assertEqual(ret, exp, "list.index returned wrong value") + @given(xs=st.dictionaries(st.integers(), st.binary())) def test_dict_keys(self, xs): source_code = """ @@ -384,6 +406,28 @@

    Classes

    exp = None self.assertEqual(ret, exp, "dict[] returned wrong value") + @given(st.data()) + def test_list_index(self, data): + source_code = """ +def validator(x: List[int], z: int) -> int: + return x.index(z) + """ + xs = data.draw(st.lists(st.integers())) + z = data.draw( + st.one_of(st.sampled_from(xs), st.integers()) + if len(xs) > 0 + else st.integers() + ) + try: + ret = eval_uplc_value(source_code, xs, z) + except RuntimeError as e: + ret = None + try: + exp = xs.index(z) + except ValueError: + exp = None + self.assertEqual(ret, exp, "list.index returned wrong value") + @given(xs=st.dictionaries(st.integers(), st.binary())) def test_dict_keys(self, xs): source_code = """ @@ -856,6 +900,38 @@

    Methods

    self.assertEqual(ret, list(xs.values()), "dict.keys returned wrong value") +
    +def test_list_index(self) ‑> None +
    +
    +
    +
    + +Expand source code + +
        @given(st.data())
    +    def test_list_index(self, data):
    +        source_code = """
    +def validator(x: List[int], z: int) -> int:
    +    return x.index(z)
    +            """
    +        xs = data.draw(st.lists(st.integers()))
    +        z = data.draw(
    +            st.one_of(st.sampled_from(xs), st.integers())
    +            if len(xs) > 0
    +            else st.integers()
    +        )
    +        try:
    +            ret = eval_uplc_value(source_code, xs, z)
    +        except RuntimeError as e:
    +            ret = None
    +        try:
    +            exp = xs.index(z)
    +        except ValueError:
    +            exp = None
    +        self.assertEqual(ret, exp, "list.index returned wrong value")
    +
    +
    def test_plutusdata_to_cbor(self) ‑> None
    @@ -1045,6 +1121,7 @@

    test_dict_keys
  • test_dict_subscript
  • test_dict_values
  • +
  • test_list_index
  • test_plutusdata_to_cbor
  • test_str_encode
  • test_union_to_cbor
  • diff --git a/docs/opshin/type_inference.html b/docs/opshin/type_inference.html index 66efa705..7cae0c99 100644 --- a/docs/opshin/type_inference.html +++ b/docs/opshin/type_inference.html @@ -152,7 +152,7 @@

    Module opshin.type_inference

    ), "Constant lists must contain elements of a single type only" return InstanceType(ListType(first_typ)) if isinstance(c, dict): - assert len(c) > 0, "Lists must be non-empty" + assert len(c) > 0, "Dicts must be non-empty" first_key_typ = constant_type(next(iter(c.keys()))) first_value_typ = constant_type(next(iter(c.values()))) assert all( @@ -497,8 +497,27 @@

    Module opshin.type_inference

    def visit_AnnAssign(self, node: AnnAssign) -> TypedAnnAssign: typed_ass = copy(node) - typed_ass.value: TypedExpression = self.visit(node.value) typed_ass.annotation = self.type_from_annotation(node.annotation) + if isinstance(typed_ass.annotation, ListType) and ( + (isinstance(node.value, Constant) and node.value.value == []) + or (isinstance(node.value, List) and node.value.elts == []) + ): + # Empty lists are only allowed in annotated assignments + typed_ass.value: TypedExpression = copy(node.value) + typed_ass.value.typ = InstanceType(typed_ass.annotation) + elif isinstance(typed_ass.annotation, DictType) and ( + (isinstance(node.value, Constant) and node.value.value == {}) + or ( + isinstance(node.value, Dict) + and node.value.keys == [] + and node.value.values == [] + ) + ): + # Empty lists are only allowed in annotated assignments + typed_ass.value: TypedExpression = copy(node.value) + typed_ass.value.typ = InstanceType(typed_ass.annotation) + else: + typed_ass.value: TypedExpression = self.visit(node.value) assert isinstance( node.target, Name ), "Can only assign to variable names, no type deconstruction" @@ -711,7 +730,7 @@

    Module opshin.type_inference

    def visit_UnaryOp(self, node: UnaryOp) -> TypedUnaryOp: tu = copy(node) tu.operand = self.visit(node.operand) - tu.typ = tu.operand.typ + tu.typ = tu.operand.typ.typ.unop_type(node.op).rettyp return tu def visit_Subscript(self, node: Subscript) -> TypedSubscript: @@ -976,6 +995,21 @@

    Module opshin.type_inference

    typed_listcomp.typ = InstanceType(ListType(typed_listcomp.elt.typ)) return typed_listcomp + def visit_DictComp(self, node: DictComp) -> TypedDictComp: + typed_dictcomp = copy(node) + # inside the comprehension is a seperate scope + self.enter_scope() + # first evaluate generators for assigned variables + typed_dictcomp.generators = [self.visit(s) for s in node.generators] + # then evaluate elements + typed_dictcomp.key = self.visit(node.key) + typed_dictcomp.value = self.visit(node.value) + self.exit_scope() + typed_dictcomp.typ = InstanceType( + DictType(typed_dictcomp.key.typ, typed_dictcomp.value.typ) + ) + return typed_dictcomp + def visit_FormattedValue(self, node: FormattedValue) -> TypedFormattedValue: typed_node = copy(node) typed_node.value = self.visit(node.value) @@ -1131,7 +1165,7 @@

    Module opshin.type_inference

    def visit_Return(self, node: Return) -> bool: assert ( self.func_rettyp >= node.typ - ), f"Function '{node.name}' annotated return type does not match actual return type" + ), f"Function annotated return type does not match actual return type" return True def check_fulfills(self, node: FunctionDef): @@ -1177,7 +1211,7 @@

    Functions

    ), "Constant lists must contain elements of a single type only" return InstanceType(ListType(first_typ)) if isinstance(c, dict): - assert len(c) > 0, "Lists must be non-empty" + assert len(c) > 0, "Dicts must be non-empty" first_key_typ = constant_type(next(iter(c.keys()))) first_value_typ = constant_type(next(iter(c.values()))) assert all( @@ -1542,8 +1576,27 @@

    Classes

    def visit_AnnAssign(self, node: AnnAssign) -> TypedAnnAssign: typed_ass = copy(node) - typed_ass.value: TypedExpression = self.visit(node.value) typed_ass.annotation = self.type_from_annotation(node.annotation) + if isinstance(typed_ass.annotation, ListType) and ( + (isinstance(node.value, Constant) and node.value.value == []) + or (isinstance(node.value, List) and node.value.elts == []) + ): + # Empty lists are only allowed in annotated assignments + typed_ass.value: TypedExpression = copy(node.value) + typed_ass.value.typ = InstanceType(typed_ass.annotation) + elif isinstance(typed_ass.annotation, DictType) and ( + (isinstance(node.value, Constant) and node.value.value == {}) + or ( + isinstance(node.value, Dict) + and node.value.keys == [] + and node.value.values == [] + ) + ): + # Empty lists are only allowed in annotated assignments + typed_ass.value: TypedExpression = copy(node.value) + typed_ass.value.typ = InstanceType(typed_ass.annotation) + else: + typed_ass.value: TypedExpression = self.visit(node.value) assert isinstance( node.target, Name ), "Can only assign to variable names, no type deconstruction" @@ -1756,7 +1809,7 @@

    Classes

    def visit_UnaryOp(self, node: UnaryOp) -> TypedUnaryOp: tu = copy(node) tu.operand = self.visit(node.operand) - tu.typ = tu.operand.typ + tu.typ = tu.operand.typ.typ.unop_type(node.op).rettyp return tu def visit_Subscript(self, node: Subscript) -> TypedSubscript: @@ -2021,6 +2074,21 @@

    Classes

    typed_listcomp.typ = InstanceType(ListType(typed_listcomp.elt.typ)) return typed_listcomp + def visit_DictComp(self, node: DictComp) -> TypedDictComp: + typed_dictcomp = copy(node) + # inside the comprehension is a seperate scope + self.enter_scope() + # first evaluate generators for assigned variables + typed_dictcomp.generators = [self.visit(s) for s in node.generators] + # then evaluate elements + typed_dictcomp.key = self.visit(node.key) + typed_dictcomp.value = self.visit(node.value) + self.exit_scope() + typed_dictcomp.typ = InstanceType( + DictType(typed_dictcomp.key.typ, typed_dictcomp.value.typ) + ) + return typed_dictcomp + def visit_FormattedValue(self, node: FormattedValue) -> TypedFormattedValue: typed_node = copy(node) typed_node.value = self.visit(node.value) @@ -2257,8 +2325,27 @@

    Methods

    def visit_AnnAssign(self, node: AnnAssign) -> TypedAnnAssign:
         typed_ass = copy(node)
    -    typed_ass.value: TypedExpression = self.visit(node.value)
         typed_ass.annotation = self.type_from_annotation(node.annotation)
    +    if isinstance(typed_ass.annotation, ListType) and (
    +        (isinstance(node.value, Constant) and node.value.value == [])
    +        or (isinstance(node.value, List) and node.value.elts == [])
    +    ):
    +        # Empty lists are only allowed in annotated assignments
    +        typed_ass.value: TypedExpression = copy(node.value)
    +        typed_ass.value.typ = InstanceType(typed_ass.annotation)
    +    elif isinstance(typed_ass.annotation, DictType) and (
    +        (isinstance(node.value, Constant) and node.value.value == {})
    +        or (
    +            isinstance(node.value, Dict)
    +            and node.value.keys == []
    +            and node.value.values == []
    +        )
    +    ):
    +        # Empty lists are only allowed in annotated assignments
    +        typed_ass.value: TypedExpression = copy(node.value)
    +        typed_ass.value.typ = InstanceType(typed_ass.annotation)
    +    else:
    +        typed_ass.value: TypedExpression = self.visit(node.value)
         assert isinstance(
             node.target, Name
         ), "Can only assign to variable names, no type deconstruction"
    @@ -2542,6 +2629,31 @@ 

    Methods

    return tt
    +
    +def visit_DictComp(self, node: ast.DictComp) ‑> TypedDictComp +
    +
    +
    +
    + +Expand source code + +
    def visit_DictComp(self, node: DictComp) -> TypedDictComp:
    +    typed_dictcomp = copy(node)
    +    # inside the comprehension is a seperate scope
    +    self.enter_scope()
    +    # first evaluate generators for assigned variables
    +    typed_dictcomp.generators = [self.visit(s) for s in node.generators]
    +    # then evaluate elements
    +    typed_dictcomp.key = self.visit(node.key)
    +    typed_dictcomp.value = self.visit(node.value)
    +    self.exit_scope()
    +    typed_dictcomp.typ = InstanceType(
    +        DictType(typed_dictcomp.key.typ, typed_dictcomp.value.typ)
    +    )
    +    return typed_dictcomp
    +
    +
    def visit_Expr(self, node: ast.Expr) ‑> TypedExpr
    @@ -3030,7 +3142,7 @@

    Methods

    def visit_UnaryOp(self, node: UnaryOp) -> TypedUnaryOp:
         tu = copy(node)
         tu.operand = self.visit(node.operand)
    -    tu.typ = tu.operand.typ
    +    tu.typ = tu.operand.typ.typ.unop_type(node.op).rettyp
         return tu
    @@ -3490,7 +3602,7 @@

    Methods

    def visit_Return(self, node: Return) -> bool: assert ( self.func_rettyp >= node.typ - ), f"Function '{node.name}' annotated return type does not match actual return type" + ), f"Function annotated return type does not match actual return type" return True def check_fulfills(self, node: FunctionDef): @@ -3576,7 +3688,7 @@

    Methods

    def visit_Return(self, node: Return) -> bool:
         assert (
             self.func_rettyp >= node.typ
    -    ), f"Function '{node.name}' annotated return type does not match actual return type"
    +    ), f"Function annotated return type does not match actual return type"
         return True
    @@ -3956,6 +4068,7 @@

    visit_Compare
  • visit_Constant
  • visit_Dict
  • +
  • visit_DictComp
  • visit_Expr
  • visit_For
  • visit_FormattedValue
  • diff --git a/docs/opshin/typed_ast.html b/docs/opshin/typed_ast.html index db393fe1..65265dae 100644 --- a/docs/opshin/typed_ast.html +++ b/docs/opshin/typed_ast.html @@ -188,8 +188,14 @@

    Module opshin.typed_ast

    class TypedListComp(typedexpr, ListComp): - generators: typing.List[typedcomprehension] elt: typedexpr + generators: typing.List[typedcomprehension] + + +class TypedDictComp(typedexpr, DictComp): + key: typedexpr + value: typedexpr + generators: typing.List[typedcomprehension] class TypedFormattedValue(typedexpr, FormattedValue): @@ -797,6 +803,58 @@

    Methods

    +
    +class TypedDictComp +(*args, **kwargs) +
    +
    +

    DictComp(expr key, expr value, comprehension* generators)

    +
    + +Expand source code + +
    class TypedDictComp(typedexpr, DictComp):
    +    key: typedexpr
    +    value: typedexpr
    +    generators: typing.List[typedcomprehension]
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var generators : List[typedcomprehension]
    +
    +
    +
    +
    var keytypedexpr
    +
    +
    +
    +
    var valuetypedexpr
    +
    +
    +
    +
    +

    Methods

    +
    +
    +def typechecks(self) ‑> Dict[str, Type] +
    +
    +

    +Inherited from: +typedexpr.typechecks +

    +

    Successful typechecks if this expression evaluates to True

    +
    +
    +
    class TypedExpr (*args, **kwargs) @@ -1203,8 +1261,8 @@

    Methods

    Expand source code
    class TypedListComp(typedexpr, ListComp):
    -    generators: typing.List[typedcomprehension]
    -    elt: typedexpr
    + elt: typedexpr + generators: typing.List[typedcomprehension]

    Ancestors

      @@ -1744,6 +1802,7 @@

      Subclasses

    • TypedCall
    • TypedCompare
    • TypedDict
    • +
    • TypedDictComp
    • TypedFormattedValue
    • TypedJoinedStr
    • TypedList
    • @@ -2003,6 +2062,15 @@

      TypedDictComp

      + + +
    • TypedExpr

      • value
      • diff --git a/docs/opshin/types.html b/docs/opshin/types.html index 56214172..674bf128 100644 --- a/docs/opshin/types.html +++ b/docs/opshin/types.html @@ -177,6 +177,40 @@

        Module opshin.types

        f"{type(self).__name__} can not be used with operation {binop.__class__.__name__}" ) + def unop_type(self, unop: unaryop) -> "Type": + """ + Type of a unary operation on self. + """ + return FunctionType( + [InstanceType(self)], + InstanceType(self._unop_return_type(unop)), + ) + + def _unop_return_type(self, unop: unaryop) -> "Type": + """ + Return the type of a binary operation between self and other + """ + raise NotImplementedError( + f"{type(self).__name__} does not implement {unop.__class__.__name__}" + ) + + def unop(self, unop: unaryop) -> plt.AST: + """ + Implements a unary operation on self + """ + return OLambda( + ["self"], + self._unop_fun(unop)(OVar("self")), + ) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + """ + Returns a unary function that implements the unary operation on self. + """ + raise NotImplementedError( + f"{type(self).__name__} can not be used with operation {unop.__class__.__name__}" + ) + @dataclass(frozen=True, unsafe_hash=True) class Record: @@ -238,6 +272,30 @@

        Module opshin.types

        and not isinstance(other, PolymorphicFunctionType) ) + 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)) + or isinstance(o, UnionType) + or isinstance(o, AnyType) + ): + # Note that comparison with Record and UnionType is actually fine because both are Data + if isinstance(op, Eq): + return plt.BuiltIn(uplc.BuiltInFun.EqualsData) + if isinstance(op, NotEq): + return OLambda( + ["x", "y"], + plt.Not( + plt.Apply( + plt.BuiltIn(uplc.BuiltInFun.EqualsData), + OVar("x"), + OVar("y"), + ) + ), + ) + return super().cmp(op, o) + def stringify(self, recursive: bool = False) -> plt.AST: _LOGGER.warning( "Serializing AnyType will result in RawPlutusData (CBOR representation) to be printed without additional type information. Annotate types where possible to avoid this warning." @@ -518,9 +576,16 @@

        Module opshin.types

        """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 (self.record >= o.record or o.record >= self.record) - ) or (isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs)): + ( + isinstance(o, RecordType) + and (self.record >= o.record or o.record >= self.record) + ) + or ( + isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs) + ) + or isinstance(o, AnyType) + ): + # Note that comparison with AnyType is actually fine because both are Data if isinstance(op, Eq): return plt.BuiltIn(uplc.BuiltInFun.EqualsData) if isinstance(op, NotEq): @@ -913,6 +978,48 @@

        Module opshin.types

        def __ge__(self, other): return isinstance(other, ListType) and self.typ >= other.typ + def attribute_type(self, attr) -> "Type": + if attr == "index": + return InstanceType( + FunctionType(frozenlist([self.typ]), IntegerInstanceType) + ) + super().attribute_type(attr) + + def attribute(self, attr) -> plt.AST: + if attr == "index": + return OLambda( + ["self", "x"], + OLet( + [("x", plt.Force(OVar("x")))], + plt.Apply( + plt.RecFun( + OLambda( + ["index", "xs", "a"], + plt.IteNullList( + OVar("xs"), + plt.TraceError("Did not find element in list"), + plt.Ite( + plt.EqualsInteger( + OVar("x"), plt.HeadList(OVar("xs")) + ), + OVar("a"), + plt.Apply( + OVar("index"), + OVar("index"), + plt.TailList(OVar("xs")), + plt.AddInteger(OVar("a"), plt.Integer(1)), + ), + ), + ), + ), + ), + OVar("self"), + plt.Integer(0), + ), + ), + ) + super().attribute(attr) + def stringify(self, recursive: bool = False) -> plt.AST: return OLambda( ["self"], @@ -997,6 +1104,16 @@

        Module opshin.types

        ): return plt.AppendList + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.IteNullList(x, plt.Bool(True), plt.Bool(False)) + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class DictType(ClassType): @@ -1284,6 +1401,16 @@

        Module opshin.types

        ) return OLambda(["self"], mapped_attrs) + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.IteNullList(x, plt.Bool(True), plt.Bool(False)) + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class FunctionType(ClassType): @@ -1345,6 +1472,12 @@

        Module opshin.types

        def binop(self, binop: operator, other: AST) -> plt.AST: return self.typ.binop(binop, other) + def unop_type(self, unop: unaryop) -> "Type": + return self.typ.unop_type(unop) + + def unop(self, unop: unaryop) -> plt.AST: + return self.typ.unop(unop) + @dataclass(frozen=True, unsafe_hash=True) class IntegerType(AtomicType): @@ -1521,7 +1654,15 @@

        Module opshin.types

        elif isinstance(binop, Mod): return plt.ModInteger elif isinstance(binop, Pow): - return PowImpl + return lambda x, y: OLet( + [("y", y)], + plt.Ite( + plt.LessThanInteger(OVar("y"), plt.Integer(0)), + plt.TraceError("Negative exponentiation is not supported"), + PowImpl(x, OVar("y")), + ), + ) + if isinstance(binop, Mult): if other.typ == IntegerInstanceType: return plt.MultiplyInteger @@ -1530,6 +1671,24 @@

        Module opshin.types

        elif other.typ == StringInstanceType: return lambda x, y: StrIntMulImpl(y, x) + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, USub): + return IntegerType() + elif isinstance(unop, UAdd): + return IntegerType() + elif isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, USub): + return lambda x: plt.SubtractInteger(plt.Integer(0), x) + if isinstance(unop, UAdd): + return lambda x: x + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger(x, plt.Integer(0)) + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class StringType(AtomicType): @@ -1580,6 +1739,18 @@

        Module opshin.types

        if other.typ == IntegerInstanceType: return StrIntMulImpl + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger( + plt.LengthOfByteString(plt.EncodeUtf8(x)), plt.Integer(0) + ) + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class ByteStringType(AtomicType): @@ -1921,6 +2092,18 @@

        Module opshin.types

        if other.typ == IntegerInstanceType: return ByteStrIntMulImpl + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger( + plt.LengthOfByteString(x), plt.Integer(0) + ) + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class BoolType(AtomicType): @@ -1956,6 +2139,16 @@

        Module opshin.types

        ), ) + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return plt.Not + return super()._unop_fun(unop) + @dataclass(frozen=True, unsafe_hash=True) class UnitType(AtomicType): @@ -1970,6 +2163,16 @@

        Module opshin.types

        def stringify(self, recursive: bool = False) -> plt.AST: return OLambda(["self"], plt.Text("None")) + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.Bool(True) + return super()._unop_fun(unop) + IntegerInstanceType = InstanceType(IntegerType()) StringInstanceType = InstanceType(StringType()) @@ -2824,6 +3027,30 @@

        Classes

        and not isinstance(other, PolymorphicFunctionType) ) + 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)) + or isinstance(o, UnionType) + or isinstance(o, AnyType) + ): + # Note that comparison with Record and UnionType is actually fine because both are Data + if isinstance(op, Eq): + return plt.BuiltIn(uplc.BuiltInFun.EqualsData) + if isinstance(op, NotEq): + return OLambda( + ["x", "y"], + plt.Not( + plt.Apply( + plt.BuiltIn(uplc.BuiltInFun.EqualsData), + OVar("x"), + OVar("y"), + ) + ), + ) + return super().cmp(op, o) + def stringify(self, recursive: bool = False) -> plt.AST: _LOGGER.warning( "Serializing AnyType will result in RawPlutusData (CBOR representation) to be printed without additional type information. Annotate types where possible to avoid this warning." @@ -3101,6 +3328,34 @@

        Methods

        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))
        +        or isinstance(o, UnionType)
        +        or isinstance(o, AnyType)
        +    ):
        +        # Note that comparison with Record and UnionType is actually fine because both are Data
        +        if isinstance(op, Eq):
        +            return plt.BuiltIn(uplc.BuiltInFun.EqualsData)
        +        if isinstance(op, NotEq):
        +            return OLambda(
        +                ["x", "y"],
        +                plt.Not(
        +                    plt.Apply(
        +                        plt.BuiltIn(uplc.BuiltInFun.EqualsData),
        +                        OVar("x"),
        +                        OVar("y"),
        +                    )
        +                ),
        +            )
        +    return super().cmp(op, o)
        +
        def constr(self) ‑> pluthon.pluthon_ast.AST @@ -3348,6 +3603,26 @@

        Methods

        )
        +
        +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
        +
        +

        +Inherited from: +ClassType.unop +

        +

        Implements a unary operation on self

        +
        +
        +def unop_type(self, unop: ast.unaryop) ‑> Type +
        +
        +

        +Inherited from: +ClassType.unop_type +

        +

        Type of a unary operation on self.

        +
        @@ -3471,6 +3746,26 @@

        Methods

        Returns a stringified version of the object …

        +
        +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
        +
        +

        +Inherited from: +ClassType.unop +

        +

        Implements a unary operation on self

        +
        +
        +def unop_type(self, unop: ast.unaryop) ‑> Type +
        +
        +

        +Inherited from: +ClassType.unop_type +

        +

        Type of a unary operation on self.

        +
        @@ -3649,7 +3944,17 @@

        Methods

        plt.Text("True"), plt.Text("False"), ), - )
        + ) + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return plt.Not + return super()._unop_fun(unop)

        Ancestors

          @@ -3794,6 +4099,26 @@

          Methods

          ) +
          +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
          +
          +

          +Inherited from: +AtomicType.unop +

          +

          Implements a unary operation on self

          +
          +
          +def unop_type(self, unop: ast.unaryop) ‑> Type +
          +
          +

          +Inherited from: +AtomicType.unop_type +

          +

          Type of a unary operation on self.

          +
          @@ -4143,7 +4468,19 @@

          Methods

          return plt.AppendByteString if isinstance(binop, Mult): if other.typ == IntegerInstanceType: - return ByteStrIntMulImpl
          + return ByteStrIntMulImpl + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger( + plt.LengthOfByteString(x), plt.Integer(0) + ) + return super()._unop_fun(unop)

          Ancestors

            @@ -4585,6 +4922,26 @@

            Methods

            ) +
            +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
            +
            +

            +Inherited from: +AtomicType.unop +

            +

            Implements a unary operation on self

            +
            +
            +def unop_type(self, unop: ast.unaryop) ‑> Type +
            +
            +

            +Inherited from: +AtomicType.unop_type +

            +

            Type of a unary operation on self.

            +
            @@ -4862,6 +5219,26 @@

            Methods

            Returns a stringified version of the object …

            +
            +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
            +
            +

            +Inherited from: +Type.unop +

            +

            Implements a unary operation on self

            +
            +
            +def unop_type(self, unop: ast.unaryop) ‑> Type +
            +
            +

            +Inherited from: +Type.unop_type +

            +

            Type of a unary operation on self.

            +
            @@ -5158,7 +5535,17 @@

            Methods

            ), plt.EmptyDataPairList(), ) - return OLambda(["self"], mapped_attrs)
            + return OLambda(["self"], mapped_attrs) + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.IteNullList(x, plt.Bool(True), plt.Bool(False)) + return super()._unop_fun(unop)

            Ancestors

              @@ -5559,6 +5946,26 @@

              Methods

              ) +
              +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
              +
              +

              +Inherited from: +ClassType.unop +

              +

              Implements a unary operation on self

              +
              +
              +def unop_type(self, unop: ast.unaryop) ‑> Type +
              +
              +

              +Inherited from: +ClassType.unop_type +

              +

              Type of a unary operation on self.

              +
              @@ -5713,6 +6120,26 @@

              Methods

              return OLambda(["x"], plt.Text("<function>"))
              +
              +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
              +
              +

              +Inherited from: +ClassType.unop +

              +

              Implements a unary operation on self

              +
              +
              +def unop_type(self, unop: ast.unaryop) ‑> Type +
              +
              +

              +Inherited from: +ClassType.unop_type +

              +

              Type of a unary operation on self.

              +
              @@ -5827,6 +6254,26 @@

              Methods

              Returns a stringified version of the object …

              +
              +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
              +
              +

              +Inherited from: +ClassType.unop +

              +

              Implements a unary operation on self

              +
              +
              +def unop_type(self, unop: ast.unaryop) ‑> Type +
              +
              +

              +Inherited from: +ClassType.unop_type +

              +

              Type of a unary operation on self.

              +
              @@ -5874,7 +6321,13 @@

              Methods

              return self.typ.binop_type(binop, other) def binop(self, binop: operator, other: AST) -> plt.AST: - return self.typ.binop(binop, other)
              + return self.typ.binop(binop, other) + + def unop_type(self, unop: unaryop) -> "Type": + return self.typ.unop_type(unop) + + def unop(self, unop: unaryop) -> plt.AST: + return self.typ.unop(unop)

              Ancestors

                @@ -6049,19 +6502,53 @@

                Methods

                return self.typ.stringify(recursive=recursive) - - -
                -class IntImpl -(*args, **kwargs) +
                +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST
                -
                +

                +Inherited from: +Type.unop +

                +

                Implements a unary operation on self

                Expand source code -
                class IntImpl(PolymorphicFunction):
                +
                def unop(self, unop: unaryop) -> plt.AST:
                +    return self.typ.unop(unop)
                +
                +
                +
                +def unop_type(self, unop: ast.unaryop) ‑> Type +
                +
                +

                +Inherited from: +Type.unop_type +

                +

                Type of a unary operation on self.

                +
                + +Expand source code + +
                def unop_type(self, unop: unaryop) -> "Type":
                +    return self.typ.unop_type(unop)
                +
                +
                + + +
                +class IntImpl +(*args, **kwargs) +
                +
                +
                +
                + +Expand source code + +
                class IntImpl(PolymorphicFunction):
                     def type_from_args(self, args: typing.List[Type]) -> FunctionType:
                         assert (
                             len(args) == 1
                @@ -6576,14 +7063,40 @@ 

                Methods

                elif isinstance(binop, Mod): return plt.ModInteger elif isinstance(binop, Pow): - return PowImpl + return lambda x, y: OLet( + [("y", y)], + plt.Ite( + plt.LessThanInteger(OVar("y"), plt.Integer(0)), + plt.TraceError("Negative exponentiation is not supported"), + PowImpl(x, OVar("y")), + ), + ) + if isinstance(binop, Mult): if other.typ == IntegerInstanceType: return plt.MultiplyInteger elif other.typ == ByteStringInstanceType: return lambda x, y: ByteStrIntMulImpl(y, x) elif other.typ == StringInstanceType: - return lambda x, y: StrIntMulImpl(y, x)
                + return lambda x, y: StrIntMulImpl(y, x) + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, USub): + return IntegerType() + elif isinstance(unop, UAdd): + return IntegerType() + elif isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, USub): + return lambda x: plt.SubtractInteger(plt.Integer(0), x) + if isinstance(unop, UAdd): + return lambda x: x + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger(x, plt.Integer(0)) + return super()._unop_fun(unop)

                Ancestors

                  @@ -6838,6 +7351,26 @@

                  Methods

                  )
                +
                +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                +
                +

                +Inherited from: +AtomicType.unop +

                +

                Implements a unary operation on self

                +
                +
                +def unop_type(self, unop: ast.unaryop) ‑> Type +
                +
                +

                +Inherited from: +AtomicType.unop_type +

                +

                Type of a unary operation on self.

                +
                @@ -6857,6 +7390,48 @@

                Methods

                def __ge__(self, other): return isinstance(other, ListType) and self.typ >= other.typ + def attribute_type(self, attr) -> "Type": + if attr == "index": + return InstanceType( + FunctionType(frozenlist([self.typ]), IntegerInstanceType) + ) + super().attribute_type(attr) + + def attribute(self, attr) -> plt.AST: + if attr == "index": + return OLambda( + ["self", "x"], + OLet( + [("x", plt.Force(OVar("x")))], + plt.Apply( + plt.RecFun( + OLambda( + ["index", "xs", "a"], + plt.IteNullList( + OVar("xs"), + plt.TraceError("Did not find element in list"), + plt.Ite( + plt.EqualsInteger( + OVar("x"), plt.HeadList(OVar("xs")) + ), + OVar("a"), + plt.Apply( + OVar("index"), + OVar("index"), + plt.TailList(OVar("xs")), + plt.AddInteger(OVar("a"), plt.Integer(1)), + ), + ), + ), + ), + ), + OVar("self"), + plt.Integer(0), + ), + ), + ) + super().attribute(attr) + def stringify(self, recursive: bool = False) -> plt.AST: return OLambda( ["self"], @@ -6939,7 +7514,17 @@

                Methods

                if isinstance(other.typ, InstanceType) and isinstance( other.typ.typ, ListType ): - return plt.AppendList
                + return plt.AppendList + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.IteNullList(x, plt.Bool(True), plt.Bool(False)) + return super()._unop_fun(unop)

                Ancestors

                  @@ -6964,6 +7549,45 @@

                  Methods

                  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 == "index":
                  +        return OLambda(
                  +            ["self", "x"],
                  +            OLet(
                  +                [("x", plt.Force(OVar("x")))],
                  +                plt.Apply(
                  +                    plt.RecFun(
                  +                        OLambda(
                  +                            ["index", "xs", "a"],
                  +                            plt.IteNullList(
                  +                                OVar("xs"),
                  +                                plt.TraceError("Did not find element in list"),
                  +                                plt.Ite(
                  +                                    plt.EqualsInteger(
                  +                                        OVar("x"), plt.HeadList(OVar("xs"))
                  +                                    ),
                  +                                    OVar("a"),
                  +                                    plt.Apply(
                  +                                        OVar("index"),
                  +                                        OVar("index"),
                  +                                        plt.TailList(OVar("xs")),
                  +                                        plt.AddInteger(OVar("a"), plt.Integer(1)),
                  +                                    ),
                  +                                ),
                  +                            ),
                  +                        ),
                  +                    ),
                  +                    OVar("self"),
                  +                    plt.Integer(0),
                  +                ),
                  +            ),
                  +        )
                  +    super().attribute(attr)
                  +
                  def attribute_type(self, attr) ‑> Type @@ -6974,6 +7598,17 @@

                  Methods

                  ClassType.attribute_type

                  The types of the named attributes of this class

                  +
                  + +Expand source code + +
                  def attribute_type(self, attr) -> "Type":
                  +    if attr == "index":
                  +        return InstanceType(
                  +            FunctionType(frozenlist([self.typ]), IntegerInstanceType)
                  +        )
                  +    super().attribute_type(attr)
                  +
                  def binop(self, binop: ast.operator, other: ast.AST) ‑> pluthon.pluthon_ast.AST @@ -7119,6 +7754,26 @@

                  Methods

                  )
                  +
                  +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                  +
                  +

                  +Inherited from: +ClassType.unop +

                  +

                  Implements a unary operation on self

                  +
                  +
                  +def unop_type(self, unop: ast.unaryop) ‑> Type +
                  +
                  +

                  +Inherited from: +ClassType.unop_type +

                  +

                  Type of a unary operation on self.

                  +
                  @@ -7291,6 +7946,26 @@

                  Methods

                  )
                  +
                  +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                  +
                  +

                  +Inherited from: +ClassType.unop +

                  +

                  Implements a unary operation on self

                  +
                  +
                  +def unop_type(self, unop: ast.unaryop) ‑> Type +
                  +
                  +

                  +Inherited from: +ClassType.unop_type +

                  +

                  Type of a unary operation on self.

                  +
                  @@ -7484,6 +8159,26 @@

                  Methods

                  Returns a stringified version of the object …

                  +
                  +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                  +
                  +

                  +Inherited from: +InstanceType.unop +

                  +

                  Implements a unary operation on self

                  +
                  +
                  +def unop_type(self, unop: ast.unaryop) ‑> Type +
                  +
                  +

                  +Inherited from: +InstanceType.unop_type +

                  +

                  Type of a unary operation on self.

                  +
                  @@ -7607,6 +8302,26 @@

                  Methods

                  Returns a stringified version of the object …

                  +
                  +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                  +
                  +

                  +Inherited from: +ClassType.unop +

                  +

                  Implements a unary operation on self

                  +
                  +
                  +def unop_type(self, unop: ast.unaryop) ‑> Type +
                  +
                  +

                  +Inherited from: +ClassType.unop_type +

                  +

                  Type of a unary operation on self.

                  +
                  @@ -7739,9 +8454,16 @@

                  Class variables

                  """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 (self.record >= o.record or o.record >= self.record) - ) or (isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs)): + ( + isinstance(o, RecordType) + and (self.record >= o.record or o.record >= self.record) + ) + or ( + isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs) + ) + or isinstance(o, AnyType) + ): + # Note that comparison with AnyType is actually fine because both are Data if isinstance(op, Eq): return plt.BuiltIn(uplc.BuiltInFun.EqualsData) if isinstance(op, NotEq): @@ -7971,9 +8693,16 @@

                  Methods

                  """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 (self.record >= o.record or o.record >= self.record) - ) or (isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs)): + ( + isinstance(o, RecordType) + and (self.record >= o.record or o.record >= self.record) + ) + or ( + isinstance(o, UnionType) and any(self >= o or self >= o for o in o.typs) + ) + or isinstance(o, AnyType) + ): + # Note that comparison with AnyType is actually fine because both are Data if isinstance(op, Eq): return plt.BuiltIn(uplc.BuiltInFun.EqualsData) if isinstance(op, NotEq): @@ -8154,6 +8883,26 @@

                  Methods

                  )
                  +
                  +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                  +
                  +

                  +Inherited from: +ClassType.unop +

                  +

                  Implements a unary operation on self

                  +
                  +
                  +def unop_type(self, unop: ast.unaryop) ‑> Type +
                  +
                  +

                  +Inherited from: +ClassType.unop_type +

                  +

                  Type of a unary operation on self.

                  +
                  @@ -8277,7 +9026,19 @@

                  Methods

                  return plt.AppendString if isinstance(binop, Mult): if other.typ == IntegerInstanceType: - return StrIntMulImpl
                  + return StrIntMulImpl + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.EqualsInteger( + plt.LengthOfByteString(plt.EncodeUtf8(x)), plt.Integer(0) + ) + return super()._unop_fun(unop)

                  Ancestors

                    @@ -8428,6 +9189,26 @@

                    Methods

                    return OLambda(["self"], OVar("self"))
                    +
                    +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                    +
                    +

                    +Inherited from: +AtomicType.unop +

                    +

                    Implements a unary operation on self

                    +
                    +
                    +def unop_type(self, unop: ast.unaryop) ‑> Type +
                    +
                    +

                    +Inherited from: +AtomicType.unop_type +

                    +

                    Type of a unary operation on self.

                    +
                    @@ -8634,6 +9415,26 @@

                    Methods

                    )
                    +
                    +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                    +
                    +

                    +Inherited from: +ClassType.unop +

                    +

                    Implements a unary operation on self

                    +
                    +
                    +def unop_type(self, unop: ast.unaryop) ‑> Type +
                    +
                    +

                    +Inherited from: +ClassType.unop_type +

                    +

                    Type of a unary operation on self.

                    +
                    @@ -8733,6 +9534,40 @@

                    Methods

                    """ raise NotImplementedError( f"{type(self).__name__} can not be used with operation {binop.__class__.__name__}" + ) + + def unop_type(self, unop: unaryop) -> "Type": + """ + Type of a unary operation on self. + """ + return FunctionType( + [InstanceType(self)], + InstanceType(self._unop_return_type(unop)), + ) + + def _unop_return_type(self, unop: unaryop) -> "Type": + """ + Return the type of a binary operation between self and other + """ + raise NotImplementedError( + f"{type(self).__name__} does not implement {unop.__class__.__name__}" + ) + + def unop(self, unop: unaryop) -> plt.AST: + """ + Implements a unary operation on self + """ + return OLambda( + ["self"], + self._unop_fun(unop)(OVar("self")), + ) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + """ + Returns a unary function that implements the unary operation on self. + """ + raise NotImplementedError( + f"{type(self).__name__} can not be used with operation {unop.__class__.__name__}" )

                    Subclasses

                    @@ -8893,6 +9728,44 @@

                    Methods

                    raise NotImplementedError(f"{type(self).__name__} can not be stringified")
                    +
                    +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                    +
                    +

                    Implements a unary operation on self

                    +
                    + +Expand source code + +
                    def unop(self, unop: unaryop) -> plt.AST:
                    +    """
                    +    Implements a unary operation on self
                    +    """
                    +    return OLambda(
                    +        ["self"],
                    +        self._unop_fun(unop)(OVar("self")),
                    +    )
                    +
                    +
                    +
                    +def unop_type(self, unop: ast.unaryop) ‑> Type +
                    +
                    +

                    Type of a unary operation on self.

                    +
                    + +Expand source code + +
                    def unop_type(self, unop: unaryop) -> "Type":
                    +    """
                    +    Type of a unary operation on self.
                    +    """
                    +    return FunctionType(
                    +        [InstanceType(self)],
                    +        InstanceType(self._unop_return_type(unop)),
                    +    )
                    +
                    +
                    @@ -9418,6 +10291,26 @@

                    Methods

                    )
                    +
                    +def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST +
                    +
                    +

                    +Inherited from: +ClassType.unop +

                    +

                    Implements a unary operation on self

                    +
                    +
                    +def unop_type(self, unop: ast.unaryop) ‑> Type +
                    +
                    +

                    +Inherited from: +ClassType.unop_type +

                    +

                    Type of a unary operation on self.

                    +
                    @@ -9440,7 +10333,17 @@

                    Methods

                    return super().cmp(op, o) def stringify(self, recursive: bool = False) -> plt.AST: - return OLambda(["self"], plt.Text("None"))
                    + return OLambda(["self"], plt.Text("None")) + + def _unop_return_type(self, unop: unaryop) -> "Type": + if isinstance(unop, Not): + return BoolType() + return super()._unop_return_type(unop) + + def _unop_fun(self, unop: unaryop) -> Callable[[plt.AST], plt.AST]: + if isinstance(unop, Not): + return lambda x: plt.Bool(True) + return super()._unop_fun(unop)

                    Ancestors

                  • @@ -9668,6 +10593,8 @@

                    Ato
                  • constr_type
                  • copy_only_attributes
                  • stringify
                  • +
                  • unop
                  • +
                  • unop_type
                • @@ -9689,6 +10616,8 @@

                  BoolTyp
                • constr_type
                • copy_only_attributes
                • stringify
                • +
                • unop
                • +
                • unop_type
              • @@ -9703,6 +10632,8 @@

                constr_type

              • copy_only_attributes
              • stringify
              • +
              • unop
              • +
              • unop_type
            • @@ -9724,6 +10655,8 @@

              Class
            • constr_type
            • copy_only_attributes
            • stringify
            • +
            • unop
            • +
            • unop_type
          • @@ -9739,6 +10672,8 @@

            DictTyp
          • copy_only_attributes
          • key_typ
          • stringify
          • +
          • unop
          • +
          • unop_type
          • value_typ
          @@ -9757,6 +10692,8 @@

          copy_only_attributes
        • rettyp
        • stringify
        • +
        • unop
        • +
        • unop_type
      • @@ -9771,6 +10708,8 @@

        constr_type

      • copy_only_attributes
      • stringify
      • +
      • unop
      • +
      • unop_type
    • @@ -9786,6 +10725,8 @@

      copy_only_attributes

    • stringify
    • typ
    • +
    • unop
    • +
    • unop_type
  • @@ -9807,6 +10748,8 @@

    I
  • constr_type
  • copy_only_attributes
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9822,6 +10765,8 @@

    ListTyp
  • copy_only_attributes
  • stringify
  • typ
  • +
  • unop
  • +
  • unop_type
  • @@ -9838,6 +10783,8 @@

    PairTyp
  • l_typ
  • r_typ
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9861,6 +10808,8 @@

    polymorphic_function

  • stringify
  • typ
  • +
  • unop
  • +
  • unop_type
  • @@ -9876,6 +10825,8 @@

    copy_only_attributes

  • polymorphic_function
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9900,6 +10851,8 @@

    Rec
  • copy_only_attributes
  • record
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9921,6 +10874,8 @@

    Str
  • constr_type
  • copy_only_attributes
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9936,6 +10891,8 @@

    Tuple
  • copy_only_attributes
  • stringify
  • typs
  • +
  • unop
  • +
  • unop_type
  • @@ -9950,6 +10907,8 @@

    Type
  • constr_type
  • copy_only_attributes
  • stringify
  • +
  • unop
  • +
  • unop_type
  • @@ -9968,6 +10927,8 @@

    Union
  • copy_only_attributes
  • stringify
  • typs
  • +
  • unop
  • +
  • unop_type
  • @@ -9982,6 +10943,8 @@

    UnitTyp
  • constr_type
  • copy_only_attributes
  • stringify
  • +
  • unop
  • +
  • unop_type
  • diff --git a/docs/opshin/util.html b/docs/opshin/util.html index 43c932d1..6984ddf2 100644 --- a/docs/opshin/util.html +++ b/docs/opshin/util.html @@ -804,6 +804,8 @@

    Subclasses

  • RewriteAugAssign
  • RewriteConditions
  • RewriteComparisonChaining
  • +
  • RewriteEmptyDicts
  • +
  • RewriteEmptyLists
  • RewriteForbiddenOverwrites
  • RewriteForbiddenReturn
  • RewriteImport