Manual for CFL 2.0.3

Introduction

ComeFrom Language is an estoric programming language. It explores what is possible given only the most unwieldy of flow control operators, 'comefrom' and 'comefromif'. While the idea is certainly not unique, nor at 40 years of age new, it has previously lacked some accessibility. Any language implementing it, such as INTERCAL, has way too much cruft to let you focus on the problem of comefrom. CFL therefore features a minimal stack-based language which is easy to learn and read, and a nice web-based IDE to program in.

Syntax

Every command must have a line number, then a value or a command. CFL is a stack-based language, and values and commands all use the same first-in, last-out stack.

Values are pushed to the stack, from which commands will take them and process them. To put a string on the stack, preface it with a $. To put a number on the stack, preface it with a #. Example: The program 10 #3.14 puts the number 3.14 on the stack. Note: It is only customary for the lines to appear in order in the source code, not required.

There are two types of commands. Normal commands, when run, take their arguments off the top of the stack and put their return values on the stack when they're done. Infix commands, however, are put on the operator stack while they wait for more arguments. For example, the divider operator, /, is an infix command. Running 10 #2, 20 /, 30 #4 would leave the value of 0.5 on the stack. 10 $hello, 20 +, 30 $ there would leave "hello there" on the stack.

Comefrom and comefromif are special cases, and are written as 10 comefrom 20.

Comments are written as 10 !this is a comment.

If two or more instructions share a line number, one is chosen at random each time that line is executed. 10 comefrom 20, 20 #0, 20 #1 will push 0s and 1s to the stack.

A statement is terminated by a comma or a newline, unless preceded by a comma. In that case, the preceding comma will be removed from the program. Most of the examples here use commas for compactness.

Commands

Math Operators
+, -, *, /, % Infix operators. Add, subtract, multiply, divide, or take the modulo of the next number to be pushed to the stack with the number currently on the stack. Only addition works with strings, concatenating them. 10 2, 20 /, 30 4 → [0.5]
<, =, > Infix operators. Compare the number currently on the stack with the next to be put on the stack, returning 1 if the assertion was true and 0 if not. 10 2, 20 <, 30 4 → [1]
^ Infix operator. Raise the number on the stack to the power of the next number to be put on the stack. 10 2, 20 ^, 30 4 → [16]
calljs Call a javascript function. For example, take the stack ['Enter your password:', 1, 'prompt<window']. When calljs is executed it will prompt the user to enter their password and put the result on the stack. The newest value on the stack is the name of the function to call. eg; 'prompt<window' calls Javascript's window.prompt function. The number indicates the arity of the function, and then pops that many variables off the stack to feed to the function. A value which is not a number, boolean, or string is interpreted as nil. See also: readjs
10 $Enter your password:
20 #1
30 $prompt<window
40 calljs
→ [$my_password]
comefrom Come from a line number to this line. 10 $cfl , 20 comefrom 40, 30 dup, 40 print prints "cfl" repeatedly
comefromif Comes from a line number to this line, IF the top value on the stack is truthy. The value is not removed from stack. Truthy values are anything other than #0, $, nul, or the empty stack. 10 #5, 20 comefromif 40, 30 -, 40 #1 → [0]
depth Puts the size of the stack prior to the instruction to the stack. 10 #100, 20 #101, 30 depth → [#100, #101, #2]
drop Removes the first value on the stack. 10 #5, 20 drop → []
dup Takes the first value on the stack and adds it to the stack twice, duplicating it. 10 $test1, 20 $test2, 30 drop → [$test1]
log Pop a value to stack, and print it to the javascript console. See also: print, println 10 #2, 20 log → []
nop Take no action. Very easy to implement! 10 nop → []
not Logically negate the first value on the stack. (In CFL, truthy values are anything other than #0, $, or nul.) 10 "hello", 20 not → [0]
num Cast the top value on the stack to a number. See also: str 10 $512, 20 num → [#512]
print Print and remove the top value of the stack. See also: log, println 10 $hi, 20 print → []
println Print and remove the top value of the stack. Advance the cursor to a new line. See also: log, print 10 $hi, 20 println → []
reach Reach back in the stack, read a value, and push the read value to the stack. Does not remove the read value. 10 #5, 20 #1, 30 reach is equivalent to 10 #5, 20 dup. 10 $A, 20 $C, 30 $D, 40 #2, 50 reach → [$A, $C, $D, $C]
readjs Read a javascript value as given by the js path string on top of the stack. For example, to read Math.PI, we'd push $PI<Math to the stack and then invoke readjs. See also: calljs 10 $PI<Math, 20 readjs → [#3.141592653589793]
str Cast the top value on the stack to a string. See also: num 10 #512, 20 str → [$512]
swap Reverse the position of the top two values on the stack. 10 #1, 20 #2, 30 swap → [#2, #1]

Examples

Dividing Two Numbers
10 #1
20 /
30 #2
40 print
Skipping a Command
10 $a
20 $b
30 $c
40 comefrom 20
50 log
Adding Three Numbers
10 #5
20 #3
30 +
40 +
50 #4
Counting Up to Ten
10 #0
20 comefrom 120
30 +
40 #1
50 dup
55 dup
60 <
70 #10
80 drop
100 comefromif 75
120 drop
130 comefrom 90
145 drop
99 Bottles of Beer
0 !99 Bottles v1.0.0
10 #99
19 nul
20 comefromif 205
21 drop
30 dup
40 str
45 dup
50 + 
60 $ bottles of beer on the wall,,
70 println
80 +
90 $ bottles of beer.\nTake one down,, pass it around,,
100 println
120 -
130 #1
140 dup
145 swap
150 str
155 +
160 $ bottles of beer on the wall.\n
170 println
180 dup
190 >
200 #2
215 $1 bottle of beer on the wall,,\n1 bottle of beer.
214 $Take one down,, pass it around,,\nno more bottles of beer on the wall.\n
213 $No more bottles of beer on the wall,,\nno more bottles of beer.
212 $Go to the store,, buy some more,,
211 $99 bottles of beer on the wall.\n
210 $... oh fine I'll stop now.
218 !loop until we've printed the entire stack we just filled
219 comefromif 220
220 println

Language Proposals

How about a return statement, gotoing the last line we camefrom? That would allow truly invisible flow.