~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/stdlib/src/qlc_pt.erl

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2009-05-07 15:07:37 UTC
  • mfrom: (1.2.1 upstream) (5.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20090507150737-i4yb5elwinm7r0hc
Tags: 1:13.b-dfsg1-1
* Removed another bunch of non-free RFCs from original tarball
  (closes: #527053).
* Fixed build-dependencies list by adding missing comma. This requires
  libsctp-dev again. Also, added libsctp1 dependency to erlang-base and
  erlang-base-hipe packages because the shared library is loaded via
  dlopen now and cannot be added using dh_slibdeps (closes: #526682).
* Weakened dependency of erlang-webtool on erlang-observer to recommends
  to avoid circular dependencies (closes: #526627).
* Added solaris-i386 to HiPE enabled architectures.
* Made script sources in /usr/lib/erlang/erts-*/bin directory executable,
  which is more convenient if a user wants to create a target Erlang system.
* Shortened extended description line for erlang-dev package to make it
  fit 80x25 terminals.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
%% ``The contents of this file are subject to the Erlang Public License,
 
1
%%
 
2
%% %CopyrightBegin%
 
3
%% 
 
4
%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
 
5
%% 
 
6
%% The contents of this file are subject to the Erlang Public License,
2
7
%% Version 1.1, (the "License"); you may not use this file except in
3
8
%% compliance with the License. You should have received a copy of the
4
9
%% Erlang Public License along with this software. If not, it can be
5
 
%% retrieved via the world wide web at http://www.erlang.org/.
 
10
%% retrieved online at http://www.erlang.org/.
6
11
%% 
7
12
%% Software distributed under the License is distributed on an "AS IS"
8
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
14
%% the License for the specific language governing rights and limitations
10
15
%% under the License.
11
16
%% 
12
 
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
 
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
 
%% AB. All Rights Reserved.''
15
 
%% 
16
 
%%     $Id $
 
17
%% %CopyrightEnd%
17
18
%%
18
19
-module(qlc_pt).
19
20
 
22
23
-export([parse_transform/2, transform_from_evaluator/2, 
23
24
         transform_expression/2]).
24
25
 
25
 
%% Exported to qlc.erl only:
26
 
-export([vars/1, aux_name1/3]).
27
 
 
28
 
-import(lists, [append/1, flatmap/2, flatten/1, keysearch/3, sort/1]).
29
 
 
30
26
-include_lib("stdlib/include/ms_transform.hrl").
31
27
 
32
28
-define(APIMOD, qlc).
150
146
-record(qid, {lcid,no}).
151
147
 
152
148
mforms(Tag, L) ->
153
 
    sort([{Tag,M} || {_File,Ms} <- L, M <- Ms]).
 
149
    lists:sort([{Tag,M} || {_File,Ms} <- L, M <- Ms]).
154
150
 
155
151
%% Avoid duplicated lint warnings and lint errors. Care has been taken
156
152
%% not to introduce unused variables in the transformed code.
173
169
    {mforms2(error, Es),mforms2(warning, Ws)}.
174
170
 
175
171
mforms(L) ->
176
 
    sort([{File,[M]} || {File,Ms} <- L, M <- Ms]).
 
172
    lists:sort([{File,[M]} || {File,Ms} <- L, M <- Ms]).
177
173
 
178
174
mforms2(Tag, L) ->
179
175
    Line = 0,
180
 
    ML = flatmap(fun({File,Ms}) ->
181
 
                         [[{attribute,Line,file,{File,Line}}, {Tag,M}] || 
182
 
                             M <- Ms]
183
 
                 end, sort(L)),
184
 
    flatten(sort(ML)).
 
176
    ML = lists:flatmap(fun({File,Ms}) ->
 
177
                               [[{attribute,Line,file,{File,Line}}, {Tag,M}] ||
 
178
                                   M <- Ms]
 
179
                       end, lists:sort(L)),
 
180
    lists:flatten(lists:sort(ML)).
185
181
 
186
182
is_qlc_q_imported(Forms) ->
187
183
    [[] || {attribute,_,import,{?APIMOD,FAs}} <- Forms, {?Q,1} <- FAs] =/= [].
265
261
intro_variables(FormsNoShadows, State) ->
266
262
    Fun = fun(QId, {T,_L,P0,_E0}=Q, {GVs,QIds}, Foo) when T =:= b_generate;
267
263
                                                          T =:= generate ->
268
 
                  PVs = var_ufold(fun({var,_,V}) -> {QId,V} end, P0),
 
264
                  PVs = qlc:var_ufold(fun({var,_,V}) -> {QId,V} end, P0),
269
265
                  {Q,{ordsets:to_list(PVs) ++ GVs,[{QId,[]} | QIds]},Foo};
270
266
             (QId, Filter0, {GVs,QIds}, Foo) ->
271
267
                  %% The filter F is replaced by begin E, F, E end,
272
268
                  %% where E is an LC expression consisting of a
273
269
                  %% template mentioning all variables occurring in F.
274
 
                  Vs = ordsets:to_list(vars(Filter0)),
 
270
                  Vs = ordsets:to_list(qlc:vars(Filter0)),
275
271
                  Id = QId#qid.lcid,
276
272
                  LC1 = embed_vars([{var,{QId,f1},V} || V <- Vs], Id),
277
273
                  LC2 = embed_vars([{var,{QId,f2},V} || V <- Vs], Id),
303
299
            [];
304
300
        {Errors, _Warnings} ->
305
301
            ?DEBUG("got errors ~p~n", [Errors]),
306
 
            flatmap(fun({_File,Es}) -> Es end, Errors)
 
302
            lists:flatmap(fun({_File,Es}) -> Es end, Errors)
307
303
    end.
308
304
 
309
305
-define(MAX_NUM_OF_LINES, 23). % assume max 1^23 lines (> 8 millions)
360
356
                            {var, L, OrigVar} = undo_no_shadows(Var),
361
357
                            {var, {extra, L, get(?QLC_FILE), OrigVar}, V} 
362
358
                    end,
363
 
                Vs = [Var || {var, _, V}=Var <- var_fold(F, [], LE),
 
359
                Vs = [Var || {var, _, V}=Var <- qlc:var_fold(F, [], LE),
364
360
                             lists:member(V, IVsSoFar0)],
365
361
                Exprs = case Vs of
366
362
                            [] -> Exprs0;
376
372
    Acc0 = {IntroVars, [{atom, 0, true}]},
377
373
    {_, {[], Exprs}} = qual_fold(F, Acc0, [], FormsNoShadows, State),
378
374
    FunctionNames = [Name || {function, _, Name, _, _} <- FormsNoShadows],
379
 
    UniqueFName = aux_name(used_genvar, 1, sets:from_list(FunctionNames)),
 
375
    UniqueFName = qlc:aux_name(used_genvar, 1, sets:from_list(FunctionNames)),
380
376
    {function,0,UniqueFName,0,[{clause,0,[],[],lists:reverse(Exprs)}]}.
381
377
    
382
378
q_intro_vars(QId, [{QId, IVs} | QsIVs], IVsSoFar) -> {QsIVs, IVs ++ IVsSoFar}.
476
472
 
477
473
transform(FormsNoShadows, State) ->
478
474
    IntroVars = intro_variables(FormsNoShadows, State),
479
 
    AllVars = sets:from_list(ordsets:to_list(vars(FormsNoShadows))),
 
475
    AllVars = sets:from_list(ordsets:to_list(qlc:vars(FormsNoShadows))),
480
476
    ?DEBUG("AllVars = ~p~n", [sets:to_list(AllVars)]),
481
477
    F1 = fun(QId, {generate,_,P,LE}, Foo, {GoI,SI}) ->
482
478
                 {{QId,GoI,SI,{gen,P,LE}},Foo,{GoI + 3, SI + 2}};
525
521
 
526
522
                 Dependencies = qualifier_dependencies(Qs, IntroVs),
527
523
                 L = no_compiler_warning(LcL),
528
 
                 {ColumnConstants, SizeInfo, ExtraConsts} = 
529
 
                      constants_and_sizes(Qs, E, Dependencies, AllIVs, State),
 
524
                 {EqColumnConstants, EqualColumnConstants,
 
525
                  ExtraConsts, SizeInfo} =
 
526
                     constants_and_sizes(Qs, E, Dependencies, AllIVs, State),
530
527
                 {JoinInfo, XWarn} = 
531
528
                     join_kind(Qs, LcL, AllIVs, Dependencies, State),
532
529
                 %% Not at all sure it is a good idea to try and find 
533
530
                 %% failing qualifiers; Dialyzer does it so much better.
534
531
                 %% But there are a few cases where qlc finds more... (r12b).
535
 
                 FWarn = warn_failing_qualifiers(Qs, State),
 
532
                 FWarn = warn_failing_qualifiers(Qs, AllIVs, Dependencies, 
 
533
                                                 State),
536
534
                 JQs = join_quals(JoinInfo, QCs, L, LcNo, ExtraConsts, AllVars),
537
535
                 XQCs = QCs ++ JQs,
538
536
                 Cs0 = clauses(XQCs, RL, Fun, Go, NGV, Err, AllIVs, State),
554
552
                     template_columns(Qs, E, AllIVs, Dependencies, State),
555
553
                 %% ExtraConsts should be used by match_spec_quals.
556
554
                 MSQs = match_spec_quals(E, Dependencies, Qs, State),
557
 
                 Opt = opt_info(TemplateInfo, SizeInfo,
558
 
                                JoinInfo, ColumnConstants, MSQs, L),
 
555
                 Opt = opt_info(TemplateInfo, SizeInfo, JoinInfo, MSQs, L,
 
556
                                EqColumnConstants, EqualColumnConstants),
559
557
                 LCTuple = 
560
558
                     case qlc_kind(OrigE, Qs) of
561
559
                         qlc ->
576
574
join_kind(Qs, LcL, AllIVs, Dependencies, State) ->
577
575
    {EqualCols2, EqualColsN} = equal_columns(Qs, AllIVs, Dependencies, State),
578
576
    {MatchCols2, MatchColsN} = eq_columns(Qs, AllIVs, Dependencies, State),
579
 
    Tables = lists:usort([T || C <- EqualCols2, {T,_} <- C]
580
 
                         ++ [T || C <- EqualCols2, T <- C, is_integer(T)]),
 
577
    Tables = lists:usort
 
578
               ([T || {C,_Skip} <- EqualCols2, {T,_} <- C]
 
579
             ++ [T || {C,_Skip} <- EqualCols2, T <- C, is_integer(T)]),
581
580
    if 
582
581
        EqualColsN =/= []; MatchColsN =/= [] -> 
583
582
            {[], 
608
607
%% Finds filters and patterns that cannot match any values at all. 
609
608
%% Nothing but the patterns and the filters themselves is analyzed.
610
609
%% A much weaker analysis than the one of Dialyzer.
611
 
warn_failing_qualifiers(Qualifiers, State) ->
 
610
warn_failing_qualifiers(Qualifiers, AllIVs, Dependencies, State) ->
612
611
    {FilterData, GeneratorData} = qual_data(Qualifiers),    
613
612
    Anon = 1,
614
 
    Imported = [],
615
 
    BindFun = fun(Value, Op) -> is_bindable(Value, Op, Imported) end,
 
613
    BindFun = fun(_Op, Value) -> is_bindable(Value) end,
616
614
    {PFrame, _PatternVars} = 
617
615
        pattern_frame(GeneratorData, BindFun, Anon, State),
 
616
    {_, _, Imported} = 
 
617
        filter_info(FilterData, AllIVs, Dependencies, State),
618
618
    PFrames = frame2frames(PFrame),
619
 
    SkipFun = fun(Fs) -> Fs end,
620
619
    {_, Warnings} = 
621
620
        lists:foldl(fun({_QId,{fil,_Filter}}, {[]=Frames,Warnings}) ->
622
621
                            {Frames,Warnings};
623
622
                       ({_QId,{fil,Filter}}, {Frames,Warnings}) ->
624
623
                        case filter(set_line(Filter, 0), Frames, BindFun, 
625
 
                                    SkipFun, State) of
 
624
                                    State, Imported) of
626
625
                            [] ->
627
626
                                {[],
628
627
                                 [{get(?QLC_FILE),
647
646
-define(TNO, 0).
648
647
-define(TID, #qid{lcid = template, no = ?TNO}).
649
648
 
650
 
opt_info(TemplateInfo, Sizes, JoinInfo, ColumnConstants0, MSQs, L) ->
651
 
    SzCls = [{clause,L,[?I(C)],[],[?I(Sz)]} || {C,Sz} <- sort(Sizes)]
 
649
opt_info(TemplateInfo, Sizes, JoinInfo, MSQs, L, 
 
650
         EqColumnConstants0, EqualColumnConstants0) ->
 
651
    SzCls = [{clause,L,[?I(C)],[],[?I(Sz)]} || {C,Sz} <- lists:sort(Sizes)]
652
652
            ++ [{clause,L,[?V('_')],[],[?A(undefined)]}],
653
653
    S = [{size, {'fun', L, {clauses, SzCls}}}],
654
654
    J = case JoinInfo of [] -> []; _ -> [{join, abstr(JoinInfo, L)}] end,
655
655
    %% Superfluous clauses may be emitted:
656
 
    TCls0 = append(
 
656
    TCls0 = lists:append(
657
657
              [[{clause,L,[abstr(Col, L),EqType],[],
658
658
                 [abstr(TemplCols, L)]} ||
659
659
                   {Col,TemplCols} <- TemplateColumns]
660
660
               || {EqType, TemplateColumns} <- TemplateInfo]),
661
 
    TCls = sort(TCls0) ++ [{clause,L,[?V('_'),?V('_')],[],[{nil,L}]}],
 
661
    TCls = lists:sort(TCls0) ++ [{clause,L,[?V('_'),?V('_')],[],[{nil,L}]}],
662
662
    T = [{template, {'fun', L, {clauses, TCls}}}],
663
663
 
664
664
    %% The template may also have a constant function (IdNo = 0).
665
665
    %% Only constant template columns are interesting.
666
 
    ColumnConstants = [CC || {{IdNo,_Col},Const,_FilNs}=CC <- ColumnConstants0,
667
 
                             (IdNo =/= ?TNO) or (length(Const) =:= 1)],
668
 
    Ns = lists:usort([IdNo || {{IdNo,_Col},_Const,_FilNs} <- ColumnConstants]),
669
 
    CCs = [{clause,L,[?I(IdNo)],[],[column_fun(ColumnConstants, IdNo, L)]}
670
 
           || IdNo <- Ns]
671
 
         ++ [{clause,L,[?V('_')],[],[?A(no_column_fun)]}],
672
 
    C = [{constants,{'fun',L,{clauses,CCs}}}],
673
 
 
674
 
    ConstCols = [{IdNo,Col} || {{IdNo,Col},[_],_FilNs} <- ColumnConstants],
 
666
    EqColumnConstants = opt_column_constants(EqColumnConstants0),
 
667
    CCs = opt_constants(L, EqColumnConstants),
 
668
    EqC = {constants,{'fun',L,{clauses,CCs}}},
 
669
 
 
670
    EqualColumnConstants = opt_column_constants(EqualColumnConstants0),
 
671
    ECCs = opt_constants(L, EqualColumnConstants),
 
672
    EqualC = {equal_constants,{'fun',L,{clauses,ECCs}}},
 
673
    C = [EqC | [EqualC || true <- [CCs =/= ECCs]]],
 
674
 
 
675
    %% Comparisons yield more constant columns than matchings.
 
676
    ConstCols = [{IdNo,Col} || 
 
677
                    {{IdNo,Col},[_],_FilNs} <- EqualColumnConstants],
675
678
    ConstColsFamily = family_list(ConstCols),
676
679
    NSortedCols0 = [{IdNo,hd(lists:seq(1, length(Cols)+1)--Cols)} ||
677
680
                       {IdNo,Cols} <- ConstColsFamily],
691
694
    MS = [{match_specs, {'fun',L,{clauses,MSCls}}}],
692
695
 
693
696
    Cls = [{clause,L,[?A(Tag)],[],[V]} || 
694
 
              {Tag,V} <- append([J, S, T, C, N, CC, MS])]
 
697
              {Tag,V} <- lists:append([J, S, T, C, N, CC, MS])]
695
698
          ++ [{clause,L,[?V('_')],[],[?A(undefined)]}],
696
699
    {'fun', L, {clauses, Cls}}.
697
700
 
 
701
opt_column_constants(ColumnConstants0) ->
 
702
    [CC || {{IdNo,_Col},Const,_FilNs}=CC <- ColumnConstants0,
 
703
           (IdNo =/= ?TNO) or (length(Const) =:= 1)].
 
704
 
 
705
opt_constants(L, ColumnConstants) ->
 
706
    Ns = lists:usort([IdNo || {{IdNo,_Col},_Const,_FilNs} <- ColumnConstants]),
 
707
    [{clause,L,[?I(IdNo)],[],[column_fun(ColumnConstants, IdNo, L)]}
 
708
     || IdNo <- Ns]
 
709
     ++ [{clause,L,[?V('_')],[],[?A(no_column_fun)]}].
 
710
 
698
711
abstr(Term, Line) ->
699
712
    erl_parse:abstract(Term, Line).
700
713
 
744
757
                Cs2 = join_handle_constants(QId2, ExtraConstants),
745
758
                H1 = join_handle(AP1, L, Aux, Cs1),
746
759
                H2 = join_handle(AP2, L, Aux, Cs2),
 
760
                %% Op is not used.
747
761
                Join = {join,Op,QId1#qid.no,QId2#qid.no,H1,H2,Cs1,Cs2},
748
762
                G = {NQId=QId#qid{no = QId#qid.no + 1},
749
763
                     {QIVs,{{gen,{cons,L,P1,P2},Join,GV1},GoI,SI}}},
754
768
    Qs.
755
769
 
756
770
join_qnums(Cols) ->
757
 
    [{Q1, Q2} || [{Q1,_C1}, {Q2,_C2}] <- Cols].
 
771
    lists:usort([{Q1, Q2} || {[{Q1,_C1}, {Q2,_C2}], _Skip} <- Cols]).
758
772
 
759
773
%% Variables occurring only once are replaced by '_'.
760
774
anon_pattern(P) ->
761
 
    MoreThanOnce = lists:usort(occ_vars(P) -- vars(P)),
 
775
    MoreThanOnce = lists:usort(occ_vars(P) -- qlc:vars(P)),
762
776
    {AP, foo} = var_mapfold(fun({var, L, V}, A) ->
763
777
                                    case lists:member(V, MoreThanOnce) of
764
778
                                        true -> 
782
796
        _ ->
783
797
            G0 = [begin
784
798
                      Call = {call,0,{atom,0,element},[{integer,0,Col},O]},
785
 
                      list2op([{op,0,'=:=',Con,Call} || Con <- Cs], 'or')
 
799
                      list2op([{op,0,Op,Con,Call} || {Con,Op} <- Cs], 'or')
786
800
                  end || {Col,Cs} <- Constants],
787
801
            G = if G0 =:= [] -> G0; true -> [G0] end,
788
802
            CC1 = {clause,L,[AP],G,[{cons,L,O,closure({call,L,F,[F,C]},L)}]},
802
816
join_handle_constants(QId, ExtraConstants) ->
803
817
    IdNo = QId#qid.no,
804
818
    case lists:keysearch(IdNo, 1, ExtraConstants) of
805
 
        {value, {IdNo, Consts}} -> Consts;
806
 
        false -> []
 
819
        {value, {IdNo, ConstOps}} -> 
 
820
            ConstOps;
 
821
        false ->
 
822
            []
807
823
    end.
808
824
 
809
825
%%% By the term "imported variable" is meant a variable that is bound
825
841
                               lists:foldr
826
842
                                   (fun(F, A) -> {cons,0,{integer,0,F},A} 
827
843
                                    end, {nil,0}, Fils)]},
828
 
             Tag = case ordsets:to_list(vars(Vs1)) of
 
844
             Tag = case ordsets:to_list(qlc:vars(Vs1)) of
829
845
                       Imp when length(Imp) > 0, % imported vars
830
846
                                length(Vs0) > 1 ->
831
847
                           usort_needed;
850
866
%% -> [{EqType,Equal | Match}]
851
867
%% Equal = Match = TemplateColumns
852
868
%% EqType = abstract code for {_ | '==' | '=:='}
853
 
%% TemplateColumns = [{Column,Integers}]
854
 
%% Column = {QualifierNumber,ColumnNumber}}
 
869
%% TemplateColumns = [{Column,Integers}]    % integer is position in template
 
870
%% Column = {QualifierNumber,ColumnNumber}} % column is position in pattern
855
871
 
856
872
template_columns(Qs0, E0, AllIVs, Dependencies, State) ->
857
873
    E = expand_expr_records(pre_expand(E0), State),
869
885
            [{?A('=='), Equal}, {?A('=:='), Match}]
870
886
    end.
871
887
 
 
888
equal_columns2(Qualifiers, AllIVs, Dependencies, State) ->
 
889
    {JI, _Skip} = 
 
890
        join_info(Qualifiers, AllIVs, Dependencies, State,_JoinOp = '=='),
 
891
    JI.
 
892
 
 
893
eq_columns2(Qualifiers, AllIVs, Dependencies, State) ->
 
894
    {JI, _SKip} = 
 
895
        join_info(Qualifiers, AllIVs, Dependencies, State, _JoinOp = '=:='),
 
896
    JI.
 
897
 
872
898
template_cols(ColumnClasses) ->
873
 
    sort([{{IdNo,Col}, lists:usort(Cs)} ||
874
 
             Class <- ColumnClasses,
875
 
             {IdNo,Col} <- Class,
876
 
             IdNo =/= ?TNO,
877
 
             [] =/= (Cs = [C || {?TNO,C} <- Class])]).
 
899
    lists:sort([{{IdNo,Col}, lists:usort(Cs)} ||
 
900
                   Class <- ColumnClasses,
 
901
                   {IdNo,Col} <- Class,
 
902
                   IdNo =/= ?TNO,
 
903
                   [] =/= (Cs = [C || {?TNO,C} <- Class])]).
878
904
 
879
905
template_as_pattern(E) ->
880
906
    P = simple_template(E),
903
929
    {FilterData, _} = qual_data(Qualifiers),
904
930
    Used = sofs:relation([{QId,UV} ||
905
931
                             {QId,{fil,F}} <- FilterData,
906
 
                             UV <- vars(F)]),
 
932
                             UV <- qlc:vars(F)]),
907
933
    Depend = sofs:strict_relation(sofs:relative_product(Used, Intro)),
908
934
    G = sofs:family_to_digraph(sofs:relation_to_family(Depend)),
909
935
    Dep0 = [{V,digraph_utils:reachable_neighbours([V], G)} || 
994
1020
    L = 0,
995
1021
    {TemplVar, {match, L, E, TemplVar}}.
996
1022
 
997
 
%% Tries to find columns which are matched against constant values or
998
 
%% other columns. To that end unification is used. A frame is a list
999
 
%% of bindings created by unification.
 
1023
%% Tries to find columns which are compared or matched against
 
1024
%% constant values or other columns. To that end unification is used.
 
1025
%% A frame is a list of bindings created by unification.
1000
1026
%% Also tries to find the number of columns of patterns.
1001
1027
%% Note that the template is handled more or less as a pattern.
1002
 
%% -> {ColumnConstants, PatternSizes, ExtraConstants}
 
1028
%% -> {ColumnConstants, SizeInfo, ExtraConstants}
1003
1029
%% ColumnConstants = [{Column,[Constant],[FilterNo]}]
1004
 
%% PatternSizes = [{QualifierNumber,NumberOfColumns}]
 
1030
%% SizeInfo = [{QualifierNumber,NumberOfColumns}]
1005
1031
%% Column = {QualifierNumber,ColumnNumber}}
1006
1032
%% FilterNo is a filter that can be skipped at runtime provided constants
1007
1033
%% are looked up.
1008
 
%% ExtraConstants = [{GeneratorNumber,[{ColumnNumber,AbstractConstants}]}]
 
1034
%% ExtraConstants = 
 
1035
%%     [{GeneratorNumber,[{ColumnNumber,
 
1036
%%                         [{AbstractConstant,AbstractOperator}]}]}]
1009
1037
%% For every generator such that the unification binds value(s) to
1010
1038
%% some column(s), extra constants are returned. These constants are
1011
1039
%% the results of the unification, and do not occur in the pattern of
1016
1044
    {FilterData, GeneratorData} = qual_data(Qualifiers),
1017
1045
    {Filter, Anon1, Imported} = 
1018
1046
        filter_info(FilterData, AllIVs, Dependencies, State),
1019
 
    BindFun = fun(Value, Op) -> is_bindable(Value, Op, Imported) end,
 
1047
    PatBindFun = fun(_Op, Value) -> is_bindable(Value) end,
1020
1048
    {PatternFrame, PatternVars} = 
1021
 
        pattern_frame(GeneratorData, BindFun, Anon1, State),
1022
 
    SkipFun = fun(Fs) -> Fs end,
 
1049
        pattern_frame(GeneratorData, PatBindFun, Anon1, State),
1023
1050
    PatternFrames = frame2frames(PatternFrame),
1024
 
    Fs = filter(Filter, PatternFrames, BindFun, SkipFun, State),
1025
 
 
1026
 
    Selector = fun(Value) -> is_const(Value, Imported) end,
1027
 
    ColumnConstants0 = [frames_to_columns(Fs, PV, QId, Selector) || 
1028
 
                           {QId,PV} <- PatternVars],
1029
 
    ColumnConstants1 = flatten(ColumnConstants0),
1030
 
 
 
1051
    FilterFun = 
 
1052
        fun(BindFun) -> 
 
1053
              filter(Filter, PatternFrames, BindFun, State, Imported)
 
1054
        end,
 
1055
    SzFs = FilterFun(PatBindFun),
 
1056
 
 
1057
    SizeInfo = pattern_sizes(PatternVars, SzFs),
 
1058
    SelectorFun = const_selector(Imported),
1031
1059
    PatternConstants = 
1032
 
        flatten([frames_to_columns(PatternFrames, PV, QId, Selector) || 
1033
 
                    {QId,PV} <- PatternVars]),
1034
 
    ExtraConstants = 
1035
 
      family_list([{GId, {Col,Vals}} ||
1036
 
                      {{GId,Col},Vals} <- ColumnConstants1--PatternConstants,
1037
 
                      GId =/= ?TNO]),
1038
 
 
1039
 
    ColumnConstants = lu_skip(ColumnConstants1, FilterData, BindFun, Selector,
1040
 
                              PatternFrame, PatternVars, Dependencies, State),
1041
 
    PatternSizes = [{QId#qid.no, Size} || 
1042
 
                       {QId,PV} <- PatternVars,
1043
 
                       undefined =/= (Size = pattern_size(Fs, PV))],
1044
 
    {ColumnConstants, PatternSizes, ExtraConstants}.
 
1060
        lists:flatten(frames_to_columns(PatternFrames, PatternVars,
 
1061
                                        deref_pattern(Imported),
 
1062
                                        SelectorFun, Imported,
 
1063
                                        '=:=')),
 
1064
 
 
1065
    {EqColumnConstants, _EqExtraConsts} = 
 
1066
        constants(FilterFun, PatternVars, PatternConstants, PatternFrame,
 
1067
                  FilterData, Dependencies, _LookupOp1 = '=:=', 
 
1068
                  Imported, State),
 
1069
    {EqualColumnConstants, EqualExtraConsts} = 
 
1070
        constants(FilterFun, PatternVars, PatternConstants, PatternFrame,
 
1071
                  FilterData, Dependencies, _LookupOp2 = '==', 
 
1072
                  Imported, State),
 
1073
 
 
1074
    %% Use compared extra constants only because:
 
1075
    %% - merge join compares terms;
 
1076
    %% - the constants from the matching unification is a subset of the
 
1077
    %%   constants from the comparing unification.
 
1078
    %% Using constants from the matching unification would make it
 
1079
    %% possible to skip some (more) objects when joining.
 
1080
    ExtraCon1 = 
 
1081
        [{{GId,Col},{Val,Op}} ||
 
1082
            {Consts,Op} <- [{EqualExtraConsts,'=='}],
 
1083
            {{GId,Col},Val} <- Consts],
 
1084
    ExtraConstants = 
 
1085
      family_list([{GId, {Col,ValOps}} ||
 
1086
                      {{GId,Col},ValOps} <- family_list(ExtraCon1)]),
 
1087
    {EqColumnConstants, EqualColumnConstants, ExtraConstants, SizeInfo}.
 
1088
 
 
1089
constants(FilterFun, PatternVars, PatternConstants, PatternFrame, 
 
1090
          FilterData, Dependencies, LookupOp, Imported, State) ->
 
1091
    BindFun = fun(_Op, Value) -> is_bindable(Value) end,
 
1092
    Fs = FilterFun(BindFun),
 
1093
    SelectorFun = const_selector(Imported),
 
1094
    ColumnConstants0 = frames_to_columns(Fs, PatternVars, 
 
1095
                                         deref_lookup(Imported, LookupOp),
 
1096
                                         SelectorFun, Imported, LookupOp),
 
1097
    ColumnConstants1 = lists:flatten(ColumnConstants0),
 
1098
    ExtraConstants = 
 
1099
       [{{GId,Col},Val} ||
 
1100
           {{GId,Col},Vals} <- ColumnConstants1 -- PatternConstants,
 
1101
           GId =/= ?TNO,
 
1102
           Val <- Vals],
 
1103
    ColumnConstants = lu_skip(ColumnConstants1, FilterData, PatternFrame,
 
1104
                              PatternVars, Dependencies, State,
 
1105
                              Imported, LookupOp),
 
1106
    {ColumnConstants, ExtraConstants}.
 
1107
 
 
1108
%%% ** Comparing Terms **
 
1109
%%%  When comparing the key against a term where some integer (or float
 
1110
%%% comparing equal to an integer) occurs, one has to be careful if the
 
1111
%%% table matches keys. One way would be to look up the term both with
 
1112
%%% the integer and with the float comparing equal to the integer--then
 
1113
%%% all objects that could possibly be answers are filtered (with
 
1114
%%% reasonable assumptions). But if integers occur several times in the
 
1115
%%% term all combinations have to be looked up, and that could be just
 
1116
%%% too many.
 
1117
%%%  If imported variables occur in the term one could assume at compile
 
1118
%%% time that they are not integers and check that assumption at
 
1119
%%% runtime. However, this would probably be bad design since some keys
 
1120
%%% can be looked up, but others cannot.
 
1121
%%%  However, the current implementation is simple: do not bind a
 
1122
%%% variable to a term if imported variables or integers occur in the
 
1123
%%% term.
 
1124
 
 
1125
deref_lookup(Imported, '==') ->
 
1126
    %% Comparing table. Every value can be looked up.
 
1127
    fun(PV, F) -> deref_values(PV, F, Imported) end;
 
1128
deref_lookup(Imported, '=:=') ->
 
1129
    %% Matching table. Ignore comparisons unless the value is free of
 
1130
    %% integers. See also Comparing Terms.
 
1131
    BFun = fun(DV, Op) ->
 
1132
                   Op =:= '=:=' orelse free_of_integers(DV, Imported)
 
1133
           end,
 
1134
    fun(PV, F) -> deref_values(PV, F, BFun, Imported) end.
1045
1135
 
1046
1136
%% Augment ColConstants with filters that do not need to be run
1047
1137
%% provided that constants are looked up.
1048
 
lu_skip(ColConstants, FilterData, BindFun, Selector, PatternFrame, 
1049
 
        PatternVars, Dependencies, State) ->
 
1138
%% Does not find all filters that can be removed.
 
1139
lu_skip(ColConstants, FilterData, PatternFrame, PatternVars, 
 
1140
        Dependencies, State, Imported, LookupOp) ->
1050
1141
    %% If there is a test that does not compare or match, then the
1051
1142
    %% filter cannot be skipped.
1052
 
    FailSelector = fun(_Value) -> true end,
 
1143
    FailSelector = fun(_Frame) -> fun(Value) -> {yes, Value} end end,
1053
1144
    %% In runtime, constants are looked up and matched against a pattern 
1054
1145
    %% (the pattern acts like a filter), then the filters are run.
1055
1146
    PatternFrames = frame2frames(PatternFrame),
1056
1147
    PatternColumns = 
1057
 
        flatten([frames_to_columns(PatternFrames, PV, QId, FailSelector) ||
1058
 
                    {QId,PV} <- PatternVars]),
 
1148
        lists:flatten(frames_to_columns(PatternFrames, PatternVars,
 
1149
                                        deref_pattern(Imported), FailSelector,
 
1150
                                        Imported, LookupOp)),
 
1151
 
1059
1152
    %% Note: ColFil can contain filters for columns that cannot be
1060
1153
    %% looked up. Such (possibly bogus) elements are however not used.
1061
1154
    %% Note: one filter at a time is tested; only the pattern is
1063
1156
    %% would be advantageously to assume some filter(s) occurring
1064
1157
    %% before the filter had been run as well 
1065
1158
    %% (an example: {{X,Y}} <- LE, X =:= 1, Y =:= a).
 
1159
    BindFun = fun(_Op, Value) -> is_bindable(Value) end,
1066
1160
    ColFil = [{Column, FId#qid.no} ||
1067
1161
                 {FId,{fil,Fil}} <- 
1068
1162
                     filter_list(FilterData, Dependencies, State),
1069
 
                 [] =/= (SFs = safe_filter(set_line(Fil, 0), 
1070
 
                                           PatternFrames, BindFun, State)),
 
1163
                 [] =/= (SFs = safe_filter(set_line(Fil, 0), PatternFrames,
 
1164
                                           BindFun, State, Imported)),
1071
1165
                 {GId,PV} <- PatternVars,
1072
 
                 GId#qid.lcid =:= FId#qid.lcid,
1073
 
                 [] =/= (F = frames_to_columns(SFs, PV, GId, Selector)),
 
1166
                 [] =/= 
 
1167
                    (Cols = hd(frames_to_columns(SFs, [{GId, PV}],
 
1168
                                                 deref_lu_skip(LookupOp,
 
1169
                                                               Imported),
 
1170
                                                 const_selector(Imported),
 
1171
                                                 Imported, LookupOp))),
1074
1172
                 %% The filter must not test more than one column (unless the
1075
1173
                 %% pattern has already done the test):
1076
 
                 length(D = F -- PatternColumns) =:= 1,
 
1174
                 %% Note: if the pattern and the filter test the same
 
1175
                 %% column, the filter will not be skipped.
 
1176
                 %% (an example: {X=1} <- ..., X =:= 1).
 
1177
                 length(D = Cols -- PatternColumns) =:= 1,
1077
1178
                 Frame <- SFs,
1078
1179
                 begin
1079
1180
                     %% The column is compared/matched against a constant.
1081
1182
                     %% the filter can be replaced by the lookup of
1082
1183
                     %% the constant.
1083
1184
                     [{{_,Col} = Column, Constants}] = D,
1084
 
                     Value = column_i(Frame, PV, Col),
1085
 
                     PVar = {var, 0, PV},
1086
 
                     Call = {call,0,{atom,0,element},[{integer,0,Col},PVar]},
1087
 
                     {NV, F1} = element_calls(Call, PatternFrame, BindFun),
1088
 
                     F2 = unify('=:=', NV, Value, F1, BindFun),
 
1185
                     {VarI, FrameI} = unify_column(Frame, PV, Col, BindFun,
 
1186
                                                   Imported),
 
1187
                     VarValues = deref_skip(VarI, FrameI, LookupOp, Imported),
 
1188
 
 
1189
                     {NV, F1} = unify_column(PatternFrame, PV, Col, BindFun,
 
1190
                                             Imported),
 
1191
                     F2 = unify_var_bindings(VarValues, '=:=', NV, F1, 
 
1192
                                             BindFun, Imported, false),
1089
1193
                     %% F2: the pattern has been matched and the
1090
1194
                     %% constant has been looked up. If Frame has no
1091
1195
                     %% more bindings than F2 (modulo unique
1101
1205
                             false -> [];
1102
1206
                             {value, {Column,LUCs}} -> LUCs
1103
1207
                         end,
1104
 
                     bindings_is_subset(Frame, F2)
1105
 
                     and (Constants -- LookedUpConstants =:= [])
 
1208
                     %% Don't try to handle filters that compare several
 
1209
                     %% values equal. See also frames_to_columns().
 
1210
                     length(VarValues) =< 1 andalso
 
1211
                     (Constants -- LookedUpConstants =:= []) andalso
 
1212
                     bindings_is_subset(Frame, F2, Imported)
1106
1213
                 end],
1107
1214
    ColFils = family_list(ColFil),
1108
 
    %% The atom 'all' means that all filters are covered by the lookup.
 
1215
    %% The skip tag 'all' means that all filters are covered by the lookup.
1109
1216
    %% It does not imply that there is only one generator as is the case
1110
1217
    %% for match specifications (see match_spec_quals above).
1111
 
    [{Col,Constants,case keysearch(Col, 1, ColFils) of
1112
 
                        {value, {Col, FilL}} -> 
1113
 
                            Tag = if
1114
 
                                      length(FilterData) =:= length(FilL) ->
1115
 
                                          all;
1116
 
                                      true ->
1117
 
                                          some
1118
 
                                  end,
1119
 
                            {Tag, FilL};
1120
 
                        false -> 
1121
 
                            {some,[]}
1122
 
                    end} || {Col,Constants} <- ColConstants].
 
1218
    [{Col, Constants, skip_tag(Col, ColFils, FilterData)} ||
 
1219
        {Col,Constants} <- ColConstants].
 
1220
 
 
1221
deref_skip(E, F, _LookupOp, Imported) ->
 
1222
    deref(E, F, Imported).
 
1223
 
 
1224
deref_lu_skip('==', Imported) ->
 
1225
    %% Comparing table. Cannot skip filters that match integers.
 
1226
    BFun = fun(DV, Op) ->
 
1227
                   Op =:= '==' orelse free_of_integers(DV, Imported)
 
1228
           end,
 
1229
    fun(PV, F) -> deref_values(PV, F, BFun, Imported) end;
 
1230
deref_lu_skip('=:=', Imported) ->
 
1231
    %% Matching table. Skip filters regardless of operator.
 
1232
    fun(PV, F) -> deref_values(PV, F, Imported) end.
1123
1233
 
1124
1234
equal_columns(Qualifiers, AllIVs, Dependencies, State) ->
1125
 
    Cs = equal_columns2(Qualifiers, AllIVs, Dependencies, State),
1126
 
    join_gens(Cs).
 
1235
    {Cs, Skip} = 
 
1236
        join_info(Qualifiers, AllIVs, Dependencies, State, _JoinOp = '=='),
 
1237
    join_gens(Cs, Qualifiers, Skip).
1127
1238
 
1128
1239
eq_columns(Qualifiers, AllIVs, Dependencies, State) ->
1129
 
    Cs = eq_columns2(Qualifiers, AllIVs, Dependencies, State),
1130
 
    join_gens(Cs).
 
1240
    {Cs, Skip} = 
 
1241
        join_info(Qualifiers, AllIVs, Dependencies, State, _JoinOp = '=:='),
 
1242
    join_gens(Cs, Qualifiers, Skip).
1131
1243
 
1132
 
%% Group columns of the same generator together.
1133
 
%% -> {TwoGen, ManyGens}
1134
 
join_gens(Cs0) ->
 
1244
%% -> {TwoGens, ManyGens}
 
1245
join_gens(Cs0, Qs, Skip) ->
1135
1246
    Cs = [family_list(C) || C <- Cs0],
1136
 
    {[C || C <- Cs, length(C) =:= 2],
1137
 
     [C || C <- Cs, length(C) > 2]}.
1138
 
 
1139
 
%% Tries to find columns (possibly in the same table) that are
1140
 
%% matched (=:=/2) or compared (==/2). Unification again.
1141
 
%% -> [[{QualifierNumber,ColumnNumber}]] % Eq.classes.
1142
 
 
1143
 
equal_columns2(Qualifiers, AllIVs, Dependencies, State) ->
1144
 
    BindFun = fun(Imp) -> fun(V, Op) -> is_no_const(V, Op, Imp) end end,
1145
 
    join_info(Qualifiers, AllIVs, Dependencies, BindFun, State).
1146
 
 
1147
 
%% Tries to find columns (possibly in the same table) that are matched
1148
 
%% (=:=/2).
1149
 
%% -> [[{QualifierNumber,ColumnNumber}]] % Eq.classes.
1150
 
 
1151
 
eq_columns2(Qualifiers, AllIVs, Dependencies, State) ->
1152
 
    BindFun = fun(Imp) -> fun(V, Op) -> is_match_no_const(V, Op, Imp) end end,
1153
 
    join_info(Qualifiers, AllIVs, Dependencies, BindFun, State).
1154
 
 
1155
 
join_info(Qualifiers, AllIVs, Dependencies, BindFun0, State) ->
 
1247
    {FD, _GeneratorData} = qual_data(Qs),
 
1248
    {join_gens2(lists:filter(fun(C) -> length(C) =:= 2 end, Cs), FD, Skip),
 
1249
     join_gens2(lists:filter(fun(C) -> length(C) > 2 end, Cs), FD, Skip)}.
 
1250
 
 
1251
join_gens2(Cs0, FilterData, Skip) ->
 
1252
    [{J, skip_tag(case lists:keysearch(J, 1, Skip) of
 
1253
                      {value, {J,FilL}} ->
 
1254
                          FilL;
 
1255
                      false ->
 
1256
                          []
 
1257
                  end, FilterData)} ||
 
1258
        J <- lists:append([qlc:all_selections(C) || C <- Cs0])].
 
1259
 
 
1260
skip_tag(FilList, FilterData) ->
 
1261
    {if
 
1262
         length(FilterData) =:= length(FilList) ->
 
1263
             all;
 
1264
         true ->
 
1265
             some
 
1266
     end, FilList}.
 
1267
 
 
1268
skip_tag(Col, ColFils, FilterData) ->
 
1269
    case lists:keysearch(Col, 1, ColFils) of
 
1270
        {value, {Col, FilL}} -> 
 
1271
            Tag = if
 
1272
                      length(FilterData) =:= length(FilL) ->
 
1273
                          all;
 
1274
                      true ->
 
1275
                          some
 
1276
                  end,
 
1277
            {Tag, FilL};
 
1278
        false -> 
 
1279
            {some,[]}
 
1280
    end.
 
1281
 
 
1282
%% Tries to find columns (possibly in the same table) that are equal.
 
1283
%% If LookupOp is '=:=' then "equal" means that the columns are matched;
 
1284
%% if LookupOp is '==' then "equal" means that the columns are matched or
 
1285
%% compared.
 
1286
%% -> [[{QualifierNumber,ColumnNumber}]] % Eq.classes.
 
1287
join_info(Qualifiers, AllIVs, Dependencies, State, JoinOp) ->
1156
1288
    {FilterData, GeneratorData} = qual_data(Qualifiers),
1157
1289
    {Filter, Anon1, Imported} = 
1158
1290
        filter_info(FilterData, AllIVs, Dependencies, State),
1159
 
    BindFun = BindFun0(Imported),
 
1291
    BindFun = fun(_Op, V) -> bind_no_const(V, Imported) end,
1160
1292
    {PatternFrame, PatternVars} = 
1161
1293
        pattern_frame(GeneratorData, BindFun, Anon1, State),
1162
1294
    PatternFrames = frame2frames(PatternFrame),
1163
 
    SkipFun = fun(Fs) -> Fs end,
1164
 
    Fs = filter(Filter, PatternFrames, BindFun, SkipFun, State),
1165
 
    Selector = fun(Value) -> not is_const(Value, Imported) end,
1166
 
    join_classes(fun(PV, QId) -> frames_to_columns(Fs, PV, QId, Selector) 
1167
 
                 end, PatternVars).
1168
 
 
1169
 
join_classes(FramesFun, PatternVars) ->
1170
 
    Cols0 = [FramesFun(PV, QId) || {QId,PV} <- PatternVars],
1171
 
    ColVar = sofs:relation(append(Cols0)),
 
1295
    Fs = filter(Filter, PatternFrames, BindFun, State, Imported),
 
1296
    SelectorFun = no_const_selector(Imported),
 
1297
    Cols = frames_to_columns(Fs, PatternVars,
 
1298
                             fun(PV1, F) -> deref_join(PV1, F, JoinOp) end,
 
1299
                             SelectorFun, Imported, '=:='),
 
1300
    JC = join_classes(Cols),
 
1301
    Skip = join_skip(JC, FilterData, PatternFrame,
 
1302
                     PatternVars, Dependencies, State, Imported, JoinOp),
 
1303
    {JC, Skip}.
 
1304
 
 
1305
deref_join(E, Frame, '==') ->
 
1306
    deref_values(E, Frame, _Imp = []);
 
1307
deref_join(E, Frame, '=:=') ->
 
1308
    %% Matching table. It is possible that some objects read from the
 
1309
    %% other table (the one with the objects to look up) contain
 
1310
    %% integers. By making all variables imported it is ensured that
 
1311
    %% comparisons are kept. See also Comparing Terms.
 
1312
    deref_values(E, Frame, fun(_DV, Op) -> Op =:= '=:=' end, all).
 
1313
 
 
1314
join_classes(Cols0) ->
 
1315
    ColVar = sofs:relation(lists:append(Cols0)),
1172
1316
    Cols = sofs:partition(2, ColVar),
1173
1317
    [[C || {C,_} <- Cs] || Cs <- sofs:to_external(Cols), length(Cs) > 1].
1174
1318
 
 
1319
join_skip(JoinClasses, FilterData, PatternFrame, PatternVars, Dependencies,
 
1320
          State, Imported, JoinOp) ->
 
1321
    PatternFrames = frame2frames(PatternFrame),
 
1322
    ColFil = [{JoinClass,FId#qid.no} ||
 
1323
                 [{Q1,C1}, {Q2,C2}]=JoinClass <- JoinClasses,
 
1324
                 {GId1, PV1} <- PatternVars,
 
1325
                 GId1#qid.no =:= Q1,
 
1326
                 {GId2, PV2} <- PatternVars,
 
1327
                 GId2#qid.no =:= Q2,
 
1328
 
 
1329
                 %% Select a filter that depends on the two generators:
 
1330
                 {FId,{fil,Fil}} <- 
 
1331
                     filter_list(FilterData, Dependencies, State),
 
1332
                 {value,{_,GIds}} <- 
 
1333
                     [lists:keysearch(FId, 1, Dependencies)],
 
1334
                 GIds =:= lists:sort([GId1,GId2]),
 
1335
 
 
1336
                 begin
 
1337
                     %% Do what the join does: 
 
1338
                     %% element(C1, G1) JoinOp element(C2, G2).
 
1339
                     %% As for lu_skip: sometimes it would be
 
1340
                     %% advantageously to assume some filter(s)
 
1341
                     %% occurring before the join filter had been run
 
1342
                     %% as well.
 
1343
                     BindFun = fun(_Op, V) -> is_bindable(V) end,
 
1344
                     {V1, JF1} = 
 
1345
                       unify_column(PatternFrame, PV1, C1, BindFun, Imported),
 
1346
                     {V2, JF2} = 
 
1347
                         unify_column(JF1, PV2, C2, BindFun, Imported),
 
1348
                     JF = unify(JoinOp, V1, V2, JF2, BindFun, Imported),
 
1349
 
 
1350
                     %% "Run" the filter:
 
1351
                     SFs = safe_filter(set_line(Fil, 0), PatternFrames,
 
1352
                                       BindFun, State, Imported),
 
1353
                     JImp = qlc:vars([SFs, JF]), % kludge
 
1354
                     lists:all(fun(Frame) -> 
 
1355
                                       bindings_is_subset(Frame, JF, JImp)
 
1356
                               end, SFs) andalso SFs =/= []
 
1357
                 end],
 
1358
    family_list(ColFil).
 
1359
 
1175
1360
filter_info(FilterData, AllIVs, Dependencies, State) ->
1176
1361
    FilterList = filter_list(FilterData, Dependencies, State),
1177
1362
    Filter0 = set_line(filters_as_one(FilterList), 0),
1178
1363
    Anon0 = 0,
1179
1364
    {Filter, Anon1} = anon_var(Filter0, Anon0),
1180
 
    Imported = ordsets:subtract(vars(Filter), % anonymous too
1181
 
                                sort(AllIVs)), 
 
1365
    Imported = ordsets:subtract(qlc:vars(Filter), % anonymous too
 
1366
                                ordsets:from_list(AllIVs)), 
1182
1367
    {Filter, Anon1, Imported}.
1183
1368
 
1184
1369
%% Selects the guard filters. Other filters than guard filters are
1200
1385
sel_gf([{#qid{no = N}=Id,{fil,F}}=Fil | FData], N, Deps, RDs, Gens, Gens1) ->
1201
1386
    case erl_lint:is_guard_test(F, RDs) of
1202
1387
        true ->
1203
 
            {value, {Id,GIds}} = keysearch(Id, 1, Deps),
 
1388
            {value, {Id,GIds}} = lists:keysearch(Id, 1, Deps),
1204
1389
            case length(GIds) =< 1 of
1205
1390
                true ->
1206
1391
                    case generators_in_scope(GIds, Gens1) of
1236
1421
                    end, {Frame0, Anon1, []}, GeneratorData),
1237
1422
    {PatternFrame, PatternVars}.
1238
1423
              
1239
 
is_match_no_const(Value, Op, Imported) ->
1240
 
    (Op =/= '==') andalso is_no_const(Value, Op, Imported).
1241
 
 
1242
 
is_no_const(Value, Op, Imported) ->
1243
 
    is_bindable(Value, Op, Imported) andalso not is_const(Value, Imported).
 
1424
const_selector(Imported) ->
 
1425
    selector(Imported, fun is_const/2).
 
1426
 
 
1427
no_const_selector(Imported) ->
 
1428
    selector(Imported, fun(V, I) -> not is_const(V, I) end).
 
1429
 
 
1430
selector(Imported, TestFun) ->
 
1431
    fun(_Frame) ->
 
1432
            fun(Value) -> 
 
1433
                    case TestFun(Value, Imported) of
 
1434
                        true ->
 
1435
                            {yes, Value};
 
1436
                        false ->
 
1437
                            no
 
1438
                    end
 
1439
            end
 
1440
    end.
 
1441
 
 
1442
bind_no_const(Value, Imported) ->
 
1443
    case is_const(Value, Imported) of
 
1444
        true ->
 
1445
            false;
 
1446
        false ->
 
1447
            is_bindable(Value)
 
1448
    end.
1244
1449
 
1245
1450
%% Tuple tails are variables, never constants.
1246
1451
is_const(Value, Imported) ->
1247
1452
    %% is_bindable() has checked that E is normalisable. 
1248
 
    [] =:= ordsets:to_list(ordsets:subtract(vars(Value), Imported)).
1249
 
 
1250
 
%% If there is an integer (or float comparing equal to an integer) in
1251
 
%% the value one has to be careful. One way would be to look up the
1252
 
%% value both with the integer and with the float comparing equal to
1253
 
%% the integer - then all objects that could possibly be answers are
1254
 
%% filtered (with reasonable assumptions). But if integers occur
1255
 
%% several times in the value all combinations have to be looked up,
1256
 
%% and that could be just too many.
1257
 
%%
1258
 
%% If there are imported variables in the value one could assume at
1259
 
%% compile time that they are not integers and check that assumption
1260
 
%% at runtime. However, this implementation is much simpler: do not
1261
 
%% bind the variable to the value if imported variables or integers
1262
 
%% occur in the value. This will probably do.
1263
 
 
1264
 
is_bindable(Value, Op, Imp) ->
 
1453
    [] =:= ordsets:to_list(ordsets:subtract(qlc:vars(Value), Imported)).
 
1454
 
 
1455
is_bindable(Value) ->
1265
1456
    case normalise(Value) of
1266
 
        {ok, NValue} when Op =:= '==' ->
1267
 
            case {ordsets:to_list(ordsets:intersection(vars(Value), Imp)), 
1268
 
                  has_integer(NValue)} of
1269
 
                {[], false} ->
1270
 
                    true;
1271
 
                _ ->
1272
 
                    false
1273
 
            end;
1274
 
        {ok, _} when Op =:= '=:=' ->
 
1457
        {ok, _C} ->
1275
1458
            true;
1276
1459
        not_ok ->
1277
1460
            false
1286
1469
    P2 = set_line(P1, 0),
1287
1470
    {P3, AnonN} = anon_var(P2, AnonI),
1288
1471
    {P4, F1} = match_in_pattern(tuple2cons(P3), Frame0, BindFun),
1289
 
    {P, F2} = element_calls(P4, F1, BindFun), % kludge for templates
 
1472
    {P, F2} = element_calls(P4, F1, BindFun, _Imp=[]), % kludge for templates
1290
1473
    {var, _, PatternVar} = UniqueVar = unique_var(),
1291
 
    F = unify('=:=', UniqueVar, P, F2, BindFun),
 
1474
    F = unify('=:=', UniqueVar, P, F2, BindFun, _Imported = []),
1292
1475
    {F, AnonN, PatternVar}.
1293
1476
 
1294
1477
frame2frames(failed) ->
1300
1483
    {E1, F1} = match_in_pattern(E10, F0, BF),
1301
1484
    {E2, F} = match_in_pattern(E20, F1, BF),
1302
1485
    %% This is for join: chosing a constant could "hide" a variable.
1303
 
    E = case BF(E1, '=:=') of
 
1486
    E = case BF('=:=', E1) of
1304
1487
            true -> E1;
1305
1488
            false -> E2
1306
1489
        end,
1307
 
    {E, unify('=:=', E1, E2, F, BF)};
 
1490
    {E, unify('=:=', E1, E2, F, BF, _Imported = [])};
1308
1491
match_in_pattern(T, F0, BF) when is_tuple(T) ->
1309
1492
    {L, F} = match_in_pattern(tuple_to_list(T), F0, BF),
1310
1493
    {list_to_tuple(L), F};
1326
1509
set_line(T, L) ->
1327
1510
    map_lines(fun(_L) -> L end, T).
1328
1511
 
1329
 
-record(fstate, {state, bind_fun, skip_fun}).
 
1512
-record(fstate, {state, bind_fun, imported}).
1330
1513
 
1331
 
filter(_E, []=Frames0, _BF, _SF, _State) ->
 
1514
filter(_E, []=Frames0, _BF, _State, _Imported) ->
1332
1515
    Frames0;
1333
 
filter(E0, Frames0, BF, SF, State) ->
 
1516
filter(E0, Frames0, BF, State, Imported) ->
1334
1517
    E = pre_expand(E0),
1335
 
    FState = #fstate{state = State, bind_fun = BF, skip_fun = SF},
 
1518
    FState = #fstate{state = State, bind_fun = BF, imported = Imported},
1336
1519
    filter1(E, Frames0, FState).
1337
1520
 
1338
 
%% One frame for each path through the and/or formula.
 
1521
%% One frame for each path through the and/or expression.
1339
1522
%%
1340
1523
%% "A xor B" is equal to "(A and not B) or (not A and B)". 
1341
1524
%% Ignoring "not B" and "not A" this is the same as "A or B"; 
1360
1543
%% all (except in generator patterns).
1361
1544
 
1362
1545
filter1({op, _, Op, L0, R0}, Fs, FS) when Op =:= '=:='; Op =:= '==' ->
1363
 
    #fstate{state = S, bind_fun = BF} = FS,
 
1546
    #fstate{state = S, bind_fun = BF, imported = Imported} = FS,
1364
1547
    %% In the transformed code there are no records in lookup values
1365
1548
    %% because records are expanded away in prep_expr.
1366
 
    flatmap(fun(F0) ->
1367
 
                    {L, F1} = prep_expr(L0, F0, S, BF),
1368
 
                    {R, F2} = prep_expr(R0, F1, S, BF),
1369
 
                    case unify(Op, L, R, F2, BF) of
1370
 
                        failed -> [];
1371
 
                        F -> [F]
1372
 
                    end
1373
 
            end, Fs);
 
1549
    lists:flatmap(fun(F0) ->
 
1550
                          {L, F1} = prep_expr(L0, F0, S, BF, Imported),
 
1551
                          {R, F2} = prep_expr(R0, F1, S, BF, Imported),
 
1552
                          case unify(Op, L, R, F2, BF, Imported) of
 
1553
                              failed -> [];
 
1554
                              F -> [F]
 
1555
                          end
 
1556
                  end, Fs);
1374
1557
filter1({op, _, Op, L, R}, Fs, FS) when Op =:= 'and'; Op =:= 'andalso' ->
1375
1558
    filter1(R, filter1(L, Fs, FS), FS);
1376
1559
filter1({op, _, Op, L, R}, Fs, FS) when Op =:= 'or'; 
1388
1571
filter1({call,L,{remote,L1,{atom,_,erlang}=M,{atom,L2,is_record}},[T,R,_Sz]},
1389
1572
        Fs, FS) ->
1390
1573
    filter1({call,L,{remote,L1,M,{atom,L2,is_record}},[T,R]}, Fs, FS);
1391
 
filter1(_E, Fs, FS) ->
1392
 
    (FS#fstate.skip_fun)(Fs).
 
1574
filter1(_E, Fs, _FS) ->
 
1575
    Fs.
1393
1576
 
1394
1577
%% filter() tries to extract as much information about constant
1395
1578
%% columns as possible. It ignores those parts of the filter that are
1396
1579
%% uninteresting. safe_filter() on the other hand ensures that the
1397
 
%% bindings returned capture _all_ aspects of the filter.
1398
 
safe_filter(_E, []=Frames0, _BF, _State) ->
 
1580
%% bindings returned capture _all_ aspects of the filter (wrt BF).
 
1581
safe_filter(_E, []=Frames0, _BF, _State, _Imported) ->
1399
1582
    Frames0;
1400
 
safe_filter(E0, Frames0, BF, State) ->
 
1583
safe_filter(E0, Frames0, BF, State, Imported) ->
1401
1584
    E = pre_expand(E0),
1402
 
    FailFun = fun(_Fs) -> [] end,
1403
 
    FState = #fstate{state = State, bind_fun = BF, skip_fun = FailFun},
 
1585
    FState = #fstate{state = State, bind_fun = BF, imported = Imported},
1404
1586
    safe_filter1(E, Frames0, FState).
1405
1587
 
1406
1588
safe_filter1({op, _, Op, L0, R0}, Fs, FS) when Op =:= '=:='; Op =:= '==' ->
1407
 
    #fstate{state = S, bind_fun = BF} = FS,
1408
 
    flatmap(fun(F0) ->
1409
 
                    {L, F1} = prep_expr(L0, F0, S, BF),
1410
 
                    {R, F2} = prep_expr(R0, F1, S, BF),
1411
 
                    case safe_unify(Op, L, R, F2, BF) of
1412
 
                        failed -> [];
1413
 
                        F -> [F]
1414
 
                    end
1415
 
            end, Fs);
 
1589
    #fstate{state = S, bind_fun = BF, imported = Imported} = FS,
 
1590
    lists:flatmap(fun(F0) ->
 
1591
                          {L, F1} = prep_expr(L0, F0, S, BF, Imported),
 
1592
                          {R, F2} = prep_expr(R0, F1, S, BF, Imported),
 
1593
                          case safe_unify(Op, L, R, F2, BF, Imported) of
 
1594
                              failed -> [];
 
1595
                              F -> [F]
 
1596
                          end
 
1597
                  end, Fs);
1416
1598
safe_filter1({op, _, Op, L, R}, Fs, FS) when Op =:= 'and'; Op =:= 'andalso' ->
1417
1599
    safe_filter1(R, safe_filter1(L, Fs, FS), FS);
1418
1600
safe_filter1({op, _, Op, L, R}, Fs, FS) when Op =:= 'or'; Op =:= 'orelse' ->
1419
1601
    safe_filter1(L, Fs, FS) ++ safe_filter1(R, Fs, FS);
1420
 
safe_filter1({atom,_,Atom}, _Fs, _FS) when Atom =/= true ->
1421
 
    [];
1422
 
safe_filter1(_E, Fs, FS) ->
1423
 
    (FS#fstate.skip_fun)(Fs).
 
1602
safe_filter1({atom,_,true}, Fs, _FS) ->
 
1603
    Fs;
 
1604
safe_filter1(_E, _Fs, _FS) ->
 
1605
    [].
1424
1606
 
1425
1607
%% Substitutions: 
1426
1608
%% M:F() for {M,F}(); erlang:F() for F(); is_record() for record().
1437
1619
pre_expand(T) ->
1438
1620
    T.
1439
1621
 
1440
 
column_i(Frame, PatternVar, I) ->
1441
 
    {cons_tuple, Cs} = deref({var, 0, PatternVar}, Frame),
1442
 
    column_i_2(Cs, 1, I).
1443
 
 
1444
 
column_i_2({cons,_,V,_}, I, I) ->
1445
 
    V;
1446
 
column_i_2({cons,_,_,E}, I, N) ->
1447
 
    column_i_2(E, I+1, N).
1448
 
 
1449
 
pattern_size(Fs, PatternVar) ->
1450
 
    Szs = [case deref({var, 0, PatternVar}, F) of
1451
 
               {cons_tuple, Cs} -> pattern_sz(Cs, 0);
1452
 
               _ -> undefined
1453
 
           end || F <- Fs],
1454
 
    case lists:usort(Szs) of
1455
 
        [Sz] when Sz >= 0 -> Sz;
1456
 
        _  -> undefined
1457
 
    end.
1458
 
 
1459
 
pattern_sz({cons,_,_C,E}, Col) ->
1460
 
    pattern_sz(E, Col+1);
1461
 
pattern_sz({nil,_}, Sz) ->
1462
 
    Sz;
1463
 
pattern_sz(_, _Sz) ->
1464
 
    undefined.
1465
 
 
1466
 
%% -> [{{QualifierNumber,ColumnNumber}, [Value]}]
1467
 
frames_to_columns(Fs, PatternVar, PatternId, Selector) ->
1468
 
    F = fun({cons_tuple, Cs}) -> 
1469
 
                sel_columns(Cs, 1, PatternId, Selector);
1470
 
           (_) -> 
1471
 
                []
1472
 
        end,
1473
 
    all_frames(Fs, PatternVar, F).
1474
 
 
1475
 
sel_columns({cons,_,C,E}, Col, PId, Selector) ->
1476
 
    case Selector(C) of
1477
 
        true -> 
1478
 
            V = {{PId#qid.no,Col},cons2tuple(C)},
1479
 
            [V | sel_columns(E, Col+1, PId, Selector)];
1480
 
        false ->
1481
 
            sel_columns(E, Col+1, PId, Selector)
1482
 
    end;
1483
 
sel_columns(_, _Col, _PId, _Selector) ->
1484
 
    [].
1485
 
 
1486
 
all_frames([], _PatternVar, _DerefFun) ->
 
1622
%% -> [ [{{QualifierNumber,ColumnNumber}, [Value]}] ]
 
1623
frames_to_columns([], _PatternVars, _DerefFun, _SelectorFun, _Imp, _CompOp) ->
1487
1624
    [];
1488
 
all_frames(Fs, PatternVar, DerefFun) ->
1489
 
    Rs = [begin
1490
 
              Deref = deref({var, 0, PatternVar}, F),
1491
 
              RL = DerefFun(Deref),
1492
 
              sofs:relation(RL) % possibly empty
1493
 
          end || F <- Fs],
 
1625
frames_to_columns(Fs, PatternVars, DerefFun, SelectorFun, Imp, CompOp) ->
 
1626
    %% It is important that *the same* variables are introduced for
 
1627
    %% columns in every frame. (When trying to find constant columns
 
1628
    %% it doesn't matter, but when trying to find joined columns, the
 
1629
    %% same variables have to be the representatives in every frame.)
 
1630
    SizesVarsL =
 
1631
        [begin 
 
1632
             PatVar = {var,0,PV},
 
1633
             PatternSizes = [pattern_size([F], PatVar, false) || 
 
1634
                                F <- Fs],
 
1635
             MaxPZ = lists:max([0 | PatternSizes -- [undefined]]),
 
1636
             Vars = pat_vars(MaxPZ),
 
1637
             {PatternId#qid.no, PatVar, PatternSizes, Vars}
 
1638
         end || {PatternId, PV} <- PatternVars],
 
1639
    BF = fun(_Op, Value) -> is_bindable(Value) end,
 
1640
    Fun = fun({_PatN, PatVar, PatSizes, Vars}, Frames) -> 
 
1641
                  [unify('=:=', pat_tuple(Sz, Vars), PatVar, Frame, BF, Imp) ||
 
1642
                      {Sz, Frame} <- lists:zip(PatSizes, Frames)]
 
1643
          end,
 
1644
    NFs = lists:foldl(Fun, Fs, SizesVarsL),
 
1645
    [frames2cols(NFs, PatN, PatSizes, Vars, DerefFun, SelectorFun, CompOp) ||
 
1646
        {PatN, _PatVar, PatSizes, Vars} <- SizesVarsL].
 
1647
 
 
1648
frames2cols(Fs, PatN, PatSizes, Vars, DerefFun, SelectorFun, CompOp) ->
 
1649
    Rs = [ begin
 
1650
               RL = [{{PatN,Col},cons2tuple(element(2, Const))} ||
 
1651
                        {V, Col} <- lists:zip(sublist(Vars, PatSz),
 
1652
                                              seq(1, PatSz)),
 
1653
                        %% Do not handle the case where several
 
1654
                        %% values compare equal, e.g. "X =:= 1
 
1655
                        %% andalso X == 1.0". Looking up both
 
1656
                        %% values or one of them won't always do
 
1657
                        %% because it is more or less undefined
 
1658
                        %% whether the table returns the given key
 
1659
                        %% or the one stored in the table. Or
 
1660
                        %% rather, it would be strange if the table
 
1661
                        %% did not return the stored key upon
 
1662
                        %% request, but the 'lookup_fun' function
 
1663
                        %% may have to add the given key (see also
 
1664
                        %% gb_table in qlc(3)). (Not a very strong
 
1665
                        %% argument. "X =:= 1" could (should?) be
 
1666
                        %% seen as a bug.) Note: matching tables
 
1667
                        %% cannot skip the filter, but looking up
 
1668
                        %% one of the values should be OK.
 
1669
                        tl(Consts = DerefFun(V, F)) =:= [],
 
1670
                        (Const = (SelectorFun(F))(hd(Consts))) =/= no],
 
1671
               sofs:relation(RL) % possibly empty
 
1672
            end || {F,PatSz} <- lists:zip(Fs, PatSizes)],
1494
1673
    Ss = sofs:from_sets(Rs),
1495
1674
    %% D: columns occurring in every frame (path).
1496
1675
    D = sofs:intersection(sofs:projection(fun(S) -> sofs:projection(1, S) end,
1497
1676
                                          Ss)),
1498
1677
    Cs = sofs:restriction(sofs:relation_to_family(sofs:union(Ss)), D),
1499
 
    sofs:to_external(Cs).
1500
 
 
1501
 
prep_expr(E, F, S, BF) ->
1502
 
    element_calls(tuple2cons(expand_expr_records(E, S)), F, BF).
 
1678
    [C || {_,Vs}=C <- sofs:to_external(Cs), not col_ignore(Vs, CompOp)].
 
1679
 
 
1680
pat_vars(N) ->
 
1681
    [unique_var() || _ <- seq(1, N)].
 
1682
 
 
1683
pat_tuple(Sz, Vars) when is_integer(Sz), Sz > 0 ->
 
1684
    TupleTail = unique_var(),
 
1685
    {cons_tuple, list2cons(sublist(Vars, Sz) ++ TupleTail)};
 
1686
pat_tuple(_, _Vars) ->
 
1687
    unique_var().
 
1688
 
 
1689
%% Do not handle tests as "X =:= 1.0 orelse X == 1" either.
 
1690
%% Similar problems as described above.
 
1691
col_ignore(_Vs, '=:=') ->
 
1692
    false;
 
1693
col_ignore(Vs, '==') ->
 
1694
    length(Vs) =/= length(lists:usort([element(2, normalise(V)) || V <- Vs])).
 
1695
 
 
1696
pattern_sizes(PatternVars, Fs) ->
 
1697
    [{QId#qid.no, Size} || 
 
1698
        {QId,PV} <- PatternVars,
 
1699
        undefined =/= (Size = pattern_size(Fs, {var,0,PV}, true))].
 
1700
 
 
1701
pattern_size(Fs, PatternVar, Exact) ->
 
1702
    Fun = fun(F) -> (deref_pattern(_Imported = []))(PatternVar, F) end,
 
1703
    Derefs = lists:flatmap(Fun, Fs),
 
1704
    Szs = [pattern_sz(Cs, 0, Exact) || {cons_tuple, Cs} <- Derefs],
 
1705
    case lists:usort(Szs) of
 
1706
        [Sz] when is_integer(Sz), Sz >= 0 -> Sz;
 
1707
        [] when not Exact -> 0;
 
1708
        _  -> undefined
 
1709
    end.
 
1710
 
 
1711
pattern_sz({cons,_,_C,E}, Col, Exact) ->
 
1712
    pattern_sz(E, Col+1, Exact);
 
1713
pattern_sz({nil,_}, Sz, _Exact) ->
 
1714
    Sz;
 
1715
pattern_sz(_, _Sz, true) ->
 
1716
    undefined;
 
1717
pattern_sz(_, Sz, false) ->
 
1718
    Sz.
 
1719
 
 
1720
deref_pattern(Imported) ->
 
1721
    fun(PV, F) -> deref_values(PV, F, Imported) end.
 
1722
 
 
1723
prep_expr(E, F, S, BF, Imported) ->
 
1724
    element_calls(tuple2cons(expand_expr_records(E, S)), F, BF, Imported).
 
1725
 
 
1726
unify_column(Frame, Var, Col, BindFun, Imported) ->
 
1727
    Call = {call,0,{atom,0,element},[{integer,0,Col}, {var,0,Var}]},
 
1728
    element_calls(Call, Frame, BindFun, Imported).
1503
1729
 
1504
1730
%% cons_tuple is used for representing {V1, ..., Vi | TupleTail}.
1505
1731
%%
1507
1733
%% {_, a | _}. The tail may be unified later, when more information
1508
1734
%% about the size of the tuple is known.
1509
1735
element_calls({call,_,{remote,_,{atom,_,erlang},{atom,_,element}},
1510
 
               [{integer,_,I},Term0]}, F0, BF) when I > 0 ->
1511
 
    VarI = unique_var(),
 
1736
               [{integer,_,I},Term0]}, F0, BF, Imported) when I > 0 ->
1512
1737
    TupleTail = unique_var(),
1513
 
    Tuple = element_tuple(I, [VarI | TupleTail]),
1514
 
    {Term, F} = element_calls(Term0, F0, BF),    
1515
 
    {VarI, unify('=:=', Tuple, Term, F, BF)};
1516
 
element_calls({call,L1,{atom,_,element}=E,As}, F0, BF) ->
 
1738
    VarsL = [unique_var() || _ <- lists:seq(1, I)],
 
1739
    Vars = VarsL ++ TupleTail,
 
1740
    Tuple = {cons_tuple, list2cons(Vars)},
 
1741
    VarI = lists:nth(I, VarsL),
 
1742
    {Term, F} = element_calls(Term0, F0, BF, Imported),
 
1743
    {VarI, unify('=:=', Tuple, Term, F, BF, Imported)};
 
1744
element_calls({call,L1,{atom,_,element}=E,As}, F0, BF, Imported) ->
1517
1745
    %% erl_expand_records should add "erlang:"...
1518
 
    element_calls({call,L1,{remote,L1,{atom,L1,erlang},E}, As}, F0, BF);
1519
 
element_calls(T, F0, BF) when is_tuple(T) ->
1520
 
    {L, F} = element_calls(tuple_to_list(T), F0, BF),
 
1746
    element_calls({call,L1,{remote,L1,{atom,L1,erlang},E}, As}, F0, BF,
 
1747
                  Imported);
 
1748
element_calls(T, F0, BF, Imported) when is_tuple(T) ->
 
1749
    {L, F} = element_calls(tuple_to_list(T), F0, BF, Imported),
1521
1750
    {list_to_tuple(L), F};
1522
 
element_calls([E0 | Es0], F0, BF) ->
1523
 
    {E, F1} = element_calls(E0, F0, BF),
1524
 
    {Es, F} = element_calls(Es0, F1, BF),
 
1751
element_calls([E0 | Es0], F0, BF, Imported) ->
 
1752
    {E, F1} = element_calls(E0, F0, BF, Imported),
 
1753
    {Es, F} = element_calls(Es0, F1, BF, Imported),
1525
1754
    {[E | Es], F};
1526
 
element_calls(E, F, _BF) ->
 
1755
element_calls(E, F, _BF, _Imported) ->
1527
1756
    {E, F}.
1528
1757
 
1529
 
element_tuple(1, Es) ->
1530
 
    {cons_tuple, list2cons(Es)};
1531
 
element_tuple(I, Es) ->
1532
 
    element_tuple(I-1, [unique_var() | Es]).
1533
 
 
1534
1758
unique_var() ->
1535
1759
    {var, 0, make_ref()}.
1536
1760
 
1561
1785
pe(E) ->
1562
1786
    E.
1563
1787
 
1564
 
unify(Op, E1, E2, F, BF) ->
1565
 
    unify(Op, E1, E2, F, BF, false).
1566
 
 
1567
 
safe_unify(Op, E1, E2, F, BF) ->
1568
 
    unify(Op, E1, E2, F, BF, true).
1569
 
 
1570
 
unify(_Op, _E1, _E2, failed, _BF, _Safe) -> % contradiction
 
1788
unify(Op, E1, E2, F, BF, Imported) ->
 
1789
    unify(Op, E1, E2, F, BF, Imported, false).
 
1790
 
 
1791
safe_unify(Op, E1, E2, F, BF, Imported) ->
 
1792
    unify(Op, E1, E2, F, BF, Imported, true).
 
1793
 
 
1794
unify(_Op, _E1, _E2, failed, _BF, _Imported, _Safe) -> % contradiction
1571
1795
    failed;
1572
 
unify(_Op, E, E, F, _BF, _Safe) ->
 
1796
unify(_Op, E, E, F, _BF, _Imported, _Safe) ->
1573
1797
    F;
1574
 
unify(Op, {var, _, _}=Var, E2, F, BF, Safe) ->
1575
 
    extend_frame(Op, Var, E2, F, BF, Safe);
1576
 
unify(Op, E1, {var, _, _}=Var, F, BF, Safe) ->
1577
 
    extend_frame(Op, Var, E1, F, BF, Safe);
1578
 
unify(Op, {cons_tuple, Es1}, {cons_tuple, Es2}, F, BF, Safe) ->
1579
 
    unify(Op, Es1, Es2, F, BF, Safe);
1580
 
unify(Op, {cons, _, L1, R1}, {cons, _, L2, R2}, F, BF, Safe) ->
1581
 
    unify(Op, R1, R2, unify(Op, L1, L2, F, BF, Safe), BF, Safe);
1582
 
unify(Op, E1, E2, F, _BF, Safe) ->
1583
 
    %% This clause could just return F.
 
1798
unify(Op, {var, _, _}=Var, E2, F, BF, Imported, Safe) ->
 
1799
    extend_frame(Op, Var, E2, F, BF, Imported, Safe);
 
1800
unify(Op, E1, {var, _, _}=Var, F, BF, Imported, Safe) ->
 
1801
    extend_frame(Op, Var, E1, F, BF, Imported, Safe);
 
1802
unify(Op, {cons_tuple, Es1}, {cons_tuple, Es2}, F, BF, Imported, Safe) ->
 
1803
    unify(Op, Es1, Es2, F, BF, Imported, Safe);
 
1804
unify(Op, {cons, _, L1, R1}, {cons, _, L2, R2}, F, BF, Imported, Safe) ->
 
1805
    E = unify(Op, L1, L2, F, BF, Imported, Safe),
 
1806
    unify(Op, R1, R2, E, BF, Imported, Safe);
 
1807
unify(Op, E1, E2, F, _BF, _Imported, Safe) ->
1584
1808
    try
1585
1809
      {ok, C1} = normalise(E1),
1586
1810
      {ok, C2} = normalise(E2),
1595
1819
    catch error:_ when Safe -> failed;
1596
1820
          error:_ when not Safe -> F   % ignored
1597
1821
    end.
1598
 
%% Binaries are not handled at all.
1599
 
 
1600
 
-record(bind, {var, value}).
1601
 
 
1602
 
extend_frame(Op, Var, Value, F, BF, Safe) ->
1603
 
    case binding(Var, F) of
1604
 
        #bind{var = Var, value = VarValue} ->
1605
 
            unify(Op, VarValue, Value, F, BF, Safe);
1606
 
        false ->
 
1822
%% Binaries are not handled at all (by unify).
 
1823
 
 
1824
%% Note that a variable can be bound to several values, for instance:
 
1825
%% X =:= 3, X == 3.0. As a consequence, deref() returns a list of
 
1826
%% values.
 
1827
 
 
1828
%% Binding a variable to several values makes the unification and
 
1829
%% dereferencing more complicated. An alternative would be not to try
 
1830
%% to find lookup values for such QLCs at all. That might have been a
 
1831
%% better design decision.
 
1832
 
 
1833
-record(bind, {var, value, op}). 
 
1834
 
 
1835
extend_frame(Op, Var, Value, F, BF, Imported, Safe) ->
 
1836
    case var_values(Var, F) of
 
1837
        [] ->
1607
1838
            case Value of
1608
1839
                {var, _, _} ->
1609
 
                    case binding(Value, F) of
1610
 
                        #bind{var = Value, value = ValueValue} ->
1611
 
                            unify(Op, Var, ValueValue, F, BF, Safe);
1612
 
                        false ->
1613
 
                            add_binding(Op, Var, Value, F, BF)
 
1840
                    case var_values(Value, F) of
 
1841
                        [] ->
 
1842
                            add_binding(Op, Value, Var, F, BF, Imported, Safe);
 
1843
                        ValsOps ->
 
1844
                            maybe_add_binding(ValsOps, Op, Value, Var, F, 
 
1845
                                              BF, Imported, Safe)
1614
1846
                    end;
1615
1847
                _ ->
1616
 
                    add_binding(Op, Var, Value, F, BF)
 
1848
                    add_binding(Op, Var, Value, F, BF, Imported, Safe)
 
1849
            end;
 
1850
        ValsOps ->
 
1851
            maybe_add_binding(ValsOps, Op, Var, Value, F, BF, Imported, Safe)
 
1852
    end.
 
1853
 
 
1854
maybe_add_binding(ValsOps, Op, Var, Value, F0, BF, Imported, Safe) ->
 
1855
    case unify_var_bindings(ValsOps, Op, Value, F0, BF, Imported, Safe) of
 
1856
        failed ->
 
1857
            failed;
 
1858
        F ->
 
1859
            case already_bound(Op, Var, Value, F) of
 
1860
                true -> 
 
1861
                    F;
 
1862
                false ->
 
1863
                    add_binding(Op, Var, Value, F, BF, Imported, Safe)
1617
1864
            end
1618
1865
    end.
1619
 
    
1620
 
add_binding(Op, Var, Value, F, BF) ->
1621
 
    case BF(Value, Op) of
1622
 
        true -> 
1623
 
            add_binding(Var, Value, F);
1624
 
        false ->
 
1866
 
 
1867
already_bound(Op, Var, Value, F) ->
 
1868
    %% Note: all variables are treated as imported. The dereferenced
 
1869
    %% values must not depend on Imported.
 
1870
    BFun = fun(_DV, BOp) ->  Op =:= BOp end,
 
1871
    DerefValue = deref_value(Value, Op, F, BFun, all),
 
1872
    DerefVar = deref_var(Var, F, BFun, all),
 
1873
    DerefValue -- DerefVar =:= [].
 
1874
 
 
1875
unify_var_bindings([], _Op, _Value, F, _BF, _Imported, _Safe) ->
 
1876
    F;
 
1877
unify_var_bindings([{VarValue, Op2} | Bindings],
 
1878
                   Op1, Value, F0, BF, Imported, Safe) ->
 
1879
    Op = deref_op(Op1, Op2),
 
1880
    case unify(Op, VarValue, Value, F0, BF, Imported, Safe) of
 
1881
        failed ->
 
1882
            failed;
 
1883
        F ->
 
1884
            unify_var_bindings(Bindings, Op1, Value, F, BF, Imported, Safe)
 
1885
    end.
 
1886
 
 
1887
deref_op('=:=', '=:=') ->
 
1888
    '=:=';
 
1889
deref_op(_, _) ->
 
1890
    '=='.
 
1891
 
 
1892
%%% Note: usort works; {integer,L,3} does not match {float,L,3.0}.
 
1893
 
 
1894
var_values(Var, Frame) ->
 
1895
    [{Value, Op} || 
 
1896
        #bind{value = Value, op = Op} <- var_bindings(Var, Frame)].
 
1897
 
 
1898
deref_var(Var, Frame, Imported) ->
 
1899
    deref_var(Var, Frame, fun(_DV, _Op) -> true end, Imported).
 
1900
 
 
1901
deref_var(Var, Frame, BFun, Imported) ->
 
1902
    lists:usort([ValOp || 
 
1903
                    #bind{value = Value, op = Op} <- var_bindings(Var, Frame),
 
1904
                    ValOp <- deref_value(Value, Op, Frame, BFun, Imported)]).
 
1905
 
 
1906
deref_value(Value, Op, Frame, BFun, Imported) ->
 
1907
    lists:usort([{Val,value_op(ValOp, Op, Imported)} || 
 
1908
                    {Val,_Op}=ValOp <- deref(Value, Frame, BFun, Imported)]).
 
1909
 
 
1910
add_binding(Op, Var0, Value0, F, BF, Imported, Safe) ->
 
1911
    {Var, Value} = maybe_swap_var_value(Var0, Value0, F, Imported),
 
1912
    case BF(Op, Value) of
 
1913
        true ->
 
1914
            add_binding2(Var, Value, Op, F);
 
1915
        false when Safe ->
 
1916
            failed;
 
1917
        false when not Safe ->
1625
1918
            F
1626
1919
    end.
1627
1920
 
1628
 
add_binding(Var, Value, F) ->
1629
 
    case {occurs(Var, Value, F), Value} of
1630
 
        {true, _} ->
 
1921
add_binding2(Var, Value, Op, F) ->
 
1922
    case occurs(Var, Value, F) of
 
1923
        true ->
1631
1924
            failed;
1632
 
        {false, {var, _, Ref}} when is_reference(Ref) ->
1633
 
            %% Push imported variables to the end of the binding chain
1634
 
            %% in order to make is_const/1 work.
1635
 
            [#bind{var = Value, value = Var} | F];
1636
 
        {false, _} ->
1637
 
            [#bind{var = Var, value = Value} | F]
1638
 
    end.
 
1925
        false ->
 
1926
            [#bind{var = Var, value = Value, op = Op} | F]
 
1927
    end.
 
1928
 
 
1929
%% Ensure that imported variables are visible in the dereferenced
 
1930
%% value by pushing them to the end of the binding chain. Be careful
 
1931
%% not to introduce loops.
 
1932
maybe_swap_var_value(Var, Value, Frame, Imported) ->
 
1933
    case do_swap_var_value(Var, Value, Frame, Imported) of
 
1934
        true ->
 
1935
            {Value, Var};
 
1936
        false ->
 
1937
            {Var, Value}
 
1938
    end.
 
1939
 
 
1940
do_swap_var_value({var, _, V1}=Var1, {var, _, V2}=Var2, F, Imported) ->
 
1941
    case swap_vv(Var1, Var2, F) of
 
1942
        [] ->
 
1943
            case swap_vv(Var2, Var1, F) of
 
1944
                [] ->
 
1945
                    ordsets:is_element(V1, Imported) andalso 
 
1946
                        not ordsets:is_element(V2, Imported);
 
1947
                _Bs ->
 
1948
                    true
 
1949
            end;                
 
1950
        _Bs ->
 
1951
           false
 
1952
    end;
 
1953
do_swap_var_value(_, _, _F, _Imp) ->
 
1954
    false.
 
1955
 
 
1956
swap_vv(V1, V2, F) ->
 
1957
    [V || #bind{value = V} <- var_bindings(V1, F), V =:= V2].
1639
1958
 
1640
1959
normalise(E) ->
1641
1960
    %% Tuple tails are OK.
1649
1968
occurs(V, V, _F) ->
1650
1969
    true;
1651
1970
occurs(V, {var, _, _} = Var, F) ->
1652
 
    case binding(Var, F) of
1653
 
        #bind{value = Value} ->
1654
 
            occurs(V, Value, F);
1655
 
        false ->
1656
 
            false
1657
 
    end;
 
1971
    lists:any(fun(B) -> occurs(V, B#bind.value, F) end, var_bindings(Var, F));
1658
1972
occurs(V, T, F) when is_tuple(T) ->
1659
1973
    lists:any(fun(E) -> occurs(V, E, F) end, tuple_to_list(T));
1660
1974
occurs(V, [E | Es], F) ->
1661
 
    occurs(V, E, F) or occurs(V, Es, F);
 
1975
    occurs(V, E, F) orelse occurs(V, Es, F);
1662
1976
occurs(_V, _E, _F) ->
1663
1977
    false.
1664
1978
 
1665
 
has_integer(I) when is_integer(I) ->
1666
 
    true;
1667
 
has_integer(F) when is_float(F) ->
1668
 
    round(F) == F;
1669
 
has_integer(T) when is_tuple(T) ->
1670
 
    has_integer(tuple_to_list(T));
1671
 
has_integer([E | Es]) ->
1672
 
    has_integer(E) or has_integer(Es);
1673
 
has_integer(_) ->
1674
 
    false.
1675
 
 
1676
 
deref(E, F) ->
1677
 
    var_map(fun(V) ->
1678
 
                    case binding(V, F) of
1679
 
                        #bind{value = Val} ->
1680
 
                            deref(Val, F);
1681
 
                        false ->
1682
 
                            V
1683
 
                    end
1684
 
            end, E).
1685
 
 
1686
 
binding(V, [#bind{var = V}=B | _]) ->
1687
 
    B;
1688
 
binding(V, [_ | F]) ->
1689
 
    binding(V, F);
1690
 
binding(_V, _F) ->
 
1979
deref_values(E, Frame, Imported) ->
 
1980
    deref_values(E, Frame, fun(_DV, _Op) -> true end, Imported).
 
1981
 
 
1982
deref_values(E, Frame, BFun, Imported) ->
 
1983
    lists:usort([V || 
 
1984
                    {V, Op} <- deref(E, Frame, BFun, Imported),
 
1985
                    BFun(V, Op)]).
 
1986
 
 
1987
deref(E, F, Imp) ->
 
1988
    BFun = fun(_DV, _Op) -> true end,
 
1989
    deref(E, F, BFun, Imp).
 
1990
 
 
1991
deref({var, _, _}=V, F, BFun, Imp) ->
 
1992
    DBs = lists:flatmap(fun(B) -> deref_binding(B, F, BFun, Imp) 
 
1993
                        end, var_bindings(V, F)),
 
1994
    case DBs of
 
1995
        [] ->
 
1996
            [{V, '=:='}];
 
1997
        _ ->
 
1998
            lists:usort(DBs)
 
1999
    end;
 
2000
deref(T, F, BFun, Imp) when is_tuple(T) ->
 
2001
    [{list_to_tuple(DL), Op} || 
 
2002
        {DL, Op} <- deref(tuple_to_list(T), F, BFun, Imp)];
 
2003
deref(Es, F, BFun, Imp) when is_list(Es) ->
 
2004
    L = [deref(C, F, BFun, Imp) || C <- Es],
 
2005
    lists:usort([deref_list(S) || S <- all_comb(L)]);
 
2006
deref(E, _F, _BFun, _Imp) ->
 
2007
    [{E, '=:='}].
 
2008
 
 
2009
var_bindings(Var, F) ->
 
2010
    [B || #bind{var = V}=B <- F, V =:= Var].
 
2011
 
 
2012
deref_binding(Bind, Frame, BFun, Imp) ->
 
2013
    #bind{value = Value, op = Op0} = Bind,
 
2014
    [{Val, Op} ||
 
2015
        {Val, _Op}=ValOp <- deref(Value, Frame, BFun, Imp),
 
2016
        BFun(Val, Op = value_op(ValOp, Op0, Imp))].
 
2017
    
 
2018
deref_list(L) ->
 
2019
    Op = case lists:usort([Op || {_Val, Op} <- L]) of
 
2020
             ['=:='] ->
 
2021
                 '=:=';
 
2022
             _ ->
 
2023
                 '=='
 
2024
         end,
 
2025
    {[V || {V, _Op} <- L], Op}.
 
2026
 
 
2027
value_op({_V, '=='}, _BindOp, _Imp) ->
 
2028
    '==';
 
2029
value_op({_V, '=:='}, _BindOp='=:=', _Imp) ->
 
2030
    '=:=';
 
2031
value_op({V, '=:='}, _BindOp='==', Imp) ->
 
2032
    case free_of_integers(V, Imp) of
 
2033
        true ->
 
2034
            '=:=';
 
2035
        false ->
 
2036
            '=='
 
2037
    end.
 
2038
 
 
2039
all_comb([]) ->
 
2040
    [[]];
 
2041
all_comb([Cs | ICs]) ->
 
2042
    [[C | L] || C <- Cs, L <- all_comb(ICs)].
 
2043
 
 
2044
%% "Free of integers" here means that there are not imported variables
 
2045
%% in V (which could take on integer values), but there may be other
 
2046
%% variables in V.
 
2047
free_of_integers(V, Imported) ->
 
2048
    not has_integer(V) andalso not has_imported_vars(V, Imported).
 
2049
 
 
2050
%% Assumes that imported variables are representatives, if Value is a
 
2051
%% dereferenced value.
 
2052
has_imported_vars(Value, all) ->
 
2053
    qlc:vars(Value) =/= [];
 
2054
has_imported_vars(Value, Imported) ->
 
2055
    [Var || Var <- qlc:vars(Value), lists:member(Var, Imported)] =/= [].
 
2056
 
 
2057
has_integer(Abstr) ->
 
2058
    try
 
2059
        has_int(Abstr)
 
2060
    catch throw:true -> true
 
2061
    end.
 
2062
 
 
2063
has_int({integer,_,I}) when float(I) == I ->
 
2064
    throw(true);
 
2065
has_int({float,_,F}) when round(F) == F ->
 
2066
    throw(true);
 
2067
has_int(T) when is_tuple(T) ->
 
2068
    has_int(tuple_to_list(T));
 
2069
has_int([E | Es]) ->
 
2070
    has_int(E), 
 
2071
    has_int(Es);
 
2072
has_int(_) ->
1691
2073
    false.
1692
2074
 
1693
2075
tuple2cons({tuple, _, Es}) ->
1724
2106
    [cons2tuple(E)].
1725
2107
 
1726
2108
%% Returns true if all bindings in F1 also occur in F2.
1727
 
%% All unique variables are considered equal after deref.
1728
 
bindings_is_subset(F1, F2) ->
1729
 
    lists:all(fun(#bind{var = V}) ->
1730
 
                      is_unique_var(V) 
1731
 
                      orelse deref_ss(V, F1) =:= deref_ss(V, F2)
1732
 
              end, F1).
 
2109
%% Viewing F1 and F2 as sets, the fact that F1 is a subset of F2 iff
 
2110
%% F1 union F2 is equal to F2 is used. (This should take care of 
 
2111
%% issues with anonymous variables.)
 
2112
bindings_is_subset(F1, F2, Imported) ->
 
2113
    BF = fun(_Op, _Value) -> true end, % don't need any test here
 
2114
    %% Extend F2 with the bindings in F1:
 
2115
    F = lists:foldl(fun(#bind{var = V, value = Value, op = Op}, Frame) ->
 
2116
                            unify(Op, V, Value, Frame, BF, Imported)
 
2117
                    end, F2, F1),
 
2118
    bindings_subset(F, F2, Imported) andalso bindings_subset(F2, F, Imported).
1733
2119
 
1734
 
deref_ss(E, F) ->
1735
 
    var_map(fun(V) ->
1736
 
                    case is_unique_var(V) of
1737
 
                        true -> unique_var;
1738
 
                        false -> V
1739
 
                    end
1740
 
            end, deref(E, F)).
 
2120
bindings_subset(F1, F2, Imp) ->
 
2121
    Vars = lists:usort([V || #bind{var = V} <- F1, not is_unique_var(V)]),
 
2122
    lists:all(fun(V) ->
 
2123
                      deref_var(V, F1, Imp) =:= deref_var(V, F2, Imp)
 
2124
              end, Vars).
1741
2125
 
1742
2126
%% Recognizes all QLCs on the form [T || P <- LE, F] such that
1743
2127
%% ets:fun2ms(fun(P) when F -> T end) is a match spec. This is OK with
1787
2171
               {join, Op, Q1, Q2, H1, H2, Cs1_0, Cs2_0} ->
1788
2172
                   Cs1 = qcon(Cs1_0),
1789
2173
                   Cs2 = qcon(Cs2_0),
1790
 
                   Compat = {nil,L}, % meant for redundant match spec
 
2174
                   %% -- R12B-3: {nil,L}
 
2175
                   %% R12B-4 --: {atom,L,v1}
 
2176
                   Compat = {atom,L,v1}, % meant for redundant match spec
1791
2177
                   CF = closure({tuple,L,[Cs1,Cs2,Compat]}, L),
1792
2178
                   {tuple,L,[?A(join),?A(Op),?I(Q1),?I(Q2),H1,H2,CF]};
1793
2179
               _ ->
1803
2189
    {nil,L}.
1804
2190
 
1805
2191
qcon(Cs) ->
1806
 
    list2cons([{tuple,0,[{integer,0,C},list2cons(Vs)]} || {C,Vs} <- Cs]).
 
2192
    list2cons([{tuple,0,[{integer,0,Col},list2cons(qcon1(ConstOps))]} || 
 
2193
                  {Col,ConstOps} <- Cs]).
 
2194
 
 
2195
qcon1(ConstOps) ->
 
2196
    [{tuple,0,[Const,abstr(Op, 0)]} || {Const,Op} <- ConstOps].
1807
2197
 
1808
2198
%% The original code (in Source) is used for filters and the template
1809
2199
%% since the translated code can have QLCs and we don't want them to
1989
2379
    [aux_var(Name, LcN, 0, 1, AllVars) || Name <- Vars].
1990
2380
 
1991
2381
aux_var(Name, LcN, QN, N, AllVars) ->
1992
 
    aux_name(lists:concat([Name, LcN, '_', QN, '_']), N, AllVars).
1993
 
 
1994
 
aux_name(Name, N, AllNames) ->
1995
 
    {VN, _} = aux_name1(Name, N, AllNames),
1996
 
    VN.
1997
 
 
1998
 
aux_name1(Name, N, AllNames) ->
1999
 
    SN = name_suffix(Name, N),
2000
 
    case sets:is_element(SN, AllNames) of
2001
 
        true -> aux_name1(Name, N + 1, AllNames);
2002
 
        false -> {SN, N}
2003
 
    end.
 
2382
    qlc:aux_name(lists:concat([Name, LcN, '_', QN, '_']), N, AllVars).
2004
2383
 
2005
2384
no_compiler_warning(Line) ->
2006
2385
    - abs(Line).
2065
2444
qlcmf(T, _F, _Imp, A, No) ->
2066
2445
    {T, A, No}.
2067
2446
 
2068
 
vars(E) ->
2069
 
    var_ufold(fun({var,_L,V}) -> V end, E).
2070
 
 
2071
2447
occ_vars(E) ->
2072
 
    var_fold(fun({var,_L,V}) -> V end, [], E).
2073
 
 
2074
 
var_ufold(F, E) ->
2075
 
    ordsets:from_list(var_fold(F, [], E)).
2076
 
 
2077
 
var_fold(F, A, {var,_,V}=Var) when V =/= '_' ->
2078
 
    [F(Var) | A];
2079
 
var_fold(F, A, T) when is_tuple(T) ->
2080
 
    var_fold(F, A, tuple_to_list(T));
2081
 
var_fold(F, A, [E | Es]) ->
2082
 
    var_fold(F, var_fold(F, A, E), Es);
2083
 
var_fold(_F, A, _T) ->
2084
 
    A.
 
2448
    qlc:var_fold(fun({var,_L,V}) -> V end, [], E).
2085
2449
 
2086
2450
no_shadows(Forms0, State) ->
2087
2451
    %% Variables that may shadow other variables are introduced in
2102
2466
    %% The original names of variables are kept in the line number
2103
2467
    %% position of the abstract code: {var, {OriginalName, L},
2104
2468
    %% NewName}. undo_no_shadows/1 re-creates the original code.
2105
 
    AllVars = sets:from_list(ordsets:to_list(vars(Forms0))),
 
2469
    AllVars = sets:from_list(ordsets:to_list(qlc:vars(Forms0))),
2106
2470
    ?DEBUG("nos AllVars = ~p~n", [sets:to_list(AllVars)]),
2107
2471
    VFun = fun(_Id, LC, Vs) -> nos(LC, Vs) end,
2108
2472
    LI = ets:new(?APIMOD,[]),
2168
2532
    {[P | Ps], S, PVs};
2169
2533
nos_pattern({var,L,V}, {LI,Vs0,UV,A,Sg}, PVs0) when V =/= '_' ->
2170
2534
    {Name, Vs, PVs} = 
2171
 
        case keysearch(V, 1, PVs0) of
 
2535
        case lists:keysearch(V, 1, PVs0) of
2172
2536
            {value, {V,VN}} -> 
2173
2537
                _ = used_var(V, Vs0, UV), 
2174
2538
                {VN, Vs0, PVs0};
2190
2554
used_var(V, Vs, UV) ->
2191
2555
    case dict:find(V, Vs) of
2192
2556
        {ok,Value} ->
2193
 
            VN = name_suffix(V, Value),
 
2557
            VN = qlc:name_suffix(V, Value),
2194
2558
            _ = ets:update_counter(UV, VN, 1),
2195
2559
            {true, VN};
2196
2560
        error -> false
2202
2566
                 [] -> 1
2203
2567
             end,
2204
2568
    true = ets:insert(LI, {V, NValue}),
2205
 
    VN = name_suffix(V, NValue),
 
2569
    VN = qlc:name_suffix(V, NValue),
2206
2570
    case sets:is_element(VN, AllVars) of
2207
2571
        true -> next_var(V, Vs, AllVars, LI, UV);
2208
2572
        false -> true = ets:insert(UV, {VN, 0}),
2210
2574
                 {VN, NVs}
2211
2575
    end.
2212
2576
 
2213
 
name_suffix(A, Suff) ->
2214
 
    list_to_atom(lists:concat([A, Suff])).
2215
 
 
2216
2577
undo_no_shadows(E) ->
2217
2578
    var_map(fun undo_no_shadows1/1, E).
2218
2579
 
2250
2611
sgn(X) when X < 0 ->
2251
2612
    -1.
2252
2613
 
 
2614
seq(S, E) when S - E =:= 1 ->
 
2615
    [];
 
2616
seq(S, E) -> 
 
2617
    lists:seq(S, E).
 
2618
 
 
2619
sublist(_, 0) ->
 
2620
    [];
 
2621
sublist(L, N) ->
 
2622
    lists:sublist(L, N).
 
2623
 
2253
2624
qid(LCId, No) ->
2254
2625
    #qid{no = No, lcid = LCId}.
2255
2626
 
2269
2640
embed_expr(Expr, L) ->
2270
2641
    {lc,L,Expr,[{generate,L,{var,L,'_'},{nil,L}}]}.
2271
2642
 
 
2643
%% Doesn't handle binaries very well, but don't bother for now.
2272
2644
var2const(E) ->
2273
2645
    var_map(fun({var, L, V}) -> {atom, L, V} end, E).
2274
2646