Uxnbal is a stack effect validator.
Program validation is done at compile-time by comparing a routine's stack effect, against the resulting balance of all stack changes occurring in the routine's code. Words that do not pass the stack-checker are generating a warning, and so essentially this defines a very basic and permissive type system that nevertheless catches some invalid programs and enables compiler optimizations. For more details, see Uxnbal.
The simplest case is when a piece of code does not have any branches or recursion, and merely pushes literals and calls words. The stack effect routines is always known statically from the declaration.
@add-eight ( a -- a+8 ) #0008 ADD JMP2r
Working-stack imbalance of +1, in add-eight.
In the case of branching, each branch is evaluated and if an imbalance occurs inside one of the branches, the branch name is indicated:
@branching ( a* -- c ) LDAk #01 EQU ?&one LDAk #02 EQU ?&two POP2 #ff JMP2r &one ( a* -- c ) POP2 #12 JMP2r &two ( a* -- c d ) ADD JMP2r
Working-stack imbalance of -1, in branching/two.
In the case of a recursion, the validator will use the stack effect instead of repeatedly walking through the body of the routine.
@print-string ( str* -- ) LDAk DUP ?{ POP POP2 JMP2r } emit-letter INC2 !print-string
For loops that exits without affecting the stack depth, a > prefixed label is used as a shorthand to reduce the need for extraneous stack effect definitions in cases where it can be inferred:
@many-times ( a -- ) DUP &>l INC DUP ?&>l POP2 JMP2r
Routines that pull items from the stack beyond their allowed depth will also raise a warning, making the stack effect act a sort of boundary:
@shallow ( a -- ) POP2 JMP2r
Working-stack depth error of 1, in shallow.
Lastly, a runtime specific solution to validate the stack state at any one point during the execution of a program, is to read the System/wst port and compare it against a given stack pointer byte value.
@on-reset ( -> ) #abcd DUP2 .System/wst DEI #05 EQU ?{ #01 .System/debug DEO } BRK
incoming: uxntal software