Previous Up Next
Chapter 7 Other extensions
7.1 Extensible functions

Camlp4 provides a system of functions defined by pattern matching, which are extensible.

The library module is Extfun and the syntax to be loaded is "pa_extfun.cmo". The empty function is Extfun.empty. You can extend a function using the statement extfun whose syntax is:

extfun expression with
[ pattern-1 -> expression-1
| pattern-2 -> expression-2
...
| pattern-n -> expression-n ]

The patterns are ordered in lexicographic order (for example, in a tuple, first comparing the first elements of the tuple). Variables are inserted after constructors. In an extension, the patterns do not need to be in a ``good'' order, since they are sorted. Non exhaustive pattern matching do not generate a warning.

``Or'' patterns can be used only at the first level. In this case:
          pat1 | pat2 -> expr
The binding is split into two cases (the expr is duplicated):
            pat1 -> expr
          | pat2 -> expr
Internal ``or'' patterns inside patterns are not accepted.

The statement extfun returns another extensible function. The type of extensible functions is ('a, 'b) Extfun.t. To use an extensible function, one must use the function Extfun.apply which transforms it in a function of type 'a -> 'b. If matching failed, such a function raises the exception Extfun.Failure.

The contents (patterns) of an extensible function can be displayed using Extfun.print.

Remark: extensible functions are not efficient: when applied, all patterns are tested, one by one, until one of them matches.

Extensible functions are used in Camlp4 extensible pretty printing.

7.2 Functional streams

The functional streams are another implementation of streams. Like normal streams, their contents can be accessible only one element at a time. But the elements are not removed. A functional stream parser returns the couple of a result and the remaining stream.

The library module is Fstream and the syntax to be loaded is "pa_fstream.cmo". The syntax of a functional stream is:

functional-stream ::=
  fstream [: list-of-components-separated-by-semicolon :]
  component ::=
  ` stream-element
  | stream

and a functional parser, applying to a functional stream is:

functional-parser ::=
  fparser
  [ stream-pattern-1 -> expression-1
  | stream-pattern-2 -> expression-2
  ..
  | stream-pattern-n -> expression-n ]
  stream-pattern ::=
  [: list-of-components-separated-by-semicolon :]
  component ::=
  ` stream-pattern-element
  | pattern = expression
  | stream-pattern

The functional stream patterns elements syntax are actually the same than in normal stream pattern.

A functional stream is of type 'a Fstream.t and a functional stream parser of type 'a Fstream.t -> ('a * 'a Fstream.t) option. When a parser fails, it returns None, otherwise Some of the result and the remaining stream. The elements in the initial stream are not removed.

A functional parser use limited backtrack. It is a backtrack in a sense that when a rule fails, the next rule is tested with the initial stream. If no rule applies, the functional parser returns None. There is no Error exception causing the parsing to be abandoned.

The backtrack is limited in a sense that if a rule is [: p1 = e1; p2 = e2 :], if e2 fails, the rule is abandoned: there is no attempt to try the next possible rule inside e1 (which would suppose continuations).

The functions available in the module Fstream are like the ones in Stream. But there is no function ``Fstream.peek'', only Fstream.next.

Functional parsers have a drawback that in case of syntax error, one cannot know where, since the parsing continues until all rules have been tested. To turn around this problem, the function Fstream.count_frozen returns the number of unfrozen tokens in the stream, allowing to find the location of the error, providing a location array have been used (which is normal usage in stream parsing and grammars). It works if the stream had not been unfrozen before.



Previous Up Next