-
Notifications
You must be signed in to change notification settings - Fork 2
Syntax
Strings are the only things in Déjà Vu syntax that can contain #
characters
without starting a comment, so they are processed before comments. Strings start
and end with double quote characters ("
). Strings do not to be seperated with
whitespace from anything, even other strings. So this works:
>> . ."a""b"
a
b
Comments are started by #
and run to the end of the line.
Words are seperated by whitespace. Not counting strings and special cases, there are three kind of words:
- Numbers. Examples:
0
,3
,-504
- Proper words. Examples:
+
,drop
,[]
- Idents. They represent proper words, without calling them.
Think of them as references. Examples:
'+'
,'name-error'
,'('
Numbers, strings and idents are pushed to the stack, proper words are called.
Calling a word can result in two things: if the word refers to a number, string or ident, that value is pushed to the stack. If it refers to a function of any kind, that function is called.
There are two kinds of functions: Déjà Vu functions and Python functions. The Standard Library is implemented in Python.
A function can be defined in four ways:
func something:
something-else
something:
something-else
local something:
something-else
labda:
something-else
The first two are synonymous, as the second is simply syntactic sugar for the first.
The third is similar to the first two, only it binds the function to the local closure, instead of the global environment.
The fourth is what is generally called an anonymous function or lambda expression. Note
it is spelled labda
in Déjà Vu. (Those who have studied Ancient Greek know why.)
A labda is pushed on the stack instead of bound to a name. The following expressions are therefore equal:
func this:
that
labda:
that
set 'this'
Déjà Vu has if
, elseif
and else
, which work like you would expect:
if < x 0:
. "x is negative"
elseif > x 0:
. "x is positive"
else:
. "x is zero"
There are two types of loops: while
and for
.
While-loops work as you would expect:
set 'x' 5
while > x 0:
. x
set 'x' - x 1
For loops are a bit more interesting. The basic form is:
for counter-name some-code:
body
When the loop is entered, some-code
is run. Next, a value is taken from the stack. This can be either a reference to a function, or an ident for a function. This function is called. It is expected to push three values to the stack, like this:
[things already on the stack] func hidden item
func
can be either (an ident to) a function, in which case that will be called next iteration, or zero, in which case the loop will end. Whether or not body
will be executed one last time or not depends on the truth-value of hidden
. If func
is non-zero, hidden
will be kept around as hidden state and pushed onto the stack before func
is called.
If func
is non-zero or hidden
is true, item
is then locally bound to the name counter-name
, after which body
is executed.
A useful function is stop-iter
, defined in the standard library, which simply pushes three zeros to the stack.
If you don't intend to write your own iterators, in
and range
are still useful:
>> for x range 1 4:
.. . x
..
1
2
3
>> for n in [ 1 9 5 ]:
.. . n
..
1
9
5
Like many stdlib functions, in
destructively updates the stack passed to it.
Note that unlike in a while-loop, the some-code
part is run only once and can be safely moved to the line above:
>> in [ 4 2 ]
>> for n:
.. n
..
4
2
This will be replaced by a better explanation of error handling in Déjà Vu. Here's an example:
>> catch . pop-from . :
.. this-word-does-not-exist
name-error
this-word-does-not-exist
Also very nice: catch-if
, which re-raises the exception if it isn't of the proper type:
>> catch catch-if 'name-error':
.. this-word-does-not-exist