<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def decoratable_funcdef_stmt_handle(self, original, loc, tokens, is_async=False):
 """Determines if TCO or TRE can be done and if so does it, handles dotted function names, and universalizes async functions."""

        if len(tokens) == 1:
            decorators, funcdef = "", tokens[0]
        elif len(tokens) == 2:
            decorators, funcdef = tokens
        else:
            raise CoconutInternalException("invalid function definition tokens", tokens)

        # extract information about the function
        raw_lines = funcdef.splitlines(True)
        def_stmt = raw_lines.pop(0)
        func_name, func_args, func_params = None, None, None
        with self.complain_on_err():
            func_name, func_args, func_params = parse(self.split_func_name_args_params, def_stmt)

        undotted_name = None  # the function __name__ if func_name is a dotted name
        if func_name is not None:
            if "." in func_name:
                undotted_name = func_name.rsplit(".", 1)[-1]
                def_stmt = def_stmt.replace(func_name, undotted_name)

        # handle async functions
        if is_async:
            if not self.target:
                raise self.make_err(
                    CoconutTargetError,
                    "async function definition requires a specific target",
                    original, loc,
                    target="sys",
                )
            elif self.target_info >= (3, 5):
                def_stmt = "async " + def_stmt
            else:
                decorators += "@_coconut.asyncio.coroutine\n"

            # only Python 3.3+ supports returning values inside generators
            if self.target_info < (3, 3):
                func_code = self.transform_returns(raw_lines, is_async=True)
            else:
                func_code = "".join(raw_lines)

        # handle normal functions
        else:
            # tre does not work with decorators, though tco does
            attempt_tre = func_name is not None and not decorators
            if attempt_tre:
                use_mock = func_args and func_args != func_params[1:-1]
                func_store = tre_store_var + "_" + str(self.tre_store_count)
                self.tre_store_count += 1
                tre_return_grammar = self.tre_return(func_name, func_args, func_store, use_mock)
            else:
                use_mock = func_store = tre_return_grammar = None

            func_code, tco, tre = self.transform_returns(
                raw_lines,
                tre_return_grammar,
                use_mock,
            )

            if tre:
                comment, rest = split_leading_comment(func_code)
                indent, base, dedent = split_leading_trailing_indent(rest, 1)
                base, base_dedent = split_trailing_indent(base)
                docstring, base = self.split_docstring(base)
                func_code = (
                    comment + indent
                    + (docstring + "\n" if docstring is not None else "")
                    + (
                        "def " + tre_mock_var + func_params + ": return " + func_args + "\n"
                        if use_mock else ""
                    ) + "while True:\n"
                        + openindent + base + base_dedent
                        + ("\n" if "\n" not in base_dedent else "") + "return None"
                        + ("\n" if "\n" not in dedent else "") + closeindent + dedent
                    + func_store + " = " + (func_name if undotted_name is None else undotted_name) + "\n"
                )
            if tco:
                decorators += "@_coconut_tco\n"  # binds most tightly

        out = decorators + def_stmt + func_code
        if undotted_name is not None:
            out += func_name + " = " + undotted_name + "\n"
        return out