Skip to content

Commit

Permalink
Add error for scratch slot load before store (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos authored Mar 26, 2021
1 parent 9191e3c commit 147d2b6
Show file tree
Hide file tree
Showing 62 changed files with 1,159 additions and 894 deletions.
5 changes: 2 additions & 3 deletions pyteal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from .ir import __all__ as ir_all
from .compiler import compileTeal
from .types import TealType
from .errors import TealInternalError, TealTypeError, TealInputError
from .util import execute
from .errors import TealInternalError, TealTypeError, TealInputError, TealCompileError
from .config import MAX_GROUP_SIZE

__all__ = ast_all + ir_all + [
Expand All @@ -14,6 +13,6 @@
"TealInternalError",
"TealTypeError",
"TealInputError",
"execute",
"TealCompileError",
"MAX_GROUP_SIZE",
]
3 changes: 2 additions & 1 deletion pyteal/ast/addr.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ def __init__(self, address: str) -> None:
Args:
address: A string containing a valid base32 Algorand address
"""
super().__init__()
valid_address(address)
self.address = address

def __teal__(self):
op = TealOp(Op.addr, self.address)
op = TealOp(self, Op.addr, self.address)
return TealBlock.FromOp(op)

def __str__(self):
Expand Down
2 changes: 1 addition & 1 deletion pyteal/ast/addr_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def test_addr():
expr = Addr("NJUWK3DJNZTWU2LFNRUW4Z3KNFSWY2LOM5VGSZLMNFXGO2TJMVWGS3THMF")
assert expr.type_of() == TealType.bytes
expected = TealSimpleBlock([
TealOp(Op.addr, "NJUWK3DJNZTWU2LFNRUW4Z3KNFSWY2LOM5VGSZLMNFXGO2TJMVWGS3THMF")
TealOp(expr, Op.addr, "NJUWK3DJNZTWU2LFNRUW4Z3KNFSWY2LOM5VGSZLMNFXGO2TJMVWGS3THMF")
])
actual, _ = expr.__teal__()
assert actual == expected
Expand Down
3 changes: 2 additions & 1 deletion pyteal/ast/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class App(LeafExpr):
"""An expression related to applications."""

def __init__(self, field:AppField, args) -> None:
super().__init__()
self.field = field
self.args = args

Expand All @@ -58,7 +59,7 @@ def __str__(self):
return ret_str

def __teal__(self):
return TealBlock.FromOp(TealOp(self.field.get_op()), *self.args)
return TealBlock.FromOp(TealOp(self, self.field.get_op()), *self.args)

def type_of(self):
return self.field.type_of()
Expand Down
110 changes: 61 additions & 49 deletions pyteal/ast/app_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,44 @@

def test_on_complete():
assert OnComplete.NoOp.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "NoOp")
TealOp(OnComplete.NoOp, Op.int, "NoOp")
])

assert OnComplete.OptIn.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "OptIn")
TealOp(OnComplete.OptIn, Op.int, "OptIn")
])

assert OnComplete.CloseOut.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "CloseOut")
TealOp(OnComplete.CloseOut, Op.int, "CloseOut")
])

assert OnComplete.ClearState.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "ClearState")
TealOp(OnComplete.ClearState, Op.int, "ClearState")
])

assert OnComplete.UpdateApplication.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "UpdateApplication")
TealOp(OnComplete.UpdateApplication, Op.int, "UpdateApplication")
])

assert OnComplete.DeleteApplication.__teal__()[0] == TealSimpleBlock([
TealOp(Op.int, "DeleteApplication")
TealOp(OnComplete.DeleteApplication, Op.int, "DeleteApplication")
])

def test_app_id():
expr = App.id()
assert expr.type_of() == TealType.uint64
assert expr.__teal__()[0] == Global.current_application_id().__teal__()[0]
with TealComponent.Context.ignoreExprEquality():
assert expr.__teal__()[0] == Global.current_application_id().__teal__()[0]

def test_opted_in():
expr = App.optedIn(Int(1), Int(12))
args = [Int(1), Int(12)]
expr = App.optedIn(args[0], args[1])
assert expr.type_of() == TealType.uint64

expected = TealSimpleBlock([
TealOp(Op.int, 1),
TealOp(Op.int, 12),
TealOp(Op.app_opted_in)
TealOp(args[0], Op.int, 1),
TealOp(args[1], Op.int, 12),
TealOp(expr, Op.app_opted_in)
])

actual, _ = expr.__teal__()
Expand All @@ -49,13 +51,14 @@ def test_opted_in():
assert actual == expected

def test_local_get():
expr = App.localGet(Int(0), Bytes("key"))
args = [Int(0), Bytes("key")]
expr = App.localGet(args[0], args[1])
assert expr.type_of() == TealType.anytype

expected = TealSimpleBlock([
TealOp(Op.int, 0),
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_local_get)
TealOp(args[0], Op.int, 0),
TealOp(args[1], Op.byte, "\"key\""),
TealOp(expr, Op.app_local_get)
])

actual, _ = expr.__teal__()
Expand All @@ -72,24 +75,26 @@ def test_local_get_invalid():
App.localGet(Int(0), Int(1))

def test_local_get_ex():
expr = App.localGetEx(Int(0), Int(6), Bytes("key"))
args = [Int(0), Int(6), Bytes("key")]
expr = App.localGetEx(args[0], args[1], args[2])
assert expr.type_of() == TealType.none
assert expr.value().type_of() == TealType.anytype

expected = TealSimpleBlock([
TealOp(Op.int, 0),
TealOp(Op.int, 6),
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_local_get_ex),
TealOp(Op.store, expr.slotOk),
TealOp(Op.store, expr.slotValue)
TealOp(args[0], Op.int, 0),
TealOp(args[1], Op.int, 6),
TealOp(args[2], Op.byte, "\"key\""),
TealOp(expr, Op.app_local_get_ex),
TealOp(None, Op.store, expr.slotOk),
TealOp(None, Op.store, expr.slotValue)
])

actual, _ = expr.__teal__()
actual.addIncoming()
actual = TealBlock.NormalizeBlocks(actual)

assert actual == expected
with TealComponent.Context.ignoreExprEquality():
assert actual == expected

def test_local_get_ex_invalid():
with pytest.raises(TealTypeError):
Expand All @@ -102,12 +107,13 @@ def test_local_get_ex_invalid():
App.localGetEx(Int(0), Int(0), Int(1))

def test_global_get():
expr = App.globalGet(Bytes("key"))
arg = Bytes("key")
expr = App.globalGet(arg)
assert expr.type_of() == TealType.anytype

expected = TealSimpleBlock([
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_global_get)
TealOp(arg, Op.byte, "\"key\""),
TealOp(expr, Op.app_global_get)
])

actual, _ = expr.__teal__()
Expand All @@ -121,23 +127,25 @@ def test_global_get_invalid():
App.globalGet(Int(7))

def test_global_get_ex():
expr = App.globalGetEx(Int(6), Bytes("key"))
args = [Int(6), Bytes("key")]
expr = App.globalGetEx(args[0], args[1])
assert expr.type_of() == TealType.none
assert expr.value().type_of() == TealType.anytype

expected = TealSimpleBlock([
TealOp(Op.int, 6),
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_global_get_ex),
TealOp(Op.store, expr.slotOk),
TealOp(Op.store, expr.slotValue)
TealOp(args[0], Op.int, 6),
TealOp(args[1], Op.byte, "\"key\""),
TealOp(expr, Op.app_global_get_ex),
TealOp(None, Op.store, expr.slotOk),
TealOp(None, Op.store, expr.slotValue)
])

actual, _ = expr.__teal__()
actual.addIncoming()
actual = TealBlock.NormalizeBlocks(actual)

assert actual == expected
with TealComponent.Context.ignoreExprEquality():
assert actual == expected

def test_global_get_ex_invalid():
with pytest.raises(TealTypeError):
Expand All @@ -147,14 +155,15 @@ def test_global_get_ex_invalid():
App.globalGetEx(Int(0), Int(1))

def test_local_put():
expr = App.localPut(Int(0), Bytes("key"), Int(5))
args = [Int(0), Bytes("key"), Int(5)]
expr = App.localPut(args[0], args[1], args[2])
assert expr.type_of() == TealType.none

expected = TealSimpleBlock([
TealOp(Op.int, 0),
TealOp(Op.byte, "\"key\""),
TealOp(Op.int, 5),
TealOp(Op.app_local_put)
TealOp(args[0], Op.int, 0),
TealOp(args[1], Op.byte, "\"key\""),
TealOp(args[2], Op.int, 5),
TealOp(expr, Op.app_local_put)
])

actual, _ = expr.__teal__()
Expand All @@ -174,13 +183,14 @@ def test_local_put_invalid():
App.localPut(Int(1), Bytes("key"), Pop(Int(1)))

def test_global_put():
expr = App.globalPut(Bytes("key"), Int(5))
args = [Bytes("key"), Int(5)]
expr = App.globalPut(args[0], args[1])
assert expr.type_of() == TealType.none

expected = TealSimpleBlock([
TealOp(Op.byte, "\"key\""),
TealOp(Op.int, 5),
TealOp(Op.app_global_put)
TealOp(args[0], Op.byte, "\"key\""),
TealOp(args[1], Op.int, 5),
TealOp(expr, Op.app_global_put)
])

actual, _ = expr.__teal__()
Expand All @@ -197,13 +207,14 @@ def test_global_put_invalid():
App.globalPut(Bytes("key"), Pop(Int(1)))

def test_local_del():
expr = App.localDel(Int(0), Bytes("key"))
args = [Int(0), Bytes("key")]
expr = App.localDel(args[0], args[1])
assert expr.type_of() == TealType.none

expected = TealSimpleBlock([
TealOp(Op.int, 0),
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_local_del)
TealOp(args[0], Op.int, 0),
TealOp(args[1], Op.byte, "\"key\""),
TealOp(expr, Op.app_local_del)
])

actual, _ = expr.__teal__()
Expand All @@ -220,12 +231,13 @@ def test_local_del_invalid():
App.localDel(Int(1), Int(2))

def test_global_del():
expr = App.globalDel(Bytes("key"))
arg = Bytes("key")
expr = App.globalDel(arg)
assert expr.type_of() == TealType.none

expected = TealSimpleBlock([
TealOp(Op.byte, "\"key\""),
TealOp(Op.app_global_del)
TealOp(arg, Op.byte, "\"key\""),
TealOp(expr, Op.app_global_del)
])

actual, _ = expr.__teal__()
Expand Down
4 changes: 3 additions & 1 deletion pyteal/ast/arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def __init__(self, index: int) -> None:
Args:
index: The integer index of the argument to get. Must be between 0 and 255 inclusive.
"""
super().__init__()

if type(index) is not int:
raise TealInputError("invalid arg input type {}".format(type(index)))

Expand All @@ -24,7 +26,7 @@ def __init__(self, index: int) -> None:
self.index = index

def __teal__(self):
op = TealOp(Op.arg, self.index)
op = TealOp(self, Op.arg, self.index)
return TealBlock.FromOp(op)

def __str__(self):
Expand Down
2 changes: 1 addition & 1 deletion pyteal/ast/arg_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def test_arg():
expr = Arg(0)
assert expr.type_of() == TealType.bytes
expected = TealSimpleBlock([
TealOp(Op.arg, 0)
TealOp(expr, Op.arg, 0)
])
actual, _ = expr.__teal__()
assert actual == expected
Expand Down
4 changes: 2 additions & 2 deletions pyteal/ast/assert_.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from ..types import TealType, require_type
from ..ir import TealOp, Op, TealSimpleBlock, TealConditionalBlock
from ..util import new_label
from .expr import Expr

class Assert(Expr):
Expand All @@ -12,14 +11,15 @@ def __init__(self, cond: Expr) -> None:
Args:
cond: The condition to check. Must evaluate to a uint64.
"""
super().__init__()
require_type(cond.type_of(), TealType.uint64)
self.cond = cond

def __teal__(self):
condStart, condEnd = self.cond.__teal__()

end = TealSimpleBlock([])
errBlock = TealSimpleBlock([TealOp(Op.err)])
errBlock = TealSimpleBlock([TealOp(self, Op.err)])

branchBlock = TealConditionalBlock([])
branchBlock.setTrueBlock(end)
Expand Down
3 changes: 2 additions & 1 deletion pyteal/ast/assert_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def test_assert():

actual, _ = expr.__teal__()

assert actual == expected
with TealComponent.Context.ignoreExprEquality():
assert actual == expected

def test_assert_invalid():
with pytest.raises(TealTypeError):
Expand Down
2 changes: 1 addition & 1 deletion pyteal/ast/asset.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum

from ..types import TealType, require_type
from ..ir import TealOp, Op
from ..ir import Op
from .expr import Expr
from .leafexpr import LeafExpr
from .maybe import MaybeValue
Expand Down
Loading

0 comments on commit 147d2b6

Please sign in to comment.