Module refinery.lib.scripts.xlm.references

The resolution of the reference nodes of the formula model against the cell a formula sits in: the cursor of the running engine turns the offsets of an R1C1-relative reference into absolute positions and the corners of a range into the cells it spans, and the pending positions of a run — the branches a partial IF holds, the loops WHILE and FOR.CELL open, and the calls the run returns to — carry the cursors they continue from.

Expand source code Browse git
"""
The resolution of the reference nodes of the formula model against the cell a formula sits in:
the cursor of the running engine turns the offsets of an R1C1-relative reference into absolute
positions and the corners of a range into the cells it spans, and the pending positions of a
run — the branches a partial `IF` holds, the loops `WHILE` and `FOR.CELL` open, and the calls
the run returns to — carry the cursors they continue from.
"""
from __future__ import annotations

import enum

from typing import Callable, Iterator, NamedTuple

from refinery.lib.excel.formula.model import XlA1Reference, XlR1C1Reference
from refinery.lib.scripts.xlm.values import XlmReference, XlmValue


class XlmArrival(enum.Enum):
    """
    How the engine reached the cell of the step it runs: by the jump a command asked for, by
    the row fall-through or the continuation below the cell a return hands its value to, by
    resuming a branch of a partial `IF` or the anchor a run or a call starts at, or by the
    replay of a false branch onto the marker of its block. A marker that carries an arm — an
    `ELSE`, or an `ELSE.IF` that names a condition — runs it for a jump and for a replay, and
    skips to the `END.IF` of the block for a fall — an arm that ran to its end, or the cell
    below one a macro call returned to — and for a resume, which an empty true arm and an
    anchor a run or a call starts at arrive by.
    """

    JUMP = 0
    FALL = 1
    RESUME = 2
    REPLAY = 3


class XlmCursor(NamedTuple):
    """
    The cell the engine is currently evaluating: the sheet it sits on with its one-based row
    and column. The relative references of the formula in this cell resolve against it.
    """

    sheet: str
    row: int
    col: int

    def reference(self) -> XlmReference:
        """
        The address of the cursor's own cell.
        """
        return XlmReference(None, self.row, self.col)


class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None


class XlmLoop:
    """
    One `WHILE` or `FOR.CELL` loop on the loop stack: the cursor of the cell that heads it, the
    indentation the loop started at — the `NEXT` that pairs with it restores it, so every pass
    of the body starts at the same indentation, whatever the blocks the body left open —
    whether it still holds — a `WHILE` loop holds when its condition is true, a `FOR.CELL` loop
    until its range runs out, and a loop the engine opened while it skipped the body of
    another never holds — and for a `FOR.CELL`, the addresses of its range with the position
    of the next one. The engine skips the body of every loop that does not hold.
    """

    def __init__(
        self,
        cursor: XlmCursor,
        holds: bool = False,
        cells: tuple[XlmReference, ...] | None = None,
        base: int = 0,
    ):
        self.cursor = cursor
        self.holds = holds
        self.cells = cells
        self.base = base
        self.position = 0

    def advance(self) -> XlmReference | None:
        """
        The next address of a `FOR.CELL` range, or `None` once the range ran out.
        """
        if self.cells is None or self.position >= len(self.cells):
            return None
        reference = self.cells[self.position]
        self.position += 1
        return reference

    def copy(self) -> XlmLoop:
        """
        A copy of the loop that later iterations of the original leave as it is.
        """
        loop = XlmLoop(self.cursor, self.holds, self.cells, self.base)
        loop.position = self.position
        return loop


class XlmReturnSlot:
    """
    The entry a macro call inside an expression leaves on the call stack: the value the
    subroutine returns lands here rather than in a cell, and the run of the subroutine ends
    with it.
    """

    def __init__(self):
        self.value: XlmValue | None = None


class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None


def resolve_reference(
    node: XlA1Reference | XlR1C1Reference,
    cursor: XlmCursor,
) -> XlmReference:
    """
    The address a reference node names, resolved against the cursor. The numbers of an A1
    reference are absolute positions already; the number of a relative axis of an R1C1
    reference is an offset from the cursor on that axis. A reference qualified by a 3-D span
    of two sheets names the first sheet of the span.
    """
    if isinstance(node, XlR1C1Reference):
        row = cursor.row + node.row if node.relative_row else node.row
        col = cursor.col + node.col if node.relative_col else node.col
    else:
        row = node.row
        col = node.col
    sheet = node.sheets[0] if node.sheets else None
    return XlmReference(sheet, row, col)


