diff --git a/docs/index.js b/docs/index.js
index 9018f559..033fc648 100644
--- a/docs/index.js
+++ b/docs/index.js
@@ -5,6 +5,7 @@ URLS=[
"opshin/tests/index.html",
"opshin/tests/test_builtins.html",
"opshin/tests/utils.html",
+"opshin/tests/test_hashlib.html",
"opshin/tests/test_misc.html",
"opshin/tests/test_ops.html",
"opshin/tests/test_ledger/index.html",
@@ -23,9 +24,8 @@ URLS=[
"opshin/ledger/interval.html",
"opshin/types.html",
"opshin/optimize/index.html",
-"opshin/optimize/optimize_varlen.html",
-"opshin/util.html",
"opshin/optimize/optimize_remove_pass.html",
+"opshin/util.html",
"opshin/optimize/optimize_remove_comments.html",
"opshin/optimize/optimize_remove_deadvars.html",
"opshin/optimize/optimize_const_folding.html",
@@ -47,6 +47,7 @@ URLS=[
"opshin/rewrite/rewrite_import_hashlib.html",
"opshin/rewrite/rewrite_tuple_assign.html",
"opshin/rewrite/rewrite_comparison_chaining.html",
+"opshin/rewrite/rewrite_forbidden_return.html",
"opshin/rewrite/rewrite_import.html",
"opshin/rewrite/rewrite_orig_name.html",
"opshin/std/index.html",
@@ -117,7 +118,7 @@ INDEX=[
{
"ref":"opshin.typed_ast.typedstmt",
"url":2,
-"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | TryStar(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
+"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
},
{
"ref":"opshin.typed_ast.typedstmt.typ",
@@ -167,7 +168,7 @@ INDEX=[
{
"ref":"opshin.typed_ast.TypedModule",
"url":2,
-"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | TryStar(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
+"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
},
{
"ref":"opshin.typed_ast.TypedModule.body",
@@ -222,7 +223,7 @@ INDEX=[
{
"ref":"opshin.typed_ast.TypedExpression",
"url":2,
-"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | TryStar(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
+"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
},
{
"ref":"opshin.typed_ast.TypedExpression.body",
@@ -496,7 +497,7 @@ INDEX=[
{
"ref":"opshin.typed_ast.TypedIfExp",
"url":2,
-"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | TryStar(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
+"doc":"stmt = FunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | AsyncFunctionDef(identifier name, arguments args, stmt body, expr decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, expr bases, keyword keywords, stmt body, expr decorator_list) | Return(expr? value) | Delete(expr targets) | Assign(expr targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) | AnnAssign(expr target, expr annotation, expr? value, int simple) | For(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt body, stmt orelse, string? type_comment) | While(expr test, stmt body, stmt orelse) | If(expr test, stmt body, stmt orelse) | With(withitem items, stmt body, string? type_comment) | AsyncWith(withitem items, stmt body, string? type_comment) | Match(expr subject, match_case cases) | Raise(expr? exc, expr? cause) | Try(stmt body, excepthandler handlers, stmt orelse, stmt finalbody) | Assert(expr test, expr? msg) | Import(alias names) | ImportFrom(identifier? module, alias names, int? level) | Global(identifier names) | Nonlocal(identifier names) | Expr(expr value) | Pass | Break | Continue"
},
{
"ref":"opshin.typed_ast.TypedIfExp.test",
@@ -900,3921 +901,4582 @@ INDEX=[
"func":1
},
{
-"ref":"opshin.tests.test_misc",
+"ref":"opshin.tests.test_hashlib",
"url":6,
"doc":""
},
{
-"ref":"opshin.tests.test_misc.fib",
+"ref":"opshin.tests.test_hashlib.test_sha256",
"url":6,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.A",
+"ref":"opshin.tests.test_hashlib.test_sha3_256",
+"url":6,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_hashlib.test_blake2b",
"url":6,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc",
+"url":7,
+"doc":""
+},
+{
+"ref":"opshin.tests.test_misc.fib",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.A",
+"url":7,
"doc":"A(foo: int)"
},
{
"ref":"opshin.tests.test_misc.A.foo",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.A.CONSTR_ID",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.B",
-"url":6,
+"url":7,
"doc":"B(foobar: int, bar: int)"
},
{
"ref":"opshin.tests.test_misc.B.foobar",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.B.bar",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.B.CONSTR_ID",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.MiscTest",
-"url":6,
+"url":7,
"doc":"A class whose instances are single test cases. By default, the test code itself should be placed in a method named 'runTest'. If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute. Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively. If it is necessary to override the __init__ method, the base class __init__ method must always be called. It is important that subclasses should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run. When subclassing TestCase, you can set these attributes: failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required. Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name."
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_assert_sum_contract_succeed",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_assert_sum_contract_fail",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_mult_for",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.MiscTest.test_mult_while",
-"url":6,
+"ref":"opshin.tests.test_misc.MiscTest.test_mult_for_return",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_mult_while_return",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_sum",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_complex_datum_correct_vals",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_hello_world",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_list_datum_correct_vals",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_showcase",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_fib_iter",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_fib_rec",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_gift_contract_succeed",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_gift_contract_fail",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.MiscTest.test_recursion",
-"url":6,
+"ref":"opshin.tests.test_misc.MiscTest.test_recursion_simple",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_recursion_illegal",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_recursion_legal",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_uninitialized_access",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_illegal_bind",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_type_reassignment_function_bound",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_illegal_function_retype",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_datum_cast",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_wrapping_contract_compile",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_dual_use_compile",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_marketplace_compile",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_marketplace_compile_fail",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_parameterized_compile",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_dict_datum",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_dict_datum_wrong",
-"url":6,
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_removedeadvar_noissue",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_removedeadvar_noissue2",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_removedeadvar_noissue3",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_overopt_removedeadvar",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_opt_shared_var",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_list_expr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_list_expr_not_const",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_dict_expr_not_const",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_redefine_poly_constr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_redefine_constr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_wrap_into_generic_data",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_list_comprehension_even",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_list_comprehension_all",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_access_all_records",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_access_all_records_diff_pos",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_all_records_same_constr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_access_all_records_same_constr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_access_maximum_type",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_union_type_attr_anytype",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_anything_int",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_int_anything",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_int_anything_int",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_anything_int_anything",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_int_str",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_typecast_int_int",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_zero_ary",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_zero_ary_exec",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_zero_ary_method",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_zero_ary_method_exec",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_zero_ary_method_exec_suc",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_return_anything",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_no_return_annotation",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_no_parameter_annotation",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_dict_items_values_deconstr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_nested_deconstruction",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_no_return_annotation_no_return",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_opt_unsafe_cast",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_disabled",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_list",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_dict",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_complex",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_plutusdata",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_user_def",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_ifelse",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_for",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_for_target",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_while",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_guaranteed_branch",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_scoping",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_no_scoping",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_repeated_assign",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_math",
-"url":6,
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_reassign_builtin",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_reassign_builtin_invalid_type",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_ignore_reassignment",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_constant_folding_no_print_eval",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_inner_outer_state_functions",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_inner_outer_state_functions_nonglobal",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_outer_state_change_functions",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_failing_annotated_type",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_access_enclosing_variable_before_def",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_access_local_variable_before_assignment",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_warn_bytestring",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_script_context_str_format_0_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820746957f0eb57f2b11119684e611a98f373afea93473fefbb7632d579af2f6259ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_script_context_str_format_1_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820797a1e1720b63621c6b185088184cb8e23af6e46b55bd83e7a91024c823a6c2affffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_script_context_str_format_2_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a1401a000f4240d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff9f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffa1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820c17c32f6433ae22c2acaebfb796bbfaee3993ff7ebb58a2bac6b4a3bdd2f6d28ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_script_context_str_format",
-"url":6,
+"url":7,
"doc":""
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_uplc_builtin",
-"url":6,
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_trace_order",
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_print_empty",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_cast_bool_ite",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_cast_bool_ite_expr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_cast_bool_while",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_cast_bool_boolops",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_if",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_complex_isinstance_cast_if",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_ifexpr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_while",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_random",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_shortcut_and",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_assert",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_assert_if",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_or",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_or_sameconstr",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_not",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_ifelse",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_or_else",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_and_else",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_complex_and",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_isinstance_cast_shortcut_or",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.MiscTest.test_retype_if",
-"url":6,
+"ref":"opshin.tests.test_misc.MiscTest.test_uniontype_if",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_if_no_retype_no_plutusdata",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_while_no_retype_no_plutusdata",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_retype_while",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_retype_if_branch_correct",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_retype_while_branch_correct",
-"url":6,
+"url":7,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_misc.MiscTest.test_retype_while_wrong_after_iter",
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_retype",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_retype_if_primitives",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_in_list",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_comparison_chaining",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_double_import_offset",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_double_import_direct",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_double_import_deep",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_bytearray_alternative",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_ByteString_alternative",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_boolop_chaining",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_wrapping_contract_apply",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_wrapping_contract_dump_load",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_bridge",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_misc.MiscTest.test_forbidden_overwrite",
-"url":6,
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local",
-"url":6,
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_00_examples_dict_datum_py",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external",
-"url":6,
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_01_examples_inspect_script_context_py",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_02_examples_datum_cast_py",
"url":7,
-"doc":""
+"doc":"",
+"func":1
},
{
-"ref":"opshin.tests.test_ops.frozenlist",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_03_examples_sum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.rec_data_strategies",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_04_examples_complex_datum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_05_examples_list_datum_py",
"url":7,
-"doc":"A class whose instances are single test cases. By default, the test code itself should be placed in a method named 'runTest'. If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute. Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively. If it is necessary to override the __init__ method, the base class __init__ method must always be called. It is important that subclasses should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run. When subclassing TestCase, you can set these attributes: failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required. Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name."
+"doc":"",
+"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_and_bool",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_06_examples_hello_world_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_or_bool",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_07_examples_mult_for_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_not_bool",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_08_examples_list_comprehensions_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_usub_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_09_examples_fib_rec_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_add_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_10_examples_showcase_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_sub_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_11_examples_fib_iter_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mul_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_12_examples_mult_while_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_div_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_13_examples_smart_contracts_dual_use_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mod_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_14_examples_smart_contracts_simple_script_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_pow_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_15_examples_smart_contracts_parameterized_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_add_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_16_examples_smart_contracts_gift_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_add_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_17_examples_smart_contracts_wrapped_token_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_slice_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_18_examples_smart_contracts_always_true_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_index_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_19_examples_smart_contracts_micropayments_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_index_list",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_20_examples_smart_contracts_marketplace_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_in_list_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local_21_examples_smart_contracts_assert_sum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_in_list_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_local",
"url":7,
-"doc":"",
-"func":1
+"doc":""
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_eq_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_00_examples_dict_datum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_eq_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_01_examples_inspect_script_context_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_eq_bool",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_02_examples_datum_cast_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mul_int_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_03_examples_sum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mul_str_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_04_examples_complex_datum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mul_int_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_05_examples_list_datum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_mul_bytes_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_06_examples_hello_world_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_07_examples_mult_for_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_bool",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_08_examples_list_comprehensions_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_09_examples_fib_rec_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_bytes",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_10_examples_showcase_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_none",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_11_examples_fib_iter_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_dataclass",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_12_examples_mult_while_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_multiple",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_13_examples_smart_contracts_dual_use_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_tuple_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_14_examples_smart_contracts_simple_script_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_tuple_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_15_examples_smart_contracts_parameterized_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_pair_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_16_examples_smart_contracts_gift_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_pair_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_17_examples_smart_contracts_wrapped_token_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_list_str",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_18_examples_smart_contracts_always_true_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_list_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_19_examples_smart_contracts_micropayments_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_dict_int",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_20_examples_smart_contracts_marketplace_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ops.OpTest.test_fmt_any",
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external_21_examples_smart_contracts_assert_sum_py",
"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger",
-"url":8,
-"doc":""
-},
-{
-"ref":"opshin.tests.test_ledger.test_interval",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_compilation_deterministic_external",
+"url":7,
"doc":""
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_illegal",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_commutative_compare_extended",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_in_loop",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_extended",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_in_for",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_lower_bound",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_in_if",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_commutative_lower_bound",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_in_if_same_type",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_upper_bound",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_in_if_missing_return",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_commutative_compare_upper_bound",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_different_return_types_anything",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_contains",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_different_return_types_while_loop",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_from",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_different_return_types_for_loop",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_range",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_else_loop_while",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_to",
-"url":9,
+"ref":"opshin.tests.test_misc.MiscTest.test_return_else_loop_for",
+"url":7,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_compare_extended_helper",
-"url":9,
-"doc":"",
-"func":1
+"ref":"opshin.tests.test_ops",
+"url":8,
+"doc":""
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_get_bool",
-"url":9,
+"ref":"opshin.tests.test_ops.frozenlist",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_make_to_in_make_range",
-"url":9,
+"ref":"opshin.tests.test_ops.rec_data_strategies",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_interval.test_make_from_in_make_range",
-"url":9,
+"ref":"opshin.tests.test_ops.OpTest",
+"url":8,
+"doc":"A class whose instances are single test cases. By default, the test code itself should be placed in a method named 'runTest'. If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute. Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively. If it is necessary to override the __init__ method, the base class __init__ method must always be called. It is important that subclasses should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run. When subclassing TestCase, you can set these attributes: failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required. Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name."
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_and_bool",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_api_v2",
-"url":10,
-"doc":""
+"ref":"opshin.tests.test_ops.OpTest.test_or_bool",
+"url":8,
+"doc":"",
+"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_0_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820746957f0eb57f2b11119684e611a98f373afea93473fefbb7632d579af2f6259ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":10,
+"ref":"opshin.tests.test_ops.OpTest.test_not_bool",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_1_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820797a1e1720b63621c6b185088184cb8e23af6e46b55bd83e7a91024c823a6c2affffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":10,
+"ref":"opshin.tests.test_ops.OpTest.test_usub_int",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_2_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a1401a000f4240d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff9f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffa1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820c17c32f6433ae22c2acaebfb796bbfaee3993ff7ebb58a2bac6b4a3bdd2f6d28ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
-"url":10,
+"ref":"opshin.tests.test_ops.OpTest.test_add_int",
+"url":8,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_std",
+"ref":"opshin.tests.test_ops.OpTest.test_sub_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mul_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_div_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mod_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_pow_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_add_bytes",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_add_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_bytes",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_bytes_lower",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_bytes_upper",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_bytes_full",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_index_bytes",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_index_list",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_list",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_list_lower",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_list_upper",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_slice_list_full",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_in_list_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_in_list_bytes",
+"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_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_eq_bool",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mul_int_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mul_str_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mul_int_bytes",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_mul_bytes_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_add_list",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_bool",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_bytes",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_none",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_dataclass",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_multiple",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_tuple_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_tuple_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_pair_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_pair_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_list_str",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_list_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_dict_int",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ops.OpTest.test_fmt_any",
+"url":8,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger",
+"url":9,
+"doc":""
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval",
+"url":10,
+"doc":""
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_commutative_compare_extended",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_extended",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_lower_bound",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_commutative_lower_bound",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_ordering_compare_upper_bound",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_commutative_compare_upper_bound",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_contains",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_from",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_range",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_make_to",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_fuzz_compare_extended_helper",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_get_bool",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_make_to_in_make_range",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_interval.test_make_from_in_make_range",
+"url":10,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_api_v2",
"url":11,
"doc":""
},
{
-"ref":"opshin.tests.test_std.test_math",
+"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_0_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820746957f0eb57f2b11119684e611a98f373afea93473fefbb7632d579af2f6259ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
+"url":11,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_1_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820797a1e1720b63621c6b185088184cb8e23af6e46b55bd83e7a91024c823a6c2affffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
+"url":11,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_ledger.test_api_v2.test_script_context_repr_correct_2_d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a1401a000f4240d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff9f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffa1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820c17c32f6433ae22c2acaebfb796bbfaee3993ff7ebb58a2bac6b4a3bdd2f6d28ffffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff",
+"url":11,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_std",
"url":12,
"doc":""
},
{
+"ref":"opshin.tests.test_std.test_math",
+"url":13,
+"doc":""
+},
+{
"ref":"opshin.tests.test_std.test_math.test_gcd",
-"url":12,
+"url":13,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_math.test_sign",
-"url":12,
+"url":13,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_math.test_unsigned_int_from_bytes_big",
-"url":12,
+"url":13,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_math.test_ceil",
-"url":12,
+"url":13,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_math.test_floor",
-"url":12,
+"url":13,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity",
-"url":13,
+"url":14,
"doc":""
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_0",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_1",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_2",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_3",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_list_0",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_list_1",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_list_2",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_dict_0",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_dict_1",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_dict_2",
-"url":13,
+"url":14,
"doc":"",
"func":1
},
{
-"ref":"opshin.tests.test_std.test_fractions",
+"ref":"opshin.tests.test_std.test_integrity.test_integrity_check_rename",
"url":14,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.tests.test_std.test_fractions",
+"url":15,
"doc":""
},
{
"ref":"opshin.tests.test_std.test_fractions.native_fraction_from_oc_fraction",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_add",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_sub",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_neg",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_mul",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_div",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_norm_sign",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_norm",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_ge",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_le",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_lt",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_gt",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_eq",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_floor",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_fractions.test_ceil",
-"url":14,
+"url":15,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap",
-"url":15,
+"url":16,
"doc":""
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_init_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.bytes_and_index",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_test_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test__set_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_set_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_reset_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_flip_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_size_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_all_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_any_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_none_bitmap",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_flip_roundtrip",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_set_test",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_std.test_bitmap.test_reset_test",
-"url":15,
+"url":16,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib",
-"url":16,
+"url":17,
"doc":""
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest",
-"url":16,
+"url":17,
"doc":"A class whose instances are single test cases. By default, the test code itself should be placed in a method named 'runTest'. If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute. Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively. If it is necessary to override the __init__ method, the base class __init__ method must always be called. It is important that subclasses should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run. When subclassing TestCase, you can set these attributes: failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required. Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name."
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_get",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_subscript",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_keys",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_values",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_items_keys_sum",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_dict_items_values_sum",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_str_encode",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_bytes_decode",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_bytes_hex",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_constant_bytestring",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_constant_integer",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_constant_string",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_constant_unit",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_constant_bool",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_plutusdata_to_cbor",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.tests.test_stdlib.StdlibTest.test_union_to_cbor",
-"url":16,
+"url":17,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.LenImpl",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.LenImpl.type_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.LenImpl.impl_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.ReversedImpl",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.ReversedImpl.type_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.ReversedImpl.impl_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.PrintImpl",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PrintImpl.type_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.PrintImpl.impl_from_args",
-"url":17,
+"url":18,
"doc":"",
"func":1
},
{
"ref":"opshin.fun_impls.PythonBuiltIn",
-"url":17,
-"doc":"Create a collection of name/value pairs. Example enumeration: >>> class Color(Enum): . RED = 1 . BLUE = 2 . GREEN = 3 Access them by: - attribute access >>> Color.RED - value lookup: >>> Color(1) - name lookup: >>> Color['RED'] Enumerations can be iterated over, and know how many members they have: >>> len(Color) 3 >>> list(Color) [ , , ] Methods can be added to enumerations, and members can have their own attributes see the documentation for details."
+"url":18,
+"doc":"An enumeration."
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.all",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.any",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.abs",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.chr",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.breakpoint",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.hex",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.len",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.max",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.min",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.print",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.pow",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.oct",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.range",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.reversed",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.fun_impls.PythonBuiltIn.sum",
-"url":17,
+"url":18,
"doc":""
},
{
"ref":"opshin.builder",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose",
-"url":18,
-"doc":"Create a collection of name/value pairs. Example enumeration: >>> class Color(Enum): . RED = 1 . BLUE = 2 . GREEN = 3 Access them by: - attribute access >>> Color.RED - value lookup: >>> Color(1) - name lookup: >>> Color['RED'] Enumerations can be iterated over, and know how many members they have: >>> len(Color) 3 >>> list(Color) [ , , ] Methods can be added to enumerations, and members can have their own attributes see the documentation for details."
+"url":19,
+"doc":"An enumeration."
},
{
"ref":"opshin.builder.Purpose.spending",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose.minting",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose.rewarding",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose.certifying",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose.any",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.Purpose.lib",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract",
-"url":18,
-"doc":"PlutusContract(contract: pycardano.plutus.PlutusV2Script, datum_type: Optional[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = None, redeemer_type: Optional[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = None, parameter_types: List[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = , purpose: Iterable[opshin.builder.Purpose] = ( ,), version: Optional[str] = '1.0.0', title: str = 'validator', description: Optional[str] = 'opshin 0.18.0 Smart Contract', license: Optional[str] = None)"
+"url":19,
+"doc":"PlutusContract(contract: pycardano.plutus.PlutusV2Script, datum_type: Optional[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = None, redeemer_type: Optional[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = None, parameter_types: List[Tuple[str, Type[Union[pycardano.plutus.PlutusData, dict, int, bytes, pycardano.serialization.IndefiniteList, pycardano.serialization.RawCBOR, pycardano.plutus.RawPlutusData = , purpose: Iterable[opshin.builder.Purpose] = ( ,), version: Optional[str] = '1.0.0', title: str = 'validator', description: Optional[str] = 'opshin 0.19.0 Smart Contract', license: Optional[str] = None)"
},
{
"ref":"opshin.builder.PlutusContract.contract",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.parameter_types",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.datum_type",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.redeemer_type",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.purpose",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.version",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.title",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.description",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.license",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.cbor",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.cbor_hex",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.script_hash",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.policy_id",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.mainnet_addr",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.testnet_addr",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.plutus_json",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.blueprint",
-"url":18,
+"url":19,
"doc":""
},
{
"ref":"opshin.builder.PlutusContract.apply_parameter",
-"url":18,
+"url":19,
"doc":"Returns a new OpShin Contract with the applied parameters",
"func":1
},
{
"ref":"opshin.builder.PlutusContract.dump",
-"url":18,
+"url":19,
"doc":"",
"func":1
},
{
"ref":"opshin.builder.compile",
-"url":18,
+"url":19,
"doc":"",
"func":1
},
{
"ref":"opshin.builder.build",
-"url":18,
+"url":19,
"doc":"Expects a python module and returns the build artifacts from compiling it",
"func":1
},
{
"ref":"opshin.builder.to_plutus_schema",
-"url":18,
+"url":19,
"doc":"Convert to a dictionary representing a json schema according to CIP 57 Plutus Blueprint Reference of the core structure: https: cips.cardano.org/cips/cip57/ corevocabulary Args: kwargs: Extra key word arguments to be passed to json.dumps() Returns: dict: a dict representing the schema of this class.",
"func":1
},
{
"ref":"opshin.builder.from_plutus_schema",
-"url":18,
+"url":19,
"doc":"Convert from a dictionary representing a json schema according to CIP 57 Plutus Blueprint",
"func":1
},
{
"ref":"opshin.builder.apply_parameters",
-"url":18,
+"url":19,
"doc":"Expects a plutus script (compiled) and returns the compiled script from applying parameters to it",
"func":1
},
{
"ref":"opshin.builder.load",
-"url":18,
+"url":19,
"doc":"Load a contract from a file or directory and generate the artifacts",
"func":1
},
{
"ref":"opshin.ledger",
-"url":19,
+"url":20,
"doc":"OpShin provides some helper classes that define concepts introduced in PlutusTx and used by the cardano node to encode data. In particular you find the definition of the entire Script Context for Plutus V2 in the file api_v2 . from opshin.ledger.api_v2 import "
},
{
"ref":"opshin.ledger.api_v2",
-"url":20,
+"url":21,
"doc":"The PlutusV2 ledger API. All classes involved in defining the ScriptContext passed by the node."
},
{
"ref":"opshin.ledger.api_v2.TxId",
-"url":20,
+"url":21,
"doc":"A transaction id, a 64 bytes long hash of the transaction body (also called transaction hash). Example value: TxId(bytes.fromhex(\"842a4d37b036da6ab3c04331240e67d81746beb44f23ad79703e026705361956\" "
},
{
"ref":"opshin.ledger.api_v2.TxId.tx_id",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxId.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TrueData",
-"url":20,
+"url":21,
"doc":"A Datum that represents True in Haskell implementations. It is thus used as an encoding for True in the ScriptContext. Example value: TrueData()"
},
{
"ref":"opshin.ledger.api_v2.TrueData.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.FalseData",
-"url":20,
+"url":21,
"doc":"A Datum that represents False in Haskell implementations. It is thus used as an encoding for False in the ScriptContext. Example value: FalseData()"
},
{
"ref":"opshin.ledger.api_v2.FalseData.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOutRef",
-"url":20,
+"url":21,
"doc":"A reference to a transaction output (hash/id + index)"
},
{
"ref":"opshin.ledger.api_v2.TxOutRef.id",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOutRef.idx",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOutRef.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.PubKeyCredential",
-"url":20,
+"url":21,
"doc":"Part of an address that is authenticated by a public key hash Example value: PubKeyCredential(bytes.fromhex(\"c06ddaad12fc4ded18e56feac72957c1aa75fce6096b40e63ec88274\" "
},
{
"ref":"opshin.ledger.api_v2.PubKeyCredential.credential_hash",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.PubKeyCredential.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.ScriptCredential",
-"url":20,
+"url":21,
"doc":"Part of an address that is authenticated by a smart cotnract Example value: ScriptCredential(bytes.fromhex(\"c06ddaad12fc4ded18e56feac72957c1aa75fce6096b40e63ec88274\" "
},
{
"ref":"opshin.ledger.api_v2.ScriptCredential.credential_hash",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.ScriptCredential.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingHash",
-"url":20,
+"url":21,
"doc":"Indicates that the stake of this address is controlled by the associated credential"
},
{
"ref":"opshin.ledger.api_v2.StakingHash.value",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingHash.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingPtr",
-"url":20,
+"url":21,
"doc":"Indicates that the stake of this address is controlled by the associated pointer. In an address, a chain pointer refers to a point of the chain containing a stake key registration certificate. A point is identified by the 3 coordinates in this object."
},
{
"ref":"opshin.ledger.api_v2.StakingPtr.slot_no",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingPtr.tx_index",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingPtr.cert_index",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.StakingPtr.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.NoStakingCredential",
-"url":20,
+"url":21,
"doc":"Indicates that this address has no staking credentials. Its funds can not be delegated."
},
{
"ref":"opshin.ledger.api_v2.NoStakingCredential.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeStakingCredential",
-"url":20,
+"url":21,
"doc":"Indicates that this address has staking credentials. Its funds can be delegated by the credentialed user."
},
{
"ref":"opshin.ledger.api_v2.SomeStakingCredential.staking_credential",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeStakingCredential.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Address",
-"url":20,
+"url":21,
"doc":"A Shelley address, consisting of a payment and staking credential"
},
{
"ref":"opshin.ledger.api_v2.Address.payment_credential",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Address.staking_credential",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Address.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeDatumHash",
-"url":20,
+"url":21,
"doc":"Indicates that there is a datum associated with this output, which has the given hash."
},
{
"ref":"opshin.ledger.api_v2.SomeDatumHash.datum_hash",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeDatumHash.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeScriptHash",
-"url":20,
+"url":21,
"doc":"Indicates that there is a script associated with this output, which has the given hash."
},
{
"ref":"opshin.ledger.api_v2.SomeScriptHash.script_hash",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeScriptHash.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.NoOutputDatum",
-"url":20,
+"url":21,
"doc":"Indicates that there is no datum associated with an output"
},
{
"ref":"opshin.ledger.api_v2.NoOutputDatum.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatumHash",
-"url":20,
+"url":21,
"doc":"Indicates that there is an datum associated with an output, which has the attached hash"
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatumHash.datum_hash",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatumHash.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatum",
-"url":20,
+"url":21,
"doc":"Indicates that there is an datum associated with an output, which is inlined and equal to the attached datum"
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatum.datum",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.SomeOutputDatum.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.NoScriptHash",
-"url":20,
+"url":21,
"doc":"Indicates that there is no script associated with an output"
},
{
"ref":"opshin.ledger.api_v2.NoScriptHash.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOut",
-"url":20,
+"url":21,
"doc":"The plutus representation of an transaction output, consisting of - address: address owning this output - value: tokens associated with this output - datum: datum associated with this output - reference_script: reference script associated with this output"
},
{
"ref":"opshin.ledger.api_v2.TxOut.address",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOut.value",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOut.datum",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOut.reference_script",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxOut.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInInfo",
-"url":20,
+"url":21,
"doc":"The plutus representation of an transaction output, that is consumed by the transaction."
},
{
"ref":"opshin.ledger.api_v2.TxInInfo.out_ref",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInInfo.resolved",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInInfo.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegRegKey",
-"url":20,
+"url":21,
"doc":"DCertDelegRegKey(value: Union[opshin.ledger.api_v2.StakingHash, opshin.ledger.api_v2.StakingPtr])"
},
{
"ref":"opshin.ledger.api_v2.DCertDelegRegKey.value",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegRegKey.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDeRegKey",
-"url":20,
+"url":21,
"doc":"DCertDelegDeRegKey(value: Union[opshin.ledger.api_v2.StakingHash, opshin.ledger.api_v2.StakingPtr])"
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDeRegKey.value",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDeRegKey.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDelegate",
-"url":20,
+"url":21,
"doc":"DCertDelegDelegate(delegator: Union[opshin.ledger.api_v2.StakingHash, opshin.ledger.api_v2.StakingPtr], delegatee: bytes)"
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDelegate.delegator",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDelegate.delegatee",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertDelegDelegate.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRegister",
-"url":20,
+"url":21,
"doc":"DCertPoolRegister(pool_id: bytes, pool_vfr: bytes)"
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRegister.pool_id",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRegister.pool_vfr",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRegister.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRetire",
-"url":20,
+"url":21,
"doc":"DCertPoolRetire(retirement_certificate: bytes, epoch: int)"
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRetire.retirement_certificate",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRetire.epoch",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertPoolRetire.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertGenesis",
-"url":20,
+"url":21,
"doc":"DCertGenesis()"
},
{
"ref":"opshin.ledger.api_v2.DCertGenesis.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.DCertMir",
-"url":20,
+"url":21,
"doc":"DCertMir()"
},
{
"ref":"opshin.ledger.api_v2.DCertMir.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.NegInfPOSIXTime",
-"url":20,
+"url":21,
"doc":"Negative infinite POSIX time, used to indicate that there is no lower bound for the execution of this transaction"
},
{
"ref":"opshin.ledger.api_v2.NegInfPOSIXTime.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.FinitePOSIXTime",
-"url":20,
+"url":21,
"doc":"Finite POSIX time, used to indicate that there is a lower or upper bound for the execution of this transaction"
},
{
"ref":"opshin.ledger.api_v2.FinitePOSIXTime.time",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.FinitePOSIXTime.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.PosInfPOSIXTime",
-"url":20,
+"url":21,
"doc":"Infinite POSIX time, used to indicate that there is no upper bound for the execution of this transaction"
},
{
"ref":"opshin.ledger.api_v2.PosInfPOSIXTime.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.UpperBoundPOSIXTime",
-"url":20,
+"url":21,
"doc":"Upper bound for the execution of this transaction"
},
{
"ref":"opshin.ledger.api_v2.UpperBoundPOSIXTime.limit",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.UpperBoundPOSIXTime.closed",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.UpperBoundPOSIXTime.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.LowerBoundPOSIXTime",
-"url":20,
+"url":21,
"doc":"Lower bound for the execution of this transaction"
},
{
"ref":"opshin.ledger.api_v2.LowerBoundPOSIXTime.limit",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.LowerBoundPOSIXTime.closed",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.LowerBoundPOSIXTime.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.POSIXTimeRange",
-"url":20,
+"url":21,
"doc":"Time range in which this transaction can be executed"
},
{
"ref":"opshin.ledger.api_v2.POSIXTimeRange.lower_bound",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.POSIXTimeRange.upper_bound",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.POSIXTimeRange.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Minting",
-"url":20,
+"url":21,
"doc":"Script purpose indicating that the given policy id is being minted or burned"
},
{
"ref":"opshin.ledger.api_v2.Minting.policy_id",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Minting.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Spending",
-"url":20,
+"url":21,
"doc":"Script purpose indicating that the given transaction output is being spent, which is owned by the invoked contract"
},
{
"ref":"opshin.ledger.api_v2.Spending.tx_out_ref",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Spending.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Rewarding",
-"url":20,
+"url":21,
"doc":"Rewarding(staking_credential: Union[opshin.ledger.api_v2.StakingHash, opshin.ledger.api_v2.StakingPtr])"
},
{
"ref":"opshin.ledger.api_v2.Rewarding.staking_credential",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Rewarding.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Certifying",
-"url":20,
+"url":21,
"doc":"Certifying(d_cert: Union[opshin.ledger.api_v2.DCertDelegRegKey, opshin.ledger.api_v2.DCertDelegDeRegKey, opshin.ledger.api_v2.DCertDelegDelegate, opshin.ledger.api_v2.DCertPoolRegister, opshin.ledger.api_v2.DCertPoolRetire, opshin.ledger.api_v2.DCertGenesis, opshin.ledger.api_v2.DCertMir])"
},
{
"ref":"opshin.ledger.api_v2.Certifying.d_cert",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.Certifying.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo",
-"url":20,
+"url":21,
"doc":"A complex agglomeration of everything that could be of interest to the executed script, regarding the transaction that invoked the script"
},
{
"ref":"opshin.ledger.api_v2.TxInfo.inputs",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.reference_inputs",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.outputs",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.fee",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.mint",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.dcert",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.wdrl",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.valid_range",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.signatories",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.redeemers",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.data",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.id",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.TxInfo.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.ScriptContext",
-"url":20,
+"url":21,
"doc":"Auxiliary information about the transaction and reason for invocation of the called script."
},
{
"ref":"opshin.ledger.api_v2.ScriptContext.tx_info",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.ScriptContext.purpose",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.api_v2.ScriptContext.CONSTR_ID",
-"url":20,
+"url":21,
"doc":""
},
{
"ref":"opshin.ledger.interval",
-"url":21,
+"url":22,
"doc":"A library to assist with interval handling"
},
{
"ref":"opshin.ledger.interval.compare",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.compare_extended_helper",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.compare_extended",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.get_bool",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.compare_upper_bound",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.compare_lower_bound",
-"url":21,
+"url":22,
"doc":"",
"func":1
},
{
"ref":"opshin.ledger.interval.contains",
-"url":21,
+"url":22,
"doc":"Returns True if the interval b is entirely contained in a .",
"func":1
},
{
"ref":"opshin.ledger.interval.make_range",
-"url":21,
+"url":22,
"doc":"Create a bounded interval from the given time lower_bound up to the given upper_bound , including the given time",
"func":1
},
{
"ref":"opshin.ledger.interval.make_from",
-"url":21,
+"url":22,
"doc":"Create a bounded interval from the given time lower_bound up to infinity, including the given time",
"func":1
},
{
"ref":"opshin.ledger.interval.make_to",
-"url":21,
+"url":22,
"doc":"Create a bounded interval from negative infinity up to the given upper_bound , including the given time",
"func":1
},
{
"ref":"opshin.types",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.FunctionType",
-"url":22,
-"doc":"FunctionType(argtyps: List[opshin.types.Type], rettyp: opshin.types.Type)"
+"url":23,
+"doc":"FunctionType(argtyps: List[opshin.types.Type], rettyp: opshin.types.Type, bound_vars: List[str] = )"
},
{
"ref":"opshin.types.FunctionType.argtyps",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.FunctionType.rettyp",
-"url":22,
+"url":23,
+"doc":""
+},
+{
+"ref":"opshin.types.FunctionType.bound_vars",
+"url":23,
"doc":""
},
{
"ref":"opshin.types.FunctionType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.FunctionType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.FunctionType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.FunctionType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.FunctionType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.FunctionType.attribute",
-"url":22,
+"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.FunctionType.cmp",
-"url":22,
+"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.FunctionType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.FunctionType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.TypeInferenceError",
-"url":22,
+"url":23,
"doc":"Assertion failed."
},
{
"ref":"opshin.types.Type",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.Type.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.Type.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.Type.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.Type.attribute",
-"url":22,
+"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.Type.cmp",
-"url":22,
+"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.Type.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.Type.copy_only_attributes",
-"url":22,
-"doc":"",
+"url":23,
+"doc":"Pluthon function that returns a copy of only the attributes of the object",
+"func":1
+},
+{
+"ref":"opshin.types.Type.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.Type.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
"func":1
},
{
"ref":"opshin.types.Record",
-"url":22,
-"doc":"Record(name: str, constructor: int, fields: Union[List[Tuple[str, opshin.types.Type , frozenlist2.frozenlist])"
+"url":23,
+"doc":"Record(name: str, orig_name: str, constructor: int, fields: Union[List[Tuple[str, opshin.types.Type , frozenlist2.frozenlist])"
},
{
"ref":"opshin.types.Record.name",
-"url":22,
+"url":23,
+"doc":""
+},
+{
+"ref":"opshin.types.Record.orig_name",
+"url":23,
"doc":""
},
{
"ref":"opshin.types.Record.constructor",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.Record.fields",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.ClassType",
-"url":22,
+"url":23,
"doc":"ClassType()"
},
{
"ref":"opshin.types.ClassType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.ClassType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.ClassType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.ClassType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.ClassType.attribute",
-"url":22,
+"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.ClassType.cmp",
-"url":22,
+"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.ClassType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
+"ref":"opshin.types.ClassType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.ClassType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.AnyType",
-"url":22,
+"url":23,
"doc":"The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)"
},
{
"ref":"opshin.types.AnyType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.AnyType.attribute",
-"url":22,
+"url":23,
"doc":"The attributes of this class. Need to be a lambda that expects as first argument the object itself",
"func":1
},
{
"ref":"opshin.types.AnyType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.AnyType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.AnyType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.AnyType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.AnyType.cmp",
-"url":22,
+"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.",
+"func":1
+},
+{
+"ref":"opshin.types.AnyType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.AtomicType",
-"url":22,
+"url":23,
"doc":"AtomicType()"
},
{
"ref":"opshin.types.AtomicType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.AtomicType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.AtomicType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.AtomicType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.AtomicType.attribute",
-"url":22,
+"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.AtomicType.cmp",
-"url":22,
+"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.AtomicType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
+"ref":"opshin.types.AtomicType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.AtomicType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.RecordType",
-"url":22,
+"url":23,
"doc":"RecordType(record: opshin.types.Record)"
},
{
"ref":"opshin.types.RecordType.record",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.RecordType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.RecordType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.RecordType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.RecordType.attribute",
-"url":22,
+"url":23,
"doc":"The attributes of this class. Need to be a lambda that expects as first argument the object itself",
"func":1
},
{
"ref":"opshin.types.RecordType.cmp",
-"url":22,
+"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.RecordType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object",
"func":1
},
{
"ref":"opshin.types.RecordType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
+"ref":"opshin.types.RecordType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.RecordType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.UnionType",
-"url":22,
+"url":23,
"doc":"UnionType(typs: List[opshin.types.RecordType])"
},
{
"ref":"opshin.types.UnionType.typs",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.UnionType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.UnionType.attribute",
-"url":22,
+"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.UnionType.cmp",
-"url":22,
+"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.UnionType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.UnionType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.UnionType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.UnionType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
+"ref":"opshin.types.UnionType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.UnionType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.TupleType",
-"url":22,
+"url":23,
"doc":"TupleType(typs: List[opshin.types.Type])"
},
{
"ref":"opshin.types.TupleType.typs",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.TupleType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.TupleType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.TupleType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.TupleType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.TupleType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.TupleType.attribute",
-"url":22,
+"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.TupleType.cmp",
-"url":22,
+"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.TupleType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.TupleType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.PairType",
-"url":22,
+"url":23,
"doc":"An internal type representing built-in PlutusData pairs"
},
{
"ref":"opshin.types.PairType.l_typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.PairType.r_typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.PairType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.PairType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.PairType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.PairType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.PairType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.PairType.attribute",
-"url":22,
+"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.PairType.cmp",
-"url":22,
+"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.PairType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.PairType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.ListType",
-"url":22,
+"url":23,
"doc":"ListType(typ: opshin.types.Type)"
},
{
"ref":"opshin.types.ListType.typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.ListType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.ListType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.ListType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.ListType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.ListType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.ListType.attribute",
-"url":22,
+"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.cmp",
-"url":22,
+"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.ListType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.ListType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.DictType",
-"url":22,
+"url":23,
"doc":"DictType(key_typ: opshin.types.Type, value_typ: opshin.types.Type)"
},
{
"ref":"opshin.types.DictType.key_typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.DictType.value_typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.DictType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.DictType.attribute",
-"url":22,
+"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.DictType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.DictType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.DictType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.DictType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.DictType.cmp",
-"url":22,
+"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.DictType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.DictType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.InstanceType",
-"url":22,
+"url":23,
"doc":"InstanceType(typ: opshin.types.ClassType)"
},
{
"ref":"opshin.types.InstanceType.typ",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.InstanceType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.InstanceType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.InstanceType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.InstanceType.attribute",
-"url":22,
+"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.InstanceType.cmp",
-"url":22,
+"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.InstanceType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.InstanceType.copy_only_attributes",
-"url":22,
-"doc":"",
+"url":23,
+"doc":"Pluthon function that returns a copy of only the attributes of the object",
+"func":1
+},
+{
+"ref":"opshin.types.InstanceType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.InstanceType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
"func":1
},
{
"ref":"opshin.types.IntegerType",
-"url":22,
+"url":23,
"doc":"IntegerType()"
},
{
"ref":"opshin.types.IntegerType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.IntegerType.cmp",
-"url":22,
+"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.IntegerType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.IntegerType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.IntegerType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.IntegerType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.IntegerType.attribute",
-"url":22,
+"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.IntegerType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.IntegerType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.StringType",
-"url":22,
+"url":23,
"doc":"StringType()"
},
{
"ref":"opshin.types.StringType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.StringType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.StringType.attribute",
-"url":22,
+"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.StringType.cmp",
-"url":22,
+"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.StringType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.StringType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.StringType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
+"ref":"opshin.types.StringType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.StringType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.ByteStringType",
-"url":22,
+"url":23,
"doc":"ByteStringType()"
},
{
"ref":"opshin.types.ByteStringType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.ByteStringType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.ByteStringType.attribute",
-"url":22,
+"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.ByteStringType.cmp",
-"url":22,
+"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.ByteStringType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.ByteStringType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.ByteStringType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
+"ref":"opshin.types.ByteStringType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.ByteStringType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.BoolType",
-"url":22,
+"url":23,
"doc":"BoolType()"
},
{
"ref":"opshin.types.BoolType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.BoolType.cmp",
-"url":22,
+"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.BoolType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.BoolType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.BoolType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.BoolType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.BoolType.attribute",
-"url":22,
+"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.BoolType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.BoolType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.UnitType",
-"url":22,
+"url":23,
"doc":"UnitType()"
},
{
"ref":"opshin.types.UnitType.cmp",
-"url":22,
+"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.UnitType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
"ref":"opshin.types.UnitType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.UnitType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.UnitType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.UnitType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.UnitType.attribute",
-"url":22,
+"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.UnitType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.UnitType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.InaccessibleType",
-"url":22,
+"url":23,
"doc":"A type that blocks overwriting of a function"
},
{
"ref":"opshin.types.InaccessibleType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.InaccessibleType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.InaccessibleType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.InaccessibleType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.InaccessibleType.attribute",
-"url":22,
+"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.InaccessibleType.cmp",
-"url":22,
+"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.InaccessibleType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
+"ref":"opshin.types.InaccessibleType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.types.InaccessibleType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.types.repeated_addition",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.PowImpl",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.ByteStrIntMulImpl",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.StrIntMulImpl",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunction",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.PolymorphicFunction.type_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunction.impl_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.StrImpl",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.StrImpl.type_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.StrImpl.impl_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.IntImpl",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.IntImpl.type_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.IntImpl.impl_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.BoolImpl",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.BoolImpl.type_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.BoolImpl.impl_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.BytesImpl",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.BytesImpl.type_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.BytesImpl.impl_from_args",
-"url":22,
+"url":23,
"doc":"",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunctionType",
-"url":22,
+"url":23,
"doc":"A special type of builtin that may act differently on different parameters"
},
{
"ref":"opshin.types.PolymorphicFunctionType.polymorphic_function",
-"url":22,
+"url":23,
"doc":""
},
{
"ref":"opshin.types.PolymorphicFunctionType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunctionType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunctionType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunctionType.attribute_type",
-"url":22,
+"url":23,
"doc":"The types of the named attributes of this class",
"func":1
},
{
"ref":"opshin.types.PolymorphicFunctionType.attribute",
-"url":22,
+"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.PolymorphicFunctionType.cmp",
-"url":22,
+"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.PolymorphicFunctionType.stringify",
-"url":22,
-"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
-"func":1
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType",
-"url":22,
-"doc":"PolymorphicFunctionInstanceType(typ: opshin.types.FunctionType, polymorphic_function: opshin.types.PolymorphicFunction)"
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.typ",
-"url":22,
-"doc":""
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.polymorphic_function",
-"url":22,
-"doc":""
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.constr_type",
-"url":22,
-"doc":"The type of the constructor for this class",
-"func":1
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.constr",
-"url":22,
-"doc":"The constructor for this class",
-"func":1
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.attribute_type",
-"url":22,
-"doc":"The types of the named attributes of this class",
-"func":1
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.attribute",
-"url":22,
-"doc":"The attributes of this class. Needs to be a lambda that expects as first argument the object itself",
-"func":1
-},
-{
-"ref":"opshin.types.PolymorphicFunctionInstanceType.cmp",
-"url":22,
-"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.PolymorphicFunctionInstanceType.stringify",
-"url":22,
-"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
-"func":1
-},
-{
-"ref":"opshin.types.empty_list",
-"url":22,
-"doc":"",
+"url":23,
+"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
-"ref":"opshin.types.transform_ext_params_map",
-"url":22,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
"func":1
},
{
-"ref":"opshin.types.transform_output_map",
-"url":22,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
"func":1
},
{
-"ref":"opshin.optimize",
+"ref":"opshin.types.PolymorphicFunctionInstanceType",
"url":23,
-"doc":""
+"doc":"PolymorphicFunctionInstanceType(typ: opshin.types.FunctionType, polymorphic_function: opshin.types.PolymorphicFunction)"
},
{
-"ref":"opshin.optimize.optimize_varlen",
-"url":24,
+"ref":"opshin.types.PolymorphicFunctionInstanceType.typ",
+"url":23,
"doc":""
},
{
-"ref":"opshin.optimize.optimize_varlen.NameCollector",
-"url":24,
-"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.optimize.optimize_varlen.NameCollector.step",
-"url":24,
+"ref":"opshin.types.PolymorphicFunctionInstanceType.polymorphic_function",
+"url":23,
"doc":""
},
{
-"ref":"opshin.optimize.optimize_varlen.NameCollector.visit_Name",
-"url":24,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.constr_type",
+"url":23,
+"doc":"The type of the constructor for this class",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.NameCollector.visit_ClassDef",
-"url":24,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.constr",
+"url":23,
+"doc":"The constructor for this class",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.NameCollector.visit_FunctionDef",
-"url":24,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.attribute_type",
+"url":23,
+"doc":"The types of the named attributes of this class",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.NameCollector.visit",
-"url":25,
-"doc":"Visit a node.",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.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.optimize.optimize_varlen.bs_from_int",
-"url":24,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.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.optimize.optimize_varlen.OptimizeVarlen",
-"url":24,
-"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.types.PolymorphicFunctionInstanceType.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",
+"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.step",
-"url":24,
-"doc":""
+"ref":"opshin.types.PolymorphicFunctionInstanceType.copy_only_attributes",
+"url":23,
+"doc":"Pluthon function that returns a copy of only the attributes of the object",
+"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.varmap",
-"url":24,
-"doc":""
+"ref":"opshin.types.PolymorphicFunctionInstanceType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.visit_Module",
-"url":24,
-"doc":"",
+"ref":"opshin.types.PolymorphicFunctionInstanceType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.visit_Name",
-"url":24,
+"ref":"opshin.types.empty_list",
+"url":23,
"doc":"",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.visit_ClassDef",
-"url":24,
+"ref":"opshin.types.transform_ext_params_map",
+"url":23,
"doc":"",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.visit_FunctionDef",
-"url":24,
+"ref":"opshin.types.transform_output_map",
+"url":23,
"doc":"",
"func":1
},
{
-"ref":"opshin.optimize.optimize_varlen.OptimizeVarlen.visit",
-"url":25,
-"doc":"Visit a node.",
-"func":1
+"ref":"opshin.optimize",
+"url":24,
+"doc":""
},
{
"ref":"opshin.optimize.optimize_remove_pass",
-"url":26,
+"url":25,
"doc":""
},
{
"ref":"opshin.optimize.optimize_remove_pass.OptimizeRemovePass",
-"url":26,
+"url":25,
"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.optimize.optimize_remove_pass.OptimizeRemovePass.step",
-"url":26,
+"url":25,
"doc":""
},
{
"ref":"opshin.optimize.optimize_remove_pass.OptimizeRemovePass.visit_Pass",
-"url":26,
+"url":25,
"doc":"",
"func":1
},
{
"ref":"opshin.optimize.optimize_remove_pass.OptimizeRemovePass.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -4841,7 +5503,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_remove_comments.OptimizeRemoveDeadconstants.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -4880,7 +5542,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_remove_deadvars.NameLoadCollector.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -4926,7 +5588,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_remove_deadvars.SafeOperationVisitor.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5024,7 +5686,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_remove_deadvars.OptimizeRemoveDeadvars.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5063,7 +5725,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_const_folding.ShallowNameDefCollector.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5127,7 +5789,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_const_folding.DefinedTimesVisitor.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5233,7 +5895,7 @@ INDEX=[
},
{
"ref":"opshin.optimize.optimize_const_folding.OptimizeConstantFolding.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5261,9 +5923,20 @@ INDEX=[
"func":1
},
{
-"ref":"opshin.compiler.extend_statemonad",
+"ref":"opshin.compiler.FunctionBoundVarsCollector",
+"url":30,
+"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.compiler.FunctionBoundVarsCollector.visit_FunctionDef",
+"url":30,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.compiler.extract_function_bound_vars",
"url":30,
-"doc":"Ensures that the argument is fully evaluated before being passed into the monad (like in imperative languages)",
+"doc":"",
"func":1
},
{
@@ -5470,7 +6143,7 @@ INDEX=[
},
{
"ref":"opshin.compiler.PlutoCompiler.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5538,7 +6211,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_cast_condition.RewriteConditions.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5565,7 +6238,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_remove_type_stuff.RewriteRemoveTypeStuff.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5603,7 +6276,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_typing.RewriteImportTyping.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5630,7 +6303,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_inject_builtin_constr.RewriteInjectBuiltinsConstr.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5668,7 +6341,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_dataclasses.RewriteImportDataclasses.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5695,7 +6368,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_subscript38.RewriteSubscript38.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5734,7 +6407,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_scoping.ShallowNameDefCollector.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5744,6 +6417,16 @@ INDEX=[
"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,
+"doc":""
+},
+{
+"ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.scopes",
+"url":38,
+"doc":""
+},
+{
"ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.step",
"url":38,
"doc":""
@@ -5803,12 +6486,41 @@ INDEX=[
"func":1
},
{
+"ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit_NoneType",
+"url":38,
+"doc":"",
+"func":1
+},
+{
"ref":"opshin.rewrite.rewrite_scoping.RewriteScoping.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
+"ref":"opshin.rewrite.rewrite_scoping.RecordScoper",
+"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_scoping.RecordScoper.scope",
+"url":38,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_scoping.RecordScoper.visit_ClassDef",
+"url":38,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_scoping.RecordScoper.visit_AnnAssign",
+"url":38,
+"doc":"",
+"func":1
+},
+{
"ref":"opshin.rewrite.rewrite_augassign",
"url":39,
"doc":""
@@ -5831,7 +6543,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_augassign.RewriteAugAssign.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5875,7 +6587,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_integrity_check.RewriteImportIntegrityCheck.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5907,7 +6619,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_forbidden_overwrites.RewriteForbiddenOverwrites.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5934,7 +6646,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_inject_builtins.RewriteInjectBuiltins.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -5972,7 +6684,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_plutusdata.RewriteImportPlutusData.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -6010,7 +6722,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_uplc_builtins.RewriteImportUPLCBuiltins.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -6038,38 +6750,50 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.copy_only_attributes",
-"url":22,
+"url":23,
"doc":"Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record types and union types, this is the identity function.",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.constr_type",
-"url":22,
+"url":23,
"doc":"The type of the constructor for this class",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.constr",
-"url":22,
+"url":23,
"doc":"The constructor for this class",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.cmp",
-"url":22,
+"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.rewrite.rewrite_import_hashlib.HashType.stringify",
-"url":22,
+"url":23,
"doc":"Returns a stringified version of the object The recursive parameter informs the method whether it was invoked recursively from another invokation",
"func":1
},
{
+"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.binop_type",
+"url":23,
+"doc":"Type of a binary operation between self and other.",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_import_hashlib.HashType.binop",
+"url":23,
+"doc":"Implements a binary operation between self and other",
+"func":1
+},
+{
"ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib",
"url":45,
-"doc":"Create a collection of name/value pairs. Example enumeration: >>> class Color(Enum): . RED = 1 . BLUE = 2 . GREEN = 3 Access them by: - attribute access >>> Color.RED - value lookup: >>> Color(1) - name lookup: >>> Color['RED'] Enumerations can be iterated over, and know how many members they have: >>> len(Color) 3 >>> list(Color) [ , , ] Methods can be added to enumerations, and members can have their own attributes see the documentation for details."
+"doc":"An enumeration."
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.PythonHashlib.sha256",
@@ -6109,7 +6833,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_import_hashlib.RewriteImportHashlib.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -6147,7 +6871,7 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_tuple_assign.RewriteTupleAssign.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
@@ -6174,1126 +6898,1369 @@ INDEX=[
},
{
"ref":"opshin.rewrite.rewrite_comparison_chaining.RewriteComparisonChaining.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
-"ref":"opshin.rewrite.rewrite_import",
+"ref":"opshin.rewrite.rewrite_forbidden_return",
"url":48,
"doc":""
},
{
-"ref":"opshin.rewrite.rewrite_import.import_module",
+"ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn",
+"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_forbidden_return.RewriteForbiddenReturn.step",
+"url":48,
+"doc":""
+},
+{
+"ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.visit_Return",
+"url":48,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.visit_FunctionDef",
"url":48,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_forbidden_return.RewriteForbiddenReturn.visit",
+"url":26,
+"doc":"Visit a node.",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_import",
+"url":49,
+"doc":""
+},
+{
+"ref":"opshin.rewrite.rewrite_import.import_module",
+"url":49,
"doc":"An approximate implementation of import.",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import.RewriteLocation",
-"url":48,
+"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_import.RewriteLocation.visit",
-"url":48,
+"url":49,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import.RewriteImport",
-"url":48,
+"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_import.RewriteImport.step",
-"url":48,
+"url":49,
"doc":""
},
{
"ref":"opshin.rewrite.rewrite_import.RewriteImport.visit_ImportFrom",
-"url":48,
+"url":49,
"doc":"",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_import.RewriteImport.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_orig_name",
-"url":49,
+"url":50,
"doc":""
},
{
"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName",
-"url":49,
+"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_orig_name.RewriteOrigName.step",
-"url":49,
+"url":50,
"doc":""
},
{
"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_Name",
-"url":49,
+"url":50,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_ClassDef",
+"url":50,
"doc":"",
"func":1
},
{
-"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_ClassDef",
-"url":49,
+"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_NoneType",
+"url":50,
"doc":"",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit_FunctionDef",
-"url":49,
+"url":50,
"doc":"",
"func":1
},
{
"ref":"opshin.rewrite.rewrite_orig_name.RewriteOrigName.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.std",
-"url":50,
+"url":51,
"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":51,
+"url":52,
"doc":"A special libary that gives access to a function that checks the integrity of PlutusDatum objects."
},
{
"ref":"opshin.std.integrity.check_integrity",
-"url":51,
+"url":52,
"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":52,
+"url":53,
"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":52,
+"url":53,
"doc":"Adds two integers and returns the result.",
"func":1
},
{
"ref":"opshin.std.builtins.subtract_integer",
-"url":52,
+"url":53,
"doc":"Subtract fist integer by second and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.multiply_integer",
-"url":52,
+"url":53,
"doc":"Multiply 2 integers and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.divide_integer",
-"url":52,
+"url":53,
"doc":"Divide first integer by second and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.quotient_integer",
-"url":52,
+"url":53,
"doc":"Quotient of first integer by second and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.remainder_integer",
-"url":52,
+"url":53,
"doc":"Remainder of first integer by second and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.mod_integer",
-"url":52,
+"url":53,
"doc":"Modulus of first integer by second and return the result.",
"func":1
},
{
"ref":"opshin.std.builtins.equals_integer",
-"url":52,
+"url":53,
"doc":"Equality between two integers.",
"func":1
},
{
"ref":"opshin.std.builtins.less_than_integer",
-"url":52,
+"url":53,
"doc":"Returns x < y",
"func":1
},
{
"ref":"opshin.std.builtins.less_than_equals_integer",
-"url":52,
+"url":53,
"doc":"Returns x <= y.",
"func":1
},
{
"ref":"opshin.std.builtins.append_byte_string",
-"url":52,
+"url":53,
"doc":"Concatenate two bytestrings.",
"func":1
},
{
"ref":"opshin.std.builtins.cons_byte_string",
-"url":52,
+"url":53,
"doc":"Prepend a byte, represented by a natural number (Integer), to a bytestring.",
"func":1
},
{
"ref":"opshin.std.builtins.slice_byte_string",
-"url":52,
+"url":53,
"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":52,
+"url":53,
"doc":"Get the length of a bytestring.",
"func":1
},
{
"ref":"opshin.std.builtins.index_byte_string",
-"url":52,
+"url":53,
"doc":"Get the byte at given index from a bytestring.",
"func":1
},
{
"ref":"opshin.std.builtins.equals_byte_string",
-"url":52,
+"url":53,
"doc":"Returns x y.",
"func":1
},
{
"ref":"opshin.std.builtins.less_than_byte_string",
-"url":52,
+"url":53,
"doc":"Returns x < y.",
"func":1
},
{
"ref":"opshin.std.builtins.less_than_equals_byte_string",
-"url":52,
+"url":53,
"doc":"Returns x <= y.",
"func":1
},
{
"ref":"opshin.std.builtins.sha2_256",
-"url":52,
+"url":53,
"doc":"Hash a bytestring using SHA-256.",
"func":1
},
{
"ref":"opshin.std.builtins.sha3_256",
-"url":52,
+"url":53,
"doc":"Hash a bytestring using SHA3-256.",
"func":1
},
{
"ref":"opshin.std.builtins.blake2b_256",
-"url":52,
+"url":53,
"doc":"Hash a bytestring using Blake2B-256.",
"func":1
},
{
"ref":"opshin.std.builtins.verify_ed25519_signature",
-"url":52,
+"url":53,
"doc":"Given PubKey, Message, and Signature, verify the Ed25519 signature.",
"func":1
},
{
"ref":"opshin.std.builtins.verify_ecdsa_secp256k1_signature",
-"url":52,
+"url":53,
"doc":"Given PubKey, Message, and Signature, verify the ECDSA signature.",
"func":1
},
{
"ref":"opshin.std.builtins.verify_schnorr_secp256k1_signature",
-"url":52,
+"url":53,
"doc":"Given PubKey, Message, and Signature, verify the Schnorr signature.",
"func":1
},
{
"ref":"opshin.std.builtins.append_string",
-"url":52,
+"url":53,
"doc":"Concatenate two strings/texts.",
"func":1
},
{
"ref":"opshin.std.builtins.equals_string",
-"url":52,
+"url":53,
"doc":"Returns x y.",
"func":1
},
{
"ref":"opshin.std.builtins.encode_utf8",
-"url":52,
+"url":53,
"doc":"Encode a string/text using UTF-8.",
"func":1
},
{
"ref":"opshin.std.builtins.decode_utf8",
-"url":52,
+"url":53,
"doc":"Decode a string/text using UTF-8.",
"func":1
},
{
"ref":"opshin.std.builtins.constr_data",
-"url":52,
+"url":53,
"doc":"Create a datum with constructor id x and fields y.",
"func":1
},
{
"ref":"opshin.std.builtins.equals_data",
-"url":52,
+"url":53,
"doc":"Equality between two complex classes.",
"func":1
},
{
"ref":"opshin.std.builtins.serialise_data",
-"url":52,
+"url":53,
"doc":"Serialize a datum into its CBOR representation.",
"func":1
},
{
"ref":"opshin.std.bitmap",
-"url":53,
+"url":54,
"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":53,
+"url":54,
"doc":"Creates an empty bitmap with size bits",
"func":1
},
{
"ref":"opshin.std.bitmap.test_bitmap",
-"url":53,
+"url":54,
"doc":"Tests if bit at position i has been set to 1",
"func":1
},
{
"ref":"opshin.std.bitmap.set_bitmap",
-"url":53,
+"url":54,
"doc":"Sets a bit in the bitmap to 1",
"func":1
},
{
"ref":"opshin.std.bitmap.reset_bitmap",
-"url":53,
+"url":54,
"doc":"Sets a bit in the bitmap to 0",
"func":1
},
{
"ref":"opshin.std.bitmap.flip_bitmap",
-"url":53,
+"url":54,
"doc":"Flips a bit in the bitmap",
"func":1
},
{
"ref":"opshin.std.bitmap.size_bitmap",
-"url":53,
+"url":54,
"doc":"Returns the size of the bitmap in bits",
"func":1
},
{
"ref":"opshin.std.bitmap.any_bitmap",
-"url":53,
+"url":54,
"doc":"Returns whether any bit was set to 1",
"func":1
},
{
"ref":"opshin.std.bitmap.all_bitmap",
-"url":53,
+"url":54,
"doc":"Returns whether all bits were set to 1",
"func":1
},
{
"ref":"opshin.std.bitmap.none_bitmap",
-"url":53,
+"url":54,
"doc":"Returns whether no bits were set to 1",
"func":1
},
{
"ref":"opshin.std.math",
-"url":54,
+"url":55,
"doc":"An implementation of some math operations in opshin"
},
{
"ref":"opshin.std.math.gcd",
-"url":54,
+"url":55,
"doc":"",
"func":1
},
{
"ref":"opshin.std.math.sign",
-"url":54,
+"url":55,
"doc":"",
"func":1
},
{
"ref":"opshin.std.math.unsigned_int_from_bytes_big",
-"url":54,
+"url":55,
"doc":"Converts a bytestring into the corresponding integer, big/network byteorder, unsigned",
"func":1
},
{
"ref":"opshin.std.math.ceil",
-"url":54,
+"url":55,
"doc":"Returns a divided by b rounded towards positive infinity",
"func":1
},
{
"ref":"opshin.std.math.floor",
-"url":54,
+"url":55,
"doc":"Returns a divided by b rounded towards negative infinity",
"func":1
},
{
"ref":"opshin.std.hashlib",
-"url":55,
+"url":56,
"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":56,
+"url":57,
"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":56,
+"url":57,
"doc":"Fraction(numerator: int, denominator: int)"
},
{
"ref":"opshin.std.fractions.Fraction.numerator",
-"url":56,
+"url":57,
"doc":""
},
{
"ref":"opshin.std.fractions.Fraction.denominator",
-"url":56,
+"url":57,
"doc":""
},
{
"ref":"opshin.std.fractions.Fraction.CONSTR_ID",
-"url":56,
+"url":57,
"doc":""
},
{
"ref":"opshin.std.fractions.add_fraction",
-"url":56,
+"url":57,
"doc":"returns a + b",
"func":1
},
{
"ref":"opshin.std.fractions.neg_fraction",
-"url":56,
+"url":57,
"doc":"returns -a",
"func":1
},
{
"ref":"opshin.std.fractions.sub_fraction",
-"url":56,
+"url":57,
"doc":"returns a - b",
"func":1
},
{
"ref":"opshin.std.fractions.mul_fraction",
-"url":56,
+"url":57,
"doc":"returns a b",
"func":1
},
{
"ref":"opshin.std.fractions.div_fraction",
-"url":56,
+"url":57,
"doc":"returns a / b",
"func":1
},
{
"ref":"opshin.std.fractions.norm_fraction",
-"url":56,
+"url":57,
"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":56,
+"url":57,
"doc":"returns a >= b",
"func":1
},
{
"ref":"opshin.std.fractions.le_fraction",
-"url":56,
+"url":57,
"doc":"returns a <= b",
"func":1
},
{
"ref":"opshin.std.fractions.eq_fraction",
-"url":56,
+"url":57,
"doc":"returns a b",
"func":1
},
{
"ref":"opshin.std.fractions.lt_fraction",
-"url":56,
+"url":57,
"doc":"returns a < b",
"func":1
},
{
"ref":"opshin.std.fractions.gt_fraction",
-"url":56,
+"url":57,
"doc":"returns a > b",
"func":1
},
{
"ref":"opshin.std.fractions.floor_fraction",
-"url":56,
+"url":57,
"doc":"",
"func":1
},
{
"ref":"opshin.std.fractions.ceil_fraction",
-"url":56,
+"url":57,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference",
-"url":57,
+"url":58,
"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":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.constant_type",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.union_types",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.intersection_types",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.TypeCheckVisitor",
-"url":57,
+"url":58,
"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":57,
+"url":58,
"doc":"Called if no explicit visitor function exists for a node.",
"func":1
},
{
"ref":"opshin.type_inference.TypeCheckVisitor.visit_Call",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.TypeCheckVisitor.visit_BoolOp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.TypeCheckVisitor.visit_UnaryOp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.TypeCheckVisitor.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.type_inference.merge_scope",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer",
-"url":57,
+"url":58,
"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":57,
+"url":58,
"doc":""
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.scopes",
-"url":57,
+"url":58,
"doc":""
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.variable_type",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.enter_scope",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.exit_scope",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.set_variable_type",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.implement_typechecks",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.type_from_annotation",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_sequence",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ClassDef",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Constant",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Tuple",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_List",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Dict",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Assign",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_AnnAssign",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_If",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_While",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_For",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Name",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Compare",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_arg",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_arguments",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_FunctionDef",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Module",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Expr",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_BinOp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_BoolOp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_UnaryOp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Subscript",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Call",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Pass",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Return",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Attribute",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_Assert",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_RawPlutoExpr",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_IfExp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_comprehension",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ListComp",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_FormattedValue",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_JoinedStr",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit_ImportFrom",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.generic_visit",
-"url":57,
+"url":58,
"doc":"Called if no explicit visitor function exists for a node.",
"func":1
},
{
"ref":"opshin.type_inference.AggressiveTypeInferencer.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader",
-"url":57,
+"url":58,
"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":57,
+"url":58,
+"doc":""
+},
+{
+"ref":"opshin.type_inference.RecordReader.orig_name",
+"url":58,
"doc":""
},
{
"ref":"opshin.type_inference.RecordReader.constructor",
-"url":57,
+"url":58,
"doc":""
},
{
"ref":"opshin.type_inference.RecordReader.attributes",
-"url":57,
+"url":58,
"doc":""
},
{
"ref":"opshin.type_inference.RecordReader.extract",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.visit_AnnAssign",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.visit_ClassDef",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.visit_Pass",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.visit_Assign",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.visit_Expr",
-"url":57,
+"url":58,
"doc":"",
"func":1
},
{
"ref":"opshin.type_inference.RecordReader.generic_visit",
-"url":57,
+"url":58,
"doc":"Called if no explicit visitor function exists for a node.",
"func":1
},
{
"ref":"opshin.type_inference.typed_ast",
-"url":57,
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.map_to_orig_name",
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor",
+"url":58,
+"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,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor.visit_If",
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor.visit_For",
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor.visit_While",
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor.visit_Return",
+"url":58,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.type_inference.ReturnExtractor.check_fulfills",
+"url":58,
"doc":"",
"func":1
},
{
+"ref":"opshin.type_inference.ReturnExtractor.visit",
+"url":26,
+"doc":"Visit a node.",
+"func":1
+},
+{
"ref":"opshin.util",
-"url":25,
+"url":26,
"doc":""
},
{
"ref":"opshin.util.distinct",
-"url":25,
+"url":26,
"doc":"Returns true iff the list consists of distinct elements",
"func":1
},
{
"ref":"opshin.util.TypedNodeTransformer",
-"url":25,
+"url":26,
"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.util.TypedNodeTransformer.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.util.TypedNodeVisitor",
-"url":25,
+"url":26,
"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.util.TypedNodeVisitor.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.util.CompilerError",
-"url":25,
+"url":26,
"doc":"Common base class for all non-exit exceptions."
},
{
"ref":"opshin.util.CompilingNodeTransformer",
-"url":25,
+"url":26,
"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.util.CompilingNodeTransformer.step",
-"url":25,
+"url":26,
"doc":""
},
{
"ref":"opshin.util.CompilingNodeTransformer.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.util.NoOp",
-"url":25,
+"url":26,
"doc":"A variation of the Compiling Node transformer that performs no changes"
},
{
"ref":"opshin.util.NoOp.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.util.CompilingNodeVisitor",
-"url":25,
+"url":26,
"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.util.CompilingNodeVisitor.step",
-"url":25,
+"url":26,
"doc":""
},
{
"ref":"opshin.util.CompilingNodeVisitor.visit",
-"url":25,
+"url":26,
"doc":"Visit a node.",
"func":1
},
{
"ref":"opshin.util.data_from_json",
-"url":25,
+"url":26,
"doc":"",
"func":1
},
{
"ref":"opshin.util.datum_to_cbor",
-"url":25,
+"url":26,
"doc":"",
"func":1
},
{
"ref":"opshin.util.datum_to_json",
-"url":25,
+"url":26,
"doc":"",
"func":1
},
{
"ref":"opshin.util.custom_fix_missing_locations",
-"url":25,
+"url":26,
"doc":"Works like ast.fix_missing_location but forces it onto everything",
"func":1
},
{
"ref":"opshin.util.make_pattern",
-"url":25,
+"url":26,
"doc":"Creates a shared pattern from the given lambda, cached so that it is re-used in subsequent calls",
"func":1
},
{
"ref":"opshin.util.patternize",
-"url":25,
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.force_params",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameWriteCollector",
+"url":26,
+"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.util.NameWriteCollector.step",
+"url":26,
+"doc":""
+},
+{
+"ref":"opshin.util.NameWriteCollector.visit_Name",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameWriteCollector.visit_ClassDef",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameWriteCollector.visit_FunctionDef",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameWriteCollector.visit",
+"url":26,
+"doc":"Visit a node.",
+"func":1
+},
+{
+"ref":"opshin.util.written_vars",
+"url":26,
+"doc":"Returns all variable names written to in this node",
+"func":1
+},
+{
+"ref":"opshin.util.NameReadCollector",
+"url":26,
+"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.util.NameReadCollector.step",
+"url":26,
+"doc":""
+},
+{
+"ref":"opshin.util.NameReadCollector.visit_AnnAssign",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameReadCollector.visit_FunctionDef",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameReadCollector.visit_Name",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameReadCollector.visit_ClassDef",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.NameReadCollector.visit",
+"url":26,
+"doc":"Visit a node.",
+"func":1
+},
+{
+"ref":"opshin.util.read_vars",
+"url":26,
+"doc":"Returns all variable names read to in this node",
+"func":1
+},
+{
+"ref":"opshin.util.all_vars",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.externally_bound_vars",
+"url":26,
+"doc":"A superset of the variables bound from an outer scope",
+"func":1
+},
+{
+"ref":"opshin.util.opshin_name_scheme_compatible_varname",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.OVar",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.OLambda",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.OLet",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.SafeLambda",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.SafeOLambda",
+"url":26,
+"doc":"",
+"func":1
+},
+{
+"ref":"opshin.util.SafeApply",
+"url":26,
"doc":"",
"func":1
},
{
"ref":"opshin.prelude",
-"url":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.Nothing",
-"url":58,
+"url":59,
"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":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.Token",
-"url":58,
+"url":59,
"doc":"A token, represented by policy id and token name"
},
{
"ref":"opshin.prelude.Token.policy_id",
-"url":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.Token.token_name",
-"url":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.Token.CONSTR_ID",
-"url":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.Nothing",
-"url":58,
+"url":59,
"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":58,
+"url":59,
"doc":""
},
{
"ref":"opshin.prelude.all_tokens_unlocked_from_address",
-"url":58,
+"url":59,
"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":58,
+"url":59,
"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":58,
+"url":59,
"doc":"Returns how many tokens of specified type are locked at the given address",
"func":1
},
{
"ref":"opshin.prelude.resolve_spent_utxo",
-"url":58,
+"url":59,
"doc":"Returns the UTxO whose spending should be validated",
"func":1
},
{
"ref":"opshin.prelude.resolve_datum_unsafe",
-"url":58,
+"url":59,
"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":58,
+"url":59,
"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":58,
+"url":59,
"doc":"",
"func":1
},
{
"ref":"opshin.prelude.own_policy_id",
-"url":58,
+"url":59,
"doc":"obtain the policy id for which this contract can validate minting/burning",
"func":1
},
{
"ref":"opshin.prelude.own_address",
-"url":58,
+"url":59,
"doc":"Computes the spending script address corresponding to the given policy ID",
"func":1
},
{
"ref":"opshin.prelude.token_present_in_inputs",
-"url":58,
+"url":59,
"doc":"Returns whether the given token is spent in one of the inputs of the transaction",
"func":1
}
diff --git a/docs/opshin/builder.html b/docs/opshin/builder.html
index 10531994..08131ecb 100644
--- a/docs/opshin/builder.html
+++ b/docs/opshin/builder.html
@@ -926,10 +926,10 @@
pass_through defines how many parameters x would normally take and should be passed through to x
"""
- return plt.Lambda(
+ return OLambda(
[f"v{i}" for i in range(pass_through)] + ["a0", "a1"],
- plt.Let(
- [("p", plt.Apply(x, *(plt.Var(f"v{i}") for i in range(pass_through))))],
+ OLet(
+ [("p", plt.Apply(x, *(OVar(f"v{i}") for i in range(pass_through))))],
plt.Ite(
# if the second argument has constructor 0 = script context
plt.DelayedChooseData(
- plt.Var("a1"),
- plt.EqualsInteger(plt.Constructor(plt.Var("a1")), plt.Integer(0)),
+ OVar("a1"),
+ plt.EqualsInteger(plt.Constructor(OVar("a1")), plt.Integer(0)),
plt.Bool(False),
plt.Bool(False),
plt.Bool(False),
@@ -247,38 +194,40 @@
Module opshin.compiler
),
# call the validator with a0, a1, and plug in "Nothing" for data
plt.Apply(
- plt.Var("p"),
+ OVar("p"),
plt.UPLCConstant(uplc.PlutusConstr(6, [])),
- plt.Var("a0"),
- plt.Var("a1"),
+ OVar("a0"),
+ OVar("a1"),
),
# else call the validator with a0, a1 and return (now partially bound)
- plt.Apply(plt.Var("p"), plt.Var("a0"), plt.Var("a1")),
+ plt.Apply(OVar("p"), OVar("a0"), OVar("a1")),
),
),
)
-def extend_statemonad(
- names: typing.List[str],
- values: typing.List[plt.AST],
- old_statemonad: plt.FunctionalMap,
-):
- """Ensures that the argument is fully evaluated before being passed into the monad (like in imperative languages)"""
- assert len(names) == len(values), "Unequal amount of names and values passed in"
- lam_names = [f"a{i}" for i, _ in enumerate(names)]
- return plt.Apply(
- plt.Lambda(
- lam_names,
- plt.FunctionalMapExtend(
- old_statemonad, names, [plt.Var(n) for n in lam_names]
- ),
- ),
- *values,
- )
+CallAST = typing.Callable[[plt.AST], plt.AST]
+
+class FunctionBoundVarsCollector(NodeVisitor):
+ def __init__(self):
+ self.functions_bound_vars: typing.Dict[
+ FunctionType, typing.List[str]
+ ] = defaultdict(list)
+
+ def visit_FunctionDef(self, node: FunctionDef) -> None:
+ self.functions_bound_vars[node.typ.typ] = sorted(
+ set(self.functions_bound_vars[node.typ.typ] + externally_bound_vars(node))
+ )
+ self.generic_visit(node)
-INITIAL_STATE = plt.FunctionalMap()
+
+def extract_function_bound_vars(
+ node: AST,
+) -> typing.Dict[FunctionType, typing.List[str]]:
+ e = FunctionBoundVarsCollector()
+ e.visit(node)
+ return e.functions_bound_vars
class PlutoCompiler(CompilingNodeTransformer):
@@ -289,51 +238,42 @@
Module opshin.compiler
step = "Compiling python statements to UPLC"
def __init__(self, force_three_params=False, validator_function_name="validator"):
+ # parameters
self.force_three_params = force_three_params
self.validator_function_name = validator_function_name
+ # marked knowledge during compilation
+ self.current_function_typ: typing.List[FunctionType] = []
+ self.function_bound_vars: typing.Dict[
+ FunctionType, typing.List[str]
+ ] = defaultdict(list)
- def visit_sequence(self, node_seq: typing.List[typedstmt]) -> plt.AST:
- s = plt.Var(STATEMONAD)
- for n in node_seq:
- compiled_stmt = self.visit(n)
- s = plt.Apply(compiled_stmt, s)
- return plt.Lambda([STATEMONAD], s)
+ def visit_sequence(self, node_seq: typing.List[typedstmt]) -> CallAST:
+ def g(s: plt.AST):
+ for n in reversed(node_seq):
+ compiled_stmt = self.visit(n)
+ s = compiled_stmt(s)
+ return s
+
+ return g
def visit_BinOp(self, node: TypedBinOp) -> plt.AST:
- opmap = BinOpMap.get(type(node.op))
- if opmap is None:
- raise NotImplementedError(f"Operation {node.op} is not implemented")
- opmap2 = opmap.get(node.left.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ}"
- )
- op = opmap2.get(node.right.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ} and right type {node.right.typ}"
- )
- return plt.Lambda(
- [STATEMONAD],
- op(
- plt.Apply(self.visit(node.left), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.right), plt.Var(STATEMONAD)),
- ),
+ op = node.left.typ.binop(node.op, node.right)
+ return plt.Apply(
+ op,
+ self.visit(node.left),
+ self.visit(node.right),
)
def visit_BoolOp(self, node: TypedBoolOp) -> plt.AST:
op = BoolOpMap.get(type(node.op))
assert len(node.values) >= 2, "Need to compare at least to values"
ops = op(
- plt.Apply(self.visit(node.values[0]), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.values[1]), plt.Var(STATEMONAD)),
+ self.visit(node.values[0]),
+ self.visit(node.values[1]),
)
for v in node.values[2:]:
- ops = op(ops, plt.Apply(self.visit(v), plt.Var(STATEMONAD)))
- return plt.Lambda(
- [STATEMONAD],
- ops,
- )
+ ops = op(ops, self.visit(v))
+ return ops
def visit_UnaryOp(self, node: TypedUnaryOp) -> plt.AST:
opmap = UnaryOpMap.get(type(node.op))
@@ -342,10 +282,7 @@
Module opshin.compiler
assert (
op is not None
), f"Operator {type(node.op)} is not supported for type {node.operand.typ}"
- return plt.Lambda(
- [STATEMONAD],
- op(plt.Apply(self.visit(node.operand), plt.Var(STATEMONAD))),
- )
+ return op(self.visit(node.operand))
def visit_Compare(self, node: TypedCompare) -> plt.AST:
assert len(node.ops) == 1, "Only single comparisons are supported"
@@ -353,21 +290,16 @@
Module opshin.compiler
cmpop = node.ops[0]
comparator = node.comparators[0].typ
op = node.left.typ.cmp(cmpop, comparator)
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
- op,
- plt.Apply(self.visit(node.left), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.comparators[0]), plt.Var(STATEMONAD)),
- ),
+ return plt.Apply(
+ op,
+ self.visit(node.left),
+ self.visit(node.comparators[0]),
)
def visit_Module(self, node: TypedModule) -> plt.AST:
- compiled_body = plt.Apply(self.visit_sequence(node.body), INITIAL_STATE)
- if self.validator_function_name is None:
- # for libraries, just return the body (a statemonad)
- validator = compiled_body
- else:
+ # extract actually read variables by each function
+ self.function_bound_vars = extract_function_bound_vars(node)
+ if self.validator_function_name is not None:
# for validators find main function
# TODO can use more sophisiticated procedure here i.e. functions marked by comment
main_fun: typing.Optional[InstanceType] = None
@@ -411,37 +343,52 @@
Module opshin.compiler
"The second argument to the validator function potentially has constructor id 0. The validator will not be able to double function as minting script and spending script."
)
- validator = plt.Lambda(
- [f"p{i}" for i, _ in enumerate(main_fun_typ.argtyps)] or ["_"],
- transform_output_map(main_fun_typ.rettyp)(
- plt.Let(
- [
- (
- "s",
- compiled_body,
+ body = node.body + (
+ [
+ TypedReturn(
+ TypedCall(
+ func=Name(
+ id=main_fun.name,
+ typ=InstanceType(main_fun_typ),
+ ctx=Load(),
),
- (
- "g",
- plt.FunctionalMapAccess(
- plt.Var("s"),
- plt.ByteString(main_fun.name),
- plt.TraceError(
- f"NameError: {self.validator_function_name}"
+ typ=main_fun_typ.rettyp,
+ args=[
+ RawPlutoExpr(
+ expr=transform_ext_params_map(a)(
+ OVar(f"val_param{i}")
),
- ),
- ),
- ],
- plt.Apply(
- plt.Var("g"),
- *[
- transform_ext_params_map(a)(plt.Var(f"p{i}"))
+ typ=a,
+ )
for i, a in enumerate(main_fun_typ.argtyps)
],
- plt.Var("s"),
- ),
+ )
+ )
+ ]
+ )
+ self.current_function_typ.append(FunctionType([], InstanceType(AnyType())))
+ all_vs = sorted(set(all_vars(node)))
+
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = SafeOLambda(
+ [f"val_param{i}" for i, _ in enumerate(main_fun_typ.argtyps)],
+ plt.Let(
+ [
+ (
+ x,
+ plt.Delay(
+ plt.TraceError(f"NameError: {map_to_orig_name(x)}")
+ ),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
),
),
)
+ self.current_function_typ.pop()
if enable_double_func_mint_spend:
validator = wrap_validator_double_function(
validator, pass_through=len(main_fun_typ.argtyps) - 3
@@ -451,6 +398,25 @@
Module opshin.compiler
raise RuntimeError(
"The contract can not always detect if it was passed three or two parameters on-chain."
)
+ else:
+ all_vs = sorted(set(all_vars(node)))
+
+ body = node.body
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = plt.Let(
+ [
+ (
+ x,
+ plt.Delay(plt.TraceError(f"NameError: {map_to_orig_name(x)}")),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ ),
+ )
+
cp = plt.Program((1, 0, 0), validator)
return cp
@@ -465,12 +431,12 @@
Module opshin.compiler
f"The string {node.value} looks like it is supposed to be a hex-encoded bytestring but is actually utf8-encoded. Try using `bytes.fromhex('{node.value.decode()}')` instead."
)
plt_val = plt.UPLCConstant(rec_constant_map(node.value))
- return plt.Lambda([STATEMONAD], plt_val)
+ return plt_val
def visit_NoneType(self, _: typing.Optional[typing.Any]) -> plt.AST:
- return plt.Lambda([STATEMONAD], plt.Unit())
+ return plt.Unit()
- def visit_Assign(self, node: TypedAssign) -> plt.AST:
+ def visit_Assign(self, node: TypedAssign) -> CallAST:
assert (
len(node.targets) == 1
), "Assignments to more than one variable not supported yet"
@@ -478,27 +444,24 @@
Module opshin.compiler
node.targets[0], Name
), "Assignments to other things then names are not supported"
compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
varname = node.targets[0].id
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [varname],
- [plt.Apply(compiled_e, plt.Var(STATEMONAD))],
- plt.Var(STATEMONAD),
- ),
+ # first evaluate the term, then wrap in a delay
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(varname), compiled_e),
+ (varname, plt.Delay(OVar(varname))),
+ ],
+ x,
)
- def visit_AnnAssign(self, node: AnnAssign) -> plt.AST:
+ def visit_AnnAssign(self, node: AnnAssign) -> CallAST:
assert isinstance(
node.target, Name
), "Assignments to other things then names are not supported"
assert isinstance(
node.target.typ, InstanceType
), "Can only assign instances to instances"
- compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
- val = plt.Apply(compiled_e, plt.Var(STATEMONAD))
+ val = self.visit(node.value)
if isinstance(node.value.typ, InstanceType) and isinstance(
node.value.typ.typ, AnyType
):
@@ -511,13 +474,12 @@
Module opshin.compiler
# we need to map this back as it will be treated as PlutusData
# AnyType is the only type other than the builtin itself that can be cast to from builtin values
val = transform_output_map(node.value.typ)(val)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.target.id],
- [val],
- plt.Var(STATEMONAD),
- ),
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(node.target.id), val),
+ (node.target.id, plt.Delay(OVar(node.target.id))),
+ ],
+ x,
)
def visit_Name(self, node: TypedName) -> plt.AST:
@@ -526,30 +488,15 @@
Module opshin.compiler
raise NotImplementedError(f"Context {node.ctx} not supported")
if isinstance(node.typ, ClassType):
# if this is not an instance but a class, call the constructor
- return plt.Lambda(
- [STATEMONAD],
- node.typ.constr(),
- )
- return plt.Lambda(
- [STATEMONAD],
- plt.FunctionalMapAccess(
- plt.Var(STATEMONAD),
- plt.ByteString(node.id),
- plt.TraceError(f"NameError: {node.orig_id}"),
- ),
- )
+ return node.typ.constr()
+ return plt.Force(plt.Var(node.id))
- def visit_Expr(self, node: TypedExpr) -> plt.AST:
+ def visit_Expr(self, node: TypedExpr) -> CallAST:
# we exploit UPLCs eager evaluation here
# the expression is computed even though its value is eventually discarded
# Note this really only makes sense for Trace
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
- plt.Lambda(["_"], plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.value), plt.Var(STATEMONAD)),
- ),
- )
+ # we use an invalid name here to avoid conflicts
+ return lambda x: plt.Apply(OLambda(["0"], x), self.visit(node.value))
def visit_Call(self, node: TypedCall) -> plt.AST:
# compiled_args = " ".join(f"({self.visit(a)} {STATEMONAD})" for a in node.args)
@@ -557,106 +504,104 @@
Module opshin.compiler
# TODO function is actually not of type polymorphic function type here anymore
if isinstance(node.func.typ, PolymorphicFunctionInstanceType):
# edge case for weird builtins that are polymorphic
- func_plt = node.func.typ.polymorphic_function.impl_from_args(
- node.func.typ.typ.argtyps
+ func_plt = force_params(
+ node.func.typ.polymorphic_function.impl_from_args(
+ node.func.typ.typ.argtyps
+ )
)
else:
- func_plt = plt.Apply(self.visit(node.func), plt.Var(STATEMONAD))
+ assert isinstance(node.func.typ, InstanceType) and isinstance(
+ node.func.typ.typ, FunctionType
+ )
+ func_plt = self.visit(node.func)
+ bound_vs = self.function_bound_vars[node.func.typ.typ]
args = []
for a, t in zip(node.args, node.func.typ.typ.argtyps):
assert isinstance(t, InstanceType)
# pass in all arguments evaluated with the statemonad
- a_int = plt.Apply(self.visit(a), plt.Var(STATEMONAD))
+ a_int = self.visit(a)
if isinstance(t.typ, AnyType):
# if the function expects input of generic type data, wrap data before passing it inside
a_int = transform_output_map(a.typ)(a_int)
args.append(a_int)
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
+ # First assign to let to ensure that the arguments are evaluated before the call, but need to delay
+ # as this is a variable assignment
+ # Also bring all states of variables read inside the function into scope / update with value in current state
+ # before call to simulate statemonad with current state being passed in
+ return OLet(
+ [(f"p{i}", a) for i, a in enumerate(args)],
+ SafeApply(
func_plt,
- *args,
- # eventually pass in the state monad as well
- plt.Var(STATEMONAD),
+ *[plt.Var(n) for n in bound_vs],
+ *[plt.Delay(OVar(f"p{i}")) for i in range(len(args))],
),
)
- def visit_FunctionDef(self, node: TypedFunctionDef) -> plt.AST:
+ def visit_FunctionDef(self, node: TypedFunctionDef) -> CallAST:
body = node.body.copy()
- if not body or not isinstance(body[-1], Return):
- tr = Return(TypedConstant(None, typ=NoneInstanceType))
- tr.typ = NoneInstanceType
- body.append(tr)
- compiled_body = self.visit_sequence(body[:-1])
- args_state = (
- extend_statemonad(
- # the function can see its argument under the argument names
- [a.arg for a in node.args.args],
- [plt.Var(f"p{i}") for i in range(len(node.args.args))],
- plt.Var(STATEMONAD),
- )
- if node.args.args
- else plt.Var(STATEMONAD)
- )
- compiled_return = plt.Apply(
- self.visit(body[-1].value),
- plt.Apply(
- compiled_body,
- args_state,
- ),
- )
- if isinstance(node.typ.typ.rettyp.typ, AnyType):
- # if the function returns generic data, wrap the function return value
- compiled_return = transform_output_map(body[-1].value.typ)(compiled_return)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.name],
- [
- plt.Lambda(
- # expect the statemonad again -> this is the basis for internally available values
- [f"p{i}" for i in range(len(node.args.args))] + [STATEMONAD],
- compiled_return,
- )
- ],
- plt.Var(STATEMONAD),
- ),
+ # defaults to returning None if there is no return statement
+ if node.typ.typ.rettyp.typ == AnyType():
+ ret_val = plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ else:
+ ret_val = plt.Unit()
+ read_vs = self.function_bound_vars[node.typ.typ]
+ self.current_function_typ.append(node.typ.typ)
+ compiled_body = self.visit_sequence(body)(ret_val)
+ self.current_function_typ.pop()
+ return lambda x: plt.Let(
+ [
+ (
+ node.name,
+ plt.Delay(
+ SafeLambda(
+ read_vs + [a.arg for a in node.args.args],
+ compiled_body,
+ )
+ ),
+ )
+ ],
+ x,
)
- def visit_While(self, node: TypedWhile) -> plt.AST:
- compiled_c = self.visit(node.test)
- compiled_s = self.visit_sequence(node.body)
+ def visit_While(self, node: TypedWhile) -> CallAST:
+ # the while loop calls itself, updating the values at overwritten names
+ # by overwriting them with arguments to its self-recall
if node.orelse:
# If there is orelse, transform it to an appended sequence (TODO check if this is correct)
cn = copy(node)
cn.orelse = []
return self.visit_sequence([cn] + node.orelse)
- # return rf"(\{STATEMONAD} -> let g = (\s f -> if ({compiled_c} s) then f ({compiled_s} s) f else s) in (g {STATEMONAD} g))"
- return plt.Lambda(
- [STATEMONAD],
- plt.Let(
- bindings=[
- (
- "g",
- plt.Lambda(
- ["s", "f"],
- plt.Ite(
- plt.Apply(compiled_c, plt.Var("s")),
- plt.Apply(
- plt.Var("f"),
- plt.Apply(compiled_s, plt.Var("s")),
- plt.Var("f"),
- ),
- plt.Var("s"),
- ),
- ),
- ),
- ],
- term=plt.Apply(plt.Var("g"), plt.Var(STATEMONAD), plt.Var("g")),
+ compiled_c = self.visit(node.test)
+ compiled_s = self.visit_sequence(node.body)
+ written_vs = written_vars(node)
+ pwritten_vs = [plt.Var(x) for x in written_vs]
+ s_fun = lambda x: plt.Lambda(
+ [opshin_name_scheme_compatible_varname("while")] + written_vs,
+ plt.Ite(
+ compiled_c,
+ compiled_s(
+ plt.Apply(
+ OVar("while"),
+ OVar("while"),
+ *deepcopy(pwritten_vs),
+ )
+ ),
+ x,
),
)
- def visit_For(self, node: TypedFor) -> plt.AST:
+ return lambda x: OLet(
+ [
+ ("adjusted_next", SafeLambda(written_vs, x)),
+ (
+ "while",
+ s_fun(SafeApply(OVar("adjusted_next"), *deepcopy(pwritten_vs))),
+ ),
+ ],
+ plt.Apply(OVar("while"), OVar("while"), *deepcopy(pwritten_vs)),
+ )
+
+ def visit_For(self, node: TypedFor) -> CallAST:
if node.orelse:
# If there is orelse, transform it to an appended sequence (TODO check if this is correct)
cn = copy(node)
@@ -667,44 +612,81 @@
# Important to call this one first - it imports all further files
RewriteImport(filename=filename),
# Rewrites that simplify the python code
+ RewriteForbiddenReturn(),
OptimizeConstantFolding() if constant_folding else NoOp(),
RewriteSubscript38(),
RewriteAugAssign(),
@@ -1109,18 +1089,17 @@
Module opshin.compiler
RewriteImportDataclasses(),
RewriteInjectBuiltins(),
RewriteConditions(),
+ # Save the original names of variables
+ RewriteOrigName(),
+ RewriteScoping(),
# 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
RewriteImportUPLCBuiltins(),
RewriteInjectBuiltinsConstr(),
RewriteRemoveTypeStuff(),
- # Save the original names of variables
- RewriteOrigName(),
- RewriteScoping(),
# Apply optimizations
OptimizeRemoveDeadvars() if remove_dead_code else NoOp(),
- OptimizeVarlen(),
OptimizeRemoveDeadconstants(),
OptimizeRemovePass(),
]
@@ -1167,6 +1146,7 @@
Functions
# Important to call this one first - it imports all further files
RewriteImport(filename=filename),
# Rewrites that simplify the python code
+ RewriteForbiddenReturn(),
OptimizeConstantFolding() if constant_folding else NoOp(),
RewriteSubscript38(),
RewriteAugAssign(),
@@ -1180,18 +1160,17 @@
Functions
RewriteImportDataclasses(),
RewriteInjectBuiltins(),
RewriteConditions(),
+ # Save the original names of variables
+ RewriteOrigName(),
+ RewriteScoping(),
# 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
RewriteImportUPLCBuiltins(),
RewriteInjectBuiltinsConstr(),
RewriteRemoveTypeStuff(),
- # Save the original names of variables
- RewriteOrigName(),
- RewriteScoping(),
# Apply optimizations
OptimizeRemoveDeadvars() if remove_dead_code else NoOp(),
- OptimizeVarlen(),
OptimizeRemoveDeadconstants(),
OptimizeRemovePass(),
]
@@ -1209,32 +1188,21 @@
Ensures that the argument is fully evaluated before being passed into the monad (like in imperative languages)
+
Expand source code
-
def extend_statemonad(
- names: typing.List[str],
- values: typing.List[plt.AST],
- old_statemonad: plt.FunctionalMap,
-):
- """Ensures that the argument is fully evaluated before being passed into the monad (like in imperative languages)"""
- assert len(names) == len(values), "Unequal amount of names and values passed in"
- lam_names = [f"a{i}" for i, _ in enumerate(names)]
- return plt.Apply(
- plt.Lambda(
- lam_names,
- plt.FunctionalMapExtend(
- old_statemonad, names, [plt.Var(n) for n in lam_names]
- ),
- ),
- *values,
- )
pass_through defines how many parameters x would normally take and should be passed through to x
"""
- return plt.Lambda(
+ return OLambda(
[f"v{i}" for i in range(pass_through)] + ["a0", "a1"],
- plt.Let(
- [("p", plt.Apply(x, *(plt.Var(f"v{i}") for i in range(pass_through))))],
+ OLet(
+ [("p", plt.Apply(x, *(OVar(f"v{i}") for i in range(pass_through))))],
plt.Ite(
# if the second argument has constructor 0 = script context
plt.DelayedChooseData(
- plt.Var("a1"),
- plt.EqualsInteger(plt.Constructor(plt.Var("a1")), plt.Integer(0)),
+ OVar("a1"),
+ plt.EqualsInteger(plt.Constructor(OVar("a1")), plt.Integer(0)),
plt.Bool(False),
plt.Bool(False),
plt.Bool(False),
@@ -1340,13 +1308,13 @@
Functions
),
# call the validator with a0, a1, and plug in "Nothing" for data
plt.Apply(
- plt.Var("p"),
+ OVar("p"),
plt.UPLCConstant(uplc.PlutusConstr(6, [])),
- plt.Var("a0"),
- plt.Var("a1"),
+ OVar("a0"),
+ OVar("a1"),
),
# else call the validator with a0, a1 and return (now partially bound)
- plt.Apply(plt.Var("p"), plt.Var("a0"), plt.Var("a1")),
+ plt.Apply(OVar("p"), OVar("a0"), OVar("a1")),
),
),
)
@@ -1357,6 +1325,68 @@
Functions
Classes
+
+class FunctionBoundVarsCollector
+
+
+
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.
class PlutoCompiler(force_three_params=False, validator_function_name='validator')
@@ -1375,51 +1405,42 @@
Classes
step = "Compiling python statements to UPLC"
def __init__(self, force_three_params=False, validator_function_name="validator"):
+ # parameters
self.force_three_params = force_three_params
self.validator_function_name = validator_function_name
+ # marked knowledge during compilation
+ self.current_function_typ: typing.List[FunctionType] = []
+ self.function_bound_vars: typing.Dict[
+ FunctionType, typing.List[str]
+ ] = defaultdict(list)
- def visit_sequence(self, node_seq: typing.List[typedstmt]) -> plt.AST:
- s = plt.Var(STATEMONAD)
- for n in node_seq:
- compiled_stmt = self.visit(n)
- s = plt.Apply(compiled_stmt, s)
- return plt.Lambda([STATEMONAD], s)
+ def visit_sequence(self, node_seq: typing.List[typedstmt]) -> CallAST:
+ def g(s: plt.AST):
+ for n in reversed(node_seq):
+ compiled_stmt = self.visit(n)
+ s = compiled_stmt(s)
+ return s
+
+ return g
def visit_BinOp(self, node: TypedBinOp) -> plt.AST:
- opmap = BinOpMap.get(type(node.op))
- if opmap is None:
- raise NotImplementedError(f"Operation {node.op} is not implemented")
- opmap2 = opmap.get(node.left.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ}"
- )
- op = opmap2.get(node.right.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ} and right type {node.right.typ}"
- )
- return plt.Lambda(
- [STATEMONAD],
- op(
- plt.Apply(self.visit(node.left), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.right), plt.Var(STATEMONAD)),
- ),
+ op = node.left.typ.binop(node.op, node.right)
+ return plt.Apply(
+ op,
+ self.visit(node.left),
+ self.visit(node.right),
)
def visit_BoolOp(self, node: TypedBoolOp) -> plt.AST:
op = BoolOpMap.get(type(node.op))
assert len(node.values) >= 2, "Need to compare at least to values"
ops = op(
- plt.Apply(self.visit(node.values[0]), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.values[1]), plt.Var(STATEMONAD)),
+ self.visit(node.values[0]),
+ self.visit(node.values[1]),
)
for v in node.values[2:]:
- ops = op(ops, plt.Apply(self.visit(v), plt.Var(STATEMONAD)))
- return plt.Lambda(
- [STATEMONAD],
- ops,
- )
+ ops = op(ops, self.visit(v))
+ return ops
def visit_UnaryOp(self, node: TypedUnaryOp) -> plt.AST:
opmap = UnaryOpMap.get(type(node.op))
@@ -1428,10 +1449,7 @@
Classes
assert (
op is not None
), f"Operator {type(node.op)} is not supported for type {node.operand.typ}"
- return plt.Lambda(
- [STATEMONAD],
- op(plt.Apply(self.visit(node.operand), plt.Var(STATEMONAD))),
- )
+ return op(self.visit(node.operand))
def visit_Compare(self, node: TypedCompare) -> plt.AST:
assert len(node.ops) == 1, "Only single comparisons are supported"
@@ -1439,21 +1457,16 @@
Classes
cmpop = node.ops[0]
comparator = node.comparators[0].typ
op = node.left.typ.cmp(cmpop, comparator)
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
- op,
- plt.Apply(self.visit(node.left), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.comparators[0]), plt.Var(STATEMONAD)),
- ),
+ return plt.Apply(
+ op,
+ self.visit(node.left),
+ self.visit(node.comparators[0]),
)
def visit_Module(self, node: TypedModule) -> plt.AST:
- compiled_body = plt.Apply(self.visit_sequence(node.body), INITIAL_STATE)
- if self.validator_function_name is None:
- # for libraries, just return the body (a statemonad)
- validator = compiled_body
- else:
+ # extract actually read variables by each function
+ self.function_bound_vars = extract_function_bound_vars(node)
+ if self.validator_function_name is not None:
# for validators find main function
# TODO can use more sophisiticated procedure here i.e. functions marked by comment
main_fun: typing.Optional[InstanceType] = None
@@ -1497,37 +1510,52 @@
Classes
"The second argument to the validator function potentially has constructor id 0. The validator will not be able to double function as minting script and spending script."
)
- validator = plt.Lambda(
- [f"p{i}" for i, _ in enumerate(main_fun_typ.argtyps)] or ["_"],
- transform_output_map(main_fun_typ.rettyp)(
- plt.Let(
- [
- (
- "s",
- compiled_body,
+ body = node.body + (
+ [
+ TypedReturn(
+ TypedCall(
+ func=Name(
+ id=main_fun.name,
+ typ=InstanceType(main_fun_typ),
+ ctx=Load(),
),
- (
- "g",
- plt.FunctionalMapAccess(
- plt.Var("s"),
- plt.ByteString(main_fun.name),
- plt.TraceError(
- f"NameError: {self.validator_function_name}"
+ typ=main_fun_typ.rettyp,
+ args=[
+ RawPlutoExpr(
+ expr=transform_ext_params_map(a)(
+ OVar(f"val_param{i}")
),
- ),
- ),
- ],
- plt.Apply(
- plt.Var("g"),
- *[
- transform_ext_params_map(a)(plt.Var(f"p{i}"))
+ typ=a,
+ )
for i, a in enumerate(main_fun_typ.argtyps)
],
- plt.Var("s"),
- ),
+ )
+ )
+ ]
+ )
+ self.current_function_typ.append(FunctionType([], InstanceType(AnyType())))
+ all_vs = sorted(set(all_vars(node)))
+
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = SafeOLambda(
+ [f"val_param{i}" for i, _ in enumerate(main_fun_typ.argtyps)],
+ plt.Let(
+ [
+ (
+ x,
+ plt.Delay(
+ plt.TraceError(f"NameError: {map_to_orig_name(x)}")
+ ),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
),
),
)
+ self.current_function_typ.pop()
if enable_double_func_mint_spend:
validator = wrap_validator_double_function(
validator, pass_through=len(main_fun_typ.argtyps) - 3
@@ -1537,6 +1565,25 @@
Classes
raise RuntimeError(
"The contract can not always detect if it was passed three or two parameters on-chain."
)
+ else:
+ all_vs = sorted(set(all_vars(node)))
+
+ body = node.body
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = plt.Let(
+ [
+ (
+ x,
+ plt.Delay(plt.TraceError(f"NameError: {map_to_orig_name(x)}")),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ ),
+ )
+
cp = plt.Program((1, 0, 0), validator)
return cp
@@ -1551,12 +1598,12 @@
Classes
f"The string {node.value} looks like it is supposed to be a hex-encoded bytestring but is actually utf8-encoded. Try using `bytes.fromhex('{node.value.decode()}')` instead."
)
plt_val = plt.UPLCConstant(rec_constant_map(node.value))
- return plt.Lambda([STATEMONAD], plt_val)
+ return plt_val
def visit_NoneType(self, _: typing.Optional[typing.Any]) -> plt.AST:
- return plt.Lambda([STATEMONAD], plt.Unit())
+ return plt.Unit()
- def visit_Assign(self, node: TypedAssign) -> plt.AST:
+ def visit_Assign(self, node: TypedAssign) -> CallAST:
assert (
len(node.targets) == 1
), "Assignments to more than one variable not supported yet"
@@ -1564,27 +1611,24 @@
Classes
node.targets[0], Name
), "Assignments to other things then names are not supported"
compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
varname = node.targets[0].id
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [varname],
- [plt.Apply(compiled_e, plt.Var(STATEMONAD))],
- plt.Var(STATEMONAD),
- ),
+ # first evaluate the term, then wrap in a delay
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(varname), compiled_e),
+ (varname, plt.Delay(OVar(varname))),
+ ],
+ x,
)
- def visit_AnnAssign(self, node: AnnAssign) -> plt.AST:
+ def visit_AnnAssign(self, node: AnnAssign) -> CallAST:
assert isinstance(
node.target, Name
), "Assignments to other things then names are not supported"
assert isinstance(
node.target.typ, InstanceType
), "Can only assign instances to instances"
- compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
- val = plt.Apply(compiled_e, plt.Var(STATEMONAD))
+ val = self.visit(node.value)
if isinstance(node.value.typ, InstanceType) and isinstance(
node.value.typ.typ, AnyType
):
@@ -1597,13 +1641,12 @@
Classes
# we need to map this back as it will be treated as PlutusData
# AnyType is the only type other than the builtin itself that can be cast to from builtin values
val = transform_output_map(node.value.typ)(val)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.target.id],
- [val],
- plt.Var(STATEMONAD),
- ),
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(node.target.id), val),
+ (node.target.id, plt.Delay(OVar(node.target.id))),
+ ],
+ x,
)
def visit_Name(self, node: TypedName) -> plt.AST:
@@ -1612,30 +1655,15 @@
Classes
raise NotImplementedError(f"Context {node.ctx} not supported")
if isinstance(node.typ, ClassType):
# if this is not an instance but a class, call the constructor
- return plt.Lambda(
- [STATEMONAD],
- node.typ.constr(),
- )
- return plt.Lambda(
- [STATEMONAD],
- plt.FunctionalMapAccess(
- plt.Var(STATEMONAD),
- plt.ByteString(node.id),
- plt.TraceError(f"NameError: {node.orig_id}"),
- ),
- )
+ return node.typ.constr()
+ return plt.Force(plt.Var(node.id))
- def visit_Expr(self, node: TypedExpr) -> plt.AST:
+ def visit_Expr(self, node: TypedExpr) -> CallAST:
# we exploit UPLCs eager evaluation here
# the expression is computed even though its value is eventually discarded
# Note this really only makes sense for Trace
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
- plt.Lambda(["_"], plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.value), plt.Var(STATEMONAD)),
- ),
- )
+ # we use an invalid name here to avoid conflicts
+ return lambda x: plt.Apply(OLambda(["0"], x), self.visit(node.value))
def visit_Call(self, node: TypedCall) -> plt.AST:
# compiled_args = " ".join(f"({self.visit(a)} {STATEMONAD})" for a in node.args)
@@ -1643,106 +1671,104 @@
Classes
# TODO function is actually not of type polymorphic function type here anymore
if isinstance(node.func.typ, PolymorphicFunctionInstanceType):
# edge case for weird builtins that are polymorphic
- func_plt = node.func.typ.polymorphic_function.impl_from_args(
- node.func.typ.typ.argtyps
+ func_plt = force_params(
+ node.func.typ.polymorphic_function.impl_from_args(
+ node.func.typ.typ.argtyps
+ )
)
else:
- func_plt = plt.Apply(self.visit(node.func), plt.Var(STATEMONAD))
+ assert isinstance(node.func.typ, InstanceType) and isinstance(
+ node.func.typ.typ, FunctionType
+ )
+ func_plt = self.visit(node.func)
+ bound_vs = self.function_bound_vars[node.func.typ.typ]
args = []
for a, t in zip(node.args, node.func.typ.typ.argtyps):
assert isinstance(t, InstanceType)
# pass in all arguments evaluated with the statemonad
- a_int = plt.Apply(self.visit(a), plt.Var(STATEMONAD))
+ a_int = self.visit(a)
if isinstance(t.typ, AnyType):
# if the function expects input of generic type data, wrap data before passing it inside
a_int = transform_output_map(a.typ)(a_int)
args.append(a_int)
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
+ # First assign to let to ensure that the arguments are evaluated before the call, but need to delay
+ # as this is a variable assignment
+ # Also bring all states of variables read inside the function into scope / update with value in current state
+ # before call to simulate statemonad with current state being passed in
+ return OLet(
+ [(f"p{i}", a) for i, a in enumerate(args)],
+ SafeApply(
func_plt,
- *args,
- # eventually pass in the state monad as well
- plt.Var(STATEMONAD),
+ *[plt.Var(n) for n in bound_vs],
+ *[plt.Delay(OVar(f"p{i}")) for i in range(len(args))],
),
)
- def visit_FunctionDef(self, node: TypedFunctionDef) -> plt.AST:
+ def visit_FunctionDef(self, node: TypedFunctionDef) -> CallAST:
body = node.body.copy()
- if not body or not isinstance(body[-1], Return):
- tr = Return(TypedConstant(None, typ=NoneInstanceType))
- tr.typ = NoneInstanceType
- body.append(tr)
- compiled_body = self.visit_sequence(body[:-1])
- args_state = (
- extend_statemonad(
- # the function can see its argument under the argument names
- [a.arg for a in node.args.args],
- [plt.Var(f"p{i}") for i in range(len(node.args.args))],
- plt.Var(STATEMONAD),
- )
- if node.args.args
- else plt.Var(STATEMONAD)
- )
- compiled_return = plt.Apply(
- self.visit(body[-1].value),
- plt.Apply(
- compiled_body,
- args_state,
- ),
- )
- if isinstance(node.typ.typ.rettyp.typ, AnyType):
- # if the function returns generic data, wrap the function return value
- compiled_return = transform_output_map(body[-1].value.typ)(compiled_return)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.name],
- [
- plt.Lambda(
- # expect the statemonad again -> this is the basis for internally available values
- [f"p{i}" for i in range(len(node.args.args))] + [STATEMONAD],
- compiled_return,
- )
- ],
- plt.Var(STATEMONAD),
- ),
+ # defaults to returning None if there is no return statement
+ if node.typ.typ.rettyp.typ == AnyType():
+ ret_val = plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ else:
+ ret_val = plt.Unit()
+ read_vs = self.function_bound_vars[node.typ.typ]
+ self.current_function_typ.append(node.typ.typ)
+ compiled_body = self.visit_sequence(body)(ret_val)
+ self.current_function_typ.pop()
+ return lambda x: plt.Let(
+ [
+ (
+ node.name,
+ plt.Delay(
+ SafeLambda(
+ read_vs + [a.arg for a in node.args.args],
+ compiled_body,
+ )
+ ),
+ )
+ ],
+ x,
)
- def visit_While(self, node: TypedWhile) -> plt.AST:
- compiled_c = self.visit(node.test)
- compiled_s = self.visit_sequence(node.body)
+ def visit_While(self, node: TypedWhile) -> CallAST:
+ # the while loop calls itself, updating the values at overwritten names
+ # by overwriting them with arguments to its self-recall
if node.orelse:
# If there is orelse, transform it to an appended sequence (TODO check if this is correct)
cn = copy(node)
cn.orelse = []
return self.visit_sequence([cn] + node.orelse)
- # return rf"(\{STATEMONAD} -> let g = (\s f -> if ({compiled_c} s) then f ({compiled_s} s) f else s) in (g {STATEMONAD} g))"
- return plt.Lambda(
- [STATEMONAD],
- plt.Let(
- bindings=[
- (
- "g",
- plt.Lambda(
- ["s", "f"],
- plt.Ite(
- plt.Apply(compiled_c, plt.Var("s")),
- plt.Apply(
- plt.Var("f"),
- plt.Apply(compiled_s, plt.Var("s")),
- plt.Var("f"),
- ),
- plt.Var("s"),
- ),
- ),
- ),
- ],
- term=plt.Apply(plt.Var("g"), plt.Var(STATEMONAD), plt.Var("g")),
+ compiled_c = self.visit(node.test)
+ compiled_s = self.visit_sequence(node.body)
+ written_vs = written_vars(node)
+ pwritten_vs = [plt.Var(x) for x in written_vs]
+ s_fun = lambda x: plt.Lambda(
+ [opshin_name_scheme_compatible_varname("while")] + written_vs,
+ plt.Ite(
+ compiled_c,
+ compiled_s(
+ plt.Apply(
+ OVar("while"),
+ OVar("while"),
+ *deepcopy(pwritten_vs),
+ )
+ ),
+ x,
),
)
- def visit_For(self, node: TypedFor) -> plt.AST:
+ return lambda x: OLet(
+ [
+ ("adjusted_next", SafeLambda(written_vs, x)),
+ (
+ "while",
+ s_fun(SafeApply(OVar("adjusted_next"), *deepcopy(pwritten_vs))),
+ ),
+ ],
+ plt.Apply(OVar("while"), OVar("while"), *deepcopy(pwritten_vs)),
+ )
+
+ def visit_For(self, node: TypedFor) -> CallAST:
if node.orelse:
# If there is orelse, transform it to an appended sequence (TODO check if this is correct)
cn = copy(node)
@@ -1753,44 +1779,81 @@
def visit_AnnAssign(self, node: AnnAssign) -> CallAST:
assert isinstance(
node.target, Name
), "Assignments to other things then names are not supported"
assert isinstance(
node.target.typ, InstanceType
), "Can only assign instances to instances"
- compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
- val = plt.Apply(compiled_e, plt.Var(STATEMONAD))
+ val = self.visit(node.value)
if isinstance(node.value.typ, InstanceType) and isinstance(
node.value.typ.typ, AnyType
):
@@ -2238,18 +2296,17 @@
Methods
# we need to map this back as it will be treated as PlutusData
# AnyType is the only type other than the builtin itself that can be cast to from builtin values
val = transform_output_map(node.value.typ)(val)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.target.id],
- [val],
- plt.Var(STATEMONAD),
- ),
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(node.target.id), val),
+ (node.target.id, plt.Delay(OVar(node.target.id))),
+ ],
+ x,
)
def visit_Assign(self, node: TypedAssign) -> CallAST:
assert (
len(node.targets) == 1
), "Assignments to more than one variable not supported yet"
@@ -2292,15 +2344,14 @@
Methods
node.targets[0], Name
), "Assignments to other things then names are not supported"
compiled_e = self.visit(node.value)
- # (\{STATEMONAD} -> (\x -> if (x ==b {self.visit(node.targets[0])}) then ({compiled_e} {STATEMONAD}) else ({STATEMONAD} x)))
varname = node.targets[0].id
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [varname],
- [plt.Apply(compiled_e, plt.Var(STATEMONAD))],
- plt.Var(STATEMONAD),
- ),
+ # first evaluate the term, then wrap in a delay
+ return lambda x: plt.Let(
+ [
+ (opshin_name_scheme_compatible_varname(varname), compiled_e),
+ (varname, plt.Delay(OVar(varname))),
+ ],
+ x,
)
def visit_BinOp(self, node: TypedBinOp) -> plt.AST:
- opmap = BinOpMap.get(type(node.op))
- if opmap is None:
- raise NotImplementedError(f"Operation {node.op} is not implemented")
- opmap2 = opmap.get(node.left.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ}"
- )
- op = opmap2.get(node.right.typ)
- if opmap2 is None:
- raise NotImplementedError(
- f"Operation {node.op} is not implemented for left type {node.left.typ} and right type {node.right.typ}"
- )
- return plt.Lambda(
- [STATEMONAD],
- op(
- plt.Apply(self.visit(node.left), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.right), plt.Var(STATEMONAD)),
- ),
+ op = node.left.typ.binop(node.op, node.right)
+ return plt.Apply(
+ op,
+ self.visit(node.left),
+ self.visit(node.right),
)
@@ -2369,15 +2404,12 @@
Methods
op = BoolOpMap.get(type(node.op))
assert len(node.values) >= 2, "Need to compare at least to values"
ops = op(
- plt.Apply(self.visit(node.values[0]), plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.values[1]), plt.Var(STATEMONAD)),
+ self.visit(node.values[0]),
+ self.visit(node.values[1]),
)
for v in node.values[2:]:
- ops = op(ops, plt.Apply(self.visit(v), plt.Var(STATEMONAD)))
- return plt.Lambda(
- [STATEMONAD],
- ops,
- )
+ ops = op(ops, self.visit(v))
+ return ops
@@ -2395,33 +2427,42 @@
Methods
# TODO function is actually not of type polymorphic function type here anymore
if isinstance(node.func.typ, PolymorphicFunctionInstanceType):
# edge case for weird builtins that are polymorphic
- func_plt = node.func.typ.polymorphic_function.impl_from_args(
- node.func.typ.typ.argtyps
+ func_plt = force_params(
+ node.func.typ.polymorphic_function.impl_from_args(
+ node.func.typ.typ.argtyps
+ )
)
else:
- func_plt = plt.Apply(self.visit(node.func), plt.Var(STATEMONAD))
+ assert isinstance(node.func.typ, InstanceType) and isinstance(
+ node.func.typ.typ, FunctionType
+ )
+ func_plt = self.visit(node.func)
+ bound_vs = self.function_bound_vars[node.func.typ.typ]
args = []
for a, t in zip(node.args, node.func.typ.typ.argtyps):
assert isinstance(t, InstanceType)
# pass in all arguments evaluated with the statemonad
- a_int = plt.Apply(self.visit(a), plt.Var(STATEMONAD))
+ a_int = self.visit(a)
if isinstance(t.typ, AnyType):
# if the function expects input of generic type data, wrap data before passing it inside
a_int = transform_output_map(a.typ)(a_int)
args.append(a_int)
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
+ # First assign to let to ensure that the arguments are evaluated before the call, but need to delay
+ # as this is a variable assignment
+ # Also bring all states of variables read inside the function into scope / update with value in current state
+ # before call to simulate statemonad with current state being passed in
+ return OLet(
+ [(f"p{i}", a) for i, a in enumerate(args)],
+ SafeApply(
func_plt,
- *args,
- # eventually pass in the state monad as well
- plt.Var(STATEMONAD),
+ *[plt.Var(n) for n in bound_vs],
+ *[plt.Delay(OVar(f"p{i}")) for i in range(len(args))],
),
)
f"The string {node.value} looks like it is supposed to be a hex-encoded bytestring but is actually utf8-encoded. Try using `bytes.fromhex('{node.value.decode()}')` instead."
)
plt_val = plt.UPLCConstant(rec_constant_map(node.value))
- return plt.Lambda([STATEMONAD], plt_val)
+ return plt_val
def visit_Expr(self, node: TypedExpr) -> CallAST:
# we exploit UPLCs eager evaluation here
# the expression is computed even though its value is eventually discarded
# Note this really only makes sense for Trace
- return plt.Lambda(
- [STATEMONAD],
- plt.Apply(
- plt.Lambda(["_"], plt.Var(STATEMONAD)),
- plt.Apply(self.visit(node.value), plt.Var(STATEMONAD)),
- ),
- )
+ # we use an invalid name here to avoid conflicts
+ return lambda x: plt.Apply(OLambda(["0"], x), self.visit(node.value))
def visit_For(self, node: TypedFor) -> CallAST:
if node.orelse:
# If there is orelse, transform it to an appended sequence (TODO check if this is correct)
cn = copy(node)
@@ -2560,22 +2586,51 @@
def visit_FunctionDef(self, node: TypedFunctionDef) -> plt.AST:
- body = node.body.copy()
- if not body or not isinstance(body[-1], Return):
- tr = Return(TypedConstant(None, typ=NoneInstanceType))
- tr.typ = NoneInstanceType
- body.append(tr)
- compiled_body = self.visit_sequence(body[:-1])
- args_state = (
- extend_statemonad(
- # the function can see its argument under the argument names
- [a.arg for a in node.args.args],
- [plt.Var(f"p{i}") for i in range(len(node.args.args))],
- plt.Var(STATEMONAD),
- )
- if node.args.args
- else plt.Var(STATEMONAD)
- )
- compiled_return = plt.Apply(
- self.visit(body[-1].value),
- plt.Apply(
- compiled_body,
- args_state,
- ),
- )
- if isinstance(node.typ.typ.rettyp.typ, AnyType):
- # if the function returns generic data, wrap the function return value
- compiled_return = transform_output_map(body[-1].value.typ)(compiled_return)
- return plt.Lambda(
- [STATEMONAD],
- extend_statemonad(
- [node.name],
- [
- plt.Lambda(
- # expect the statemonad again -> this is the basis for internally available values
- [f"p{i}" for i in range(len(node.args.args))] + [STATEMONAD],
- compiled_return,
- )
- ],
- plt.Var(STATEMONAD),
- ),
+
+
+
+
+Expand source code
+
+
def visit_FunctionDef(self, node: TypedFunctionDef) -> CallAST:
+ body = node.body.copy()
+ # defaults to returning None if there is no return statement
+ if node.typ.typ.rettyp.typ == AnyType():
+ ret_val = plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ else:
+ ret_val = plt.Unit()
+ read_vs = self.function_bound_vars[node.typ.typ]
+ self.current_function_typ.append(node.typ.typ)
+ compiled_body = self.visit_sequence(body)(ret_val)
+ self.current_function_typ.pop()
+ return lambda x: plt.Let(
+ [
+ (
+ node.name,
+ plt.Delay(
+ SafeLambda(
+ read_vs + [a.arg for a in node.args.args],
+ compiled_body,
+ )
+ ),
+ )
+ ],
+ x,
)
assert isinstance(node.typ.typ, ListType)
l = empty_list(node.typ.typ.typ)
for e in reversed(node.elts):
- l = plt.MkCons(plt.Apply(self.visit(e), plt.Var(STATEMONAD)), l)
- return plt.Lambda([STATEMONAD], l)
+ l = plt.MkCons(self.visit(e), l)
+ return l
def visit_Module(self, node: TypedModule) -> plt.AST:
- compiled_body = plt.Apply(self.visit_sequence(node.body), INITIAL_STATE)
- if self.validator_function_name is None:
- # for libraries, just return the body (a statemonad)
- validator = compiled_body
- else:
+ # extract actually read variables by each function
+ self.function_bound_vars = extract_function_bound_vars(node)
+ if self.validator_function_name is not None:
# for validators find main function
# TODO can use more sophisiticated procedure here i.e. functions marked by comment
main_fun: typing.Optional[InstanceType] = None
@@ -2851,37 +2877,52 @@
Methods
"The second argument to the validator function potentially has constructor id 0. The validator will not be able to double function as minting script and spending script."
)
- validator = plt.Lambda(
- [f"p{i}" for i, _ in enumerate(main_fun_typ.argtyps)] or ["_"],
- transform_output_map(main_fun_typ.rettyp)(
- plt.Let(
- [
- (
- "s",
- compiled_body,
+ body = node.body + (
+ [
+ TypedReturn(
+ TypedCall(
+ func=Name(
+ id=main_fun.name,
+ typ=InstanceType(main_fun_typ),
+ ctx=Load(),
),
- (
- "g",
- plt.FunctionalMapAccess(
- plt.Var("s"),
- plt.ByteString(main_fun.name),
- plt.TraceError(
- f"NameError: {self.validator_function_name}"
+ typ=main_fun_typ.rettyp,
+ args=[
+ RawPlutoExpr(
+ expr=transform_ext_params_map(a)(
+ OVar(f"val_param{i}")
),
- ),
- ),
- ],
- plt.Apply(
- plt.Var("g"),
- *[
- transform_ext_params_map(a)(plt.Var(f"p{i}"))
+ typ=a,
+ )
for i, a in enumerate(main_fun_typ.argtyps)
],
- plt.Var("s"),
- ),
+ )
+ )
+ ]
+ )
+ self.current_function_typ.append(FunctionType([], InstanceType(AnyType())))
+ all_vs = sorted(set(all_vars(node)))
+
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = SafeOLambda(
+ [f"val_param{i}" for i, _ in enumerate(main_fun_typ.argtyps)],
+ plt.Let(
+ [
+ (
+ x,
+ plt.Delay(
+ plt.TraceError(f"NameError: {map_to_orig_name(x)}")
+ ),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
),
),
)
+ self.current_function_typ.pop()
if enable_double_func_mint_spend:
validator = wrap_validator_double_function(
validator, pass_through=len(main_fun_typ.argtyps) - 3
@@ -2891,6 +2932,25 @@
Methods
raise RuntimeError(
"The contract can not always detect if it was passed three or two parameters on-chain."
)
+ else:
+ all_vs = sorted(set(all_vars(node)))
+
+ body = node.body
+ # write all variables that are ever read
+ # once at the beginning so that we can always access them (only potentially causing a nameerror at runtime)
+ validator = plt.Let(
+ [
+ (
+ x,
+ plt.Delay(plt.TraceError(f"NameError: {map_to_orig_name(x)}")),
+ )
+ for x in all_vs
+ ],
+ self.visit_sequence(body)(
+ plt.ConstrData(plt.Integer(0), plt.EmptyDataList())
+ ),
+ )
+
cp = plt.Program((1, 0, 0), validator)
return cp
@@ -2910,18 +2970,8 @@
Methods
raise NotImplementedError(f"Context {node.ctx} not supported")
if isinstance(node.typ, ClassType):
# if this is not an instance but a class, call the constructor
- return plt.Lambda(
- [STATEMONAD],
- node.typ.constr(),
- )
- return plt.Lambda(
- [STATEMONAD],
- plt.FunctionalMapAccess(
- plt.Var(STATEMONAD),
- plt.ByteString(node.id),
- plt.TraceError(f"NameError: {node.orig_id}"),
- ),
- )
+ return node.typ.constr()
+ return plt.Force(plt.Var(node.id))
def visit_Return(self, node: TypedReturn) -> plt.AST:
- raise NotImplementedError(
- "Compilation of return statements except for last statement in function is not supported."
- )
+
def visit_Return(self, node: TypedReturn) -> CallAST:
+ value_plt = self.visit(node.value)
+ assert self.current_function_typ, "Can not handle Return outside of a function"
+ if isinstance(self.current_function_typ[-1].rettyp.typ, AnyType):
+ value_plt = transform_output_map(node.value.typ)(value_plt)
+ return lambda _: value_plt
@@ -3002,13 +3054,10 @@
Methods
if index < 0:
index += len(node.value.typ.typ.typs)
assert isinstance(node.ctx, Load), "Tuples are read-only"
- return plt.Lambda(
- [STATEMONAD],
- plt.FunctionalTupleAccess(
- plt.Apply(self.visit(node.value), plt.Var(STATEMONAD)),
- index,
- len(node.value.typ.typ.typs),
- ),
+ return plt.FunctionalTupleAccess(
+ self.visit(node.value),
+ index,
+ len(node.value.typ.typ.typs),
)
if isinstance(node.value.typ.typ, PairType):
assert isinstance(
@@ -3027,176 +3076,212 @@
def visit_Tuple(self, node: TypedTuple) -> plt.AST:
- return plt.Lambda(
- [STATEMONAD],
- plt.FunctionalTuple(
- *(plt.Apply(self.visit(e), plt.Var(STATEMONAD)) for e in node.elts)
- ),
- )
+ return plt.FunctionalTuple(*(self.visit(e) for e in node.elts))
@@ -3238,14 +3318,11 @@
Methods
assert (
op is not None
), f"Operator {type(node.op)} is not supported for type {node.operand.typ}"
- return plt.Lambda(
- [STATEMONAD],
- op(plt.Apply(self.visit(node.operand), plt.Var(STATEMONAD))),
- )
+ return op(self.visit(node.operand))
def visit_sequence(self, node_seq: typing.List[typedstmt]) -> plt.AST:
- s = plt.Var(STATEMONAD)
- for n in node_seq:
- compiled_stmt = self.visit(n)
- s = plt.Apply(compiled_stmt, s)
- return plt.Lambda([STATEMONAD], s)
+
def visit_sequence(self, node_seq: typing.List[typedstmt]) -> CallAST:
+ def g(s: plt.AST):
+ for n in reversed(node_seq):
+ compiled_stmt = self.visit(n)
+ s = compiled_stmt(s)
+ return s
+
+ return g
arg = args[0]
assert isinstance(arg, InstanceType), "Can only determine length of instances"
if arg == ByteStringInstanceType:
- return plt.Lambda(["x", "_"], plt.LengthOfByteString(plt.Var("x")))
+ return OLambda(["x"], plt.LengthOfByteString(OVar("x")))
elif isinstance(arg.typ, ListType) or isinstance(arg.typ, DictType):
# simple list length function
- return plt.Lambda(
- ["x", "_"],
+ return OLambda(
+ ["x"],
plt.FoldList(
- plt.Var("x"),
- plt.Lambda(
- ["a", "_"], plt.AddInteger(plt.Var("a"), plt.Integer(1))
- ),
+ OVar("x"),
+ OLambda(["a", "_"], plt.AddInteger(OVar("a"), plt.Integer(1))),
plt.Integer(0),
),
)
elif isinstance(arg.typ, TupleType):
- return plt.Lambda(
- ["x", "_"],
+ return OLambda(
+ ["x"],
plt.Integer(len(arg.typ.typs)),
)
raise NotImplementedError(f"'len' is not implemented for type {arg}")
@@ -647,22 +638,20 @@
Methods
arg = args[0]
assert isinstance(arg, InstanceType), "Can only determine length of instances"
if arg == ByteStringInstanceType:
- return plt.Lambda(["x", "_"], plt.LengthOfByteString(plt.Var("x")))
+ return OLambda(["x"], plt.LengthOfByteString(OVar("x")))
elif isinstance(arg.typ, ListType) or isinstance(arg.typ, DictType):
# simple list length function
- return plt.Lambda(
- ["x", "_"],
+ return OLambda(
+ ["x"],
plt.FoldList(
- plt.Var("x"),
- plt.Lambda(
- ["a", "_"], plt.AddInteger(plt.Var("a"), plt.Integer(1))
- ),
+ OVar("x"),
+ OLambda(["a", "_"], plt.AddInteger(OVar("a"), plt.Integer(1))),
plt.Integer(0),
),
)
elif isinstance(arg.typ, TupleType):
- return plt.Lambda(
- ["x", "_"],
+ return OLambda(
+ ["x"],
plt.Integer(len(arg.typ.typs)),
)
raise NotImplementedError(f"'len' is not implemented for type {arg}")
@@ -707,16 +696,17 @@
Methods
return FunctionType(args, NoneInstanceType)
def impl_from_args(self, args: typing.List[Type]) -> plt.AST:
+ if not args:
+ return SafeOLambda([], plt.Trace(plt.Text("\n"), plt.NoneData()))
assert all(
isinstance(arg, InstanceType) for arg in args
), "Can only stringify instances"
stringify_ops = [
- plt.Apply(arg.typ.stringify(), plt.Var(f"x{i}"), plt.Var("_"))
- for i, arg in enumerate(args)
+ plt.Apply(arg.typ.stringify(), OVar(f"x{i}")) for i, arg in enumerate(args)
]
stringify_ops_joined = sum(((x, plt.Text(" ")) for x in stringify_ops), ())[:-1]
- print = plt.Lambda(
- [f"x{i}" for i in range(len(args))] + ["_"],
+ print = SafeOLambda(
+ [f"x{i}" for i in range(len(args))],
plt.Trace(plt.ConcatString(*stringify_ops_joined), plt.NoneData()),
)
return print
@@ -737,16 +727,17 @@
Methods
Expand source code
def impl_from_args(self, args: typing.List[Type]) -> plt.AST:
+ if not args:
+ return SafeOLambda([], plt.Trace(plt.Text("\n"), plt.NoneData()))
assert all(
isinstance(arg, InstanceType) for arg in args
), "Can only stringify instances"
stringify_ops = [
- plt.Apply(arg.typ.stringify(), plt.Var(f"x{i}"), plt.Var("_"))
- for i, arg in enumerate(args)
+ plt.Apply(arg.typ.stringify(), OVar(f"x{i}")) for i, arg in enumerate(args)
]
stringify_ops_joined = sum(((x, plt.Text(" ")) for x in stringify_ops), ())[:-1]
- print = plt.Lambda(
- [f"x{i}" for i in range(len(args))] + ["_"],
+ print = SafeOLambda(
+ [f"x{i}" for i in range(len(args))],
plt.Trace(plt.ConcatString(*stringify_ops_joined), plt.NoneData()),
)
return print
Module opshin.optimize.optimize_remove_deadvars
from copy import copy
from collections import defaultdict
+from ordered_set import OrderedSet
+
from ..util import CompilingNodeVisitor, CompilingNodeTransformer
from ..type_inference import INITIAL_SCOPE
from ..typed_ast import TypedAnnAssign
@@ -163,7 +165,7 @@
Module opshin.optimize.optimize_remove_deadvars
# collect all variable names
collector = NameLoadCollector()
collector.visit(node_cp)
- loaded_vars = set(collector.loaded.keys()) | {"validator_0"}
+ loaded_vars = OrderedSet(collector.loaded.keys()) | {"validator_0"}
# break if the set of loaded vars did not change -> set of vars to remove does also not change
if loaded_vars == self.loaded_vars:
break
@@ -185,7 +187,7 @@
Module opshin.optimize.optimize_remove_deadvars
scope_orelse_cp = self.guaranteed_avail_names[-1].copy()
self.exit_scope()
# what remains after this in the scope is the intersection of both
- for var in set(scope_body_cp).intersection(scope_orelse_cp):
+ for var in OrderedSet(scope_body_cp).intersection(scope_orelse_cp):
self.set_guaranteed(var)
return node_cp
@@ -457,7 +459,7 @@
Methods
# collect all variable names
collector = NameLoadCollector()
collector.visit(node_cp)
- loaded_vars = set(collector.loaded.keys()) | {"validator_0"}
+ loaded_vars = OrderedSet(collector.loaded.keys()) | {"validator_0"}
# break if the set of loaded vars did not change -> set of vars to remove does also not change
if loaded_vars == self.loaded_vars:
break
@@ -479,7 +481,7 @@
Methods
scope_orelse_cp = self.guaranteed_avail_names[-1].copy()
self.exit_scope()
# what remains after this in the scope is the intersection of both
- for var in set(scope_body_cp).intersection(scope_orelse_cp):
+ for var in OrderedSet(scope_body_cp).intersection(scope_orelse_cp):
self.set_guaranteed(var)
return node_cp
@@ -779,7 +781,7 @@
Methods
scope_orelse_cp = self.guaranteed_avail_names[-1].copy()
self.exit_scope()
# what remains after this in the scope is the intersection of both
- for var in set(scope_body_cp).intersection(scope_orelse_cp):
+ for var in OrderedSet(scope_body_cp).intersection(scope_orelse_cp):
self.set_guaranteed(var)
return node_cp
@@ -803,7 +805,7 @@
Methods
# collect all variable names
collector = NameLoadCollector()
collector.visit(node_cp)
- loaded_vars = set(collector.loaded.keys()) | {"validator_0"}
+ loaded_vars = OrderedSet(collector.loaded.keys()) | {"validator_0"}
# break if the set of loaded vars did not change -> set of vars to remove does also not change
if loaded_vars == self.loaded_vars:
break
diff --git a/docs/opshin/optimize/optimize_varlen.html b/docs/opshin/optimize/optimize_varlen.html
deleted file mode 100644
index 7b679aef..00000000
--- a/docs/opshin/optimize/optimize_varlen.html
+++ /dev/null
@@ -1,592 +0,0 @@
-
-
-
-
-
-
-
-
-opshin.optimize.optimize_varlen API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module opshin.optimize.optimize_varlen
-
-
-
-
-Expand source code
-
-
from ast import *
-from copy import copy
-from collections import defaultdict
-
-from ..util import CompilingNodeTransformer, CompilingNodeVisitor
-
-"""
-Rewrites all variable names to a minimal length equivalent
-"""
-
-
-class NameCollector(CompilingNodeVisitor):
- step = "Collecting occuring variable names"
-
- def __init__(self):
- self.vars = defaultdict(int)
-
- def visit_Name(self, node: Name) -> None:
- self.vars[node.id] += 1
-
- def visit_ClassDef(self, node: ClassDef):
- self.vars[node.name] += 1
- # ignore the content (i.e. attribute names) of class definitions
-
- def visit_FunctionDef(self, node: FunctionDef):
- self.vars[node.name] += 1
- for a in node.args.args:
- # ignore type hints
- self.vars[a.arg] += 1
- for s in node.body:
- self.visit(s)
-
-
-def bs_from_int(i: int):
- hex_str = f"{i:x}"
- if len(hex_str) % 2 == 1:
- hex_str = "0" + hex_str
- return bytes.fromhex(hex_str)
-
-
-class OptimizeVarlen(CompilingNodeTransformer):
- step = "Reducing the length of variable names"
-
- varmap = None
-
- def visit_Module(self, node: Module) -> Module:
- # collect all variable names
- collector = NameCollector()
- collector.visit(node)
- # sort by most used
- varmap = {}
- varnames = sorted(collector.vars.items(), key=lambda x: x[1], reverse=True)
- for i, (v, _) in enumerate(varnames):
- varmap[v] = bs_from_int(i)
- self.varmap = varmap
- node_cp = copy(node)
- node_cp.body = [self.visit(s) for s in node.body]
- return node_cp
-
- def visit_Name(self, node: Name) -> Name:
- nc = copy(node)
- nc.id = self.varmap[node.id]
- return nc
-
- def visit_ClassDef(self, node: ClassDef) -> ClassDef:
- node_cp = copy(node)
- node_cp.name = self.varmap[node.name]
- # ignore the content of class definitions
- return node_cp
-
- def visit_FunctionDef(self, node: FunctionDef) -> FunctionDef:
- node_cp = copy(node)
- node_cp.name = self.varmap[node.name]
- node_cp.args = copy(node.args)
- node_cp.args.args = []
- for a in node.args.args:
- a_cp = copy(a)
- a_cp.arg = self.varmap[a.arg]
- node_cp.args.args.append(a_cp)
- node_cp.body = [self.visit(s) for s in node.body]
- return node_cp
A node visitor base class that walks the abstract syntax tree and calls a
-visitor function for every node found.
-This function may return a value
-which is forwarded by the visit method.
-
This class is meant to be subclassed, with the subclass adding visitor
-methods.
-
Per default the visitor functions for the nodes are 'visit_' +
-class name of the node.
-So a TryFinally node visit function would
-be visit_TryFinally.
-This behavior can be changed by overriding
-the visit method.
-If no visitor function exists for a node
-(return value None) the generic_visit visitor is used instead.
-
Don't use the NodeVisitor if you want to apply changes to nodes during
-traversing.
-For this a special visitor exists (NodeTransformer) that
-allows modifications.
-
-
-Expand source code
-
-
class NameCollector(CompilingNodeVisitor):
- step = "Collecting occuring variable names"
-
- def __init__(self):
- self.vars = defaultdict(int)
-
- def visit_Name(self, node: Name) -> None:
- self.vars[node.id] += 1
-
- def visit_ClassDef(self, node: ClassDef):
- self.vars[node.name] += 1
- # ignore the content (i.e. attribute names) of class definitions
-
- def visit_FunctionDef(self, node: FunctionDef):
- self.vars[node.name] += 1
- for a in node.args.args:
- # ignore type hints
- self.vars[a.arg] += 1
- for s in node.body:
- self.visit(s)
def visit_FunctionDef(self, node: FunctionDef):
- self.vars[node.name] += 1
- for a in node.args.args:
- # ignore type hints
- self.vars[a.arg] += 1
- for s in node.body:
- self.visit(s)
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']::
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 OptimizeVarlen(CompilingNodeTransformer):
- step = "Reducing the length of variable names"
-
- varmap = None
-
- def visit_Module(self, node: Module) -> Module:
- # collect all variable names
- collector = NameCollector()
- collector.visit(node)
- # sort by most used
- varmap = {}
- varnames = sorted(collector.vars.items(), key=lambda x: x[1], reverse=True)
- for i, (v, _) in enumerate(varnames):
- varmap[v] = bs_from_int(i)
- self.varmap = varmap
- node_cp = copy(node)
- node_cp.body = [self.visit(s) for s in node.body]
- return node_cp
-
- def visit_Name(self, node: Name) -> Name:
- nc = copy(node)
- nc.id = self.varmap[node.id]
- return nc
-
- def visit_ClassDef(self, node: ClassDef) -> ClassDef:
- node_cp = copy(node)
- node_cp.name = self.varmap[node.name]
- # ignore the content of class definitions
- return node_cp
-
- def visit_FunctionDef(self, node: FunctionDef) -> FunctionDef:
- node_cp = copy(node)
- node_cp.name = self.varmap[node.name]
- node_cp.args = copy(node.args)
- node_cp.args.args = []
- for a in node.args.args:
- a_cp = copy(a)
- a_cp.arg = self.varmap[a.arg]
- node_cp.args.args.append(a_cp)
- node_cp.body = [self.visit(s) for s in node.body]
- return node_cp
from ast import *
+
+from ..util import CompilingNodeTransformer
+
+"""
+Make sure that returns are not allowed in the outermost scope
+"""
+
+
+class RewriteForbiddenReturn(CompilingNodeTransformer):
+ step = "Checking for forbidden return statements"
+
+ def visit_Return(self, node):
+ raise SyntaxError(f"Forbidden return statement outside function")
+
+ def visit_FunctionDef(self, node: Name) -> Name:
+ # skip the content of the function definition
+ return node
+
+
+
+
+
+
+
+
+
+
Classes
+
+
+class RewriteForbiddenReturn
+
+
+
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']::
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 RewriteForbiddenReturn(CompilingNodeTransformer):
+ step = "Checking for forbidden return statements"
+
+ def visit_Return(self, node):
+ raise SyntaxError(f"Forbidden return statement outside function")
+
+ def visit_FunctionDef(self, node: Name) -> Name:
+ # skip the content of the function definition
+ return node
Module opshin.rewrite.rewrite_import_uplc_builtinsClasses
), "To wrap builtin functions, you need to import the builtin function. Add `from opshin.bridge import wraps_builtin` to your code."
# we replace the body with a forwarded call to the wrapped builtin
CamelCaseFunName = "".join(
- p.capitalize() for p in re.split(r"_(?!\d)", node.name)
+ p.capitalize() for p in re.split(r"_(?!\d)", node.orig_name)
)
uplc_fun = plt.__dict__[CamelCaseFunName]
pluto_expression = RawPlutoExpr(
typ=node.typ.typ.rettyp,
- expr=plt.Lambda(
- ["_"],
- uplc_fun(
- *(plt.Var(f"p{i}") for i in range(len(node.args.args))),
- ),
+ expr=uplc_fun(
+ *(plt.Force(plt.Var(a.arg)) for a in node.args.args),
),
)
node_cp = copy(node)
@@ -264,16 +258,13 @@
Methods
), "To wrap builtin functions, you need to import the builtin function. Add `from opshin.bridge import wraps_builtin` to your code."
# we replace the body with a forwarded call to the wrapped builtin
CamelCaseFunName = "".join(
- p.capitalize() for p in re.split(r"_(?!\d)", node.name)
+ p.capitalize() for p in re.split(r"_(?!\d)", node.orig_name)
)
uplc_fun = plt.__dict__[CamelCaseFunName]
pluto_expression = RawPlutoExpr(
typ=node.typ.typ.rettyp,
- expr=plt.Lambda(
- ["_"],
- uplc_fun(
- *(plt.Var(f"p{i}") for i in range(len(node.args.args))),
- ),
+ expr=uplc_fun(
+ *(plt.Force(plt.Var(a.arg)) for a in node.args.args),
),
)
node_cp = copy(node)
diff --git a/docs/opshin/rewrite/rewrite_inject_builtin_constr.html b/docs/opshin/rewrite/rewrite_inject_builtin_constr.html
index 2801fbe2..43bfde43 100644
--- a/docs/opshin/rewrite/rewrite_inject_builtin_constr.html
+++ b/docs/opshin/rewrite/rewrite_inject_builtin_constr.html
@@ -98,7 +98,7 @@
class RewriteScoping(CompilingNodeTransformer):
step = "Rewrite all variables to inambiguously point to the definition in the nearest enclosing scope"
-
- def __init__(self):
- self.latest_scope_id = 0
- self.scopes = [(set(INITIAL_SCOPE.keys()), -1)]
+ latest_scope_id: int
+ scopes: typing.List[typing.Tuple[OrderedSet, int]]
def variable_scope_id(self, name: str) -> int:
"""find the id of the scope in which this variable is defined (closest to its usage)"""
@@ -119,7 +118,7 @@
return f"{name}_{scope_id}"
def visit_Module(self, node: Module) -> Module:
+ self.latest_scope_id = 0
+ self.scopes = [(OrderedSet(INITIAL_SCOPE.keys() | FORBIDDEN_NAMES), -1)]
node_cp = copy(node)
self.enter_scope()
# vars defined in this scope
@@ -155,11 +156,7 @@
Module opshin.rewrite.rewrite_scoping
return nc
def visit_ClassDef(self, node: ClassDef) -> ClassDef:
- node_cp = copy(node)
- # setting is handled in either enclosing module or function
- node_cp.name = self.map_name(node.name)
- # ignore the content of class definitions
- return node_cp
+ return RecordScoper.scope(node, self)
def visit_FunctionDef(self, node: FunctionDef) -> FunctionDef:
node_cp = copy(node)
@@ -173,7 +170,9 @@
Module opshin.rewrite.rewrite_scoping
a_cp = copy(a)
self.set_variable_scope(a.arg)
a_cp.arg = self.map_name(a.arg)
+ a_cp.annotation = self.visit(a.annotation)
node_cp.args.args.append(a_cp)
+ node_cp.returns = self.visit(node.returns)
# vars defined in this scope
shallow_node_def_collector = ShallowNameDefCollector()
for s in node.body:
@@ -184,6 +183,34 @@
Module opshin.rewrite.rewrite_scoping
# map all vars and recurse
node_cp.body = [self.visit(s) for s in node.body]
self.exit_scope()
+ return node_cp
+
+ def visit_NoneType(self, node: None) -> None:
+ return node
+
+
+class RecordScoper(NodeTransformer):
+ _scoper: RewriteScoping
+
+ def __init__(self, scoper: RewriteScoping):
+ self._scoper = scoper
+
+ @classmethod
+ def scope(cls, c: ClassDef, scoper: RewriteScoping) -> ClassDef:
+ f = cls(scoper)
+ return f.visit(c)
+
+ def visit_ClassDef(self, c: ClassDef) -> ClassDef:
+ node_cp = copy(c)
+ node_cp.name = self._scoper.map_name(node_cp.name)
+ return self.generic_visit(node_cp)
+
+ def visit_AnnAssign(self, node: AnnAssign) -> AnnAssign:
+ assert isinstance(
+ node.target, Name
+ ), "Record elements must have named attributes"
+ node_cp = copy(node)
+ node_cp.annotation = self._scoper.visit(node_cp.annotation)
return node_cp
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']::
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.
class RewriteScoping(CompilingNodeTransformer):
step = "Rewrite all variables to inambiguously point to the definition in the nearest enclosing scope"
-
- def __init__(self):
- self.latest_scope_id = 0
- self.scopes = [(set(INITIAL_SCOPE.keys()), -1)]
+ latest_scope_id: int
+ scopes: typing.List[typing.Tuple[OrderedSet, int]]
def variable_scope_id(self, name: str) -> int:
"""find the id of the scope in which this variable is defined (closest to its usage)"""
@@ -249,7 +394,7 @@
return f"{name}_{scope_id}"
def visit_Module(self, node: Module) -> Module:
+ self.latest_scope_id = 0
+ self.scopes = [(OrderedSet(INITIAL_SCOPE.keys() | FORBIDDEN_NAMES), -1)]
node_cp = copy(node)
self.enter_scope()
# vars defined in this scope
@@ -285,11 +432,7 @@
Classes
return nc
def visit_ClassDef(self, node: ClassDef) -> ClassDef:
- node_cp = copy(node)
- # setting is handled in either enclosing module or function
- node_cp.name = self.map_name(node.name)
- # ignore the content of class definitions
- return node_cp
+ return RecordScoper.scope(node, self)
def visit_FunctionDef(self, node: FunctionDef) -> FunctionDef:
node_cp = copy(node)
@@ -303,7 +446,9 @@
Classes
a_cp = copy(a)
self.set_variable_scope(a.arg)
a_cp.arg = self.map_name(a.arg)
+ a_cp.annotation = self.visit(a.annotation)
node_cp.args.args.append(a_cp)
+ node_cp.returns = self.visit(node.returns)
# vars defined in this scope
shallow_node_def_collector = ShallowNameDefCollector()
for s in node.body:
@@ -314,7 +459,10 @@
Classes
# map all vars and recurse
node_cp.body = [self.visit(s) for s in node.body]
self.exit_scope()
- return node_cp
def visit_ClassDef(self, node: ClassDef) -> ClassDef:
- node_cp = copy(node)
- # setting is handled in either enclosing module or function
- node_cp.name = self.map_name(node.name)
- # ignore the content of class definitions
- return node_cp
+ return RecordScoper.scope(node, self)
@@ -457,7 +609,9 @@
Methods
a_cp = copy(a)
self.set_variable_scope(a.arg)
a_cp.arg = self.map_name(a.arg)
+ a_cp.annotation = self.visit(a.annotation)
node_cp.args.args.append(a_cp)
+ node_cp.returns = self.visit(node.returns)
# vars defined in this scope
shallow_node_def_collector = ShallowNameDefCollector()
for s in node.body:
@@ -481,6 +635,8 @@
Methods
Expand source code
def visit_Module(self, node: Module) -> Module:
+ self.latest_scope_id = 0
+ self.scopes = [(OrderedSet(INITIAL_SCOPE.keys() | FORBIDDEN_NAMES), -1)]
node_cp = copy(node)
self.enter_scope()
# vars defined in this scope
@@ -510,6 +666,19 @@
uid = self.unique_id
self.unique_id += 1
# write the tuple into a singleton variable
- new_for.target = Name(f"{uid}_tup", Store())
+ new_for.target = Name(f"2_{uid}_tup", Store())
assignments = []
# iteratively assign the deconstructed parts to the original variable names
for i, t in enumerate(node.target.elts):
@@ -123,7 +123,7 @@
uid = self.unique_id
self.unique_id += 1
# write the tuple into a singleton variable
- new_for.target = Name(f"{uid}_tup", Store())
+ new_for.target = Name(f"2_{uid}_tup", Store())
assignments = []
# iteratively assign the deconstructed parts to the original variable names
for i, t in enumerate(node.target.elts):
@@ -222,7 +222,7 @@
uid = self.unique_id
self.unique_id += 1
# write the tuple into a singleton variable
- new_for.target = Name(f"{uid}_tup", Store())
+ new_for.target = Name(f"2_{uid}_tup", Store())
assignments = []
# iteratively assign the deconstructed parts to the original variable names
for i, t in enumerate(node.target.elts):
@@ -320,7 +320,7 @@
from hypothesis import strategies as st
from parameterized import parameterized
-import pluthon
from uplc import ast as uplc, eval as uplc_eval
from . import PLUTUS_VM_PROFILE
-from .. import compiler, prelude, builder, Purpose, PlutusContract
+from .. import prelude, builder, Purpose, PlutusContract
from .utils import eval_uplc_value, Unit, eval_uplc
from ..bridge import wraps_builtin
@@ -100,6 +99,13 @@
Module opshin.tests.test_misc
from pycardano import RawPlutusData
from cbor2 import CBORTag
+ALL_EXAMPLES = [
+ os.path.join(root, f)
+ for root, dirs, files in os.walk("examples")
+ for f in files
+ if f.endswith(".py") and not f.startswith("broken") and not f.startswith("extract")
+]
+
def fib(n):
a, b = 0, 1
@@ -130,7 +136,16 @@
"""
eval_uplc(source_code, bytearray(b"hello"))
+ # TODO enable when pycardano version is fixed s.t. import of ByteString works
+ @unittest.expectedFailure
def test_ByteString_alternative(self):
source_code = """
def validator(
@@ -2246,8 +2499,8 @@
"""
eval_uplc(source_code, bytearray(b"hello"))
+ # TODO enable when pycardano version is fixed s.t. import of ByteString works
+ @unittest.expectedFailure
def test_ByteString_alternative(self):
source_code = """
def validator(
@@ -4540,8 +5200,8 @@
def test_dual_use_compile(self):
- # TODO devise tests for this
- input_file = "examples/smart_contracts/dual_use.py"
- with open(input_file) as fp:
- source_code = fp.read()
- builder._compile(source_code, force_three_params=True)
def test_double_import_deep(self):
+ source_code = """
+from opshin.ledger.interval import *
+from opshin.prelude import *
+
+def validator(
+ d: Nothing,
+ r: Nothing,
+ context: ScriptContext,
+):
+ house_address = Address(
+ payment_credential=PubKeyCredential(
+ credential_hash=b""
+ ),
+ staking_credential=SomeStakingCredential(
+ staking_credential=StakingHash(
+ value=PubKeyCredential(
+ credential_hash=b""
+ )
+ )
+ ),
+ )
+"""
+ # would fail because Address is assigned multiple times and then not constant folded
+ # TODO find a better way
+ builder._compile(source_code, constant_folding=True)
+
+
+
+def test_double_import_direct(self)
+
+
+
+
+
+Expand source code
+
+
def test_double_import_direct(self):
+ source_code = """
+from opshin.prelude import *
+from opshin.prelude import *
+
+def validator(
+ d: Nothing,
+ r: Nothing,
+ context: ScriptContext,
+):
+ house_address = Address(
+ payment_credential=PubKeyCredential(
+ credential_hash=b""
+ ),
+ staking_credential=SomeStakingCredential(
+ staking_credential=StakingHash(
+ value=PubKeyCredential(
+ credential_hash=b""
+ )
+ )
+ ),
+ )
+"""
+ # would fail because Address is assigned multiple times and then not constant folded
+ # TODO find a better way
+ builder._compile(source_code, constant_folding=True)
+
+
+
+def test_double_import_offset(self)
+
+
+
+
+
+Expand source code
+
+
def test_double_import_offset(self):
+ source_code = """
+from opshin.ledger.api_v2 import *
+from opshin.prelude import *
+
+def validator(
+ d: Nothing,
+ r: Nothing,
+ context: ScriptContext,
+):
+ house_address = Address(
+ payment_credential=PubKeyCredential(
+ credential_hash=b""
+ ),
+ staking_credential=SomeStakingCredential(
+ staking_credential=StakingHash(
+ value=PubKeyCredential(
+ credential_hash=b""
+ )
+ )
+ ),
+ )
+"""
+ # would fail because Address is assigned multiple times and then not constant folded
+ # TODO find a better way
+ builder._compile(source_code, constant_folding=True)
+
+
+
+def test_dual_use_compile(self)
+
+
+
+
+
+Expand source code
+
+
def test_dual_use_compile(self):
+ # TODO devise tests for this
+ input_file = "examples/smart_contracts/dual_use.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ builder._compile(source_code, force_three_params=True)
+
+
+
+def test_failing_annotated_type(self)
+
+
+
+
+
+Expand source code
+
+
@unittest.expectedFailure
+ def test_failing_annotated_type(self):
+ source_code = """
+def c():
+ a = 2
+ def b() -> int:
+ return a
+ return b
+
+def validator(_: None):
+ a = 3
+ return c()
+"""
+ eval_uplc(source_code, Unit())
@hypothesis.given(a_or_b, st.integers())
+ @hypothesis.example(A(0), 0)
+ def test_isinstance_cast_shortcut_and(self, x, y):
source_code = """
from dataclasses import dataclass
from typing import Dict, List, Union
@@ -6257,25 +8007,18 @@
Methods
CONSTR_ID = 1
foobar: int
bar: int
-
-@dataclass()
-class C(PlutusData):
- CONSTR_ID = 2
- foo: int
-def validator(x: Union[A, B, C]) -> int:
- if isinstance(x, A) or isinstance(x, C):
- res = x.foo
- else:
- res = 100
- return res
+def validator(x: Union[A, B], y: int) -> bool:
+ return isinstance(x, A) and x.foo == y or isinstance(x, B) and x.bar == y
"""
- res = eval_uplc_value(source_code, x)
- self.assertEqual(res, x.foo if isinstance(x, A) else 100)
+ res = eval_uplc_value(source_code, x, y)
+ self.assertEqual(
+ res, isinstance(x, A) and x.foo == y or isinstance(x, B) and x.bar == y
+ )
@hypothesis.given(a_or_b)
+ def test_isinstance_cast_while(self, x):
source_code = """
from dataclasses import dataclass
from typing import Dict, List, Union
@@ -6339,24 +8080,237 @@
Methods
foobar: int
bar: int
-@dataclass()
-class C(PlutusData):
- CONSTR_ID = 0
- foo: int
-
def validator(x: Union[A, B]) -> int:
- if isinstance(x, A) or isinstance(x, C):
- res = x.foo
- else:
- res = 100
- return res
+ foo = 0
+ while isinstance(x, B) and foo != 1:
+ foo = x.bar
+ foo = 1
+ return foo
+"""
+ res = eval_uplc_value(source_code, x)
+ self.assertEqual(res, 1 if isinstance(x, B) else 0)
+
+
+
+def test_list_comprehension_all(self)
+
+
+
+
+
+Expand source code
+
+
def test_list_comprehension_all(self):
+ input_file = "examples/list_comprehensions.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ ret = eval_uplc_value(source_code, 8, 0)
+ ret = [x.value for x in ret]
+ self.assertEqual(
+ ret,
+ [x * x for x in range(8)],
+ "List comprehension incorrectly evaluated",
+ )
+
+
+
+def test_list_comprehension_even(self)
+
+
+
+
+
+Expand source code
+
+
def test_list_comprehension_even(self):
+ input_file = "examples/list_comprehensions.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ ret = eval_uplc_value(source_code, 8, 1)
+ ret = [x.value for x in ret]
+ self.assertEqual(
+ ret,
+ [x * x for x in range(8) if x % 2 == 0],
+ "List comprehension with filter incorrectly evaluated",
+ )
def test_list_expr(self):
+ # this tests that the list expression is evaluated correctly
+ source_code = """
+def validator(x: None) -> List[int]:
+ return [1, 2, 3, 4, 5]
+ """
+ ret = eval_uplc_value(source_code, Unit())
+ ret = [x.value for x in ret]
+ self.assertEqual(ret, [1, 2, 3, 4, 5], "List expression incorrectly compiled")
+
+
+
+def test_list_expr_not_const(self)
+
+
+
+
+
+Expand source code
+
+
def test_list_expr_not_const(self):
+ # this tests that the list expression is evaluated correctly (for non-constant expressions)
+ source_code = """
+def validator(x: int) -> List[int]:
+ return [x, x+1, x+2, x+3, x+4]
+ """
+ ret = eval_uplc_value(source_code, 1)
+ ret = [x.value for x in ret]
+ self.assertEqual(ret, [1, 2, 3, 4, 5], "List expression incorrectly compiled")
+
+
+
+def test_marketplace_compile(self)
+
+
+
+
+
+Expand source code
+
+
def test_marketplace_compile(self):
+ # TODO devise tests for this
+ input_file = "examples/smart_contracts/marketplace.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ builder._compile(source_code)
+
+
+
+def test_marketplace_compile_fail(self)
+
+
+
+
+
+Expand source code
+
+
@unittest.expectedFailure
+def test_marketplace_compile_fail(self):
+ input_file = "examples/smart_contracts/marketplace.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ builder._compile(source_code, force_three_params=True)
+
+
+
+def test_mult_for(self) ‑> None
+
+
+
+
+
+Expand source code
+
+
@given(
+ a=st.integers(min_value=-10, max_value=10),
+ b=st.integers(min_value=0, max_value=10),
+)
+def test_mult_for(self, a: int, b: int):
+ input_file = "examples/mult_for.py"
+ with open(input_file) as fp:
+ source_code = fp.read()
+ ret = eval_uplc_value(source_code, a, b)
+ self.assertEqual(ret, a * b)
+
+
+
+def test_mult_for_return(self) ‑> None
+
+
+
+
+
+Expand source code
+
+
@given(
+ a=st.integers(min_value=-10, max_value=10),
+ b=st.integers(min_value=0, max_value=10),
+ )
+ def test_mult_for_return(self, a: int, b: int):
+ source_code = """
+def validator(a: int, b: int) -> int:
+ c = 0
+ i = 0
+ for i in range(b):
+ c += a
+ if i == 1:
+ return c
+ return c
+"""
+ ret = eval_uplc_value(source_code, a, b)
+ self.assertEqual(ret, a * min(b, 2))
+
+
+
+def test_mult_while_return(self) ‑> None
+
+
+
+
+
+Expand source code
+
+
@given(
+ a=st.integers(min_value=-10, max_value=10),
+ b=st.integers(min_value=0, max_value=10),
+ )
+ def test_mult_while_return(self, a: int, b: int):
+ source_code = """
+def validator(a: int, b: int) -> int:
+ c = 0
+ i = 0
+ while i < b:
+ c += a
+ i += 1
+ if i == 2:
+ return c
+ return c
"""
- builder._compile(source_code)
- print("Union of same constructor id was allowed, should be disallowed")
+ ret = eval_uplc_value(source_code, a, b)
+ self.assertEqual(ret, a * min(2, b))
def test_no_return_annotation_no_return(self):
source_code = """
-from dataclasses import dataclass
-from typing import Dict, List, Union
-from pycardano import Datum as Anything, PlutusData
-
-@dataclass()
-class A(PlutusData):
- CONSTR_ID = 0
- foo: int
-
-@dataclass()
-class B(PlutusData):
- CONSTR_ID = 1
- foobar: int
- bar: int
+from opshin.prelude import *
-def validator(x: Union[A, B], y: int) -> bool:
- return isinstance(x, A) and x.foo == y or isinstance(x, B) and x.bar == y
+def validator(a):
+ pass
"""
- res = eval_uplc_value(source_code, x, y)
- self.assertEqual(
- res, isinstance(x, A) and x.foo == y or isinstance(x, B) and x.bar == y
- )
+ res = eval_uplc(source_code, 0)
+ self.assertEqual(res, uplc.PlutusConstr(0, []))
@unittest.expectedFailure
+ def test_opt_unsafe_cast(self):
+ # test that unsafe casts are not optimized away
source_code = """
-from dataclasses import dataclass
-from typing import Dict, List, Union
-from pycardano import Datum as Anything, PlutusData
-
-@dataclass()
-class A(PlutusData):
- CONSTR_ID = 0
- foo: int
-
-@dataclass()
-class B(PlutusData):
- CONSTR_ID = 1
- foobar: int
- bar: int
-
-def validator(x: Union[A, B]) -> int:
- foo = 0
- while isinstance(x, B) and foo != 1:
- foo = x.bar
- foo = 1
- return foo
-"""
- res = eval_uplc_value(source_code, x)
- self.assertEqual(res, 1 if isinstance(x, B) else 0)
+from opshin.prelude import *
+def validator(x: Token) -> bool:
+ b: Anything = x
+ a: int = b
+ return True
+ """
+ ret = eval_uplc(source_code, Unit())
-
-def test_list_comprehension_all(self)
+
+def test_outer_state_change_functions(self)
@@ -6582,21 +8447,42 @@
Methods
Expand source code
-
def test_list_comprehension_all(self):
- input_file = "examples/list_comprehensions.py"
- with open(input_file) as fp:
- source_code = fp.read()
- ret = eval_uplc_value(source_code, 8, 0)
- ret = [x.value for x in ret]
- self.assertEqual(
- ret,
- [x * x for x in range(8)],
- "List comprehension incorrectly evaluated",
- )
def test_parameterized_compile(self):
+ # TODO devise tests for this
+ input_file = "examples/smart_contracts/parameterized.py"
with open(input_file) as fp:
source_code = fp.read()
- ret = eval_uplc_value(source_code, 8, 1)
- ret = [x.value for x in ret]
- self.assertEqual(
- ret,
- [x * x for x in range(8) if x % 2 == 0],
- "List comprehension with filter incorrectly evaluated",
- )
def test_marketplace_compile(self):
- # TODO devise tests for this
- input_file = "examples/smart_contracts/marketplace.py"
- with open(input_file) as fp:
- source_code = fp.read()
- builder._compile(source_code)
+
@unittest.expectedFailure
+ def test_recursion_illegal(self):
+ # this is now an illegal retyping because read variables dont match
+ source_code = """
+def validator(_: None) -> int:
+ def a(n: int) -> int:
+ if n == 0:
+ res = 0
+ else:
+ res = a(n-1)
+ return res
+ b = a
+ def a(x: int) -> int:
+ return 100
+ return b(1)
+ """
+ ret = eval_uplc_value(source_code, Unit())
+ self.assertEqual(100, ret)
-
-def test_marketplace_compile_fail(self)
+
+def test_recursion_legal(self)
@@ -6705,16 +8602,29 @@
Methods
Expand source code
-
@unittest.expectedFailure
-def test_marketplace_compile_fail(self):
- input_file = "examples/smart_contracts/marketplace.py"
- with open(input_file) as fp:
- source_code = fp.read()
- builder._compile(source_code, force_three_params=True)
+
def test_recursion_legal(self):
+ source_code = """
+def validator(_: None) -> int:
+ def a(n: int) -> int:
+ if n == 0:
+ res = 0
+ else:
+ res = a(n-1)
+ return res
+ b = a
+ def a(n: int) -> int:
+ a
+ if 1 == n:
+ pass
+ return 100
+ return b(1)
+ """
+ ret = eval_uplc_value(source_code, Unit())
+ self.assertEqual(100, ret)
-
-def test_mult_for(self) ‑> None
+
+def test_recursion_simple(self)
@@ -6722,20 +8632,23 @@
Methods
Expand source code
-
@given(
- a=st.integers(min_value=-10, max_value=10),
- b=st.integers(min_value=0, max_value=10),
-)
-def test_mult_for(self, a: int, b: int):
- input_file = "examples/mult_for.py"
- with open(input_file) as fp:
- source_code = fp.read()
- ret = eval_uplc_value(source_code, a, b)
- self.assertEqual(ret, a * b)
+
def test_recursion_simple(self):
+ source_code = """
+def validator(_: None) -> int:
+ def a(n: int) -> int:
+ if n == 0:
+ res = 0
+ else:
+ res = a(n-1)
+ return res
+ return a(1)
+ """
+ ret = eval_uplc_value(source_code, Unit())
+ self.assertEqual(0, ret)
-
-def test_mult_while(self) ‑> None
+
+def test_redefine_constr(self) ‑> None
@@ -6743,20 +8656,30 @@
Methods
Expand source code
-
@given(
- a=st.integers(min_value=-10, max_value=10),
- b=st.integers(min_value=0, max_value=10),
-)
-def test_mult_while(self, a: int, b: int):
- input_file = "examples/mult_while.py"
- with open(input_file) as fp:
- source_code = fp.read()
- ret = eval_uplc_value(source_code, a, b)
- self.assertEqual(ret, a * b)
+
@given(st.booleans())
+ def test_redefine_constr(self, x):
+ # this tests that classes defined by assignment inherit constructors
+ source_code = """
+from dataclasses import dataclass
+from typing import Dict, List, Union
+from pycardano import Datum as Anything, PlutusData
+
+@dataclass()
+class A(PlutusData):
+ CONSTR_ID = 0
+ foo: int
+ bar: int
+
+def validator(x: int) -> int:
+ a = A
+ return a(x, 1).foo
+ """
+ ret = eval_uplc_value(source_code, int(x))
+ self.assertEqual(ret, int(x), "Re-assignment of class constr failed")
-
-def test_nested_deconstruction(self)
+
+def test_redefine_poly_constr(self)
@@ -6764,22 +8687,19 @@
Methods
Expand source code
-
def test_nested_deconstruction(self):
+
def test_redefine_poly_constr(self):
+ # this tests that classes defined by assignment inherit constructors
source_code = """
-def validator(xs) -> int:
- a, ((b, c), d) = (1, ((2, 3), 4))
- return a + b + c + d
-"""
+def validator(x: None) -> bytes:
+ a = bytes
+ return a([2, 3])
+ """
ret = eval_uplc_value(source_code, Unit())
- self.assertEqual(
- ret,
- 1 + 2 + 3 + 4,
- "for loop deconstruction did not behave as expected",
- )
+ self.assertEqual(ret, bytes([2, 3]), "Re-assignment of global variable failed")
-
-def test_no_parameter_annotation(self)
+
+def test_removedeadvar_noissue(self)
@@ -6787,20 +8707,20 @@
Methods
Expand source code
-
def test_no_parameter_annotation(self):
+
def test_removedeadvar_noissue(self):
source_code = """
from opshin.prelude import *
-
-def validator(a) -> bytes:
- b: bytes = a
- return b
-"""
- res = eval_uplc(source_code, b"")
- self.assertEqual(res, uplc.PlutusByteString(b""))
+def validator(x: Token) -> bool:
+ b = 4
+ a = b
+ return True
+ """
+ ret = eval_uplc_value(source_code, Unit())
+ self.assertEqual(ret, True)
@unittest.expectedFailure
- def test_opt_unsafe_cast(self):
- # test that unsafe casts are not optimized away
+
def test_return_else_loop_for(self):
source_code = """
-from opshin.prelude import *
-def validator(x: Token) -> bool:
- b: Anything = x
- a: int = b
- return True
- """
- ret = eval_uplc(source_code, Unit())
+def validator(a: int) -> int:
+ for _ in range(a):
+ a -= 1
+ else:
+ return 0
+"""
+ res = eval_uplc_value(source_code, 1)
+ self.assertEqual(res, 0, "Invalid return")
-
-def test_outer_state_change_functions(self)
+
+def test_return_else_loop_while(self)
@@ -6893,22 +8817,20 @@
Methods
Expand source code
-
def test_outer_state_change_functions(self):
+
def test_return_else_loop_while(self):
source_code = """
-a = 2
-def b() -> int:
- return a
-a = 3
-
-def validator(_: None) -> int:
- return b()
+def validator(a: int) -> int:
+ while a > 0:
+ a -= 1
+ else:
+ return 0
"""
- res = eval_uplc_value(source_code, Unit())
- self.assertEqual(res, 3)
+ res = eval_uplc_value(source_code, 1)
+ self.assertEqual(res, 0, "Invalid return")
-
-def test_overopt_removedeadvar(self)
+
+def test_return_illegal(self)
@@ -6917,18 +8839,18 @@
Methods
Expand source code
@unittest.expectedFailure
- def test_overopt_removedeadvar(self):
+ def test_return_illegal(self):
+ # this is now an illegal retyping because read variables dont match
source_code = """
-from opshin.prelude import *
-def validator(x: Token) -> bool:
- a = x.policy_id
- return True
+return 1
+def validator(_: None) -> int:
+ return 0
"""
- ret = eval_uplc(source_code, Unit())
+ builder._compile(source_code)
-
-def test_parameterized_compile(self)
+
+def test_return_in_for(self)
@@ -6936,16 +8858,22 @@
Methods
Expand source code
-
def test_parameterized_compile(self):
- # TODO devise tests for this
- input_file = "examples/smart_contracts/parameterized.py"
- with open(input_file) as fp:
- source_code = fp.read()
- builder._compile(source_code, force_three_params=True)
+
def test_return_in_for(self):
+ source_code = """
+def validator(_: None) -> int:
+ i = 0
+ for i in range(10):
+ i += 1
+ if i == 5:
+ return i
+ return 0
+ """
+ res = eval_uplc_value(source_code, Unit())
+ self.assertEqual(res, 5, "Invalid return break")
-
-def test_recursion(self)
+
+def test_return_in_if(self)
@@ -6953,26 +8881,21 @@
Methods
Expand source code
-
def test_recursion(self):
+
def test_return_in_if(self):
source_code = """
def validator(_: None) -> int:
- def a(n: int) -> int:
- if n == 0:
- res = 0
- else:
- res = a(n-1)
- return res
- b = a
- def a(x: int) -> int:
- return 100
- return b(1)
+ i = 0
+ if i == 1:
+ return 0
+ else:
+ return 1
"""
- ret = eval_uplc_value(source_code, Unit())
- self.assertEqual(100, ret)
+ res = eval_uplc_value(source_code, Unit())
+ self.assertEqual(res, 1, "Invalid return")
-
-def test_redefine_constr(self) ‑> None
+
+def test_return_in_if_missing_return(self)
@@ -6980,30 +8903,21 @@
Methods
Expand source code
-
@given(st.booleans())
- def test_redefine_constr(self, x):
- # this tests that classes defined by assignment inherit constructors
+
@unittest.expectedFailure
+ def test_return_in_if_missing_return(self):
source_code = """
-from dataclasses import dataclass
-from typing import Dict, List, Union
-from pycardano import Datum as Anything, PlutusData
-
-@dataclass()
-class A(PlutusData):
- CONSTR_ID = 0
- foo: int
- bar: int
-
-def validator(x: int) -> int:
- a = A
- return a(x, 1).foo
+def validator(_: None) -> str:
+ i = 0
+ if i == 1:
+ return "a"
+ else:
+ pass
"""
- ret = eval_uplc_value(source_code, int(x))
- self.assertEqual(ret, int(x), "Re-assignment of class constr failed")
+ builder._compile(source_code)
-
-def test_redefine_poly_constr(self)
+
+def test_return_in_if_same_type(self)
@@ -7011,19 +8925,21 @@
Methods
Expand source code
-
def test_redefine_poly_constr(self):
- # this tests that classes defined by assignment inherit constructors
+
@unittest.expectedFailure
+ def test_return_in_if_same_type(self):
source_code = """
-def validator(x: None) -> bytes:
- a = bytes
- return a([2, 3])
+def validator(_: None) -> str:
+ i = 0
+ if i == 1:
+ return "a"
+ else:
+ return 1
"""
- ret = eval_uplc_value(source_code, Unit())
- self.assertEqual(ret, bytes([2, 3]), "Re-assignment of global variable failed")
@unittest.expectedFailure
+ def test_type_reassignment_function_bound(self):
+ # changing the type of a variable should be disallowed if the variable is bound by a function
+ # it can be ok if the types can be merged (resulting in union type inside the function) but
+ # generally should be disallowed
+ source_code = """
+def validator(_: None) -> int:
+ b = 1
+ def a(n: int) -> int:
+ return b
+ b = b''
+ return a(1)
+ """
+ builder._compile(source_code)
def record_from_plutusdata(c: PlutusData):
return Record(
name=c.__class__.__name__,
+ orig_name=c.__class__.__name__,
constructor=c.CONSTR_ID,
fields=frozenlist([(k, constant_type(v)) for k, v in c.__dict__.items()]),
)
@@ -169,69 +167,27 @@
Module opshin.type_inference
raise NotImplementedError(f"Type {type(c)} not supported")
-BinOpTypeMap = {
- Add: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- },
- ByteStringInstanceType: {
- ByteStringInstanceType: ByteStringInstanceType,
- },
- StringInstanceType: {
- StringInstanceType: StringInstanceType,
- },
- },
- Sub: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- }
- },
- Mult: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- ByteStringInstanceType: ByteStringInstanceType,
- StringInstanceType: StringInstanceType,
- },
- StringInstanceType: {
- IntegerInstanceType: StringInstanceType,
- },
- ByteStringInstanceType: {
- IntegerInstanceType: ByteStringInstanceType,
- },
- },
- FloorDiv: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- }
- },
- Mod: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- }
- },
- Pow: {
- IntegerInstanceType: {
- IntegerInstanceType: IntegerInstanceType,
- }
- },
-}
-
-
TypeMap = typing.Dict[str, Type]
TypeMapPair = typing.Tuple[TypeMap, TypeMap]
def union_types(*ts: Type):
- ts = list(set(ts))
+ ts = OrderedSet(ts)
+ # If all types are the same, just return the type
if len(ts) == 1:
return ts[0]
+ # If there is a type that is compatible with all other types, choose the maximum
+ for t in ts:
+ if all(t >= tp for tp in ts):
+ return t
assert ts, "Union must combine multiple classes"
ts = [t if isinstance(t, UnionType) else UnionType(frozenlist([t])) for t in ts]
- assert all(
- isinstance(e, UnionType) and all(isinstance(e2, RecordType) for e2 in e.typs)
- for e in ts
- ), "Union must combine multiple PlutusData classes"
- union_set = set()
+ for e in ts:
+ for e2 in e.typs:
+ assert isinstance(
+ e2, RecordType
+ ), f"Union must combine multiple PlutusData classes but found {e2.__class__.__name__}"
+ union_set = OrderedSet()
for t in ts:
union_set.update(t.typs)
assert distinct(
@@ -241,12 +197,12 @@
Module opshin.type_inference
def intersection_types(*ts: Type):
- ts = list(set(ts))
+ ts = OrderedSet(ts)
if len(ts) == 1:
return ts[0]
ts = [t if isinstance(t, UnionType) else UnionType(frozenlist([t])) for t in ts]
assert ts, "Must have at least one type to intersect"
- intersection_set = set(ts[0].typs)
+ intersection_set = OrderedSet(ts[0].typs)
for t in ts[1:]:
intersection_set.intersection_update(t.typs)
return UnionType(frozenlist(intersection_set))
@@ -267,9 +223,9 @@
Module opshin.type_inference
return getattr(node, "typechecks", ({}, {}))
def visit_Call(self, node: Call) -> TypeMapPair:
- if isinstance(node.func, Name) and node.func.id == SPECIAL_BOOL:
+ if isinstance(node.func, Name) and node.func.orig_id == SPECIAL_BOOL:
return self.visit(node.args[0])
- if not (isinstance(node.func, Name) and node.func.id == "isinstance"):
+ if not (isinstance(node.func, Name) and node.func.orig_id == "isinstance"):
return ({}, {})
# special case for Union
assert isinstance(
@@ -341,7 +297,7 @@
Module opshin.type_inference
def merge_scope(s1: typing.Dict[str, Type], s2: typing.Dict[str, Type]):
- keys = set(s1.keys()).union(s2.keys())
+ keys = OrderedSet(s1.keys()).union(s2.keys())
merged = {}
for k in keys:
if k not in s1.keys():
@@ -350,11 +306,9 @@
Module opshin.type_inference
merged[k] = s1[k]
else:
try:
- assert (
- isinstance(s1[k], InstanceType) and isinstance(s2[k], InstanceType)
- ) or s1[k] == s2[
- k
- ], "Can only merge instance types or same types into one"
+ assert isinstance(s1[k], InstanceType) and isinstance(
+ s2[k], InstanceType
+ ), "Can only merge instance types"
merged[k] = InstanceType(union_types(s1[k].typ, s2[k].typ))
except AssertionError as e:
raise AssertionError(
@@ -378,7 +332,9 @@
Module opshin.type_inference
for scope in reversed(self.scopes):
if name in scope:
return scope[name]
- raise TypeInferenceError(f"Variable {name} not initialized at access")
+ raise TypeInferenceError(
+ f"Variable {map_to_orig_name(name)} not initialized at access"
+ )
def enter_scope(self):
self.scopes.append({})
@@ -392,7 +348,7 @@
Module opshin.type_inference
# the specified type is broader, we pass on this
return
raise TypeInferenceError(
- f"Type {self.scopes[-1][name]} of variable {name} in local scope does not match inferred type {typ}"
+ f"Type {self.scopes[-1][name]} of variable {map_to_orig_name(name)} in local scope does not match inferred type {typ}"
)
self.scopes[-1][name] = typ
@@ -414,18 +370,18 @@
Module opshin.type_inference
if isinstance(v_t, ClassType):
return v_t
raise TypeInferenceError(
- f"Class name {ann.id} not initialized before annotating variable"
+ f"Class name {ann.orig_id} not initialized before annotating variable"
)
if isinstance(ann, Subscript):
assert isinstance(
ann.value, Name
), "Only Union, Dict and List are allowed as Generic types"
- if ann.value.id == "Union":
+ if ann.value.orig_id == "Union":
ann_types = frozenlist(
[self.type_from_annotation(e) for e in ann.slice.elts]
)
return union_types(*ann_types)
- if ann.value.id == "List":
+ if ann.value.orig_id == "List":
ann_type = self.type_from_annotation(ann.slice)
assert isinstance(
ann_type, ClassType
@@ -434,7 +390,7 @@
Module opshin.type_inference
ann_type, TupleType
), "List can currently not hold tuples"
return ListType(InstanceType(ann_type))
- if ann.value.id == "Dict":
+ if ann.value.orig_id == "Dict":
assert isinstance(ann.slice, Tuple), "Dict must combine two classes"
assert len(ann.slice.elts) == 2, "Dict must combine two classes"
ann_types = self.type_from_annotation(
@@ -447,7 +403,7 @@
Module opshin.type_inference
isinstance(e, TupleType) for e in ann_types
), "Dict can currently not hold tuples"
return DictType(*(InstanceType(a) for a in ann_types))
- if ann.value.id == "Tuple":
+ if ann.value.orig_id == "Tuple":
assert isinstance(
ann.slice, Tuple
), "Tuple must combine several classes"
@@ -534,8 +490,8 @@
Module opshin.type_inference
assert isinstance(
t, Name
), "Can only assign to variable names, no type deconstruction"
- # Overwrite previous type -> this will only affect following statements
- self.set_variable_type(t.id, typed_ass.value.typ, force=True)
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(t.id, typed_ass.value.typ)
typed_ass.targets = [self.visit(t) for t in node.targets]
return typed_ass
@@ -546,9 +502,8 @@
Module opshin.type_inference
assert isinstance(
node.target, Name
), "Can only assign to variable names, no type deconstruction"
- self.set_variable_type(
- node.target.id, InstanceType(typed_ass.annotation), force=True
- )
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(node.target.id, InstanceType(typed_ass.annotation))
typed_ass.target = self.visit(node.target)
assert (
typed_ass.value.typ >= InstanceType(typed_ass.annotation)
@@ -667,7 +622,7 @@
Module opshin.type_inference
tfd = copy(node)
wraps_builtin = (
all(
- isinstance(o, Name) and o.id == "wraps_builtin"
+ isinstance(o, Name) and o.orig_id == "wraps_builtin"
for o in node.decorator_list
)
and node.decorator_list
@@ -680,6 +635,7 @@
Module opshin.type_inference
functyp = FunctionType(
frozenlist([t.typ for t in tfd.args.args]),
InstanceType(self.type_from_annotation(tfd.returns)),
+ externally_bound_vars(node),
)
tfd.typ = InstanceType(functyp)
if wraps_builtin:
@@ -690,14 +646,8 @@
Module opshin.type_inference
self.set_variable_type(node.name, tfd.typ)
tfd.body = self.visit_sequence(node.body)
# Check that return type and annotated return type match
- if not isinstance(node.body[-1], Return):
- assert (
- functyp.rettyp >= NoneInstanceType
- ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
- else:
- assert (
- functyp.rettyp >= tfd.body[-1].typ
- ), f"Function '{node.name}' annotated return type does not match actual return type"
+ rets_extractor = ReturnExtractor(functyp.rettyp)
+ rets_extractor.check_fulfills(tfd)
self.exit_scope()
# We need the function type outside for usage
@@ -720,15 +670,8 @@
Module opshin.type_inference
tb = copy(node)
tb.left = self.visit(node.left)
tb.right = self.visit(node.right)
- outcome_typ_map = BinOpTypeMap.get(type(node.op)).get(tb.left.typ)
- assert (
- outcome_typ_map is not None
- ), f"Operation {node.op} not defined for {tb.left.typ}"
- outcome_typ = outcome_typ_map.get(tb.right.typ)
- assert (
- outcome_typ is not None
- ), f"Operation {node.op} not defined for types {tb.left.typ} and {tb.right.typ}"
- tb.typ = outcome_typ
+ binop_fun_typ: FunctionType = tb.left.typ.binop_type(tb.op, tb.right.typ)
+ tb.typ = binop_fun_typ.rettyp
return tb
def visit_BoolOp(self, node: BoolOp) -> TypedBoolOp:
@@ -774,7 +717,7 @@
Module opshin.type_inference
def visit_Subscript(self, node: Subscript) -> TypedSubscript:
ts = copy(node)
# special case: Subscript of Union / Dict / List and atomic types
- if isinstance(ts.value, Name) and ts.value.id in [
+ if isinstance(ts.value, Name) and ts.value.orig_id in [
"Union",
"Dict",
"List",
@@ -808,9 +751,29 @@
Module opshin.type_inference
f"Could not infer type of subscript of typ {ts.value.typ.typ.__class__}"
)
elif isinstance(ts.value.typ.typ, ListType):
- ts.typ = ts.value.typ.typ.typ
- ts.slice = self.visit(node.slice)
- assert ts.slice.typ == IntegerInstanceType, "List indices must be integers"
+ if not isinstance(ts.slice, Slice):
+ ts.typ = ts.value.typ.typ.typ
+ ts.slice = self.visit(node.slice)
+ assert (
+ ts.slice.typ == IntegerInstanceType
+ ), "List indices must be integers"
+ else:
+ ts.typ = ts.value.typ
+ if ts.slice.lower is None:
+ ts.slice.lower = Constant(0)
+ ts.slice.lower = self.visit(node.slice.lower)
+ assert (
+ ts.slice.lower.typ == IntegerInstanceType
+ ), "lower slice indices for lists must be integers"
+ if ts.slice.upper is None:
+ ts.slice.upper = Call(
+ func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
+ )
+ ts.slice.upper.func.orig_id = "len"
+ ts.slice.upper = self.visit(node.slice.upper)
+ assert (
+ ts.slice.upper.typ == IntegerInstanceType
+ ), "upper slice indices for lists must be integers"
elif isinstance(ts.value.typ.typ, ByteStringType):
if not isinstance(ts.slice, Slice):
ts.typ = IntegerInstanceType
@@ -818,7 +781,7 @@
Module opshin.type_inference
assert (
ts.slice.typ == IntegerInstanceType
), "bytes indices must be integers"
- elif isinstance(ts.slice, Slice):
+ else:
ts.typ = ByteStringInstanceType
if ts.slice.lower is None:
ts.slice.lower = Constant(0)
@@ -830,16 +793,12 @@
Module opshin.type_inference
ts.slice.upper = Call(
func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
)
+ ts.slice.upper.func.orig_id = "len"
ts.slice.upper = self.visit(node.slice.upper)
assert (
ts.slice.upper.typ == IntegerInstanceType
), "upper slice indices for bytes must be integers"
- else:
- raise TypeInferenceError(
- f"Could not infer type of subscript of typ {ts.value.typ.__class__}"
- )
elif isinstance(ts.value.typ.typ, DictType):
- # TODO could be implemented with potentially just erroring. It might be desired to avoid this though.
if not isinstance(ts.slice, Slice):
ts.slice = self.visit(node.slice)
assert (
@@ -861,7 +820,7 @@
Module opshin.type_inference
tc = copy(node)
tc.args = [self.visit(a) for a in node.args]
# might be isinstance
- if isinstance(tc.func, Name) and tc.func.id == "isinstance":
+ if isinstance(tc.func, Name) and tc.func.orig_id == "isinstance":
target_class = tc.args[1].typ
if (
isinstance(tc.args[0].typ, InstanceType)
@@ -964,9 +923,17 @@
def visit_ClassDef(self, node: ClassDef) -> None:
self.name = node.name
+ self.orig_name = node.orig_name
for s in node.body:
self.visit(s)
@@ -1117,7 +1086,60 @@
Module opshin.type_inference
def typed_ast(ast: AST):
- return AggressiveTypeInferencer().visit(ast)
+ return AggressiveTypeInferencer().visit(ast)
+
+
+def map_to_orig_name(name: str):
+ return re.sub(r"_\d+$", "", name)
+
+
+class ReturnExtractor(TypedNodeVisitor):
+ """
+ Utility to check that all paths end in Return statements with the proper type
+
+ Returns whether there is no remaining path
+ """
+
+ def __init__(self, func_rettyp: Type):
+ self.func_rettyp = func_rettyp
+
+ def visit_sequence(self, nodes: typing.List[TypedAST]) -> bool:
+ all_paths_covered = False
+ for node in nodes:
+ all_paths_covered = self.visit(node)
+ if all_paths_covered:
+ break
+ return all_paths_covered
+
+ def visit_If(self, node: If) -> bool:
+ return self.visit_sequence(node.body) and self.visit_sequence(node.orelse)
+
+ def visit_For(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
+
+ def visit_While(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
+
+ 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"
+ return True
+
+ def check_fulfills(self, node: FunctionDef):
+ all_paths_covered = self.visit_sequence(node.body)
+ if not all_paths_covered:
+ assert (
+ self.func_rettyp >= NoneInstanceType
+ ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
@@ -1180,17 +1202,30 @@
Functions
Expand source code
def intersection_types(*ts: Type):
- ts = list(set(ts))
+ ts = OrderedSet(ts)
if len(ts) == 1:
return ts[0]
ts = [t if isinstance(t, UnionType) else UnionType(frozenlist([t])) for t in ts]
assert ts, "Must have at least one type to intersect"
- intersection_set = set(ts[0].typs)
+ intersection_set = OrderedSet(ts[0].typs)
for t in ts[1:]:
intersection_set.intersection_update(t.typs)
return UnionType(frozenlist(intersection_set))
def merge_scope(s1: typing.Dict[str, Type], s2: typing.Dict[str, Type]):
- keys = set(s1.keys()).union(s2.keys())
+ keys = OrderedSet(s1.keys()).union(s2.keys())
merged = {}
for k in keys:
if k not in s1.keys():
@@ -1210,11 +1245,9 @@
Functions
merged[k] = s1[k]
else:
try:
- assert (
- isinstance(s1[k], InstanceType) and isinstance(s2[k], InstanceType)
- ) or s1[k] == s2[
- k
- ], "Can only merge instance types or same types into one"
+ assert isinstance(s1[k], InstanceType) and isinstance(
+ s2[k], InstanceType
+ ), "Can only merge instance types"
merged[k] = InstanceType(union_types(s1[k].typ, s2[k].typ))
except AssertionError as e:
raise AssertionError(
@@ -1235,6 +1268,7 @@
Functions
def record_from_plutusdata(c: PlutusData):
return Record(
name=c.__class__.__name__,
+ orig_name=c.__class__.__name__,
constructor=c.CONSTR_ID,
fields=frozenlist([(k, constant_type(v)) for k, v in c.__dict__.items()]),
)
@@ -1263,16 +1297,22 @@
Functions
Expand source code
def union_types(*ts: Type):
- ts = list(set(ts))
+ ts = OrderedSet(ts)
+ # If all types are the same, just return the type
if len(ts) == 1:
return ts[0]
+ # If there is a type that is compatible with all other types, choose the maximum
+ for t in ts:
+ if all(t >= tp for tp in ts):
+ return t
assert ts, "Union must combine multiple classes"
ts = [t if isinstance(t, UnionType) else UnionType(frozenlist([t])) for t in ts]
- assert all(
- isinstance(e, UnionType) and all(isinstance(e2, RecordType) for e2 in e.typs)
- for e in ts
- ), "Union must combine multiple PlutusData classes"
- union_set = set()
+ for e in ts:
+ for e2 in e.typs:
+ assert isinstance(
+ e2, RecordType
+ ), f"Union must combine multiple PlutusData classes but found {e2.__class__.__name__}"
+ union_set = OrderedSet()
for t in ts:
union_set.update(t.typs)
assert distinct(
@@ -1337,7 +1377,9 @@
Classes
for scope in reversed(self.scopes):
if name in scope:
return scope[name]
- raise TypeInferenceError(f"Variable {name} not initialized at access")
+ raise TypeInferenceError(
+ f"Variable {map_to_orig_name(name)} not initialized at access"
+ )
def enter_scope(self):
self.scopes.append({})
@@ -1351,7 +1393,7 @@
Classes
# the specified type is broader, we pass on this
return
raise TypeInferenceError(
- f"Type {self.scopes[-1][name]} of variable {name} in local scope does not match inferred type {typ}"
+ f"Type {self.scopes[-1][name]} of variable {map_to_orig_name(name)} in local scope does not match inferred type {typ}"
)
self.scopes[-1][name] = typ
@@ -1373,18 +1415,18 @@
Classes
if isinstance(v_t, ClassType):
return v_t
raise TypeInferenceError(
- f"Class name {ann.id} not initialized before annotating variable"
+ f"Class name {ann.orig_id} not initialized before annotating variable"
)
if isinstance(ann, Subscript):
assert isinstance(
ann.value, Name
), "Only Union, Dict and List are allowed as Generic types"
- if ann.value.id == "Union":
+ if ann.value.orig_id == "Union":
ann_types = frozenlist(
[self.type_from_annotation(e) for e in ann.slice.elts]
)
return union_types(*ann_types)
- if ann.value.id == "List":
+ if ann.value.orig_id == "List":
ann_type = self.type_from_annotation(ann.slice)
assert isinstance(
ann_type, ClassType
@@ -1393,7 +1435,7 @@
Classes
ann_type, TupleType
), "List can currently not hold tuples"
return ListType(InstanceType(ann_type))
- if ann.value.id == "Dict":
+ if ann.value.orig_id == "Dict":
assert isinstance(ann.slice, Tuple), "Dict must combine two classes"
assert len(ann.slice.elts) == 2, "Dict must combine two classes"
ann_types = self.type_from_annotation(
@@ -1406,7 +1448,7 @@
Classes
isinstance(e, TupleType) for e in ann_types
), "Dict can currently not hold tuples"
return DictType(*(InstanceType(a) for a in ann_types))
- if ann.value.id == "Tuple":
+ if ann.value.orig_id == "Tuple":
assert isinstance(
ann.slice, Tuple
), "Tuple must combine several classes"
@@ -1493,8 +1535,8 @@
Classes
assert isinstance(
t, Name
), "Can only assign to variable names, no type deconstruction"
- # Overwrite previous type -> this will only affect following statements
- self.set_variable_type(t.id, typed_ass.value.typ, force=True)
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(t.id, typed_ass.value.typ)
typed_ass.targets = [self.visit(t) for t in node.targets]
return typed_ass
@@ -1505,9 +1547,8 @@
Classes
assert isinstance(
node.target, Name
), "Can only assign to variable names, no type deconstruction"
- self.set_variable_type(
- node.target.id, InstanceType(typed_ass.annotation), force=True
- )
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(node.target.id, InstanceType(typed_ass.annotation))
typed_ass.target = self.visit(node.target)
assert (
typed_ass.value.typ >= InstanceType(typed_ass.annotation)
@@ -1626,7 +1667,7 @@
Classes
tfd = copy(node)
wraps_builtin = (
all(
- isinstance(o, Name) and o.id == "wraps_builtin"
+ isinstance(o, Name) and o.orig_id == "wraps_builtin"
for o in node.decorator_list
)
and node.decorator_list
@@ -1639,6 +1680,7 @@
Classes
functyp = FunctionType(
frozenlist([t.typ for t in tfd.args.args]),
InstanceType(self.type_from_annotation(tfd.returns)),
+ externally_bound_vars(node),
)
tfd.typ = InstanceType(functyp)
if wraps_builtin:
@@ -1649,14 +1691,8 @@
Classes
self.set_variable_type(node.name, tfd.typ)
tfd.body = self.visit_sequence(node.body)
# Check that return type and annotated return type match
- if not isinstance(node.body[-1], Return):
- assert (
- functyp.rettyp >= NoneInstanceType
- ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
- else:
- assert (
- functyp.rettyp >= tfd.body[-1].typ
- ), f"Function '{node.name}' annotated return type does not match actual return type"
+ rets_extractor = ReturnExtractor(functyp.rettyp)
+ rets_extractor.check_fulfills(tfd)
self.exit_scope()
# We need the function type outside for usage
@@ -1679,15 +1715,8 @@
Classes
tb = copy(node)
tb.left = self.visit(node.left)
tb.right = self.visit(node.right)
- outcome_typ_map = BinOpTypeMap.get(type(node.op)).get(tb.left.typ)
- assert (
- outcome_typ_map is not None
- ), f"Operation {node.op} not defined for {tb.left.typ}"
- outcome_typ = outcome_typ_map.get(tb.right.typ)
- assert (
- outcome_typ is not None
- ), f"Operation {node.op} not defined for types {tb.left.typ} and {tb.right.typ}"
- tb.typ = outcome_typ
+ binop_fun_typ: FunctionType = tb.left.typ.binop_type(tb.op, tb.right.typ)
+ tb.typ = binop_fun_typ.rettyp
return tb
def visit_BoolOp(self, node: BoolOp) -> TypedBoolOp:
@@ -1733,7 +1762,7 @@
Classes
def visit_Subscript(self, node: Subscript) -> TypedSubscript:
ts = copy(node)
# special case: Subscript of Union / Dict / List and atomic types
- if isinstance(ts.value, Name) and ts.value.id in [
+ if isinstance(ts.value, Name) and ts.value.orig_id in [
"Union",
"Dict",
"List",
@@ -1767,9 +1796,29 @@
Classes
f"Could not infer type of subscript of typ {ts.value.typ.typ.__class__}"
)
elif isinstance(ts.value.typ.typ, ListType):
- ts.typ = ts.value.typ.typ.typ
- ts.slice = self.visit(node.slice)
- assert ts.slice.typ == IntegerInstanceType, "List indices must be integers"
+ if not isinstance(ts.slice, Slice):
+ ts.typ = ts.value.typ.typ.typ
+ ts.slice = self.visit(node.slice)
+ assert (
+ ts.slice.typ == IntegerInstanceType
+ ), "List indices must be integers"
+ else:
+ ts.typ = ts.value.typ
+ if ts.slice.lower is None:
+ ts.slice.lower = Constant(0)
+ ts.slice.lower = self.visit(node.slice.lower)
+ assert (
+ ts.slice.lower.typ == IntegerInstanceType
+ ), "lower slice indices for lists must be integers"
+ if ts.slice.upper is None:
+ ts.slice.upper = Call(
+ func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
+ )
+ ts.slice.upper.func.orig_id = "len"
+ ts.slice.upper = self.visit(node.slice.upper)
+ assert (
+ ts.slice.upper.typ == IntegerInstanceType
+ ), "upper slice indices for lists must be integers"
elif isinstance(ts.value.typ.typ, ByteStringType):
if not isinstance(ts.slice, Slice):
ts.typ = IntegerInstanceType
@@ -1777,7 +1826,7 @@
Classes
assert (
ts.slice.typ == IntegerInstanceType
), "bytes indices must be integers"
- elif isinstance(ts.slice, Slice):
+ else:
ts.typ = ByteStringInstanceType
if ts.slice.lower is None:
ts.slice.lower = Constant(0)
@@ -1789,16 +1838,12 @@
Classes
ts.slice.upper = Call(
func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
)
+ ts.slice.upper.func.orig_id = "len"
ts.slice.upper = self.visit(node.slice.upper)
assert (
ts.slice.upper.typ == IntegerInstanceType
), "upper slice indices for bytes must be integers"
- else:
- raise TypeInferenceError(
- f"Could not infer type of subscript of typ {ts.value.typ.__class__}"
- )
elif isinstance(ts.value.typ.typ, DictType):
- # TODO could be implemented with potentially just erroring. It might be desired to avoid this though.
if not isinstance(ts.slice, Slice):
ts.slice = self.visit(node.slice)
assert (
@@ -1820,7 +1865,7 @@
Classes
tc = copy(node)
tc.args = [self.visit(a) for a in node.args]
# might be isinstance
- if isinstance(tc.func, Name) and tc.func.id == "isinstance":
+ if isinstance(tc.func, Name) and tc.func.orig_id == "isinstance":
target_class = tc.args[1].typ
if (
isinstance(tc.args[0].typ, InstanceType)
@@ -1923,9 +1968,17 @@
# the specified type is broader, we pass on this
return
raise TypeInferenceError(
- f"Type {self.scopes[-1][name]} of variable {name} in local scope does not match inferred type {typ}"
+ f"Type {self.scopes[-1][name]} of variable {map_to_orig_name(name)} in local scope does not match inferred type {typ}"
)
self.scopes[-1][name] = typ
@@ -2114,18 +2167,18 @@
Methods
if isinstance(v_t, ClassType):
return v_t
raise TypeInferenceError(
- f"Class name {ann.id} not initialized before annotating variable"
+ f"Class name {ann.orig_id} not initialized before annotating variable"
)
if isinstance(ann, Subscript):
assert isinstance(
ann.value, Name
), "Only Union, Dict and List are allowed as Generic types"
- if ann.value.id == "Union":
+ if ann.value.orig_id == "Union":
ann_types = frozenlist(
[self.type_from_annotation(e) for e in ann.slice.elts]
)
return union_types(*ann_types)
- if ann.value.id == "List":
+ if ann.value.orig_id == "List":
ann_type = self.type_from_annotation(ann.slice)
assert isinstance(
ann_type, ClassType
@@ -2134,7 +2187,7 @@
Methods
ann_type, TupleType
), "List can currently not hold tuples"
return ListType(InstanceType(ann_type))
- if ann.value.id == "Dict":
+ if ann.value.orig_id == "Dict":
assert isinstance(ann.slice, Tuple), "Dict must combine two classes"
assert len(ann.slice.elts) == 2, "Dict must combine two classes"
ann_types = self.type_from_annotation(
@@ -2147,7 +2200,7 @@
Methods
isinstance(e, TupleType) for e in ann_types
), "Dict can currently not hold tuples"
return DictType(*(InstanceType(a) for a in ann_types))
- if ann.value.id == "Tuple":
+ if ann.value.orig_id == "Tuple":
assert isinstance(
ann.slice, Tuple
), "Tuple must combine several classes"
@@ -2178,7 +2231,9 @@
Methods
for scope in reversed(self.scopes):
if name in scope:
return scope[name]
- raise TypeInferenceError(f"Variable {name} not initialized at access")
+ raise TypeInferenceError(
+ f"Variable {map_to_orig_name(name)} not initialized at access"
+ )
@@ -2207,9 +2262,8 @@
Methods
assert isinstance(
node.target, Name
), "Can only assign to variable names, no type deconstruction"
- self.set_variable_type(
- node.target.id, InstanceType(typed_ass.annotation), force=True
- )
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(node.target.id, InstanceType(typed_ass.annotation))
typed_ass.target = self.visit(node.target)
assert (
typed_ass.value.typ >= InstanceType(typed_ass.annotation)
@@ -2258,8 +2312,8 @@
Methods
assert isinstance(
t, Name
), "Can only assign to variable names, no type deconstruction"
- # Overwrite previous type -> this will only affect following statements
- self.set_variable_type(t.id, typed_ass.value.typ, force=True)
+ # Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
+ self.set_variable_type(t.id, typed_ass.value.typ)
typed_ass.targets = [self.visit(t) for t in node.targets]
return typed_ass
@@ -2295,15 +2349,8 @@
Methods
tb = copy(node)
tb.left = self.visit(node.left)
tb.right = self.visit(node.right)
- outcome_typ_map = BinOpTypeMap.get(type(node.op)).get(tb.left.typ)
- assert (
- outcome_typ_map is not None
- ), f"Operation {node.op} not defined for {tb.left.typ}"
- outcome_typ = outcome_typ_map.get(tb.right.typ)
- assert (
- outcome_typ is not None
- ), f"Operation {node.op} not defined for types {tb.left.typ} and {tb.right.typ}"
- tb.typ = outcome_typ
+ binop_fun_typ: FunctionType = tb.left.typ.binop_type(tb.op, tb.right.typ)
+ tb.typ = binop_fun_typ.rettyp
return tb
@@ -2365,7 +2412,7 @@
Methods
tc = copy(node)
tc.args = [self.visit(a) for a in node.args]
# might be isinstance
- if isinstance(tc.func, Name) and tc.func.id == "isinstance":
+ if isinstance(tc.func, Name) and tc.func.orig_id == "isinstance":
target_class = tc.args[1].typ
if (
isinstance(tc.args[0].typ, InstanceType)
@@ -2586,7 +2633,7 @@
Methods
tfd = copy(node)
wraps_builtin = (
all(
- isinstance(o, Name) and o.id == "wraps_builtin"
+ isinstance(o, Name) and o.orig_id == "wraps_builtin"
for o in node.decorator_list
)
and node.decorator_list
@@ -2599,6 +2646,7 @@
Methods
functyp = FunctionType(
frozenlist([t.typ for t in tfd.args.args]),
InstanceType(self.type_from_annotation(tfd.returns)),
+ externally_bound_vars(node),
)
tfd.typ = InstanceType(functyp)
if wraps_builtin:
@@ -2609,14 +2657,8 @@
Methods
self.set_variable_type(node.name, tfd.typ)
tfd.body = self.visit_sequence(node.body)
# Check that return type and annotated return type match
- if not isinstance(node.body[-1], Return):
- assert (
- functyp.rettyp >= NoneInstanceType
- ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
- else:
- assert (
- functyp.rettyp >= tfd.body[-1].typ
- ), f"Function '{node.name}' annotated return type does not match actual return type"
+ rets_extractor = ReturnExtractor(functyp.rettyp)
+ rets_extractor.check_fulfills(tfd)
self.exit_scope()
# We need the function type outside for usage
@@ -2686,9 +2728,17 @@
def visit_Subscript(self, node: Subscript) -> TypedSubscript:
ts = copy(node)
# special case: Subscript of Union / Dict / List and atomic types
- if isinstance(ts.value, Name) and ts.value.id in [
+ if isinstance(ts.value, Name) and ts.value.orig_id in [
"Union",
"Dict",
"List",
@@ -2887,9 +2937,29 @@
Methods
f"Could not infer type of subscript of typ {ts.value.typ.typ.__class__}"
)
elif isinstance(ts.value.typ.typ, ListType):
- ts.typ = ts.value.typ.typ.typ
- ts.slice = self.visit(node.slice)
- assert ts.slice.typ == IntegerInstanceType, "List indices must be integers"
+ if not isinstance(ts.slice, Slice):
+ ts.typ = ts.value.typ.typ.typ
+ ts.slice = self.visit(node.slice)
+ assert (
+ ts.slice.typ == IntegerInstanceType
+ ), "List indices must be integers"
+ else:
+ ts.typ = ts.value.typ
+ if ts.slice.lower is None:
+ ts.slice.lower = Constant(0)
+ ts.slice.lower = self.visit(node.slice.lower)
+ assert (
+ ts.slice.lower.typ == IntegerInstanceType
+ ), "lower slice indices for lists must be integers"
+ if ts.slice.upper is None:
+ ts.slice.upper = Call(
+ func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
+ )
+ ts.slice.upper.func.orig_id = "len"
+ ts.slice.upper = self.visit(node.slice.upper)
+ assert (
+ ts.slice.upper.typ == IntegerInstanceType
+ ), "upper slice indices for lists must be integers"
elif isinstance(ts.value.typ.typ, ByteStringType):
if not isinstance(ts.slice, Slice):
ts.typ = IntegerInstanceType
@@ -2897,7 +2967,7 @@
Methods
assert (
ts.slice.typ == IntegerInstanceType
), "bytes indices must be integers"
- elif isinstance(ts.slice, Slice):
+ else:
ts.typ = ByteStringInstanceType
if ts.slice.lower is None:
ts.slice.lower = Constant(0)
@@ -2909,16 +2979,12 @@
Methods
ts.slice.upper = Call(
func=Name(id="len", ctx=Load()), args=[ts.value], keywords=[]
)
+ ts.slice.upper.func.orig_id = "len"
ts.slice.upper = self.visit(node.slice.upper)
assert (
ts.slice.upper.typ == IntegerInstanceType
), "upper slice indices for bytes must be integers"
- else:
- raise TypeInferenceError(
- f"Could not infer type of subscript of typ {ts.value.typ.__class__}"
- )
elif isinstance(ts.value.typ.typ, DictType):
- # TODO could be implemented with potentially just erroring. It might be desired to avoid this though.
if not isinstance(ts.slice, Slice):
ts.slice = self.visit(node.slice)
assert (
@@ -3131,6 +3197,7 @@
Methods
class RecordReader(NodeVisitor):
name: str
+ orig_name: str
constructor: int
attributes: typing.List[typing.Tuple[str, Type]]
_type_inferencer: AggressiveTypeInferencer
@@ -3144,7 +3211,7 @@
Utility to check that all paths end in Return statements with the proper type
+
Returns whether there is no remaining path
+
+
+Expand source code
+
+
class ReturnExtractor(TypedNodeVisitor):
+ """
+ Utility to check that all paths end in Return statements with the proper type
+
+ Returns whether there is no remaining path
+ """
+
+ def __init__(self, func_rettyp: Type):
+ self.func_rettyp = func_rettyp
+
+ def visit_sequence(self, nodes: typing.List[TypedAST]) -> bool:
+ all_paths_covered = False
+ for node in nodes:
+ all_paths_covered = self.visit(node)
+ if all_paths_covered:
+ break
+ return all_paths_covered
+
+ def visit_If(self, node: If) -> bool:
+ return self.visit_sequence(node.body) and self.visit_sequence(node.orelse)
+
+ def visit_For(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
+
+ def visit_While(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
+
+ 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"
+ return True
+
+ def check_fulfills(self, node: FunctionDef):
+ all_paths_covered = self.visit_sequence(node.body)
+ if not all_paths_covered:
+ assert (
+ self.func_rettyp >= NoneInstanceType
+ ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
def check_fulfills(self, node: FunctionDef):
+ all_paths_covered = self.visit_sequence(node.body)
+ if not all_paths_covered:
+ assert (
+ self.func_rettyp >= NoneInstanceType
+ ), f"Function '{node.name}' has no return statement but is supposed to return not-None value"
def visit_For(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
def visit_While(self, node: For) -> bool:
+ # The body simply has to be checked but has no influence on whether all paths are covered
+ # because it might never be visited
+ self.visit_sequence(node.body)
+ # the else path is always visited
+ return self.visit_sequence(node.orelse)
def visit_sequence(self, nodes: typing.List[TypedAST]) -> bool:
+ all_paths_covered = False
+ for node in nodes:
+ all_paths_covered = self.visit(node)
+ if all_paths_covered:
+ break
+ return all_paths_covered
+
+
+
+
class TypeCheckVisitor(allow_isinstance_anything=False)
@@ -3396,9 +3645,9 @@
Methods
return getattr(node, "typechecks", ({}, {}))
def visit_Call(self, node: Call) -> TypeMapPair:
- if isinstance(node.func, Name) and node.func.id == SPECIAL_BOOL:
+ if isinstance(node.func, Name) and node.func.orig_id == SPECIAL_BOOL:
return self.visit(node.args[0])
- if not (isinstance(node.func, Name) and node.func.id == "isinstance"):
+ if not (isinstance(node.func, Name) and node.func.orig_id == "isinstance"):
return ({}, {})
# special case for Union
assert isinstance(
@@ -3549,9 +3798,9 @@
Methods
Expand source code
def visit_Call(self, node: Call) -> TypeMapPair:
- if isinstance(node.func, Name) and node.func.id == SPECIAL_BOOL:
+ if isinstance(node.func, Name) and node.func.orig_id == SPECIAL_BOOL:
return self.visit(node.args[0])
- if not (isinstance(node.func, Name) and node.func.id == "isinstance"):
+ if not (isinstance(node.func, Name) and node.func.orig_id == "isinstance"):
return ({}, {})
# special case for Union
assert isinstance(
@@ -3674,6 +3923,7 @@
raise NotImplementedError(f"{type(self).__name__} can not be stringified")
def copy_only_attributes(self) -> plt.AST:
+ """
+ Pluthon function that returns a copy of only the attributes of the object
+ """
raise NotImplementedError(f"{type(self).__name__} can not be copied")
+ def binop_type(self, binop: operator, other: "Type") -> "Type":
+ """
+ Type of a binary operation between self and other.
+ """
+ return FunctionType(
+ [InstanceType(self), InstanceType(other)],
+ InstanceType(self._binop_return_type(binop, other)),
+ )
+
+ def _binop_return_type(self, binop: operator, other: "Type") -> "Type":
+ """
+ Return the type of a binary operation between self and other
+ """
+ raise NotImplementedError(
+ f"{type(self).__name__} does not implement {binop.__class__.__name__}"
+ )
+
+ def binop(self, binop: operator, other: AST) -> plt.AST:
+ """
+ Implements a binary operation between self and other
+ """
+ return OLambda(
+ ["self", "other"],
+ self._binop_bin_fun(binop, other)(OVar("self"), OVar("other")),
+ )
+
+ def _binop_bin_fun(
+ self, binop: operator, other: AST
+ ) -> Callable[[plt.AST, plt.AST], plt.AST]:
+ """
+ Returns a binary function that implements the binary operation between self and other.
+ """
+ raise NotImplementedError(
+ f"{type(self).__name__} can not be used with operation {binop.__class__.__name__}"
+ )
+
@dataclass(frozen=True, unsafe_hash=True)
class Record:
name: str
+ orig_name: str
constructor: int
fields: typing.Union[typing.List[typing.Tuple[str, Type]], frozenlist]
+ def __post_init__(self):
+ object.__setattr__(self, "fields", frozenlist(self.fields))
+
def __ge__(self, other):
if not isinstance(other, Record):
return False
@@ -161,7 +208,7 @@
Module opshin.types
Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too).
For anything but record types and union types, this is the identity function.
"""
- return plt.Lambda(["self"], plt.Var("self"))
+ return OLambda(["self"], OVar("self"))
@dataclass(frozen=True, unsafe_hash=True)
@@ -178,9 +225,9 @@
Module opshin.types
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
return super().attribute(attr)
@@ -195,44 +242,42 @@
build_constr_params = plt.EmptyDataList()
for n, t in reversed(self.record.fields):
build_constr_params = plt.MkCons(
- transform_output_map(t)(plt.Var(n)), build_constr_params
+ transform_output_map(t)(plt.Force(OVar(n))), build_constr_params
)
# then build a constr type with this PlutusData
- return plt.Lambda(
- [n for n, _ in self.record.fields] + ["_"],
+ return SafeOLambda(
+ [n for n, _ in self.record.fields],
plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
)
@@ -449,28 +488,28 @@
Module opshin.types
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
if attr in (n for n, t in self.record.fields):
attr_typ = self.attribute_type(attr)
pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
# access to normal fields
- return plt.Lambda(
+ return OLambda(
["self"],
transform_ext_params_map(attr_typ)(
plt.NthField(
- plt.Var("self"),
+ OVar("self"),
plt.Integer(pos),
),
),
)
if attr == "to_cbor":
- return plt.Lambda(
+ return OLambda(
["self", "_"],
plt.SerialiseData(
- plt.Var("self"),
+ OVar("self"),
),
)
raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")
@@ -485,13 +524,13 @@
class UnionType(ClassType):
typs: typing.List[RecordType]
+ def __post_init__(self):
+ object.__setattr__(self, "typs", frozenlist(self.typs))
+
def attribute_type(self, attr) -> "Type":
if attr == "CONSTR_ID":
return IntegerInstanceType
# need to have a common field with the same name
if all(attr in (n for n, t in x.record.fields) for x in self.typs):
- attr_types = set(
+ attr_types = OrderedSet(
t for x in self.typs for n, t in x.record.fields if n == attr
)
for at in attr_types:
@@ -631,9 +671,9 @@
Module opshin.types
def attribute(self, attr: str) -> plt.AST:
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
# iterate through all names/types of the unioned records by position
if any(attr in (n for n, t in r.record.fields) for r in self.typs):
@@ -660,11 +700,11 @@
Module opshin.types
for pos, constrs in pos_constrs:
assert constrs, "Found empty constructors for a position"
constr_check = plt.EqualsInteger(
- plt.Var("constr"), plt.Integer(constrs[0])
+ OVar("constr"), plt.Integer(constrs[0])
)
for constr in constrs[1:]:
constr_check = plt.Or(
- plt.EqualsInteger(plt.Var("constr"), plt.Integer(constr)),
+ plt.EqualsInteger(OVar("constr"), plt.Integer(constr)),
constr_check,
)
pos_decisor = plt.Ite(
@@ -672,23 +712,23 @@
and any(o.typ.typ >= t or t >= o.typ.typ for t in self.typs)
):
if isinstance(op, In):
- return plt.Lambda(
+ return OLambda(
["x", "y"],
plt.EqualsData(
- plt.Var("x"),
+ OVar("x"),
plt.FindList(
- plt.Var("y"),
+ OVar("y"),
plt.Apply(
plt.BuiltIn(uplc.BuiltInFun.EqualsData),
- plt.Var("x"),
+ OVar("x"),
),
# this simply ensures the default is always unequal to the searched value
plt.ConstrData(
plt.AddInteger(
- plt.Constructor(plt.Var("x")), plt.Integer(1)
+ plt.Constructor(OVar("x")), plt.Integer(1)
),
plt.MkNilData(plt.Unit()),
),
@@ -753,15 +793,15 @@
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
return super().attribute(attr)
@@ -2705,44 +2828,42 @@
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
return super().attribute(attr)
Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too).
For anything but record types and union types, this is the identity function.
"""
- return plt.Lambda(["self"], plt.Var("self"))
Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too).
For anything but record types and union types, this is the identity function.
"""
- return plt.Lambda(["self"], plt.Var("self"))
+ return OLambda(["self"], OVar("self"))
@@ -4715,24 +4907,34 @@
Methods
def attribute(self, attr) -> plt.AST:
if attr == "get":
- return plt.Lambda(
- ["self", "key", "default", "_"],
+ return OLambda(
+ ["self", "key", "default"],
transform_ext_params_map(self.value_typ)(
- plt.SndPair(
- plt.FindList(
- plt.Var("self"),
- plt.Lambda(
- ["x"],
- plt.EqualsData(
- transform_output_map(self.key_typ)(plt.Var("key")),
- plt.FstPair(plt.Var("x")),
+ OLet(
+ [
+ (
+ "key_mapped",
+ transform_output_map(self.key_typ)(
+ plt.Force(OVar("key"))
),
- ),
- # this is a bit ugly... we wrap - only to later unwrap again
- plt.MkPairData(
- transform_output_map(self.key_typ)(plt.Var("key")),
- transform_output_map(self.value_typ)(
- plt.Var("default")
+ )
+ ],
+ plt.SndPair(
+ plt.FindList(
+ OVar("self"),
+ OLambda(
+ ["x"],
+ plt.EqualsData(
+ OVar("key_mapped"),
+ plt.FstPair(OVar("x")),
+ ),
+ ),
+ # this is a bit ugly... we wrap - only to later unwrap again
+ plt.MkPairData(
+ OVar("key_mapped"),
+ transform_output_map(self.value_typ)(
+ plt.Force(OVar("default"))
+ ),
),
),
),
@@ -4740,37 +4942,35 @@
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 …
+
Implements a binary operation between self and other
-
-def constr(self) ‑> pluthon.pluthon_ast.AST
+
+def binop_type(self, binop: ast.operator, other: Type) ‑> Type
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 …
@dataclass(frozen=True, unsafe_hash=True)
class Record:
name: str
+ orig_name: str
constructor: int
fields: typing.Union[typing.List[typing.Tuple[str, Type]], frozenlist]
+ def __post_init__(self):
+ object.__setattr__(self, "fields", frozenlist(self.fields))
+
def __ge__(self, other):
if not isinstance(other, Record):
return False
@@ -7166,6 +7652,10 @@
Class variables
+
var orig_name :Â str
+
+
+
@@ -7194,11 +7684,11 @@
Class variables
build_constr_params = plt.EmptyDataList()
for n, t in reversed(self.record.fields):
build_constr_params = plt.MkCons(
- transform_output_map(t)(plt.Var(n)), build_constr_params
+ transform_output_map(t)(plt.Force(OVar(n))), build_constr_params
)
# then build a constr type with this PlutusData
- return plt.Lambda(
- [n for n, _ in self.record.fields] + ["_"],
+ return SafeOLambda(
+ [n for n, _ in self.record.fields],
plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
)
@@ -7219,28 +7709,28 @@
Class variables
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
if attr in (n for n, t in self.record.fields):
attr_typ = self.attribute_type(attr)
pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
# access to normal fields
- return plt.Lambda(
+ return OLambda(
["self"],
transform_ext_params_map(attr_typ)(
plt.NthField(
- plt.Var("self"),
+ OVar("self"),
plt.Integer(pos),
),
),
)
if attr == "to_cbor":
- return plt.Lambda(
+ return OLambda(
["self", "_"],
plt.SerialiseData(
- plt.Var("self"),
+ OVar("self"),
),
)
raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")
@@ -7255,13 +7745,13 @@
"""The attributes of this class. Need to be a lambda that expects as first argument the object itself"""
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
if attr in (n for n, t in self.record.fields):
attr_typ = self.attribute_type(attr)
pos = next(i for i, (n, _) in enumerate(self.record.fields) if n == attr)
# access to normal fields
- return plt.Lambda(
+ return OLambda(
["self"],
transform_ext_params_map(attr_typ)(
plt.NthField(
- plt.Var("self"),
+ OVar("self"),
plt.Integer(pos),
),
),
)
if attr == "to_cbor":
- return plt.Lambda(
+ return OLambda(
["self", "_"],
plt.SerialiseData(
- plt.Var("self"),
+ OVar("self"),
),
)
raise NotImplementedError(f"Attribute {attr} not implemented for type {self}")
@@ -7446,6 +7934,26 @@
and (o.typ.typ >= self or self >= o.typ.typ)
):
if isinstance(op, In):
- return plt.Lambda(
+ return OLambda(
["x", "y"],
plt.EqualsData(
- plt.Var("x"),
+ OVar("x"),
plt.FindList(
- plt.Var("y"),
+ OVar("y"),
plt.Apply(
plt.BuiltIn(uplc.BuiltInFun.EqualsData),
- plt.Var("x"),
+ OVar("x"),
),
# this simply ensures the default is always unequal to the searched value
plt.ConstrData(
plt.AddInteger(
- plt.Constructor(plt.Var("x")), plt.Integer(1)
+ plt.Constructor(OVar("x")), plt.Integer(1)
),
plt.MkNilData(plt.Unit()),
),
@@ -7526,11 +8034,11 @@
Methods
build_constr_params = plt.EmptyDataList()
for n, t in reversed(self.record.fields):
build_constr_params = plt.MkCons(
- transform_output_map(t)(plt.Var(n)), build_constr_params
+ transform_output_map(t)(plt.Force(OVar(n))), build_constr_params
)
# then build a constr type with this PlutusData
- return plt.Lambda(
- [n for n, _ in self.record.fields] + ["_"],
+ return SafeOLambda(
+ [n for n, _ in self.record.fields],
plt.ConstrData(plt.Integer(self.record.constructor), build_constr_params),
)
@@ -7573,28 +8081,28 @@
raise NotImplementedError(f"{type(self).__name__} can not be stringified")
def copy_only_attributes(self) -> plt.AST:
- raise NotImplementedError(f"{type(self).__name__} can not be copied")
+ """
+ Pluthon function that returns a copy of only the attributes of the object
+ """
+ raise NotImplementedError(f"{type(self).__name__} can not be copied")
+
+ def binop_type(self, binop: operator, other: "Type") -> "Type":
+ """
+ Type of a binary operation between self and other.
+ """
+ return FunctionType(
+ [InstanceType(self), InstanceType(other)],
+ InstanceType(self._binop_return_type(binop, other)),
+ )
+
+ def _binop_return_type(self, binop: operator, other: "Type") -> "Type":
+ """
+ Return the type of a binary operation between self and other
+ """
+ raise NotImplementedError(
+ f"{type(self).__name__} does not implement {binop.__class__.__name__}"
+ )
+
+ def binop(self, binop: operator, other: AST) -> plt.AST:
+ """
+ Implements a binary operation between self and other
+ """
+ return OLambda(
+ ["self", "other"],
+ self._binop_bin_fun(binop, other)(OVar("self"), OVar("other")),
+ )
+
+ def _binop_bin_fun(
+ self, binop: operator, other: AST
+ ) -> Callable[[plt.AST, plt.AST], plt.AST]:
+ """
+ Returns a binary function that implements the binary operation between self and other.
+ """
+ raise NotImplementedError(
+ f"{type(self).__name__} can not be used with operation {binop.__class__.__name__}"
+ )
Pluthon function that returns a copy of only the attributes of the object
Expand source code
def copy_only_attributes(self) -> plt.AST:
+ """
+ Pluthon function that returns a copy of only the attributes of the object
+ """
raise NotImplementedError(f"{type(self).__name__} can not be copied")
@@ -8286,12 +8929,15 @@
Ancestors
class UnionType(ClassType):
typs: typing.List[RecordType]
+ def __post_init__(self):
+ object.__setattr__(self, "typs", frozenlist(self.typs))
+
def attribute_type(self, attr) -> "Type":
if attr == "CONSTR_ID":
return IntegerInstanceType
# need to have a common field with the same name
if all(attr in (n for n, t in x.record.fields) for x in self.typs):
- attr_types = set(
+ attr_types = OrderedSet(
t for x in self.typs for n, t in x.record.fields if n == attr
)
for at in attr_types:
@@ -8317,9 +8963,9 @@
Ancestors
def attribute(self, attr: str) -> plt.AST:
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
# iterate through all names/types of the unioned records by position
if any(attr in (n for n, t in r.record.fields) for r in self.typs):
@@ -8346,11 +8992,11 @@
Ancestors
for pos, constrs in pos_constrs:
assert constrs, "Found empty constructors for a position"
constr_check = plt.EqualsInteger(
- plt.Var("constr"), plt.Integer(constrs[0])
+ OVar("constr"), plt.Integer(constrs[0])
)
for constr in constrs[1:]:
constr_check = plt.Or(
- plt.EqualsInteger(plt.Var("constr"), plt.Integer(constr)),
+ plt.EqualsInteger(OVar("constr"), plt.Integer(constr)),
constr_check,
)
pos_decisor = plt.Ite(
@@ -8358,23 +9004,23 @@
and any(o.typ.typ >= t or t >= o.typ.typ for t in self.typs)
):
if isinstance(op, In):
- return plt.Lambda(
+ return OLambda(
["x", "y"],
plt.EqualsData(
- plt.Var("x"),
+ OVar("x"),
plt.FindList(
- plt.Var("y"),
+ OVar("y"),
plt.Apply(
plt.BuiltIn(uplc.BuiltInFun.EqualsData),
- plt.Var("x"),
+ OVar("x"),
),
# this simply ensures the default is always unequal to the searched value
plt.ConstrData(
plt.AddInteger(
- plt.Constructor(plt.Var("x")), plt.Integer(1)
+ plt.Constructor(OVar("x")), plt.Integer(1)
),
plt.MkNilData(plt.Unit()),
),
@@ -8439,15 +9085,15 @@
def attribute(self, attr: str) -> plt.AST:
if attr == "CONSTR_ID":
# access to constructor
- return plt.Lambda(
+ return OLambda(
["self"],
- plt.Constructor(plt.Var("self")),
+ plt.Constructor(OVar("self")),
)
# iterate through all names/types of the unioned records by position
if any(attr in (n for n, t in r.record.fields) for r in self.typs):
@@ -8530,11 +9174,11 @@
Methods
for pos, constrs in pos_constrs:
assert constrs, "Found empty constructors for a position"
constr_check = plt.EqualsInteger(
- plt.Var("constr"), plt.Integer(constrs[0])
+ OVar("constr"), plt.Integer(constrs[0])
)
for constr in constrs[1:]:
constr_check = plt.Or(
- plt.EqualsInteger(plt.Var("constr"), plt.Integer(constr)),
+ plt.EqualsInteger(OVar("constr"), plt.Integer(constr)),
constr_check,
)
pos_decisor = plt.Ite(
@@ -8542,23 +9186,23 @@
return IntegerInstanceType
# need to have a common field with the same name
if all(attr in (n for n, t in x.record.fields) for x in self.typs):
- attr_types = set(
+ attr_types = OrderedSet(
t for x in self.typs for n, t in x.record.fields if n == attr
)
for at in attr_types:
@@ -8606,6 +9250,26 @@
and any(o.typ.typ >= t or t >= o.typ.typ for t in self.typs)
):
if isinstance(op, In):
- return plt.Lambda(
+ return OLambda(
["x", "y"],
plt.EqualsData(
- plt.Var("x"),
+ OVar("x"),
plt.FindList(
- plt.Var("y"),
+ OVar("y"),
plt.Apply(
plt.BuiltIn(uplc.BuiltInFun.EqualsData),
- plt.Var("x"),
+ OVar("x"),
),
# this simply ensures the default is always unequal to the searched value
plt.ConstrData(
plt.AddInteger(
- plt.Constructor(plt.Var("x")), plt.Integer(1)
+ plt.Constructor(OVar("x")), plt.Integer(1)
),
plt.MkNilData(plt.Unit()),
),
@@ -8711,16 +9375,14 @@
def OLet(bindings: typing.List[typing.Tuple[str, plt.AST]], term: plt.AST):
+ return plt.Let(
+ [(opshin_name_scheme_compatible_varname(n), t) for n, t in bindings], term
+ )
def read_vars(node):
+ """
+ Returns all variable names read to in this node
+ """
+ collector = NameReadCollector()
+ collector.visit(node)
+ return sorted(collector.read.keys())
+
+
+
+def written_vars(node)
+
+
+
Returns all variable names written to in this node
+
+
+Expand source code
+
+
def written_vars(node):
+ """
+ Returns all variable names written to in this node
+ """
+ collector = NameWriteCollector()
+ collector.visit(node)
+ return sorted(collector.written.keys())
A node visitor base class that walks the abstract syntax tree and calls a
+visitor function for every node found.
+This function may return a value
+which is forwarded by the visit method.
+
This class is meant to be subclassed, with the subclass adding visitor
+methods.
+
Per default the visitor functions for the nodes are 'visit_' +
+class name of the node.
+So a TryFinally node visit function would
+be visit_TryFinally.
+This behavior can be changed by overriding
+the visit method.
+If no visitor function exists for a node
+(return value None) the generic_visit visitor is used instead.
+
Don't use the NodeVisitor if you want to apply changes to nodes during
+traversing.
+For this a special visitor exists (NodeTransformer) that
+allows modifications.
+
+
+Expand source code
+
+
class NameReadCollector(CompilingNodeVisitor):
+ step = "Collecting variables that are read"
+
+ def __init__(self):
+ self.read = defaultdict(int)
+
+ def visit_AnnAssign(self, node) -> None:
+ # ignore annotations of variables
+ self.visit(node.value)
+ self.visit(node.target)
+
+ def visit_FunctionDef(self, node) -> None:
+ # ignore annotations of paramters and return
+ self.visit(node.args)
+ for b in node.body:
+ self.visit(b)
+
+ def visit_Name(self, node: Name) -> None:
+ if isinstance(node.ctx, Load):
+ self.read[node.id] += 1
+
+ def visit_ClassDef(self, node: ClassDef):
+ # ignore the content (i.e. attribute names) of class definitions
+ pass
+
+ def visit_FunctionDef(self, node: FunctionDef):
+ # ignore the type hints of function arguments
+ for s in node.body:
+ self.visit(s)
A node visitor base class that walks the abstract syntax tree and calls a
+visitor function for every node found.
+This function may return a value
+which is forwarded by the visit method.
+
This class is meant to be subclassed, with the subclass adding visitor
+methods.
+
Per default the visitor functions for the nodes are 'visit_' +
+class name of the node.
+So a TryFinally node visit function would
+be visit_TryFinally.
+This behavior can be changed by overriding
+the visit method.
+If no visitor function exists for a node
+(return value None) the generic_visit visitor is used instead.
+
Don't use the NodeVisitor if you want to apply changes to nodes during
+traversing.
+For this a special visitor exists (NodeTransformer) that
+allows modifications.
+
+
+Expand source code
+
+
class NameWriteCollector(CompilingNodeVisitor):
+ step = "Collecting variables that are written"
+
+ def __init__(self):
+ self.written = defaultdict(int)
+
+ def visit_Name(self, node: Name) -> None:
+ if isinstance(node.ctx, Store):
+ self.written[node.id] += 1
+
+ def visit_ClassDef(self, node: ClassDef):
+ # ignore the content (i.e. attribute names) of class definitions
+ self.written[node.name] += 1
+ pass
+
+ def visit_FunctionDef(self, node: FunctionDef):
+ # ignore the type hints of function arguments
+ self.written[node.name] += 1
+ for a in node.args.args:
+ self.written[a.arg] += 1
+ for s in node.body:
+ self.visit(s)
def visit_FunctionDef(self, node: FunctionDef):
+ # ignore the type hints of function arguments
+ self.written[node.name] += 1
+ for a in node.args.args:
+ self.written[a.arg] += 1
+ for s in node.body:
+ self.visit(s)