Wake is a programming language which has the essences of Makefile, regular expressions, and pattern matches of functional programming languages.
This language intended to be an esolang. As this language doesn't have native support for integer arithmetics, this language is not practical.
This package contains two interpreters (C++ and Ruby) and some sample code (in test/ directory).
This document aims to introduce the features of wake with some examples.
all: "Hello, world!\n"
Like Makefiles, a wake program consists of a number of rules.
Each rule has one target and some actions.
In the above example, all
is the target of this rule
and "Hello, world!\n"
is the action.
If an action is a string literal, the string will be outputted.
The another type of action has no quotes.
When the interpreter finds this type of action,
the interpreter searches a corresponding target and runs its actions.
The following code also outputs "Hello, world!\n"
.
all: "Hello, " world world: "world!\n"
The world
in the first rule invokes the
world
in the second rule.
A target is actually a regular expression. For example:
all: foo bar baz .*: "yay!\n"
As the target of the second rule (.*
) matches all strings,
the second rule will be applied three times (foo
,
bar
, and baz
).
Hence this program outputs "yay!\nyay!\nyay!\n"
.
You can use special variables $&
, $+
, $1
,
$2
, $3
, ..., and $9
in actions.
The meanings of them are as same as these variables in Perl or Ruby -
$&
is the matched string, $+
is the last
back reference, and $N
is the N-th back reference.
For example, the following code reverses and outputs
"foobar"
(so the actual output is "raboof"
).
all: foobar "\n" (.*)(.): "$2" $1 :
The target in the second line matches all strings except for an empty string. The first action in the second line outputs the last character and the second action applies the rest of string until the string becomes empty. The third line matches an empty string and does nothing.
If there are multiple rules which can be applied, the first rule will be applied. For example, you can write a program which converts "o" into "O"
all: foobar "\n" o(.*): "O" $1 (.)(.*): "$1" $2 :
This program outputs fOObar
.
The above program is trivial as it always outputs the fixed string.
You can use $<
to read all characters from the
standard input.
Let's make the program a bit more interesting by using this feature:
all: $< "\n" o(.*): "O" $1 (.)(.*): "$1" $2 :
This program reads all characters from the standard input and outputs the characters, converting "o" to "O".
Note that you can use $<
multiple times.
The following example code outputs the input twice:
all: "$<" "$<"
If there is an expression $(...)
in actions,
wake evaluates ...
(i.e., finds a rule whose target
matches ...
and invokes its actions) and the
$(...)
will be replaced by the result.
As I couldn't come up with a short example for this feature, the example of this feature is lengthy:
fizzbuzz: fb@1,1 inc1@(\d);.*?\1(\d)\d*: "$2" inc@: "1" inc@(\d*)9: inc@$1 "0" inc@(\d*)(\d): "$1" inc1@$2;0123456789 inc_mod3@(\d): inc1@$1;0120 output@\d*[50],0: "FizzBuzz" output@\d*[50],\d: "Buzz" output@\d+,0: "Fizz" output@(\d+),\d: "$1" # Done fb@101,\d: fb@(\d+),(\d): output@$1,$2 "\n" fb@$(inc@$1),$(inc_mod3@$2)
This is a
FizzBuzz program
in wake.
Let's look into fb@
in the last line.
The $(...)
expression is used to construct two
"parameters" for fb@
.
This rule is meant to be a "function" like
void fb(int count, int count_mod3) { output(count, count_mod3); puts("\n"); fb(inc(count), inc_mod3(count_mod3)); }
If a line starts from #include
, the interpreter reads
rules from the specified file.
This is an example program which uses the standard library
std/num.wake
:
test: test_add test_sub test_mul test_div test_mod test_divmod test_add: add(42,9) "\n" # 51 test_sub: sub(42,9) "\n" # 33 test_mul: mul(42,9) "\n" # 378 test_div: div(42,9) "\n" # 4 test_mod: mod(42,9) "\n" # 6 test_divmod: divmod(42,9) "\n" # 4,6 #include "std/num.wake"
Note that you should not #include the library in the first line.
If you put the #include
in the first line, the execution
will start from the first rule of std/num.wake
, not
the first rule of the your program (i.e., test
in the
above example).
As of July 18, 2010, std/num.wake
is the only
standard library and the above example program showed all functions in
this library.
The library provides 6 "functions" - add
,
sub
, mul
, div
,
mod
, and divmod
. They are expected to be
used inside $()
to invoke another rule with a calculated
value.
Here is another example code which uses
std/num.wake
. This program counts from 0 to 9 and outputs
them.
all: count0 count10: count(\d): "$1\n" count$(add($1,1)) #include "std/num.wake"
Empty lines and whitespace-only lines add no rule. You can put any numbers of whitespaces before and after actions and they have no meanings. Note that whitespaces before the first colon (the separator for a target and actions) have effects. These whitespaces are part of the target.
In a string literal and an action, backslashes can be used as a escape
character. "\n"
and "\r"
mean a newline and
a carriage return, respectively. Other sequences start from
backslashes just mean the second character. Note that you can output
$1
by "\$1"
, "
by
"\""
, and \
by "\\"
.
Also, you can invoke an action which contains whitespaces with a
backslash. For example, the following code outputs "OK".
test: use\ backslash use backslash: "OK\n"
To use a colon in a target, you can use \:
.
Here is an example code:
all: : \:: "OK\n"
The two reference implementations in the package should have the same semantics except for the detail of regular expressions. If you find a program which yields different results between the two implementations, this may be a bug.
Though wake is a small language, we can write non trivial code thanks for the power of regular expressions. In fact, std/num.wake , which is the only standard library in wake, implements integer arithmetics without special supports from the language.
The brainfuck interpreter would be another example you may be interested in.
My golf server also has a bunch of wake programs thanks to golf players.