Beispiel #1
0
    def has_short_move(self, dsts: List[str]) -> bool:
        if self.array_size() < 2:
            return False

        for dst in dsts:
            sign, dst = separate_sign(dst)

            if not self._main.is_sub(dst):
                return False

            target = cast(SubsystemBase, self._main.get_instance(dst))

            if not target.is_writable_array():
                return False

            if self.array_size() < 2 or target.array_size() < 2:
                return False

            for i in range(1, min(self.array_size(), target.array_size())):
                if (self.addressof(str(i)) - self.addressof(str(i - 1)) !=
                        target.addressof(str(i)) -
                        target.addressof(str(i - 1))):
                    return False

        return True
Beispiel #2
0
    def put_clear_dsts(self, out_vars: list):
        """clear destinations without sign."""

        for out_var in out_vars:
            sign, addr0 = separate_sign(out_var)
            addr = self._main.addressof(addr0)

            if sign == "":
                self._main.put_at(addr, "[-]")
Beispiel #3
0
    def put_short_array_move(self, dsts: List[str], copy=False):
        if not self.has_short_move(dsts):
            raise Exception(f"destination is not compatible")

        base = self.addressof("0")
        sizes = set([])
        dsts2: Tuple[int, str, SubsystemBase, int] = []

        for dst in dsts:
            sign, dst = separate_sign(dst)
            sub = cast(SubsystemBase, self._main.get_instance(dst))

            size = min(sub.array_size(), self.array_size())
            sizes |= set([size])

            dsts2.append((size, sign, sub, sub.addressof("0") - base))

        sizes = sorted(list(sizes))

        for i, size in enumerate(sizes):
            base_idx = 0 if i == 0 else sizes[i - 1]
            size2 = size - base_idx

            # n = 2
            # 0, v0, n -> 1, v1, n-1 -> 1, v2, n-2 -> 0
            self._main.put(">" * self.offset(base_idx * 2 + 2))

            self._main.put("+" * size2)

            self._main.put("[-[>>+<<-]<")

            for dst_size, sign, dst, dst_addr in dsts2:
                if sign == "":
                    self._main.put_at(dst_addr, "[-]")

            self._main.put("[")

            if copy:
                self._main.put(">+<")

            for dst_size, sign, dst, dst_addr in dsts2:
                o = "-" if sign == "-" else "+"

                self._main.put_at(dst_addr, o)

            self._main.put("-]")

            if copy:
                self._main.put(">[<+>-]<")

            self._main.put(">+>>]")

            self._main.put("<<[-<<]")

            self._main.put("<" * self.offset(base_idx * 2))
Beispiel #4
0
    def put_juggling_push(self,
                          value: str,
                          first=False,
                          last=False,
                          tmps: List[int] = None):
        """starts and ends at first unused value"""

        sign, value = separate_sign(value)

        if self._main.is_var(value):
            addr = self._main.addressof(value)
            tmp = -1

            if sign != "-":
                tmp = self._main.get_nearest_tmp(tmps, [addr])

            if not first:
                self.put_juggling_end()

            self._main.put_at(addr, "[")

            if sign != "-":
                self._main.put_at(tmp, "+")

            self._main.put_at(self.offset(), ">>[>>]<+<[<<]")
            self._main.put_at(addr, "-]")

            self._main.put_at(self.offset(), ">>[>>]+[<<]")

            if sign != "-":
                self._main.put_move(tmp, [f"+#{addr}"])

            if not last:
                self.put_juggling_start()

            return

        if first:
            self.put_juggling_start()

        if value == "input":
            self._main.put(",>+>")
        elif self._main.is_val(value):
            v = self._main.valueof(value)
            self.put_set_char(v)
            self._main.put("+>")
        else:
            raise Exception(f"unknown args{value}")

        if last:
            self.put_juggling_end()
