README

* General informations
To know how to write programs in the DSL take a look at the example files present
in the directory (*.proto).
To translate them into ocaml modules you first need to compile protocols/genproto.ml
and call it as described at the end of this file.
This will produce a trx file and an OCaml file/module which you will use afterward
in your applications.
There are a few examples of minimalistic applications using the generated ocaml
module for the moment, you might want to take a look at them, they're placed in
libnet and libnet/test.
* More info about the DSL itself
** The symbol "+" :
It's used to define the entering node of the automata. (there can only be one)
** The symbol "-!-" :
It's used to close the connection (it *must* be used in the terminal nodes)
** The commentaries
They're introduced by at least one % and continue 'til the end of the line.
** The -generate rule
The -generate must be put in all your proto files, she takes one argument :
either "client" or "server". She'll be used by genproto to know what
to generate.
** A word about -include, -open, -import, -set, -type and -define
-include takes a (quoted) string corresponding to a filepath, reads and
parse the content of the file and concat the result with the parsing of
the current file.
-open Open a caml module (will be placed on top of the caml generated file)
-type introduces a new type definition.
-import will add a value to the signature of the module used as a parameter
for the functor (when you use at least one -import, the generated module becomes
a functor)
-set let you define a constant.
-define is used to specifie the "form" of a message. All the definition we'll
be used first to define the algebraic datatype named Â« msg Â». The default
parameter's type is "string" but any other simple type can be specified (option
type and even lists might appear later), you can also use ! as you would do
with teerex.
A function "string_of_msg" will also be generated by these defines (it will be
automaticaly used when you use the keword send).
And finally, a teerex grammar will be extracted.
For more information about how to use those keywords take a look at the few
example files included in the directory.
/!\ There is no reordering with these definitions, that is particulary important
for the teerex grammar which will be generated, a general pattern like :
-define RawInput str = str
should be put *after* any other pattern. If you don't some pattern will never
even be tested and it will produce some unintended results.
** About the states :
Here the order doesn't matter, you can write them in any order you want.
The reordering is done automaticaly before translating into OCaml.
In a state, there are a limited numbers of constructions you can use :
- send: It sends a message (after serialising it) to a connection.
Everything that comes after a send is encapsulated in a continuation.
- send_all: Sends a list of messages. The behavior being the same than
with send.
- receive: It pops a message out of the queue and try to match it with
the different patterns specified.
The pattern matching behave as in caml, the only difference being,
when you want to introduce a guard, you must put the conditional expression
in verbatim (between {{ }} that is, see below).
Note: when the queue is empty it reads on the connection, encapsulate
everything into a continuation and parse the messages it has read with
trx before pushing them into the queue.
It can be extended with two optionnal construction : "catch"
which allow you to catch the network errors (Connection_closed, Timeout, ...)
defined in weblib/net.ml
The second one is after, which let you specify a timeout.
This extensions must be used like this :
receive
| _ -> ...
catch
| _ -> ...
after X -> ...
- listen({{ port_spec }},state_name): sets up the state as a listener for the
given Network.port_spec.
- let cnt_buff = readconn(conn,blocksize);
Low-level read from connection conn with blocksize:int and returning
(cnt:int,buff:string).
- writeconn(conn,str);
Write string str to connection conn.
- let conn = connect(port_spec);
Return a connection to port_spec.
- [[ ... ]] it's used to introduce verbatim ocaml code.
- {{ ... }} it's used to introduce ocaml_parser parsed ocaml code.
- << ... >> do the same but will be rewritten in CPS, for example :
let a = << foo >>
bar
will produce :
foo (fun a -> bar)
- if ... then ... else ... is kinda obvious. Notice however that
the condition must be put between brackets.
- begin ... end, introduce a block (it should soon be redondant with
parenthesis). It should be used in pair with the condition block if
you want to send something or change state inside the condition.
- match {{ ocaml_expr }} with | ocaml_pat -> DSL_code ;
Ocaml-style match. Note the ';' is obligatory.
* Example
There are two ways to generate the ml(i) and trx files from a .proto. The
easiest is let bld do the job for you, by calling it like this (from
opageneral) :
% ./bld path/to/yourFile.ml
Which will generate you yourFile.ml and yourFile_parse.trx from p/t/yourFile.proto
The second way is to manually use genproto, here is how :
% genproto path/to/foo.proto path/to/opageneral destination/path ml_file_name trx_file_name
This line will generate you to files : destination/path/ml_file_name.ml and
destination/path/trx_file_name.trx
* Complementary notes
The DSL and the Erlang language have many syntactic structures in common, you might
wanna use the erlang-mode (or :set filetype=erlang) when writing files using the
DSL.