Enigma
******

This manual is for Enigma, version 0.1. Copyright © 2010 Niels Serup

     Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license is included in the section entitled "GNU Free Documentation License".

     This document is also available under the terms of the Creative Commons Attribution-Share Alike 3.0 (or any later version) Unported license. A copy of the license is available at http://creativecommons.org/licenses/by-sa/3.0/legalcode.

New versions of this manual will be available at http://metanohi.org/projects/enigma/.

A short introduction
********************

Today, in the world of programming, the commonly used programming languages have --- to some extent --- adapted the same basic syntax. Both C, C++, Java, Python and Ruby (and others) all share several paradigms, even though they are still very different. Enigma, on the other hand, is very different from the ``common'' languages. See this small program to get an idea of Enigma:

{/a,b/
    a 2 ! multiply = c;
    b c ! add = return;
} = odd-add;

9 4 ! odd-add | stdout temp ! write;

Here, 9 is first multiplied with 2 and then added to 4. The program then prints the result (22).

With only a few constructs and built-in variables, Enigma is quite small and relatively simple. Any logic can be expressed in Enigma. The above example may seem odd, but its aspects will be dealt with in the next chapter.

Enigma is not the kind of programming language that likes to control programmers. When programming in Enigma, one creates functions that call other functions --- instead of creating functions that are called by built-in functions.

On the other hand, Enigma is very restrictive. There are limits to certain things. If these limits were not present, chaos would ensue. Perhaps.

Like many other languages, Enigma is quite fond of pointers. In Enigma, all variables are pointers. When x is assigned to a, and b is assigned to a, changing b also changes a. As a matter of fact, when two pointers points to the same place, they are forever linked together.

Enigma is not recommended for serious use. Use with caution!

The language
************

Enigma consists of functions. Any file being parsed is a function. Within functions there can be local variables. These variables are to disappear when the function exits.

Functions have return values. These values can be determined by the programmer.

Within functions, there are commands. These commands constitute the very base of Enigma. Commands can interact with built-in functions, meaning that writing to and reading from files, calculating, as well as manipulating strings and lists, is possible.

There are no simple types. Enigma lies in the world of objects. Numbers, strings, lists.. It's just objects. Also, all commands must end with a semicolon;

Operators
=========

Enigma has 4 operators: !, =, |, and *. ! and = are the most important ones.

To assign values to variables, use the = operator. For example:
obj = hello-string;
Here, the variable hello-string receives the object obj. Note the syntax. The objects comes first. Unless hello-string is already defined, it is created as a local variable.

Now, say we have a function called think and we want to send objects to it. This is how that's done:

obj1 obj2 obj3 ! think;

There are no limits to the amount of objects that can be sent to a function. Whitespace characters are used to separate objects, also when assigning them to a variable. There is a difference between using one object and more objects as arguments, though. When using only one object, that object is simply used, but when using more objects, a list containing all objects is created and transmitted instead. So, in reality, when assigning two or more objects to a variable, the variable points to a list with the objects. More about lists later.

The | operator is merely a shortcut operator. It can merge several commands into one, long command. See the following example:

# Long version
a ! b = c;
d c ! e = c;
# Short version
a ! b | d temp ! e = c;

Here, a is sent to b, which is then --- together with d --- sent to e and saved in c. The | acts like the semicolon, but it copies the return value of the last function (in this case b) and stores the value in the local variable temp. Hackers are encouraged to use this operator.

The final operator, *, has the same function as =, except that it works on a global level. So, if the code is b = a; and a does not exist, it is created --- in the global space.

Numbers
=======

Numbers in Enigma can be arbitrarily large. They are written as one usually writes numbers. Currently only the decimal system is supported.

7587 = age;
2556 ! numfunc;

Strings
=======

Strings are defined using the " character.

"This is a string!" " This too!" ! add;
"A" = A;
"Now comes
a newline" = nl;
"\"\\\n\t\
" = escaped;

Lists
=====

Lists are special in Enigma. They are used a lot, but unlike eg. numbers and strings they cannot be defined in their own syntax. When one writes this:

123 "witch" = lst;

..one creates a list. Lists can be nested.

Booleans
========

Booleans are used a lot in Enigma. The predefined variables true and false can be used.

Files
=====

Files can only be created using the built-in function open. Files are either readable or writeable. If a file is writeable, text written to the file may optionally be appended to any existing text.

"a" "r" ! open = f1;
"b" "w" ! open = f2;
"c" "a" ! open = f3;

# Read one character
f1 ! read | stdout temp ! write;
# Write a string
f2 "Aaar" ! write;
# Append a string
f3 "Ouu" ! write;

f1!close;f2!close;f3!close;

To read an entire file, one must use a loop construct. See Loops. When there are no more characters left, the read function returns an empty string. Using equality testing, reading a complete file is thus possible. See Conditionals.

filename "r" ! open = f;
{f ! read = c; stdout c ! write; c "" ! equal ! not = return;} ! loop;