Beispiel #5
0
    def put(self,
            name: str,
            args: List[Union[int, str]],
            tmps: List[int] = None):
        if name == "init":
            return

        if name == "clean":
            self.put_clean()
            return

        if name in ["@=write", "@=writeln"]:
            self.put("@set", args)
            self.put(f"@{name[2:]}", [])
            return

        if name in ["@=+write", "@=+writeln"]:
            self.put("@+set", args)
            self.put(f"@{name[3:]}", [])
            return

        if name == "@set":
            self.put("@clear", [])
            name = "@+set"

        if name in "@+set":
            self._main.put(">" * self.offset() + ">>[>]")

            for c in " ".join(args):
                self.put_set_char(ord(c))

            self._main.put("<[<]<" + "<" * self.offset())

            return

        if name == "@clear":
            self._main.put_at(self.offset(), ">>[>]<[[-]<]<")

            return

        if name in ["@readln", "@read"]:
            self.put("@clear", [])
            name = "@+readln"

        if name == "@+readln":
            if len(args) == 0:
                self._main.put_at(
                    self.offset(),
                    ">>[>],----------[++++++++++>,----------]<[<]<")

                return

            arg = args[0]

            if self._main.is_var(arg):
                self._main.put_at(arg, "[")
                self._main.put_at(self.offset(), ">>[>]>+<[<]<")
                self._main.put_at(arg, "-]")
            else:
                size = self._main.valueof(arg)
                self._main.put_at(self.offset(),
                                  ">>[>]>" + "+" * size + "<<[<]<")

            self._main.put_at(
                self.offset(),
                ">>[>]>[->>>+<<<<,"
                # 255
                + "+[-"
                # 26
                + ("----- ----- ----- ----- ----- -[" +
                   "+++++ +++++ +++++ +++++ +++++ +") + "----------[>>+>+<<<-]"
                # 26
                + "]"
                # 255
                + "]" +
                ">>[<<+>>-]>[<<<++++++++++>>>>-<[-]]>[<<<[-]>>>-]<<<[>+<-]>]<<<[<]<"
            )

            return

        # uses 2 right tmp
        if name == "@+read":
            if len(args) == 0:
                self._main.put_at(self.offset(), ">>[>]>+<<[<]<")
            else:
                arg = args[0]

                if self._main.is_var(arg):
                    self._main.put_at(arg, "[")
                    self._main.put_at(self.offset(), ">>[>]>+<[<]<")
                    self._main.put_at(arg, "-]")
                else:
                    size = self._main.valueof(arg)
                    self._main.put_at(self.offset(),
                                      ">>[>]>" + "+" * size + "<<[<]<")

            self._main.put_at(self.offset(), ">>[>]>[-[>+<-]<,>>]<<[<]<")

            return

        if name == "@write":
            if len(args) > 0 and args[0] == "reversed":
                self._main.put_at(self.offset(), ">>[>]<[.<]<")
            else:
                self._main.put_at(self.offset(), ">>[.>]<[<]<")

            return

        if name == "@writeln":
            if len(args) > 0 and args[0] == "reversed":
                self._main.put_at(self.offset(), ">>[>]<[.<]++++++++++.[-]<")
            else:
                self._main.put_at(self.offset(), ">>[.>]++++++++++.[-]<[<]<")

            return

        if name in ["@push", "@copypush"]:
            if len(args) == 0:
                raise Exception("str:@push requires 1 arg")

            for arg in args:
                if arg == "input":
                    self._main.put_at(self.offset(), ">>[>],<<[<]<")

                    continue

                if self._main.is_var(arg):
                    addr = self._main.addressof(arg)

                    self._main.put_at(addr, "[")

                    if name == "@copypush":
                        self._main.put("+")

                    self._main.put_at(self.offset(), ">>[>]>+<<[<]<")
                    self._main.put_at(addr, "-]")
                    self._main.put_at(self.offset(), ">>[>]>[<+>-]<<[<]<")

                    if name == "@copypush":
                        self._main.put("[")
                        self._main.put_at(addr, "+")
                        self._main.put("-]")

                    continue

                v = self._main.valueof(arg)

                self._main.put(">" * self.offset() + ">>[>]")
                self.put_set_char(v)
                self._main.put("<<[<]<" + "<" * self.offset())

            return

        if name == "@pop":
            if len(args) == 0:
                self._main.put_at(self.offset(), ">>[>]<[[-]<[<]]<")

                return

            self.put_clear_dsts(args)

            for arg in args:
                sign, addr0 = separate_sign(arg)
                addr = self._main.addressof(addr0)

                self._main.put_at(self.offset(),
                                  ">>[>]<[[>+<-]>[<<[<]<+>>[>]>-]<<[<]]<")
                self._main.put_at(self.offset(), "[")
                self._main.put_at(addr, "-" if sign == "-" else "+")
                self._main.put_at(self.offset(), "-]")

            return

        if name == "@drop":
            if len(args) == 0:
                self._main.put_at(self.offset(), ">>[-]>[[<+>-]>]<<[<]<")

                return

            self.put_clear_dsts(args)

            for arg in args:
                sign, addr0 = separate_sign(arg)
                addr = self._main.addressof(addr0)

                self._main.put_at(self.offset(), ">>[<<+>>-]>[[<+>-]>]<<[<]<")
                self._main.put_at(self.offset(), "[")
                self._main.put_at(addr, "-" if sign == "-" else "+")
                self._main.put_at(self.offset(), "-]")

            return

        if name in ["@move", "@move_reversed", "@split"]:
            if name == "@split":
                args2 = args[1:]
            else:
                args2 = args

            for arg in args2:
                if not self._main.is_sub(arg, "str"):
                    raise Exception(f"[str:{name}] takes only str")

                arg_str: SubsystemBase = self._main.subsystem_by_alias(arg)

                arg_str.put("@clear", [])

            name = "@+" + name[1:]

        if name in ["@+move", "@+move_reversed"]:
            ins_pop = "@drop" if name == "@+move" else "@pop"

            self.put(ins_pop, [0])
            self._main.put("[")

            self._main.put("[")

            if len(set(args)) != len(args):
                raise Exception(f"[str:{name}] takes every str only once")

            for arg in args:
                if not self._main.is_sub(arg, "str"):
                    raise Exception(f"[str:{name}] takes only str")

                arg_str: SubsystemBase = self._main.subsystem_by_alias(arg)

                if arg_str == self:
                    raise Exception("[str:@move] can not move to the same str")

                self._main.put_at(arg_str.offset(), ">>[>]>+<<[<]<")

            self._main.put("-]")

            for arg in args:
                arg_str: SubsystemBase = self._main.subsystem_by_alias(arg)

                self._main.put_at(arg_str.offset(), ">>[>]>[<+>-]<[<]<")

            self.put(ins_pop, [0])
            self._main.put("]")

            return

        if name == "@+split":
            sep = args[0]

            if not self._main.is_val(sep):
                raise Exception(
                    f"first arg of [str:{name}] should be immediate")

            n_sep = self._main.valueof(sep)
            args = args[1:]

            for arg in args:
                arg_str: SubsystemBase = self._main.subsystem_by_alias(arg)

                arg_str.put("@clear", [])

            for arg in args:
                arg_str: SubsystemBase = self._main.subsystem_by_alias(arg)
                """
                inc it
                while it
                    clear it
                    self:drop self:tmp_L
                    if self:L
                        sub self:L sep
                        if self:L
                            add self:L sep
                            self:@push self:L
                            inc it
                """
                self._main.put("+[[-]")

                # safe version of self.put("@drop", [self.offset()])
                self._main.put_at(self.offset(),
                                  "[-]>>[<<+>>-]>[[<+>-]>]<<[<]<")

                n, m = calc_small_pair(n_sep, 1)
                if m == 1:
                    self._main.put_at(self.offset(),
                                      "[" + ("-" * n) + "[" + ("+" * n))
                else:
                    self._main.put_at(
                        self.offset(), "[>" + ("+" * n) + "[<" + ("-" * m) +
                        ">-]<[>" + ("+" * n) + "[<" + ("+" * m) + ">-]<")

                # safe version of arg_str.put("@push", [self.offset()])
                self._main.put_at(self.offset(), "[")
                self._main.put_at(arg_str.offset(), ">>[>]>+<<[<]<")
                self._main.put_at(self.offset(), "-]")
                self._main.put_at(arg_str.offset(), ">>[>]>[<+>-]<<[<]<")

                self._main.put("+")
                self._main.put_at(self.offset(), "[-]]]")
                self._main.put("]")

            return

        if name == "@len":
            self.put_clear_dsts(args)

            self._main.put_at(self.offset(),
                              ">>[[>]<[>+<-]<[<]<+>>]>[[<+>-]>]<<[<]<[")

            for arg in args:
                sign, addr0 = separate_sign(arg)
                addr = self._main.addressof(addr0)

                self._main.put_at(addr, "-" if sign == "-" else "+")

            self._main.put_at(self.offset(), "-]")

            return

        raise Exception(f"wnknown ins: {name} {args}")
