Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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()
Ejemplo n.º 9
0
    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()
Ejemplo n.º 10
0
    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))
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
 def type_of(self):
     if self.doBlock is None:
         raise TealCompileError("While expression must have a doBlock",
                                self)
     return TealType.none
Ejemplo n.º 15
0
    def __str__(self):
        if self.doBlock is None:
            raise TealCompileError("While expression must have a doBlock",
                                   self)

        return "(While {} {})".format(self.cond, self.doBlock)