Fabris is a stack-oriented, concatenative language designed to be simple, friendly and efficient.
Fabris is inspired by Forth, Python, Joy, DSSP, Factor, COBOL and Unix.
Current Fabris version is unstable and is intended only for experimental use.
The name comes from first leters of main components of Fabris VM: (F)ixed point base, (A)uxiliary pointers, (B)ase pointer, (R)eturn stack, (I)nstruction pointer, (S)tack.
Similarity with the name of Italian fencing master Salvator Fabris is not a coincidence.
Basic expressions:
"the answer is " print 40 2 add dot
Line comment:
"hello world" print -- the rest of line is ignored
-- this line is also ignored
Stream comment:
4 10 mul (this is a comment) 1 1 add add ( this also )
Conditional statement:
if 10 equal then "equals ten" print end
Conditional statement with alternative:
if 10 or-more then "ten or more" else "nine or less" end
Conditional statement with multiple branches:
10 or-more then "ten or more" else
8 or-less then "eight or less" else
"exactly nine" end
Counted loop:
3 times
"Hastur! " print
loop
Universal loop:
do
scan-for-enemies
if enemy then
break end
patrol-area
loop
exterminate exterminate exterminate
New function definition:
def square dup mul ret
New function definition with named parameters:
def energy in h m v out 1 (e)
m v v mul mul 2 div -- kinetic energy
h m g mul mul -- potential energy
add (e) ret
Testing:
test 40 2 add 42 ok
test 10 dup inc 11 ok 10 ok
Lambda expressions:
[ " world" print ] [ "hello" print ] call call -- prints "hello world"
Recurrency:
def print-stack
if depth then dot drop print-stack end ret
List reduction:
[ 1 3 5 7 9 ] list [ add ] fold -- sum all elements
Include module:
use string
do each-word
print
loop
Top-down programming:
def c b ret
def b a ret
def a 42 ret
c dot -- prints 42
Fixed point arithmetics:
1000 tof
3.14159 2 mul fdot -- prints 6.282
3.14159 2.0 fmul fdot -- prints 6.282
3141 2 mul fdot -- prints 6.282
3141 2000 fmul fdot -- prints 6.282
name effect comments core swap (ab--ba) swap the two top stack items yes dup (a--aa) duplicate the top stack item yes drop (a--) discard the top item yes depth (--n) push number of items on stack yes tor (a--)(=a) move the top item to the return stack yes r (--x)(a=) move the top item of return stack to stack yes tof (a--) move the top item to the fixed point base yes
name effect comments core add sub mul div mod inc dec abs
(ab--x) (ab--x) (ab--x) (ab--x) (ab--x) (a--x) (a--x) (a--x)
add two top items (a+b) subtract top item from second item (a-b) multiply two top items (a*b) divide second item by top item (a/b) reminder of dividing second item by top item (a%b) increment the top item (a+1) decrement the top item (a-1) return absolute value (abs(a))
yes
neg (a--x) change the sign (-a) yes fmul (ab--x) fixed point - multiply two top items (a*b) opt. fdiv (ab--x) fixed point - divide of second item by top item (a/b) opt.
name effect comments core zero (a--ax) check if a == 0 yes negative positive less or-less more or-more equal within
(a--ax) (a--ax) (ab--ax) (ab--ax) (ab--ax) (ab--ax) (ab--ax) (nab--nx)
check if a < 0 check if a > 0 check if a < b check if a <= b check if a > b check if a >= b check if a == b check if a <= n <= b
yes
name effect comments core and (ab--x) and two top items (a&b) yes or (ab--x) or two top items (a|b) yes xor (ab--x) xor two top items (a^b) yes not (a--x) logical negation (!a) yes
name effect comments core emit (c--) write single character to standard output yes take (--c) read single character from standard input
opt. untake print
(c--) (an--)
unread single character from standard input
prints n characters at address a
opt.
argc (--x) returns number of program arguments opt. argv dot fdot udot xdot write
(a--xn) (a--a) (a--a) (a--a) (a--a) (anf--)
returns address and length of argument number a prints top item as number followed by space prints top item as fixed point number followed by space prints top item as unsigned number followed by space prints top item as hexadecimal number followed by a space write n characters at address a to file with descriptor f
opt.
name effect comments core def X (--) define new word X yes ret (--) return from definition yes macro X (--) define new macro X opt. mend (--) end macro definition opt. then (x--) execute following code if x is not zero yes else (--) branch for the then word (optional) yes end (--) finish then/else sequence yes do (=x) start of unconditioned loop yes break (x=) break out of the current loop yes loop (--) repeat loop yes times (x--)(=i) start of counted loop yes "X" (--an) start/end of a string, places addres and length on the stack yes [ (--) start of anonymous code block yes ] (--r) end of anonymous code block, put reference to it on the stack yes _ (x--) capture stack item into code block, right to left yes call (r--) call code block referenced by r yes yield (--r) return and push reference to next instruction yes 'X' (--c) start/end of a char yes X (--x) place integer X in the stack yes use X (--) use module X yes dyn X (--) declare word X as dynamic, that can change at the runtime yes ref X (--r) put reference to word X on the stack yes as X (r--) redefine dynamic word X as code reference r yes in X... (--) define names of input parameters, set input register yes out X (--) define number of output parameters yes
name effect comments core nop (--) do nothig clock (--x) returns number of microseconds since the program was launched opt. halt (--) stops program execution yes peek (a--c) get character (unsigned) from address a opt. poke ok trace sprint
(ca--) (ab--) (--) (--)
set character at addres a to c halt and print error if two top items are not equal prints information about VM state - stack, ip, ... prints stack
opt.
name effect comments core shl shr ushr inv
(ab--x) (ab--x) (ab--x) (a--x)
shift a left by b bits (a<<b) shift a right by b bits (a>>b) shift unsigned a right by b bits (a>>b) invert all bits (~a)
name effect comments core over nip tuck rot unrot yank mark count cut chars bytes ndrop dup2 swap2 drop2 pick reverse reverse2
(ab--aba) (ab--b) (ab--bab) (abc--bca) (abc--cab) (--a)(ab=b) (--)(=n) (--x)(n=) (?--)(n=) (n--x) (n--x) (?n--) (ab--abab) (abxy--xyab) (ab--) (n--x) (?n--?n) (?n--?n)
push the second item on top discard the second item insert copy of top item before second item rotate the third item to the top unrotate the top to the third item remove second item from return stack and place it on stack mark stack location (push stack depth to return stack) push number of items after the mark, unmark stack drop items after marked stack location calculate number of items for storing n characters calculate number of items for storing n bytes discard n top items (not counting n) duplicate top pair swap two pairs drop pair pick nth stack item from top (not counting n) reverse order of n top stack items reverse order of n top stack pairs
name effect comments core hash split strip lstrip rstrip substr index
(an--x) (an--rxfy) (an--bx) (an--bx) (an--bx) (ankc--anbc) (anbm--anx)
return hash value for given string (x65599 algorithm) return first word from a string and the rest of the string return string without leading and trailing whitespaces return string without leading whitespaces return string without trailing whitespaces return substring of c characters starting at b return index of bm string within an string, or -1
char upper lower
(ani--anx) (an--an) (an--an)
- return character at index i in given string
destructive change to lowercase destructive change to uppercase
yes?
name effect comments begins (anbm--anx) return true if an string begins with bm string ends (anbm--anx) return true if an string ends with bm string contains (anbm--anx) return true if an string contains bm string
arein (anbm--anx) return true if an string contains any character from bm string
haschar (anc--anx) return true if an string contains character c
name effect comments min (ab--x) return lower value max (ab--x) return greater value limit (xab--y) limit value of x (aka clamp), if x<a then a, if x>b then b divmul (abc--x) ... (a/b*c)
muldiv (abc--x) ... (a*b/c)
muldivmod (abc--xr) ... (a*b/c, a*b%c)
divmod (ab--xr) ... (a/b, a%b)
Different dispatching techniques results in different efficiency depending on the CPU architecture1.
Fabris offers multiple dispatching strategies in the single VM.
benchmark N goto switch call direct repl.sw c.call c.inl python ENV VM cfg nested-loops 16 508
862
990
391
518
489
464
11671
E.1
C.0
nested-loops 16 398
882
934
287
546
400
369
7142
E.1
C.1
fibonacci 32 867
1043
1183 665
904
520
485
6037
E.1
C.0
fibonacci 32 620
1017
1001 501
787
506
401
4524
E.1
C.2
Programs are based on Benchmark Tests from http://dada.perl.it/shootout/.
Times are given in milliseconds for best of 5 runs. More benchmarks and results coming soon.
- Environment:
- E.1 - Intel Atom N570 1.66 @ 1.0 GHz, gcc 4.8.4, -O3 -fomit-frame-pointer
- VM config:
- C.0 - Default Fabris config. Python 3.5
- C.1 - Fabris registers: sp on ESI, ip on EDI. Python 2.7
- C.2 - Fabris registers: sp on ESI, ip on EDI, rp on EBX. Python 2.7
Related articles: