[m-dev.] for review: record syntax [1]

David Glen JEFFERY dgj at cs.mu.OZ.AU
Wed Jan 5 16:31:20 AEDT 2000


On 04-Jan-2000, Simon Taylor <stayl at cs.mu.OZ.AU> wrote:
> 
> 
> Estimated hours taken: 60
> 
> Add syntax for getting and setting fields of constructors.

You might like to make this a little clearer; when I first read the above
sentence, I thought this change was only adding the syntax for fields, but
not actually implementing anything.

The order that you explain things in the log message could also be more 
helpful.

Anyhow, this change looks great. I have a few picky little comments, though.

> compiler/prog_data.m:
> compiler/prog_io.m:
> compiler/mercury_to_goedel.m:
> compiler/mercury_to_mercury.m:
> 	Store field names as `sym_name's rather than strings.
> 	Use a `maybe' type rather than an empty string to designate
> 	an unlabelled field.
> 
> compiler/hlds_data.m:
> 	Define data structures to hold information about
> 	the field names visible in a module.
> 
> compiler/hlds_module.m:
> 	Add a field to type module_info to hold information
> 	about the fields visible in a module.
> 
> compiler/hlds_pred.m:
> 	Add predicates to identify field access function names,
> 	and to handle the arguments of field access functions.
> 
> compiler/make_hlds.m:
> 	Add information about field definitions to the module_info.
> 
> 	Check that user-defined field access functions for exported
> 	fields are also exported, otherwise predicates in other modules
> 	could use a different method to access a field than predicates
> 	in module defining the field.
> 	Add a `predicate preds_add_implicit_report_error' to allow that check
> 	to be performed for functions which are added to the module_info
> 	by some means other than a `:- func' declaration.
> 
> 	Parse field access goals and expressions.
> 
> 	Add predicates `insert_arg_unifications_with_supplied_contexts',
> 	and `append_arg_unification', which allow more control over
> 	the contexts given to the added unifications. These are
> 	useful because the field value for an update is really an
> 	argument of the inner-most update function call, while the
> 	input term is an argument of the outer-most function call.
> 
> compiler/make_hlds.m:
> compiler/hlds_goal.m:
> compiler/modecheck_call.m:
> compiler/higher_order.m:
> compiler/purity.m:
> compiler/polymorphism.m:
> compiler/dnf.m:
> compiler/cse_detection.m:
> compiler/lambda.m:
> 	Move `create_atomic_unification' from make_hlds.m to hlds_goal.m
> 	because it is used by several other modules.
> 
> compiler/hlds_goal.m:
> 	Add a version of goal_info_init which takes the context of
> 	the goal, for use by make_hlds.m.
> 
> compiler/typecheck.m:
> 	Add a default clause for field access functions for which
> 	the user has supplied type and mode declarations but no
> 	clauses.
> 
> 	Typecheck field access function calls.
> 
> 	Use higher-order code to remove some duplication of code
> 	to write out comma separated lists of error descriptions.
> 
> compiler/post_typecheck.m:
> 	Expand field accessor goals into the equivalent unifications.
> 	They are expanded inline rather than generating new get and set
> 	predicates for field name to avoid having to work out how to mode
> 	the generated predicates.
> 
> 	Remove an unnecessary goal traversal to qualify function
> 	calls and constructors. That code is now called from purity.m.
> 
> compiler/type_util.m:
> 	Add a predicate `type_util__get_type_and_cons_defn' to
> 	get the hlds_type_defn and hlds_cons_defn for a user-defined
> 	constructor.
> 
> compiler/prog_util.m:
> 	Add predicates to add and remove prefixes or suffixes
> 	from the unqualified part of a sym_name.
> 
> compiler/purity.m:
> 	Thread through the pred_info so that the expansion of field accessor
> 	goals can add new variables.
> 
> compiler/prog_io_dcg.m:
> 	Allow DCG goals of the form `:=(DCGArg)', which unifies `DCGArg'
> 	with the output DCG argument, ignoring the input DCG argument. 
> 	The rationale for this change is that if we have convenient syntax
> 	for updating parts of a DCG argument, we should also have convenient
> 	syntax for updating the whole DCG argument.
> 
> compiler/mercury_to_mercury.m:
> library/ops.m:
> 	Reduce precedence of `^/2' for use as a field name separator.
> 
> 	Add operator `^'/1 to designate which side of the `:=' is
> 	the field name in a DCG field access goal.
> 
> 	Add operator `:=/2' for field update expressions. 
> 
> doc/reference_manual.texi:
> 	Document the new syntax.
> 
> 	Split the `Types' chapter into sections.
> 
> doc/transition_guide.texi:
> 	Document the new operators.
> 
> tests/hard_coded/Mmakefile:
> tests/hard_coded/record_syntax.m:
> tests/hard_coded/record_syntax.exp:
> tests/invalid/Mmakefile:
> tests/invalid/record_syntax_errors.m:
> tests/invalid/record_syntax_errors.err_exp:
> 	Test cases.

