Skip to content

Commit

Permalink
Merge pull request #305 from OpShin/feat/allow_empty_lists
Browse files Browse the repository at this point in the history
Feat/allow empty lists
  • Loading branch information
nielstron authored Jan 12, 2024
2 parents 867b24a + 2602cd5 commit 833ce51
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 1 deletion.
2 changes: 2 additions & 0 deletions opshin/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .rewrite.rewrite_augassign import RewriteAugAssign
from .rewrite.rewrite_cast_condition import RewriteConditions
from .rewrite.rewrite_comparison_chaining import RewriteComparisonChaining
from .rewrite.rewrite_empty_lists import RewriteEmptyLists
from .rewrite.rewrite_forbidden_overwrites import RewriteForbiddenOverwrites
from .rewrite.rewrite_forbidden_return import RewriteForbiddenReturn
from .rewrite.rewrite_import import RewriteImport
Expand Down Expand Up @@ -1025,6 +1026,7 @@ def compile(
# The type inference needs to be run after complex python operations were rewritten
AggressiveTypeInferencer(allow_isinstance_anything),
# Rewrites that circumvent the type inference or use its results
RewriteEmptyLists(),
RewriteImportUPLCBuiltins(),
RewriteInjectBuiltinsConstr(),
RewriteRemoveTypeStuff(),
Expand Down
25 changes: 25 additions & 0 deletions opshin/rewrite/rewrite_empty_lists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import re
from copy import copy
from typing import Optional
from enum import Enum

from ..util import CompilingNodeTransformer
from ..typed_ast import *

"""
Replaces empty lists with UPLC constants of empty lists
"""


class RewriteEmptyLists(CompilingNodeTransformer):
step = "Rewrite empty lists to uplc empty lists"

def visit_List(self, node: TypedList):
if node.elts:
return node
return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))

def visit_Constant(self, node: TypedConstant):
if node.value != []:
return node
return RawPlutoExpr(typ=node.typ, expr=empty_list(node.typ.typ.typ))
27 changes: 27 additions & 0 deletions opshin/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2624,3 +2624,30 @@ def validator(a: int) -> int:
"""
res = eval_uplc_value(source_code, 1)
self.assertEqual(res, 0, "Invalid return")

def test_empty_list_int(self):
source_code = """
def validator(_: None) -> List[int]:
a: List[int] = []
return a + [1]
"""
res = eval_uplc_value(source_code, Unit())
self.assertEqual(res, [uplc.PlutusInteger(1)])

def test_empty_list_data(self):
source_code = """
from opshin.prelude import *
def validator(_: None) -> List[Token]:
a: List[Token] = []
return a + [Token(b"", b"")]
"""
res = eval_uplc_value(source_code, Unit())
self.assertEqual(
res,
[
uplc.PlutusConstr(
0, [uplc.PlutusByteString(b""), uplc.PlutusByteString(b"")]
)
],
)
10 changes: 9 additions & 1 deletion opshin/type_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,16 @@ def visit_Assign(self, node: Assign) -> TypedAssign:

def visit_AnnAssign(self, node: AnnAssign) -> TypedAnnAssign:
typed_ass = copy(node)
typed_ass.value: TypedExpression = self.visit(node.value)
typed_ass.annotation = self.type_from_annotation(node.annotation)
if isinstance(typed_ass.annotation, ListType) and (
(isinstance(node.value, Constant) and node.value.value == [])
or (isinstance(node.value, List) and node.value.elts == [])
):
# Empty lists are only allowed in annotated assignments
typed_ass.value: TypedExpression = copy(node.value)
typed_ass.value.typ = InstanceType(typed_ass.annotation)
else:
typed_ass.value: TypedExpression = self.visit(node.value)
assert isinstance(
node.target, Name
), "Can only assign to variable names, no type deconstruction"
Expand Down

0 comments on commit 833ce51

Please sign in to comment.