#: How many addresses a range walk yields between two runs of the guard a caller passes, so
#: that a walk over a rectangle the workbook barely fills still answers to the run.
_GUARD_YIELDS = 4096


def expand_range(
    top_left: XlmReference,
    bottom_right: XlmReference,
    guard: Callable[[], None] | None = None,
) -> Iterator[XlmReference]:
    """
    Every cell address of the rectangle two corners span, in row-major order. The sheet of
    each address is the sheet of the top left corner. The guard a caller passes runs every so
    many addresses, so that a walk over a rectangle the workbook barely fills still answers to
    the deadline of the run.
    """
    row_min = min(top_left.row, bottom_right.row)
    row_max = max(top_left.row, bottom_right.row)
    col_min = min(top_left.col, bottom_right.col)
    col_max = max(top_left.col, bottom_right.col)
    walked = 0
    for row in range(row_min, row_max + 1):
        for col in range(col_min, col_max + 1):
            walked += 1
            if guard is not None and not walked % _GUARD_YIELDS:
                guard()
            yield XlmReference(top_left.sheet, row, col)

Functions

def resolve_reference(node, cursor)

The address a reference node names, resolved against the cursor. The numbers of an A1 reference are absolute positions already; the number of a relative axis of an R1C1 reference is an offset from the cursor on that axis. A reference qualified by a 3-D span of two sheets names the first sheet of the span.

Expand source code Browse git
def resolve_reference(
    node: XlA1Reference | XlR1C1Reference,
    cursor: XlmCursor,
) -> XlmReference:
    """
    The address a reference node names, resolved against the cursor. The numbers of an A1
    reference are absolute positions already; the number of a relative axis of an R1C1
    reference is an offset from the cursor on that axis. A reference qualified by a 3-D span
    of two sheets names the first sheet of the span.
    """
    if isinstance(node, XlR1C1Reference):
        row = cursor.row + node.row if node.relative_row else node.row
        col = cursor.col + node.col if node.relative_col else node.col
    else:
        row = node.row
        col = node.col
    sheet = node.sheets[0] if node.sheets else None
    return XlmReference(sheet, row, col)
def expand_range(top_left, bottom_right, guard=None)

Every cell address of the rectangle two corners span, in row-major order. The sheet of each address is the sheet of the top left corner. The guard a caller passes runs every so many addresses, so that a walk over a rectangle the workbook barely fills still answers to the deadline of the run.

Expand source code Browse git
def expand_range(
    top_left: XlmReference,
    bottom_right: XlmReference,
    guard: Callable[[], None] | None = None,
) -> Iterator[XlmReference]:
    """
    Every cell address of the rectangle two corners span, in row-major order. The sheet of
    each address is the sheet of the top left corner. The guard a caller passes runs every so
    many addresses, so that a walk over a rectangle the workbook barely fills still answers to
    the deadline of the run.
    """
    row_min = min(top_left.row, bottom_right.row)
    row_max = max(top_left.row, bottom_right.row)
    col_min = min(top_left.col, bottom_right.col)
    col_max = max(top_left.col, bottom_right.col)
    walked = 0
    for row in range(row_min, row_max + 1):
        for col in range(col_min, col_max + 1):
            walked += 1
            if guard is not None and not walked % _GUARD_YIELDS:
                guard()
            yield XlmReference(top_left.sheet, row, col)

Classes

class XlmArrival (*args, **kwds)

How the engine reached the cell of the step it runs: by the jump a command asked for, by the row fall-through or the continuation below the cell a return hands its value to, by resuming a branch of a partial IF or the anchor a run or a call starts at, or by the replay of a false branch onto the marker of its block. A marker that carries an arm — an ELSE, or an ELSE.IF that names a condition — runs it for a jump and for a replay, and skips to the END.IF of the block for a fall — an arm that ran to its end, or the cell below one a macro call returned to — and for a resume, which an empty true arm and an anchor a run or a call starts at arrive by.

Expand source code Browse git
class XlmArrival(enum.Enum):
    """
    How the engine reached the cell of the step it runs: by the jump a command asked for, by
    the row fall-through or the continuation below the cell a return hands its value to, by
    resuming a branch of a partial `IF` or the anchor a run or a call starts at, or by the
    replay of a false branch onto the marker of its block. A marker that carries an arm — an
    `ELSE`, or an `ELSE.IF` that names a condition — runs it for a jump and for a replay, and
    skips to the `END.IF` of the block for a fall — an arm that ran to its end, or the cell
    below one a macro call returned to — and for a resume, which an empty true arm and an
    anchor a run or a call starts at arrive by.
    """

    JUMP = 0
    FALL = 1
    RESUME = 2
    REPLAY = 3

