[m-rev.] For review: State Variables

Ralph Becket rafe at cs.mu.OZ.AU
Tue Jun 25 17:08:12 AEST 2002


On 11-Jun-2002, Simon Taylor wrote:
> On 07-Jun-2002, Ralph Becket <rafe at cs.mu.OZ.AU> wrote:
> > Index: make_hlds.m
> > ===================================================================
> > @@ -16,6 +16,9 @@
> >  % super-homogenous form, and introduce implicit quantification.
> >  % 
> >  % XXX we should record each error using module_info_incr_errors.
> > +%
> > +% XXX For state variables, we should allow quantifiers around if-then-else
> > +% expressions.
> 
> Just to be clear, this needs to be done immediately.

Fixed.

The syntax was not documented.  I've added docs to "Conditional
Expressions" in "Data terms" in the reference manual:

reference_manual.texi:
@@ -1121,6 +1325,9 @@
 both data-terms. The semantics of a conditional expression is that
 if @var{Goal} is true, then the expression has the meaning of
 @var{Expression1}, else the expression has the meaning of @var{Expression2}.
+
+If @var{Goal} takes the form @code{some [X, Y, Z] ...} then the scope of
+ at var{X}, @var{Y}, and @var{Z} includes @var{Expression1}.

For reference, the accepted syntax is

	if ( some [X] P ) then Q else R

where the scope of X includes Q.

> > @@ -6901,7 +7058,17 @@
> >  	% that each unification gets reduced to superhomogeneous form.
> >  	% It also gets passed a `arg_context', which indicates
> >  	% where the terms came from.
> > +
> >  	% We never insert unifications of the form X = X.
> > +	% If ForPragmaC is yes, we process unifications of the form
> > +	% X = Y by substituting the var expected by the outside environment
> > +	% (the head variable) for the variable inside the goal (which was
> > +	% created just for the pragma_c_code goal), while giving the headvar
> > +	% the name of the just eliminated variable. The result will be
> > +	% a proc_info in which the head variables have meaningful names
> > +	% and the body goal is just a pragma C code. Without this special
> > +	% treatment, the body goal will be a conjunction, which would
> > +	% complicate the handling of code generation for nondet pragma C codes.
> >  
> >  :- type arg_context
> >  	--->	
> > @@ -6919,80 +7086,89 @@
> >  		).
> >  
> >  :- pred insert_arg_unifications(list(prog_var), list(prog_term),
> > -		prog_context, arg_context, hlds_goal, prog_varset,
> > +		prog_context, arg_context, bool, hlds_goal, prog_varset,
> >  		hlds_goal, prog_varset, transform_info, transform_info,
> > -		io__state, io__state).
> > -:- mode insert_arg_unifications(in, in, in, in, in, in, out,
> > -		out, in, out, di, uo) is det.
> > +		svar_info, svar_info, io__state, io__state).
> > +:- mode insert_arg_unifications(in, in, in, in, in, in, in, out,
> > +		out, in, out, in, out, di, uo) is det.
> 
> This undoes a change I committed last week. Please go over your diff
> thoroughly to make sure there are no other stray changes.

Fixed.

> > @@ -7217,22 +7443,25 @@
> >  	%	NewVar3 = A3.
> >  	% In the trivial case `X = c', no unravelling occurs.
> >  
> > -unravel_unification(term__variable(X), RHS,
> > -			Context, MainContext, SubContext, VarSet0, Purity,
> > -			Goal, VarSet, Info0, Info) -->
> > -	{ RHS = term__functor(F, Args, FunctorContext) },
> > +unravel_unification_2(term__variable(X), RHS,
> > +		Context, MainContext, SubContext, VarSet0, Purity,
> > +		Goal, VarSet, Info0, Info, SInfo0, SInfo) -->
> > +	{ RHS = term__functor(F, Args0, FunctorContext) },
> > +	{ Args1 = expand_bang_state_var_args(Args0) },
> 
> You're still not doing this consistently. For example, !X is not
> expanded in `aditi_insert(p(!X), DB, DB)' or `X ^ field(!X) := Value'.