At this point, it may not be obvious why this works. This will be explained in the next sections.

Functions
=========

Functions are defined and called using the following syntax:

# Defining them
{stdout "Hello" ! write;} = func;
{/x,y/stdout "x=" x ", y=" y!write;} = coorprint;
{stdout args ! write;} = aprint;

# Calling them
!func;                 # Outputs "Hello"
52 12 ! coorprint;     # Outputs "x=52, y=12"
999 "abc" 21 ! aprint; # Outputs "999 abc 21"

Arguments can thus be accessed either by using the /.../ syntax in the beginning of the function or by using the local args variable. Furthermore, to make all new variables save in the global space, prepend the function content with a *. This will have the same effect as replacing all = signs in the function with the * operator.

Remember that your file is also a function, just without the curly brackets. This means that when working on the top level of your program, args actually refer to the arguments specified on the command line. All arguments are strings, but built-in functions that can convert them to numbers exist.

The previous example functions did not have any return values. This is merely because they didn't need such things. To define a return value, the return value must be sent to the special variable return.
{/a,b/a b ! multiply = return;} = 2mul;
33 3 ! 2mul = 2mult;
stdout 2mult ! write;
The execution of a function does not stop when a value is assigned to return. This has both advantages and disadvantages.

Many things are almost impossible to do without the built-in functions. Some are completely impossible. See Built-In. As all objects in Enigma are pointers, several built-in functions actually modify the objects sent to them as arguments. To solve this problem, one must use the clone function.

Conditionals
============

Any value can be related to another value. 78 is less than 85. 2 equals 2. "Hi" is not "Bye". Enigma comes with a basic set of functions that can be used to test these relations. The functions greater, lesser, equal, not, or and and are available. These functions return either true or false. To run a function on the condition that a relational function has returned true, use the function act.

While lesser and greater are aimed at numbers only, and and, or and not are aimed at booleans only, equal can be used on all objects. It tests for all equalities.

2 = a;
4 = b;

a 2 ! add | temp b ! equal = cond1;
"47" ! num | temp 48 ! greater = cond2;

cond1 cond2 ! and | temp write stdout "4 = 4 and 47 > 48\n" ! act;
cond1 cond2 ! or | temp write stdout "4 = 4 or 47 > 48\n" ! act;
cond2 ! not | cond1 temp ! and | temp write stdout "4 = 4 and !(47 >
48)\n" ! act;

