[m-rev.] for review: foreign enumerations

Julien Fischer juliensf at csse.unimelb.edu.au
Mon Aug 13 16:58:10 AEST 2007


On Mon, 13 Aug 2007, Peter Wang wrote:

> On 2007-08-09, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:

>>  Add support for foreign enumerations to Mercury.  These allow the
>>  programmer to assign foreign language values as the representation of
>>  enumeration constructors.
>>
>>  e.g.
>>  	:- type status
>>  		--->	optimal
>>  		;	infeasible
>>  		;	unbounded
>>  		;	unknown.
>>
>>  	:- pragma foreign_enum("C", status/0, [
>>  		optimal    - "STATUS_OPTIMAL",
>>  		infeasible - "STATUS_INFEASIBLE",
>>  		unbounded  - "STATUS_UNBOUNDED",
>>  		unknown     - "STATUS_UNKNOWN"
>>  	]).
>
> Funny spacing there.

Glad you found it amusing ;-)  It's fixed now.

>>  The advantage of this is that when values of type status/0 are passed to
>>  foreign code (C in this case) no translation is necessary.  This should
>>  simplify the task of writing bindings to foreign language libraries.
>>
>>  Unification and comparison for foreign enumerations are the usual
>>  unification and comparison for enumeration types, except that the default
>>  ordering on them is determined by the foreign representation of the
>>  constructors.  User-defined equality and comparison work also work.
>>  on foreign enumeration types.
>
> ... comparison work also work. on foreign ...

Fixed.

>>  Index: NEWS
>>  ===================================================================
>>  RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
>>  retrieving revision 1.474
>>  diff -u -r1.474 NEWS
>>  --- NEWS	3 Aug 2007 05:18:37 -0000	1.474
>>  +++ NEWS	9 Aug 2007 08:26:44 -0000

...

>>  +	:- pragma foreign_enum("C", matrix_mode/0, [
>>  +		texture    - "GL_TEXTURE" +		modelview  - "GL_MODELVIEW"
>>  +		projection - "GL_PROJECTION"
>>  +	]).
>>  + +  When passed to C foreign clauses values of type matrix_mode/0 will have
>>  +  the corresponding C value specified by the foreign_enum pragma.
>
> Add a comma after "C foreign clauses".

Done.
...

>>  Index: compiler/add_pragma.m
>>  ===================================================================
>>  RCS file: /home/mercury/mercury1/repository/mercury/compiler/add_pragma.m,v
>>  retrieving revision 1.68
>>  diff -u -r1.68 add_pragma.m
>>  --- compiler/add_pragma.m	1 Aug 2007 07:23:28 -0000	1.68
>>  +++ compiler/add_pragma.m	9 Aug 2007 08:26:44 -0000
> ...

...

>>  +            MaybeForeignTagMap = no
>>  +        )
>>  +    ;
>>  +        BadCtors = [_ | _],
>>  +        MaybeForeignTagMap = no
>>  +    ).
>>  +
>>  +    % The construtor names we get from the parse tree may be unqualified
>
> constructor

Fixed.

>>  +    % but the ones we match against in the HLDS are not.  Module qualify
>>  +    % them. +    %
>>  +    % XXX module_qual.m should really be doing this rather than
>>  add_pragam.m.
>
> add_pragma.m

Fixed.


>>  Index: compiler/hlds_data.m
>>  ===================================================================
>>  RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_data.m,v
>>  retrieving revision 1.114
>>  diff -u -r1.114 hlds_data.m
>>  --- compiler/hlds_data.m	9 Jul 2007 13:28:35 -0000	1.114
>>  +++ compiler/hlds_data.m	9 Aug 2007 08:26:44 -0000
> ...
>>  @@ -231,6 +236,12 @@
>>               % This means the constant is represented just as a word
>>  containing
>>               % the specified integer value. This is used for enumerations
>>  and
>>               % character constants as well as for int constants.
>>  + +    ;       foreign_tag(string)
>>  +            % This means the constant is represented by the string which is
>>  +            % embedded directly in the target language.  This is used for
>>  +            % foreign enumerations, i.e. those enumeration types that are
>>  the
>>  +            % subject of a foreign_enum pramga.
>
> pragma

Fixed.

