CLAIRE Grammar
a. Identifiers in the claire Language
A name expression in the claire language is called an identifier. It is used to designate a named object or a variable inside a claire expression. Each identifier belongs to a namespace. When it is not specified, the namespace is determined by the current reading environment, the identifier is unqualified. A qualified identifier contains its namespace as a qualification, designed by another identifier (the name of the namespace), followed by a slash '/', itself followed by the unqualified form of the identifier.
An unqualified identifier in claire is a non-empty sequence of basic characters, beginning with a non-numerical character. A basic character is any character, with the exception of '[', ']', '{', '}', '(', ')', ' '(space), EOL (end of line), ';', '”', '’', '/', '@' and ':' that play a special role in the grammar. The first six are used to define expressions. Spaces and EOL are meaningless, but are not allowed inside identifiers (therefore they are separators characters). The characters ';', ''', '"', '@', '/' and ':' are reserved to the claire system. An identifier should not start with the character #. Each sequence of characters defines one unique identifier, inside a given namespace. Identifiers are used to name objects from thing, and unqualified identifiers are used for variables.
<ident> :: <unqualified identifier> | <qualified identifier>
<qualified identifier> :: <identifier>/<unqualified identifier>
<unqualified identifier> :: <'a' .. 'Z'><basic character>*
<var> :: <unqualified identifier>
Implementation note: in claire, the length of an unqualified identifier is limited to 50 characters.
b. Symbols
Identifiers are represented in claire with entities called symbols. Each identifier is represented by a symbol. A symbol is defined by a namespace (where the identifier belongs), a name (the sequence of character from the unqualified symbol) and a status. The status of a symbol is either private or export (the default status). When the status of an identifier is private, the reader will not recognize the qualified form from a module that is not a sub-module of that of the identifier. Therefore, the only way to read the identifier is inside its own namespace. When the status of the identifier is export, the qualified form gives access to the designated object, if the sharing declarations of namespaces have been properly set (Section 6.1).
Each symbol may be bound to the object that it designates. The object becomes the value of the symbol. The name of the object must be the symbol itself. In addition, the symbol collects another piece of useful information: the module where its value (the named object) is defined. If the symbol is defined locally (through a private or export definition), this definition module is the same as the owner of the symbol itself. If the symbol is shared (if it was defined as an identifier of an above module), this module is a subpart of the owner of the symbol.
claire now supports a simple syntax for creating symbols directly, in addition to the various methods provided in the API. Symbols can be entered in the same way that they are printed, by indicating the module (namespace) to which the symbol belongs and the associated string, separated by a « / ».
<claire symbol> :: <module>/<string>
c. Characters and Strings
Characters are claire objects, which can be expressed with the following syntax:
<claire character> :: ' <character> '
Strings are objects defined as a sequence of characters. A string expression is a sequence of characters beginning and ending with ' " '. Any character may appear inside the string, but the character ' " '. Should this character be needed inside a string, it must be preceded by the ' \ ' character.
< string> :: " < <character> - ' "' >* "
The empty string, for instance, is expressed by: "". Note that the "line break" character can be either a line break (new line) or the special representation '\n'.
d. Integer and Floats
Numbers in claire can either be integers or floating numbers. Only the decimal representation of integers and floats is allowed. The syntax for integer is straightforward:
<integer> :: < - >° <positive integer>
<positive integer> :: <'0' .. '9'>+
If the integer value is too large, an overflow error is produced. The syntax for floating numbers is also very classical:
<float> :: < <integer>.<positive integer> |
<integer><.<positive integer>>opt e < + | - >opt <positive integer> >
Convention note: in this grammar we use <a>° to represent the fact that a is optional. <a>° = <a> | <nothing>
Similarly, we use <a>seq to represent a sequence of <a> separated by commas.
<a>seq+ represents a non empty sequence
Implementation note: in claire 4, integers and floats use a 64 bits representation.
e. Booleans and External Functions
The two boolean values of claire are false and true:
<boolean> :: false | true
External functions may be represented inside the claire system. An external function is defined with the following syntax:
<external_function> :: function!(<unqualified identifier>, <integer> )
The identifier must be the name of a function defined elsewhere.
f. Spaces, Lines and Comments
Spaces and end_of_lines are not meaningful in claire. However they play a role of separator:
<separator> :: | | [ | ] | { | } | ( | ) | : | " | ' | ; |
@ | SPACE | EOL | / <basic character> º <character - separator>
Comments may be placed after a '//' on any line of text. Whatever is between a ‘//’ or a ';' and a EOL character is considered as a comment and ignored. Also, the C syntax for block (multiple lines) is supported:
<comment> :: //'<character - EOL>* EOL |
;'<character - EOL>* EOL |
/* <<character> | *<character - />>* */
Comments that use ‘;’ are provided for upward compatibility reasons. However, claire comments defined with //, as in C++, have a special status since they are passed into the code generated by the compiler (for those comments that are defined between blocks). Thus, it may be useful to use « old-fashioned » comments when this behavior is not desirable.
Named objects (also called things) are also designated entities, since they can be designated by their names. The following convention is used in this syntax description for any class C:
<C> :: <x:identifier, where x is the name of a member of class C>
This convention will be used for <class>, <property> and <table>.
The set of designated entities is, therefore, defined by:
<designated entity> :: <thing> | <integer> | <float> |
<boolean> | <external function> |
<claire character> | <string>
g. Grammar
Here is a summary of the grammar. A program (or the transcript of an interpreted session) is a list of blocks. Blocks are made of definitions delimited by square brackets and of expressions, either called <exp>, when they need not to be surrounded by parentheses or <fragment> when they do.
<program> :: <block>seq+
<block> :: (<fragment>) | <definition> | <declaration call>
<fragment> :: < <statement | <conditional> >seq
<statement> :: for <var def> in <exp> <statement> |
while <exp> <statement> |
until <exp> <statement> |
let < <var def> := <comp-exp> >seq+ in <statement> |
when <var def> := <comp-exp> in <statement> |
case <exp> ( <<type> <statement> >seq+ ) |
try <statement> catch <type> <statement> |
branch( <statement> ) |
<comp-exp> | <update>
<definition> :: <ident> :: <exp> |
<var def> :: <exp> |
<ident>(< <var>:<type with var> >seq) : <range>
< -> | => > <body> |
<ident>[<var def>] : <type> := <fragment> |
<ident><[<var>seq+]>° <: <class>
< (< <property> : <type> < = <exp> >° >seq+) >° |
<ident>() :: rule(<event pattern> < & <exp> >° => <fragment>)
<conditional> :: if <exp> <statement> < else <conditional> | <statement> >°
<body> :: <exp> | let < <var def> := <comp-exp> >seq+ in (<exp>)
<update> :: < <var> | <property>(<exp>) | <table>[<exp>seq+] >
:<operation> <comp-exp>
<event pattern> :: < <var>.<property> | <table>[<var>]> < := | :add > <var>>° |
< <var>.<property> | <table>[<var>] > := ( <var> -> <var>) |
<property>(<var>,<var>)
The basic building block for a claire instruction is an expression. The grammar considers different kinds of expressions :
<comp-exp> :: <exp> | <exp> as <type> | <comp-exp> <operation> <comp-exp>
<exp> :: <ident> | <set exp> | <fragment> |
<call> | <slot> | break(<exp>) |
<table>[<exp>] | <class>(á <property> = <exp> ñseq ) |
lambda[á <var>:<type> ñseq, <exp>]
(á <var>á:<type>>ñopt ñseq ){ á<exp>ñseq }
<set exp> set<memtype>opt(<comp-exp>seq+) |
list<memtype>opt (<comp-exp>seq+) |
{ <const>seq+ } | <type> |
list<memtype>opt { <var> in <exp> | <statement> } |
(set<memtype>)opt{ <var> in <exp> | <statement> } |
list<memtype>opt { <exp> | <var> in <exp> } |
á set<memtype> ñopt{ <exp> | <var> in <exp> } |
forall(<var> in <exp> | <statement> ) |
some(<var> in <exp> | <statement> ) |
exists(<var> in <exp> | <statement> )
<memtype> :: ‘<’<type>’>’
<call> :: <function> <@ <type> >°(<comp-exp>seq)
<slot> :: <exp> . <property>