> Index: compiler/make_hlds.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
> retrieving revision 1.320
> diff -u -u -r1.320 make_hlds.m
> --- make_hlds.m	1999/12/10 02:17:57	1.320
> +++ make_hlds.m	1999/12/23 00:51:48
> @@ -316,7 +315,7 @@
>  	% dispatch on the different types of items
>  
>  :- pred add_item_decl_pass_2(item, prog_context, item_status,
> -			module_info, item_status, module_info,
> +			module_info, item_status, module_info, 
>  			io__state, io__state).
>  :- mode add_item_decl_pass_2(in, in, in, in, out, out, di, uo) is det.
>  

That isn't much of a change...

> +:- pred add_ctor_field_names(list(maybe(ctor_field_name)),
> +		need_qualifier, list(module_name), type_id, cons_id,
> +		prog_context, import_status, int, ctor_field_table,
> +		ctor_field_table, io__state, io__state).
> +:- mode add_ctor_field_names(in, in, in, in, in, in, in, in,
> +		in, out, di, uo) is det.
> +
> +add_ctor_field_names([], _, _, _, _, _, _, _,
> +		FieldNameTable, FieldNameTable) --> [].
> +add_ctor_field_names([MaybeFieldName | FieldNames], NeedQual,
> +		PartialQuals, TypeId, ConsId, Context, ImportStatus,
> +		FieldNumber, FieldNameTable0, FieldNameTable) -->
> +	( { MaybeFieldName = yes(FieldName) } ->
> +		{ FieldDefn = hlds_ctor_field_defn(Context, ImportStatus,
> +			TypeId, ConsId, FieldNumber) },
> +		add_ctor_field_name(FieldName, FieldDefn, NeedQual,
> +			PartialQuals, FieldNameTable0, FieldNameTable2)
> +	;
> +		{ FieldNameTable2 = FieldNameTable0 }
> +	),

This might be nicer as a switch rather than an ite.

