X : The Ultimate Toy Language


Introduction

X is a procedural programing language. The current implementation is written in Euphoria. Technically, it is a mere translator: a Euphoria interpreter is required to run an X program.

An X program is one, or more linked plain text files, basically a collection of commands. Each command, in turn, is an instruction, or a control structure, or a routine definitions.

Instructions are either simple declarations (export, import, global, etc), or procedure calls. Each has a fixed number (zero or more) of inputs.

Control structures are based on the familiar 'for' loop, 'while' and 'if-elsif-else' constructs.

Routine definitions are also conventional: 'func' and 'proc' constructs.

The above mentioned inputs may occasionally be mere labels (e.g. file names, unspecified symbols, pre-declared names of routines and variables, etc), or literals, variable references, function and variable calls.

The main features of X are:

It is terse, but not cryptic.

It is case sensitive.

It uses the prefix (Polish) notation. (It strengthens the imperative character of the language and avoids all precedence hassles.)

It has no constants, just variables.

There is no explicit declaration of variables in X, and variables have no types, only their values do. A variable is implicitly declared by the first assignment of a value to it.

Variable values have following types:

list dynamic sequence of any mix of values
tableassociative list, dictionary
recrecord, a structured list with named fields
realreal number
intintger

Whitespace is the universal delimiter/separator (no commas to separate individual elements of a list).

And since commas are no longer needed as separators, I use them to force repetition of the last command (procedure) call. So, for instance,

    say a, b
is the same as
    say a
    say b
A comment is introduced with a single # (hash sign, also very handy under unix!), and it extends to the end of the current line.

Single quotes (unshifted characters!) delimit a string.

Single characters are marked with a single double quote in front of them. '`' (back quote) replaces '\' (backslash) as the escape character to avoid silly clashes with directory separators in MSDOS (so, for instance, "`n is a newline char).

'$' (dollar sign) prefix marks a hexadecimal number.

Namespace scheme is simple:

The global scope is unlimited.
The local scope extends from the point of declaration (explicit for routines, implicit for variables) to the end of the current file.
Private variables exist only within routines. They include arguments of each routine and the set of variables specifically declared as 'private' at the top of a routine.
Any other variable implicitly declared within a routine definition is considered to be 'local'.

Any local symbol included in an export instruction (usually at the top of the exporting file, for easy reference) will also be 'visible' in any other file through a simple import mechanism and a special '.' (dot) notation.

So, the order of namespace searches is, where applicable: 'for loop' indices - private - local - global (global space includes all 'dot' imports).

No round brackets.

X has inherited very nice, automatic, continuous garbage collection from Euphoria, too! ;).


Some features are not implemented, yet, in the current release. The most important among them are:

Eval type of routine.

Better optional passing of parameters by reference. Currently, only a handful of built-in routines have it, and the implementation is a horrible kludge.

Uncrippled integers based on the length of the native word (for any given machine architecture, 32-bits for the current crop of PCs).

Better strings. Support for unicode.

Fast, dynamic arrays of any single type: bytes, characters, integers and reals for starters - integrated with lists, of course. Strings as array of characters.

Possibly a small amount of syntactic sweetener, a little bit of extra noise. If, for instance, 'for loop' constructs are too simple for too many people, I could consider modifying them so that 'for i 3 11' becomes 'for i from 3 to 11:'. But, quite frankly, I would not like that...

A nice(r) IDE.

A 'goto' (but way down the list - sorry, Kat!).

Eventually, I would prefer a completely free source format, abandoning the infamous 'declare-before-use' lazy compiler writer's mantra. That might force introduction of some sort of a separate 'main' block or a procedure - which may not be such a bad idea anyway.


Examples

Just for illustration, let's compare, side by side, two versions of the most abused, innocent line of code:

    -- euphoria ------------        -- X --------------

    puts(1, "Hello, world!")        say 'Hello, world!'
'Not much difference', did you say? I agree, it's subtle. I know which one I prefer...

To start with, Euphoria's version is 26% longer (24:19).

X knows where I want the message displayed (standard output: screen), and it does so, quietly, until I tell it otherwise.

No round brackets, no double quotes! They are shifted characters, and people like me, who can't type, hate them!


A now, a longer, only slightly more complex code fragment:


    -- euphoria ----------------------      -- X --------------------

 1: function shuffle(sequence s)            proc shuffle *s:
 2:     object temp                             step i length s 2 -1
 3:     integer j                                   = j rand i
 4:     for i = length(s) to 2 by -1 do             swap s[i] s[j] ;;
 5:         j = rand(i)
 6:         temp = s[j]                     = pack {}
 7:         s[j] = s[i]                     for i 1 4
 8:         s[i] = temp                         for j 1 13
 9:     end for                                     push pack i ;;
10:     return s
11: end function                            shuffle pack
12:
13: sequence pack
14: pack = {}
15: for i = 1 to 4 do
16:     for j = 1 to 13 do
17:         pack = append(pack, i)
18:     end for
19: end for
20:
21: pack = shuffle(pack)
Just a few explanatory notes, even though they are not really necessary:

Line 1: A generic shuffle routine has to be a function in euphoria. The sequence to be shuffled is passed by value, and the result has to be returned. In contrast, X's parameter is passed by reference (can you see the asterisk in front of the variable?), and extra copying of lists can be avoided.

Line 2: X has two kinds of 'for' loops. The standard 'for' takes exactly three inputs: index variable and the two limits, 'from' and 'to'. 'step' expects four inputs, the last being the index increment when value other than 1 is desired.

Line 4: X has a built-in swap(*a *b) routine, a procedure with both parameters passed to it by reference.

Line 9: push is again a built-in procedure, a shorthand for the common euphoria construct s = append(s, x)




This website maintained and coded by jiri babor