-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from jasonpaulos/restructure
Internal restructure
- Loading branch information
Showing
26 changed files
with
1,238 additions
and
1,211 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
from .ops import * | ||
from .ast import * | ||
from .errors import TealInternalError, TealTypeError, TealTypeMismatchError, TealInputError | ||
from .util import execute | ||
from .config import MAX_GROUP_SIZE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# abstract types | ||
from .expr import Expr | ||
|
||
# basic types | ||
from .leafexpr import LeafExpr | ||
from .addr import Addr | ||
from .bytes import Bytes | ||
from .err import Err | ||
from .int import Int | ||
|
||
# properties | ||
from .arg import Arg | ||
from .txn import Txn, TxnField | ||
from .gtxn import Gtxn | ||
from .global_ import Global | ||
|
||
# meta | ||
from .tmpl import Tmpl | ||
from .nonce import Nonce | ||
|
||
# unary ops | ||
from .unaryexpr import UnaryExpr, Btoi, Itob, Len, Sha256, Sha512_256, Keccak256, Pop | ||
|
||
# binary ops | ||
from .binaryexpr import BinaryExpr, Add, Minus, Mul, Div, Mod, Eq, Lt, Le, Gt, Ge | ||
|
||
# more ops | ||
from .ed25519verify import Ed25519Verify | ||
from .naryexpr import NaryExpr, And, Or | ||
|
||
# control flow | ||
from .if_ import If | ||
from .cond import Cond |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from typing import Union | ||
|
||
from ..types import TealType, valid_address | ||
from .leafexpr import LeafExpr | ||
from .tmpl import Tmpl | ||
|
||
class Addr(LeafExpr): | ||
"""An expression that represents an Algorand address.""" | ||
|
||
def __init__(self, address: Union[str, Tmpl]) -> None: | ||
"""Create a new Addr expression. | ||
Args: | ||
address: A string containing a valid base32 Algorand address, or a Tmpl object. | ||
""" | ||
if isinstance(address, Tmpl): | ||
self.address = address.name | ||
else: | ||
valid_address(address) | ||
self.address = address | ||
|
||
def __teal__(self): | ||
return [["addr", self.address]] | ||
|
||
def __str__(self): | ||
return "(address: {})".format(self.address) | ||
|
||
def type_of(self): | ||
return TealType.bytes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from ..types import TealType | ||
from ..errors import TealInputError | ||
from .leafexpr import LeafExpr | ||
|
||
class Arg(LeafExpr): | ||
"""An expression to get an argument.""" | ||
|
||
def __init__(self, index:int) -> None: | ||
"""Get an argument for this program. | ||
Args: | ||
index: The integer index of the argument to get. Must be between 0 and 255 inclusive. | ||
""" | ||
if type(index) is not int: | ||
raise TealInputError("invalid arg input type {}".format(type(index))) | ||
|
||
if index < 0 or index > 255: | ||
raise TealInputError("invalid arg index {}".format(index)) | ||
|
||
self.index = index | ||
|
||
def __teal__(self): | ||
return [["arg", str(self.index)]] | ||
|
||
def __str__(self): | ||
return "(arg {})".format(self.index) | ||
|
||
def type_of(self): | ||
return TealType.bytes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
from ..types import TealType, require_type, types_match | ||
from ..errors import TealTypeMismatchError | ||
from .expr import Expr | ||
|
||
class BinaryExpr(Expr): | ||
"""An expression with two arguments.""" | ||
|
||
def __init__(self, op: str, inputType: TealType, outputType: TealType, argLeft: Expr, argRight: Expr) -> None: | ||
require_type(argLeft.type_of(), inputType) | ||
require_type(argRight.type_of(), inputType) | ||
self.op = op | ||
self.outputType = outputType | ||
self.argLeft = argLeft | ||
self.argRight = argRight | ||
|
||
def __teal__(self): | ||
teal = self.argLeft.__teal__() + self.argRight.__teal__() | ||
teal.append([self.op]) | ||
return teal | ||
|
||
def __str__(self): | ||
return "({} {} {})".format(self.op, self.argLeft, self.argRight) | ||
|
||
def type_of(self): | ||
return self.outputType | ||
|
||
def Add(left: Expr, right: Expr): | ||
"""Add two numbers. | ||
Produces left + right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("+", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Minus(left: Expr, right: Expr): | ||
"""Subtract two numbers. | ||
Produces left - right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("-", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Mul(left: Expr, right: Expr): | ||
"""Multiply two numbers. | ||
Produces left * right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("*", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Div(left: Expr, right: Expr): | ||
"""Divide two numbers. | ||
Produces left / right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("/", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Mod(left: Expr, right: Expr): | ||
"""Modulo expression. | ||
Produces left % right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("%", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Eq(left: Expr, right: Expr): | ||
"""Equality expression. | ||
Checks if left == right. | ||
Args: | ||
left: A value to check. | ||
right: The other value to check. Must evaluate to the same type as left. | ||
""" | ||
# a hack to make this op emit TealTypeMismatchError instead of TealTypeError | ||
t1 = left.type_of() | ||
t2 = right.type_of() | ||
if not types_match(t1, t2): | ||
raise TealTypeMismatchError(t1, t2) | ||
return BinaryExpr("==", TealType.anytype, TealType.uint64, left, right) | ||
|
||
def Lt(left: Expr, right: Expr): | ||
"""Less than expression. | ||
Checks if left < right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("<", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Le(left: Expr, right: Expr): | ||
"""Less than or equal to expression. | ||
Checks if left <= right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr("<=", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Gt(left: Expr, right: Expr): | ||
"""Greater than expression. | ||
Checks if left > right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr(">", TealType.uint64, TealType.uint64, left, right) | ||
|
||
def Ge(left: Expr, right: Expr): | ||
"""Greater than or equal to expression. | ||
Checks if left >= right. | ||
Args: | ||
left: Must evaluate to uint64. | ||
right: Must evaluate to uint64. | ||
""" | ||
return BinaryExpr(">=", TealType.uint64, TealType.uint64, left, right) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from typing import Union | ||
|
||
from ..types import TealType, valid_base16, valid_base32, valid_base64 | ||
from ..errors import TealInputError | ||
from .leafexpr import LeafExpr | ||
from .tmpl import Tmpl | ||
|
||
class Bytes(LeafExpr): | ||
"""An expression that represents a byte string.""" | ||
|
||
def __init__(self, base: str, byte_str: Union[str, Tmpl]) -> None: | ||
"""Create a new byte string. | ||
Args: | ||
base: The base type for this byte string. Must be one of base16, base32, or base64. | ||
byte_string: The content of the byte string, encoding with the passed in base, or a Tmpl | ||
object. | ||
""" | ||
if base == "base32": | ||
self.base = base | ||
if isinstance(byte_str, Tmpl): | ||
self.byte_str = byte_str.name | ||
else: | ||
valid_base32(byte_str) | ||
self.byte_str = byte_str | ||
elif base == "base64": | ||
self.base = base | ||
if isinstance(byte_str, Tmpl): | ||
self.byte_str = byte_str.name | ||
else: | ||
self.byte_str = byte_str | ||
valid_base64(byte_str) | ||
elif base == "base16": | ||
self.base = base | ||
if isinstance(byte_str, Tmpl): | ||
self.byte_str = byte_str.name | ||
elif byte_str.startswith("0x"): | ||
self.byte_str = byte_str[2:] | ||
valid_base16(self.byte_str) | ||
else: | ||
self.byte_str = byte_str | ||
valid_base16(self.byte_str) | ||
else: | ||
raise TealInputError("invalid base {}, need to be base32, base64, or base16.".format(base)) | ||
|
||
def __teal__(self): | ||
if self.base != "base16": | ||
return [["byte", self.base, self.byte_str]] | ||
else: | ||
return [["byte", "0x" + self.byte_str]] | ||
|
||
def __str__(self): | ||
return "({} bytes: {})".format(self.base, self.byte_str) | ||
|
||
def type_of(self): | ||
return TealType.bytes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
from typing import List | ||
|
||
from ..types import TealType, require_type | ||
from ..errors import TealInputError | ||
from ..util import new_label | ||
from .expr import Expr | ||
from .err import Err | ||
from .if_ import If | ||
|
||
class Cond(Expr): | ||
"""A chainable branching expression that supports an arbitrary number of conditions.""" | ||
|
||
def __init__(self, *argv: List[Expr]): | ||
"""Create a new Cond expression. | ||
At least one argument must be provided, and each argument must be a list with two elements. | ||
The first element is a condition which evalutes to uint64, and the second is the body of the | ||
condition, which will execute if that condition is true. All condition bodies must have the | ||
same return type. During execution, each condition is tested in order, and the first | ||
condition to evaluate to a true value will cause its associated body to execute and become | ||
the value for this Cond expression. If no condition evalutes to a true value, the Cond | ||
expression produces an error and the TEAL program terminates. | ||
For example: | ||
Cond([Global.group_size() == Int(5), bid], | ||
[Global.group_size() == Int(4), redeem], | ||
[Global.group_size() == Int(1), wrapup]) | ||
""" | ||
|
||
if len(argv) < 1: | ||
raise TealInputError("Cond requires at least one [condition, value]") | ||
|
||
value_type = None | ||
|
||
for arg in argv: | ||
msg = "Cond should be in the form of Cond([cond1, value1], [cond2, value2], ...), error in {}" | ||
if not isinstance(arg, list): | ||
raise TealInputError(msg.format(arg)) | ||
if len(arg) != 2: | ||
raise TealInputError(msg.format(arg)) | ||
|
||
require_type(arg[0].type_of(), TealType.uint64) # cond_n should be int | ||
|
||
if value_type is None: # the types of all branches should be the same | ||
value_type = arg[1].type_of() | ||
else: | ||
require_type(arg[1].type_of(), value_type) | ||
|
||
self.value_type = value_type | ||
self.args = argv | ||
|
||
def __teal__(self): | ||
teal = [] | ||
|
||
labels = [] | ||
for arg in self.args: | ||
l = new_label() | ||
cond = arg[0] | ||
|
||
teal += cond.__teal__() | ||
teal += [["bnz", l]] | ||
|
||
labels.append(l) | ||
|
||
# err if no conditions are met | ||
teal += [["err"]] | ||
|
||
# end label | ||
labels.append(new_label()) | ||
|
||
for i, arg in enumerate(self.args): | ||
label = labels[i] + ":" | ||
branch = arg[1] | ||
|
||
teal += [[label]] | ||
teal += branch.__teal__() | ||
if i + 1 != len(self.args): | ||
teal += [["int", "1"], ["bnz", labels[-1]]] | ||
|
||
endLabel = labels[-1] + ":" | ||
|
||
teal += [[endLabel]] | ||
|
||
return teal | ||
|
||
def __str__(self): | ||
ret_str = "(Cond" | ||
for a in self.args: | ||
ret_str += " [" + a[0].__str__() + ", " + a[1].__str__() + "]" | ||
ret_str += ")" | ||
return ret_str | ||
|
||
def type_of(self): | ||
return self.value_type |
Oops, something went wrong.