Ancestors

  • enum.Enum

Class variables

var JUMP

The type of the None singleton.

var FALL

The type of the None singleton.

var RESUME

The type of the None singleton.

var REPLAY

The type of the None singleton.

class XlmCursor (sheet, row, col)

The cell the engine is currently evaluating: the sheet it sits on with its one-based row and column. The relative references of the formula in this cell resolve against it.

Expand source code Browse git
class XlmCursor(NamedTuple):
    """
    The cell the engine is currently evaluating: the sheet it sits on with its one-based row
    and column. The relative references of the formula in this cell resolve against it.
    """

    sheet: str
    row: int
    col: int

    def reference(self) -> XlmReference:
        """
        The address of the cursor's own cell.
        """
        return XlmReference(None, self.row, self.col)

Ancestors

  • builtins.tuple

Instance variables

var sheet

Alias for field number 0

Expand source code Browse git
class XlmCursor(NamedTuple):
    """
    The cell the engine is currently evaluating: the sheet it sits on with its one-based row
    and column. The relative references of the formula in this cell resolve against it.
    """

    sheet: str
    row: int
    col: int

    def reference(self) -> XlmReference:
        """
        The address of the cursor's own cell.
        """
        return XlmReference(None, self.row, self.col)
var row

Alias for field number 1

Expand source code Browse git
class XlmCursor(NamedTuple):
    """
    The cell the engine is currently evaluating: the sheet it sits on with its one-based row
    and column. The relative references of the formula in this cell resolve against it.
    """

    sheet: str
    row: int
    col: int

    def reference(self) -> XlmReference:
        """
        The address of the cursor's own cell.
        """
        return XlmReference(None, self.row, self.col)
var col

Alias for field number 2

Expand source code Browse git
class XlmCursor(NamedTuple):
    """
    The cell the engine is currently evaluating: the sheet it sits on with its one-based row
    and column. The relative references of the formula in this cell resolve against it.
    """

    sheet: str
    row: int
    col: int

    def reference(self) -> XlmReference:
        """
        The address of the cursor's own cell.
        """
        return XlmReference(None, self.row, self.col)

Methods

def reference(self)

The address of the cursor's own cell.

Expand source code Browse git
def reference(self) -> XlmReference:
    """
    The address of the cursor's own cell.
    """
    return XlmReference(None, self.row, self.col)
class XlmFrame (cursor, branch, snapshot, indent, desc)

One branch of a partial IF that has not run yet: the cell the branch runs at — its cursor is the base the relative references of the branch resolve against — the expression the branch runs instead of the cell's own formula, the snapshot a false branch rolls back to, the indentation the branch reports, and the label the first step of the branch carries. A frame that replays a false branch onto the marker of its block, and any other frame — the branch of a partial IF, or the anchor a run or a call starts at — is a resume: the arrival a pop derives from the frame follows this rule, it is not an inference about where the run came from.

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None

Ancestors

  • builtins.tuple

Instance variables

var cursor

Alias for field number 0

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None
var branch

Alias for field number 1

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None
var snapshot

Alias for field number 2

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None
var indent

Alias for field number 3

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None
var desc

Alias for field number 4

Expand source code Browse git
class XlmFrame(NamedTuple):
    """
    One branch of a partial `IF` that has not run yet: the cell the branch runs at — its cursor
    is the base the relative references of the branch resolve against — the expression the
    branch runs instead of the cell's own formula, the snapshot a false branch rolls back to,
    the indentation the branch reports, and the label the first step of the branch carries. A
    frame that replays a false branch onto the marker of its block, and any other frame — the
    branch of a partial `IF`, or the anchor a run or a call starts at — is a resume: the
    arrival a pop derives from the frame follows this rule, it is not an inference about where
    the run came from.
    """

    cursor: XlmCursor
    branch: object | None
    snapshot: XlmSnapshot | None
    indent: int
    desc: str

    @property
    def replays(self) -> bool:
        """
        Whether a pop of the frame replays a false branch onto the marker of its block: it
        rolls a snapshot back and runs the cell it resumes at as its own formula.
        """
        return self.snapshot is not None and self.branch is None
var replays

Whether a pop of the frame replays a false branch onto the marker of its block: it rolls a snapshot back and runs the cell it resumes at as its own formula.