Beispiel #6
0
    def put(self, name: str, args: list, tmps: List[int] = None):
        if name == "init":
            return

        if name == "clean":
            self.put_clean()
            return

        if name == "@clear":
            self._main.put_at(self.offset(), ">>[>>]<<[-<[-]<]")

            return

        if name == "@calc":
            if len(args) == 0:
                return

            for i, arg in enumerate(args):
                first = i == 0
                last = i + 1 == len(args)

                if arg in ["0dup", "0swap", "0rot", "0drop"]:
                    pass
                elif arg == "swap":
                    self.put_juggling_rot(2, 1, first=first, last=last)
                elif arg[1:] == "swap" and arg[0].isdigit():
                    self.put_juggling_rot(2,
                                          int(arg[0]),
                                          first=first,
                                          last=last)
                elif arg == "dup":
                    self.put_juggling_dup(1, 1, first=first, last=last)
                elif arg[1:] == "dup" and arg[0].isdigit():
                    self.put_juggling_dup(1,
                                          int(arg[0]),
                                          first=first,
                                          last=last)
                elif arg == "rot":
                    self.put_juggling_rot(3, 1, first=first, last=last)
                elif arg[1:] == "rot" and arg[0].isdigit():
                    self.put_juggling_rot(3,
                                          int(arg[0]),
                                          first=first,
                                          last=last)
                elif arg == "drop":
                    self.put_juggling_pop(None, first=first, last=last)
                elif arg == "over":
                    self.put_juggling_over(1, first=first, last=last)
                elif arg[1:] == "over" and arg[0].isdigit():
                    self.put_juggling_over(int(arg[0]), first=first, last=last)
                elif arg == "+":
                    self.put_juggling_add(sub=False, first=first, last=last)
                elif arg == "-":
                    self.put_juggling_add(sub=True, first=first, last=last)
                elif arg == "1+":
                    self.put_juggling_inc(dec=False, first=first, last=last)
                elif arg == "1-":
                    self.put_juggling_inc(dec=True, first=first, last=last)
                elif arg == ".":
                    self.put_juggling_pop("print", first=first, last=last)
                elif arg == ",":
                    self.put_juggling_push("input",
                                           first=first,
                                           last=last,
                                           tmps=tmps)
                elif arg.isdigit():
                    self.put_juggling_push(str(int(arg)),
                                           first=first,
                                           last=last,
                                           tmps=tmps)
                elif arg == "'":
                    self.put_juggling_push("32", first=first, last=last)
                elif arg.startswith("'"):
                    self.put_juggling_push(str(ord(arg[1])),
                                           first=first,
                                           last=last)
                else:
                    raise Exception(f"[stk:calc] can not compile [{arg}]")

            return

        if name in ["@push", "@copypush"]:
            if len(args) == 0:
                raise Exception("stk:@push requires 1 arg")

            for i, arg in enumerate(args):
                self.put_juggling_push(arg,
                                       i == 0,
                                       i + 1 == len(args),
                                       tmps=tmps)

            return

        if name == "@pop":
            if len(args) == 0:
                self._main.put_at(self.offset(), ">>[>>]<<[-<[-]<[<<]]")

                return

            self.put_clear_dsts(list(filter(self._main.is_var, args)))

            for arg in args:
                if arg == "print":
                    self._main.put_at(self.offset(), ">>[>>]<<[-<.[-]<[<<]]")

                    continue

                sign, arg = separate_sign(arg)

                if not self._main.is_var(arg):
                    raise Exception(f"[@pop/n] with unknown arg")

                addr = self._main.addressof(arg)

                self._main.put_at(self.offset(), ">>[>>]<<[ <[ >[<<]")
                self._main.put_at(addr, "-" if sign == "-" else "+")
                self._main.put_at(self.offset(), ">>[>>]<<<-] >-<<[<<]]")

            return

        if name == "@empty":
            for arg in args:
                sign, addr0 = separate_sign(arg)
                addr = self._main.addressof(addr0)

                self._main.put_at(addr, "[-]+")

            tmp = self._main.get_nearest_tmp(tmps, args)

            self._main.put_at(self.offset(), ">>[<<")
            self._main.put_at(tmp, "+")
            self._main.put_at(self.offset(), ">>-]<<")

            self._main.put_at(tmp, "[")

            for arg in args:
                sign, addr0 = separate_sign(arg)
                addr = self._main.addressof(addr0)

                self._main.put_at(addr, "-")

            self._main.put_at(self.offset(), ">>+<<")

            self._main.put_at(tmp, "-]")

            return

        if name in ["@add", "@sub"]:
            self.put_juggling_add(name == "@sub", first=True, last=True)

            return

        if name == "@dup":
            n = 1
            m = 1
            if len(args) > 0:
                if self._main.is_var(args[0]):
                    raise Exception(
                        f"[stk:@dup] accepts only immediates for element size")

                m = self._main.valueof(args[0])

            if len(args) > 1:
                if self._main.is_var(args[1]):
                    raise Exception(
                        f"[stk:@dup] for dynamic range is not implemented")

                n = self._main.valueof(args[1])

            if n <= 0 or m <= 0:
                return

            self.put_juggling_dup(n, m, first=True, last=True)

            return

        if name == "@swap":
            # self._main.put_at(self.offset(), ">>[>>]<<[<[>>+<<-] <<[>>+<<-] >>>>[<<<<+>>>>-] <[<<]]")
            # return

            if len(args) > 1:
                raise Exception(f"[stk:@swap/{len(args)}] is not implemented")

            name = "@rot"

            if len(args) == 1:
                args = [args[0], "2"]
            else:
                args = ["1", "2"]

        if name == "@rot":
            n = 3
            m = 1

            if len(args) > 0:
                if self._main.is_var(args[0]):
                    raise Exception(
                        f"[stk:@rot] accepts only immediates for element size")

                m = self._main.valueof(args[0])

                args = args[1:]

                if m <= 0:
                    return

            if len(args) > 0:
                sign, arg = separate_sign(args[0])

                if self._main.is_var(arg):
                    if self.stk_tmps_ < 4:
                        raise Exception(
                            f"[{self.name()}:@rot] for dynamic range requires at least 4 stack-embedded tmps"
                        )

                    if m != 1:
                        raise Exception(
                            f"[{self.name()}:@rot] for dynamic range is implemented only for element_size=1"
                        )

                    addr = self._main.addressof(arg)
                    tmp = -1

                    if sign != "-":
                        tmp = self._main.get_nearest_tmp(tmps, [addr])

                    self._main.put_at(addr, "[-[+ [")

                    if sign != "-":
                        self._main.put_at(tmp, "+")

                    # makes: ..., 0, 0, 0, n_range
                    self._main.put_at(self.offset(), ">>[>>]>>+<<<<[<<]")

                    self._main.put_at(addr, "-]")

                    # makes: ..., v[N-2], 1, v[N-1], *n_range-1, 0, 0, 0, 0
                    self._main.put(">" * self.offset() +
                                   ">>[>>]>>[<<<<+>>>>-]<<<<--")

                    # makes: ..., v[N-n_range], *0, v[N-n_range+1], 1, v[N-n_range+2], 1, 0, 0, 0, 0
                    self._main.put("[[<<+>>-]+<<--]")

                    # makes: ..., 0, *0, v[N-n_range+1], 1, v[N-n_range+2], 1, v[N-n_range], 0, 0, 0
                    self._main.put("<[>>>[>>]<+<[<<]<-]>")

                    # makes: ..., v[N-n_range+1], 1, v[N-n_range+2], 1, v[N-n_range], 1, 0, *0
                    self._main.put("+[>[<<+>>-]>]")

                    self._main.put("<<[<<]" + "<" * self.offset())

                    self._main.put_at(addr, "]]")

                    if sign != "-":
                        self._main.put_move(tmp, [f"+#{addr}"])

                    return

                if self._main.is_val(arg):
                    n = self._main.valueof(arg)

            self.put_juggling_rot(n, m, first=True, last=True)

            return

        if name == "@over":
            if len(args) > 1:
                raise Exception(f"[stk:@over/{len(args)}] is not implemented")

            m = self._main.valueof(args[0]) if len(args) > 0 else 1

            self.put_juggling_over(m, first=True, last=True)

            return

        if name in ["@inc", "@dec"]:
            self.put_juggling_inc(name == "@dec", first=True, last=True)

            return

        if name == "@juggle":
            if len(args) == 0:
                raise Exception(f"[stk:@juggle/0] is not implemented")

            self.put_juggling_juggle(args, first=True, last=True)

            return

        raise Exception(f"wnknown ins: {name} {args}")
