commit bc19febc3f82b34e46a68831fdf4bc19d5cdb9ce
parent 9d3056effbcccbc4e4db16d1b26eb7068b3e2c47
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Fri, 30 Dec 2022 10:48:44 -0500
doc/usage: add missing section about control flow
I hadn't realized it wasn't there. Big gap in docs!
Diffstat:
2 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt
@@ -49,6 +49,82 @@ character:
Any other character following the '\' results in that character being parsed as-
is, the preceding '\' being ignored.
+## Control flow
+
+: foo if 42 else 54 then . ;
+
+0 foo --> prints 54
+1 foo --> prints 42
+
+: foo begin dup . 1- ?dup not until ;
+
+5 foo --> prints 54321
+
+: foo begin 'X' emit again ;
+
+foo --> prints X forever
+
+: foo begin ?dup while 1- dup . repeat ;
+
+5 foo --> prints 43210
+
+A begin..repeat loop can have more than 1 while. In that case, things get weird
+and it behaves like "if", that is that each while has its own "loop exit point".
+Weird, but sometimes useful.
+
+: foo begin
+ dup 10 <> while dup 15 <> while dup . 1+ repeat
+ ( second while exit point ) .x1 else
+ ( first while exit point ) . then ;
+
+5 foo --> prints 5678910
+11 foo --> prints 111213140f
+
+Dusk has no do..loop. Instead, it has begin..next. "next" decreases RS top and,
+if zero, pops it and stops the loop. Otherwise, branches to begin. "begin"
+doesn't automatically puts anything on RS. This has to be done with ">r".
+
+: foo >r begin r@ . next ;
+
+5 foo --> prints 54321
+
+The "case" structure allows us to "fan out" to many possible branches depending
+on a single value. It's the functional equivalent of nested "if..then", but
+more readable. The idea is that "case" pushes a value from PS to RS, and then
+each "of" evaluates that value with a "truth word".
+
+The part before each "of" is executed as-is and then "of" does a "r@" and
+executes the specified word. If the word yields nonzero, then we stay in that
+branch. Otherwise, we branch to "endof".
+
+During the execution of a branch, the value in question is still available
+through "r@". Then, upon reaching "endof", we branch to "endcase" which then
+drops that value from RS.
+
+If no case matches, the part between the last "endof" and the "endcase" is
+executed. The value in question is also available through "r@".
+
+: foo case
+ 5 of = ." I am 5!" endof
+ of 0< ." I am negative!" endof
+ 100 of < ." I am higher than 100" endof \ yeah, order is counter-intuitive...
+ r@ .f" This number, %d, is something else" endcase ;
+
+5 foo --> I am 5!
+-1 foo --> I am negative!
+101 foo --> I am higher than 100
+42 foo --> This number, 42, is something else
+
+None of these control structures above can be ran in interpret mode. They only
+work when compiled. Sometimes, a little conditional in interpret mode can be
+useful.
+
+42 [if] ." this will be executed" [then]
+0 [if] ." this won't" even if the code is nonsensical [then]
+
+[if]..[then] work like comments and simply drop words until "[then]". There is
+no "[else]".
+
## Values, cells, constants, aliases
A "cell" is a word that refers to an area in memory. Calling this word yields
diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs
@@ -131,20 +131,9 @@ alias noop idle
begin dup 8b to@+ V2 = if leave then next ( c )
V2 1- c@ = if r> 1- r> - ( i ) else rdrop rdrop -1 then ;
-\ while..repeat
: while [compile] if swap ; immediate
: repeat [compile] again [compile] then ; immediate
-\ case..endcase
-\ The case statement is very similar to what we see in other forths, but with
-\ one major difference: the "of" word specifies the truth word. So, the
-\ "of" we see in other forths is equivalent to "of =" in Dusk OS. The comparator
-\ has to be a single word following "of".
-\ case x of = ... endof y of < ... endof ... endcase
-\ is syntactic sugar for:
-\ >r x r@ = if ... else y r@ < if ... else ... then then rdrop
-\ NOTE: if you want to access your reference value in the final "else", you
-\ need to use "r@".
: case ( -- then-stopgap ) 0 [compile] >r ; immediate
: of ( -- jump-addr ) [compile] r@ word compword [compile] if ; immediate
: endof [compile] else ; immediate