AÏOLI
What is Aļoli?
Aļoli is a toolkit to build interactive applications that manipulate
data as tree. It is composed of 5 main components:
-
VTP: an API for manipulating trees.
-
METAL: a language for defining tree formalism.
-
ANTLR: a tool for defining LL(k) parsers..
-
PPML: a language for describing layout.
-
GFXOBJ: an API for building interactive application,
To use Aļoli you simply need to add the directory of aioli classes to
your classpath so if Aļoli is installed under net we have:
CLASSPATH:=/net/aioli/classes:$CLASSPATH
There are at the moment 3 contributions to Aļoli:Exp a simple interactive calculator, Lambda a definition of the lambda calculs, Java the definition of a viewer for Java.
VTP
Each tree in Aļoli belongs to a formalism. A formalism contains
a set of operators and a set of phyla, i.e. subsets of the
set of all operators. There are three kinds of operators:
-
List operators have an arbitrary number of sons.
-
The n-ary operators have a fixed number of sons.
-
The atomic operators have no sons but contain an atomic value.
The notion of phylum allows to constrain which trees a given node accepts
as son. The definition of a new operator gives for each son
position a phylum. Note that our lists node are homogeneous so only
one phylum is required for the definition of a list operators. Note
also that a given operator may belong to several phyla.
For interactive application a special encapsulator for tree called
variable is available. It is possible to attach tools to variables
so that each modification on a variable will automatically be sent to the
tool. In particular it is with the tool mechanism that layout update is
implemented.
see: Forrmalism,
Phylum, Operator,
Tree, Variable
METAL
Eventhough it is possible to create formalism directly with the VTP Api,
Metal is a dedicated language that eases this task. Here is the syntax
definition of Metal:
program: "formalism" "of" id "is"
(def ";")*
"end"
;
def: op "->" sons
| phylum "::=" (phylum|op)+
;
sons: phylum "+.."
| phylum "*.."
|"implemented" "as" atomic
| (phylum)*
;
atomic: "STRING"
| "INTEGER"
;
id: ("a".."z"|"A".."Z")("a".."z"|"A".."Z"|"_"|"0".."9")*
op: ("a".."z") ("a".."z"|"A".."Z"|"_"|"0".."9")*
phylum: ("A".."Z") ("a".."z"|"A".."Z"|"_"|"0".."9")*
A formalism description is composed of a list of definitions. Each definition
introduces either an operator or a phylum. The operator definition gives
the name of the operator, its arity and the phyla of its sons. We use the
keywords "+...", "*..", "implemented as" to denote respectively list operators
with at least one element, list operators possibly empty and atomic operators.
The definition of a fixed arity operator simply list the
phyla of its sons. The phylum definition gives the name of the phylum and
the list of its components. Finally we use the syntactical convention
that phylum names always start with an uppercase letter while operator
names start with a lower case.
see: Metal definitions for Exp, Lambda,
Java.
ANTLR
Antlr is a generic LL(k) parser generator. A complete
introduction of Antlr can be found here, We have extended the Antlr syntax
in order to handle Vtp constructs. It gives us an alternative way to write
actions. The standard way to give action in Antlr is by directly writing
Java code between curly brackets "{}" . Vtp actions use the
double brackets "<<>>" as delimitators. Here is the syntax
definition of Vtp actions:
action: <<"" (constr ";")* ">>";
constr: path ("=="|"="|"+="|"=+") pattern;
path: id ("." int)*;
pattern: var
| node "(" (sons)? ")"
| node "[" (sons)? "]"
| node int
| node string
| node var ("^")?
;
var: "*" (id)?;
node: id (":" id)? ;
sons: pattern ("," pattern)*;
string: "\"" (~\"")* "\"";
int: "0"|("1".."9")("0".."9")*
id: ("a".."z"|"A".."Z") ("a".."z"|"A".."Z"|"_"|"0".."9")*
An action is composed of a sequence of atomic actions. There are 4 possible
atomic actions:
-
Var == Pattern defines the variable Var and gives it the
value Pattern
-
Path = Pattern changes the value denoted by Path with the
value of Pattern.
-
Path += Pattern inserts in first position of the subtree denoted
by Path the value of Pattern.
-
Path =+ Pattern inserts in last position of the subtree denoted
by Path the value of Pattern.
A variable in Vtp action corresponds to the variable in Java with the same
name. Note that when a variable is used in a pattern we prefix it with
a "*" to avoid ambiguity. The type of the corresponding Java variable
must be Tree. When we want to use a token to fill in an atomic variable,
we also postfix the name with the symbol "^". In that case the type
of the corresponding Java variable is then Token.
A Path is a variable name plus a possibly empty path using the
standard Dewey notation.
The formalism used to build a node is either given explicitly in the
construction FormalismName:Opname or is implicit. A special
global variable vtpLanguage has been added in the Antlr definition
to be able to set the default formalism.
see: Antlr definitions for Exp, Lambda, Java.
PPML
PPML is a language that describes an automatic translation from a tree
representation into a more concrete representation. The conversion
is given in term of a recursive traversal of the tree with respect
to a set of layout rules. Each rule is composed of a right part that
describes in which cases the rule should be trigerred, and a right part
that describes the corresponding layout . A simple pattern-matching
language is used to give the filters and a combinator-based language
is used to express the expected layout. Here is the syntax definition of Ppml:
program: "prettyprinter" id "of" id
( "is" | "extends" id ("," id)* "with")
("auxillary" "package" string ";")?
( rule ";")*
"end" "prettyprinter"
;
rule: cpattern "->" box;
cpattern: (id ":")? pattern ("!" int)? (annot)?
("when" fun ("and" fun)*)?
;
pattern: var ("as" pattern)?
| id "(" (pattern ("," pattern)*)? ")"
| id "[" (pattern ("," pattern)*)? "]"
| id var ;
| id string ;
fun: fname "(" (farg ("," farg)*)? ")"
;
farg: string
| int
| var
| annot
;
box: string
| (id ":")? var ("!" sint)?
| (id ":")? annot ("!" sint)?
| "in" "class" "=" id ":" box
| fname "(" var ")"
| "(" (box)+ ")"
| "[" combinator (box)+ "]"
| "if" fun ("then" box )? ("else" box )? "end"
| "case" fun (int ":" box)* ("default" ":" box)? "end"
;
combinator: "<" id (int ("," int)*)? ">"
;
var: star | doublestar;
star : "*" (id)?;
doublestar: "**" (id)?;
string: "\"" (~\"")* "\"";
sint: ("-"|"+") int
int: "0"|("1".."9")("0".."9")*
fname: id ("." id)*
id: ("a".."z"|"A".."Z") ("a".."z"|"A".."Z"|"_"|"0".."9")*
annot: "^" id
The traversal of the tree is done using a context name and an integer that
gives an indication of the depth of the recursion. In a pattern it
is possible to match these two quantities. Matching a context name
can be used to define context dependent layout while matching the depth
can be used to get layout of a large tree with a particular detail level.
The initial context is the default context "0". A rule without
context belongs to the default context.
The pattern language allows to match fixed-arity tree, list and atomic
nodes. It accommodates aliasing and extra booleans constraints. Variables
in patterns are used to represent either a single subtree or a list of
subtree. We use the syntactically convention that the former ones are prefixed
by a single star while the latter ones are prefixed by a double star. For
example in the pattern node[*x,**y,*z], *x denotes the first
subtree, *z the last one, and **y the immediate subtrees
of the node except the first and the last one.
The combinator-based language allows to define box structures. Each
box starts with a combinator that describes how the elements in the
box have to be displayed. For the moment only 3 combinators are available:
- <h n> is the horizontal combinator. It displays
the element of the box in an horizontal manner with an interword of n
between them.
- <v n, m> is the vertical combinator. It displays the elements
of the box in a vertical manner with an indentation of n with an
interline of m.
- <hv n, m, p> is the paragraph combinator. It displays the
elements of the box in a paragraph style using the page width with an interword
of n, an indentation of m and an interline of p
Variables are used to do recursive calls. It is possible to explicitly
change the context and increment or decrement the depth. Implicitly
recursive calls without context are done in the default context and recursive
calls without depth information are done with a decrement of
one. Sublist variables are dealt by the recursor "()", for example [<h
0> ( **x ) ] generates a horizontal box whose elements are
the recursive calls on the trees of the sublist **x.
The language accommodates conditionnal layout by allowing conditionnal over
external boolean functions (if) or external integer function (case).
Terminal are represented by strings that can either be given explicitly
or via an external function taking a variable as parameter. Finally it
is possible to hook a graphic attribute class to box using the "in" keyword.
Graphic attributes are used to retrieve the foreground color, background
color and fonts. A terminal inherits the attribute class of its father.
A box without attribute inherits of its father. The initial class atrribute
is "default".
Finally the keyword "auxillary package" is used to define which package is to be used for external function, if not specified the default package is aioli.lang.ppaux.
see: Ppml definitions for Exp, Lambda, Java
Gfxobj
Gfxobj contains a set of classes that helps building interactive application
using Vtp trees. The main class is the Ctedit.
It is displays a tree using a given prettyprinter, a page width and a detail level.