Exemple #1
0
    def __teal__(self, options: "CompileOptions"):
        if len(self.cond) > 1:
            asserts: list[Expr] = []
            for cond in self.cond:
                asrt = Assert(cond, comment=self.comment)
                asrt.trace = cond.trace
                asserts.append(asrt)
            return Seq(*asserts).__teal__(options)

        if options.version >= Op.assert_.min_version:
            # use assert op if available
            conds: list[Expr] = [self.cond[0]]
            if self.comment is not None:
                conds.append(Comment(self.comment))
            return TealBlock.FromOp(options, TealOp(self, Op.assert_), *conds)

        # if assert op is not available, use branches and err
        condStart, condEnd = self.cond[0].__teal__(options)

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

        branchBlock = TealConditionalBlock([])
        branchBlock.setTrueBlock(end)
        branchBlock.setFalseBlock(errBlock)

        condEnd.setNextBlock(branchBlock)

        return condStart, end
Exemple #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
Exemple #3
0
    def __teal__(self, options: "CompileOptions"):
        op = self.__get_op(options)

        verifyProgramVersion(
            op.min_version,
            options.version,
            "Program version too low to use op {}".format(op),
        )

        if op == Op.extract:
            # if possible, exploit optimization in the extract opcode that takes the suffix
            # when the length argument is 0
            return TealBlock.FromOp(
                options,
                TealOp(self, op,
                       cast(Int, self.startArg).value, 0),
                self.stringArg,
            )
        elif op == Op.substring3:
            strBlockStart, strBlockEnd = self.stringArg.__teal__(options)
            nextBlockStart, nextBlockEnd = self.startArg.__teal__(options)
            strBlockEnd.setNextBlock(nextBlockStart)

            finalBlock = TealSimpleBlock([
                TealOp(self, Op.dig, 1),
                TealOp(self, Op.len),
                TealOp(self, Op.substring3),
            ])

            nextBlockEnd.setNextBlock(finalBlock)
            return strBlockStart, finalBlock
Exemple #4
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
Exemple #5
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
Exemple #6
0
    def __teal__(self, options: "CompileOptions"):
        start = None
        end = None
        for i, arg in enumerate(self.args):
            argStart, argEnd = arg.__teal__(options)
            if i == 0:
                start = argStart
                end = argEnd
            else:
                cast(TealSimpleBlock, end).setNextBlock(argStart)
                opBlock = TealSimpleBlock([TealOp(self, self.op)])
                argEnd.setNextBlock(opBlock)
                end = opBlock

        return start, end
Exemple #7
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
Exemple #8
0
def multiplyFactors(
    expr: Expr, factors: List[Expr], options: "CompileOptions"
) -> Tuple[TealSimpleBlock, TealSimpleBlock]:
    if len(factors) == 0:
        raise TealInternalError("Received 0 factors")

    start = TealSimpleBlock([])

    fac0Start, fac0End = factors[0].__teal__(options)

    if len(factors) == 1:
        # need to use 0 as high word
        highword = TealSimpleBlock([TealOp(expr, Op.int, 0)])

        start.setNextBlock(highword)
        highword.setNextBlock(fac0Start)

        end = fac0End
    else:
        start.setNextBlock(fac0Start)

        fac1Start, fac1End = factors[1].__teal__(options)
        fac0End.setNextBlock(fac1Start)

        multiplyFirst2 = TealSimpleBlock([TealOp(expr, Op.mulw)])
        fac1End.setNextBlock(multiplyFirst2)

        end = multiplyFirst2
        for factor in factors[2:]:
            facXStart, facXEnd = factor.__teal__(options)
            end.setNextBlock(facXStart)

            # stack is [..., A, B, C], where C is current factor
            # need to pop all A,B,C from stack and push X,Y, where X and Y are:
            #       X * 2**64 + Y = (A * 2**64 + B) * C
            # <=>   X * 2**64 + Y = A * C * 2**64 + B * C
            # <=>   X = A * C + highword(B * C)
            #       Y = lowword(B * C)
            multiply = TealSimpleBlock(
                [
                    TealOp(expr, Op.uncover, 2),  # stack: [..., B, C, A]
                    TealOp(expr, Op.dig, 1),  # stack: [..., B, C, A, C]
                    TealOp(expr, Op.mul),  # stack: [..., B, C, A*C]
                    TealOp(expr, Op.cover, 2),  # stack: [..., A*C, B, C]
                    TealOp(
                        expr, Op.mulw
                    ),  # stack: [..., A*C, highword(B*C), lowword(B*C)]
                    TealOp(
                        expr, Op.cover, 2
                    ),  # stack: [..., lowword(B*C), A*C, highword(B*C)]
                    TealOp(
                        expr, Op.add
                    ),  # stack: [..., lowword(B*C), A*C+highword(B*C)]
                    TealOp(
                        expr, Op.swap
                    ),  # stack: [..., A*C+highword(B*C), lowword(B*C)]
                ]
            )

            facXEnd.setNextBlock(multiply)
            end = multiply

    return start, end