1. Description
elastiC is a very high level language (VHLL) aimed at the ease of development of large systems. It has a simple syntax, similar to that of the C language, so it should be very easy to learn. On the other side it introduces many extremely powerful features, such as:
- automatic memory management with real, fast, Garbage Collection
- dynamic typing
- lexical scoping and first class functions, to allow full functional programming
- many useful types: dynamic arrays, dictionaries, symbols, strings, ...
- OOP support (styled after Smalltalk object model)
- pervasive exception handling support
- easy C extensibility (it's possible to add functions, classes, methods, packages, ...)
- hierarchical namespaces
- easily embeddable in larger C programs as a library
- portable bytecode compilation & interpretation
This manual is not a complete reference document, but rather a quick reference.
2. Language
2.1. General Syntax Rules
- The syntax is inspired by the C language.
- elastiC programs are defined in modules (also called packages).
- elastiC programs are sequences of declarations, definitions, statements and expressions.
2.2. Comments
C style comments:
/* ... ... commented region ... */
C++ style comments:
// commented region
2.3. Reserved words
break catch class continue do else extends for from function goto if import in local method package private public return static super throw try while
2.4. Fundamental Types
Basic types are integers, floats (floating point numbers), booleans, characters, strings, symbols, arrays, hashes, classes, objects (class instances), packages, bytecode, stacks, primitive functions, primitive methods, handlers. The last four constitute a very advanced topic and can be ignored by the casual elastiC user.
The special value @nil can be used as a null value (for example to specify that no value is available).
There are also the special types undefined, error, which have only one object instantiated. The undefined object is contained in uninitialized variables and it produces an error when referenced. The error object is returned by primitive functions to alert the interpreter that an exception is pending. These types however are of interest only to the extension writer and not to the casual elastiC user.
In the remaining part of this section we'll give details on the single types and show some examples of constant values of these types.
Null value
The null value doesn't have a type, but it is a very important value anyway.
@nil
Integers
12345 0x3039 (hex) 030071 (octal)
Floats
123.45 123. 1.2345e2 1.2345e+2
Booleans
@true @false
In expressions expecting a logical value, all values are considered equivalent to @true with the exception of @nil, @false, and the integer 0
Characters
'a' 'b' ... Common characters '\\' \ - Backslash (ASCII 92) '\n' LF - Linefeed (ASCII 10) '\t' HT - Tab (ASCII 9) '\b' BS - Backspace (ASCII 8) '\r' CR - Carriage Return (ASCII 13) '\f' FF - Feed Forward (ASCII 12) '\v' VT - Vertical Tab (ASCII 11) '\a' BEL - Bell (ASCII 7) '\?' ? - Question mark "?" (ASCII 63) '\'' ' - Single Quote "'" (ASCII 39) '\0' NUL - NUL (ASCII 0)
Strings
"abc" "This is a string" "A string with \"quotes\" too !"
All the escape sequences supported by characters are available for strings too.
Symbols
#asymbol #thisIsAnotherSymbol 'anotherSymbol
Symbols are translated to integers during the compilation of the source program, and from that point on they are always handled as integers. For this reason symbols are very fast and require very little memory if compared to strings. There are also library function to convert from symbols to strings and vice versa. Symbols are used as symbolic constants (like enumerations in the C language).
Arrays
Arrays are ordered sequences of values. They can be indexed with an integer. Arrays can be nested, and can be initialized with non-constant expressions too.
#[1, 2, 3, 4.0, 'a', "A String", #aSymbol] #[1, 3, 5, #['a', 'b', 'c'], 3 + 4, 11]
Array indexing
a = #["Paris", "Rome", "Washington", "Madrid"]
a[0] will give the value "Paris"
a[1] will give the value "Rome"
a[-1] will give the value "Madrid"
a[-4] will give the value "Paris"
Hashes
Hashes are also known as dictionaries, or tables. They associate values to a key. These keys can then be used later for value retrieval or to memorize a different value.
%["key 1", "value 1", "key 2", "value 2"] %["key 1", 1, "key 2", 2, #key3, 3] %[1, 5, "abc", 6.6, 3.4, "ok", #[1, 2, 3], "cool"]
Hash indexing
a = %[1, 5, "abc", 6.6, 3.4, "ok", #[1, 2, 3], "cool"]
a[1] will give the value 5
a["abc"] will give the value 6.6
a[3.4] will give the value "ok"
a[#[1, 2, 3]] will give the value "cool"
Classes and objects
Classes and class instances (objects) will be explained in a subsequent section of this document.
public class MyClass extends basic.Object { local an_instance_variable; static a_class_variable; method a_normal_method() { basic.print( an_instance_variable ); } class method a_class_method() { basic.print( a_class_variable ); } } local anObject = [MyClass new]; [anObject a_normal_method]; [MyClass a_class_method];
Packages (modules)
Packages are the basic compilation unit in elastiC. The compiler reads the source of a package, producing a bytecode compiled version, suitable for execution by the interpreter. A package can import other packages to reference variables, functions and classes therein contained.
package mypackage; import basic; basic.print( "Hello world !" );
Bytecode
elastiC compiles source code into a special virtual machine sequence of instructions called bytecodes. Modules, functions, classes are all compiled into bytecode. These compiled objects are values as well as integers or strings, and can be manipulated in almost the same ways: they can be memorized in variables, passed to functions, and so on.
For examples the following two pieces of code, defining a function, are equivalent:
public function add(a, b) { return a + b; } private v = add(3, 5);
and
public add; add = function (a, b) { return a + b; }; private v = add(3, 5);
Stacks, primtive functions and methods, handlers
These are of interest only to C extension writers and to (very) advanced elastiC users.
2.5. Expressions
Expression are syntactical units producing values. A formal definition of expressions in elastiC would require the description of a complex grammar, but simply speaking expressions can be constant values or combinations of operations on simpler expressions. Operations are identified by operators and operands (operands are the arguments of the operator, and are expressions again). Expressions can be grouped with parenthesis.
We've already seen constant values when speaking about fundamental types (to be more precise, array and hash construction construction in the above examples are actually examples of expressions).
2.5.1. Operators
Array and hash construction operators
The #[...] syntax we've already encountered is the array construction operator. Similarly the %[...] is the hash construction operators.
Arithmetic operators
Arithmetic unary operators are the unary '+' and '-'.
+5 -4.6
Arithmentic binary operators are '+', '-', '*', '/', '%' (modulus), '**' (pow).
3 + 4 "string " + "concatenation" 2 - 1.5 4.1 * 2 8.0 / 2.0 9 % 2 2 ** 3
The arithmetic operators have the expected precedence relations and group from left to right.
Relational and equality operators
Relational operators are: '<', '<=', '>', '>='
Equality operators are: '==' (equality), '!=' (inequality)
Equality operators have lower priority than relational ones.
Bit-wise logical operators
Bit-wise logical operators are: '&' (arithmetic and), '|' (arithmetic or), '^' (arithmetic xor), '<<' (left shift), '>>' (right shift), '~' (one complement).
Logical operators
Logical operators are: '&&' (logical and), '||' (logical or)
Logical operators are short-circuited: the evaluation stops as soon as possible, without evaluating operands where not needed. For example, in:
@false && myfunction()
the function myfunction won't be called.
Assignment operators
The assignment operator '=' assign the value on the right to the name (variable) on the left. Moreover, binary operators have a corresponding assignment operator form. If OP is one of this operators, then the form:
e1 OP= e2
is equivalent to:
e1 = e1 OP e2
Increment and decrement operators
Increment and decrement operators are respectively '++' and '--', and can be either prefix or postfix. These operators can applied to an expression that could stay at the left of an assignment expression (said l-value). They perform an increment or decrement operation on the expression. The value of the expression is returned after the operation has been performed for the prefix form, and before the modification for the postfix form.
After the execution of the statements:
a = 5; b = ++a;
The following conditions will hold:
a == 6 b == 6
While, after:
a = 5; b = a++;
we'll have:
a == 6 b == 5
Conditional operator
The conditional operator (also known as ternary operator) takes the form:
e1 ? e2 : e3
The expression e1 is evaluated. If it produces a non-false value, then the e2 is evaluated and returned as the global result value, otherwise e3 is evaluated and returned as the global result value.
Sequence operators
The operator in can be used to the the membership of a value to a collection such as an array (or user-defined class instances with support for sequence operations).
"red" in #[1, 2, "green", "yellow", "red"]
will return @true
Function call
The function call is a valid expression. The syntax is:
function(argument-list)
where argument-list is a (possibly empty) comma separated list of expressions and function is an expression returning a callable bytecode object (usually created with the function statement).
Method call
The method call is a valid expression. The allowed syntactical forms are:
[object methodname argument-list]
[object keyword-argument-list]
[super methodname argument-list]
[super keyword-argument-list]
In the first two forms, object is an expression returning a class instance or a class. methodname is a name identifying a method in the class of the called object. argument-list is a (possibly empty) comma separated list of expressions. keyword-argument-list is sytactic form that specifies both the method name and its arguments. For example, in:
[anObject moveToX: 5 andY: 6]
the method name is moveToX:andY: and the arguments are 5 and 6.
The super keyword must be explained after some concepts of OOP have been introduced.
2.5.2. Function definition
Another kind of expression is the function definition. As its name implies it produces a new function, returning a callable bytecode object, that can be used with the function call defined above.
XXX TODO
2.6. Statements
As we've seen, elastiC programs are sequences of declarations, definitions, statements and expressions. Of these, roughly speaking, statements are the basic units of the language producing effects during the execution of the program.
Expressions can become statements when followed by a semicolon ';'. For example:
a = 5;
is an statement composed by an assignment expression.
2.6.1. Blocks
Blocks are groups of statements to be executed in sequence. A block constitutes a compound statement. Blocks can be placed wherever a simple statement would be considered legal. The syntax of a block is:
{ statement-1 ... statement-N }
Blocks can be nested.
2.6.2. Control statements
Selection statements
Looping statements
2.7. Functions
Function definition
Function invocation
2.8. Variables
elastiC makes a strong distinction between values and variables. Variables are essentially locations in memory, identified by a name, where the address of a value can be stored. Note that a variable contains the address of a value, not the value itself ! This implies that a value can be referenced by more than one variable. elastiC variables are not typed: a variable can contain a value of any type. Stated differently:
in elastiC type is a characteristic of values, not variables
This said, in elastiC we can have different kind of variables:
- package variables
- function / method variables
- Variables introduced in classes
When declared, variables can be also be initialized.
Package variables
Package variables are the ones declared at the top level of a package, and are visible in the package starting from the point where they are introduced. They can be of two kinds: public or private (for package variables, local is a synonym for private). Private variables are local to this module and cannot be accessed from the outside. Public variables are visible from other modules through importing and qualification.
package testpackage; public var1; public var2 = 5; private var3; private var4 = 1;
Note: function names are variables. The syntax to introduce a named function is only a shorthand for the sequence of variable declaration, and assignment of the function to the variable (as already mentioned above, functions are first-class objects, like all other values).
Function and method variables
Variables defined inside function and method bodies are visible only there and from the point where they are introduced. There are two kinds of these variables: local and static. Local variables exist only during the execution of the function or method where they have been introduced (but see lexical scoping below for a noteworthy exception) and don't retain the value across successive calls. Static variables work in the same way as local ones except that they retain their value across successive calls. Initialization for static variables is performed only once, during the first invocation of their enclosing function/method.
function localexample() { local v = 5; // a local variable v = v + 1; basic.print( v, '\n' ); } localexample(); localexample(); localexample();
will produce the output:
6 6 6
While:
function staticexample() { static v = 5; // a static variable v = v + 1; basic.print( v, '\n' ); } staticexample(); staticexample(); staticexample();
will produce the output:
6 7 8
Variables introduced in classes
Also said class-introduced, or class-scoped, are not to be confused with class variables (which are a only subset of class-introduced variables). Variables introduced inside class declarations are visible only inside the class body. There are two kind of these variables: instance variables and class variables.
Instance variables are introduced with the keyword local: every class instance (object in the narrower acception) has its own set of private members identified by instance variables. Instance variables can be referenced only from methods.
Class variables are introduced with the keyword static and they introduce members common to every instance of the class: they are a property of the entire class and not of the single instances. Class variables can be referenced from normal methods and from class methods.
2.9. Lexical scoping
elastiC is a lexically scoped language. XXX TODO
2.10. Object Oriented Programming
Class definition
Method definition
Method invocation
2.11. Defining a Module
2.12. Closures
2.13. Exceptions
3. Standard Library
3.1. basic module
3.2. sys module
3.3. math module
3.4. string module
3.5. list module
3.6. array module
3.7. re module
4. Tools
4.1. The ec interpreter
4.2. The ecc compiler
4.3. The ecdump bytecode disassembler
5. Final Considerations
6. See Also
the ec(1) manpage: for the elastiC interpreter
the ecc(1) manpage: for the elastiC compiler
the ecdump(1) manpage: for the bytecode disassembler
[Cox86]: Brad J. Cox, Object Oriented Programmingm An Evolutionary Approach, Productivity Products International, Inc.
7. Author
Marco Pantaleoni (panta@elasticworld.org)
8. Credits
I wish to thank the following people:
B.W. Kernighan, D.M. Ritchie, K. Thompson, R. Pike, for giving us the C programming language and Unix.
L. Torvalds and the other kernel hackers, for letting us common mortals to use a real operating system.
Bill, for letting us to demonstrate how much superior Unix is.
And all the others, that I can't cite in a manual page.
9. Copyright
Copyright (C) 2001 Marco Pantaleoni. All rights reserved.
The contents of this file are subject to the elastiC License version 1.0 (the "elastiC License"); you may not use this file except in compliance with the elastiC License. You may obtain a copy of the elastiC License at http://www.elasticworld.org/LICENSE
IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
See the elastiC License for the specific language governing rights and limitations under the elastiC License.