1 % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(bsyntaxtree_quantifiers,[ create_z_let/6 ]).
6
7
8 :- use_module(module_information,[module_info/2]).
9 :- module_info(group,typechecker).
10 :- module_info(description,'This module provides operations on the type-checked AST.').
11
12
13
14 :- use_module(bsyntaxtree,[find_identifier_uses/3,get_texpr_id/2, get_texpr_ids/2, get_texpr_type/2,
15 find_identifier_uses_l/3, rename_bt/3,
16 create_texpr/4]).
17
18
19 % ****************************************************
20
21 :- use_module(error_manager,[add_warning/3]).
22
23 % create Z-style let; see page 59 of Spivey, identifiers are not in scope for Value expressions
24 % ExPr is either expr or pred or a variable
25 create_z_let(ExPr,Ids,Values,Inner1,Infos,Result) :-
26 remove_unused_identifiers(Ids,Values,Inner1,RIds0,RValues0),
27 remove_unnecessary_lets(RIds0,RValues0,RIds1,RValues),
28 ( RIds1=[] -> Result = Inner1
29 ;
30 find_identifier_uses_l(RValues,[],RVars),
31 gen_fresh_typed_params(RIds1,Inner1,RVars,RIds,Inner),
32 (var(ExPr), get_texpr_type(Inner,Pred), Pred==pred -> ExPr=pred ; true), % if ExPr not set: infer it from Inner
33 (ExPr=expr ->
34 get_texpr_type(Inner,Type),
35 create_texpr(let_expression(RIds,RValues,Inner),Type,Infos,Result)
36 ; ExPr=pred ->
37 create_texpr(let_predicate(RIds,RValues,Inner),pred,Infos,Result)
38 ),
39 % extra check: but gen_fresh_typed_params should ensure everything ok
40 get_texpr_ids(RIds,S1), sort(S1,SortedIDs),
41 (ord_intersection(SortedIDs,RVars,Clash), Clash \= []
42 -> add_warning(create_let,'Variable clash in generated let:',Clash)
43 % can cause problems if we use let_predicate/let_expression which allows introducing multiple, dependent ids
44 ; true)
45 ).
46
47 :- use_module(library(lists)).
48 :- use_module(library(ordsets)).
49
50 %% rename parameters and direct definition body to use fresh ids
51 %% reason is that otherwise we repeatedly introduce the same variable and obtain nested lets with variable clashes
52 %% i.e., we may get lets of the form LET a ... LET a,b BE a=(a) & b=(a) ... where (a) is the outer value of a
53 %% Note: however, performance of test 1657 suffers if we systematically rename (hence we only rename VarsToAvoid)
54 gen_fresh_typed_params(TParams,TBody,VarsToAvoid,NewTParams,NewTBody) :-
55 maplist(alpha_typed_id_rename(VarsToAvoid),TParams,NewTParams,RenameList),
56 rename_bt(TBody,RenameList,NewTBody).
57
58 :- use_module(probsrc(gensym),[gensym/2]).
59 alpha_typed_id_rename(VarsToAvoid,b(identifier(OldID),T,I),b(identifier(FreshID),T,I),rename(OldID,FreshID)) :-
60 (ord_member(OldID,VarsToAvoid) -> gensym(OldID,FreshID) ; FreshID=OldID).
61
62 remove_unused_identifiers(TLetIds1,TLetValues1,TDef,TLetIds,TLetValues) :-
63 find_identifier_uses(TDef,[],UsedIds),
64 maplist(combine_with_minus,TLetIds1,TLetValues1,IdValuePairs),
65 include(id_is_used(UsedIds),IdValuePairs,NewIdValuePairs),
66 maplist(combine_with_minus,TLetIds,TLetValues,NewIdValuePairs).
67
68 % remove let a=a, ...
69 remove_unnecessary_lets([],[],[],[]).
70 remove_unnecessary_lets([TID|T1],[TRHS|T2],IDS,RHSS) :-
71 (unnecessary_let(TID,TRHS)
72 -> remove_unnecessary_lets(T1,T2,IDS,RHSS)
73 ; IDS=[TID|TIDS], RHSS = [TRHS|TRHSS], remove_unnecessary_lets(T1,T2,TIDS,TRHSS)
74 ).
75 unnecessary_let(b(identifier(ID),T,_),b(identifier(ID),T,_)).
76 combine_with_minus(A,B,A-B).
77 id_is_used(UsedIds,TId-_Value) :-
78 get_texpr_id(TId,Id),memberchk(Id,UsedIds).
79