class ConstructorInsn(PreambleInsn, metaclass=abc.ABCMeta):

    args = []
    argnames = ''

    def preapply(self, preamble):
        self._value = self.construct()
        return self._value

    @abc.abstractmethod
    def construct(self):
        pass

    def copy(self):
        cpy = super().copy()
        cpy._value = self._value
        return cpy

    def serialize(self, holder):
        try:
            name = holder.name_for(self._value)
        except KeyError:
            name = '!!!INVALID'
        return '$%s = %s' % (name,
                            super().serialize(holder)) class CompileTimeInsn(Insn):

    is_compiletime = True

    def declare(self):
        assert False, "Compile time insns don't declare %s" % self

    def activate(self, seq):
        pass

    def apply(self, out, func):
        assert False, "This is a compiletime insn, %s" % self class InsnArg:
class NativeType(InsnArg):
class EntitySelection(NativeType, metaclass=abc.ABCMeta):
class EntityRef(EntitySelection):
class BlockRef(NativeType):
class EntityLocal(NativeType):
class VirtualString(NativeType):
class MutableString(NativeType):
class FunctionLike(NativeType, metaclass=abc.ABCMeta):
class PlayerRef(EntityRef):
class SelectorType(InsnArg):
class Selector(EntitySelection):
class SingleEntitySelector(Selector, EntityRef):
class PosUtilEntity(EntityRef):
class ResolveEntityRef(EntityRef):
class GlobalEntity(EntityRef):
class BlockPos(BlockRef):
class Position(NativeType):
class RelPosVal(NativeType):
class AncPosVal(NativeType):
class CmdFunction(NativeType, metaclass=abc.ABCMeta):
class BlockType(c.Resolvable, NativeType):
class ItemType(c.Resolvable, NativeType):
class TeamRef(NativeType):
class TextColor(InsnArg):
class BossbarRef(NativeType):
class EventRef(NativeType):
class TagEventRef(EventRef):
class AdvEventRef(EventRef):
    def _init_from_parser(cls, value):
    def typename(cls):
    def clone(self):
    def inline_copy(self):
    def write_out(self, out):
    def as_resolve(self):
    def is_only_one(self):
    def is_only_one(self):
    def as_cmdref(self):
    def __init__(self, name, criteria):
    def clone(self):
    def write_out(self, out):
    def __init__(self, val):
    def __str__(self):
    def clone(self):
    def serialize(self):
    def __init__(self, init_val):
    def set(self, val):
    def __str__(self):
    def as_str(self):
    def clone(self):
    def append(self, val):
    def global_name(self):
    def namespace(self):
    def __init__(self, name):
    def as_resolve(self):
    def clone(self):
    def __init__(self, letter, limit):
    def lookup(cls, name):
    def _init_from_parser(cls, name):
    def new(cls, type):
    def __init__(self, type):
    def clone(self):
    def set(self, key, value):
    def set_score_range(self, objective, min, max):
    def set_nbt(self, path, value):
    def is_only_one(self):
    def as_resolve(self):
    def is_only_one(self):
    def as_resolve(self):
    def clone(self):
    def __init__(self, res):
    def as_resolve(self):
    def as_resolve(self):
    def clone(self):
    def __init__(self, x, y, z):
    def as_cmdref(self):
    def clone(self):
    def __init__(self, x, y, z):
        def internal(val):
    def as_blockpos(self):
    def as_worldpos(self):
    def clone(self):
    def __init__(self, val):
    def clone(self):
    def __init__(self, val):
    def clone(self):
    def as_cmd(self, func):
    def __init__(self, block_id):
    def add_prop(self, prop, value):
    def set_nbt(self, nbt):
    def clone(self):
    def resolve(self, scope):
    def __init__(self, item_id):
    def add_nbt(self, nbt):
    def resolve(self, scope):
    def __init__(self, name, display):
    def clone(self):
    def write_out(self, out):
    def __init__(self, name):
    def _init_from_parser(cls, value):
    def __init__(self, name, display):
    def clone(self):
    def write_out(self, out):
def Opt(optype):
    def __init__(self, name, is_tag):
    def __init__(self, name):
    def clone(self):
    def __init__(self, name):
    def add_condition(self, path, value):
    def clone(self):
    _LOOKUP = {}
    ALL_PLAYERS = None
    ALL_ENTITIES = None
    SENDER = None
    NEAREST_PLAYER = None
    RANDOM_PLAYER = None class VarType(InsnArg):

    __LOOKUP = {}

    def __init__(self, name, nbt_key, numeric, nbt_type, default, conversions):
        self.name = name
        self.nbt_path_key = nbt_key
        self.nbt_type = nbt_type
        self.isnumeric = numeric
        self.default_val = default
        self.conversions = conversions
        self.__LOOKUP[name] = self

    def __str__(self):
        return 'VarType(%s)' % (self.name)

    def to_int(self, val):
        return self.conversions.to_int(val)

    @property
    def scale(self):
        return self.conversions.scale

    @classmethod
    def _init_from_parser(cls, value):
        return cls.__LOOKUP[value]

    # pickle the singleton
    def __reduce__(self):
        return 'VarType.%s' % self.name

    i32 = None
    nbt = None
    # https://en.wikipedia.org/wiki/Q_%28number_format%29
    q10 = None class LocalVariable(ProxyVariable):

    def write_out(self, out):
        ref = self._direct_ref()
        if ref is not None:
            name = ref.objective.objective
            out.write_objective(name, None) class ParameterVariable(ProxyVariable):

    def __init__(self, type, passtype):
        byref = passtype == 'byref'
        # Always written to - stop this getting eliminated
        super().__init__(type, always_write=True, always_read=byref)
        self.passtype = passtype class Variable(NativeType, metaclass=abc.ABCMeta):

    def __init__(self, vartype):
        assert isinstance(vartype, VarType)
        self.type = vartype
        self.__use_w = 0
        self.__use_r = 0

    @property
    @abc.abstractmethod
    def namespace(self):
        pass

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self.type)

    def open_for_write(self, out, read=False):
        return OpenVar(self, out, read=read, write=True)

    def open_for_read(self, out):
        return OpenVar(self, out)

    def usage_read(self):
        self.__use_r += 1

    def usage_write(self):
        self.__use_w += 1

    def reset_usage(self):
        self.__use_w = 0
        self.__use_r = 0

    @property
    def is_read_from(self):
        return self.__use_r > 0

    @property
    def is_written_to(self):
        return self.__use_w > 0

    @property
    def is_referenced(self):
        return self.is_read_from or self.is_written_to

    @property
    def is_entity_local(self):
        # Bit of a hack
        return isinstance(self, EntityLocalVariable)

    @abc.abstractmethod
    def read(self):
        """
        Returns a command that sets the "result" to this variable's
        value. The value is left unscaled as an int.
        """
        pass

    def clone_to(self, other, out):
        assert other.type == self.type, "TODO"
        ref = other._direct_ref()
        # Need to adjust for scaling
        if ref is not None:
            self._write_to_reference(ref, out)
        else:
            other._store_from_cmd(self.read(), out)

    @abc.abstractmethod
    def set_const_val(self, value, out):
        pass

    def to_int(self, value):
        return self.type.to_int(value)

    def scale_down(self, ref, out):
        if self.type.scale != 1:
            # TODO extract to constant reference
            scaleparam = out.allocate_temp()
            out.write(c.SetConst(scaleparam, self.type.scale))
            out.write(c.OpDiv(ref, scaleparam))
            out.free_temp(scaleparam)

    def scale_other_to_this(self, other, otherref, out):
        factor = self.type.scale / other.type.scale
        op = c.OpMul
        if factor < 1:
            factor = 1 / factor
            op = c.OpDiv
        factor = int(factor)
        if factor == 1:
            return otherref, False
        scaled = out.allocate_temp()
        out.write(c.OpAssign(scaled, otherref))
        # TODO extract to constant reference
        scaleparam = out.allocate_temp()
        out.write(c.SetConst(scaleparam, factor))
        out.write(op(scaled, scaleparam))
        out.free_temp(scaleparam)
        return scaled, True

    def push_to_stack(self, out):
        self.as_nbt_variable(out).push_to_stack(out)

    def as_nbt_variable(self, out):
        # Create a virtual variable to store the value as NBT
        var = WorkingNbtVariable(self.type, self.namespace)
        self.clone_to(var, out)
        return var

    def realign_frame(self, shift):
        pass

    ## DIRECT ACCESS

    def _direct_ref(self):
        return None

    def _direct_nbt(self):
        return None

    ## INTERNAL ONLY

    def _write_to_reference(self, ref, out):
        out.write(c.ExecuteChain()
                  .store('result')
                  .score(ref)
                  .run(self.read()))

    def _read_from_reference(self, ref, out):
        self._store_from_cmd(c.GetValue(ref), out)

    @abc.abstractmethod
    def _store_from_cmd(self, cmd, out):
        """
        Store command "result" value into this variable.
        Result is not scaled therefore must be scaled as appropriate.
        """
        pass class ReturnVariable(ProxyVariable):

    def __init__(self, type):
        # Always read from - stop this from getting eliminated
        super().__init__(type, always_read=True) class EntityLocalAccess(EntityLocalVariable, ScoreStorableVariable):

    def __init__(self, local, target):
        super().__init__(VarType.i32, c.ScoreRef(target.as_resolve(),
                                               local.obj_ref)) class GlobalVariable(ProxyVariable):

    def __init__(self, type, is_extern, namespace):
        # If it's extern, it's always read and written to
        super().__init__(type, is_extern, is_extern, namespace)
        self.is_extern = is_extern

    def write_out(self, out):
        ref = self._direct_ref()
        if ref is not None:
            name = ref.objective.objective
            out.write_objective(name, None)
        nbt = self._direct_nbt()
        if nbt is not None:
            path, storage = nbt
            initval = self.type.nbt_type.new(self.type.default_val).serialize()
            out.write_global_nbt(storage, path, initval) class CompilerVariable(Variable):

    def __init__(self, type):
        super().__init__(type)
        self.value = None

    def clone(self):
        v = CompilerVariable(self.type)
        v.value = self.value
        return v

    @property
    def namespace(self):
        assert False

    def _store_from_cmd(self, cmd, out):
        assert False, "Attempted store %s into %s" % (cmd, self)

    def read(self):
        assert False

    def set_const_val(self, val):
        assert False

    def get_value(self):
        return self.value

    def set_value(self, value):
        if self.type == VarType.i32:
            value = int(value)
        elif self.type == VarType.q10:
            value = float(value)
        self.value = value class NBTBase(HolderHolder, Resolvable, NativeType):

    def declare(self):
        pass class NBTCompound(RecurseMixin):

    type = NBTType.compound

    def __init__(self, items=[]):
        super().__init__()
        self.items = OrderedDict(items)
        for v in items:
            self.hold(v)

    def set(self, name, value):
        assert isinstance(name, str)
        assert isinstance(value, NBTBase)
        self.items[name] = value
        self.hold(value)

    def declare(self):
        for item in self.items.values():
            item.declare()

    def clone(self):
        return NBTCompound((k, v.clone()) for k, v in self.items.items())

    def recurse(self, apply):
        # TODO quote keys
        return '{%s}' % (','.join('%s:%s' % (k, apply(v)) for k, v\
                                             in self.items.items())) class TextObject(HolderHolder, NativeType):

    def __init__(self):
        HolderHolder.__init__(self)
        self.style = {}
        self.children = []
        self._click_func = None

    def append(self, value):
        if isinstance(value, CompilerVariable):
            value = value.get_value()
        assert value is not None
        if isinstance(value, Variable):
            value = self.hold(value, (Variable, int))
        if isinstance(value, TextObject):
            value = self.hold(value.clone())
        self.children.append(value)

    def set_style(self, prop, value):
        self.style[prop] = value

    def set_click_func(self, action, func):
        if isinstance(func, FunctionLike):
            func = self.hold(func, FunctionLike)
        self._click_func = (action, func)

    def clone(self):
        copy = TextObject()
        copy.style.update(self.style)
        for c in self.children:
            if type(c) == int:
                copy.children.append(c)
            else:
                copy.children.append(copy.hold(c.clone()))
        if self._click_func:
            action, func = self._click_func
            copy._click_func = copy.hold(func.clone()), action
        return copy

    def declare(self):
        for child in self.children:
            if isinstance(child, TextObject):
                child.declare()
            elif isinstance(child, Holder) and isinstance(child.val, Variable):
                child.val.usage_read()
        if self._click_func is not None:
            _, func = self._click_func
            if isinstance(func.val, FunctionLike):
                func.val.usage()

    def to_component(self, out, func):
        opener = MultiOpen()
        comp = self._to_component(out, func, opener)
        opener.close()
        return comp

    def _get_style(self, out, out_func):
        style = dict(self.style)
        if self._click_func is not None:
            action, func = self._click_func
            if isinstance(func.val, FunctionLike):
                cmd = c.Function(func.val.global_name)
            else:
                cmd = func.val.as_cmd(out_func)
            style['clickEvent'] = c.TextClickAction(action, cmd)
        return style

    def _to_component(self, out, func, opener):
        return c.TextComponentHolder(self._get_style(out, func), [
            self._convert_component(child, out, func, opener) \
                for child in self.children
        ])

    def _convert_component(self, child, out, func, opener):
        if isinstance(child, Holder):
            child = child.val
        if isinstance(child, TextObject):
            return child._to_component(out, func, opener)
        if isinstance(child, (VirtualString, int)):
            return c.TextStringComponent(str(child))
        if isinstance(child, Variable):
            # optimize for direct nbt or ref
            direct_nbt = child._direct_nbt()
            if direct_nbt:
                path, storage = direct_nbt
                return c.TextNBTComponent(storage, path)
            direct_ref = child._direct_ref()
            # TODO possibly scale if not int?
            if direct_ref:
                return c.TextScoreComponent(direct_ref)
            with opener.context(child.open_for_read(out)) as ref:
                return c.TextScoreComponent(ref)
        assert False, child
from ._core import ConstructorInsn, CompileTimeInsn
from ..core_types import (SelectorType,
                          Selector,
                          VirtualString,
                          MutableString,
                          EntityLocal,
                          Opt,
                          PosType,
                          BlockType,
                          ItemType,
                          CmdFunction,
                          EntitySelection,
                          BlockPos,
                          Position,
                          RelPosVal,
                          AncPosVal,
                          BossbarRef,
                          TeamRef,
                          PlayerRef,
                          EntityRef,
                          )
from ..variables import (VarType, LocalVariable, ParameterVariable, Variable,
                         ReturnVariable, EntityLocalAccess, GlobalVariable,
                         CompilerVariable)
from ..nbt import NBTBase, NBTCompound
from .text import TextObject
import commands as c
    rettype = ItemType
    insn_name = 'item'

    def construct(self):
        return ItemType(str(self.item_id))

class ItemName(ConstructorInsn):
    """Constructs a string containing the given item's name."""

    args = [ItemType]
    argdocs = ["Item to get the name of"]
    argnames = 'item'
    rettype = VirtualString
    insn_name = 'item_name'

    def construct(self):
        return VirtualString(self.item.item_id)

class AddItemPropInsn(CompileTimeInsn):
    """Adds an NBT value to the item properties."""

    args = [ItemType, NBTCompound]
    argnames = 'item nbtprop'
    argdocs = ["Item", "NBT value"]
    insn_name = 'add_item_prop'

    def run(self, ev):
        self.item.add_nbt(self.nbtprop)

class CreateEntityLocalAccess(ConstructorInsn):
    """Creates a variable whose value depends on the objective and target
    entities."""

    args = [EntityLocal, EntitySelection]
    argnames = 'local target'
    argdocs = ["Scoreboard objective", "Target entities"]
    rettype = Variable
    insn_name = 'entity_local_access'

    def construct(self):
        return EntityLocalAccess(self.local, self.target)

class CreatePlayerRef(ConstructorInsn):
    """Creates a reference to a player name."""

    args = [VirtualString]
    argnames = 'name'
    argdocs = ["Player name"]
    rettype = EntityRef
    insn_name = 'player_ref'

    def construct(self):
        return PlayerRef(str(self.name))

class RawCommand(CmdFunction):

    def __init__(self, cmd):
        self.cmd = cmd

    def as_cmd(self, func):
        return c.Cmd(self.cmd)

class CreateCommand(ConstructorInsn):
    """Creates a command variable out of a raw command string."""

    args = [VirtualString]
    argnames = 'cmd'
    argdocs = ["Raw command string"]
    rettype = CmdFunction
    insn_name = 'command'

    def construct(self):
        return RawCommand(str(self.cmd))

class CreateTeamInsn(ConstructorInsn):
    """Creates a team reference."""

    args = [str, Opt(TextObject)]
    argnames = 'name display'
    argdocs = ["Team name", "Optional display text"]
    rettype = TeamRef
    insn_name = 'team'
    top_preamble_only = True

    def construct(self):
        return TeamRef(self.name, self.display)

class CreateBossbarInsn(ConstructorInsn):
    """Creates a bossbar reference."""

    args = [str, TextObject]
    argnames = 'name display'
    argdocs = ["Bossbar name", "Display text"]
    rettype = BossbarRef
    insn_name = 'bossbar'
    top_preamble_only = True

    def construct(self):
        return BossbarRef(self.name)

class DefineVariable(ConstructorInsn):
    """Creates a local variable of the given variable type."""

    args = [VarType]
    argnames = 'type'
    argdocs = ["Variable type"]
    rettype = Variable

    func_preamble_only = True
    insn_name = 'define'

    def construct(self):
        return LocalVariable(self.type)

class CompileOnlyVariable(ConstructorInsn):
    """Creates a local variable of the given variable type."""

    args = [VarType]
    argnames = 'type'
    argdocs = ["Variable type"]

    rettype = Variable