-
Notifications
You must be signed in to change notification settings - Fork 0
Liberty compiler design notes
This document is by no means an exhaustive “detailed design document”. I don’t believe in those; they are bound not to be up-to-date.
On the other hand one needs a few architecture and general design notes to understand how the Liberty compiler is built. For details… read the code.
The Liberty parser uses a general parsing library. Note that the LIberty Eiffel grammar belongs to the library, so anyone may build parsers using the exact Liberty language definition.
The nodes produced by the parser are “AST” nodes (Abstract Syntactic Tree). Those nodes may be found in the src/tools/syntax/tree cluster.
The root node of an AST is a class.
It is the most important tree. The root node of a semantics tree is LIBERTY_TYPE
, which represents a type of the system.
Note the difference between “syntax” and “semantics”:
- the “syntax” trees represent classes, i.e. a syntactic representation of one or more types (think generics here)
- the “semantics” tree represent types, with:
The semantics nodes are in the src/tools/semantics cluster and sub-clusters:
- contract contains the pre- and post-conditions, invariants, and so on
-
entities contains all the kinds of named entities which conform to
LIBERTY_ENTITY
-
expressions contains all the kinds of expressions which conform to
LIBERTY_EXPRESSION
-
features contains all the kinds of features which conform to
LIBERTY_FEATURE
: attributes, constants, deferred, do-, and once-functions -
instructions contains all the kinds of instructions which conform to
LIBERTY_INSTRUCTION
The class LIBERTY_TYPE_BUILDER
is in charge of building a LIBERTY_TYPE
from a LIBERTY_AST_CLASS
and a set of LIBERTY_TYPE
representing the actual generic parameters.
The class LIBERTY_UNIVERSE
is in charge of holding all the instances of LIBERTY_TYPE
.
A static type is a self-sufficient semantical structure that is attached to every expression of the system. It allows to discover some properties about the system.
A dynamic type is the run-time type of an expression. The compiler will be able to compute the complete set of possible dynamic types at each point of the progrom, thus allowing the optimization of the late-binding sites.
Each feature is defined in two steps:
- the feature definition which binds a feature to a type via its name.
- the actual feature which defines the feature without a name.
The feature hierarchy is:
-
LIBERTY_FEATURE
: any kind of feature with a contract (preconditions and postconditions)-
LIBERTY_FEATURE_CONSTANT
: feature defined with a manifest expression -
LIBERTY_FEATURE_ATTRIBUTE
: attributes -
LIBERTY_FEATURE_ROUTINE
: routines (with locals, and do/once and rescue instruction blocks)-
LIBERTY_FEATURE_DO
: “do” routines -
LIBERTY_FEATURE_ONCE
: “once” routines
-
-
LIBERTY_FEATURE_DEFERRED
: deferred features -
LIBERTY_FEATURE_EXTERNAL
: external features -
LIBERTY_FEATURE_REDEFINED
: redefined features (serve as proxy to the real redefined feature, useful to check that all the features marked as redefined are actually redefined) -
LIBERTY_FEATURE_UNIQUE
: the old “unique” constants
-