[m-dev.] diff: improve handling of top-down calls in Aditi

Simon Taylor stayl at cs.mu.OZ.AU
Wed Aug 4 13:25:06 AEST 1999


Estimated hours taken: 4

compiler/rl_exprn.m:
	Improve the error messages for unsupported top-down
	calls from Aditi predicates.

	Add the ability to call library predicates for
	which bytecodes exist in Aditi.

	Fix bugs in the handling of arguments of closures passed
	to aditi__aggregate which caused registers to be overwritten.

	Fix incorrect types used in assign instructions in aditi__aggregate.

doc/reference_manual.texi:
	Document which library predicates can be called from Aditi.


Index: compiler/rl_exprn.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/rl_exprn.m,v
retrieving revision 1.9
diff -u -u -r1.9 rl_exprn.m
--- rl_exprn.m	1999/07/13 08:53:27	1.9
+++ rl_exprn.m	1999/08/03 02:31:47
@@ -82,7 +82,7 @@
 
 :- import_module code_util, hlds_pred, hlds_data, inst_match.
 :- import_module instmap, mode_util, tree, type_util, prog_out.
-:- import_module rl_out, inlining, hlds_goal, prog_util.
+:- import_module rl_out, inlining, hlds_goal, prog_util, error_util.
 
 % Note: the reason that we need to import llds and builtin_ops here is that
 % we generate code for builtins by first converting the builtin to LLDS
@@ -698,23 +698,71 @@
 		hlds_goal_info::in, byte_tree::in, byte_tree::out, 
 		rl_exprn_info::in, rl_exprn_info::out) is det.
 
-rl_exprn__call(PredId, ProcId, Vars, _GoalInfo, Fail, Code) -->
+rl_exprn__call(PredId, ProcId, Vars, GoalInfo, Fail, Code) -->
 	rl_exprn_info_get_module_info(ModuleInfo),
 	{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
 		PredInfo, ProcInfo) },
 	{ proc_info_inferred_determinism(ProcInfo, Detism) },
