|
Leonardus
|
A general-purpose programming language LeoScript.
lb and lc as console applications
IDEA: blue print: Chapter 3 Language from the red book...
This project aims to achieve compatibility with the programming language
aspects of PostScript Level 3 as defined in the Red Book, excluding all
graphics-related features and printer-specific functionality.
The following operators and objects are not implemented, as they fall outside
the project’s scope:
packedarray, setpacking, currentpacking)globaldict and $error dictionariesmaxlength and cvrs operatorsThe following operators are not implemented due to either the potential for
improved alternatives or the pursuit of a fundamentally different approach:
start, stop, stoppedtoken operatorcvi and cvr for stringsexec for stringsexecutive, prompt, echoexecuteonly, noaccess, readonlyrcheck, wcheckLeonardus returns a language level 4. This can be used to code scripts
for both PostScript and LeoScipt. E.g.:
IDEA: TBD...
All the details are extracted from the source code into the chapter Operators.
Conceptually, for an ISO 639-2 language code xyz, there exists a vocabulary
named translate.xyz.
By using the LeoScript directive
at the beginning of a script, the translations for the language code xyz are activated.
You can query the status of the translation to language xyz by using
the Linux man page system:
The parser reads from the standard input stream, runs checks and normalizes
it into the leon-format on standard out. It also executes the vocabulary operator.
It ignores the remainder of lines starting with %. Additionally it ignores
a shebang line.
It halts execution upon error detection.
It normalizes integer tokens by stripping leading plus signs.
It removes the opening and closing parentheses from the string.
It removes all single backslashes from the string, preserving double
backslashes (\\) and newline sequences (\n). These are the only
escape sequences recognized in the leon-format.
There are limits set by the parser to check the plausibility of LeoScripts.
This is a simple line-oriented format.
Each line begins with a character code followed by a colon (:).
The code identifies the data type of the subsequent value.
The different codes and data types are:
| . | Description |
|---|---|
| I | A signed integer |
| R | A floating-point number |
| B | A boolean literal |
| S | An unquoted string with just two escape sequences \\ and \n |
| N | A literal name token consisting of any characters but whitespaces |
| X | An executable name token consisting of any characters but whitespaces |
| # | The value is a comment |
| E | An error message |
All strings and names can contain Unicode characters.
They are encoded using UTF-8.
Stack objects are used internally by the interpreter. They are used to
construct the data structures for the operand stack, the execution stack,
and the dictionary stack.
Additionally, stack objects are composite semantic objects such as arrays,
dictionaries, and strings.
Stack specific operators are:
Polymorphic operators working on stacks are: get, put, forall, type
Text representation for stacks: cvs, =, stack, __print, ==, pstack
Type agnostic operators: def, dup, cvx, cvlit, xcheck, where, known, exch,
load, roll, ...
Rational objects are used to store a fraction with arbitrary precision.
There is no limit check for the length of the numerator and denominator
which build the internal structure.
Specific operators for the rationals are:
Polymorphic operators working on rationals are:
Text representation for stacks: cvs, =, stack, __print, ==, pstack
Type agnostic operators: def, dup, cvx, cvlit, xcheck, where, known, exch,
load, roll, ...
The following operators extend LeoScript with OOP capabilities:
These operators are implemented in the vocabulary Prototype.
To create a new PTBO without a parent:
To create a new PTBO with a parent:
To override a member procedure of a parent PTBO:
To verify that a member procedure exists in a parent PTBO by using override:
To enter the namespace of a PTBO and define a member:
To enter the namespace of a PTBO and define a procedure:
To enter the namespace of a PTBO and call a member procedure:
To enter the namespace of a PTBO and call a member procedure in send semantics:
To call a core code operator, if it has been overridden in a PTBO namespace:
A ctor supporting chaining:
To create an PTBO with a constructor with parameters:
To use the object chaining of the new operator:
The ctor is a normal procedure:
Object chaining:
__ctor__ is called if there is one.
__ctor__ can consume SOs from the operand stack, but must not store
an SO on the operand stack.
IDEA: details...
LeoScript supports the concept of polymorphism, implemented through operator
overloading. For example, the 'add' operator can handle integers, real
numbers, and rational numbers with the same semantics. Using polymorphic
operators allows the programming of procedures or algorithms built on top of
them, which also become polymorphic. A useful example here is the
implementation of 'binom'.
LeoScript provides generic containers. Both arrays and dictionaries can hold
objects of any type.
There are the operators '__one' and '__zero' to program constant numeric
values.
See VOCABULARY
Leonardus supports a shebang line
#!/usr/bin/env lb
by ignoring it as first line in LeoScript files. Together with the normal
Linux executable file attibute you get the possibility to start
scripts directly. This is implemented in the Example directory scripts.
The composite semantic objects can contain other composite semantic objects,
creating trees of objects. All existing semantic objects are part of one of
the three fundamental interpreter stacks: the operand stack, the execution
stack, and the dictionary stack. Loops are not allowed in these trees and
will be detected during runtime by a heuristic.
The loop detection is implemented as a member function
SOcomposite::treeheight(), which calculates the height of the trees and
stops the calculation if the height reaches a threshold of maxtreeheight.
quit )
is a valid programm. While the parser finds the syntax error, the execution
of the quit operator prevents it from taking effect.
1 { 1
is a valid programm. The interpreter exits by ignoring the open procedure.
/X { X } def X
generates an infinite loop of the intepreter. It is very hard to identify
this kind of problems, because with an exit criterion between { and X
it was a perfectly valid script!