ENIGMA:Specification
We are not ISO; we'll be brief. We don't believe in 1,200 page specifications, especially since in this day and age, EDL is not the first language of its kind and in fact borrows from a lot of other languages.
If ENIGMA isn't actually following the specification here, but you would like it to, please let is know. This specification is part plan, part fact of life.
Variables
Variables in EDL begin with a letter as defined in the Unicode standard. To be brief, this includes a-z and A-Z. Letters after the first letter may be any word character as defined in the Unicode standard, which includes all letter characters and all number characters.
Numerals
Numerals in ENIGMA are not common in other languages. Decimal literals are denoted per C++ specification, except they may be preceded by zeros. For compatibility with similar languages, the dollar sign may be used to denote a hexadecimal literal. To improve on numeric support, the prefixes 0x, 0o, and 0b may be used to denote hexadecimal, octal, and binary literals, respectively.
a = 135790; // Decimal literal
b = 013579; // Decimal literal
c = $DECAFF; // Hex literal
d = 0xBADF00D; // Hex literal
e = 0o12345670; // Octal literal
f = 0b00011011; // Binary literal
Classes
EDL breaks from C++ for class definitions. The point of classes in ENIGMA is to behave like structures in C, and so the struct keyword is adopted to denote them. This decision was made for two simple reasons:
- In C and C++, structures are public while classes are private. Classes are protected or private in most languages which support visibility.
- The odds of a user attempting to use the word 'class' as an identifier far outweigh those of using 'struct'.
Methods
Structures in EDL can still contain methods as well as fields. These methods, as in C++, are meant only to manipulate variables declared explicitly in the structure.
Constructors/Destructors
Constructors and destructors can be defined as per ISO C++. A constructor is denoted as a typeless function with the same name as the class. A destructor is similar to the constructor, but is prefixed with a tilde. Constructors can have parameters, which are passed while initializing or instantiating with operator new
.
Unlike C++, member initialization is not done in a list before the body, but instead is either done during the declaration or during the first lines of the body.
Visibility
Often, visibility settings (such as private, public, or protected) serve to confuse or hinder in development. EDL does not enforce these attributes, except where required by the host language while crawling definitions. EDL instead shifts the responsibility to developers to select an appropriate naming convention and follow the rules.
Sample
struct circle {
var x = 0, y = 0;
double radius;
double get_area() { return pi * radius * radius; } // Simple method
circle(double r = 1) { radius = r }; // Optimizing this falls on the language plugin
~circle() { destroy_radius(x,y,radius); }
}
Enumerations
As in ISO C++, enumeration values are to be regarded as strict constants. When values are specified, they should be evaluable at the time of parse. A sample enumeration is as follows:
enum {a, b, c, d = 10, e, f};
In the above enumeration, as per ISO C++, the values of a, b, c, d, e and f are respectively 0, 1, 2, 10, 11, 12. Enums are designed to be inline in the new parser, but until then don't forget your the semicolon after the closing brace. These values should be assigned by the language-independent lexer upon initial parse. The assignment operand for initialized constants is to be regarded as a single token, though it may contain more complex expressions provided that these expressions do not entail runtime computations.
As with EDL structures, EDL enumerations need not be followed by a semicolon, as declarations using the new type must be made separately.
Declarations of enumerations are currently not possible in scripts or objects, however you can include them in definitions, under ENIGMA settings.
Unions
Unions are also allowed in ENIGMA, but are not guaranteed to exhibit the size of the largest type. Depending on the language plugin, the union may in fact have the same size as the structure. As in ISO C++, EDL unions do not permit objects with constructors as members.
Arrays
An array is always declared as a variant data type with the keyword var, followed by its name. Variant variables are not restricted to a specific data type and can hold any value you want. In order to access the element of an array, you add after its name the element index rounded by square brackets:
var myarray;
myarray[1] = 10;
EDL inherits JavaScript-like arrays rather than C++-like arrays. This is so an array can serve as an lvalue, as in the following code:
[x,y] = get_coordinates();
var fruits = ["apples", "oranges", "cherries"];
In the above case, x
and y
are set to the first and second elements in the array returned by get_coordinates()
, respectively. The second line then declares a var and assigns the given array values to it.
How this is accomplished after compile is outside the scope of this specification. Consult the appropriate export language plug-in page for details on implementation.
Preprocessors
EDL supports a subset of preprocessors available in C. This subset presently comprises define
, error
, elif
, elifdef
, elifndef
, else
, endif
, if
, ifdef
, ifndef
, undef
, and warning
.
Unlike in C, preprocessors in EDL need not begin the line. Instead of being set off by a pound symbol at the start of a line, they are enclosed in double braces. For example, consider the following code:
{{if 0}} {{define count 10}} something = true;
{{else}} {{define count 20}} something = false; {{endif}}
Types
Typing in EDL is strictly static, though primitive types exist which simulate dynamic typing.
Primitive | Range |
---|---|
bool | A boolean value of true or false. |
char | Integers from -128 to 127; often representing an ASCII letter |
short | Short integer from -32768 to 32767 |
int | A standard, 32-bit integer; any number between -2147483648 and 2147483647 |
long | A long integer; any number between -9223372036854775808 and 9223372036854775807 |
float | A 32-bit floating point number; any revalues representedal number which can be represented by the IEEE floating point specification |
double | A 64-bit floating point number; any real number which can be represented by the IEEE floating point specification |
instance_t | The type needed to refer to any instance in ENIGMA. |
string | An alias of std::string; any reasonably sized string of characters |
variant | Any value that can be stored by a double, or any string |
var | A matrix of any positive dimension storing any number of values representable as double and any number of strings |
Casting
Casting in ENIGMA is valid between any two numeric types. Casting from a floating point type to an integer type will truncate the value, and limit it to the max value of the given data type. Thus, char(500.9) = 127
, and char(100.9) = 100
.
Casting from a numeric type to string is also valid, but this must be done explicitly using string(number)
, where number is any real-valued variable.
Casting from var to any scalar type will cast only the index [0,0]
in the matrix.
Casting to boolean differs by data type.
Type | Cast Method |
---|---|
bool | Casting a boolean to a boolean is not needed. |
char, short, int, long, float, double, long double |
Casting from a numeric type to boolean is done per hardware specification; it is equivalent to value != 0 .
|
instance_t | Casting instance_t n to boolean is the same as comparing value > 0 .
|
variant, var | If the value represented is a string, then the cast is undefined. Otherwise, the cast is the same as value > .5 .
|
No special treatment is given to floats as such systems usually create bizarre corner cases. If you are looking for a fast way to compare two doubles with some laxity, cast both to float before running the comparison.