Skip to content

Commit

Permalink
Merge pull request #393 from OpShin/feat/fromhex
Browse files Browse the repository at this point in the history
Add bytes.fromhex
  • Loading branch information
nielstron authored Jul 23, 2024
2 parents 5648a1d + 20edc34 commit 6a0918b
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
24 changes: 24 additions & 0 deletions opshin/tests/test_builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,27 @@ def validator(x: int, y: bool, z: None) -> None:
print(x, y, z)
"""
eval_uplc(source_code, x, y, Unit())

@given(
i=st.one_of(
st.text(),
st.builds(lambda x: x.hex(), st.binary()),
st.builds(lambda x: x.hex()[:-1], st.binary()),
st.builds(lambda x: x.hex().upper(), st.binary()),
)
)
@example("")
def test_fromhex(self, i):
source_code = """
def validator(x: str) -> bytes:
return b"".fromhex(x)
"""
try:
ret = eval_uplc_value(source_code, i.encode("utf8"))
except RuntimeError as e:
ret = None
try:
exp = bytes.fromhex(i)
except ValueError:
exp = None
self.assertEqual(ret, exp, "fromhex returned wrong value")
144 changes: 144 additions & 0 deletions opshin/type_impls.py
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,13 @@ def attribute_type(self, attr) -> Type:
return InstanceType(FunctionType(frozenlist([]), StringInstanceType))
if attr == "hex":
return InstanceType(FunctionType(frozenlist([]), StringInstanceType))
if attr == "fromhex":
return InstanceType(
FunctionType(
frozenlist([StringInstanceType]),
ByteStringInstanceType,
)
)
return super().attribute_type(attr)

def attribute(self, attr) -> plt.AST:
Expand Down Expand Up @@ -1875,6 +1882,143 @@ def attribute(self, attr) -> plt.AST:
),
),
)
if attr == "fromhex":
return OLambda(
["_", "x"],
OLet(
[
(
"bytestr",
plt.EncodeUtf8(plt.Force(OVar("x"))),
),
(
"bytestr_len",
plt.LengthOfByteString(OVar("bytestr")),
),
(
"char_to_int",
OLambda(
["c"],
plt.Ite(
plt.And(
plt.LessThanEqualsInteger(
plt.Integer(ord("a")), OVar("c")
),
plt.LessThanEqualsInteger(
OVar("c"), plt.Integer(ord("f"))
),
),
plt.AddInteger(
plt.SubtractInteger(
OVar("c"), plt.Integer(ord("a"))
),
plt.Integer(10),
),
plt.Ite(
plt.And(
plt.LessThanEqualsInteger(
plt.Integer(ord("0")), OVar("c")
),
plt.LessThanEqualsInteger(
OVar("c"), plt.Integer(ord("9"))
),
),
plt.SubtractInteger(
OVar("c"), plt.Integer(ord("0"))
),
plt.Ite(
plt.And(
plt.LessThanEqualsInteger(
plt.Integer(ord("A")), OVar("c")
),
plt.LessThanEqualsInteger(
OVar("c"), plt.Integer(ord("F"))
),
),
plt.AddInteger(
plt.SubtractInteger(
OVar("c"), plt.Integer(ord("A"))
),
plt.Integer(10),
),
plt.TraceError("Invalid hex character"),
),
),
),
),
),
(
"splitlist",
plt.RecFun(
OLambda(
["f", "i"],
plt.Ite(
plt.LessThanInteger(
OVar("bytestr_len"),
plt.AddInteger(OVar("i"), plt.Integer(1)),
),
plt.ByteString(b""),
plt.Ite(
plt.LessThanInteger(
OVar("bytestr_len"),
plt.AddInteger(
OVar("i"), plt.Integer(2)
),
),
plt.TraceError("Invalid hex string"),
OLet(
[
(
"char_at_i",
plt.IndexByteString(
OVar("bytestr"),
OVar("i"),
),
),
(
"char_at_ip1",
plt.IndexByteString(
OVar("bytestr"),
plt.AddInteger(
OVar("i"),
plt.Integer(1),
),
),
),
],
plt.ConsByteString(
plt.AddInteger(
plt.MultiplyInteger(
plt.Apply(
OVar("char_to_int"),
OVar("char_at_i"),
),
plt.Integer(16),
),
plt.Apply(
OVar("char_to_int"),
OVar("char_at_ip1"),
),
),
plt.Apply(
OVar("f"),
OVar("f"),
plt.AddInteger(
OVar("i"),
plt.Integer(2),
),
),
),
),
),
),
)
),
),
],
plt.Apply(OVar("splitlist"), plt.Integer(0)),
),
)
return super().attribute(attr)

def cmp(self, op: cmpop, o: "Type") -> plt.AST:
Expand Down

0 comments on commit 6a0918b

Please sign in to comment.