import t, c
from stdint import *
import memhub
import string
from .base import (
    AST, ASTKind,
    _init_ast, _copy_str, _set_parent_list,
    _emit, _emit_str, _emit_int, _dump_list,
)


# ============================================================
# ExceptHandler 节点
# ============================================================

class ExceptHandler(AST):
    """ExceptHandler(type: AST, name: str)"""
    type: AST | t.CPtr
    name: str

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                type: AST | t.CPtr, name: str):
        ptr: ExceptHandler | t.CPtr = pool.alloc(ExceptHandler.__sizeof__())
        if ptr:
            string.memset(ptr, 0, ExceptHandler.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 type: AST | t.CPtr, name: str):
        _init_ast(self, pool, 0, 0)
        self.type = type
        self.name = _copy_str(pool, name)

    def kind(self) -> t.CInt:
        return ASTKind.ExceptHandler

    def type_name(self) -> str:
        return "ExceptHandler"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "ExceptHandler(type=")
        if self.type is not None:
            pos = self.type.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", name='")
        pos = _emit_str(buf, size, pos, self.name)
        pos = _emit(buf, size, pos, "', body=")
        pos = _dump_list(self.children, buf, size, pos)
        pos = _emit(buf, size, pos, ")")
        return pos


# ============================================================
# Arguments 节点
# ============================================================

class Arguments(AST):
    """Arguments(args: list[AST | CPtr], vararg: AST, kwarg: AST,
                 defaults: list[AST | CPtr], kw_defaults: list[AST | CPtr])"""
    args:         list[AST | t.CPtr] | t.CPtr
    vararg:       AST | t.CPtr
    kwarg:        AST | t.CPtr
    defaults:     list[AST | t.CPtr] | t.CPtr
    kw_defaults:  list[AST | t.CPtr] | t.CPtr

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                args: list[AST | t.CPtr] | t.CPtr,
                vararg: AST | t.CPtr, kwarg: AST | t.CPtr,
                defaults: list[AST | t.CPtr] | t.CPtr,
                kw_defaults: list[AST | t.CPtr] | t.CPtr):
        ptr: Arguments | t.CPtr = pool.alloc(Arguments.__sizeof__())
        if ptr:
            string.memset(ptr, 0, Arguments.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 args: list[AST | t.CPtr] | t.CPtr,
                 vararg: AST | t.CPtr, kwarg: AST | t.CPtr,
                 defaults: list[AST | t.CPtr] | t.CPtr,
                 kw_defaults: list[AST | t.CPtr] | t.CPtr):
        _init_ast(self, pool, 0, 0)
        self.args = args
        self.vararg = vararg
        self.kwarg = kwarg
        self.defaults = defaults
        self.kw_defaults = kw_defaults
        _set_parent_list(args, self)
        _set_parent_list(defaults, self)
        _set_parent_list(kw_defaults, self)

    def kind(self) -> t.CInt:
        return ASTKind.Arguments

    def type_name(self) -> str:
        return "Arguments"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "Arguments(args=")
        pos = _dump_list(self.args, buf, size, pos)
        pos = _emit(buf, size, pos, ", vararg=")
        if self.vararg is not None:
            pos = self.vararg.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", kwarg=")
        if self.kwarg is not None:
            pos = self.kwarg.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", defaults=")
        pos = _dump_list(self.defaults, buf, size, pos)
        pos = _emit(buf, size, pos, ", kw_defaults=")
        pos = _dump_list(self.kw_defaults, buf, size, pos)
        pos = _emit(buf, size, pos, ")")
        return pos


# ============================================================
# Arg 节点
# ============================================================

class Arg(AST):
    """Arg(arg: str, annotation: AST)"""
    arg:        str
    annotation: AST | t.CPtr

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                arg: str, annotation: AST | t.CPtr):
        ptr: Arg | t.CPtr = pool.alloc(Arg.__sizeof__())
        if ptr:
            string.memset(ptr, 0, Arg.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 arg: str, annotation: AST | t.CPtr):
        _init_ast(self, pool, 0, 0)
        self.arg = _copy_str(pool, arg)
        self.annotation = annotation

    def kind(self) -> t.CInt:
        return ASTKind.Arg

    def type_name(self) -> str:
        return "Arg"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "Arg(arg='")
        pos = _emit_str(buf, size, pos, self.arg)
        pos = _emit(buf, size, pos, "', annotation=")
        if self.annotation is not None:
            pos = self.annotation.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ")")
        return pos


# ============================================================
# Keyword 节点
# ============================================================

