Identifiers (denoted below as ID) are composed of
letters, digits and underscores and have to begin with a letter.
Preprocessor
The preprocessor understands a subset of Prolog described with the following grammar:
<program> ::= <program> <clause>
| <clause>
<clause> ::= <predicate> "."
| <predicate> ":-" <predicate-alt> "."
<predicate-alt> ::= <predicate-alt> ";" <predicate-con>
| <predicate-con>
<predicate-con> ::= <predicate-con> "," <predicate-simple>
| <predicate-simple>
<predicate-simple> ::= <predicate>
| "(" <predicate-alt> ")"
<predicate> ::= ID "(" <term-list> ")"
| ID
| "!"
| <term-relation>
<term-relation> ::= VAR "is" <term>
| VAR "=" <term>
| VAR ">" <term>
| VAR "<" <term>
| VAR "<=" <term>
| VAR ">=" <term>
<term-list> ::= <term-list> "," <term> | <term>
<compound-term> ::= <term>
| <term> "+" <term>
| <term> "-" <term>
<term> ::= VAR
| "_"
| ID
| ID "(" <term-list> ")"
| <list>
| STRING
| NUMBER
| "(" <term-list> ")"
<list> ::= "[" <term-list> "|" <term> "]" |
"[" <term-list> "]"
The preprocessor performs the following substitutions:
- Replaces list syntactic sugar with
consandnilconstructors. - Replaces numbers with the term
number. - Replaces strings with the term
string. - Adds
tupleXconstructors at the top of every predicate argument. - Replaces underscores with fresh variables.
- Unfolds alternatives.
- Replaces infix operators with constructors:
a + bwithplus(a,b)a - bwithminus(a,b)
- Replaces comparators with predicates:
a = bwithopeq(tuple2(a,b))a < bwithopsm(tuple2(a,b))a > bwithopgr(tuple2(a,b))a <= bwithopse(tuple2(a,b))a >= bwithopge(tuple2(a,b))
- Ignores exclamations.
It is important to notice that type definitions may only use the core language, not the language understood by the preprocessor.
Type Definitions
Directional types are defined by tree automata. A file with type definitions contains only a list of transitions in the following format:
f(s1, s2,...,sn) is s0.
where f is an n-ary function symbol and
s0,...,sn are states of the
automaton. The following grammar has to be obeyed:
<transition-list> ::= <transition-list> <transition> | <transition>
<transition> ::= <body> "is" ID "."
<body> ::= ID "(" <state-list> ")" | ID
<state-list> ::= <state-list> "," ID | ID
The set of states of the automaton is derived implicitly from the list
of transitions. Additionally, the special state top is
recognized by the parser as the sink-state. Formally speaking:
if there exists no transition for some n-ary function
symbol f and some states
s1,...,sn, then the automaton gets
extended with the following transition:
f(s1,...,sn) is top.
Example
An example of a type definition:
nil is list.
cons (top, list) is list.
The above definition describes a tree automaton with the
states top and list. The following terms
are examples of terms recognized by the tree automaton with the
accepting state list:
nil
cons (nil, nil)
cons (zero, cons (zero, nil))
cons (nil, cons (zero, nil))
One of the most important aspects of regular types is that there is no possibility of encoding parametric polymorphism.
Type Annotations
Type annotations need to be given in a separate file so you do not have to modify your source files. They have to respect the following grammar:
<type-list> ::= <type-list> <type>
<type> ::= ID ":" ID "->" ID "."
Type annotations define the accepting states of the automata for input and output types of the predicate.