intro
forthy2is a higher level Forth-remix in C .
method fib (0) {} method fib (1) {} method fib (Int) {-1! copy fib swap -1! fib }
setup
forthy2requires a C 17 – compiler and CMake to build.
$ git clone https: //github.com/codr7/forthy2.git $ cd forthy2 $ mkdir build $ cd build $ cmake .. $ make $ rlwrap ./forthy2 forthy2 Press Return on empty row to evaluate. Empty input clears stack and Ctrl D exits. 42 42
status
Examples from this document, as well astestsandbenchmarks; should do the right thing and run clean in Valgrind. Performance is currently hovering around Python3, I expect that to keep improving for a while.
stacks
copy
repeats the top stack item,
42 copy 42 42
whiledrop
removes it.
1 2 3 drop 1 2
swap
swaps the top two stack items.
1 2 3 swap 1 3 2
$
may be used to simplify and speed up more elaborate stack transformations, the result from evaluating the second part replaces the specified stack suffix.
1 3 5 7 $ (a b c _; b a. c) 3 6
Unknown identifiers signal compile time errors.
1 2 3 $ ( abc; d) Error at row 1, col 15: Unknown id: d
Stack literals are enclosed in parens.
(1 2 3) (1 2 3)
;
may be used to push remaining values on a separate stack.
(1 2 3; 4 5) (1 2 3 (4 5))
Stacks are dynamic and support basic stack operations.
(1 3 5) copy .push 7 (1 3 5 7) copy len (1 3 5 7) 4 drop copy pop (1 3 5) 7
Popping empty stacks returns_
.
() pop _
scopes
forthy2is strictly block scoped, definitions are tied to the containing scope and invisible from the outside.
{let foo 42} foo Error at row 2, col 0: Unknown id: foo
************
BooleansBooleans come in two flavors,T
andF
.
T not F
All values have boolean representations, non-zero integers areT
etc.
42 bool T
and
/or
both pop the first argument off the stack and return the last evaluated value.
T and 42 42
F or 42 42
numbers
Fix points derive their precision from literals.
0. 30 0. 30
Operations preserve left hand precision.
0. 23 0.1 0. 33
dot notation
Methods and macros may be called infix by adding.
between first argument and operation.
6. * 7 42
identity & equality
is
may be used to check if two values share the same memory address,
T. **********************T.is T T
42. is 42 F
while=
returns true if they are equal.
(1 2 3) .=(1 2 3) T
references
Macros and methods support capturing references using&
.
& * [Int Int] Method @ 0x 24 f 59 B0 6 swap 7 swap call 42
lambdas
Scope-references evaluate to anonymous functions.
& {42} Lambda @ 0x 24 f 73 C8 call 42
Pairs
Pairs may be created at read time by prefixing with,
,
, 1 3 , 1 3
or at run time usingpair
;
1.pair 3 , 1 3
and split usingunpair
.
, 1 3 unpair 1 3
branching
if
/else
both take a condition on the stack and a body to execute when the condition is true / false.
42 if 'ok 'ok
0 else 'ok 'ok
iteration
while
evaluates its body until it returns false.
3 while {-1 ! copy} drop 2 1 0
for
pops a sequence from the stack and evaluates its body once for every value. A missing body leaves the entire sequence on the stack unchanged. The following example builds a list of integers.
(3 for _) (0 1 2)
repeat
pops a number from the stack and evaluates its body that many times.
3 repeat 42 42 42 42
transformations
map
takes an input followed by a function as arguments, and returns an iterator for the sequence of values obtained by applying the function to the input.
(1 3 5) .map & 1! Iter @ 0x (CA) for _ 2 4 6
filter
takes an input follows by a predicate as arguments, and returns an iterator for the sequence of input values for which the predicate returns true.
(1 3 5) .filter & {.>2} Filter @ 0x 248 bca0 for _ 3 5
types
type
may be called to get the type of any value.
42 type Int
Nil
only has one value, the missing value.
_ type Nil
A
is the root type, from which all types exceptNil
are derived. The type hierarchy may be queried usingisa
; which returns the direct parent type if any, and_
Otherwise.
Nil.isa A _
Nil: able types may be created by suffixing type names with?
.
Nil.isa A? A?
bindings
let
may be used to bind names to values at compile time.
{ let foo 42 foo } 42
Values are evaluated before bound.
{ let foo {6. * 7} foo } 42
Referencing unbound names signals compile time errors,
{ let foo 42 bar } Error at row 2, col 2: Unknown id: bar
as do attempts to shadow bindings within the same scope,
let foo 1 let foo 3 Error at row 2, col 1: Dup binding: foo
while shadowing within child scopes is permitted.
let foo 1 {let foo 3} foo 1
methods
Any number of methods may use the same name as long as they take the same number of arguments but different types.
method foo (Bool) {1} method foo (Int) {3} foo T 1 foo 42 3
Literal arguments allow dispatching on specific values rather than types.
method foo (42) {5} foo 42 5
Each implementation is bound to its own unique, type-indexed name; and may be called directly.
& foo [Int] Method @ 0x 11216 d0 42 swap call 3
recalling
Lambdas and methods both support forwarding calls without creating additional frames, commonly known as tail call optimization.recall
takes an optional target as argument and forwards the current call. Specifying_
as target calls the current lambda / method recursively. Execution picks up after the current call on return, which is why'done2
is not evaluated in the following example.
method foo (T) {'done1} method foo (A) {drop T recall foo 'done2} 42 foo 'done1
quoting
Any form may be quoted by prefixing with'
.
Literals return themselves as is,
'42 42
while identifiers return symbols,
'let 'let
and scopes return forms.
'{6 7 * } Form @ 0x 2527 cc0
Forms may be turned into lambdas usingcompile
.
'{6 7 * } compile Lambda @ 0x 252 dab0 call 42
Forms may contain placeholders which allows splicing external values.
'{6% * } Form @ 0x 252 DCD0 7 splice Form @ 0x 252 DCD0 compile call 42
time
Time may be created using provided constructors (hours
/mins
/secs
/msecs
/usecs
/nsecs
) and support arithmetics and conversion.
2 hours Time @ 7200000000000 .- {30 mins} Time @ 5400000000000 mins 90
debugging
dump-stack
dumps the current stack to standard output without modifying it.
1 2 3 dump- stack (1 2 3) 1 2 3
check
may be used to trigger informative errors when a condition doesn’t hold.
check {6. * 7.is 41} Error at row 1, col 0: Check failed: {6. * 7 .is 41}
- debug
may be passed on the command line to abort on error.
$ valgrind build / forthy2 -debug forthy2 Press Return on empty row to evaluate. Empty input clears stack and Ctrl D exits. foo terminate called after throwing an instance of 'forthy2 :: ESys' what (): Error at row 1, col 0: Unknown id: foo Process terminating with default action of signal 6 (SIGABRT) at 0x (C) : raise (raise.c: 54) by 0x E) : abort (abort.c: 89) by 0x (D) F4: __gnu_cxx :: __ verbose_terminate_handler () (in / usr / lib / x 86 _ 64 - linux-gnu / libstdc .so .6.0. 24) by 0x 50 CDCE5: ??? (in / usr / lib / x 86 _ 64 - linux-gnu / libstdc .so.6.0. 24) by 0x (CDD) : std :: terminate ( () in / usr / lib / x 86 _ 64 - linux-gnu / libstdc .so.6.0. 24) by 0x 50 CDFC8: __cxa_rethrow (in / usr / lib / x 86 _ 64 - linux-gnu / libstdc . so.6.0. 24) by 0x 429 CCD: repl (forthy2: : Cx &) (main.cpp: 26) by 0x (A) ************************************************************************************************************************* (C: main) main.cpp: 75)
benchmarks
clock
may be used to measure the time it takes to run N repetitions of the specified expression.
1000000 clock {} Time @ 1503489 usecs 1503
Some type checks may be skipped in return for a 30% speed up by passing- unsafe
on the command line . Unsafe in this context means possibly crashing on failed dynamic C type casts as opposed to checking types manually and throwing more informative errors.
$ build / forthy2 bench /fib_rec.f2 60 $ build / forthy2 -unsafe bench / fib_rec.f2 46
garbage collection
forthy2supports incremental, time sliced manual garbage collection .
mark
takes an optional max time and returns the total time if completed,_
Otherwise.
_ mark nsecs 23257
sweep
provides an identical API to the second phase,
_ sweep nsecs 1746
andmark-sweep
allows performing both phases as one.
_ mark-sweep nsecs 26120
license
support
Please consider donating if you would like to support the project, every contribution helps.
Etherium: 0x 423 Ca3edCb (D) ***************************************************************************************** (b) FC5DB8D (E)
GIPHY App Key not set. Please check settings