Dirac

dirac (Delightfully Intricate Reasonably Amazing Calculator) is a programming language inspired by FALSE created by Palaiologos in early 2022. The main goal of this esoteric language was creating an obfuscated, stack-based language which can express imperative algorithms in a concatenative fashion.
=== Operations ===
Numeric literals push content to the stack. For example, 2 3+ pushes 2 and 3 and adds them, so the number 5 ends up on the stack. It is possible to push the ASCII code of a character on the stack using a single quote, so that 'A will push 65 (the ASCII code of A). String literals can be pushed on the stack using double quotes. Individual characters are pushed from the back, and the string is always terminated with a zero. Hexadecimal constants can be loaded using H. For instance, H3FF will load 0x3FF on the stack.
Reference to a variable (to be used with : or ;) can be pushed using the variable's name. For instance, var: will load the value of var on the stack. dirac is lexically scoped, so variables defined in the inner scope don't affect the outer scope (if it exists). Lambda expressions are introduced using [] and they push a reference to themselves on the stack.
The list of commands follows:
- + - a b -- a+b - addition
- - - a b -- a-b - subtraction
- * - a b -- a*b - multiplication
- / - a b -- a/b - division
- % - a b -- a%b - modulus
- # - a -- a a - duplicating the top of the stack
- $ - a -- - popping the top of the stack
- I. - -- c - character input
- I: - -- i - integer input
- I, - c -- - character output
- I; - i -- - integer output
- I< - -- i - hexadecimal integer input
- I> - i -- - hexadecimal integer output
- M< - sz -- ptr - allocating a block of memory of size sz and pushing a pointer to it
- M> - ptr -- - freeing memory pointed by ptr
- M. - ptr a -- c - reading a byte of memory at address a from ptr (byte-aligned)
- M: - ptr a -- i - reading a qword of memory at address a from ptr (qword-aligned)
- M, - ptr a c -- - writing byte c at address a in ptr (byte-aligned)
- M; - ptr a i -- - writing qword i at address a in ptr (qword-aligned)
- B| - a b -- a|b - bit-wise OR
- B& - a b -- a&b - bit-wise AND
- B^ - a b -- a^b - bit-wise XOR
- B~ - a -- ~a - bit-wise NEG
- B< - a b -- a< - bit-wise SHL
- B> - a b -- a>>b - bit-wise SHR
- C> - a b -- a>b - greater-than check
- C< - a b -- a - lesser-than check
- C>= - a b -- a>=b - greater-or-equal check
- C<= - a b -- a<=b - lesser-or-equal check
- C= - a b -- a==b - equality check
- C! - a b -- a!=b - inequality check
- @ - a_n a_n-1 ... a1 a0 i -- a_i - copy the i-th element of the stack starting from the top
- ^ - x y -- y x - two-argument rotate
- ` - x y z -- z y x - three-argument rotate
- ! - l -- - execute lambda expression l
- ? - c l -- - execute lambda expression l only if c is truthy.
- ; - v r -- - set the value of variable r to v.
- : - r -- - get the value of variable r.
- ~; - v r -- - set the value of variable r to v in the outermost scope it's defined.
- ~: - r -- - get the value of variable r in the outermost scope it's defined.
- F# - c i -- - execute i as long as executing c yields true (an equivalent of while loop in C).
- F~ - c i -- - execute i at least once as long as executing c yields true (an equivalent of do .. while loop in C).
- F$ - c t f -- - if c is true, execute t and f otherwise.
- F` - -- - exit the program.
- F% - s e t f -- - a range loop from s to e. if s < e, t is added after every iteration. if s > e, t is subtracted after every iteration. on every iteration, pushes the current counter value and calls f.
- D, - -- - print debugging information.
- & - a1 a2 a3 ... an -- a_[b_1] a_[b_2] ... a_[b_m] - arbitrary stack reordering. For instance, &210 rotates three topmost stack elements, while `&111` overwrites the three topmost stack elements with the second to top stack element. 
=== Examples ===
Stack manipulation and basic arithmetics:
2 2 { Pushes two copies of 2 on the stack }
+ { Add them together }
'0+ { Add ASCII(48) turning the result into a digit }
H0F { Push 0xF }
B| { Bit-wise OR }
# { Duplicate }
I; { Print as decimal }
'=I, { Print "=" }
I, { Print as character }
{ The code above prints "63=?", but it could also be written in a more compact way: }
2 2+'0+H0F B|#I;'=I,I,
A factorial function and it's invocation:
[1^1+1^1[*]F%I;]f;10f:! { Displays "3628800" }
A fibonacci function:
[#I;10I,]pf;[0pf:!1pf:!#3@1[$#`+pf:!]F%$$]fib;50fib:!
The following programs are sometimes used to test an implementation of dirac:
[[#0C!][I,]F#$]putstr;"Bitness: "putstr:!1 1[#0C>][1B<^1+^]F#$I;10I,
"Allocating an array, got pointer: 0x"putstr:!256M<#I>10I,
"Performing identity-fill..."putstr:!0 255 1[^#`#M,]F%10I,
"Checking correctness..."putstr:!0 255 1[^#`#`^M.C!["Failed."putstr:!F`]?]F%10I,
"Freeing the array"putstr:!M>10I,
[[#0C!][I,]F#10I,]puts;
"Test 1: General operations"puts:!
2 2+'0+H0F B|#I;'=I,I,10I,
"Test 2: Factorial"puts:!
[1^1+1^1[*]F%I;]f;10f:!10I,
"Test 3: Fibonacci"puts:!
[#I;10I,]pf;[0pf:!1pf:!#3@1[$#`+pf:!]F%$$]fib;20fib:!
"Test 4: Outer scope operations"puts:!
[0a;[[1a~;]!]!a:["Ok"]["Failed"]F$]!puts:!