>>  Index: compiler/mercury_to_mercury.m
>>  ===================================================================
>>  RCS file:
>>  /home/mercury/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
>>  retrieving revision 1.317
>>  diff -u -r1.317 mercury_to_mercury.m
>>  --- compiler/mercury_to_mercury.m	25 Jul 2007 06:12:20 -0000	1.317
>>  +++ compiler/mercury_to_mercury.m	9 Aug 2007 08:26:44 -0000
> ...
>>  @@ -3646,23 +3650,44 @@
>>       ),
>>       add_string("]", !U).
>>
>>  -:- pred mercury_format_pragma_foreign_export_enum_overrides(
>>  +    % Output an association list of sym_names and strings, as used
>>  +    % by both foreign_enum and foreign_export_enum pragmas.
>>  +    % In the output the strings will be quoted.
>
> The strings will be quoted in the output.

Done.


>>  Index: compiler/type_ctor_info.m
>>  ===================================================================
>>  RCS file:
>>  /home/mercury/mercury1/repository/mercury/compiler/type_ctor_info.m,v
>>  retrieving revision 1.88
>>  diff -u -r1.88 type_ctor_info.m
>>  --- compiler/type_ctor_info.m	13 Feb 2007 01:58:51 -0000	1.88
>>  +++ compiler/type_ctor_info.m	9 Aug 2007 08:26:44 -0000
> ...
>>  @@ -629,6 +633,76 @@
>>       svmap.det_insert(FunctorName, EnumFunctor, !NameMap).
>>
>>
>>  %---------------------------------------------------------------------------%
>>  + +    % Make the functor and layout tables for a foreign enum type.
>>  +    %
>>  +:- pred make_foreign_enum_details(list(constructor)::in,
>>  cons_tag_values::in,
>>  +    bool::in, equality_axioms::in, type_ctor_details::out) is det.
>>  +
>>  +make_foreign_enum_details(Ctors, ConsTagMap, ReserveTag, EqualityAxioms,
>>  +        Details) :-
>>  +    (
>>  +        ReserveTag = yes,
>>  +        unexpected(this_file, "foreign enum with reserved tag")
>>  +    ;
>>  +        ReserveTag = no
>>  +    ),
>>  +    make_foreign_enum_functors(Ctors, 0, ConsTagMap, ForeignEnumFunctors),
>>  +    OrdinalMap0 = map.init,
>>  +    NameMap0 = map.init,
>>  +    list.foldl2(make_foreign_enum_maps, ForeignEnumFunctors,
>>  +        OrdinalMap0, OrdinalMap, NameMap0, NameMap),
>>  +    FunctorNumberMap = make_functor_number_map(Ctors),
>>  +    Details = foreign_enum(EqualityAxioms, ForeignEnumFunctors,
>>  +        OrdinalMap, NameMap, FunctorNumberMap).
>>  + +    % Create a foreign_enum_functor structure for each functor in an enum
>>  type.
>>  +    % The functors are given to us in ordinal order (since that's how the
>>  HLDS
>>  +    % stored them), and that is how we return the list of rtti names of the
>>  +    % foreign_enum_functor_desc structures; that way, it is directly usable
>>  in
>>  +    % the type layout structure. We also return a structure that allows our
>>  +    % caller to sort this list on functor name, which is how the type
>>  functors
>>  +    % structure is constructed.
>>  +    %
>>  +:- pred make_foreign_enum_functors(list(constructor)::in,
>>  +    int::in, cons_tag_values::in, list(foreign_enum_functor)::out) is det.
>>  +
>>  +make_foreign_enum_functors([], _, _, []).
>>  +make_foreign_enum_functors([Functor | Functors], NextOrdinal0, ConsTagMap,
>>  +        [ForeignEnumFunctor | ForeignEnumFunctors]) :-
>>  +    Functor = ctor(ExistTvars, Constraints, SymName, FunctorArgs,
>>  _Context),
>>  +    expect(unify(ExistTvars, []), this_file,
>>  +        "existential arguments in functor in foreign enum"),
>>  +    expect(unify(Constraints, []), this_file,
>>  +        "class constraints on functor in foreign enum"),
>>  +    list.length(FunctorArgs, Arity),
>>  +    expect(unify(Arity, 0), this_file,
>>  +        "functor in foreign enum has nonzero arity"),
>>  +    ConsId = make_cons_id_from_qualified_sym_name(SymName, FunctorArgs),
>>  +    map.lookup(ConsTagMap, ConsId, ConsTag),
>>  +    ( ConsTag = foreign_tag(ForeignTagValue0) ->
>>  +        ForeignTagValue = ForeignTagValue0
>>  +    ;
>>  +        unexpected(this_file, "non foreign tag for foreign enum functor")
>>  +    ),
>>  +    FunctorName = unqualify_name(SymName),
>>  +    ForeignEnumFunctor = foreign_enum_functor(FunctorName, NextOrdinal0,
>>  +        ForeignTagValue),
>>  +    make_foreign_enum_functors(Functors, NextOrdinal0 + 1, ConsTagMap,
>>  +        ForeignEnumFunctors).
>
> Might as well name it NextOrdinal.

Done.

>>  Index: runtime/mercury_ml_expand_body.h
>>  ===================================================================
>>  RCS file:
>>  /home/mercury/mercury1/repository/mercury/runtime/mercury_ml_expand_body.h,v
>>  retrieving revision 1.40
>>  diff -u -r1.40 mercury_ml_expand_body.h
>>  --- runtime/mercury_ml_expand_body.h	13 Feb 2007 01:58:57 -0000	1.40
>>  +++ runtime/mercury_ml_expand_body.h	9 Aug 2007 08:26:44 -0000
>>  @@ -316,6 +316,61 @@
>>               handle_zero_arity_args();
>>               return;
>>
>>  +        case MR_TYPECTOR_REP_FOREIGN_ENUM_USEREQ:
>>  +            if (noncanon == MR_NONCANON_ABORT) {
>>  +                /* XXX should throw an exception */
>>  +                MR_fatal_error(MR_STRINGIFY(EXPAND_FUNCTION_NAME)
>>  +                    ": attempt to deconstruct noncanonical term");
>>  +                return;
>>  +            } else if (noncanon == MR_NONCANON_ALLOW) {
>>  +                handle_noncanonical_name(type_ctor_info);
>>  +                handle_zero_arity_args();
>>  +                return;
>>  +            }
>>  +            /* else fall through */
>>  + +        case MR_TYPECTOR_REP_FOREIGN_ENUM:
>>  +            {
>>  +                /*
>>  +                ** For foreign enumerations we cannot use the value as
>>  index
>>  +                ** into the type layout, since we just have to do a linear
>>  +                ** search.
>>  +                */
>
> s/since/so/

Fixed.

Also changed "as index" to "as an index".

>>  Index: runtime/mercury_type_info.h
>>  ===================================================================
>>  RCS file:
>>  /home/mercury/mercury1/repository/mercury/runtime/mercury_type_info.h,v
>>  retrieving revision 1.127
>>  diff -u -r1.127 mercury_type_info.h
>>  --- runtime/mercury_type_info.h	31 Jul 2007 07:58:44 -0000	1.127
>>  +++ runtime/mercury_type_info.h	9 Aug 2007 08:26:44 -0000
> ...
>>  @@ -988,6 +1003,24 @@
>>
>>  /*---------------------------------------------------------------------------*/
>>
>>   /*
>>  +** This type describes the function symbols in a foreign enum type.
>>  +**
>>  +** An MR_ForeignEnumLayout points to an array of pointers to functor
>>  +** descriptors.  There is one pointer for each of the function symbols, and
>>  +** thus the size of the array is given by the num_functors field of the
>>  +** type_ctor_info.  The array is ordered by declaration order,
>
> full stop?

Fixed.

>>  Index: tests/invalid/foreign_enum_invalid.m
>>  ===================================================================
>>  RCS file: tests/invalid/foreign_enum_invalid.m
>>  diff -N tests/invalid/foreign_enum_invalid.m
>>  --- /dev/null	1 Jan 1970 00:00:00 -0000
>>  +++ tests/invalid/foreign_enum_invalid.m	9 Aug 2007 08:26:44 -0000
>>  @@ -0,0 +1,41 @@
>>  +:- module foreign_enum_invalid.
>>  +:- interface.
>>  +
>>  +:- type	incomplete +	---> 	foo
>>  +	;	bar
>>  +	;	baz.
>>  +
>>  +:- type incomplete2
>>  +	--->	foo2
>>  +	;	bar2
>>  +	;	baz2.
>>  +
>>  +:- type not_a_bijection
>>  +	--->	a
>>  +	;	b
>>  +	;	c.
>>  +
>>  +:- type in_int ---> in_int.
>>  +:- pragma foreign_enum("C", in_int/0, [in_int - "300"]).
>>  +
>>  +:- type dup_foreign_enum ---> dup_foreign_enum.
>>  +
>>  +:- implementation.
>>  +
>>  +:- pragma foreign_enum("C", incomplete/0, [
>>  +	foo - "3",
>>  +	bar - "4"
>>  +]).
>>  +
>>  +:- pragma foreign_enum("C", incomplete2/0, []).
>>  +
>>  +:- pragma foreign_enum("C", not_a_bijection/0, [
>>  +	a - "30",
>>  +	a - "40",
>>  +	b - "50",
>>  +	c - "60"
>>  +]).
>
> Did you check the case where two constructors have the same foreign enum
> value?

Added.

Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list