Forbin

From Esolang
Jump to navigation Jump to search

Forbin is an esolang by User:PythonshellDebugwindow.

Overview

Forbin is an imperative esolang. Its only datatypes are functions and bits.

Syntax

The only syntactic elements in Forbin are function definitions, variable assignments, function calls, for loops, returns, and the NOT operator. Comments start at // and last until end-of-line.

Function definitions

Function definitions in Forbin consist of the function name followed by code in curly brackets. Functions all return bits.

fname {
  ...
}

Nested functions are allowed, but are only accessible to their parent function (and that function's parent if it has one, and so on).

outer {
  ...
  inner {
    ...
  }
  ...
}

Functions can have as much or as little code as you like, even an empty body.

Arguments

Optionally, functions can have arguments. Like variables, these are all bits. Unpassed parameters are set to 0. For each parameter, you simply write its name, and you can separate multiple ones with commas.

noArgs { ... }
oneArg arg { ... }
fourArgs a1, a2, a3, a4 { ... }

Variable assignments

In Forbin, variables are all bits. Variables can be global or local to a function (and its children, if any, and so on). To initialize a variable, type its name followed by an = equals sign followed by its value. A variable's value can be a bit literal (0 or 1), another variable's value, a use of the NOT operator, or a function call). Spaces are optional. Like all statements, variable assignments are terminated a semicolon.

vname = value;

Multiple assignment is also possible, in the same way Python does it.

var1, var2, ..., varN = val1, val2, ..., valN;

If only one value is provided, then that value will be passed to every variable to the left of the equals sing. Functions will be called multiple times.

var1, var2, ..., varN = value;

Function calls

For loops

There are two types of for loops: iteration loops and range loops.

Iteration loops

Iteration loops loop one or more variables through parameterized values. These variables must first be defined, typically as 0.

i, j = 0, 0;
for i:(0, 1, 0, 0, 1) {code}
for (i, j):((0, 0), (0, 1), (1, 0), (1, 1)) {code}

The above code would execute the first code 5 times, with i being 0, then 1, then 0, then 0, then 1 again. It would then execute the second code four times, with all possible combinations of i and j.

i, j = 0, 0;
for (i, j):((0, *), (1, *)) {code}
for (i, j):(*, *) {code}
for (i, j):((1, *)) {code}

The above's first for loop would do the same thing as the first for loop: asterisks in iterating for loops are like wildcards, looping through all possible values. Its second loop also does the same, but is even shorter. Its third loop loops i and j over (1, 0) and (1, 1).

Range loops

Range loops loop a variable through a range. Range loops can be used with the NOT operator to form 'if' statements. The variable used must be initialized.

i = 0;
for i:0..0 {code}
for i:0..1 {code}
for i:1..1 {code}
for i:1..0 {code}

The first loop runs once with i as 0; the second one runs twice with i as 0 and then 1; the third one runs once with i as 1; and the fourth one doesn't run at all, which can be used for if statements.

Returns

The return statement can be used to exit a function with a value (default is 0). They can only be used inside functions. Function execution stops immediately when a return is executed.

returnZero {return 0;}
returnOne {return 1; return 0;}
identity x {return x;}

The NOT operator

The prefix NOT (!) operator, the only non-for-loop-related one in Forbin, is rather simple: if its operand is equal to 0, it returns 1; otherwise, it returns 0.

!value

I/O

Forbin's only builtins have are for I/O, and they're in and out. in takes no arguments and returns a bit read from STDIN (most significant first). out takes 8 arguments and writes a byte as ASCII to STDOUT (most significant first).

Tricks

Function literals

Function literals can be created by surrounding code with {} curly braces. They can also contain returns.

code
{code} 0;

The above two lines are the same, no matter how much code is in code.

With arguments

(arg1, arg2, ..., argN @ {code-that-can-use-args})

The above works for any amount of arguments, all bits.

The underscore

The _ underscore character is like a special variable, in that it can be used as the looping variable in for loops, but its value can't be accessed.

for _:(0, 1) {code}

The above would execute code twice, but with no indexer available. This can be handy for making if statements.

If statements

We can take advantage of the fact that range for loops don't loop at all if they're told to loop through 1...

if cond, func {
  for _:!cond..cond {
    return (func 0);
  }
}

This works by looping from !cond to cond. If cond is 0, the range to loop through will be 1..0, and therefore not loop at all, but if cond is 1, the range will be 0..1, and the return ensures that func is only called once. Since we don't care about the index, the _ underscore is used to throw it out. (0 is passed as an argument to func because something has to be passed to call it, usually 0; func shouldn't take any arguments).

Equality testing

We could use if statements to test equality, but that's boring. Instead, we can use a range loop.

eq a, b {
  equal = 0;
  for _:a..b {
    equal = !equal;
  }
  return equal;
}

First, we initialize a variable equal to 0, meaning we assume the variables are different at first. We then range from a to b. If they're the same, it will loop only once (for 0..0 or 1..1), setting equal to 1; if a is 0 and b is 1, then it will loop twice, setting equal to 1 and then back to 0; and if a is 1 and b is 0, it won't loop at all, keeping equal as 0. We then return equal.

Reading a byte from STDIN

Since multiple assignment with a function call as the only value loops that function over the variables, we can loop in over 8 variables.

a,b,c,d,e,f,g,h = (in 0);

Examples

Hello World

main {
  out 0,1,0,0,1,0,0,0;
  out 0,1,1,0,0,1,0,1;
  out 0,1,1,0,1,1,0,0;
  out 0,1,1,0,1,1,0,0;
  out 0,1,1,0,1,1,1,1;
  out 0,0,1,0,0,0,0,0;
  out 0,1,0,1,0,1,1,1;
  out 0,1,1,0,1,1,1,1;
  out 0,1,1,1,0,0,1,0;
  out 0,1,1,0,1,1,0,0;
  out 0,1,1,0,0,1,0,0;
}

Cat until EOF

main {
  i, shouldLoop = 0;
  a,b,c,d,e,f,g,h = (in 0);
  out a,b,c,d,e,f,g,h;
  for i:(a,b,c,d,e,f,g,h) {
    for _:!i..i {
      shouldLoop = 1
    }
  }
  for _:!shouldLoop..shouldLoop {
    main 0;
  }
}

While loop function

while c, f {
  r = (c 0);
  for _:!r..r {
    f 0;
    while c, f;
  }
}

Truth-machine

main {
  a,b,c,d,e,f,g,h = (in 0);
  out a,b,c,d,e,f,g,h;
  for _:!h..h {
    loop 0;
  }
}
loop {
  out 0,0,1,1,0,0,0,1;
  loop 0;
}

Computational class

Forbin is a bounded-storage machine, as even though it can execute a while loop, it can only store single bits in its variables.