Chimera
This programming language is not final yet. Suggestions are much appreciated. The language is not turing-complete (yet ^^) I think.
Chimera is a esoteric programming language that emphasizes on OOP and Functional Programming concepts.
Objects in Chimera
In Chimera everything is an object. But unlike in other object-oriented languages object really means object. Instead of defining classes that represents objects, you have an object and describe behaviour via object expansion (see below).
An object itself is already information on which other object behave differently. For example if you got a tennis ball you behave differently if you had a basketball. In Chimera you define the behaviour an object has, when a certain object is passed (see object passing below).
Objects are denoted with uppercase words. The object exists as soon as it's name is written (there's is no need to create an object via a new keyword or such). Also this means that every object with the same name is equal.
Object Expansion
Every objects starts as a so called raw object. This object does not have any behaviour, but could be passed to other objects to cause some behaviour. To define behaviour the principle of object expansion is used. Object expansion could be used anytime (even in runtime).
The syntax is as follows:
OBJECT.(::[OBJECT] -> f)
where f is a lambda function.
As one can see, you specify which objects are needed for which behaviour.
One could also specify a '?' instead of OBJECT to denote that any object is possible (see wildcards for more information).
Object Passing
In order to activate a certain behaviour on an object, one must pass other objects. This is done as follows
OBJECT.(OBJECT)
This will look up if a behaviour was specified (with object expansion) that has the right "parameter list". If this is the case the lambda function f will be run, otherwise the passing will be ignored.
Special Objects
INTEGER
INTEGER is a special object, to which you could only pass object but you can not expand. A correct usage of INTEGER is the following
INTEGER.(1)
This will create an object called "INTEGER.(1)" which represents the number 1 as an object. On this new object you could use object expansion. The new object has special semantics in case of the object operations (see below)
TUPLE
A tuple object is defined as follows
TUPLE.(A,B)
where A and B are objects. As with INTEGER this will create an object called "TUPLE.(A,B)". Additionally the following holds
(TUPLE.(A,B)).(FIRST) = A (TUPLE.(A,B)).(SECOND) = B
IN and OUT
This special objects are use to receive user input and output. The only valid syntax for both of this objects are
IN.() OUT.(INTEGER)
There's no object expansion possible.
IN returns an INTEGER object (depending on what the user inputed). OUT outputs an INTEGER object.
Object Operations
+
The '+' operator is object sensitive.
- INTEGER+INTEGER: the two integer values are added together. The following should hold:
INTEGER.(1)+INTEGER.(2) = INTEGER.(1+2)
The objects OUT and IN can not be used with the '+' operator. In any other case the following happens: (consider two objects A and B)
- A new object is created with the name "A+B"
- the new object inherits the behaviour of both objects. If the "parameters" are the same, then the later (in this case B) is used (see example below).
- the new object can be passed wherever an A or B object we're possible
- the new object can be expanded
-
The '-' operator is object sensitive
- INTEGER-INTEGER: the two integer values are substracted. The following should hold:
INTEGER.(1)-INTEGER.(2) = INTEGER.(1-2)
any other behaviour is undefined.
Functions
Lambda Functions
Wildcards
Implementation
Basic concept
Basically the interpreter works with a stack. The stack is only used for handling object passing (as object expansion can be handled very easily directly). If it is an object passing the object on which to pass the objects is pushed onto the stack (with some additional information, that we have an object passing). The body then get's parsed itself (the body is that stuff between the '('..')' btw ^^). if it's not an object passing then it is just an object (aka. argument). This object then gets pushed onto the stack.
After everything has been parsed the stack is traversed. If on top of the stack is an argument, this object get's pushed into a special register (argument register). If the top of the stack is an Object that waits for object passing the object is passed the argument from the argument register. If this register is empty, an Exception get's raised.
Example
consider the following line
A.(B.(TEST))
then after the parsing step the stack looks like this
+-----------------------------+ |TEST (Object/Argument | +-----------------------------+ |B (Object Passing) | +-----------------------------+ |A (Object Passing) | +-----------------------------+
The Special register is empty. After the first interpretation step the stack looks like this
+-----------------------------+ |B (Object Passing) | +-----------------------------+ |A (Object Passing) | +-----------------------------+
The Special register looks like this
+-----------------------------+ |TEST | +-----------------------------+
After the second interpretation step the stack looks like this
+-----------------------------+ |A (Object Passing) | +-----------------------------+
The Special register is empty (as B.(TEST) did not return anything)
The third interpretation step will raise an exception as the special register is empty.
Programming Examples
have to be rewritten due to the fact the syntax has changed
Factorial
MULT.(::[INTEGER.(?),INTEGER.(1)] -> (\x,y -> x)) MULT.(::[INTEGER.(?),INTEGER.(?)] -> (\x,y -> x + MULT.(x,y – INTEGER.(1)))) FACT.(::[INTEGER.(0)] -> (\x -> INTEGER.(1))) FACT.(::[INTEGER.(?)] -> (\x -> MULT.(x,FACT.(x – INTEGER.(1))))) OUT.(FACT.(IN.()))
Object Addition
A.(::[HELLO] -> (\x -> STRING.(“Ciao!”)) A.(::[INTEGER.(?)] -> (\x -> x+INTEGER.(1)) B.(::[HELLO] -> (\x -> STRING.(“Bonjour!”)) C.(::[?] -> (\x -> A+B)) OUT.(C.(HELLO)) OUT.(C.(1))
Outputs "Bonjour!2"