The Machines · Runtime stack

cuttle

The runtime stack — machines/cuttle.shoddy

the cuttle machine's icon

Summary

cuttle turns Shoddy's own stack into a value a program can hold. A stack is a pile of values where the last one put on is the first one taken off. Ordinarily Dup Swap Rot only exist inside a Def, compiled away before anything runs. This machine gives a mill a heterogeneous runtime stack — heterogeneous meaning mixed kinds: numbers, strings, booleans, lists, quoted programs, pairs, money, matrices, one cell per value — plus the pure algebra over it: push, pop, dup, drop, swap, over, nip, tuck, rot, roll(n), pick(n), depth, clear. It knows nothing about tokens or a dictionary (a lookup table of named words). The interpreter — the program that reads and runs RPN lines (reverse Polish notation, where 2 3 + means 2 + 3) against those — is reckoner, built on top of this.

Nothing here aborts. Every popping word answers a value. An underflow (asking for more cells than the stack holds), a bad level, a kind mismatch — each comes back as an answer, never as a raised error. A stack machine that kills the session on SWAP with one cell on it is unusable for the interactive purpose it exists for.

A Brief History of the Stack

The stack was invented for exactly the job it does here: holding the middle of a calculation while the rest of it happens. Alan Turing's 1945 design for the ACE had subroutine calls that would bury a return address and unbury it afterwards. In 1957 Friedrich Bauer and Klaus Samelson in Munich patented the Kellerprinzip — the "cellar principle" — a store where the last thing put in is the first thing taken out. They invented it so a machine could evaluate a bracketed formula without reading it twice. The cellar turned out to be the most reusable idea in the building. Compilers keep their parse on one. Every running program keeps its calls on one. Whole languages — Forth on two of them, PostScript, the HP calculators — made the stack the visible surface of the language rather than its hidden plumbing. Shoddy's runtime dialect is that tradition, and cuttle is the cellar itself made into a value: not a trick of the compiler's bookkeeping but a thing a program can hold, copy, and hand back.

Why It's Useful

A stack that is only a compiler's bookkeeping cannot be handed to a caller, saved, undone, or driven one line at a time from a form field. Once it is a value — CutPush in, a new Stack out — those jobs get easy. A history is just a list of stacks. Undo is picking an earlier one. A shell can render the top few levels without knowing anything about how they got there. cuttle is that value and nothing else: no tokenizer, no registers, no notion of a word. Everything that turns typed text into calls against this stack lives one layer up, in reckoner.

Where the Name Comes From

Cuttling is the finishing operation that folds a finished piece of cloth back and forth into a layered pile on the cuttling table — lap over lap, the last fold laid resting on top. The last fold laid is the first one lifted back off. That is a last-in-first-out store, described without reaching for a metaphor from computing at all. (The heritage of the name has the rest of the mill.)

User's Guide

Build a stack from the values it should hold, typed in the order they would be pushed — the last one ends up on top:

Include "cuttle.shoddy"

Def Main()
    Let s0 = CutOf({ CutNum(3), CutStr("hi"), CutBool(True) })
    Print(CutDepth(s0))                          ' 3, True on top

    Select Case CutPop(s0)
        Case CutTook(v, s1)
            Print(CutShow(v, CutFmtStd()))       ' True
        Case CutTakeBad(why, s1)
            Print(why)

Every shuffle word answers a variant — a value that says which case happened — rather than the bare stack. The failing case always carries the stack unchanged. A caller can therefore match on success or refusal without a separate check beforehand:

Select Case CutSwap(CutOf({ CutNum(1) }))    ' only one cell — SWAP needs 2
    Case CutDone(s1)
        Print("swapped")
    Case CutOutBad(why, s1)
        Print(why)                            ' "SWAP needs 2, the stack holds 1"

A few things worth remembering:

Word Reference

Building, shuffling, and showing

Building and inspecting

WordDescription
CutNew()The empty stack.
CutOf(values)A stack built from a list of cells, typed order — the last value ends up on top.
CutPush(s, c)c pushed onto s.
CutPop(s)CutTook(v, rest) or, on an empty stack, CutTakeBad(why, s).
CutDepth(s)How many cells s holds.
CutClear(s)The empty stack, whatever s held.

The pure algebra — every one answers rather than aborting when too shallow

WordDescription
CutDup(s)( x -- x x )
CutDrop(s)( x -- )
CutSwap(s)( x y -- y x )
CutOver(s)( x y -- x y x )
CutNip(s)( x y -- y )
CutTuck(s)( x y -- y x y )
CutRot(s)( x y z -- y z x ) — the third cell down comes to the top.
CutRoll(s, n)Move the cell at level n to the top, 1-based from the top; refuses n below 1 or not a whole number.
CutPick(s, n)Copy the cell at level n to the top.

Kinds, format and display

WordDescription
CutKindOf(c)The kind name of a cell — NUMBER STRING BOOLEAN LIST PROGRAM PAIR MONEY MATRIX, or UNKNOWN for a case an older match has not been taught yet.
CutFmtStd()The default display format: mode STD, 0 digits.
CutBound()76 — the column width past which a list or quotation abbreviates.
CutShow(c, f)c rendered as text under format f — numbers per mode and digits, strings quoted, lists and quotations bracketed and abbreviated past CutBound(), money via MoneyFmt, matrices as dimensions plus rows at small sizes.

Equality and arithmetic across kinds

WordDescription
CutEqual(a, b)Structural equality, all the way down; two cells of different kinds are unequal rather than an error.
CutAdd(a, b)( a b -- a+b ) — numbers, money, matrices of one shape, or strings joined; else a CutCalcBad naming both kinds.
CutSub(a, b)( a b -- a-b ) — numbers or money.
CutMul(a, b)( a b -- a*b ) — numbers, matrices, or a matrix scaled by a number.
CutLess(a, b)Whether a orders before b — numbers, strings and money order; the underlying word for < > <= >=.

The Reckoner Seeds

Thirteen files bridge the rest of the standard library into reckoner, the engine built on this stack. Every one of them includes this machine for its value set. None is catalogued in the general machines index: a seed has no bearing on its own, only together with this stack and that engine. See the full seed list on reckoner's own page for what each one bridges.

Who Uses It

UserHow
reckonerThe whole value set and pure algebra every registered word and combinator runs against.

Every reckoner seed listed above also includes this machine, for the value set — not repeated here as thirteen identical rows.

The Machines It Uses

MachineWhy
matrixMatrix is the type CutMat carries; MatAdd, MatMul, Rows and Cols back its arithmetic and display.
moneyMoney is the type CutMoney carries; MoneyAdd, MoneySub and MoneyFmt back its arithmetic and display.
seqPair is the type CutPair carries, and the list plumbing (First, Rest, Prepend, DropN, Taken) implements the stack and its shuffles.
strJoin and the padding words build the abbreviated list and matrix renders.