It might be better to expand !X only in predicate clause heads and
predicate calls (!X doesn't really make sense in function calls).

Good point.  Done and documented:

reference_manual.texi:
+There are three restrictions concerning state variables in lambdas: first,
+ at samp{!@var{X}} is not a legitimate function result, since it stands for two
+arguments, rather than one; second, @samp{!@var{X}} may not appear as a
+parameter term in the head of a lambda since there is no syntax for specifying
+the modes of the two implied parameters; third, @samp{!@var{X}} may not appear
+as an argument in a function application since this would not make sense given
+the usual interpretation of state variables and functions.

> > +:- func reconciled_svar_infos_dots(prog_varset, svar_info, svar, svar_info) =
> > +		svar_info.
> > +
> > +reconciled_svar_infos_dots(VarSet, SInfoX, StateVar, SInfo0) = SInfo :-
> > +	( if
> > +		DotX = SInfoX ^ dot ^ elem(StateVar),
> > +		Dot0 = SInfo0 ^ dot ^ elem(StateVar)
> > +	  then
> > +	  	NameX = varset__lookup_name(VarSet, DotX) `with_type` string,
> > +	  	Name0 = varset__lookup_name(VarSet, Dot0) `with_type` string,
> > +		compare(RDot, NameX, Name0),
> > +		(
> > +			RDot  = (<),
> > +			SInfo = ( SInfo0 ^ dot ^ elem(StateVar) := Dot0 )
> > +		;
> > +			RDot  = (=),
> > +			SInfo = SInfo0
> > +		;
> > +			RDot  = (>),
> > +			SInfo = ( SInfo0 ^ dot ^ elem(StateVar) := DotX )
> > +		)
> > +	  else
> > +	  	SInfo = SInfo0
> > +	).
> 
> Does this work? For example, `STATE_VAR_X_2' will compare greater
> than `STATE_VAR_X_10'.

I've replaced string comparison with a special comparison function that
understands state variable names.

diff -u make_hlds.m make_hlds.m
--- make_hlds.m	7 Jun 2002 07:39:12 -0000
+++ make_hlds.m	25 Jun 2002 06:45:05 -0000
@@ -16,9 +16,6 @@
 % super-homogenous form, and introduce implicit quantification.
 % 
 % XXX we should record each error using module_info_incr_errors.
-%
-% XXX For state variables, we should allow quantifiers around if-then-else
-% expressions.
 
 % WISHLIST - we should handle explicit module quantification
 
@@ -5541,7 +5538,6 @@
 		VarTypes1, HeadVars, ClauseList, TI_VarMap, TCI_VarMap,
 		_HasForeignClauses) },
 
-
 		% Find all the existing clauses for this mode, and
 		% extract their implementation language and clause number
 		% (that is, their index in the list).
@@ -5680,6 +5676,7 @@
 		io__set_exit_status(1)
 	;
 		{
+		Info = Info0,
 			% build the pragma_c_code
 		goal_info_init(GoalInfo0),
 		goal_info_set_context(GoalInfo0, Context, GoalInfo1),
@@ -5687,12 +5684,12 @@
 		% this foreign code is inlined
 		add_goal_info_purity_feature(GoalInfo1, Purity, GoalInfo),
 		HldsGoal0 = foreign_proc(Attributes, PredId, 
-			ProcId, Args, ArgInfo, OrigArgTypes, PragmaImpl)
+			ProcId, HeadVars, ArgInfo, OrigArgTypes, PragmaImpl)
 			- GoalInfo,
 		ModuleInfo = ModuleInfo1,
 		map__init(EmptyVarTypes),
 		implicitly_quantify_clause_body(HeadVars,
-			HldsGoal1, VarSet2, EmptyVarTypes,
+			HldsGoal0, VarSet0, EmptyVarTypes,
 			HldsGoal, VarSet, _, _Warnings),
 		NewClause = clause([ProcId], HldsGoal,
 			foreign_language(NewLang), Context),
