def __str__(self): if self.start is None: raise TealCompileError("For expression must have a start", self) if self.cond is None: raise TealCompileError("For expression must have a condition", self) if self.step is None: raise TealCompileError("For expression must have a end", self) if self.doBlock is None: raise TealCompileError("For expression must have a doBlock", self) return "(For {} {} {} {})".format(self.start, self.cond, self.step, self.doBlock)
def __teal__(self, options: "CompileOptions"): if self.doBlock is None: raise TealCompileError("While expression must have a doBlock", self) options.enterLoop() condStart, condEnd = self.cond.__teal__(options) doStart, doEnd = self.doBlock.__teal__(options) end = TealSimpleBlock([]) doEnd.setNextBlock(condStart) branchBlock = TealConditionalBlock([]) branchBlock.setTrueBlock(doStart) branchBlock.setFalseBlock(end) condEnd.setNextBlock(branchBlock) breakBlocks, continueBlocks = options.exitLoop() for block in breakBlocks: block.setNextBlock(end) for block in continueBlocks: block.setNextBlock(condStart) return condStart, end
def __teal__(self, options: "CompileOptions"): if options.version < Op.cover.min_version: raise TealCompileError( "WideRatio requires program version {} or higher".format( Op.cover.min_version ), self, ) numStart, numEnd = multiplyFactors(self, self.numeratorFactors, options) denomStart, denomEnd = multiplyFactors(self, self.denominatorFactors, options) numEnd.setNextBlock(denomStart) combine = TealSimpleBlock( [ TealOp(self, Op.divmodw), TealOp(self, Op.pop), # pop remainder low word TealOp(self, Op.pop), # pop remainder high word TealOp(self, Op.swap), # swap quotient high and low words TealOp(self, Op.logic_not), TealOp(self, Op.assert_), # assert quotient high word is 0 # end with quotient low word remaining on the stack ] ) denomEnd.setNextBlock(combine) return numStart, combine
def __teal__(self, options: "CompileOptions"): if not options.isInLoop(): raise TealCompileError("continue is only allowed in a loop", self) start = TealSimpleBlock([]) options.addLoopContinueBlock(start) return start, start
def __str__(self): if self.thenBranch is None: raise TealCompileError("If expression must have a thenBranch", self) if self.elseBranch is None: return "(If {} {})".format(self.cond, self.thenBranch) return "(If {} {} {})".format(self.cond, self.thenBranch, self.elseBranch)
def Do(self, doBlock: Expr, *do_block_multi: Expr): if self.doBlock is not None: raise TealCompileError("While expression already has a doBlock", self) doBlock = _use_seq_if_multiple(doBlock, *do_block_multi) require_type(doBlock, TealType.none) self.doBlock = doBlock return self
def __teal__(self, options: "CompileOptions"): if options.currentSubroutine is not None: verifyProgramVersion( Op.retsub.min_version, options.version, "Program version too low to use subroutines", ) returnType = options.currentSubroutine.return_type if returnType == TealType.none: if self.value is not None: raise TealCompileError( "Cannot return a value from a subroutine with return type TealType.none", self, ) else: if self.value is None: raise TealCompileError( "A subroutine declares it returns a value, but no value is being returned", self, ) actualType = self.value.type_of() if not types_match(actualType, returnType): raise TealCompileError( "Incompatible return type from subroutine, expected {} but got {}" .format(returnType, actualType), self, ) op = Op.retsub else: if self.value is None: raise TealCompileError( "Return from main program must have an argument", self) actualType = self.value.type_of() if not types_match(actualType, TealType.uint64): raise TealCompileError( "Incompatible return type from main program, expected {} but got {}" .format(TealType.uint64, actualType), self, ) op = Op.return_ args = [] if self.value is None else [self.value] return TealBlock.FromOp(options, TealOp(self, op), *args)
def type_of(self): if self.thenBranch is None: raise TealCompileError("If expression must have a thenBranch", self) if self.elseBranch is None: # if there is only a thenBranch, it must evaluate to TealType.none require_type(self.thenBranch, TealType.none) return self.thenBranch.type_of()
def has_return(self): if self.thenBranch is None: raise TealCompileError("If expression must have a thenBranch", self) if self.elseBranch is None: # return false in this case because elseBranch does not exist, so it can't have a return # op return False # otherwise, this expression has a return op only if both branches result in a return op return self.thenBranch.has_return() and self.elseBranch.has_return()
def __teal__(self, options: "CompileOptions"): verifyFieldVersion(self.field.arg_name, self.field.min_version, options.version) opToUse = self.staticOp if type(self.index) is int else self.dynamicOp if opToUse is None: raise TealCompileError("Dynamic array indexing not supported", self) verifyProgramVersion( opToUse.min_version, options.version, "Program version too low to use op {}".format(opToUse), ) if type(self.index) is int: op = TealOp(self, opToUse, self.field.arg_name, self.index) return TealBlock.FromOp(options, op) op = TealOp(self, opToUse, self.field.arg_name) return TealBlock.FromOp(options, op, cast(Expr, self.index))
def __get_op(self, options: "CompileOptions"): s, e = cast(Int, self.startArg).value, cast(Int, self.endArg).value l = e - s if l < 0: raise TealCompileError( "The end index must be greater than or equal to the start index", self, ) if l > 0 and options.version >= Op.extract.min_version: if s < 2**8 and l < 2**8: return Op.extract else: return Op.extract3 else: if s < 2**8 and e < 2**8: return Op.substring else: return Op.substring3
def validateSlots( self, slotsInUse: Set["ScratchSlot"] = None, visited: Set[Tuple[int, ...]] = None, ) -> List[TealCompileError]: if visited is None: visited = set() if slotsInUse is None: slotsInUse = set() currentSlotsInUse = set(slotsInUse) errors = [] for op in self.ops: if op.getOp() == Op.store: for slot in op.getSlots(): currentSlotsInUse.add(slot) if op.getOp() == Op.load: for slot in op.getSlots(): if slot not in currentSlotsInUse: e = TealCompileError( "Scratch slot load occurs before store", op.expr) errors.append(e) if not self.isTerminal(): sortedSlots = sorted(slot.id for slot in currentSlotsInUse) for block in self.getOutgoing(): visitedKey = (id(block), *sortedSlots) if visitedKey in visited: continue visited.add(visitedKey) for error in block.validateSlots(currentSlotsInUse, visited): if error not in errors: errors.append(error) return errors
def __teal__(self, options: "CompileOptions"): if self.thenBranch is None: raise TealCompileError("If expression must have a thenBranch", self) condStart, condEnd = self.cond.__teal__(options) thenStart, thenEnd = self.thenBranch.__teal__(options) end = TealSimpleBlock([]) branchBlock = TealConditionalBlock([]) branchBlock.setTrueBlock(thenStart) condEnd.setNextBlock(branchBlock) thenEnd.setNextBlock(end) if self.elseBranch is None: branchBlock.setFalseBlock(end) else: elseStart, elseEnd = self.elseBranch.__teal__(options) branchBlock.setFalseBlock(elseStart) elseEnd.setNextBlock(end) return condStart, end
def type_of(self): if self.doBlock is None: raise TealCompileError("While expression must have a doBlock", self) return TealType.none
def __str__(self): if self.doBlock is None: raise TealCompileError("While expression must have a doBlock", self) return "(While {} {})".format(self.cond, self.doBlock)