[m-dev.] Re: user-defined operators

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Jul 9 12:20:39 AEST 1999


On 09-Jul-1999, Peter Schachte <schachte at cs.mu.OZ.AU> wrote:
> On Fri, Jul 09, 1999 at 07:54:28AM +1000, Fergus Henderson wrote:
> > Well, the current implementation reads in and parses one file at a time.
> 
> Ah, I see.  So presumably you'd want to change that to:  read in and
> parse one module and all its imported interfaces.

Oh, here's another problem: how do you create the interface files?
Currently this is done by reading in and parsing the file,
and then writing out the interface section.
But module interfaces are allowed to be mutually recursive!
So if you can't parse the file until you've read in the interfaces
of the imported modules, because you need the operator declarations,
then you're in a bit of a bind.

A solution to this would be to have an addition pre-pass which reads
in and tokenizes each module, parsing any operator declarations
in the module and writing them out to separate files named `<module>.ops'.
Then the next pass would parse each module by reading in just the
`.ops' files for imported module.
Unfortunately this has the usual AGNM problem [*]
as well as adding extra overhead due to the need for the extra pass.
I suppose you could create the `.ops' files during `mmake depend',
and recreate them whenever you remake the interface file...

[*] AGNM = "agh, not more files!" :-),

> > > I guess there is still the question of how to handle importation of
> > > two different modules that have incompatible operation declarations
> > 
> > One possible approach is to use a partial order rather than a total
> > order for the operator precedences.
> 
> This would give you some of the power of a real (context-free)
> grammar, but also much of the pain of one.

I think the complexity of operator precedence parsing, even with
partially ordered precedences, would be considerably less than
the complexity needed to support arbitrary user-defined grammar rules.

> In fact, maybe more,
> because you'd have to remember to declare a new operator's
> relationship to *all* the other operators it's related to.

No, operator precedence relationships would be transitive, so typically
you would only need to specify that the precedence of operator "foo"
is the same as this other operator "bar", or that the precedence
of "foo" is between that of "bar" and "baz".

> If two
> separate packages declared new (what would be) precedence 1000 xfy
> operators, they couldn't be used near each other without parenthesis.
> This would be surprising to users.

What does `precedence 1000' mean anyway?

If you declare two operators whose precedence is defined to be
equal to the precedence of ",", then their precedences would be
equal, because equality of precedences is symmetric and transitive.

> If you're going to do something like this, I think it would be better
> to go all the way and allow user-written grammar rules.  In this way,
> one could just add one new grammar rule like maybe:
> 
>     :- grammar clause_body(parallel_conj(X,Y)) --> 
> 		goal(X), ['&'], clause_body(Y).
>
> Of course, this would be significantly harder to implement.

Allowing user-written grammar rules of the kind shown above
would require rather drastic changes to they way that Mercury
syntax is currently defined.  Basically you'd be going from the current
three-level grammar (tokens -> terms -> parse tree) to a two-level grammar
(tokens -> parse tree).

User-defined operators already let you change the tokens -> terms mapping.
It might be possible to allow the same kind of affect as user-written
grammar rules without such a drastic change to the way Mercury syntax
is defined by providing (a) distfix operators
and/or (b) some way for users to affect the terms -> parse tree mapping.
However, that would require significant additional complexity, and
I don't think the additional complexity is worth it.

> > > Are there any other hard problems?
> > 
> > Integrating operators with the module system in this way would make it
> > significantly more difficult to write programs that parse Mercury source
> > code, e.g. preprocessors.
> 
> Not if your term reading library has a basic operation to read a
> module file and all the interfaces it depends on.  The user can always
> ignore the interface information if they don't need it.

No, that wouldn't solve the problem.  If I want to write a preprocessor
that adds new syntax to the language, then I won't be able to use the
standard library operation which reads a Mercury module file and all the
interfaces that it depends on, because the input to my preprocessor
won't be a valid Mercury module, it will just be a file containing
Mercury terms.

For example, suppose my preprocessor adds conditional compilation.
It might use syntax such as 

	'#if'(<Condition>, <Item>).
		If <Condition> is true, then include <Item>.

The user might well want to use it like so:

	% For Mercury version >= 3, import the "ai" module,
	% which defines the "dwim" operator.
	'#if'(mercury_version >= 3, (
		:- import_module ai
	)).

	% For Mercury versions < 3, we need to define the "dwim"
	% operator ourselves.
	'#if'(mercury_version < 3, (
		:- op(dwim, fx, 1000)
	)).

	% Use the "dwim" operator.
	dwim now.

I won't be able to parse that file using any standard library function,
because that syntax is not standard syntax.  I'll need to process it
term at a time, and read in the `.ops' or `.int' files myself.

Now, consider the case where you have two different mutually recursive
modules that both define operators, and you want to write both of these
using a preprocessor... it gets very tricky indeed.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list