module Pa_infix:sig
..end
There are two ways of using this syntax extension.
Create a file, say my_syntax.ml, in which you open Pa_infix
and
use the API below to set the operators you need, compile it to an
object file and pass the latter to camlp4. The advantage of this
approach is that the created module can be reused with various
source files. This is the recommended way of proceeding if you
want to define new operators to ship with your OCaml library.
This approach is particularly useful when you quickly need to
define prefix/postfix/infix operators in a given source file. The
syntax is INFIX ( op )
, PREFIX ( op )
, and POSTFIX ( op )
to
respectively define binary infix, unary prefix, and unary postfix
operators. These can be followed by a precedence specification:
HIGHEST
, HIGHER ( op )
, LEVEL ( op )
, LOWER ( op )
, or
LOWEST
. Finally the associativity of infix operators can be set
with LEFTA
(left associative), RIGHTA
(right associative), or
NONA
(non-associative). Operators at the same level must have
the same associativity so associativity is inherited from op
when you use LEVEL ( op )
(you cannot specify it).
Examples:
INFIX ( %+ ) RIGHTA HIGHER (+)
INFIX ( ^* ) LEVEL (+)
PREFIX ( /+/ )
POSTFIX ( /// ) LEVEL ( ! )
In case the concrete syntax conflicts with keywords in your code,
it can be disabled by passing the option -no-pa-infix
to camlp4
(in which case only the first approach is possible).
Remarks
+
, -
,..., +.
,...) cannot be
changed. This is to prevent strange bugs from occurring by
changing the meaning of code that does not use new operators
(e.g. one certainly does not want +
to bind more tightly than
*
or -
to be right associative).
op
, use the syntax let ( op ) args = expr
--
just as you would do to redefine existing alphabetic operators
such as lsl
,... Beware that prefix and postfxix operators bind
more tightly than function evaluation (think of the dereference
operator !
). Use with care.
typeoperator =
string
exception Not_operator of operator
Not_operator op
is raised if the string op
does not
designate a valid operator name.exception Forbidden of operator
Forbidden op
is raised when the operator op
belongs to the
operators which precedence or associativity one is not allowed
to change.module Level:sig
..end
type
kind =
| |
Prefix |
| |
Infix |
| |
Postfix |
exception Conflicting_kind of operator * kind * kind
Conflicting_kind op k0 k
is raised when the kind of the operator
op
was k0
but now trying to set it to k
.exception Conflicting_level of operator * string * string
Conflicting_level op l0 l
is raised when the level of the operator
op
was l0
but now trying to set it to l
.val infix : operator ->
?expr:(Camlp4.PreCast.Syntax.Ast.expr ->
Camlp4.PreCast.Syntax.Ast.expr ->
Camlp4.PreCast.Syntax.Ast.Loc.t -> Camlp4.PreCast.Syntax.Ast.expr) ->
Level.binary Level.t -> unit
infix op l
defines the operator op
as a binary infix
operator at level l
.Not_operator
if op
is not a valid operator name.Forbidden
if the operator op
is not allowed.Conflicting_kind
if there is a conflict with the kind of op
.Conflicting_level
if there is a conflict with the level of op
.Level.Bad_arity
if a '_a Level.t
is given which is not
a Level.binary Level.t
.expr
: the function performing the operator subsititution:
the expression x op y
is transformed into expr x y _loc
. It
is the rewriting rule associated to x op y
. Note that this
can be used to simplify expressions x op y
but defines in no
way the function op
; if you want op
also to work in
context where no arguments are provided immediately, you need to
bind op
to a compatible function: let (op) = ...
. The
default is to keep the function application: fun x y _loc ->
<:expr< $lid:op$ $x$ $y$ >>
.val prefix : ?expr:(Camlp4.PreCast.Syntax.Ast.expr ->
Camlp4.PreCast.Syntax.Ast.Loc.t -> Camlp4.PreCast.Syntax.Ast.expr) ->
?level:Level.unary Level.t -> operator -> unit
prefix op l
define the operator op
as a prefix operator at
level l
. Remark: if you use a prefix operator between braces,
make sure to put spaces between around the expressions. For
example, assuming you set /
as prefix, (/4)
is parsed as
"(/", "4" and ")", you have to write ( /4 )
or ( / 4 )
for
/
to be considered as a prefix operator. Note that, usually,
you will not need any braces as prefix operators bind more
tightly than evaluation: f /4 5
will be interpreted as f ( /4 ) 5
.Not_operator
if op
is not a valid operator name.Forbidden
if the operator op
is not allowed.Conflicting_kind
if there is a conflict with the kind of op
.Conflicting_level
if there is a conflict with the level of op
.Level.Bad_arity
if a '_a Level.t
is given which is not
a Level.unary Level.t
.expr
: the function performing the operator subsititution:
the expression op x
is transformed into expr x _loc
.
Default: fun x _loc -> <:expr< $lid:op$ $x$ >>
.val postfix : ?expr:(Camlp4.PreCast.Syntax.Ast.expr ->
Camlp4.PreCast.Syntax.Ast.Loc.t -> Camlp4.PreCast.Syntax.Ast.expr) ->
?level:Level.unary Level.t -> operator -> unit
postfix op l
define the operator op
as a postfix operator at
level l
. The same remarks as for prefix
apply.Not_operator
if op
is not a valid operator name.Forbidden
if the operator op
is not allowed.Conflicting_kind
if there is a conflict with the kind of op
.Conflicting_level
if there is a conflict with the level of op
.Level.Bad_arity
if a '_a Level.t
is given which is not a
Level.unary Level.t
.expr
: the function performing the operator subsititution:
the expression x op
is transformed into expr x _loc
.
Default: fun x _loc -> <:expr< $lid:op$ $x$ >>
.val assoc : operator -> Level.assoc
assoc op
returns the associativity of the operator op
.Not_operator
if op
is not a valid operator name.val level : operator -> 'a Level.t
pos op
returns the (default or assigned) level of the operator op
.Not_operator
if op
is not a valid operator name.val kind : operator -> kind
kind op
returns the (default or assigned) kind of the operator op
.Not_operator
if op
is not a valid operator name.val is_operator : operator -> bool
is_operator op
tells whether the string op
can be used as an
operator.val is_set : operator -> bool
is_set op
tells whether the operator op
has been set using
one of the functions of this API.Not_operator
if op
is not a valid operator name.val handle_error : ('a -> 'b) -> 'a -> 'b
handle_error f a
applies f
to x
and returns the result.
If an exception of this library is raised, it prints a message
describing the error and exits with code 2.