> +:- pred add_ctor_field_name(ctor_field_name, hlds_ctor_field_defn,
> +		need_qualifier, list(module_name), ctor_field_table,
> +		ctor_field_table, io__state, io__state).
> +:- mode add_ctor_field_name(in, in, in, in, in, out, di, uo) is det.
> +
> +add_ctor_field_name(FieldName, FieldDefn, NeedQual, PartialQuals,
> +		FieldNameTable0, FieldNameTable) -->
> +	{ FieldName = qualified(FieldModule0, _) ->
> +		FieldModule = FieldModule0
> +	;
> +		error("add_ctor_field_name: unqualified field name")
> +	},
> +	(
> +		%
> +		% Field names must be unique within a module, not
> +		% just within a type because the function names for
> +		% user-defined override functions for the builtin field
> +		% access functions must be unique within a module.
> +		%
> +		{ map__search(FieldNameTable0, FieldName, ConflictingDefns) }
> +	->
> +		{ ConflictingDefns = [ConflictingDefn] ->
> +			ConflictingDefn =
> +				hlds_ctor_field_defn(OrigContext, _, _, _, _)
> +		;
> +			error(
> +			"add_ctor_field_name: multiple conflicting fields")
> +		},
> +
> +		% XXX we should record each error
> +		% using module_info_incr_errors
> +		{ FieldDefn = hlds_ctor_field_defn(Context, _, _, _, _) },
> +		io__stderr_stream(StdErr),
> +		io__set_output_stream(StdErr, OldStream),
> +		prog_out__write_context(Context),
> +		io__write_string("Error: field `"),
> +		prog_out__write_sym_name(FieldName),
> +		io__write_string("' multiply defined.\n"),
> +		prog_out__write_context(OrigContext),
> +		io__write_string(
> +			"  Here is the previous definition of "),
> +		io__write_string("field `"),
> +		prog_out__write_sym_name(FieldName),
> +		io__write_string("'.\n"),
> +		io__set_exit_status(1),
> +		io__set_output_stream(OldStream, _),
> +		{ FieldNameTable = FieldNameTable0 }

I think we're trying to use error_util to compose error messages now.

> +:- pred report_field_status_mismatch(prog_context, simple_call_id,
> +		io__state, io__state).
> +:- mode report_field_status_mismatch(in, in, di, uo) is det.
> +
> +report_field_status_mismatch(Context, CallId) -->
> +	prog_out__write_context(Context),
> +	io__write_string("In declaration of "),
> +	hlds_out__write_simple_call_id(CallId),
> +	io__write_string(":\n"),
> +	prog_out__write_context(Context),
> +	io__write_string("  error: a field access function for an\n"),
> +	prog_out__write_context(Context),
> +	io__write_string("  exported field must also be exported.\n"),
> +	io__set_exit_status(1).
> +
> +:- pred report_error_redefine_builtin_field_access_function(prog_context,
> +		simple_call_id, io__state, io__state).
> +:- mode report_error_redefine_builtin_field_access_function(in,
> +		in, di, uo) is det.
> +
> +report_error_redefine_builtin_field_access_function(Context, CallId) -->
> +	prog_out__write_context(Context),
> +	io__write_string(
> +		"Error: redefinition of builtin field access "),
> +	hlds_out__write_simple_call_id(CallId),
> +	io__write_string(".\n"),
> +	io__set_exit_status(1).
> +

You should use the functions in error_util here too.

> +transform_dcg_record_syntax_2(AccessType, FieldNames, ArgTerms, Context,
> +		VarSet0, Goal, VarSet, Info0, Info, IO0, IO) :-
> +	make_fresh_arg_vars(ArgTerms, VarSet0, ArgVars, VarSet1),
> +	( ArgVars = [FieldValueVar, TermInputVar, TermOutputVar] ->
> +		(
> +			AccessType = set,
> +			expand_set_field_function_call(Context, explicit, [],
> +				FieldNames, FieldValueVar, TermInputVar,
> +				TermOutputVar, VarSet1, VarSet2, Functor,
> +				InnermostFunctor - InnermostSubContext, Goal0),
> +
> +
> +			FieldArgNumber = 2,
> +			FieldArgContext = functor(InnermostFunctor, explicit,
> +					InnermostSubContext),
> +			InputTermArgNumber = 1,
> +			InputTermArgContext = functor(Functor, explicit, []),
> +				( Functor = cons(FuncName0, FuncArity0) ->
> +				FuncName = FuncName0,
> +				FuncArity = FuncArity0
> +			;
> +				error("transform_dcg_record_syntax_2")
> +			),

Indentation.

> +expand_set_field_function_call_2(_, _, _, [], _, _, _, _, _, _, _, _) :-
> +	error("expand_set_field_function_call_2: empty list of field names").
> +expand_set_field_function_call_2(Context, MainContext, SubContext0,
> +		[FieldName | FieldNames], FieldValueVar, TermInputVar,
> +		TermOutputVar, VarSet0, VarSet, Functor, FieldSubContext,
> +		Goals) :-
> +	( FieldNames = [_|_] ->
> +		varset__new_var(VarSet0, SubTermInputVar, VarSet1),
> +		varset__new_var(VarSet1, SubTermOutputVar, VarSet2),
> +
> +		construct_field_access_function_call(set, Context,
> +			MainContext, SubContext0, FieldName,
> +			TermOutputVar, [TermInputVar, SubTermOutputVar],
> +			Functor, UpdateGoal),
> +
> +		% extract the field containing the field to update.
> +		construct_field_access_function_call(get, Context, MainContext,
> +			SubContext0, FieldName, SubTermInputVar,
> +			[TermInputVar], _, GetSubFieldGoal),
> +
> +		% recursively update the field.
> +		SubTermInputArgNumber = 2,
> +		TermInputContext = Functor - SubTermInputArgNumber,
> +		SubContext = [TermInputContext | SubContext0],
> +		expand_set_field_function_call_2(Context, MainContext,
> +			SubContext, FieldNames, FieldValueVar, SubTermInputVar,
> +			SubTermOutputVar, VarSet2, VarSet, _,
> +			FieldSubContext, Goals0),
> +
> +		list__append([GetSubFieldGoal | Goals0], [UpdateGoal], Goals)
> +	;
> +		VarSet = VarSet0,
> +		construct_field_access_function_call(set, Context,
> +			MainContext, SubContext0, FieldName,
> +			TermOutputVar, [TermInputVar, FieldValueVar],
> +			Functor, Goal),
> +		FieldSubContext = Functor - SubContext0,
> +		Goals = [Goal]
> +	).

Nice.

> +	% Wrap the list of goals for a record syntax expression
> +	% so that mode analysis treats them as an atomic goal.
> +:- pred wrap_field_access_goals(prog_context, list(hlds_goal), hlds_goal).
> +:- mode wrap_field_access_goals(in, in, out) is det.
> +
> +wrap_field_access_goals(Context, Goals, Goal) :-
> +	( Goals = [Goal0] ->
> +		Goal = Goal0
> +	;
> +		goal_info_init(Context, GoalInfo),
> +		Conj = conj(Goals) - GoalInfo,
> +		Goal = some([], can_remove, Conj) - GoalInfo
> +	).

I'm confused as to why this is necessary. Could you expand that comment a
little?


dgj
-- 
David Jeffery (dgj at cs.mu.oz.au) | If your thesis is utterly vacuous
PhD student,                    | Use first-order predicate calculus.
Dept. of Comp. Sci. & Soft. Eng.|     With sufficient formality
The University of Melbourne     |     The sheerist banality
Australia                       | Will be hailed by the critics: "Miraculous!"
                                |     -- Anon.


--------------------------------------------------------------------------
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