Expand source code Browse git
@property
def replays(self) -> bool:
    """
    Whether a pop of the frame replays a false branch onto the marker of its block: it
    rolls a snapshot back and runs the cell it resumes at as its own formula.
    """
    return self.snapshot is not None and self.branch is None
class XlmLoop (cursor, holds=False, cells=None, base=0)

One WHILE or FOR.CELL loop on the loop stack: the cursor of the cell that heads it, the indentation the loop started at — the NEXT that pairs with it restores it, so every pass of the body starts at the same indentation, whatever the blocks the body left open — whether it still holds — a WHILE loop holds when its condition is true, a FOR.CELL loop until its range runs out, and a loop the engine opened while it skipped the body of another never holds — and for a FOR.CELL, the addresses of its range with the position of the next one. The engine skips the body of every loop that does not hold.

Expand source code Browse git
class XlmLoop:
    """
    One `WHILE` or `FOR.CELL` loop on the loop stack: the cursor of the cell that heads it, the
    indentation the loop started at — the `NEXT` that pairs with it restores it, so every pass
    of the body starts at the same indentation, whatever the blocks the body left open —
    whether it still holds — a `WHILE` loop holds when its condition is true, a `FOR.CELL` loop
    until its range runs out, and a loop the engine opened while it skipped the body of
    another never holds — and for a `FOR.CELL`, the addresses of its range with the position
    of the next one. The engine skips the body of every loop that does not hold.
    """

    def __init__(
        self,
        cursor: XlmCursor,
        holds: bool = False,
        cells: tuple[XlmReference, ...] | None = None,
        base: int = 0,
    ):
        self.cursor = cursor
        self.holds = holds
        self.cells = cells
        self.base = base
        self.position = 0

    def advance(self) -> XlmReference | None:
        """
        The next address of a `FOR.CELL` range, or `None` once the range ran out.
        """
        if self.cells is None or self.position >= len(self.cells):
            return None
        reference = self.cells[self.position]
        self.position += 1
        return reference

    def copy(self) -> XlmLoop:
        """
        A copy of the loop that later iterations of the original leave as it is.
        """
        loop = XlmLoop(self.cursor, self.holds, self.cells, self.base)
        loop.position = self.position
        return loop

Methods

def advance(self)

The next address of a FOR.CELL range, or None once the range ran out.

Expand source code Browse git
def advance(self) -> XlmReference | None:
    """
    The next address of a `FOR.CELL` range, or `None` once the range ran out.
    """
    if self.cells is None or self.position >= len(self.cells):
        return None
    reference = self.cells[self.position]
    self.position += 1
    return reference
def copy(self)

A copy of the loop that later iterations of the original leave as it is.

Expand source code Browse git
def copy(self) -> XlmLoop:
    """
    A copy of the loop that later iterations of the original leave as it is.
    """
    loop = XlmLoop(self.cursor, self.holds, self.cells, self.base)
    loop.position = self.position
    return loop
class XlmReturnSlot

The entry a macro call inside an expression leaves on the call stack: the value the subroutine returns lands here rather than in a cell, and the run of the subroutine ends with it.

Expand source code Browse git
class XlmReturnSlot:
    """
    The entry a macro call inside an expression leaves on the call stack: the value the
    subroutine returns lands here rather than in a cell, and the run of the subroutine ends
    with it.
    """

    def __init__(self):
        self.value: XlmValue | None = None
class XlmSnapshot (journal, call_stack, loops, active_cell)

The state a false branch of a partial IF starts from: the journal position the writes of the true branch roll back to, and the state of the run the journal does not hold — the call stack, the open loops with their positions, and the cell the program selected.

Expand source code Browse git
class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None

Ancestors

  • builtins.tuple

Instance variables

var journal

Alias for field number 0

Expand source code Browse git
class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None
var call_stack

Alias for field number 1

Expand source code Browse git
class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None
var loops

Alias for field number 2

Expand source code Browse git
class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None
var active_cell

Alias for field number 3

Expand source code Browse git
class XlmSnapshot(NamedTuple):
    """
    The state a false branch of a partial `IF` starts from: the journal position the writes of
    the true branch roll back to, and the state of the run the journal does not hold — the
    call stack, the open loops with their positions, and the cell the program selected.
    """

    journal: int
    call_stack: tuple[XlmCursor | XlmReturnSlot, ...]
    loops: tuple[XlmLoop, ...]
    active_cell: XlmReference | None