📄 mnemosyne_transform.erl
字号:
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(mnemosyne_transform).-export([unfold/2, expand_records/4, format_error/1]).%%-define(debug,1).-include("mnemosyne_debug.hrl").-include("mnemosyne_internal_form.hrl").%%%================================================================%%% Exportsunfold(Goals, RecordDefinitions) -> {_, Alts, RecDefs} = unfold(Goals, RecordDefinitions, mnemosyne_lib:new()), {case Alts of [Alt] when is_list(Alt) -> Alt; Alts when is_list(Alts) -> {'#or', 1, lists:map(fun(A) -> #disj_alt{conj=A} end, Alts)} end, RecDefs}.expand_records(Goals, VarTypes, RecDefs, Mod) -> expand_record(Goals, VarTypes, RecDefs, Mod).format_error(Msg) -> case Msg of {undefined,{record_fields,RecName,Var,FieldNames}} -> io_lib:format("Undefined record fields in record ~w (variable ~w): ~p", [RecName,Var,FieldNames]); {undefined,{record_fields,RecName,FieldNames}} -> io_lib:format("Undefined record fields in record ~w: ~p", [RecName,FieldNames]); {undefined,{record,RecName}} -> io_lib:format("Undefined record ~w", [RecName]) end.%%%================================================================%%% Privateunfold(Goals, RecordDefinitions, SymTab) -> unfold(Goals, RecordDefinitions, SymTab, [[]]).unfold([{'#or',_,Alts0}|Goals], RecDefs0, SymTab0, Acc) -> {SymTab, Alts, RecDefs} = unfold_each_alt(Alts0, RecDefs0, SymTab0), unfold(Goals, RecDefs, SymTab, append_clauses(Alts,Acc));unfold([Goal|Goals], RecDefs0, SymTab0, Acc) when is_record(Goal,pred_sym) -> RecDefs = visible_record_definitions(RecDefs0, Goal#pred_sym.module), {RecName,_} = Goal#pred_sym.record_def, case lists:keysearch(RecName,1,RecDefs) of {value, Def} -> SymTab = symtab(Goal, SymTab0), Recursive = recursive(Goal,SymTab), unfold_pred_sym_goal(Goal#pred_sym.type, Recursive, Goal#pred_sym{% record_def=Def, recursive=Recursive}, Goals, RecDefs, SymTab, Acc); false -> throw({error, {Goal#pred_sym.line, ?MODULE, {undefined,{record,RecName}}}}) end;unfold([{'#not',C,NegGoals0}|Goals], RecDefs0, SymTab0, Acc) -> ?debugmsg(3, "~s\n", [mnemosyne_pp:body([{'#not',C,NegGoals0}])]), %% Input: ~(p,q,...) {SymTab, NegGoals, RecDefs} = unfold(NegGoals0, RecDefs0, SymTab0),?debugmsg(4, "~w\n", [NegGoals0]),?debugmsg(4, "~w\n", [NegGoals]), %% NegGoals = (p';q';...) NegAlts = lists:map(fun(Alt) -> lists:map(fun(Goal) -> {'#not',C,[Goal]} end, Alt) end, NegGoals),?debugmsg(4, "~w\n", [NegAlts]), %% NegAlts = (~p';~q';~...) %% Now we have transformed ~(p,q,...) into (~p';~q';~...) %% (partial evaluation of the '#or' clause above): Acc1 = append_clauses(NegAlts,Acc), ?debugmsg(3, "~s\n", [mnemosyne_pp:body(Acc1)]), unfold(Goals, RecDefs, SymTab, append_clauses(NegAlts,Acc));unfold([Goal|Goals], RecDefs, SymTab, Acc) -> unfold(Goals, RecDefs, SymTab, append_clauses([[Goal]],Acc));unfold([], RecDefs, SymTab, Acc) -> {SymTab,Acc,RecDefs}. unfold_pred_sym_goal(rule, non_recursive, Goal, Goals, RecDefs, SymTab, Acc) -> unfold([{'#or', 1, mnemosyne_lib:db_read_clauses(Goal)}|Goals], RecDefs, SymTab, Acc); unfold_pred_sym_goal(_, _, Goal, Goals, RecDefs, SymTab, Acc) -> unfold(Goals, RecDefs, SymTab, append_clauses([[Goal]],Acc)).unfold_each_alt(Alts, RecDefs, SymTab) -> unfold_each_alt(Alts, RecDefs, SymTab, []).unfold_each_alt([Goals|GoalsL], RecDefs0, SymTab0, Acc) -> {SymTab1, Alts, RecDefs} = unfold(Goals, RecDefs0, SymTab0, [[]]), unfold_each_alt(GoalsL, RecDefs, SymTab1, [Alts|Acc]);unfold_each_alt([], RecDefs, SymTab, Acc) -> {SymTab, lists:append(Acc), RecDefs}.append_clauses([C|Cs], Acc) -> lists:map(fun(E) -> E++C end, Acc) ++ append_clauses(Cs, Acc);append_clauses([], Acc) -> [].%%%----------------visible_record_definitions(RecDefs, ?NO_MODULE) -> RecDefs;visible_record_definitions(RecDefs, Module) -> ModuleLocalDefs = lists:flatten(mnemosyne_lib:db_data(record_defs, Module)), compose_rec_defs(ModuleLocalDefs, RecDefs).%%%----------------------------------------------------------------%%% Compose local record declarations with those already present.compose_rec_defs([D|Ds], Defs) -> {D_Name,_} = D, compose_rec_defs(Ds, case lists:keysearch(D_Name,1,Defs) of {value, _} -> Defs; false -> [D|Defs] end);compose_rec_defs([], Defs) -> Defs.%%%----------------symtab(Goal, SymTab) when Goal#pred_sym.type == rule -> case mnemosyne_lib:lookup(Goal#pred_sym.functor, SymTab) of false -> analyse(mnemosyne_lib:db_read_clauses(Goal), ordsets:from_list([Goal#pred_sym.functor]), mnemosyne_lib:insert(Goal#pred_sym.functor, non_recursive, % Might change later SymTab)); % in the analyze _ -> SymTab end;symtab(_, SymTab) -> SymTab.recursive(Goal, SymTab) when Goal#pred_sym.type == rule -> {true, R} = mnemosyne_lib:lookup( Goal#pred_sym.functor, SymTab), R;recursive(Goal, SymTab) when Goal#pred_sym.type == table -> non_recursive. analyse([Clause|Clauses], Trace, SymTab) -> analyse(Clauses, Trace, analyse_clause(Clause,Trace,SymTab));analyse([], Trace, SymTab) -> SymTab.analyse_clause([Goal|Goals], Trace, SymTab) -> analyse_clause(Goals, Trace, analyse_goal(Goal,Trace,SymTab));analyse_clause([], _, SymTab) -> SymTab.analyse_goal(Goal, Trace, SymTab0) when is_record(Goal,pred_sym), Goal#pred_sym.type == rule -> SymTab = symtab(Goal, SymTab0), case recursive(Goal,SymTab) of R when R =/= recursive -> case ordsets:is_element(Goal#pred_sym.functor, Trace) of true -> mnemosyne_lib:insert(Goal#pred_sym.functor, recursive, SymTab); false -> analyse(mnemosyne_lib:db_read_clauses(Goal), ordsets:add_element(Goal#pred_sym.functor,Trace), mnemosyne_lib:insert(Goal#pred_sym.functor, non_recursive, % Might change SymTab) %in later stage ) end; _ -> SymTab end;analyse_goal({'#not',C,NegGoals}, Trace, SymTab) -> analyse_clause(NegGoals, Trace, SymTab);analyse_goal(_, Trace, SymTab) -> SymTab. %%%----------------------------------------------------------------expand_record(R, VarTypes, RecordDefs, Mod) when is_record(R,rec_f) -> %% X.f {'#var',Var} = R#rec_f.var, case mnemosyne_compiler:lookup_record_def(R#rec_f.name, RecordDefs) of {value, {_,FieldNames}} -> Field = R#rec_f.field, case lists:member(Field,FieldNames) of true -> {'#var',{Var,Field}}; false -> throw({error, {R#rec_f.line,?MODULE, {undefined,{record_fields, R#rec_f.name,Var,[Field]}}}}) end; false -> throw({error, {R#rec_f.line,?MODULE,{undefined,{record,R#rec_f.name}}}}) end;expand_record(R, VarTypes, RecordDefs, Mod) when is_record(R,rec_c) -> %% #{a=.., b=.. ...} case mnemosyne_compiler:lookup_record_def(R#rec_c.name, RecordDefs) of {value, {RecName,FieldNames}} -> Empty = ordsets:new(), case ordsets:subtract(ordsets:from_list( mnemosyne_lib:elements(1,R#rec_c.fields) ), ordsets:from_list(FieldNames)) of Empty -> InitialValue = case catch Mod:'MNEMOSYNE RECFUNDEF'(RecName) of {'EXIT', Reason} -> throw ({error, {R#rec_c.line, ?MODULE, {internal, {record,R#rec_c.name}}}}); Initial -> Initial end, lists:foldl( fun({FieldName,_,FieldVal}, Val) -> setelement(1+mnemosyne_lib:list_pos(FieldName, FieldNames), Val, expand_record(FieldVal, VarTypes, RecordDefs,Mod)) end, InitialValue, R#rec_c.fields); S -> %% Using undeclared fields in a declared record throw({error, {R#rec_c.line,?MODULE, {undefined,{record_fields,R#rec_c.name, ordsets:to_list(S)}}}}) end; false -> throw({error, {R#rec_c.line,?MODULE,{undefined,{record,R#rec_c.name}}}}) end;expand_record({'#var',V}, VarTypes, RecDefs, Mod) -> case mnemosyne_compiler:var_type(V,VarTypes) of {value, {V,Type}} -> case mnemosyne_compiler:lookup_record_def(Type, RecDefs) of {value, {_,FieldNames}} -> expand_record(var_to_record(Type, FieldNames, [], V), VarTypes, RecDefs, Mod); false -> io:format('Why (V1) ? ~w, ~w\n', [V,VarTypes]), {'#var',V} end; false -> {'#var',V} end;expand_record([H|T], VarTypes, RecDefs, Mod) -> [ expand_record(H,VarTypes,RecDefs, Mod) | expand_record(T,VarTypes,RecDefs, Mod)];expand_record(Tuple, VarTypes, RecordDefs, Mod) when is_tuple(Tuple) -> list_to_tuple( expand_record(tuple_to_list(Tuple), VarTypes, RecordDefs, Mod));expand_record(Term, VarTypes, RecordDefs, Mod) -> Term. var_to_record(Type, Names, Fields, Var) -> list_to_tuple( [Type | lists:foldr( fun(Name,T) -> case lists:keysearch(Name,1,Fields) of%% OTP-6496. Dialyzer warning. Obviously something is wrong here,%% but don't bother to fix the bug... (there are no values!?)% {value, {FieldName,Line,FieldVal}} ->% [FieldVal|T]; false -> [{'#var',{Var,Name}}|T] end end, [], Names)]).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -