def process_string_escapes(token):
def process_int_constant(token):
def process_dec_constant(token):
    def _lexconf_deserialize(self):
    def lark_parser():
    def lark_parser():
    def __init__(self, compiler):
    def parse_program(self, text):
    def is_type_name(self, name):
    def _transform_tree(self, tree):
class Parser:
class Transformer_WithPre(Transformer): class StructuredType(CBLType):

    def __init__(self):
        super().__init__()
        self.__var_members = {}
        self.__vars_allowed = True
        self._is_nbt = False

    @property
    def meta_type_type(self):
        return StructTypeMeta

    def extend_from(self, parent):
        super().extend_from(parent)
        if isinstance(parent, StructuredType):
            self.__var_members.update(parent.get_var_members())

    @property
    def ir_type(self):
        if self._is_nbt:
            return i.VarType.nbt
        raise TypeError('%s does not have an IR type' % self)

    def ir_types(self):
        if self._is_nbt:
            return (self.ir_type,)
        types = []
        for m_type in self.__var_members.values():
            types.extend(m_type.ir_types())
        return types

    def as_variable(self, instance):
        return instance.as_variable(self.typename)

    def as_variables(self, instance):
        return instance.as_variables()

    def instance_member(self, name):
        m = super().instance_member(name)
        if m is None:
            m = self.__var_members.get(name)
        return m

    def get_var_members(self):
        return dict(self.__var_members)

    def effective_var_size(self):
        if self._is_nbt:
            return 1
        return sum(t.effective_var_size() for t in self.__var_members.values())

    def add_variable_member(self, name, type):
        self.__can_extend = False
        if self.instance_member(name):
            raise KeyError('%s is already defined in type %s' % (name,
                                                                 self.name))
        if not self.__vars_allowed:
            raise RuntimeError('Cannot add more variables. Tried adding %s' % \
                               name)
        self.__var_members[name] = type

    def allocate(self, compiler, namehint):
        assert not self.incomplete, "Incomplete type %s" % self.typename

        if self._is_nbt:
            this = compiler.create_var(namehint, i.VarType.nbt)

            def create_sub_var(subname, var_type):
                path = i.VirtualString('.' + subname)
                insn = i.NBTSubPath(this, path, var_type)
                return compiler.define(namehint + '_' + subname, insn)
        else:
            this = None

            orig_create_var = compiler.create_var
            def create_sub_var(subname, var_type):
                return orig_create_var(namehint + '_' + subname, var_type)

        with compiler.set_create_var(create_sub_var):
            return StructTypeInstance(compiler, this, self.__var_members,
                                      self.get_func_members(),
                                      self.get_func_properties())

    def add_function_member(self, compiler, name, ret_type, params, inline,
                            is_async):
        self.__complete_vars()
        return super().add_function_member(compiler, name, ret_type, params,
                                           inline, is_async)

    def add_operator_member(self, compiler, op, ret_type, params, inline):
        self.__complete_vars()
        return super().add_operator_member(compiler, op, ret_type, params,
                                           inline)

    def add_constructor(self, compiler, params, inline):
        self.__complete_vars()
        return super().add_constructor(compiler, params, inline)
        
    def __complete_vars(self):
        if not self.__vars_allowed:
            return
        self.__vars_allowed = False
        self.__can_extend = False
        # Initially we are not NBT wrapped
        size = self.effective_var_size()
        # Become NBT wrapped if size exceeds 3 variables
        if size > 3:
            self._is_nbt = True

    def _copy_impl(self, compiler, this, other):
        thisobj = this.value
        if self._is_nbt:
            compiler.add_insn(i.SetScore(thisobj.as_variable(self.typename),
                                         other.value.as_variable(other.type.typename)))
        else:
            # Pair each var member
            for var in self.__var_members.keys():
                lvar = thisobj.get_member(compiler, var)
                rvar = other.value.get_member(compiler, var)
                lvar.type.dispatch_operator(compiler, '=', lvar, rvar)
        return other

    def _default_ctor(self, compiler, container, args):
        ret = super()._default_ctor(compiler, container, args)
        self.__construct_members(compiler, container.this, {})
        return ret

    def complete_type(self, compiler):
        self.__complete_vars()
        super().complete_type(compiler)

    def do_construction(self, compiler, thisobj, member_inits):
        if self.parent_type:
            pname = self.parent_type.typename
            pargs = ()
            # Steal parent arguments if exists from member_inits
            if pname in member_inits:
                pargs = member_inits[pname]
                del member_inits[pname]
            self._construct_parent(compiler, thisobj, pargs)
        self.__construct_members(compiler, thisobj, member_inits)

    def __construct_members(self, compiler, thisobj, member_inits):
        own_members = self.__var_members
        if isinstance(self.parent_type, StructuredType):
            p_members = self.parent_type.get_var_members().keys()
            own_members = { name: m for name, m in self.__var_members.items() \
                            if name not in p_members }
        for name in member_inits.keys():
            assert name in own_members, (self, name)

        for varname in own_members.keys():
            member = thisobj.get_member(compiler, varname)
            args = member_inits.get(varname, ())
            member.type.run_constructor(compiler, member, args)

    def coerce_to(self, compiler, container, type):
        super_did_coerce = super().coerce_to(compiler, container, type)
        if super_did_coerce:
            return super_did_coerce
        if self.parent_type is not None:
            if type == self.parent_type and isinstance(type, StructuredType):
                # Can re-use the nbt wrapper. Since extend is append-only
                # we know self._is_nbt == True
                if type._is_nbt:
                    return container
                # Create a shadow copy using the subset of our members
                # found in the parent type
                val = StructTypeInstanceShadow(container.value, compiler, None,
                                               type.get_var_members(),
                                               type.get_func_members(),
                                               type.get_func_properties())
                return Temporary(type, val)
            # Walk the hierarchy to see if we can coerce from a parent type
            return self.parent_type.coerce_to(compiler, container, type)
        return None def as_var(container):
    return container.type.as_variable(container.value) class NativeType:

    def __repr__(self):
        return self.__class__.__name__

    def instantiate(self, compiler, args):
        assert not args, "%s does not take arguments" % self
        return self

    @property
    def typename(self):
        return self.__typename

    @typename.setter
    def typename(self, name):
        self.__typename = name
        meta = self.metatype
        if meta is not None:
            meta.typename = name + '--meta'

    def allocate(self, compiler, namehint):
        assert False, "%s is not allocatable" % self.typename

    @property
    def metatype(self):
        return None

    @property
    def ir_type(self):
        raise TypeError('%s does not have an IR type' % self)

    def get_property(self, compiler, container, prop):
        raise TypeError('Unknown property %s on %s' % (prop, self))

    def dispatch_operator(self, compiler, op, left, right=None):
        if op in ASSIGN_OP:
            # Remove '=' from op
            return self._assign_op(compiler, op[:-1], left, right)
        raise TypeError('Invalid operation "%s" on %s' % (op, self))

    def _assign_op(self, compiler, op, left, right):
        tmp = self.dispatch_operator(compiler, op, left, right)
        return self.dispatch_operator(compiler, '=', left, tmp)

    def ir_types(self):
        return (self.ir_type,)

    def as_variables(self, instance):
        return (self.as_variable(instance),)

    def as_variable(self, instance):
        raise TypeError('%s cannot be converted to a variable' % self)

    def as_ir_variable(self, instance):
        return self.as_variable(instance)

    # Convert a sequence of variables (e.g. from as_variables()) back into
    # Our high-level value
    def from_variables(self, compiler, vars):
        it = iter(vars)

        # The default implementation is to call allocate but provide variables
        # via the pool of yet-to-consume variables
        def shift_var(subname, var_type):
            var = next(it)
            # verify IR type is consistent
            assert var.type == var_type
            return var

        with compiler.set_create_var(shift_var):
            value = self.allocate(compiler, 'restored')
            # Check we consumed all the variables
            assert all(False for _ in it)
            return value

    def effective_var_size(self):
        if self.ir_type:
            return 1
        assert False

    def run_constructor(self, compiler, container, arguments):
        assert not arguments, (self, arguments)

    def do_construction(self, compiler, instance, member_inits):
        assert not member_inits

    def coerce_to(self, compiler, container, type):
        if type == self:
            return container
        return None class MetaType(NativeType):

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

    def call_constructor(self, compiler, container, args):
        the_type = container.type.the_type
        obj = the_type.allocate(compiler, safe_typename(the_type) + '_inst')
        tmp = Temporary(the_type, obj)
        the_type.run_constructor(compiler, tmp, args)
        return tmp class IRType(NativeType):

    @property
    def metatype(self):
        return MetaType(self)

    def allocate(self, compiler, namehint):
        return IRTypeInstance(namehint)

    def effective_var_size(self):
        # We allow using IRType in a struct as long as the usage is only
        # within macros
        return 0

    def as_ir_variable(self, instance):
        assert instance.var is not None, "Cannot convert %s to variable" % (
            instance._name)
        return instance.var

    def run_constructor(self, compiler, container, args):
        assert len(args) >= 1, (self, args)
        s = args[0]
        if s.type == compiler.type('string'):
            if isinstance(s, LiteralString):
                v = s.value
            else:
                v = s.type.as_ir_variable(s.value)
                assert isinstance(v, i.VirtualString)
                v = str(v)
            moreargs = [a.type.as_ir_variable(a.value) for a in args[1:]]
            container.value.ctor(compiler, v, moreargs)
        else:
            assert len(args) == 1
            assert s.type is self
            container.value.var = s.type.as_ir_variable(s.value)

    def dispatch_operator(self, compiler, op, left, right=None):
        if op == '=':
            assert right.type is self, right
            assert right.value.var is not None
            left.value.var = right.value.var
            return left
        return super().dispatch_operator(compiler, op, left, right) class StringType(NativeType):

    def allocate(self, compiler, namehint):
        return StringInstance()

    def effective_var_size(self):
        # We allow using StringType in a struct as long as the usage is only
        # within macros
        return 0

    def _copy_impl(self, compiler, this, other):
        return other

    def as_ir_variable(self, instance):
        # e.g. LiteralString
        if type(instance) == str:
            return i.VirtualString(instance)
        assert instance._str is not None, "String has no value"
        return instance._str

    def run_constructor(self, compiler, container, args):
        if len(args) != 1:
            return super().run_constructor(compiler, container, args)
        self.__copy(container, args[0])

    def dispatch_operator(self, compiler, op, left, right=None):
        if op == '=':
            self.__copy(left, right)
            return left
        if op == '+':
            return self.__concat(compiler, left, right)
        return super().dispatch_operator(compiler, op, left, right)

    def _as_string(self, container):
        if isinstance(container, LiteralString):
            return i.VirtualString(container.value)
        if isinstance(container.type, IRType):
            # Allow strings wrapped in _IRType
            v = container.type.as_ir_variable(container.value)
            if isinstance(v, (i.VirtualString, i.MutableString)):
                return v
            assert False, container
        else:
            assert container.type is self, container
            assert isinstance(container.value, StringInstance), container
            assert container.value._str is not None, container
            return container.value._str

    def __copy(self, this, other):
        this.value._str = self._as_string(other)

    def __concat(self, compiler, s1, s2):
        concat = compiler.define('concat', i.CreateString(None))
        compiler.add_insn(i.StringConcat(concat, self._as_string(s1)))
        compiler.add_insn(i.StringConcat(concat, self._as_string(s2)))
        return Temporary(self, StringInstance(concat)) class FunctionDispatchType(NativeType, Invokable):

    def match_arguments(self, compiler, container, args):
        # TODO possibly refactor
        has_this = isinstance(container, InstanceSymbol)
        if container.value._static:
            assert not has_this
            thiscont = None
        else:
            assert has_this
            thiscont = Temporary(container.value._type, container.this)
        return container.value.satisfy(compiler, thiscont, args) 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 InstanceFunctionType(FunctionType):

    def __init__(self, inst_type, ret_type, params, inline, is_async, static):
        if not static:
            new_params = [Parameter(inst_type, 'this', True)]
            new_params.extend(params)
        else:
            new_params = params
        super().__init__(ret_type, new_params, inline, is_async)
        self.inst_type = inst_type

    def allocate(self, compiler, namehint):
        return super().allocate(compiler, self.inst_type.typename + '/' + namehint) class MacroType(FunctionType, Invokable):

    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)
                return ret

    def __expand_compiletime(self, compiler, args):
        with compiler.compiletime():
            return self.__expand_macro(compiler, args, True) class VoidType(NativeType):

    def ir_types(self):
        return tuple() class BoolType(LogOperatorMixin, IntrinsicOperatorType):

    @property
    def ir_type(self):
        return i.VarType.i32

    def as_variable(self, instance):
        return instance

    def coerce_to(self, compiler, val, type):
        if type == compiler.type('int'):
            v = type.allocate(compiler, 'bcast')
            compiler.add_insn(i.SetScore(v, val.value))
            return Temporary(type, v)
        return super().coerce_to(compiler, val, type) class IntType(IntegerOperators, IntrinsicOperatorType):

    @property
    def ir_type(self):
        return i.VarType.i32

    def as_variable(self, instance):
        return instance

    def operator_unary_neg(self, compiler, instance):
        if isinstance(instance, LiteralInt):
            return LiteralInt(self, -instance.value)
        return super().operator_unary_neg(compiler, instance)

    def coerce_to(self, compiler, val, type):
        if type == compiler.type('decimal'):
            v = type.allocate(compiler, 'icast')
            compiler.add_insn(i.SetScore(v, val.value))
            return Temporary(type, v)
        return super().coerce_to(compiler, val, type) class DecimalType(NumericalOperators, IntrinsicOperatorType):

    @property
    def ir_type(self):
        return i.VarType.q10

    def as_variable(self, instance):
        return instance

    def operator_unary_neg(self, compiler, instance):
        if isinstance(instance, LiteralDec):
            return LiteralDec(self, -instance.value)
        return super().operator_unary_neg(compiler, instance)

    def coerce_to(self, compiler, val, type):
        if type == compiler.type('int'):
            v = type.allocate(compiler, 'dcast')
            compiler.add_insn(i.SetScore(v, val.value))
            return Temporary(type, v)
        return super().coerce_to(compiler, val, type) class NBTType(CBLType):

    @property
    def ir_type(self):
        return i.VarType.nbt

    def as_variable(self, instance):
        return instance.var

    def allocate(self, compiler, namehint):
        return NBTInstance(compiler.create_var(namehint, self.ir_type),
                           self.get_func_members(),
                           self.get_func_properties())

    def _copy_impl(self, compiler, this, other):
        if isinstance(this, DelegatedWrite):
            return this.write(compiler, other)
        compiler.add_insn(i.NBTAssign(as_var(this), as_var(other)))
        return other class TagEventType(_EventType):

    inst = TagEventInstance

    def complete_type(self, compiler):
        void = compiler.type('void')
        type, func = self.add_function_member(compiler, 'fire', void, (), True,
                                              False)
        func.set_as_intrinsic(IntrinsicCallable(self.__fire))
        super().complete_type(compiler)

    def __fire(self, compiler, container, args):
        event = args[0].value
        assert event.var is not None
        compiler.add_insn(i.FireEventInsn(event.var))
        return Temporary(compiler.type('void'), None) class AdvancementEventType(_EventType):

    inst = AdvEventInstance class MaybeType(NativeType):

    def __init__(self):
        self.type_map = {}

    def instantiate(self, compiler, args):
        assert len(args) == 1
        real_t = args[0]
        if real_t not in self.type_map:
            t = MaybeWrappedType(real_t)
            t.typename = self.typename + '<%s>' % real_t.typename
            t.complete_type(compiler)
            self.type_map[real_t] = t
        return self.type_map[real_t] class TemplatedType(NativeType):

    def __init__(self, params, parent, decls):
        assert len(params) > 0
        self._parent = parent
        self._type_params = params
        self._decls = decls
        self._late_decls = []
        self._memo_types = {}
        self._memo_type_symbols = {}
        self.__meta = MetaTemplateType(self)

    @property
    def metatype(self):
        return self.__meta

    def add_late_decl(self, compiler, decl):
        self._late_decls.append(decl)
        # Process any already constructed types
        for args in self._memo_types.keys():
            with self.with_args(compiler, args):
                compiler.process_top_decl(compiler.transform(decl))

    def instantiate(self, compiler, args):
        assert len(args) == len(self._type_params)
        args = tuple(args)
        if args not in self._memo_types:
            t = StructuredType()
            # memoize the type early so that the type definition can
            # refer back to itself
            self._memo_types[args] = t
            self.construct(compiler, t, args)
        return self._memo_types[args]

    def construct(self, compiler, t, args):
        targs = ', '.join(a.typename for a in args)
        sym = compiler.add_type('%s<%s>' % (self.typename, targs), t)
        self._memo_type_symbols[t] = sym
        with self.with_args(compiler, args):
            compiler.define_type(t, self._parent, self._decls)
            for decl in self._late_decls:
                compiler.process_top_decl(compiler.transform(decl))

    @contextlib.contextmanager
    def with_args(self, compiler, args):
        # We introduce a new type scope where the generic name (e.g. "T")
        # exists as an alias to the concrete type in args
        with compiler.types.typescope():
            # Also create a new variable scope to store the metatype
            with compiler.scope:
                for atype, aname in zip(args, self._type_params):
                    compiler.alias_type(aname, atype)
                yield class Types:

    def __init__(self):
        self.tscope = TypeScope()

    def add(self, type_name, type_instance):
        self.tscope.add(type_name, type_instance)

    def lookup(self, type_name):
        return self.tscope.lookup(type_name)

    def name_for(self, type):
        return self.tscope.name_for(type)

    def alias(self, type, alias_name):
        self.tscope.alias(type, alias_name)

    @contextlib.contextmanager
    def typescope(self, restored=None):
        orig = self.tscope
        base = self.tscope if restored is None else restored
        self.tscope = TypeScope(base)
        yield
        self.tscope = orig

    def snapshot(self):
        return self.tscope class ArraySupport:

    index_type = i.VarType.i32

    def __init__(self, compiler):
        self.compiler = compiler
        self.max_size = 0
        self.getter = None
        self.setter = None

    def allocate(self, size):
        self.max_size = max(self.max_size, size)

    def finish(self):
        if self.getter:
            self.compiler.pragma('array_support_getter', self.max_size)
        if self.setter:
            self.compiler.pragma('array_support_setter', self.max_size)

    def get(self, array, index):
        self.lazy_load_get()
        args = (array, index)
        # TODO type
        val = self.compiler.create_var('arrval', i.VarType.i32)
        ret_args = (val,)
        self.compiler.add_insn(i.Invoke(self.getter, args, ret_args))
        return val

    def set(self, array, index, value):
        self.lazy_load_set()
        args = (array, index, value)
        self.compiler.add_insn(i.Invoke(self.setter, args, None))

    def lazy_load_get(self):
        if self.getter is None:
            # TODO customize return type
            self.getter = self.compiler.extern_function('_internal/array_get', (
                (i.VarType.nbt, 'byval'), (self.index_type, 'byval')), (i.VarType.i32,))

    def lazy_load_set(self):
        if self.setter is None:
            # TODO customise value type
            self.setter = self.compiler.extern_function('_internal/array_set', (
                (i.VarType.nbt, 'byref'), (self.index_type, 'byval'),
                (i.VarType.i32, 'byval')), None)

    @classmethod
    def gen_getter(cls, top, size):
        func = top.define_function('_internal/array_get')
        arrparam = func.preamble.define(i.ParameterInsn(i.VarType.nbt, 'byval'))
        indexparam = func.preamble.define(i.ParameterInsn(cls.index_type, 'byval'))
        retvar = func.preamble.define(i.ReturnVarInsn(i.VarType.i32))
        cls._gen_for(size, func, 'get', indexparam, cls._gen_getter, arrparam, retvar)

    @classmethod
    def gen_setter(cls, top, size):
        func = top.define_function('_internal/array_set')
        arrparam = func.preamble.define(i.ParameterInsn(i.VarType.nbt, 'byref'))
        indexparam = func.preamble.define(i.ParameterInsn(cls.index_type, 'byval'))
        valparam = func.preamble.define(i.ParameterInsn(i.VarType.i32, 'byval'))
        cls._gen_for(size, func, 'set', indexparam, cls._gen_setter, arrparam, valparam)

    @staticmethod
    def _gen_getter(block, indexvar, indexval, arr, retvar):
        path = i.VirtualString('[%d]' % indexval)
        path_var = block._func.preamble.define(i.NBTSubPath(arr, path, retvar.type))
        block.add(i.SetScore(retvar, path_var))

    @staticmethod
    def _gen_setter(block, indexvar, indexval, arr, value):
        path = i.VirtualString('[%d]' % indexval)
        path_var = block._func.preamble.define(i.NBTSubPath(arr, path, value.type))
        block.add(i.SetScore(path_var, value))

    @staticmethod
    def _gen_for(size, func, prefix, indexparam, gen_callback, *cb_args):
        entry = func.create_block('entry')
        # Copy to local variable due to register allocation speedup
        index = func.preamble.define(i.DefineVariable(indexparam.type))
        entry.add(i.SetScore(index, indexparam))

        def pair_name(pair):
            return '%s_%d_%d' % (prefix, pair.min, pair.max)

        def branch(func, index, pair):
            return i.RangeBr(index, pair.min, pair.max,
                           func.get_or_create_block(pair_name(pair)), None)

        def callback(pair):
            block = func.get_or_create_block(pair_name(pair))
            block.defined = True
            if pair.left:
                block.add(branch(func, index, pair.left))
            if pair.right:
                block.add(branch(func, index, pair.right))
            if pair.min == pair.max:
                gen_callback(block, index, pair.min, *cb_args)
        root = generate_bin_tree(size, callback)
        entry.add(i.Call(func.get_or_create_block(pair_name(root))))
        entry.add(i.Return())
        func.end() class ArrayType(NativeType):

    def __init__(self, elem_type, size):
        super().__init__()
        assert size > 0, "Size must be > 0, is %d" % size
        assert elem_type.typename == 'int', "TODO"
        self.elem_type = elem_type
        self.typename = elem_type.typename + '[]'
        self.nbt_type = i.NBTType.int # TODO
        self.size = size

    def __repr__(self):
        return 'ArrayType(%s[%d])' % (self.elem_type.typename, self.size)

    @property
    def ir_type(self):
        return i.VarType.nbt

    def allocate(self, compiler, namehint):
        return compiler.create_var(namehint, self.ir_type)

    def as_variable(self, instance):
        return instance

    def run_constructor(self, compiler, instance, arguments):
        assert len(arguments) <= self.size
        compiler.array_support.allocate(self.size)
        var = instance.value
        array = compiler.insn_def(i.CreateNBTList(self.nbt_type))
        init_val = self._init_val(compiler)
        with compiler.compiletime():
            for _ in range(self.size):
                compiler.add_insn(i.NBTListAppend(array, init_val))
        compiler.add_insn(i.NBTAssign(var, array))
        for n, arg in enumerate(arguments):
            compiler.array_support.set(var, n, arg.type.as_variable(arg.value))

    def _init_val(self, compiler):
        # TODO non-int defaults
        return compiler.insn_def(i.CreateNBTValue(self.nbt_type, 0))

    def dispatch_operator(self, compiler, op, left, right=None):
        if op == '[]':
            return ArrayElementHolder(compiler, self, left, right)
        return super().dispatch_operator(compiler, op, left, right) class EntitySupport:

    def __init__(self, compiler):
        self.compiler = compiler
        self._get_or_create = None
        self._current_sender = None

    @staticmethod
    def objective():
        return i.DefineObjective(i.VirtualString('__uid'), None)

    def get_pointer(self, container):
        assert container.type == self.compiler.type('Entity')
        return container.value.get_member(self.compiler, '_ptr').value

    def assign_pointer_to_sender(self, ptr):
        assert isinstance(ptr, EntityPointer)
        if self._get_or_create is None:
            self._get_or_create = self.compiler.extern_function(
                '_internal/entity_ptr', None, (i.VarType.i32,))
            self.uid_obj = self.compiler.global_def('__uid', self.objective())
        retvars = (ptr.variable,)
        self.compiler.add_insn(i.Invoke(self._get_or_create, None, retvars))

    def construct_sender(self):
        _ptr_type = self.compiler.type('__EntityPtr')
        val = _ptr_type.allocate(self.compiler, 'sender')
        self.assign_pointer_to_sender(val)
        return Temporary(_ptr_type, val)

    def constructor(self, this, ptr):
        this.get_member(self.compiler, '_ptr').value.ctor_from(ptr.value)
        return Temporary(self.compiler.type('void'), None)

    @contextlib.contextmanager
    def set_sender(self, ptr):
        assert isinstance(ptr, EntityPointer)
        old_sender = self._current_sender
        self._current_sender = ptr.variable
        yield
        self._current_sender = old_sender

    def as_entity(self, ptr):
        block = self.compiler.create_block('as_entity')
        block.set_is_function()
        sender = self.compiler.insn_def(i.CreateSelector(i.SelectorType.SENDER))

        if ptr != self._current_sender:
            exec = self.compiler.insn_def(i.CreateExec())
            sel = self.compiler.insn_def(i.CreateSelector(
                i.SelectorType.ALL_ENTITIES))
            test_uid = self.compiler.insn_def(i.CreateEntityLocalAccess(
                self.uid_obj, sender))
            with self.compiler.compiletime():
                self.compiler.add_insn(i.ExecAsEntity(exec, sel))
                self.compiler.add_insn(i.ExecIfCmp(exec, test_uid, 'eq', ptr))
            self.compiler.add_insn(i.ExecRun(exec, block))
        else:
            self.compiler.add_insn(i.Call(block))

        return block, sender # sender for convenience

    def finish(self):
        if self._get_or_create:
            self.compiler.pragma('entity_support_ptr', None)

    @classmethod
    def gen_get_or_create(cls, top, _):
        func = top.define_function('_internal/entity_ptr')
        func.preamble.add(i.PureInsn())
        retvar = func.preamble.define(i.ReturnVarInsn(i.VarType.i32))
        ct = func.create_compiletime()
        entry = func.create_block('entry')
        set_uid = func.create_block('set_uid')
        set_uid.set_is_function()
        ctblock = ct.create_block('ct_entry')

        uid_obj = top.preamble.add(cls.objective(), True, '__uid')
        sender = func.preamble.define(i.CreateSelector(i.SelectorType.SENDER))
        self_uid = func.preamble.define(i.CreateEntityLocalAccess(uid_obj, sender))
        next_uid = func.preamble.define(i.CreateEntityLocalAccess(uid_obj,
                                      top.lookup('_global_entity')))
        ex = func.preamble.define(i.CreateExec())

        # unless our uid is 1 or greater...
        ctblock.add(i.ExecUnlessVar(ex, self_uid, 1, None))

        ct.run_and_return()

        entry.add(i.ExecRun(ex, set_uid))
        entry.add(i.SetScore(retvar, self_uid))
        entry.add(i.Return())

        set_uid.add(i.SetScore(self_uid, next_uid))
        set_uid.add(i.AddScore(next_uid, 1))
        func.end()
        return func class EntityTypeType(NativeType):

    def allocate(self, compiler, namehint):
        return EntityTypeInstance() class EntityPosComponentType(DecimalType):

    def complete_type(self, compiler):
        dec = compiler.type('decimal')
        params = (Parameter(dec, 'other', False),)
        type, func = self.add_operator_member(compiler, '=', dec, params, True)
        func.set_as_intrinsic(IntrinsicCallable(self._assign_dec))
        super().complete_type(compiler)

    def _assign_dec(self, compiler, fncontainer, args):
        other = args[1]
        with fncontainer.this.open_write() as (block, var):
            block.add(i.SetScore(var, other.type.as_variable(other.value)))
        return other

    def as_variables(self, instance):
        return ()

    def allocate(self, compiler, namehint):
        assert False

    def new_temporary(self, compiler, namehint='tmp'):
        val = super().allocate(compiler, namehint)
        dec = compiler.type('decimal')
        tmp = Temporary(dec, val)
        dec.run_constructor(compiler, tmp, ())
        return tmp

    def as_variable(self, instance):
        return instance.open_read()

    def operator_add_assign(self, left, right):
        if isinstance(right, (LiteralInt, LiteralDec)):
            left.value.tp_offset(right.value)
            return left
        return super().operator_add_assign(left, right)

    def operator_sub_assign(self, left, right):
        if isinstance(right, (LiteralInt, LiteralDec)):
            left.value.tp_offset(-right.value)
            return left
        return super().operator_sub_assign(left, right)

    def get_property(self, compiler, instance, prop):
        if prop == 'decval':
            val = self.new_temporary(compiler, 'decval')
            val.type.dispatch_operator(compiler, '=', val, instance)
            return val
        return super().get_property(instance, prop)

    def coerce_to(self, compiler, container, type):
        if type == compiler.type('decimal'):
            var = self.as_variable(container.value)
            return Temporary(type, var)
        return super().coerce_to(compiler, container, type) class EntityPointerType(CBLType):

    def allocate(self, compiler, namehint):
        var = compiler.create_var(namehint + '_ptr', i.VarType.i32)
        return EntityPointer(compiler, self, var)

    @property
    def ir_type(self):
        return i.VarType.i32

    def as_variable(self, instance):
        return instance.variable

    def _copy_impl(self, compiler, this, other):
        this.value.ctor_from(other.value)
        # compiler.add_insn(i.SetScore(this.value.variable, other.value.variable))
        return other class EntityLocalType(NativeType):

    def instantiate(self, compiler, args):
        val_type, = args
        from .base_types import IntType
        supported_types = (IntType,)
        if isinstance(val_type, supported_types):
            t = EntityLocalDerivedType(val_type)
            t.typename = self.typename + '/' + val_type.typename
            t.complete_type(compiler)
            return t
        assert False, "Invalid type argument %s" % val_type class EntityCollectionType(CBLType):

    def allocate(self, compiler, namehint):
        return EntityCollection(self.get_func_members(),
                                self.get_func_properties())

    def effective_var_size(self):
        return 0

    def _copy_impl(self, compiler, this, other):
        this.value.copy_from(compiler, other.value)
        return other class IntrinsicSupport:

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

    def traverse(self, children):
        with self.compiler.scope:
            for decl in children:
                self.compiler.transform(decl)

    def native_definition(self, func_decl, py_code):
        assert func_decl.typespace is not None
        assert py_code
        py_code = 'def run():\n' + py_code + '\n__result__ = run()'
        code = compile(py_code, 'native.py', 'exec')
        intrinsic = NativeExec(func_decl.params, code)
        t = func_decl.typespace
        from .compiler import CtorDeclaration
        if isinstance(func_decl, CtorDeclaration):
            fn = t.lookup_constructor(func_decl.params)
        elif func_decl.is_operator:
            fn = t.lookup_operator(func_decl.name, func_decl.params)
        else:
            fn = t.lookup_function_member(func_decl.name, func_decl.params)
            # Possibly refactor this
            # Lookup the static members to support intrinsic singleton funcs
            if fn is None:
                fn = t.metatype.lookup_function_member(func_decl.name,
                                                       func_decl.params)
        if fn is None:
            raise TypeError('Cannot find function member for %s' % (func_decl,))
        type, func = fn
        func.set_as_intrinsic(intrinsic)

    def type_configure(self, type_name, py_code):
        exec('if True:\n' + py_code, {
            'the_type': type_name,
            'i': i,
            'compiler': self.compiler,
            '__name__': __name__
        }) def escape_function_name(name):
    return ''.join(map(escape_name_chr, name)) def safe_typename(type):
    return ''.join(map(lambda c: '_%s_' % op_name[c] if c in op_name else c,
                       type.typename)) class TopLevel(VariableHolder):

    def __init__(self):
        self.scope = Scope()
        self.preamble = Preamble(self)
        self.finished = False
        self.store('pos_util', PosUtilEntity())
        self.store('_global_entity', GlobalEntity())
        # Internal directives. Implementation defined.
        self.pragmas = []

    def get_or_create_func(self, name):
        return self.scope.get_or_create(name, self._create_func)

    def create_function(self, namehint):
        return self.uniq(namehint, self._create_func)

    def _create_func(self, name):
        return IRFunction(name, self)

    def define_function(self, name):
        func = self.get_or_create_func(name)
        if isinstance(func, ExternFunction):
            real_func = self.scope[name] = self._create_func(name)
            real_func.expect_signature(func)
            real_func.set_namespace(func._gname.namespace)
            mapping = {func: real_func}
            for var in self.scope.values():
                if isinstance(var, IRFunction):
                    for block in var.allblocks:
                        block.apply_mapping(ExternFunction, mapping)
            func = real_func
        return func

    def create_global(self, namehint, vartype, is_extern=False, ns=None):
        from .instructions import DefineGlobal, VirtualString
        lnk = 'external' if is_extern else 'internal'
        ns = None if ns is None else VirtualString(ns)
        return self.preamble.add(DefineGlobal(vartype, lnk, ns), True, namehint)

    def lookup_func(self, name):
        func = self.lookup(name)
        if func is not None:
            assert isinstance(func, VisibleFunction)
        return func

    def include_from(self, other):
        for name, var in other.scope.items():
            if isinstance(var, VisibleFunction) and not name.startswith('__'):
                self.scope[name] = DynLinkFunction(var.global_name,
                                                   var.params, var.returns, var.is_pure)
            elif isinstance(var, Variable):
                self.scope[name] = var

    def end(self):
        assert not self.finished
        for name, var in self.scope.items():
            if isinstance(var, VisibleFunction):
                assert var.finished, "unfinished function " + name
        self.finished = True

    def writeout(self, writer):
        assert self.finished
        self.preamble.apply(writer)
        for var in self.scope.values():
            var.write_out(writer)

        table = []
        functions = []
        extern_vars = set()

        for name, var in self.scope.items():
            if isinstance(var, VisibleFunction):
                table.extend(var.get_func_table())
                functions.append(var)
            elif isinstance(var, ExternVariable):
                assert var.proxy_set, "Unbound variable $%s %s" % (name, var)
                ref = var._direct_ref()
                if ref is not None:
                    extern_vars.add(ref.objective.objective)
        writer.write_func_table(table)
        writer.write_extern_vars(extern_vars)

        temp_generator = TemporaryVarGen(writer)
        writer.write_objective('success_tracker', None)

        for func in functions:
            try:
                func.writeout(writer, temp_generator)
            except:
                print("Error in function: " + func.global_name.uqn)
                raise

        temp_generator.finish()

    def get_extern_symbol_table(self, session):
        functions = {}
        variables = {}
        for name, var in self.scope.items():
            if isinstance(var, VisibleFunction) and var.extern_visibility:
                functions[name] = {
                    '_name': session.scope.function_name(var.global_name),
                    'params': [{'t': p[0].name, 'p': p[1]} for p in var.params],
                    'returns': [r.name for r in var.returns],
                    'flags': {
                        'pure': var.is_pure,
                    },
                }
            elif isinstance(var, GlobalVariable) and var.is_extern:
                ref = var._direct_ref()
                vardesc = None
                if ref is not None:
                    vardesc = { 'score': ref.objective.objective }
                nbt = var._direct_nbt()
                if nbt is not None:
                    # We use the offset rather than the true path so it's
                    # easy to derrive the hierarchy of the NBT
                    vardesc = { 'nbt': var.var.offset }
                vardesc['type'] = var.type.name
                vardesc['namespace'] = var.namespace
                variables[name] = vardesc
        return {
            'functions': functions,
            'variables': variables,
        }

    def serialize(self):
        strs = []
        strs.append(self.preamble.serialize())
        for name, elem in self.scope.items():
            if isinstance(elem, VisibleFunction):
                strs.append(elem.serialize())
            if isinstance(elem, ExternVariable):
                # Must be before functions
                strs.insert(1, 'extern variable $%s %s\n' % (name,
                                                             elem.type.name))
        return '\n'.join(strs)

    @staticmethod
    def linker(*tops):
        """NOTE: This will LINK tops together, each TopLevel will not be
        copied so they will be mutated if the output is mutated"""
        assert tops
        if len(tops) == 1:
            return tops[0]
        out = TopLevel()
        externs = defaultdict(list)
        extern_vars = defaultdict(list)
        all_blocks = []
        # Things that should not reserve names in the scope
        # until all other variables are reserved
        # i.e renamed on conflict
        private = []
        for top in tops:
            assert top.finished
            out.preamble.insns.extend(top.preamble.insns)
            out.pragmas.extend(top.pragmas)
            for name, var in top.scope.items():
                if isinstance(var, VisibleFunction):
                    if isinstance(var, ExternFunction):
                        externs[name].append(var)
                    elif isinstance(var, IRFunction):
                        if var.extern_visibility:
                            # Name must be the same as global name
                            out.store(name, var)
                        else:
                            private.append((name, var))
                        # re-parent function scopes
                        var.scope.parent = out.scope
                        all_blocks.extend(var.blocks)
                    elif isinstance(var, DynLinkFunction):
                        out.store(name, var)
                    else:
                        assert False, var
                elif isinstance(var, GlobalVariable):
                    if var.is_extern:
                        out.store(name, var)
                    else:
                        private.append((name, var))
                elif isinstance(var, ExternVariable):
                    extern_vars[name].append(var)
                else:
                    private.append((name, var))
        extern_mapping = {}
        for name, externlist in externs.items():
            new_extern = externlist[0]
            concrete = out.lookup_func(name)
            replacement = concrete or new_extern
            for extern in externlist:
                # Externs of the same name must have same signature
                extern.expect_signature(replacement)
                if replacement != extern:
                    extern_mapping[extern] = replacement
            if not concrete:
                # Put any unresolved externs back
                out.store(name, new_extern)
        # Replace ExternFunction references in all blocks
        if extern_mapping:
            for block in all_blocks:
                block.apply_mapping(ExternFunction, extern_mapping)

        # Same again for extern variables
        # We cannot make use of the proxy ability due to name conflicts
        # with each extern in the externlist
        extern_mapping = {}
        for name, externlist in extern_vars.items():
            new_var = externlist[0]
            realvar = out.lookup(name)
            if realvar is not None:
                assert isinstance(realvar, GlobalVariable) \
                       and realvar.is_extern, realvar
            replacement = realvar or new_var
            for var in externlist:
                if replacement != var:
                    extern_mapping[var] = replacement
            if not realvar:
                out.store(name, new_var)
        if extern_mapping:
            for block in all_blocks:
                block.apply_mapping(ExternVariable, extern_mapping)

        for name, var in private:
            newvar = out.generate_name(name, var)
            if isinstance(newvar, IRFunction):
                newvar._name = newvar._name.with_name(out.name_for(newvar))

        out.end()
        return out

    def run_pragmas(self, known_pragmas):
        final = {}
        for (p_key, p_val) in self.pragmas:
            assert p_key in known_pragmas
            if p_key in final:
                final[p_key] = known_pragmas[p_key].reduce(final[p_key], p_val)
            else:
                final[p_key] = p_val
        results = {}
        for p_key, p_val in final.items():
            results[p_key] = known_pragmas[p_key].apply(self, p_val)
        return results class Pragma(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def reduce(self, acc, val):
        pass

    @abc.abstractmethod
    def apply(self, top, value):
        pass 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 SelectorType(InsnArg):

    _LOOKUP = {}

    def __init__(self, letter, limit):
        self.letter = letter
        self.max_limit = limit
        self._LOOKUP[letter] = self

    @classmethod
    def lookup(cls, name):
        return cls._LOOKUP[name]

    @classmethod
    def _init_from_parser(cls, name):
        return cls._LOOKUP[name]

    ALL_PLAYERS = None
    ALL_ENTITIES = None
    SENDER = None
    NEAREST_PLAYER = None
    RANDOM_PLAYER = None class Reader:

    def __init__(self):
        self.parser = lark_parser()
        self.env = []

    def set_env(self, name, value):
        self.env.append((name, value))

    def read(self, text):
        tree = self.parser.parse(text)
        builder = BuildProgram()
        self.preprocess(builder.top)
        builder.visit(tree)
        builder.top.end()
        return builder.top

    def preprocess(self, top):
        for name, value in self.env:
            top.store(name, value)

    def read_blocks(self, func, blocks):
        tree = self.parser.parse('%HOOK BLOCKS ' + blocks)
        builder = BuildProgram()
        builder.func = func
        builder.holder = func
        # Return blocks in order of occurence
        return builder.visit(tree)

    def read_instruction(self, func, insn, moreargs=()):
        tree = self.parser.parse('%HOOK INSN ' + insn)
        builder = BuildProgram()
        builder.func = func
        builder.holder = func
        builder._hook_more_args = moreargs
        # the "start" visitor returns a list with one element - the insn
        return builder.visit(tree)[0]
from collections import namedtuple
from .parser_ import Parser, Transformer_WithPre, v_args
from .struct_type import StructuredType
from .native_type import as_var, NativeType, MetaType
from .ir_type import IRType, StringType
from .function_type import FunctionDispatchType, FunctionType, Invokable, \
     InstanceFunctionType
from .macro_type import MacroType
from .base_types import VoidType, BoolType, IntType, DecimalType, NBTType
from .event_type import TagEventType, AdvancementEventType
from .maybe_type import MaybeType
from .template_type import TemplatedType
from .types import Types
from .containers import *
from .array_support import ArraySupport, ArrayType
from .entity_support import (EntitySupport, EntityTypeType,
                             EntityPosComponentType, EntityPointerType,
                             EntityLocalType, EntityCollectionType)
from .intrinsic_support import IntrinsicSupport
from .util import escape_function_name, safe_typename
from cmd_ir.core import TopLevel, Pragma
from cmd_ir.variables import VarType
from cmd_ir.core_types import SelectorType
from cmd_ir.reader import Reader
        from cmd_ir.core import ExternFunction
        from cmd_ir.core import CompileTimeFunction
        from cmd_ir.variables import ExternVariable
        from cmd_ir.core import BasicBlock
import contextlib
import cmd_ir.instructions as i
        import json
        import json
        import os
        import json
                                           i.VirtualString(val)))

    def dispatch_operator(self, op, left, right=None):
        return left.type.dispatch_operator(self, op, left, right)

    def __create_global(self, namehint, var_type):
        return self.top.create_global(namehint, var_type, True, self.namespace)

    def __create_local(self, namehint, var_type):
        return self.func.create_var(namehint, var_type)

    @contextlib.contextmanager
    def set_create_var(self, create_var):
        old = self.create_var
        self.create_var = create_var
        yield
        self.create_var = old
    
    def create_block(self, namehint):
        assert self.func is not None, "Tried to create block outside of function"
        return self.func.create_block(namehint)

    def define_function(self, name):
        assert name not in self._global_func_names, \
               "Function '%s' already defined" % name
        self._global_func_names.add(name)
        return self.top.define_function(escape_function_name(name))

    def extern_function(self, name, params, returns):
        ir_name = escape_function_name(name)
        extern = ExternFunction(ir_name, params, returns)
        self.top.store(ir_name, extern)
        return extern

    def add_insn(self, insn):
        self.block.add(insn)

    @contextlib.contextmanager
    def compiletime(self):
        old_func = self.func
        old_block = self.block
        old_ret_block = self.ret_block
        fn = self.func
        in_compiletime = isinstance(fn, CompileTimeFunction)
        # If we're already inside a compiletime function, remain within
        # the current one instead of creating a new one
        # Need to map return blocks to jump to end of this nested call rather
        # than return from whole compiletime function
        if not in_compiletime:
            self.func = fn = fn.create_compiletime()
            self.block = fn.create_block('entry')
        else:
            self.ret_block = fn.create_block('nested_ct')
        yield
        if not in_compiletime:
            fn.run_and_return()
            self.func = old_func
            self.block = old_block
        else:
            if not self.block.is_terminated():
                self.block.add(i.Branch(self.ret_block))
            self.block = self.ret_block
            self.ret_block = old_ret_block

    def type(self, name):
        t = self.types.lookup(name)
        assert t is not None, "Unknown type %s" % name
        return t

    def add_type(self, name, type):
        self.types.add(name, type)
        type.typename = name
        metatype = type.metatype
        if metatype is not None:
            return self.scope.store(name, Symbol(metatype, name, type))
        return None

    def alias_type(self, name, type):
        self.types.alias(type, name)
        metatype = type.metatype
        if metatype is not None:
            self.scope.store(name, Symbol(metatype, name, type))

    def add_base_type(self, name, type):
        self.add_type(name, type)
        type.complete_type(self)

    def global_def(self, namehint, insn):
        return self.top.preamble.add(insn, True, namehint)

    def define(self, namehint, insn):
        # Use globals if we are in the init func - check preamble as
        # we might be inside a compiletime of the init func
        if self.func is None or self.func.preamble is self._init_func.preamble:
            return self.top.preamble.add(insn, True, namehint)
        return self.func.preamble.add(insn, True, namehint)

    def insn_def(self, insn):
        return self.define(None, insn)

    def _declare_macro(self, name, ret_type, params, body, compiletime):
        fn_type = MacroType(ret_type, params, body, self.types.snapshot(),
                            compiletime)
        self.scope.declare_symbol(name, fn_type)

    def _declare_function(self, decl, has_definition):
        if decl.typespace is not None:
            type = decl.typespace
            static = False # TODO
            if decl.is_operator:
                assert not decl.is_async
                assert not static
                f = type.lookup_operator(decl.name, decl.params)
            else:
                f = type.lookup_function_member(decl.name, decl.params)
            assert f is not None, "Lookup failed for %s" % (decl,)
            fn_type, func = f
            # TODO check fn_type matches decl
            symbol = Symbol(fn_type, decl.name, func)
        else:

            fn_type = FunctionType(decl.ret_type, decl.params,