Even simpler, one can do this (though there's no real need for it):
# Instead of stdout "Hello" !write;
true write stdout "Hello" !act;

Loops
=====

There are several ways to loop pieces of code in Enigma. One can create a function that calls itself, for example. It is, however, advised to use the loop function.
# Infinite loop
{stdout "Forever\n" ! write; true = return;} ! loop;
loop works a bit like act, except that it runs on the premise of the return value of the function it calls. If it returns true, or any other value that can be considered true (non-zero numbers, non-empty strings, files, etc.), it runs the function again. If it returns false, the loop stops. It naturally runs the first time no matter what (no return value has been created yet).

Undefined behaviour
===================

Enigma is still new. The way built-in functions act, the way error messages appear, and the way some odd details of the language works are still undefined. In general, when something seems likely to work, it will work. But it's not necessarily defined to work.

Future aspects
**************

As Enigma is right now, it is quite limited. The only way that it can interact with the rest of one's system is by reading and writing files and by executing shell commands using the system built-in function. This obviously needs to be improved. A foreign function interface system must be implemented in version 0.2. It should be possible for Enigma to do everything C can.

The number of built-in functions seems reasonable, but it may be a good idea to implement a few more. These eventual functions should be focused on making things easier. Specifically, an import function should be considered. It is possible to create an import function in Enigma directly, but it's not exactly fast. Introducing a ``compile'' function should solve that.

Implementations
***************

As of right now (beginning of June 2010) there is only one implementation. It is written in Java and is called enigma (with a lowercase e). The code is bulky and was not written by an experienced Java hacker. For v0.2 it may be a good idea to write the interpreter in C instead. Implementing a foreign function interface should be easier that way.

The current implementation can be downloaded at http://metanohi.org/projects/enigma.

Comparison with other languages
*******************************

Assigning values
================

          type var = value;

          var = value

          value = var;

Conditionals
============

          if ((a == 2 && b < 5) || (c != 4 && !d)) do_something();

Python,if (a == 2 and b < 5) or (c != 4 and not d):
do_something()

          a 2 ! equal = cond-a;
          b 5 ! lesser = cond-b;
          c 4 ! equal ! not = cond-c;
          d ! not = cond-d;
          cond-a cond-b ! and = ncond-ab;
          cond-c cond-d ! and = ncond-cd;
          ncond-ab ncond-cd ! or = actcond;
          actcond do-something ! act;

Looping
=======

          while (thinking) run();

          for (int i = 0; i < 18; i++) run(i);

          while thinking: run()

          for i in range(18): run(i)

     {!run; thinking ! clone = return;} ! loop;

     0 = i;
     {i ! run; i 1 ! add; i 18 ! equal = return;} ! loop;

Functions
=========

     int time(float space) {
         return (int) space / 3;
     }

     t = time(81.65);

          def time(space):
              return int(space / 3)

          t = time(81.65)

     {/space/space 3 ! divide ! clone ! round = return;} = time;

     81.65 ! time = t;

Built-in values and functions
*****************************

Values
======

The following variables are special and can be accessed anytime. They can even be overwritten.
args, return, temp, stdin, stderr, stdout, zero, true, false, none, @pi,
@e, cwd, cpd, fnm
zero is a fake writable file that does nothing. none is an abstract variable with an internal value of.. none. @pi is Pi. @e is Euler's number. cwd is the directory from which Enigma is run, cpd is the directory in which the current program file resides, and fnm is the filename of the current program file. The rest are self-explanatory --- and args, return and temp are extra special.

Functions
=========

Enigma has few built-in functions. But they do exist.

str(OBJECT...): Converts all supplied values to strings.

num(OBJECT...): Converts all supplied values to numbers.

list(OBJECT...): Puts all supplied values in a list and destroys nested lists at one level.

bool(OBJECT...): Converts all supplied values to booleans.

code(OBJECT...): Converts all supplied values to code strings.

repr(OBJECT...): Converts all supplied values to representational strings. Strings get prepended and appended by " characters, code objects are surrounded by { and }, and so on.

type(OBJECT...): Converts all supplied values to type strings (string, number, file, etc.).

len(OBJECT...): Converts all supplied values to their length. This can be used for both strings and lists.

clone(OBJECT...): Clones all supplied values. When an object is cloned, its value is assigned to a new variable. The list of clones is returned.

slice(LIST|STRING, NUMBER, NUMBER): Returns a list value sliced according to the first and second number if the first variable is a list variable, or a substring if the first variable is a string variable.

loop(FUNCTION, [OBJECT]...): Executes function until it returns false. Sends the rest of the specified variables (if any) to the function as arguments.

open(STRING, STRING): Opens the file by the name of the first string, using the second string as its guide as to how it should be opened. "r" means to read, "w" means to write, and "a" means to append. Returns a file object.

close(FILE...): Closes files.

read(FILE): Reads one character of a file and returns it. If no more characters are present, an empty string is returned.

write(FILE, STRING): Writes a string to a file.

greater(NUMBER, NUMBER...: Checks if the first number is greater than the rest and returns true or false.

lesser(NUMBER, NUMBER...: Checks if the first number is lesser than the rest and returns true or false.

equal(OBJECT, OBJECT...: Checks if the objects are equal and returns true or false.

and(BOOLEAN...): Checks if all booleans are true and returns true or false.

or(BOOLEAN...): Checks if at least one boolean is true and returns true or false.

not(BOOLEAN...): Converts values of true to values of false, and vice-versa.

act(BOOLEAN, FUNCTION, [OBJECT]...): Run the function with the optional objects as arguments if the boolean is true.

system(STRING...): Join the strings and run the result as a system command.

add(NUMBER|STRING|CODE|LIST...): Add objects together. Numbers, strings, code strings and lists can be used, but only with similar types. The type of the first object determines what types the rest must be. The result is stored in the first object and also returned.

subtract(NUMBER...): Subtract numbers from each other. The first object receives the final number. It is also returned.

multiply(NUMBER...): Multiply numbers with each other. The first object receives the final number. It is also returned.

divide(NUMBER...): Divide numbers with each other. The first object receives the final number. It is also returned.

mod(NUMBER, NUMBER): Finds the remainder of the first number divided with the second number and returns it as a new variable.

pow(NUMBER, NUMBER): Returns first number^second number.

log(NUMBER, [NUMBER]): Returns the logarithm of the first number. If the second number is not specified, the natural logarith is used.

random(): Returns a random number between 0 and 1.

abs(NUMBER...): Sets and returns absolute values of numbers.

round(NUMBER, NUMBER): Rounds the first number with x decimals, where x is the second number.

floor(NUMBER, NUMBER): Floors the first number with x decimals, where x is the second number.

ceil(NUMBER, NUMBER): "Ceils" the first number with x decimals, where x is the second number.

sin(NUMBER...): Sets and returns sine values.

cos(NUMBER...): Sets and returns cosine values.

tan(NUMBER...): Sets and returns tangent values.

asin(NUMBER...): Sets and returns arcsine values.

acos(NUMBER...): Sets and returns arccosine values.

atan(NUMBER...): Sets and returns arctangent values.

sinh(NUMBER...): Sets and returns hyperbolic sine values.

cosh(NUMBER...): Sets and returns hyperbolic cosine values.

tanh(NUMBER...): Sets and returns hyperbolic tangent values.

GNU Free Documentation License
******************************

     [file fdl.texi not included]