mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Branches: main Add support for `try' goals, syntactic sugar on top of the exception handling predicates in the standard library. The syntax is documented in the reference manual. Currently one of the proposed try parameters, io(!IO), is implemented. Try goals are implemented by *two* source-to-source transformations, one at the parse tree level, then a later one on the HLDS. The reason for this is given in try_expand.m. library/ops.m: Add three new operators: try, catch, catch_any. library/exception.m: Add forwarding predicates so that code generated by the try goal transformation doesn't need to import `univ'. compiler/prog_item.m: Add representations of try goals to parse tree. compiler/prog_io_goal.m: Parse try goals. Unrelated: fix spelling of "parameter". compiler/add_clause.m: Perform the initial transformation on try goals. compiler/hlds_goal.m: Add try goals to HLDS, as shorthand goals. compiler/try_expand.m: New module to perform the latter transformation on try goals. compiler/check_hlds.m: Import the new module. compiler/mercury_compile.m: Call the try_expand pass near the end of the front-end pass. compiler/module_imports.m: Implicitly import `exception' if a `try' goal is seen. compiler/det_analysis.m: Conform to addition of try goals in HLDS. Make it not wrap a commit scope around the intermediate try goal (as it might if there are no outputs) as it is inappropriate. compiler/prog_util.m: Conform to parse tree changes. compiler/assertion.m: compiler/build_mode_constraints.m: compiler/cse_detection.m: compiler/delay_partial_inst.m: compiler/dependency_graph.m: compiler/det_report.m: compiler/equiv_type_hlds.m: compiler/format_call.m: compiler/goal_form.m: compiler/goal_path.m: compiler/goal_util.m: compiler/hlds_out.m: compiler/intermod.m: compiler/lambda.m: compiler/make_hlds_warn.m: compiler/mercury_to_mercury.m: compiler/mode_util.m: compiler/modes.m: compiler/module_qual.m: compiler/ordering_mode_constraints.m: compiler/polymorphism.m: compiler/post_typecheck.m: compiler/prop_mode_constraints.m: compiler/purity.m: compiler/quantification.m: compiler/simplify.m: compiler/stm_expand.m: compiler/stratify.m: compiler/structure_reuse.lfu.m: compiler/switch_detection.m: compiler/type_constraints.m: compiler/typecheck.m: compiler/unique_modes.m: compiler/unused_imports.m: Conform to changes in HLDS. compiler/il_peephole.m: compiler/ilasm.m: compiler/ilds.m: compiler/mlds_to_il.m: Rename some symbols to avoid the new keywords. library/exception.m: Add two helper predicates for the try goal transformations. doc/reference_manual.texi: NEWS: Document and announce the new language feature. compiler/notes/compiler_design.html: Note new compiler module. tests/hard_coded/Mmakefile: tests/hard_coded/try_syntax_1.exp: tests/hard_coded/try_syntax_1.m: tests/hard_coded/try_syntax_2.exp: tests/hard_coded/try_syntax_2.m: tests/hard_coded/try_syntax_3.exp: tests/hard_coded/try_syntax_3.m: tests/hard_coded/try_syntax_4.exp: tests/hard_coded/try_syntax_4.m: tests/hard_coded/try_syntax_5.exp: tests/hard_coded/try_syntax_5.m: tests/hard_coded/try_syntax_6.exp: tests/hard_coded/try_syntax_6.m: tests/hard_coded/try_syntax_7.exp: tests/hard_coded/try_syntax_7.m: tests/invalid/Mmakefile: tests/invalid/try_bad_params.err_exp: tests/invalid/try_bad_params.m: tests/invalid/try_io_else.err_exp: tests/invalid/try_io_else.m: Add test cases. tests/debugger/declarative/catch.m: The module name is now a keyword so requires brackets. tests/invalid/trace_goal_env.err_exp: Update test case for fixed spelling for "parameter". vim/syntax/mercury.vim: Add try, catch, catch_any as keywords.
338 lines
13 KiB
Mathematica
338 lines
13 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-2009 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: structure_reuse.lfu.m.
|
|
% Main authors: nancy.
|
|
%
|
|
% Implementation of the process of annotating each program point within
|
|
% a procedure with local forward use information.
|
|
%
|
|
% At a program point (a goal), a variable is called in local forward use iff
|
|
% * it was already instantiated before the goal
|
|
% * and it is (syntactically) used in the goals following the current goal in
|
|
% forward execution.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.ctgc.structure_reuse.lfu.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module set.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred forward_use_information(proc_info::in, proc_info::out) is det.
|
|
|
|
% add_vars_to_lfu(Vars, !ProcInfo).
|
|
%
|
|
% Add the vars to all the LFU sets in the body of the procedure.
|
|
%
|
|
:- pred add_vars_to_lfu(set(prog_var)::in, proc_info::in, proc_info::out)
|
|
is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module parse_tree.prog_type.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
forward_use_information(!ProcInfo) :-
|
|
proc_info_get_vartypes(!.ProcInfo, VarTypes),
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
|
|
% Set of variables initially instantiated.
|
|
proc_info_get_liveness_info(!.ProcInfo, InstantiatedVars0),
|
|
% Set of variables initially "dead" = instantiated variables that
|
|
% syntactically do not occur in the remainder of the goal.
|
|
set.init(DeadVars0),
|
|
|
|
forward_use_in_goal(VarTypes, Goal0, Goal,
|
|
remove_typeinfo_vars_from_set(VarTypes, InstantiatedVars0),
|
|
_InstantiatedVars, DeadVars0, _DeadVars),
|
|
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
:- pred forward_use_in_goal(vartypes::in, hlds_goal::in, hlds_goal::out,
|
|
set(prog_var)::in, set(prog_var)::out,
|
|
set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_goal(VarTypes, !Goal, !InstantiatedVars, !DeadVars) :-
|
|
!.Goal = hlds_goal(GoalExpr0, GoalInfo0),
|
|
HasSubGoals = goal_expr_has_subgoals(GoalExpr0),
|
|
(
|
|
HasSubGoals = does_not_have_subgoals,
|
|
InstantiatedVars0 = !.InstantiatedVars,
|
|
compute_instantiated_and_dead_vars(VarTypes, GoalInfo0,
|
|
!InstantiatedVars, !DeadVars),
|
|
set.difference(InstantiatedVars0, !.DeadVars, LFU),
|
|
goal_info_set_lfu(LFU, GoalInfo0, GoalInfo),
|
|
!:Goal = hlds_goal(GoalExpr0, GoalInfo)
|
|
;
|
|
HasSubGoals = has_subgoals,
|
|
goal_info_get_pre_deaths(GoalInfo0, PreDeaths),
|
|
set.union(PreDeaths, !DeadVars),
|
|
forward_use_in_composite_goal(VarTypes, !Goal,
|
|
!InstantiatedVars, !DeadVars)
|
|
).
|
|
|
|
:- pred compute_instantiated_and_dead_vars(vartypes::in, hlds_goal_info::in,
|
|
set(prog_var)::in, set(prog_var)::out,
|
|
set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
compute_instantiated_and_dead_vars(VarTypes, Info, !Inst, !Dead) :-
|
|
% Inst = Inst0 + birth-set
|
|
% Dead = Dead0 + death-set
|
|
goal_info_get_pre_births(Info, PreBirths),
|
|
goal_info_get_post_births(Info, PostBirths),
|
|
goal_info_get_post_deaths(Info, PostDeaths),
|
|
goal_info_get_pre_deaths(Info, PreDeaths),
|
|
!:Inst = set.union_list([
|
|
remove_typeinfo_vars_from_set(VarTypes, PreBirths),
|
|
remove_typeinfo_vars_from_set(VarTypes, PostBirths), !.Inst]),
|
|
!:Dead = set.union_list([PreDeaths, PostDeaths, !.Dead]).
|
|
|
|
:- pred forward_use_in_composite_goal(vartypes::in, hlds_goal::in,
|
|
hlds_goal::out, set(prog_var)::in, set(prog_var)::out,
|
|
set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_composite_goal(VarTypes, !Goal, !InstantiatedVars,
|
|
!DeadVars) :-
|
|
!.Goal = hlds_goal(GoalExpr0, GoalInfo0),
|
|
InstantiadedBefore = !.InstantiatedVars,
|
|
|
|
(
|
|
GoalExpr0 = conj(ConjType, Goals0),
|
|
forward_use_in_conj(VarTypes, Goals0, Goals,
|
|
!InstantiatedVars, !DeadVars),
|
|
GoalExpr = conj(ConjType, Goals)
|
|
;
|
|
GoalExpr0 = switch(Var, CanFail, Cases0),
|
|
forward_use_in_cases(VarTypes, Cases0, Cases,
|
|
!InstantiatedVars, !DeadVars),
|
|
GoalExpr = switch(Var, CanFail, Cases)
|
|
;
|
|
GoalExpr0 = disj(Disj0),
|
|
forward_use_in_disj(VarTypes, Disj0, Disj,
|
|
!InstantiatedVars, !DeadVars),
|
|
GoalExpr = disj(Disj)
|
|
;
|
|
GoalExpr0 = negation(SubGoal0),
|
|
forward_use_in_goal(VarTypes, SubGoal0, SubGoal,
|
|
!InstantiatedVars, !DeadVars),
|
|
GoalExpr = negation(SubGoal)
|
|
;
|
|
GoalExpr0 = scope(Reason, SubGoal0),
|
|
% XXX We should special-case the handling of from_ground_term_construct
|
|
% scopes.
|
|
forward_use_in_goal(VarTypes, SubGoal0, SubGoal,
|
|
!InstantiatedVars, !DeadVars),
|
|
GoalExpr = scope(Reason, SubGoal)
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
|
|
Inst0 = !.InstantiatedVars,
|
|
Dead0 = !.DeadVars,
|
|
forward_use_in_goal(VarTypes, Cond0, Cond,
|
|
!InstantiatedVars, !DeadVars),
|
|
forward_use_in_goal(VarTypes, Then0, Then,
|
|
!InstantiatedVars, !DeadVars),
|
|
forward_use_in_goal(VarTypes, Else0, Else, Inst0, Inst1, Dead0, Dead1),
|
|
set.union(Inst1, !InstantiatedVars),
|
|
set.union(Dead1, !DeadVars),
|
|
GoalExpr = if_then_else(Vars, Cond, Then, Else)
|
|
;
|
|
( GoalExpr0 = unify(_, _, _, _, _)
|
|
; GoalExpr0 = plain_call(_, _, _, _, _, _)
|
|
; GoalExpr0 = generic_call(_, _, _, _)
|
|
; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
|
|
),
|
|
unexpected(this_file,
|
|
"forward_use_in_composite_goal: atomic goal")
|
|
;
|
|
GoalExpr0 = shorthand(_),
|
|
unexpected(this_file,
|
|
"forward_use_in_composite_goal: shorthand")
|
|
),
|
|
set.difference(InstantiadedBefore, !.DeadVars, LFU),
|
|
goal_info_set_lfu(LFU, GoalInfo0, GoalInfo),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
:- pred forward_use_in_conj(vartypes::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, set(prog_var)::in, set(prog_var)::out,
|
|
set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_conj(VarTypes, !Goals, !InstantiatedVars, !DeadVars) :-
|
|
list.map_foldl2(forward_use_in_goal(VarTypes), !Goals,
|
|
!InstantiatedVars, !DeadVars).
|
|
|
|
:- pred forward_use_in_cases(vartypes::in, list(case)::in, list(case)::out,
|
|
set(prog_var)::in, set(prog_var)::out, set(prog_var)::in,
|
|
set(prog_var)::out) is det.
|
|
|
|
forward_use_in_cases(VarTypes, !Cases, !InstantiatedVars, !DeadVars) :-
|
|
Inst0 = !.InstantiatedVars,
|
|
Dead0 = !.DeadVars,
|
|
list.map_foldl2(forward_use_in_case(VarTypes, Inst0, Dead0),
|
|
!Cases, !InstantiatedVars, !DeadVars).
|
|
|
|
:- pred forward_use_in_case(vartypes::in, set(prog_var)::in,
|
|
set(prog_var)::in, case::in, case::out, set(prog_var)::in,
|
|
set(prog_var)::out, set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_case(VarTypes, Inst0, Dead0, !Case,
|
|
!InstantiatedVars, !DeadVars) :-
|
|
!.Case = case(MainConsId, OtherConsIds, Goal0),
|
|
forward_use_in_goal(VarTypes, Goal0, Goal, Inst0, Inst, Dead0, Dead),
|
|
!:Case = case(MainConsId, OtherConsIds, Goal),
|
|
set.union(Inst, !InstantiatedVars),
|
|
set.union(Dead, !DeadVars).
|
|
|
|
:- pred forward_use_in_disj(vartypes::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, set(prog_var)::in, set(prog_var)::out,
|
|
set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_disj(VarTypes, !Goals, !InstantiatedVars, !DeadVars):-
|
|
Inst0 = !.InstantiatedVars,
|
|
Dead0 = !.DeadVars,
|
|
list.map_foldl2(forward_use_in_disj_goal(VarTypes, Inst0, Dead0),
|
|
!Goals, !InstantiatedVars, !DeadVars).
|
|
|
|
:- pred forward_use_in_disj_goal(vartypes::in, set(prog_var)::in,
|
|
set(prog_var)::in, hlds_goal::in, hlds_goal::out, set(prog_var)::in,
|
|
set(prog_var)::out, set(prog_var)::in, set(prog_var)::out) is det.
|
|
|
|
forward_use_in_disj_goal(VarTypes, Inst0, Dead0, !Goal,
|
|
!InstantiatedVars, !DeadVars) :-
|
|
forward_use_in_goal(VarTypes, !Goal, Inst0, Inst, Dead0, Dead),
|
|
set.union(Inst, !InstantiatedVars),
|
|
set.union(Dead, !DeadVars).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
add_vars_to_lfu(ForceInUse, !ProcInfo) :-
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal),
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
:- pred add_vars_to_lfu_in_goal(set(prog_var)::in,
|
|
hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal) :-
|
|
Goal0 = hlds_goal(Expr0, GoalInfo0),
|
|
add_vars_to_lfu_in_goal_expr(ForceInUse, Expr0, Expr),
|
|
LFU0 = goal_info_get_lfu(GoalInfo0),
|
|
LFU = set.union(ForceInUse, LFU0),
|
|
goal_info_set_lfu(LFU, GoalInfo0, GoalInfo1),
|
|
goal_info_set_reuse(no_reuse_info, GoalInfo1, GoalInfo),
|
|
Goal = hlds_goal(Expr, GoalInfo).
|
|
|
|
:- pred add_vars_to_lfu_in_goal_expr(set(prog_var)::in,
|
|
hlds_goal_expr::in, hlds_goal_expr::out) is det.
|
|
|
|
add_vars_to_lfu_in_goal_expr(ForceInUse, Expr0, Expr) :-
|
|
(
|
|
Expr0 = conj(ConjType, Goals0),
|
|
add_vars_to_lfu_in_goals(ForceInUse, Goals0, Goals),
|
|
Expr = conj(ConjType, Goals)
|
|
;
|
|
Expr0 = disj(Goals0),
|
|
add_vars_to_lfu_in_goals(ForceInUse, Goals0, Goals),
|
|
Expr = disj(Goals)
|
|
;
|
|
Expr0 = switch(Var, Det, Cases0),
|
|
add_vars_to_lfu_in_cases(ForceInUse, Cases0, Cases),
|
|
Expr = switch(Var, Det, Cases)
|
|
;
|
|
Expr0 = if_then_else(Vars, Cond0, Then0, Else0),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Cond0, Cond),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Then0, Then),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Else0, Else),
|
|
Expr = if_then_else(Vars, Cond, Then, Else)
|
|
;
|
|
Expr0 = negation(Goal0),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal),
|
|
Expr = negation(Goal)
|
|
;
|
|
Expr0 = scope(Reason, Goal0),
|
|
% XXX We should special-case the handling of from_ground_term_construct
|
|
% scopes.
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal),
|
|
Expr = scope(Reason, Goal)
|
|
;
|
|
Expr0 = generic_call(_, _, _, _),
|
|
Expr = Expr0
|
|
;
|
|
Expr0 = plain_call(_, _, _, _, _, _),
|
|
Expr = Expr0
|
|
;
|
|
Expr0 = unify(_, _, _, _, _),
|
|
Expr = Expr0
|
|
;
|
|
Expr0 = call_foreign_proc(_, _, _, _, _, _, _),
|
|
Expr = Expr0
|
|
;
|
|
Expr0 = shorthand(Shorthand0),
|
|
(
|
|
Shorthand0 = atomic_goal(GoalType, Outer, Inner,
|
|
MaybeOutputVars, MainGoal0, OrElseGoals0, OrElseInners),
|
|
add_vars_to_lfu_in_goal(ForceInUse, MainGoal0, MainGoal),
|
|
add_vars_to_lfu_in_goals(ForceInUse, OrElseGoals0, OrElseGoals),
|
|
Shorthand = atomic_goal(GoalType, Outer, Inner,
|
|
MaybeOutputVars, MainGoal, OrElseGoals, OrElseInners)
|
|
;
|
|
Shorthand0 = bi_implication(LeftGoal0, RightGoal0),
|
|
add_vars_to_lfu_in_goal(ForceInUse, LeftGoal0, LeftGoal),
|
|
add_vars_to_lfu_in_goal(ForceInUse, RightGoal0, RightGoal),
|
|
Shorthand = bi_implication(LeftGoal, RightGoal)
|
|
;
|
|
Shorthand0 = try_goal(_, _, _),
|
|
unexpected(this_file, "add_vars_to_lfu_in_goal_expr: try_goal")
|
|
),
|
|
Expr = shorthand(Shorthand)
|
|
).
|
|
|
|
:- pred add_vars_to_lfu_in_goals(set(prog_var)::in,
|
|
hlds_goals::in, hlds_goals::out) is det.
|
|
|
|
add_vars_to_lfu_in_goals(_, [], []).
|
|
add_vars_to_lfu_in_goals(ForceInUse, [Goal0 | Goals0], [Goal | Goals]) :-
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal),
|
|
add_vars_to_lfu_in_goals(ForceInUse, Goals0, Goals).
|
|
|
|
:- pred add_vars_to_lfu_in_cases(set(prog_var)::in,
|
|
list(case)::in, list(case)::out) is det.
|
|
|
|
add_vars_to_lfu_in_cases(_, [], []).
|
|
add_vars_to_lfu_in_cases(ForceInUse, [Case0 | Cases0], [Case | Cases]) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
add_vars_to_lfu_in_goal(ForceInUse, Goal0, Goal),
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
add_vars_to_lfu_in_cases(ForceInUse, Cases0, Cases).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "structure_reuse.lfu.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.ctgc.structure_reuse.lfu.
|
|
%-----------------------------------------------------------------------------%
|