@@ -5751,7 +5748,7 @@
 	  else
 		ArgContext = head(PredOrFunc, Arity),
 		insert_arg_unifications(HeadVars, Args, Context, ArgContext,
-			no, Head0, VarSet1, Head, VarSet2, Info0, Info1,
+			Head0, VarSet1, Head, VarSet2, Info0, Info1,
 			SInfo1, SInfo2, IO1, IO2)
 	),
 
@@ -6021,8 +6018,7 @@
 
 		{ record_called_pred_or_func(predicate, Name, Arity,
 			Info0, Info1) },
-		insert_arg_unifications(HeadVars, Args,
-			Context, call(CallId), no,
+		insert_arg_unifications(HeadVars, Args, Context, call(CallId),
 			Goal0, VarSet1, Goal, VarSetX, Info1, Info,
 			SInfo1, SInfoX)
 	),
@@ -6629,7 +6625,7 @@
 			{ record_called_pred_or_func(PredOrFunc, SymName, 
 				InsertArity, Info0, Info1) },
 			insert_arg_unifications(AllArgs, AllArgTerms,
-				Context, call(CallId), no, Goal0,
+				Context, call(CallId), Goal0,
 				VarSet3, Goal, VarSet, Info1, Info,
 				SInfo0, SInfo)
 		;
@@ -6736,7 +6732,7 @@
 			PredGoal0, VarSet3, Info0, Info1, SInfo0, SInfo1),
 		{ ArgContext = head(PredOrFunc, PredArity) },
 		insert_arg_unifications(HeadArgs, HeadArgs1, Context,
-			ArgContext, no, PredGoal0, VarSet3, PredGoal1, VarSet4,
+			ArgContext, PredGoal0, VarSet3, PredGoal1, VarSet4,
 			Info1, Info2, SInfo1, SInfo2), 
 		% Quantification will reduce this down to
 		% the proper set of nonlocal arguments.
@@ -6807,7 +6803,7 @@
 		insert_arg_unifications(AllArgs,
 			[term__variable(LambdaVar), AditiState0Term,
 				AditiStateTerm],
-			Context, CallId, no, UpdateConj,
+			Context, CallId, UpdateConj,
 			VarSet7, UpdateGoal, VarSet, Info4, Info, SInfo2, SInfo)
 	;
 		%
