# Path: cbl/function_type.py
# class FunctionType(NativeType, Invokable):
# 
#     def __init__(self, ret_type, params, inline, is_async):
#         self.ret_type = ret_type
#         self.params = tuple(params)
#         self.is_inline = inline
#         self.is_async = is_async
#         self.is_intrinsic = False
# 
#     def param_str(self):
#         return '(%s)' % ', '.join('%s %s%s' % (p.type.typename,
#                                                '&' if p.by_ref else '',
#                                                p.name) \
#                                   for p in self.params)
# 
#     def allocate(self, compiler, namehint):
#         return FunctionContainer(self, compiler, namehint)
# 
#     def intrinsic_invoke(self, container, args):
#         assert self.is_intrinsic, "Function is not intrinsic"
#         return container.value.intrinsic_invoke(container, args)
# 
#     def invoke(self, container, args, ret_args):
#         assert not self.is_intrinsic, "Cannot call invoke on intrinsic"
#         return container.value.invoke(args, ret_args)
# 
#     def match_arguments(self, compiler, container, args):
#         matcher = FunctionMatcher(compiler, container.value.name)
#         matcher.add_candidate(container)
#         return matcher.satisfy(args)
# 
# class Invokable:
# 
#     def match_arguments(self, compiler, container, args):
#         assert False
# 
# class IntrinsicCallable(IntrinsicFunction):
# 
#     def __init__(self, func):
#         assert callable(func)
#         self.__func = func
# 
#     def invoke(self, compiler, container, args):
#         ret = self.__func(compiler, container, args)
#         assert ret is not None
#         return ret
# 
# Path: cbl/containers.py
# class AsyncReturn:
# class DelegatedWrite:
#     def __init__(self, realret, callback):
#     def must_await(self):
#     def type(self):
#     def value(self):
#     def write(self, compiler, other):


from .function_type import FunctionType, Invokable, IntrinsicCallable
from .containers import Temporary

    def __init__(self, ret_type, params, body, typescope, compiletime):
        super().__init__(ret_type, params, True, False)
        self._typescope = typescope
        if type(body) == tuple:
            self._body, self._init_list = body
        else:
            self._body, self._init_list = body, False
        self.compiletime = compiletime

    def allocate(self, compiler, namehint):
        func = super().allocate(compiler, namehint)
        func.set_as_intrinsic(IntrinsicCallable(self.__expand))
        return func

    def __expand(self, compiler, container, args):
        if self.compiletime:
            return self.__expand_compiletime(compiler, args)
        else:
            return self.__expand_macro(compiler, args)

    def __expand_macro(self, compiler, args, ret_does_return=False):
        with compiler._process_body_main(self.ret_type,
                return_var=False, ret_does_return=ret_does_return) as ret:
            with compiler.types.typescope(self._typescope):
                compiler._alloc_and_copy_params(self.params, args)
                if self._init_list != False:
                    compiler.construct_this(self._init_list)
                compiler.transform(self._body)
                if ret is None:

# Path: cbl/function_type.py
# class FunctionType(NativeType, Invokable):
# 
#     def __init__(self, ret_type, params, inline, is_async):
#         self.ret_type = ret_type
#         self.params = tuple(params)
#         self.is_inline = inline
#         self.is_async = is_async
#         self.is_intrinsic = False
# 
#     def param_str(self):
#         return '(%s)' % ', '.join('%s %s%s' % (p.type.typename,
#                                                '&' if p.by_ref else '',
#                                                p.name) \
#                                   for p in self.params)
# 
#     def allocate(self, compiler, namehint):
#         return FunctionContainer(self, compiler, namehint)
# 
#     def intrinsic_invoke(self, container, args):
#         assert self.is_intrinsic, "Function is not intrinsic"
#         return container.value.intrinsic_invoke(container, args)
# 
#     def invoke(self, container, args, ret_args):
#         assert not self.is_intrinsic, "Cannot call invoke on intrinsic"
#         return container.value.invoke(args, ret_args)
# 
#     def match_arguments(self, compiler, container, args):
#         matcher = FunctionMatcher(compiler, container.value.name)
#         matcher.add_candidate(container)
#         return matcher.satisfy(args)
# 
# class Invokable:
# 
#     def match_arguments(self, compiler, container, args):
#         assert False
# 
# class IntrinsicCallable(IntrinsicFunction):
# 
#     def __init__(self, func):
#         assert callable(func)
#         self.__func = func
# 
#     def invoke(self, compiler, container, args):
#         ret = self.__func(compiler, container, args)
#         assert ret is not None
#         return ret
# 
# Path: cbl/containers.py
# class AsyncReturn:
# class DelegatedWrite:
#     def __init__(self, realret, callback):
#     def must_await(self):
#     def type(self):
#     def value(self):
#     def write(self, compiler, other):


# Path: cbl/macro_type.py
from .function_type import FunctionType, Invokable, IntrinsicCallable
from .containers import Temporary


    def __init__(self, ret_type, params, body, typescope, compiletime):
        super().__init__(ret_type, params, True, False)
        self._typescope = typescope
        if type(body) == tuple:
            self._body, self._init_list = body
        else:
            self._body, self._init_list = body, False
        self.compiletime = compiletime

    def allocate(self, compiler, namehint):
        func = super().allocate(compiler, namehint)
        func.set_as_intrinsic(IntrinsicCallable(self.__expand))
        return func

    def __expand(self, compiler, container, args):
        if self.compiletime:
            return self.__expand_compiletime(compiler, args)
        else:
            return self.__expand_macro(compiler, args)

    def __expand_macro(self, compiler, args, ret_does_return=False):
        with compiler._process_body_main(self.ret_type,
                return_var=False, ret_does_return=ret_does_return) as ret:
            with compiler.types.typescope(self._typescope):
                compiler._alloc_and_copy_params(self.params, args)
                if self._init_list != False:
                    compiler.construct_this(self._init_list)
                compiler.transform(self._body)
                if ret is None:

                    return Temporary(compiler.type('void'), None)