-	( { determinism_components(Detism, _, at_most_many) } ->
-		{ error("Sorry, not yet implemented - nondeterministic Mercury calls in Aditi procedures") }
+	rl_exprn_info_get_parent_pred_proc_ids(Parents0),
+	(
+		% XXX Nondet top-down calls are not yet implemented.
+		{ determinism_components(Detism, _, at_most_many) }
+	->
+		{ goal_info_get_context(GoalInfo, Context) },
+		{ rl_exprn__call_not_implemented_error(Context,
+			ModuleInfo, PredId, ProcId,
+			"nondeterministic Mercury calls in Aditi procedures") }
 	;
+		% XXX Top-down calls to imported predicates
+		% are not yet implemented.
 		{ pred_info_is_imported(PredInfo) },
-		{ \+ code_util__predinfo_is_builtin(PredInfo) }
+
+		% Calls to `unify/2' and `compare/3' will have been
+		% transformed into the type-specific versions
+		% by polymorphism.m. Polymorphic types are not allowed
+		% in Aditi predicates so the types must be known.
+		\+ {
+			% `index/2' doesn't work in Aditi.
+			code_util__compiler_generated(PredInfo),
+			\+ pred_info_name(PredInfo, "__Index__")
+		},
+		{ \+ code_util__predinfo_is_builtin(PredInfo) },
+		{ \+ rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
+			ProcId, _) }
+	->
+		{ goal_info_get_context(GoalInfo, Context) },
+		{ rl_exprn__call_not_implemented_error(Context,
+			ModuleInfo, PredId, ProcId,
+			"calls to imported Mercury procedures from Aditi") }
+	;
+		% XXX Recursive top-down calls are not yet implemented.
+		{ set__member(proc(PredId, ProcId), Parents0) }
 	->
-		{ error("Sorry, not yet implemented - calls to imported Mercury procedures from Aditi") }
+		{ goal_info_get_context(GoalInfo, Context) },
+		{ rl_exprn__call_not_implemented_error(Context,
+			ModuleInfo, PredId, ProcId,
+			"recursive Mercury calls in Aditi procedures") }
 	;
 		rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
 			Fail, Vars, Code)
 	).
 
+:- pred rl_exprn__call_not_implemented_error(prog_context::in, module_info::in,
+		pred_id::in, proc_id::in, string::in) is erroneous.
+
+rl_exprn__call_not_implemented_error(Context, 
+		ModuleInfo, PredId, ProcId, ErrorDescr) :-
+	error_util__describe_one_proc_name(ModuleInfo,
+		proc(PredId, ProcId), ProcName),
+	prog_out__context_to_string(Context, ContextStr),
+	string__append_list(
+		[
+			ContextStr, "in call to ", ProcName, ":\n",
+			"sorry, not yet implemented - ", ErrorDescr
+		],
+		Msg),
+	error(Msg).
+
 :- pred rl_exprn__call_body(pred_id::in, proc_id::in, pred_info::in,
 	proc_info::in, byte_tree::in, list(prog_var)::in, byte_tree::out,
 	rl_exprn_info::in, rl_exprn_info::out) is det.  
@@ -722,10 +770,18 @@
 rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo, Fail, Args, Code) -->
 	{ pred_info_name(PredInfo, PredName) },
 	{ pred_info_arity(PredInfo, Arity) },
-	( { code_util__predinfo_is_builtin(PredInfo) } ->
+	(
+		{ code_util__predinfo_is_builtin(PredInfo) }
+	->
 		rl_exprn__generate_builtin_call(PredId, ProcId, PredInfo,
 			Args, Fail, Code)
 	;
+		{ rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
+			ProcId, Bytecode) }
+	->
+		rl_exprn__generate_extra_aditi_builtin(Bytecode,
+			Args, Code)
+	;
 		% Handle unify/2 specially, since it is possibly recursive,
 		% which will cause the code below to fall over. Also, magic.m
 		% doesn't add type_info arguments yet.
@@ -789,15 +845,8 @@
 	;
 		% XXX temporary hack until we allow Mercury calls from Aditi -
 		% generate the goal of the called procedure, not a call to 
-		% the called procedure, checking first that the call is not
-		% recursive.
-
+		% the called procedure.
 		rl_exprn_info_get_parent_pred_proc_ids(Parents0),
-		( { set__member(proc(PredId, ProcId), Parents0) } ->
-			{ error("sorry, recursive Mercury calls in Aditi-RL code are not yet implemented") }
-		;	
-			[]
-		),
 		{ set__insert(Parents0, proc(PredId, ProcId), Parents) },
 		rl_exprn_info_set_parent_pred_proc_ids(Parents),
 		rl_exprn__inline_call(PredId, ProcId,
@@ -1388,6 +1437,119 @@
 rl_exprn__binop_bytecode(float_ge, rl_EXP_flt_ge).
 
 %-----------------------------------------------------------------------------%
+
+	% Generate code for deterministic library predicates and functions
+	% for which all arguments except the last are input.
+	% This is not an exhaustive list, it's just the ones that
+	% Aditi happens to have bytecodes for.
+	% This is only needed until Aditi can call arbitrary Mercury code.
+:- pred rl_exprn__generate_extra_aditi_builtin(bytecode::in, 
+		list(prog_var)::in, byte_tree::out,
+		rl_exprn_info::in, rl_exprn_info::out) is det.
+
+rl_exprn__generate_extra_aditi_builtin(Bytecode, Args, Code) -->
+	% The extra aditi builtins are not all functions, but
+	% this does the right thing.
+	{ pred_args_to_func_args(Args, InArgs, OutArg) },
+
+	rl_exprn__push_builtin_args(InArgs, empty, PushCode),
+
+	rl_exprn_info_lookup_var(OutArg, OutReg),
+	rl_exprn_info_lookup_var_type(OutArg, OutVarType),
+	rl_exprn__generate_pop(reg(OutReg), OutVarType, PopCode),
+	
+	{ Code =
+		tree(PushCode,
+		tree(node([Bytecode]),
+		PopCode
+	)) }.
+
+:- pred rl_exprn__push_builtin_args(list(prog_var)::in, byte_tree::in,
+	byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
+
+rl_exprn__push_builtin_args([], Code, Code) --> [].
+rl_exprn__push_builtin_args([Var | Vars], Code0, Code) -->
+	rl_exprn_info_lookup_var(Var, VarReg),
+	rl_exprn_info_lookup_var_type(Var, VarType),
+	rl_exprn__generate_push(reg(VarReg), VarType, Code1),
+	rl_exprn__push_builtin_args(Vars, tree(Code0, Code1), Code).
+
+:- pred rl_exprn__is_simple_extra_aditi_builtin(pred_info::in, proc_id::in,
+		bytecode::out) is semidet.
+
+rl_exprn__is_simple_extra_aditi_builtin(PredInfo, ProcId, Bytecode) :-
+	pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
+	pred_info_module(PredInfo, PredModule),
+	PredModule = unqualified(PredModuleName),
+	pred_info_name(PredInfo, PredName),
+	pred_info_arity(PredInfo, PredArity0),
+	hlds_pred__proc_id_to_int(ProcId, ProcInt),
+	adjust_func_arity(PredOrFunc, PredArity, PredArity0),
+	rl_exprn__simple_extra_builtin(PredOrFunc, PredModuleName,
+		PredName, PredArity, ProcInt, Bytecode).
+
+:- pred rl_exprn__simple_extra_builtin(pred_or_func::in, string::in,
+		string::in, int::in, int::in, bytecode::in) is semidet.
+:- mode rl_exprn__simple_extra_builtin(in, in, in, in, out, out) is semidet.
+
+rl_exprn__simple_extra_builtin(predicate, "int", "to_float", 2, 0,
+		rl_EXP_int_toflt).
+rl_exprn__simple_extra_builtin(predicate, "int", "max", 3, 0, rl_EXP_int_max).
+rl_exprn__simple_extra_builtin(predicate, "int", "min", 3, 0, rl_EXP_int_min).
+rl_exprn__simple_extra_builtin(predicate, "int", "abs", 2, 0, rl_EXP_int_abs).
+
+rl_exprn__simple_extra_builtin(function, "float", "float", 1, 0,
+		rl_EXP_int_toflt).
+rl_exprn__simple_extra_builtin(function, "float",
+		"truncate_to_int", 1, 0, rl_EXP_flt_toint).
+rl_exprn__simple_extra_builtin(function, "float", "pow", 2, 0, rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(predicate, "float", "pow", 3, 0,
+		rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(function, "float", "abs", 1, 0, rl_EXP_flt_abs).
+rl_exprn__simple_extra_builtin(predicate, "float", "abs", 2, 0,
+		rl_EXP_flt_abs).
+rl_exprn__simple_extra_builtin(function, "float", "max", 2, 0, rl_EXP_flt_max).
+rl_exprn__simple_extra_builtin(predicate, "float", "max", 3, 0,
+		rl_EXP_flt_max).
+rl_exprn__simple_extra_builtin(function, "float", "min", 2, 0, rl_EXP_flt_min).
+rl_exprn__simple_extra_builtin(predicate, "float", "min", 3, 0,
+		rl_EXP_flt_min).
+
+rl_exprn__simple_extra_builtin(function, "math", "ceiling", 1, 0,
+		rl_EXP_flt_ceil).
+rl_exprn__simple_extra_builtin(function, "math", "floor", 1, 0,
+		rl_EXP_flt_floor).
+rl_exprn__simple_extra_builtin(function, "math", "round", 1, 0,
+		rl_EXP_flt_round).
+rl_exprn__simple_extra_builtin(function, "math", "sqrt", 1, 0,
+		rl_EXP_flt_sqrt).
+rl_exprn__simple_extra_builtin(function, "math", "pow", 2, 0, rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(function, "math", "exp", 1, 0, rl_EXP_flt_exp).
+rl_exprn__simple_extra_builtin(function, "math", "ln", 1, 0, rl_EXP_flt_log).
+rl_exprn__simple_extra_builtin(function, "math", "log10", 1, 0,
+		rl_EXP_flt_log10).
+rl_exprn__simple_extra_builtin(function, "math", "log2", 1, 0,
+		rl_EXP_flt_log2).
+rl_exprn__simple_extra_builtin(function, "math", "sin", 1, 0, rl_EXP_flt_sin).
+rl_exprn__simple_extra_builtin(function, "math", "cos", 1, 0, rl_EXP_flt_cos).
+rl_exprn__simple_extra_builtin(function, "math", "tan", 1, 0, rl_EXP_flt_tan).
+rl_exprn__simple_extra_builtin(function, "math", "asin", 1, 0,
+		rl_EXP_flt_asin).
+rl_exprn__simple_extra_builtin(function, "math", "acos", 1, 0,
+		rl_EXP_flt_acos).
+rl_exprn__simple_extra_builtin(function, "math", "atan", 1, 0,
+		rl_EXP_flt_atan).
+rl_exprn__simple_extra_builtin(function, "math", "sinh", 1, 0,
+		rl_EXP_flt_sinh).
+rl_exprn__simple_extra_builtin(function, "math", "cosh", 1, 0,
+		rl_EXP_flt_cosh).
+rl_exprn__simple_extra_builtin(function, "math", "tanh", 1, 0,
+		rl_EXP_flt_tanh).
+
+rl_exprn__simple_extra_builtin(predicate, "string", "length", 2, 0,
+		rl_EXP_str_length).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 rl_exprn__aggregate(ModuleInfo, ComputeInitial, UpdateAcc, GrpByType, 
@@ -1462,7 +1624,7 @@
 
 	rl_exprn_info_get_free_reg(NonGrpByType, NonGrpByReg),
 	rl_exprn__assign(reg(NonGrpByReg), input_field(one, 1),
-		GrpByType, NonGrpByAssign),
+		NonGrpByType, NonGrpByAssign),
 
 	rl_exprn_info_get_free_reg(AccType, InitialAccReg),
 
@@ -1471,7 +1633,8 @@
 	% the group, and assign it to a register.
 	% 
 	{ Args = [GrpByReg, NonGrpByReg, InitialAccReg] },
-	rl_exprn__closure(ComputeClosure, Args, IsConst, AccCode0),
+	{ ArgTypes = [GrpByType, NonGrpByType, AccType] },
+	rl_exprn__closure(ComputeClosure, Args, ArgTypes, IsConst, AccCode0),
 
 	% Restore the initial value of the accumulator at the start
 	% of a new group.
@@ -1510,13 +1673,14 @@
 		NonGrpByType, NonGrpByCode),
 
 	% Allocate a location to collect the new accumulator.
-	rl_exprn_info_get_free_reg(GrpByType, OutputAccReg),
+	rl_exprn_info_get_free_reg(AccType, OutputAccReg),
 	rl_exprn__assign(reg(AccReg), reg(OutputAccReg),
 		AccType, AccAssignCode),
 
 	{ Args = [GrpByReg, NonGrpByReg, AccReg, OutputAccReg] },
+	{ ArgTypes = [GrpByType, NonGrpByType, AccType, AccType] },
 
-	rl_exprn__closure(UpdateClosure, Args, _, UpdateCode),
+	rl_exprn__closure(UpdateClosure, Args, ArgTypes, _, UpdateCode),
 	{ Code =
 		tree(NonGrpByCode,
 		tree(UpdateCode,
@@ -1530,27 +1694,32 @@
 	% Return whether the input arguments are actually used in
 	% constructing the outputs. If not, the closure is constant
 	% and can be evaluated once, instead of once per group.
-:- pred rl_exprn__closure(pred_proc_id::in, list(reg_id)::in, bool::out,
-		byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
+:- pred rl_exprn__closure(pred_proc_id::in, list(reg_id)::in, list(type)::in,
+		bool::out, byte_tree::out,
+		rl_exprn_info::in, rl_exprn_info::out) is det.
 
-rl_exprn__closure(proc(PredId, ProcId), ArgLocs, IsConst, Code) -->
+rl_exprn__closure(proc(PredId, ProcId), ArgLocs, ArgTypes, IsConst, Code) -->
 	rl_exprn_info_get_module_info(ModuleInfo),
 	{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
 		PredInfo, ProcInfo) },
-	{ proc_info_vartypes(ProcInfo, VarTypes) },
-	{ proc_info_varset(ProcInfo, VarSet) },
-	rl_exprn_info_set_vartypes(VarTypes),
+
+	% Create dummy variables for the arguments of the procedure.
+	rl_exprn_info_get_varset(VarSet0),
+	rl_exprn_info_get_vartypes(VarTypes0),
+	{ list__length(ArgTypes, NumVars) },
+	{ varset__new_vars(VarSet0, NumVars, ArgVars, VarSet) },
+	{ map__det_insert_from_corresponding_lists(VarTypes0, 
+		ArgVars, ArgTypes, VarTypes) },
 	rl_exprn_info_set_varset(VarSet),
+	rl_exprn_info_set_vartypes(VarTypes),
 
-	{ proc_info_headvars(ProcInfo, HeadVars) },
-	{ map__from_corresponding_lists(HeadVars, ArgLocs, VarLocs) },
-	{ list__length(HeadVars, NextVar) },
-	rl_exprn_info_set_vars(VarLocs - NextVar),
+	rl_exprn_info_set_var_locs(ArgVars, ArgLocs),
 
 	% Check if the closure depends on the input arguments.
 	{ proc_info_goal(ProcInfo, Goal) },
 	{ Goal = _ - GoalInfo },
 	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
+	{ proc_info_headvars(ProcInfo, HeadVars) },
 	{ proc_info_argmodes(ProcInfo, ArgModes) },
 	{ partition_args(ModuleInfo, ArgModes, HeadVars, InputArgs, _) },
 	{ set__list_to_set(InputArgs, InputArgSet) },
@@ -1563,7 +1732,7 @@
 
 	{ Fail = node([rl_EXP_return_false]) },
 	rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
-			Fail, HeadVars, Code).
+			Fail, ArgVars, Code).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -1828,6 +1997,9 @@
 :- pred rl_exprn_info_set_varset(prog_varset, rl_exprn_info, rl_exprn_info).
 :- mode rl_exprn_info_set_varset(in, in, out) is det.
 
+:- pred rl_exprn_info_get_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_get_vars(out, in, out) is det.
+
 :- pred rl_exprn_info_set_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
 :- mode rl_exprn_info_set_vars(in, in, out) is det.
 
@@ -1870,6 +2042,14 @@
 		rl_exprn_info, rl_exprn_info).
 :- mode rl_exprn_info_lookup_var_type(in, out, in, out) is det.
 
+:- pred rl_exprn_info_set_var_locs(list(prog_var), list(reg_id),
+		rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_set_var_locs(in, in, in, out) is det.
+
+:- pred rl_exprn_info_set_var_loc(prog_var, reg_id,
+		rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_set_var_loc(in, in, in, out) is det.
+
 :- pred rl_exprn_info_get_decls(list(type), rl_exprn_info, rl_exprn_info).
 :- mode rl_exprn_info_get_decls(out, in, out) is det.
 
@@ -1956,6 +2136,8 @@
 	Info = rl_exprn_info(_,_,C,_,_,_,_,_,_,_).
 rl_exprn_info_get_varset(D, Info, Info) :-
 	Info = rl_exprn_info(_,_,_,D,_,_,_,_,_,_).
+rl_exprn_info_get_vars(E, Info, Info) :-
+	Info = rl_exprn_info(_,_,_,_,E,_,_,_,_,_).
 rl_exprn_info_get_consts(G, Info, Info) :-
 	Info = rl_exprn_info(_,_,_,_,_,_,G,_,_,_).
 rl_exprn_info_get_rules(H, Info, Info) :-
@@ -2014,6 +2196,20 @@
 rl_exprn_info_lookup_var_type(Var, Type) -->
 	rl_exprn_info_get_vartypes(VarTypes),
 	{ map__lookup(VarTypes, Var, Type) }.
+
+rl_exprn_info_set_var_locs([], []) --> [].
+rl_exprn_info_set_var_locs([_|_], []) -->
+	{ error("rl_exprn_info_set_var_locs") }.
+rl_exprn_info_set_var_locs([], [_|_]) -->
+	{ error("rl_exprn_info_set_var_locs") }.
+rl_exprn_info_set_var_locs([Var | Vars], [Loc | Locs]) -->
+	rl_exprn_info_set_var_loc(Var, Loc),
+	rl_exprn_info_set_var_locs(Vars, Locs).
+
+rl_exprn_info_set_var_loc(Var, Loc) -->
+	rl_exprn_info_get_vars(VarMap0 - NextVar),
+	{ map__det_insert(VarMap0, Var, Loc, VarMap) },
+	rl_exprn_info_set_vars(VarMap - NextVar).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/reference_manual.texi,v
retrieving revision 1.147
diff -u -u -r1.147 reference_manual.texi
--- reference_manual.texi	1999/07/15 06:25:06	1.147
+++ reference_manual.texi	1999/08/04 03:18:23
@@ -5521,6 +5521,75 @@
 Some useful predicates are defined in @file{extras/aditi/aditi.m} in the
 @samp{mercury-extras} distribution.
 
+The Aditi interface currently has the major restriction that recursive or
+imported top-down Mercury predicates or functions cannot be called from
+predicates with @samp{pragma aditi} declarations.
+The following predicates and functions from the standard library
+can be called from Aditi: 
+
+ at samp{builtin__compare/3},
+
+ at samp{int:'<'/2},
+ at samp{int:'>'/2},
+ at samp{int:'=<'/2},
+ at samp{int:'>='/2},
+ at samp{int__abs/2},
+ at samp{int__max/3},
+ at samp{int__min/3},
+ at samp{int__to_float/2},
+ at samp{int__pow/2},
+ at samp{int__log2/2},
+ at samp{int:'+'/2},
+ at samp{int:'+'/1},
+ at samp{int:'-'/2},
+ at samp{int:'-'/1},
+ at samp{int:'*'/2},
+ at samp{int:'//'/2},
+ at samp{int__rem/2},
+
+ at samp{float:'<'/2},
+ at samp{float:'>'/2},
+ at samp{float:'>='/2},
+ at samp{float:'=<'/2},
+ at samp{float__abs/1},
+ at samp{float__abs/2},
+ at samp{float__max/2},
+ at samp{float__max/3},
+ at samp{float__min/2},
+ at samp{float__min/3},
+ at samp{float__pow/2},
+ at samp{float__log2/2},
+ at samp{float__float/1},
+ at samp{float__truncate_to_int/1},
+ at samp{float__truncate_to_int/2},
+ at samp{float:'+'/2},
+ at samp{float:'+'/1},
+ at samp{float:'-'/2},
+ at samp{float:'-'/1},
+ at samp{float:'*'/2},
+ at samp{float:'/'/2},
+
+ at samp{math__ceiling/1},
+ at samp{math__round/1},
+ at samp{math__floor/1},
+ at samp{math__sqrt/1},
+ at samp{math__pow/2},
+ at samp{math__exp/1},
+ at samp{math__ln/1},
+ at samp{math__log10/1},
+ at samp{math__log2/1},
+ at samp{math__sin/1},
+ at samp{math__cos/1},
+ at samp{math__tan/1},
+ at samp{math__asin/1},
+ at samp{math__acos/1},
+ at samp{math__atan/1},
+ at samp{math__sinh/1},
+ at samp{math__cosh/1},
+ at samp{math__tanh/1},
+
+ at samp{string__length/2}.
+
 @node Aditi pragma declarations
 @subsubsection Aditi pragma declarations
 
@@ -5588,14 +5657,13 @@
 @c generated by the Aditi system, so this documentation should disappear
 @c eventually.
 @example
-:- pragma aditi_index(@var{Name}/@var{Arity},
-                @var{IndexType}, @var{Attributes}).
+:- pragma aditi_index(@var{Name}/@var{Arity}, @var{IndexType}, @var{Attributes}).
 @end example
 
 The base relation has the given B-tree index. B-tree indexes allow efficient
 retrieval of a tuple or range of tuples from a base relation.
- at var{IndexType} must be one of @samp{unique_B_tree} or
- at samp{non_unique_B_tree}. @var{Attributes} is a list of argument
+ at samp{@var{IndexType}} must be one of @samp{unique_B_tree} or
+ at samp{non_unique_B_tree}. @samp{@var{Attributes}} is a list of argument
 numbers (argument numbers are counted from one).
 
 @node Aditi update syntax
--------------------------------------------------------------------------
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