class Keyword(AST):
    """Keyword(arg: str, value: AST)"""
    arg:   str
    value: AST | t.CPtr

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                arg: str, value: AST | t.CPtr):
        ptr: Keyword | t.CPtr = pool.alloc(Keyword.__sizeof__())
        if ptr:
            string.memset(ptr, 0, Keyword.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 arg: str, value: AST | t.CPtr):
        _init_ast(self, pool, 0, 0)
        self.arg = _copy_str(pool, arg)
        self.value = value

    def kind(self) -> t.CInt:
        return ASTKind.Keyword

    def type_name(self) -> str:
        return "Keyword"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "Keyword(arg='")
        pos = _emit_str(buf, size, pos, self.arg)
        pos = _emit(buf, size, pos, "', value=")
        if self.value is not None:
            pos = self.value.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ")")
        return pos


# ============================================================
# Alias 节点
# ============================================================

class Alias(AST):
    """Alias(name: str, asname: str)"""
    name:   str
    asname: str

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                name: str, asname: str):
        ptr: Alias | t.CPtr = pool.alloc(Alias.__sizeof__())
        if ptr:
            string.memset(ptr, 0, Alias.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 name: str, asname: str):
        _init_ast(self, pool, 0, 0)
        self.name = _copy_str(pool, name)
        self.asname = _copy_str(pool, asname)

    def kind(self) -> t.CInt:
        return ASTKind.Alias

    def type_name(self) -> str:
        return "Alias"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "Alias(name='")
        pos = _emit_str(buf, size, pos, self.name)
        pos = _emit(buf, size, pos, "', asname='")
        pos = _emit_str(buf, size, pos, self.asname)
        pos = _emit(buf, size, pos, "')")
        return pos


# ============================================================
# WithItem 节点
# ============================================================

class WithItem(AST):
    """WithItem(context_expr: AST, optional_vars: AST)"""
    context_expr:  AST | t.CPtr
    optional_vars: AST | t.CPtr

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr):
        ptr: WithItem | t.CPtr = pool.alloc(WithItem.__sizeof__())
        if ptr:
            string.memset(ptr, 0, WithItem.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr):
        _init_ast(self, pool, 0, 0)
        self.context_expr = context_expr
        self.optional_vars = optional_vars

    def kind(self) -> t.CInt:
        return ASTKind.WithItem

    def type_name(self) -> str:
        return "WithItem"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "WithItem(context_expr=")
        if self.context_expr is not None:
            pos = self.context_expr.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", optional_vars=")
        if self.optional_vars is not None:
            pos = self.optional_vars.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ")")
        return pos


# ============================================================
# Comprehension 节点
# ============================================================

class Comprehension(AST):
    """Comprehension(target: AST, iter: AST, ifs: list[AST | CPtr], is_async: CInt)"""
    target:   AST | t.CPtr
    iter:     AST | t.CPtr
    ifs:      list[AST | t.CPtr] | t.CPtr
    is_async: t.CInt

    def __new__(self, pool: memhub.MemManager | t.CPtr,
                target: AST | t.CPtr, iter: AST | t.CPtr,
                ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt):
        ptr: Comprehension | t.CPtr = pool.alloc(Comprehension.__sizeof__())
        if ptr:
            string.memset(ptr, 0, Comprehension.__sizeof__())
        return ptr

    def __init__(self, pool: memhub.MemManager | t.CPtr,
                 target: AST | t.CPtr, iter: AST | t.CPtr,
                 ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt):
        _init_ast(self, pool, 0, 0)
        self.target = target
        self.iter = iter
        self.ifs = ifs
        self.is_async = is_async
        _set_parent_list(ifs, self)

    def kind(self) -> t.CInt:
        return ASTKind.Comprehension

    def type_name(self) -> str:
        return "Comprehension"

    def dump(self, buf: bytes, size: t.CSizeT,
             pos: t.CSizeT) -> t.CSizeT:
        pos = _emit(buf, size, pos, "Comprehension(target=")
        if self.target is not None:
            pos = self.target.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", iter=")
        if self.iter is not None:
            pos = self.iter.dump(buf, size, pos)
        else:
            pos = _emit(buf, size, pos, "None")
        pos = _emit(buf, size, pos, ", ifs=")
        pos = _dump_list(self.ifs, buf, size, pos)
        pos = _emit(buf, size, pos, ", is_async=")
        pos = _emit_int(buf, size, pos, t.CInt64T(self.is_async))
        pos = _emit(buf, size, pos, ")")
        return pos
