An experimental general-purpose programming language
Before we dive into how to define your own scopes, we need to define some
language for talking about scopes, and identify some components of scopes. We
will start with scopes that are common in most programming languages: if
and
while
.
Scopes can consist of one or more blocks of code. For while
loops, most
languages do not give a name to the block, but the block is chunk of code that
is executed on each loop iteration. In the Icarus standard library, we would
write while (condition) do { ... }
, so the block would be do
.
If statements in most languages can have either one or two blocks: The then
block is mandatory, and the else
block is optional.
You may be wondering about “else if”, but this is not actually a special construct in all languages. In particular in Icarus, we allow “else if”, but it is syntactic sugar. That is,
if (a) then {
...
} else if (b) then {
...
} else {
...
}
is syntactic sugar for
if (a) then {
} else {
if (b) then {
...
} else {
...
}
}
Let’s start by defining a relatively simple scope named forever
which will
loop forever. Because each scope needs at least one block, and blocks must be
named in Icarus, we will choose the name do
for the block.
The implementation of this scope looks like:
forever ::= scope {
enter ::= jump () { goto do() }
do ::= block {
before ::= () -> () {}
after ::= jump () { goto do() }
}
}
// Usage
forever () do {
do_something()
}
When a call to the forever
scope is reached, the enter
jump will be executed.
The jump says that it should go to the do
block, so control jumps to the
before
function in the do
block. Once the function executes (it is trivial
in this case, but you may imagine wanting to do something interesting here), the
body of the do
block is executed. In this example, that’s the call to
do_something
. When the body of the do
block completes, the do
block’s
after
jump is executed which once again directs control back to the do
block
itself, restarting the loop.
TODO: Dive into more details here.