This tutorial assumes you have prior programming experience. You'll need to know about procedural programming, and some knowledge about functional programming and stack-based programming will help. You probably will need to run Linux, since that's what the Déjà Vu virtual machine was developed on, and the creator of the language regretfully informs you that he hasn't got around to adding support for alternative operating systems. Oh, and it probably will crash hard if you try to run it on a 32-bit system. Good luck.
You can download the compiler and virtual machine straight from the repository.
The compiler (along with assorted tools) is written in Python 2.6. If you run Linux, you probably have that installed already (or a near enough version of Python). If you have Python 3, it's probably possible to get that to work. The compiler doesn't depend on anything but Python's standard library, so that helps. (If you manage to do that, please send me a patch or a pull request or what not.)
You'll need to build the virtual machine with gcc. A Makefile is supplied in
the vm/
directory that should be sufficient. Run make
release
(a bare make
will build both the release VM
(vu
) and the VM used for debugging the language and virtual
machine itself (vu-dbg
)).
You can test if everything works by running:
touch null.deja
python dvc.py null.deja > null.vu
vm/vu null
If nothing seems to happen, you're golden.
You'll notice an empty null.deja
and a null.vu
of
about 27 bytes are now in your working directory. We'll talk about
.vu
files later. For now, remember this work flow (compiling with
dvc.py
when you've made changes, running with vu
).
(Side note: I probably should rewrite the compiler in C and integrate it with
the virtual machine, so that the compiling step is invisible, like in Python. I
promise I'll rewrite this section when I do that.)
Déjà Vu will blow your mind. At least, I hope so. In this section, we will go over a few example programs, with which I will try to slowly and gently blow your mind.
func sum list:
local :total 0
for item in list:
set :total + total item
return total
print sum [ 10 5 20 ]
You can probably guess what this program will print. (It's 35.)
Still, there are a lot of things that seem odd if you're familiar with other
programming languages. The location of the +
, for example. It's
important to note here that +
is a function, and in Déjà Vu, the
arguments to a function are to its right. Déjà Vu is top-to-bottom like most
programming languages, but unlike them, it's right-to-left. The reason for that
is that in languages like Python, nested function calls are also from right to
left: f(g(x))
is "call g
with x
, and
then call f
with the result of that function call". If
you want to do that in stack-based languages like Forth, you would say
x g f
. That seemed unintuitive to me, so I turned it back around
for Déjà Vu, where it is: f g x
.
Now, which of the words you saw in the above code snippet calculating the sum of 10, 5 and 20 are function calls? Let's repeat the snippet, but make the functon calls bold and draw attention-grabbing rectangles around them:
func sum list:
local :total 0
for item in list:
set :total + total item
return total
print sum [ 10 5 20 ]
That's a lot of function calls. Eight in total. Now, to be fair, the
compiler usually translates calls to functions like return
,
local
, set
and the like to special opcodes, but it
doesn't have to (and you can still take the value of functions like that, and
pass them around).
Let's talk about [
. That's a very important function. It's
similar to []
, which creates a new empty list. The difference is
that [
takes values off the stack and adds them to the new list
until it finds a ]
.
func sum list:
local :total 0
for item in list:
set :total + total item
return total
print sum [ 10 5 20 ]
You probably guessed that the numbers were literal values, but why are
those words starting with colons literal values? Those are called idents.
They are symbols or names, often of variables, but not always. When calling
set
or one of its friend like local
,
setglobal
, get
or getglobal
, it expects
such an ident as its first argument to tell the function what variable you mean.
Identrs are first class values: you can pass them around and give them names,
just like you can with numbers, strings, functions…
There is a lot more to say about idents, but that will have to wait for now.