|
|
|
The FunLog++ interpreter call
FunLog++ syntax is very simple. A FunLog++ program is a sequence of functions. A FunLog++ function is either a method, an inlay or a class. Methods and classes are syntactically very similar as both consist of a receptor, a public (::=) or private (::-) is-defined-as symbol, a method body or a function body, and a finishing point. The bodies of classes and methods are different. A class body begins with a curly opening bracket, followed by a sequence of (sub-)functions, and is finished by curly closing bracket. A method body, in contrast, is a message which is a functional, a formula, an atomic, a constant, a list, or a variable. A third sort of function is an inlay which looks like a receptorless method. Inlays define inheritance links between objects.
We introduce the notion of rootclass for a (invisible) class comprehending all programs of different FunLog++ source files belonging to an application. We call a function A to be an element of class B if A is in the function list of the program of B.
As classes may contain other (sub-)classes we get a static class hierarchie. This hierarchie allows an absolute or relative denotation of any function by an appropriate message.
The signature of a receptor or message is its name plus its arity (number of parameters). A function is suitable to a message if its receptor signature is the same as the message signature. An inlay function is suitable to all messages. Private functions are only visible to messages from within the same class, public functions are visible to all messages.
program :: | functions. |
functions :: | function; functions, function. |
function :: | class; method; inlay. |
class :: | receptor, isdefinedas, classbody, ".". |
method :: | receptor, ".";
receptor, isdefinedas, methodbody, ".". |
inlay :: | isdefinedas, inlaybody, ".". |
isdefinedas:: | "::="; "::-". |
classbody :: | "{", "}" ;"{", program, "}". |
methodbody :: | message. |
inlaybody :: | message. |
A list is a data structure, e.g. [3,5,7,11], which is used to represent an ordered sequence of arbitrary objects. A list may be seen as one or more head element followed by a list of tail elements. There is also a denotation, e.g. [3,5,7,11,|MORE], where the list of tail elements is a variable, e.g. MORE. List objects are enclosed in square brackets. Number of list elements may increase as long as the sublist of tail elements is a variable. [ ]is the empty list denotation which has no elements. Comment: Due to an error in the current FunLog++ compiler version it is important to have at least one character (e.g. a blank) between [ and].
formula(P) :: | prefix(P); infix(P); postfix(P). |
prefix(P) :: | operator("fx",P), operand(P-1). |
infix(P) :: | operand(P-1), operator("xfx",P), operand(P-1);
operand(P-1), operator("xfy",P), operand(P); operand(P), operator("yfx",P), operand(P-1). |
postfix(P) :: | operand(P-1), operator("yf",P). |
list :: | "[", "]"; "[", parameters, "]"; "[", parameters, listtail, "]". |
listtail :: | "|", variable name; "|", list. |
constant :: | number; text. |
number :: | Informal syntax definition: A number constant is an integer or a real. An integer constant is a sequence of digits. A real constants is a sequence of digits, followed by a fractional part and/or followed by an exponent. A fractional part is a decimal point followed by a sequence of digits. An exponent part is the letter E (always upper case) followed by an optional sign followed by an integer. |
text :: | Informal syntax definition: A text constant is a sequence of characters written within double quotes. Within the quotes any printing character other than \ or " is represented by itself. Other characters are represented by escape sequences beginning with \. |
operator(Type,Priority) :: | Informal syntax definition: An operator(Type,Priority) is one of the atomics mentioned as operator name in one of the following three tables. In order to be accepted Type must be one of symbols (fx, xfx, xfy, yfx, yf) mentions as the operator's type. Furthermore Priority must be a number greater or equal to the operator's priority given in the table below. |
atomic :: | name. |
function name :: | Informal syntax definition: A function name (1) begins with a lower case letter and consists entirely of letters, numbers and the underscore character; or (2) consists entirely of symbol characters, that is: + - * / \ ^ < > = ~ : . % ? ! @ # $ , ; & ; or (3) is any sequence of characters in single quotes where the quote itself is represented by two quotes. |
variable name :: | A variable name is a symbol, beginning with a capital letter or an underscore and followed by letters, digits, or underscore characters. Examples of variable names are A, SELF, MORE, _12345, _. |
The following three tables relate operator symbol with its type (fx, xfx, xfy, yfx, xf) and its priority (an integer between 0 and 12). Operators with high priority numbers bind loose while operators with low priorities bind tight. In the first table operators for control-, unification-, and ordering functions are shown:
|
In the following table operators for concatenation, arithmetic, and interval construction are listed:
|
|
A command
is also a data structure at runtime. It is determined by a specific message
in a FunLog++ program plus its actual parameters which are objects or commands.
An object is obtained as the final result of the evaluation of a command,
the resulting object of that command. So a command is equivalent with its
resulting object. It is in some sense a not (or not completely) evaluated
object. Commands are important for lazy evaluation. A command is the runtime
equivalent of the compiletime construct message.
|
alpha/0 is super-class of beta/0. beta/0 is sub-class of alpha/0. Class beta/0 is one of the functions of alpha/0. The result of message omega is "Hello world". |
A receiving class may also be calculated during evaluation. E.g. X:display(T) is subfunction display(T) in the receiver X whereX has to be a known object at the time of evaluation of X:display(T). In FunLog++ it is not possible to calculateX during evaluation of X:display(T). But the following message is legal: X = :standard:number(N), X:display(T).
From within a function receptor (the handle) or from within a message we can refer to the surrounding class object be the reserved Variable name SELF. But in FunLog++ it is not possible to calculate some object in the superclass of some object X. (We could want to write X:..:alpha to denote some object alpha in the superclass of X.)
The user of some function need not to know if it denotes a class or a method. In any case he/she gets the parameters and the result unified with appropriate objects. Thus methods may be used to rename or shortcut other methods or classes. That is why FunLog++ syntax is so simple.
|
alpha/0 is child-class of gamma/0. gamma/0 is parent-class of alpha/0. Class alpha/0 inherits from class gamma/0 by the inlay function ::= :gamma. The result of message omega is "Hello world". |
A command is suitable to a function
if name and arity (=number of parameters) are equal. A command is acceptable
to a function if there is no failing gate condition. Class definitions
have no gate conditions and so always accept. A method definition accepts
a command if the evaluation of the method body does not return the
missing/0 object. The
missing/0 object is not visible
to the programmer but it is internally used to find the suitable function
definition. The missing/0 object is generated if the left hand operand
of the gate operator fails, i.e. if A fails
in A | B. As
non variable formal method parameters are converted using the gate operator
|/2 , unsuccessful pattern
matching also generates a missing/0 object.
E.g.
say("red") ::= "The colour is red".
say("yellow") ::= "The colour is yellow".
say("green") ::= "The colour is green".
The three function definitions of say/1 is converted internally by the FunLog++ compiler to a function
say(X) ::= X="red"
| "The colour is red"
:: X="yellow" | "The colour is yellow"
:: X="green" | "The colour is green".
The formal parameter X is tested by unification if it is red, yellow or green. The ::/2 operator returns its left operand if this is not missing/0, otherwise it returns its right operand. The command say("blue") will be suitable to say/1 as it also has one parameter. But as the gate condition fails for all alternatives, this say/1 method definition will return missing/0.
If there is no suitable function
or if a suitable function definition is not acceptable then inheritance
is tried. That means that if there is a inlay function then its body is
evaluated returning a receiver object. Then the command is tried to be
identified in the program of that receiver object. If local identification
and inheritance fail then the so called parameter oriented command identification
is tried.
If context oriented command identification fails then the command's parameter list is evaluated. If there are parameters then the first parameter is evaluated. Then the class of the obtained parameter object is tried as a context to find a suitable, fitting and acceptable function definition. If the first parameters does not work then the next parameter is tried, and so on. If the command has no parameters at all then the system class atomic/0 is tried as a last choice. If neither a parameter's class nor class atomic/0 worked then the system exception object exception("function undefined",Source) is returned.
With parameter oriented command identification a further condition has to be fulfilled. The parameter position used for the new identification context must fit the function definition, i.e. the function in question must have a formal parameter called SELF in the appropriate position. E.g. in the standard library class number/1 there is a method sqrt/1 which only can be identified through its parameter.
number(A) ::= {
...
sqrt(SELF) ::= power(A,0.5).
...
}.
Or as a second example in standard library class list/1 the method member/2 is identified through its second parameter which always is a list.
list(A) ::= {
...
member(_,SELF)
::= SELF = [ ] | failure.
member(ELEM,SELF) ::=
SELF = [Head|_] | ELEM == Head.
member(ELEM,SELF) ::=
SELF = [_|List], member(ELEM,List).
...
}.
Finally parameterless commands may be identify their method in the system class atomic/0. E.g. the message pi/0 may be calculated that way.
atomic ::= {
...
pi ::= 3.14.
...
}.
A important consequence of this technique
of parameter oriented command identification is, that a FunLog++ programmer
needs no knowledge about the internal structure of the standard library
nor about its class names. This works as the FunLog++ compiler recognizes
the type of number, text, and list denotations and it then generates code
to build up an object of the appropriate class. So a command like
sqrt(pi) can easy be evaluated
as first pi/0 is
found in class atomic/0
and
then sqrt(3.14) is
found in class number/0. No
class selector and no inheritance is needed for that.
|
|