@@ -6848,7 +6844,7 @@
 		{ record_called_pred_or_func(PredOrFunc, SymName, Arity,
 			Info0, Info1) },
 		insert_arg_unifications(OtherArgs, OtherArgs0, Context, CallId,
-			no, Call, VarSet1, UpdateGoal,
+			Call, VarSet1, UpdateGoal,
 			VarSet, Info1, Info, SInfo0, SInfo)
 	;
 		{ invalid_goal(Descr, Args0, GoalInfo,
@@ -7060,15 +7056,6 @@
 	% where the terms came from.
 
 	% We never insert unifications of the form X = X.
-	% If ForPragmaC is yes, we process unifications of the form
-	% X = Y by substituting the var expected by the outside environment
-	% (the head variable) for the variable inside the goal (which was
-	% created just for the pragma_c_code goal), while giving the headvar
-	% the name of the just eliminated variable. The result will be
-	% a proc_info in which the head variables have meaningful names
-	% and the body goal is just a pragma C code. Without this special
-	% treatment, the body goal will be a conjunction, which would
-	% complicate the handling of code generation for nondet pragma C codes.
 
 :- type arg_context
 	--->	
@@ -7086,13 +7073,13 @@
 		).
 
 :- pred insert_arg_unifications(list(prog_var), list(prog_term),
-		prog_context, arg_context, bool, hlds_goal, prog_varset,
+		prog_context, arg_context, hlds_goal, prog_varset,
 		hlds_goal, prog_varset, transform_info, transform_info,
 		svar_info, svar_info, io__state, io__state).
-:- mode insert_arg_unifications(in, in, in, in, in, in, in, out,
+:- mode insert_arg_unifications(in, in, in, in, in, in, out,
 		out, in, out, in, out, di, uo) is det.
 
-insert_arg_unifications(HeadVars, Args0, Context, ArgContext, ForPragmaC,
+insert_arg_unifications(HeadVars, Args0, Context, ArgContext,
 		Goal0, VarSet0, Goal, VarSet, Info0, Info, SInfo0, SInfo) -->
 	( { HeadVars = [] } ->
 		{ Goal = Goal0 },
@@ -7105,42 +7092,42 @@
 		substitute_state_var_mappings(Args0, Args, VarSet0, VarSet1,
 			SInfo0, SInfo1),
 		insert_arg_unifications_2(HeadVars, Args, Context, ArgContext,
-			ForPragmaC, 0, List0, VarSet1, List, VarSet,
+			0, List0, VarSet1, List, VarSet,
 			Info0, Info, SInfo1, SInfo),
 		{ goal_info_set_context(GoalInfo0, Context, GoalInfo) },
 		{ conj_list_to_goal(List, GoalInfo, Goal) }
 	).
 
 :- pred insert_arg_unifications_2(list(prog_var), list(prog_term),
-		prog_context, arg_context, bool, int, list(hlds_goal),
+		prog_context, arg_context, int, list(hlds_goal),
 		prog_varset, list(hlds_goal), prog_varset,
 		transform_info, transform_info, svar_info, svar_info,
 		io__state, io__state).
-:- mode insert_arg_unifications_2(in, in, in, in, in, in, in, in,
+:- mode insert_arg_unifications_2(in, in, in, in, in, in, in,
 		out, out, in, out, in, out, di, uo) is det.
 
-insert_arg_unifications_2([], [_|_], _, _, _, _, _, _, _, _, _, _, _, _) -->
+insert_arg_unifications_2([], [_|_], _, _, _, _, _, _, _, _, _, _, _) -->
 	{ error("insert_arg_unifications_2: length mismatch") }.
-insert_arg_unifications_2([_|_], [], _, _, _, _, _, _, _, _, _, _, _, _) -->
+insert_arg_unifications_2([_|_], [], _, _, _, _, _, _, _, _, _, _, _) -->
 	{ error("insert_arg_unifications_2: length mismatch") }.
-insert_arg_unifications_2([], [], _, _, _, _, List, VarSet, List, VarSet,
+insert_arg_unifications_2([], [], _, _, _, List, VarSet, List, VarSet,
 		Info, Info, SInfo, SInfo) --> [].
 insert_arg_unifications_2([Var|Vars], [Arg|Args], Context, ArgContext,
-		ForPragmaC, N0, List0, VarSet0, List, VarSet,
+		N0, List0, VarSet0, List, VarSet,
 		Info0, Info, SInfo0, SInfo) -->
 	{ N1 is N0 + 1 },
 	insert_arg_unification(Var, Arg, Context, ArgContext,
-		ForPragmaC, N1, List0, VarSet0, List1, VarSet1, ArgUnifyConj,
+		N1, List0, VarSet0, List1, VarSet1, ArgUnifyConj,
 		Info0, Info1, SInfo0, SInfo1),
 	(
 		{ ArgUnifyConj = [] }
 	->
 		insert_arg_unifications_2(Vars, Args, Context, ArgContext,
-			ForPragmaC, N1, List1, VarSet1, List, VarSet,
+			N1, List1, VarSet1, List, VarSet,
 			Info1, Info, SInfo1, SInfo)
 	;
 		insert_arg_unifications_2(Vars, Args, Context, ArgContext,
-			ForPragmaC, N1, List1, VarSet1, List2, VarSet,
+			N1, List1, VarSet1, List2, VarSet,
 			Info1, Info, SInfo1, SInfo),
 		{ list__append(ArgUnifyConj, List2, List) }
 	).	
@@ -7196,7 +7183,7 @@
 		{ Terms = [Term | Terms1] },
 		{ ArgContexts = [ArgNumber - ArgContext | ArgContexts1] }
 	->
-		insert_arg_unification(Var, Term, Context, ArgContext, no,
+		insert_arg_unification(Var, Term, Context, ArgContext,
 			ArgNumber, List0, VarSet0, List1, VarSet1,
 			UnifyConj, Info0, Info1, SInfo0, SInfo1),
 		insert_arg_unifications_with_supplied_contexts_2(Vars1, Terms1,
@@ -7208,14 +7195,14 @@
 	).
 
 :- pred insert_arg_unification(prog_var, prog_term,
-		prog_context, arg_context, bool, int,
+		prog_context, arg_context, int,
 		list(hlds_goal), prog_varset, list(hlds_goal), prog_varset,
 		list(hlds_goal), transform_info, transform_info,
 		svar_info, svar_info, io__state, io__state).
-:- mode insert_arg_unification(in, in, in, in, in, in,
+:- mode insert_arg_unification(in, in, in, in, in,
 		in, in, out, out, out, in, out, in, out, di, uo) is det.
 
-insert_arg_unification(Var, Arg, Context, ArgContext, ForPragmaC, N1,
+insert_arg_unification(Var, Arg, Context, ArgContext, N1,
 		List0, VarSet0, List1, VarSet1, ArgUnifyConj,
 		Info0, Info, SInfo0, SInfo) -->
 	(
@@ -7228,23 +7215,6 @@
 		{ List1 = List0 },
 		{ SInfo = SInfo0 }
 	;
-		{ Arg = term__variable(ArgVar) },
-		{ ForPragmaC = yes }
-	->
-		% Handle unifications of the form `X = Y' by substitution
-		% if this is safe.
-		{ Info = Info0 },
-		{ ArgUnifyConj = [] },
-		{ map__init(Subst0) },
-		{ map__det_insert(Subst0, ArgVar, Var, Subst) },
-		{ goal_util__rename_vars_in_goals(List0, no, Subst, List1) },
-		{ varset__search_name(VarSet0, ArgVar, ArgVarName) ->
-			varset__name_var(VarSet0, Var, ArgVarName, VarSet1)
-		;
-			VarSet1 = VarSet0
-		},
-		{ SInfo = SInfo0 }
-	;
 		{ arg_context_to_unify_context(ArgContext, N1,
 			UnifyMainContext, UnifySubContext) },
 		unravel_unification(term__variable(Var), Arg,
@@ -7446,8 +7416,7 @@
 unravel_unification_2(term__variable(X), RHS,
 		Context, MainContext, SubContext, VarSet0, Purity,
 		Goal, VarSet, Info0, Info, SInfo0, SInfo) -->
-	{ RHS = term__functor(F, Args0, FunctorContext) },
-	{ Args1 = expand_bang_state_var_args(Args0) },
+	{ RHS = term__functor(F, Args1, FunctorContext) },
 	substitute_state_var_mappings(Args1, Args, VarSet0, VarSet1,
 		SInfo0, SInfo1),
 	(
@@ -7567,21 +7536,45 @@
 		},
 		{ term__coerce(IfTerm0, IfTerm) },
 		{ parse_some_vars_goal(IfTerm, VarSet1, Vars,
-			IfParseTree, VarSet11) }
+			IfParseTree0, VarSet11) }
 	->
-		{ prepare_for_if_then_else_expr_condition(SInfo1, SInfo2) },
+			% The condition can introduce state variables that
+			% also range over the Then goal.  We need to
+			% preserve these state variables for processing the
+			% Then goal and remove them afterwards.
+
+		{ if IfParseTree0 = some_state_vars(StateVars0, IfParseTree1) -
+					_IfCtxt
+		  then
+		  	StateVars   = StateVars0,
+		  	IfParseTree = IfParseTree1
+		  else
+		  	StateVars   = [],
+			IfParseTree = IfParseTree0
+		},
+
+		{ prepare_for_if_then_else_expr(StateVars, VarSet11, VarSet11a,
+			SInfo1, SInfo2) },
+
 		check_expr_purity(Purity, Context, Info0, Info1),
 		{ map__init(EmptySubst) },
-		transform_goal(IfParseTree, VarSet11, EmptySubst,
+		transform_goal(IfParseTree, VarSet11a, EmptySubst,
 			IfGoal, VarSet22, Info1, Info2, SInfo2, SInfo3),
+
 		{ finish_if_then_else_expr_condition(SInfo1, SInfo3, SInfo4) },
+
 		unravel_unification(term__variable(X), ThenTerm,
 			Context, MainContext, SubContext, VarSet22, 
 			pure, ThenGoal, VarSet33, Info2, Info3, SInfo4, SInfo5),
+
+		{ finish_if_then_else_expr_then_goal(StateVars,
+			SInfo1, SInfo5, SInfo6) },
+
 		unravel_unification(term__variable(X), ElseTerm,
 			Context, MainContext, SubContext, VarSet33, pure,
-			ElseGoal, VarSet, Info3, Info, SInfo5, SInfo),
-		{ IfThenElse = if_then_else(Vars, IfGoal,
+			ElseGoal, VarSet, Info3, Info, SInfo6, SInfo),
+
+		{ IfThenElse = if_then_else(StateVars ++ Vars, IfGoal,
 			ThenGoal, ElseGoal) },
 		{ goal_info_init(Context, GoalInfo) },
 		{ Goal = IfThenElse - GoalInfo }
@@ -7695,7 +7688,7 @@
 					Purity, GoalInfo) },
 				{ Goal1 = GoalExpr - GoalInfo },
 				insert_arg_unifications(HeadVars, FunctorArgs,
-					FunctorContext, ArgContext, no, Goal1,
+					FunctorContext, ArgContext, Goal1,
 					VarSet2, Goal, VarSet,
 					Info1, Info, SInfo1, SInfo)
 			)
@@ -7857,8 +7850,7 @@
 		{ Info   = Info1 }
 	;
 		{ prepare_for_lambda(SInfo0, SInfo1) },
-		{ Args1  = expand_bang_state_var_args(Args0) },
-		substitute_state_var_mappings(Args1, Args, VarSet0, VarSet1,
+		substitute_state_var_mappings(Args0, Args, VarSet0, VarSet1,
 			SInfo1, SInfo2),
 
 		{ list__length(Args, NumArgs) },
@@ -7868,7 +7860,7 @@
 		{ ArgContext = head(PredOrFunc, NumArgs) },
 
 		insert_arg_unifications(LambdaVars, Args, Context, ArgContext,
-			no, Head0, VarSet2, Head, VarSet3, Info1, Info2,
+			Head0, VarSet2, Head, VarSet3, Info1, Info2,
 			SInfo2, SInfo3),
 
 		{ prepare_for_body(FinalSVarMap, VarSet3, VarSet4,
@@ -9032,7 +9024,7 @@
 			VarSet = VarSet0,
 			SInfo  = SInfo0,
 			IO     = IO0
-		  else if SInfo0 ^ colon `contains` StateVar then
+		  else if SInfo0 `has_svar_colon_mapping_for` StateVar then
 		  	new_dot_state_var(StateVar, Var,
 				VarSet0, VarSet, SInfo0, SInfo),
 			report_unitialized_state_var(Context, VarSet, StateVar,
@@ -9041,11 +9033,22 @@
 		  	Var    = StateVar,
 			VarSet = VarSet0,
 			SInfo  = SInfo0,
-			report_non_visible_state_var(Context, VarSet, StateVar,
-				IO0, IO)
+			report_non_visible_state_var(".", Context,
+				VarSet, StateVar, IO0, IO)
 		)
 	).
 
+
+:- pred svar_info `has_svar_colon_mapping_for` svar.
+:- mode in `has_svar_colon_mapping_for` in is semidet.
+
+SInfo `has_svar_colon_mapping_for` StateVar :-
+	SInfo ^ colon `contains` StateVar.
+
+SInfo `has_svar_colon_mapping_for` StateVar :-
+	SInfo ^ ctxt = in_atom(_, ParentSInfo),
+	ParentSInfo `has_svar_colon_mapping_for` StateVar.
+
 %------------------------------------------------------------------------------%
 
 	% Obtain the mapping for a !:X state variable reference.
@@ -9092,7 +9095,7 @@
 			SInfo  = SInfo0,
 			PError = ( if SInfo0 ^ external_dot `contains` StateVar
 				   then report_illegal_state_var_update
-				   else report_non_visible_state_var
+				   else report_non_visible_state_var(":")
 				 ),
 			PError(Context, VarSet, StateVar, IO0, IO)
 		)
@@ -9510,7 +9513,7 @@
 	  then
 	  	NameX = varset__lookup_name(VarSet, DotX) `with_type` string,
 	  	Name0 = varset__lookup_name(VarSet, Dot0) `with_type` string,
-		compare(RDot, NameX, Name0),
+		compare_svar_names(RDot, NameX, Name0),
 		(
 			RDot  = (<),
 			SInfo = ( SInfo0 ^ dot ^ elem(StateVar) := Dot0 )
@@ -9536,7 +9539,7 @@
 	  then
 	  	NameX = varset__lookup_name(VarSet, ColonX) `with_type` string,
 	  	Name0 = varset__lookup_name(VarSet, Colon0) `with_type` string,
-		compare(RColon, NameX, Name0),
+		compare_svar_names(RColon, NameX, Name0),
 		(
 			RColon = (<),
 			SInfo  = ( SInfo0 ^ colon ^ elem(StateVar) := Colon0 )
@@ -9579,6 +9582,73 @@
 
 %------------------------------------------------------------------------------%
 
+	% We implement a special purpose comparison for state variable
+	% names that compares the numbers appended at the right hand
+	% ends of the name strings.
+	%
+	% NOTE state variable names are either "..._X" or "..._X_N"
+	% where X is the name of the program variable used for the
+	% state variable and N is a decimal number with no leading
+	% zeroes.
+	%
+:- pred compare_svar_names(comparison_result, string, string).
+:- mode compare_svar_names(out, in, in) is det.
+
+compare_svar_names(R, A, B) :-
+	csvns_1(R, 1, A, length(A), B, length(B)).
+
+
+	% First find the start of the numbers at the right hand end, if
+	% present.
+	%
+:- pred csvns_1(comparison_result, int, string, int, string, int).
+:- mode csvns_1(out, in, in, in, in, in) is det.
+
+csvns_1(R, I, A, MaxA, B, MaxB) :-
+	( if I < MaxA, I < MaxB then
+		X = A `unsafe_index` (MaxA - I),
+		Y = B `unsafe_index` (MaxB - I),
+		( if is_digit(X), is_digit(Y)      then
+			csvns_1(R, I + 1, A, MaxA, B, MaxB)
+		  else if X = ('_'),   is_digit(Y) then
+		  	R = (<)
+		  else if is_digit(X), Y = ('_')   then
+		  	R = (>)
+		  else if X = ('_'),   Y = ('_')   then
+		  	csvns_2(R, I - 1, A, MaxA, B, MaxB)
+		  else if X = Y                    then
+		  	R = (=)
+		  else
+			error("make_hlds__compare_svar_names: \
+names are not in expected format")
+		)
+	  else
+		error("make_hlds__compare_svar_names: \
+names are not in expected format")
+	).
+
+
+	% Decide the greater of the two numbers at the right hand end
+	% (both numbers will have the same number of digits.)
+	%
+:- pred csvns_2(comparison_result, int, string, int, string, int).
+:- mode csvns_2(out, in, in, in, in, in) is det.
+
+csvns_2(R, I, A, MaxA, B, MaxB) :-
+	( if 0 < I then
+		X = A `unsafe_index` (MaxA - I) `with_type` char,
+		Y = B `unsafe_index` (MaxB - I) `with_type` char,
+		compare(RXY, X, Y),
+		(	RXY = (<),	R = (<)
+		;	RXY = (=),	csvns_2(R, I - 1, A, MaxA, B, MaxB)
+		;	RXY = (>),	R = (>)
+		)
+	  else
+	  	R = (=)
+	).
+
+%------------------------------------------------------------------------------%
+
 	% We treat equivalence goals as if they were negations (they are
 	% in a negated context after all.)
 	%
@@ -9638,17 +9708,21 @@
 %------------------------------------------------------------------------------%
 
 	% The condition of an if-then-else expression is a goal in which
-	% only !.X state variables are visible (although the goal may
-	% use local state variables introduced via an explicit quantifier.)
+	% only !.X state variables in scope are visible (although the goal
+	% may use local state variables introduced via an explicit
+	% quantifier.)  The StateVars are local to the condition and then-
+	% goal.
 	%
-:- pred prepare_for_if_then_else_expr_condition(svar_info, svar_info).
-:- mode prepare_for_if_then_else_expr_condition(in, out) is det.
+:- pred prepare_for_if_then_else_expr(svars, prog_varset, prog_varset,
+		svar_info, svar_info).
+:- mode prepare_for_if_then_else_expr(in, in, out, in, out) is det.
 
-prepare_for_if_then_else_expr_condition(SInfo0, SInfo) :-
-	SInfo = (((( SInfo0 ^ ctxt         := in_body      )
-			    ^ external_dot := SInfo0 ^ dot )
-			    ^ dot          := map__init    )
-			    ^ colon        := map__init    ).
+prepare_for_if_then_else_expr(StateVars, VarSet0, VarSet, SInfo0, SInfo) :-
+	SInfo1 = ((( new_svar_info ^ ctxt         := in_body      )
+	                           ^ external_dot := SInfo0 ^ dot )
+				   ^ num          := SInfo0 ^ num ),
+	prepare_for_local_state_vars(StateVars, VarSet0, VarSet,
+		SInfo1, SInfo).
 
 %------------------------------------------------------------------------------%
 
@@ -9656,7 +9730,16 @@
 :- mode finish_if_then_else_expr_condition(in, in, out) is det.
 
 finish_if_then_else_expr_condition(SInfoBefore, SInfo0, SInfo) :-
-	SInfo = ( SInfoBefore ^ num := SInfo0 ^ num ).
+	SInfo = ( SInfo0 ^ ctxt := SInfoBefore ^ ctxt ).
+
+%------------------------------------------------------------------------------%
+
+:- pred finish_if_then_else_expr_then_goal(svars,
+		svar_info, svar_info, svar_info).
+:- mode finish_if_then_else_expr_then_goal(in, in, in, out) is det.
+
+finish_if_then_else_expr_then_goal(StateVars, SInfoBefore, SInfo0, SInfo) :-
+	finish_local_state_vars(StateVars, _, SInfoBefore, SInfo0, SInfo).
 
 %------------------------------------------------------------------------------%
 
@@ -9866,7 +9949,7 @@
 %------------------------------------------------------------------------------%
 
 	% We do not allow !X to appear as a lambda head argument.
-	% XXX We could extend the syntax still further to accommodate
+	% We might extend the syntax still further to accommodate
 	% this as an option, e.g. !IO::(di, uo).
 	%
 :- pred lambda_args_contain_bang_state_var(list(prog_term), prog_var).
@@ -9895,14 +9978,15 @@
 
 %------------------------------------------------------------------------------%
 
-:- pred report_non_visible_state_var(prog_context, prog_varset, svar, io, io).
-:- mode report_non_visible_state_var(in, in, in, di, uo) is det.
+:- pred report_non_visible_state_var(string, prog_context, prog_varset, svar,
+		io, io).
+:- mode report_non_visible_state_var(in, in, in, in, di, uo) is det.
 
-report_non_visible_state_var(Context, VarSet, StateVar) -->
+report_non_visible_state_var(DorC, Context, VarSet, StateVar) -->
 	{ Name = varset__lookup_name(VarSet, StateVar) },
 	prog_out__write_context(Context),
 	report_error(string__format("\
-state variable !:%s is not visible in this context.\n", [s(Name)])).
+state variable !%s%s is not visible in this context.\n", [s(DorC), s(Name)])).
 
 %------------------------------------------------------------------------------%
 
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list