Beispiel #7
0
    def put(self, ins_name: str, args: list, tmps: List[int]):
        if ins_name == "init":
            return

        if ins_name == "clean":
            self.put_clean(args)
            return

        if ins_name == "@clear":
            self.mem2_clean(args)
            return

        if (len(args) < 2 and ins_name in [
                "@set", "@w_copy", "@w_move", "@w_copy", "@w_copyadd",
                "@w_copysub", "@w_move", "@w_moveadd", "@w_movesub", "@r_copy",
                "@r_copyadd", "@r_copysub", "@r_move", "@r_moveadd",
                "@r_movesub"
        ]):
            raise Exception(f"error: {ins_name} {args}")

        # aliases
        if ins_name in ["@w_copy", "@w_move"]:
            if self._main.is_val(args[0]):
                ins_name = "@set"

        if ins_name in ["@w_copyadd", "@w_copysub"]:
            sign = "+" if ins_name == "@w_copyadd" else "-"
            ins_name = "@w_copy"
            args = [args[0]] + [sign + x for x in args[1:]]

        if ins_name in ["@w_moveadd", "@w_movesub"]:
            sign = "+" if ins_name == "@w_moveadd" else "-"
            ins_name = "@w_move"
            args = [args[0]] + [sign + x for x in args[1:]]

        if ins_name in ["@r_copyadd", "@r_copysub"]:
            sign = "+" if ins_name == "@r_copyadd" else "-"
            ins_name = "@r_copy"
            args = [args[0]] + [sign + x for x in args[1:]]

        if ins_name in ["@r_moveadd", "@r_movesub"]:
            sign = "+" if ins_name == "@r_moveadd" else "-"
            ins_name = "@r_move"
            args = [args[0]] + [sign + x for x in args[1:]]

        if ins_name == "@set":
            if self._main.is_var(args[0]):
                raise Exception("[mem:@set var ...out] is not implemented")

            value = self._main.valueof(args[0])

            for dst in args[1:]:
                dst_sign, dst = separate_sign(dst)

                if self._main.is_val(dst):
                    idx = self._main.valueof(dst)
                    dst_addr = self.offset(idx * 2 + 1)

                    self._main.put_set(value, [f"{dst_sign}#{dst_addr}"])
                elif self._main.is_var(dst):
                    dst_addr = self._main.addressof(dst)
                    tmp = self._main.get_nearest_tmp(tmps, [self.offset()])

                    self._main.put_copy(dst_addr, [f"+#{self.offset(2)}"])

                    self._main.put(">" * self.offset())
                    self._main.put(""">>[[>>+<<-]+>>-]<""")

                    self._main.put_set(value, f"{dst_sign}#0")

                    self._main.put("""<[-<<]""")
                    self._main.put("<" * self.offset())

            return

        if ins_name in ["@w_move", "@w_copy"]:
            if not self._main.is_var(args[0]):
                raise Exception(
                    f"[mem:{ins_name} val ...out] is not implemented")

            addr = self._main.addressof(args[0])

            if ins_name == "@w_copy":
                self._main.put_copy(addr, [f"+#{self.offset(4)}"])
            else:
                self._main.put_move(addr, [f"+#{self.offset(4)}"])

            out_vars = args[1:]
            tmp = self._main.get_nearest_tmp(tmps, [addr])

            for i in range(len(out_vars)):
                name = out_vars[i]
                sign, name = separate_sign(name)

                if self._main.is_var(name):
                    dst_addr = self._main.addressof(name)

                    self._main.put_copy(dst_addr, [f"+#{self.offset(2)}"])

                    # for next destination
                    if i < len(out_vars) - 1:
                        self._main.put_copy(self.offset(4),
                                            [f"+#{self.offset()}"])

                    self._main.put(">" * self.offset())
                    self._main.put(""">>[->>[>>+<<-]<<[>>+<<-]+>>]""")
                    if sign == "":
                        self._main.put("""<[-]>""")
                    self._main.put(""">>[<<<""")
                    self._main.put("-" if sign == "-" else "+")
                    self._main.put(""">>>-]<<<<[-<<]""")
                    self._main.put("<" * self.offset())

                    if i < len(out_vars) - 1:
                        self._main.put_move(tmp, [f"+#{self.offset(4)}"])

                    continue

                if self._main.is_val(name):
                    dst_idx = self._main.valueof(name)

                    self._main.put_at(self.offset(4), "[")
                    self._main.put_at(self.offset(1 + dst_idx * 2), "+")

                    if i + 1 < len(out_vars):
                        self._main.put_at(self.offset(2), "+")

                    self._main.put_at(self.offset(4), "-]")

                    if i + 1 < len(out_vars):
                        self._main.put_move(self.offset(2),
                                            [f"+#{self.offset(4)}"])

                    continue

            return

        if ins_name in ["@r_move", "@r_copy"]:
            src = args[0]

            if len(list(filter(self._main.is_var, args[1:]))) != len(args[1:]):
                raise Exception(
                    f"unknown instruction: [mem:{ins_name}] with non-variable destinations"
                )

            # static addressing
            if self._main.is_val(src):
                idx = self._main.valueof(src)
                addr = self.offset(idx * 2 + 1)

                if ins_name == "@r_copy":
                    self._main.put_copy(addr, args[1:])
                else:
                    self._main.put_move(addr, args[1:])
            elif self._main.is_var(src):
                idx_addr = self._main.addressof(src)

                self._main.put_copy(idx_addr, [f"+#{self.offset(2)}"])

                self._main.put(">" * self.offset())
                self._main.put(""">>[[>>+<<-]+>>-]""")
                if ins_name == "@r_copy":
                    self._main.put("""<[>>>+<<<-]>>>[<<+<+>>>-]<<""")
                else:
                    self._main.put("""<[>+<-]>""")
                self._main.put("""<<[->>>>[<<+>>-]<<<<<<]>>>>[<<+>>-]<<<<""")
                self._main.put("<" * self.offset())

                self._main.put_move(self.offset(2), args[1:])

            return

        raise Exception(f"error unknown: {ins_name} {args}")