| 1 | | % (c) 2009-2022 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
| 2 | | % Heinrich Heine Universitaet Duesseldorf |
| 3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
| 4 | | |
| 5 | | /* dotTuple: |
| 6 | | either associative tuples or if first argument constructor a record |
| 7 | | |
| 8 | | tuple: |
| 9 | | associative tuple; already computed; however tuples may be present inside |
| 10 | | in(.) patterns which have only been instantiated after tuple was computed |
| 11 | | |
| 12 | | record: |
| 13 | | record; already constructed |
| 14 | | |
| 15 | | % pat(Vals,Channel): |
| 16 | | % associative tuple; constructed for a particular channel |
| 17 | | */ |
| 18 | | |
| 19 | | :- module(csp_tuples,[get_constructor_arguments/4, evaluate_channel_outputs/6, |
| 20 | | evaluate_dot_tuple/3, evaluate_dot_tuple/2, is_constructor/3, unify_values/5, |
| 21 | | list_projection/5, tuple_projection/4,incomplete_record/3,pattern_match_function_argument/3, |
| 22 | | na_tuple_projection/4, empty_tuple/1 |
| 23 | | ]). |
| 24 | | :- use_module(probsrc(module_information)). |
| 25 | | :- module_info(group,csp). |
| 26 | | :- module_info(description,'Operations on CSP tuples.'). |
| 27 | | |
| 28 | | :- use_module(library(lists)). |
| 29 | | |
| 30 | | /***************** PROB modules ***************/ |
| 31 | | :- use_module(probsrc(self_check)). |
| 32 | | :- use_module(probsrc(debug)). |
| 33 | | :- use_module(probsrc(error_manager)). |
| 34 | | %--------- CSP modules: |
| 35 | | :- use_module(probcspsrc(haskell_csp), |
| 36 | | [force_evaluate_argument/2, |
| 37 | | evaluate_argument/2,add_error_with_span/4, add_internal_error_with_span/4]). |
| 38 | | :- use_module(probcspsrc(haskell_csp_analyzer), |
| 39 | | [is_csp_constructor/1, is_a_channel_name/1, csp_full_type_constructor/3]). |
| 40 | | :- use_module(probcspsrc(csp_sets),[is_member_set_alsoPat/2]). |
| 41 | | /***************** ----------- ***************/ |
| 42 | | |
| 43 | | empty_tuple(tuple([])). |
| 44 | | |
| 45 | | %:- assert_must_succeed(( csp_tuples:evaluate_channel_outputs([in(X)],left,R,RC), R==tail_in(X), RC==left )). |
| 46 | | |
| 47 | | evaluate_channel_outputs(Values,ChannelExpr,EvaluatedValueList,Channel,Span,WF) :- |
| 48 | | % print(ev_channel(ChannelExpr,Values)),nl, |
| 49 | ? | evaluate_dot_tuple([ChannelExpr|Values],Res,WF), % print(Res),nl, |
| 50 | | %print(evaluated_dot_tuple(dotTuple([ChannelExpr|Values]),Res)),nl, |
| 51 | | (Res = tuple([Ch|VL]) |
| 52 | | -> (EvaluatedValueList,Channel) = (VL,Ch) % if we unify VL without Ch we may get error messages ! |
| 53 | | ; add_error_with_span(evaluate_channel_outputs,'Not a channel pattern: ', (ChannelExpr,Res),Span),fail |
| 54 | | ), |
| 55 | ? | (is_a_channel_name(Channel) -> true |
| 56 | | ; add_error_with_span(evaluate_channel_outputs,'Channel not declared: ',Channel,Span) ). |
| 57 | | |
| 58 | | % ev_channel(dotTuple([gen_high_pri,valarg]),[in(_6892)]) tuple([gen_high_pri,record(valarg,[]),in(_6892)]) |
| 59 | | |
| 60 | | % ------------------------------------------------------------ |
| 61 | | |
| 62 | | |
| 63 | | :- assert_must_succeed(( |
| 64 | | csp_tuples:evaluate_dot_tuple([X,int(2)],R), |
| 65 | | X = int(1), |
| 66 | | R == tuple([int(1),int(2)]) )). |
| 67 | | :- assert_must_succeed((csp_tuples: evaluate_dot_tuple([],R), R == tuple([]))). |
| 68 | | |
| 69 | | evaluate_dot_tuple(List,Res) :- |
| 70 | | evaluate_dot_tuple(List,Res,_WF). %_WF not needed as inGuard cannot appear in normal tuples |
| 71 | | |
| 72 | | :- block evaluate_dot_tuple(-,?,?). |
| 73 | ? | evaluate_dot_tuple(L,Res,WF) :- evaluate_dot_tuple_to_list(L,R,WF),construct_tuple(R,Res). |
| 74 | | |
| 75 | | % construct a tuple from a list of evaluated arguments: we need to check if we have a real |
| 76 | | % tuple or "just" a single record constructed using . |
| 77 | | :- block construct_tuple(-,?). |
| 78 | | construct_tuple([],tuple([])). |
| 79 | ? | construct_tuple([H|T],R) :- construct_tuple2(H,T,R). |
| 80 | | :- block construct_tuple2(-,?,?), construct_tuple2(?,-,?). |
| 81 | | construct_tuple2(record(C,F),[],Res) :- !, Res= record(C,F). % this is not a dotTuple but a simple record |
| 82 | | construct_tuple2(H,T,tuple([H|T])). % we have a real associative tuple |
| 83 | | |
| 84 | | |
| 85 | | % evaluate a dot tuple list to a single list of its constituents |
| 86 | | :- block evaluate_dot_tuple_to_list(-,?,?). |
| 87 | | evaluate_dot_tuple_to_list([],R,_WF) :- !,R=[]. |
| 88 | ? | evaluate_dot_tuple_to_list([H|T],R,WF) :- !, evaluate_cons_to_list(H,T,R,WF). |
| 89 | | evaluate_dot_tuple_to_list(X,R,_WF) :- add_internal_error('Internal Error: Could not evaluate dotTuple List: ',X),R=X. |
| 90 | | |
| 91 | | :- block evaluate_cons_to_list(-,?,?,?). |
| 92 | | evaluate_cons_to_list(dotTuple(L),T,R,WF) :- !, |
| 93 | ? | append(L,T,LT), evaluate_dot_tuple_to_list(LT,R,WF). |
| 94 | | evaluate_cons_to_list(tuple(L),T,R,WF) :- !, |
| 95 | | append(L,T,LT), evaluate_dot_tuple_to_list(LT,R,WF). |
| 96 | | evaluate_cons_to_list(tupleExp(L),T,R,WF) :- !, |
| 97 | | haskell_csp: evaluate_argument2(tupleExp(L),Res), |
| 98 | | evaluate_dot_tuple_to_list(T,LT,WF), |
| 99 | | append([Res],LT,R). |
| 100 | ? | evaluate_cons_to_list(X,T,R,WF) :- is_constructor(X,Constructor,SubTypes),!, |
| 101 | | % print(constructor(Constructor,SubTypes)),nl, |
| 102 | | evaluate_dot_tuple_to_list(T,ET,WF), %print(evalt(ET)),nl, |
| 103 | | get_constructor_arguments(SubTypes,ET,Fields,Rest), |
| 104 | | R=[record(Constructor,Fields)|Rest]. |
| 105 | ? | evaluate_cons_to_list(H,T,R,WF) :- !, evaluate_dot_argument(H,EH,WF), |
| 106 | ? | evaluate_cons_to_list_evhead(EH,T,R,WF). |
| 107 | | |
| 108 | | % a version where the head is already evaluated; do not evaluate again |
| 109 | | % this cannot be a constructor (right ?? ---> check ) |
| 110 | | :- block evaluate_cons_to_list_evhead(-,?,?,?). |
| 111 | | %evaluate_cons_to_list_evhead(pat(L,Ch),T,R,WF) :- !, R = pat(R3,Ch),append(L,R2,R3), |
| 112 | | % evaluate_dot_tuple_to_list(T,R2,WF). |
| 113 | | evaluate_cons_to_list_evhead(tuple(L),T,R,WF) :- !, append(L,R2,R), |
| 114 | ? | evaluate_dot_tuple_to_list(T,R2,WF). |
| 115 | | evaluate_cons_to_list_evhead(REC,T,R,WF) :- |
| 116 | | incomplete_record(REC,MissingFields,FullREC),!, |
| 117 | | %print(eval_cons_record(REC,MissingFields,FullREC)),nl, |
| 118 | | evaluate_dot_tuple_to_list(T,ET,WF), %print(evalt(ET)),nl, |
| 119 | | get_constructor_arguments(MissingFields,ET,MissingFields,Rest), |
| 120 | | %print(full_rec(FullREC,Rest)),nl, |
| 121 | | R=[FullREC|Rest]. |
| 122 | | evaluate_cons_to_list_evhead(EH,T,R,WF) :- R=[EH|ET], evaluate_dot_tuple_to_list(T,ET,WF). |
| 123 | | |
| 124 | | % check if we have an incomplete record, or a record whose last element is incomplete .... |
| 125 | | incomplete_record(record(X,Fields), MissingFields, record(Constructor,FullFields)) :- |
| 126 | | is_constructor(X,Constructor,SubTypes), |
| 127 | | get_missing_fields(Fields,SubTypes,MissingFields,FullFields). |
| 128 | | |
| 129 | | get_missing_fields([],[H|T],MissingFields,MissingFields) :- same_length([H|T],MissingFields). |
| 130 | | get_missing_fields([Rec],[_TH],MissingFields,[FullRec]) :- % we could have incomplete record at end |
| 131 | | incomplete_record(Rec,MissingFields,FullRec),!. |
| 132 | | get_missing_fields([FH|FT],[_TH|TT],MF,[FH|FFT]) :- get_missing_fields(FT,TT,MF,FFT). |
| 133 | | |
| 134 | | |
| 135 | | |
| 136 | | is_constructor(out(Constructor),Constructor,ArgSubTypes) :- atomic(Constructor), |
| 137 | | csp_full_type_constructor(Constructor,_Type,ArgSubTypes). |
| 138 | | is_constructor(Constructor,Constructor,ArgSubTypes) :- atomic(Constructor), |
| 139 | | csp_full_type_constructor(Constructor,_Type,ArgSubTypes). |
| 140 | | |
| 141 | | /* some special constructs are allowed in the presence of channel dot tuples: */ |
| 142 | | :- block evaluate_dot_argument(-,?,?). |
| 143 | | |
| 144 | | evaluate_dot_argument(out(X),R,_) :- !, force_evaluate_argument(X,R). |
| 145 | | evaluate_dot_argument(in(X),R,_) :- !, R=in(X). |
| 146 | | evaluate_dot_argument(inGuard(X,Set),R,WF) :- !, R = in(X), |
| 147 | | %print(check_guard(X,Set)),nl, |
| 148 | ? | check_guard(X,Set,WF). |
| 149 | ? | evaluate_dot_argument(H,EH,_) :- force_evaluate_argument(H,EH). %%% was evaluate_argument |
| 150 | | |
| 151 | | |
| 152 | | :- use_module(probsrc(kernel_waitflags)). |
| 153 | | :- use_module(probcspsrc(csp_sets),[try_get_cardinality_for_wait_flag/2]). |
| 154 | | check_guard(Var,Guard,WF) :- %print(check_guard(Var,Guard)),nl, |
| 155 | | %(is_boolean_expression(Guard) -> check_boolean_expression(Guard) /* syntax in CIA-CSP but actually not allowed in CSP-M ! */ |
| 156 | ? | haskell_csp:force_evaluate_argument_for_member_check(Guard,Set), |
| 157 | | /* already evaluate before Var is ground; avoid re-evaluation */ |
| 158 | | try_get_cardinality_for_wait_flag(Set,Prio), |
| 159 | | get_wait_flag(Prio,check_guard,WF,LWF), |
| 160 | | % print(check_guard(Var,Guard,LWF)),nl, |
| 161 | | % TO DO: trigger earlier; Set must be a subset of the channel type; so we can always enumerate before full channel enumeration ! |
| 162 | | when((ground(Var);nonvar(LWF)),( % |
| 163 | | (ground(Var) -> evaluate_argument(Var,EVar) ; EVar=Var), % relevant for CorrectRouter.csp; TODO: investigate why |
| 164 | | %print(is_member_set(Var,Set)),nl, |
| 165 | | is_member_set_alsoPat(EVar,Set))). |
| 166 | | :- assert_must_succeed((csp_tuples: get_constructor_arguments([],[X,Y],[],Rest), Rest == [X,Y])). |
| 167 | | :- assert_must_fail((csp_tuples: get_constructor_arguments([dotTupleType([int(1),X,int(3)])],[int(1),X],Fields,Rest), |
| 168 | | Fields == [int(1),X], Rest == [int(3)])). |
| 169 | | :- assert_must_fail((csp_tuples: get_constructor_arguments([int(1),X,int(3)],[int(1),X],Fields,Rest), |
| 170 | | Fields == [int(1),X], Rest == [int(3)])). |
| 171 | | :- assert_must_succeed((csp_tuples: get_constructor_arguments([dotTupleType([int(1),int(2)])],[int(1),int(2),int(3)],Fields,Rest), |
| 172 | | Fields == [int(1),int(2)], Rest == [int(3)])). |
| 173 | | :- assert_must_succeed((csp_tuples: get_constructor_arguments([int(1),int(2)],[int(1),int(2),int(3)],Fields,Rest), |
| 174 | | Fields == [int(1),int(2)], Rest == [int(3)])). |
| 175 | | |
| 176 | | get_constructor_arguments([],T,[],T). |
| 177 | | get_constructor_arguments([H|T],DotArgs,Fields,R) :- nonvar(H), H = dotTupleType(L), !, append(L,T,LL), get_constructor_arguments(LL,DotArgs,Fields,R). |
| 178 | | get_constructor_arguments([_Type|TT],DotArgs,Fields,R) :- |
| 179 | | (DotArgs = [H|DT] |
| 180 | | -> Fields = [H|T], get_constructor_arguments(TT,DT,T,R) |
| 181 | | ; % Have removed preference: incomplete records also arise in renamings; hard to distinguish proper from improper use |
| 182 | | %(preferences:preference(cspm_allow_incomplete_records,true) -> true |
| 183 | | % ; length([_Type|TT],Len),add_error(csp_tuples,'Incomplete record / missing arguments for record constructor (set CSP preference to turn off this message): ',ConstructorT:missing_args(Len))), |
| 184 | | /* Casper generated CSP files will trigger this; as will renaming of record names ?! !! */ |
| 185 | | DotArgs=[], R = [], |
| 186 | | Fields = [] /* to do check if we can work with this */ |
| 187 | | ). |
| 188 | | |
| 189 | | |
| 190 | | % -------------------------------------------------------------------- |
| 191 | | |
| 192 | | :- assert_must_succeed(( |
| 193 | | csp_tuples:unify_values([int(1)],[in(X)],R,a), |
| 194 | | R == [int(1)], X==int(1) )). |
| 195 | | :- assert_must_succeed(( |
| 196 | | csp_tuples:unify_values([int(1),int(2)],[int(1),in(X)],R,a), |
| 197 | | R == [int(1),int(2)], X==int(2) )). |
| 198 | | :- assert_must_succeed(( |
| 199 | | csp_tuples:unify_values([int(1),int(2)],[in(X)],R,a), |
| 200 | | R == [int(1),int(2)], X==tuple(R) )). |
| 201 | | :- assert_must_succeed(( |
| 202 | | csp_tuples:unify_values([int(1),int(2)],[in(dotTuple([X,Y]))],R,a), |
| 203 | | R == [int(1),int(2)], X==int(1), Y==int(2) )). |
| 204 | | :- assert_must_succeed(( |
| 205 | | csp_tuples:unify_values([in(dotTuple([X,Y]))],[int(1),int(2)],R,a), |
| 206 | | R == [int(1),int(2)], X==int(1), Y==int(2) )). |
| 207 | | :- assert_must_succeed(( |
| 208 | | csp_tuples:unify_values([in(dotTuple([X,Y]))],V2,R,a), |
| 209 | | V2 = [int(1),int(2)], |
| 210 | | R == [int(1),int(2)], X==int(1), Y==int(2) )). |
| 211 | | :- assert_must_succeed(( |
| 212 | | csp_tuples:unify_values([int(1),in(Y),int(3)],[int(1),in(X)],R,a), |
| 213 | | R == [int(1),in(Y),int(3)], X==tuple([in(Y),int(3)]) )). |
| 214 | | :- assert_must_succeed(( |
| 215 | | csp_tuples:unify_values([oranges],LHS,R,a), LHS = [H], H=in(X), |
| 216 | | R == [oranges], X==oranges )). |
| 217 | | :- assert_must_succeed(( |
| 218 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [H|T], H=in(X), T=[], |
| 219 | | RHS = [oranges|RR], RR=[], |
| 220 | | R == [oranges], X==oranges )). |
| 221 | | :- assert_must_succeed(( |
| 222 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [in(X)], |
| 223 | | RHS = [oranges|RR], RR=[apples|RR2],RR2=[], |
| 224 | | R == [oranges,apples], X==tuple([oranges,apples]) )). |
| 225 | | :- assert_must_succeed(( |
| 226 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [dotTuple(ppp,[na_tuple([X,Y])])], RHS = [dotTuple(ppp,[na_tuple([v1,v2])])], |
| 227 | | R =[dotTuple(ppp,[na_tuple([v1,v2])])],X=v1,Y=v2 )). |
| 228 | | :- assert_must_succeed(( |
| 229 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [record(ppp,[na_tuple([X,Y])])], RHS = [record(ppp,[na_tuple([v1,v2])])], |
| 230 | | R=[record(ppp,[na_tuple([v1,v2])])],X=v1,Y=v2 )). |
| 231 | | :- assert_must_succeed(( |
| 232 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [list([int(2),int(3)])], RHS = [list(X)], |
| 233 | | R=[list([int(2),int(3)])], X=[int(2),int(3)] )). |
| 234 | | :- assert_must_succeed(( |
| 235 | | csp_tuples:unify_values(LHS,RHS,R,a), LHS = [tuple([int(2),int(3)])], RHS = [in(X)], |
| 236 | | R=[tuple([int(2),int(3)])], X=tuple([int(2),int(3)]) )). |
| 237 | | |
| 238 | | :- block pattern_match_function_argument(-,?,?). |
| 239 | | pattern_match_function_argument(Value1,Value2,Function) :- |
| 240 | | %% print(pat_match(Value1,Value2,Function)),nl, %% |
| 241 | | (Value1 = tuple(X) |
| 242 | | -> pattern_match_f2(Value2,X,Function) |
| 243 | | ; (Value1 = Value2) /* Probably DEAD CODE, first argument is always tuple(-) (see use in haskell_csp_analyzer module)*/ |
| 244 | | ). |
| 245 | | :- block pattern_match_f2(-,?,?). |
| 246 | | pattern_match_f2(Value2,X,Function) :- |
| 247 | | ((Value2 = tuple(Y); Value2 = dotTuple(Y)) -> unify_values(X,Y,_,Function,symbol(Function)) %use Function as span |
| 248 | | ; Value2 = record(Cons,Args) -> X=[Cons|TX], unify_values(TX,Args,_,Function,symbol(Function)) |
| 249 | | ; unify_values(X,[Value2],_,Function,symbol(Function))). |
| 250 | | |
| 251 | | unify_values(Values1,Values2,Res,Channel) :- |
| 252 | | unify_values(Values1,Values2,Res,Channel,no_loc_info_available). |
| 253 | | |
| 254 | | :- block unify_values(-,?,?,?,?), unify_values(?,-,?,?,?). |
| 255 | | unify_values(Values1,Values2,Res,Channel,Span) :- |
| 256 | | % print(unify_values(Values1,Values2,Channel,Span)),nl, |
| 257 | ? | unify_tuple_args(Values1,Values2,Res,Channel,Span). |
| 258 | | |
| 259 | | :- use_module(probsrc(translate),[translate_csp_value/2]). |
| 260 | | :- use_module(probsrc(tools_strings),[ajoin/2]). |
| 261 | | unify_tuple_args([],[],R,_,_) :- !, R=[]. |
| 262 | | unify_tuple_args([],[in(X)|T],R,Ch,Span) :- !, R=[], empty_tuple(X), unify_tuple_args([],T,_,Ch,Span). |
| 263 | | unify_tuple_args([],[H|T],_R,Ch,Span) :- !, |
| 264 | | translate_csp_value(dotTuple([H|T]),Xtra), |
| 265 | | ajoin(['Mismatch in number of arguments for synchronisation on channel ',Ch,' with extra argument(s): '],Msg), |
| 266 | | add_error_with_span(unify_tuple_args,Msg,Xtra,Span), |
| 267 | | fail. |
| 268 | | unify_tuple_args([H|T],[],R,Ch,Span) :- !, unify_tuple_args([],[H|T],R,Ch,Span). |
| 269 | | %unify_tuple_args([X],[Y],R,_Ch) :- !, unify_arg(X,Y,XY), R=[XY]. |
| 270 | | unify_tuple_args([in(X)|TAIL],V2,Res,Ch,Span) :- is_tuple(X,List),!, gen_ins(List,INList), |
| 271 | | append(INList,TAIL,NewV1), |
| 272 | | unify_tuple_args(NewV1,V2,Res,Ch,Span). |
| 273 | | unify_tuple_args([in(X)|TAIL],[H|T2],R,_Ch,Span) :- TAIL==[],!, R=[H|T2], |
| 274 | ? | unify_tuple_args2(T2,X,H,R,Span). |
| 275 | | unify_tuple_args(V1,[in(X)|TAIL],R,Ch,Span) :- is_tuple(X,List),!, gen_ins(List,INList), |
| 276 | | append(INList,TAIL,NewV2), |
| 277 | | unify_tuple_args(V1,NewV2,R,Ch,Span). |
| 278 | | unify_tuple_args([H|T2],[in(X)|TAIL],R,_Ch,Span) :- TAIL==[],!, |
| 279 | | /* only treat it as a tail_in(X) if it is definitely at the end of the list |
| 280 | | see example LetTestChannel -> TEST(2) process for complication if we do |
| 281 | | not check that TAIL==[] */ |
| 282 | | R=[H|T2], |
| 283 | ? | unify_tuple_args2(T2,X,H,R,Span). |
| 284 | | unify_tuple_args([X|T1],[Y|T2],R,Ch,Span) :- !, |
| 285 | ? | unify_arg(X,Y,XY,Span), R=[XY|RT], unify_values(T1,T2,RT,Ch,Span). |
| 286 | | unify_tuple_args(X,Y,R,Ch,Span) :- |
| 287 | | add_internal_error_with_span(csp_tuples,'Could not evaluate: ',unify_tuple_args(X,Y,R,Ch),Span), |
| 288 | | X=Y, R=X. |
| 289 | | |
| 290 | | is_tuple(X,List) :- nonvar(X), |
| 291 | | (X=tuple(List) -> true |
| 292 | | ; X = dotTuple(List) -> debug_println(9,unevaluated_dotTupleValue(List)) % can come from in(.) generated from inGuard |
| 293 | | ; X = dotpat(List)%, nl,print(unevaluated_dotpat(List)),nl % should't really happen |
| 294 | | ). |
| 295 | | |
| 296 | | :- block unify_tuple_args2(-,?,?,?,?). |
| 297 | ? | unify_tuple_args2(T2,X,H,R,Span) :- (T2=[] -> unify_arg(in(X),H,_,Span) ; X = tuple(R)). |
| 298 | | |
| 299 | | gen_ins([],[]). |
| 300 | | gen_ins([X|T],[in(X)|IT]) :- gen_ins(T,IT). |
| 301 | | |
| 302 | | /* DEAD CODE: unify_arg/3 will never be called, instead of that unify_arg/4 will be used. */ |
| 303 | | %unify_arg(A,B,R) :- unify_arg(A,B,R,no_loc_info_available). |
| 304 | | |
| 305 | | :- block unify_arg(-,?,?,?), unify_arg(?,-,?,?). |
| 306 | | unify_arg(in(X),in(Y),R,Span) :- !, direct_unify_values(X,Y,Span), R=in(X). |
| 307 | | unify_arg(in(X),Y,R,Span) :- !, |
| 308 | | valid_value(Y,unify_arg(in(X),Y),true,Span), |
| 309 | ? | direct_unify_values(Y,X,Span), R=X. |
| 310 | | unify_arg(X,in(Y),R,Span) :- !, |
| 311 | | valid_value(X,unify_arg(X,in(Y)),true,Span), |
| 312 | ? | direct_unify_values(X,Y,Span),R=Y. |
| 313 | ? | unify_arg(X,Y,R,Span) :- unify_arg2(X,Y,R,Span). |
| 314 | | |
| 315 | | unify_arg2(X,Y,Res,_Span) :- (var(X);var(Y)), !, X=Y,Res=X. |
| 316 | | unify_arg2(record(FX,XL),record(FY,YL),Res,Span) :- !, FX=FY, |
| 317 | ? | unify_values(XL,YL,RL,record(FX),Span),Res=record(FX,RL). |
| 318 | | unify_arg2(na_tuple(XL),na_tuple(YL),Res,Span) :- !, |
| 319 | | l_unify_arg(XL,YL,RL,Span), Res=na_tuple(RL). |
| 320 | | %unify_arg2(tuple(XL),tuple(YL),Res,Span) :- !, |
| 321 | | % l_unify_arg(XL,YL,RL,Span), Res=tuple(RL). |
| 322 | | %unify_arg(X,Y,X,Span) :- !,valid_value(X,unify_arg1(X,Y),false,Span),valid_value(Y,unify_arg2(X,Y),false,Span),X=Y. |
| 323 | | unify_arg2(X,Y,Res,Span) :- direct_unify_values(X,Y,Span),Res=X. |
| 324 | | %unify_arg(X,X,X,Span) :- valid_tuple_value(X,unify_arg(X,X),false,Span). |
| 325 | | |
| 326 | | |
| 327 | | direct_unify_values(X,Y,_Span) :- (var(X) ; var(Y)),!, X=Y. |
| 328 | | direct_unify_values(int(X),Y,Span) :- !,direct_unify_check(int(YY),Y,Span),X=YY. |
| 329 | | direct_unify_values(na_tuple(X),Y,Span) :- !,direct_unify_check(na_tuple(YY),Y,Span),X=YY. |
| 330 | | %direct_unify_values(tuple(X),Y,Span) :- !,direct_unify_check(tuple(YY),Y,Span),X=YY. |
| 331 | | direct_unify_values(list(X),Y,Span) :- !,direct_unify_check(list(YY),Y,Span),X=YY. |
| 332 | | direct_unify_values(X,X,_). |
| 333 | | |
| 334 | | direct_unify_check(Pattern,Value,Span) :- if(Pattern=Value,true, |
| 335 | | add_error_fail(direct_unify_check,'Unification type failure: ', '='(Value,Pattern, Span))). |
| 336 | | |
| 337 | | l_unify_arg([],[],R,_Span) :- !, R=[]. |
| 338 | | l_unify_arg([HX|TX],[HY|TY],R,Span) :- !, R = [HR|TR], |
| 339 | | unify_arg2(HX,HY,HR,Span), % calling unify_arg/4 here will not unify if one of the argments is variable |
| 340 | | l_unify_arg(TX,TY,TR,Span). |
| 341 | | l_unify_arg(X,Y,R,Span) :- add_internal_error_with_span(l_unify_arg,'Illegal lists to unify: ',l_unify_arg(X,Y,R),Span),fail. |
| 342 | | |
| 343 | | |
| 344 | | % check if we have a valid value |
| 345 | | :- block valid_value(-,?,?,?). |
| 346 | | valid_value(int(X),_,_,_) :- !, safe_number(X). |
| 347 | | valid_value(X,_,_,_) :- haskell_csp: valid_constant(X),!. |
| 348 | | valid_value(tuple(L),Value,AllowIn,Span) :- !,l_valid_tuple_value(L,Value,AllowIn,Span). |
| 349 | | valid_value(na_tuple(L),Value,AllowIn,Span) :- !, l_valid_value(L,Value,AllowIn,Span). |
| 350 | | valid_value(dotTuple(L),Value,AllowIn,Span) :- !, l_valid_value(L,Value,AllowIn,Span). |
| 351 | | valid_value(record(C,F),Value,AllowIn,Span) :- |
| 352 | ? | is_csp_constructor(C), !, l_valid_value(F,Value,AllowIn,Span). |
| 353 | | valid_value(true,_,_,_) :- !. |
| 354 | | valid_value(false,_,_,_) :- !. |
| 355 | | valid_value(list(List),OuterValue,AllowIn,Span) :- !, l_valid_value(List,OuterValue,AllowIn,Span). |
| 356 | | valid_value(setValue(List),OuterValue,AllowIn,Span) :- !, l_valid_value(List,OuterValue,AllowIn,Span). |
| 357 | | valid_value(setFrom(Low),OuterValue,AllowIn,Span) :- !, |
| 358 | | valid_value(Low,OuterValue,AllowIn,Span). |
| 359 | | valid_value(setFromTo(Low,Up),OuterValue,AllowIn,Span) :- !, |
| 360 | | valid_value(Low,OuterValue,AllowIn,Span), |
| 361 | | valid_value(Up,OuterValue,AllowIn,Span). |
| 362 | | valid_value(in(X),Value,AllowIn,Span) :- !, |
| 363 | | (AllowIn=true -> true % we allow the in/1 constructor |
| 364 | | ; add_internal_error(valid_value,'Input inside value: ',in(X):Value,Span) |
| 365 | | ). |
| 366 | | /* CSP-M constructors are asserted as valid constants. See second clause of valid_value/4 and |
| 367 | | the implementation of the valid_constant/1 predicate in the haskell_csp_analyzer module. |
| 368 | | Do we want to distinguish between valid_constants and csp constructors? */ |
| 369 | | %valid_value(C,OuterValue,_,Span) :- haskell_csp_analyzer: is_csp_constructor(C),!, |
| 370 | | % add_error_with_span(valid_value,'Warning: datatype constructor used as value: ',C:outer(OuterValue),Span). |
| 371 | | valid_value(Channel,OuterValue,_,Span) :- |
| 372 | | is_a_channel_name(Channel),!, % from haskell_csp_analyzer |
| 373 | | add_error_with_span(valid_value,'Warning: channel name used as value (should be wrapped in tuple): ',Channel:outer(OuterValue),Span). |
| 374 | | % should we generate a warning ? see e.g., angel2.csp |
| 375 | | |
| 376 | | /* This clause should call the add_internal_error_with_span/4 predicate. We have to complete the implementation of the valid_value/4 predicate. See TODO below. */ |
| 377 | | valid_value(X,OuterCall,_,Span) :- |
| 378 | | add_error_with_span(valid_value,'Warning: Illegal data value: ',X:outer(OuterCall),Span). |
| 379 | | /* to do: add sets,sequences,...*/ |
| 380 | | |
| 381 | | :- block valid_tuple_value(-,?,?,?). |
| 382 | | valid_tuple_value(C,_,_,_Span) :- |
| 383 | | is_csp_constructor(C),!. % from haskell_csp_analyzer; here it could be ok to use datatype constructor |
| 384 | | valid_tuple_value(X,V,A,Span) :- valid_value(X,V,A,Span). |
| 385 | | |
| 386 | | :- block safe_number(-). |
| 387 | | safe_number(X) :- number(X). |
| 388 | | |
| 389 | | :- block l_valid_value(-,?,?,?). |
| 390 | | l_valid_value([],_,_AllowIn,_Span). |
| 391 | | l_valid_value([H|T],Value,AllowIn,Span) :- valid_value(H,Value,AllowIn,Span), l_valid_value(T,Value,AllowIn,Span). |
| 392 | | |
| 393 | | :- block l_valid_tuple_value(-,?,?,?). |
| 394 | | l_valid_tuple_value([],_,_AllowIn,_Span). |
| 395 | | l_valid_tuple_value([H|T],Value,AllowIn,Span) :- valid_tuple_value(H,Value,AllowIn,Span), l_valid_tuple_value(T,Value,AllowIn,Span). |
| 396 | | |
| 397 | | % -------------------------------------------------------------------- |
| 398 | | |
| 399 | | :- block list_projection(-,?,?,?,?), list_projection(?,-,?,?,?), list_projection(?,?,-,?,?). |
| 400 | | list_projection(Nr,Len,list(List),Res,Span) :- !, list_projection2(Nr,Len,List,Res,Span). |
| 401 | | list_projection(Nr,Len,Tuple,_,Span) :- !, |
| 402 | | add_error_with_span(list_projection,'Could not match list pattern: ', Nr/Len/Tuple,Span),fail. |
| 403 | | :- block list_projection2(?,?,-,?,?). |
| 404 | | list_projection2(Nr,Len,List,Res,Span) :- |
| 405 | | (nth1(Nr,List,Res) -> |
| 406 | | (length(List,Len) -> |
| 407 | | true |
| 408 | | ; add_error_with_span(list_projection,'List is not of the right length for pattern: ',Len/list(List),Span) |
| 409 | | ) |
| 410 | | ; add_error_with_span(list_projection,'List is too short for pattern: ',Nr/list(List),Span),fail |
| 411 | | ). |
| 412 | | |
| 413 | | :- block na_tuple_projection(-,?,?,?), na_tuple_projection(?,-,?,?). |
| 414 | | na_tuple_projection(Nr,na_tuple(List),Res,Span) :- !, |
| 415 | | (nth1(Nr,List,Res) -> |
| 416 | | true |
| 417 | | ; add_error_with_span(csp_tuples,'NA Tuple is too small for pattern: ',Nr/na_tuple(List),Span),fail |
| 418 | | ). |
| 419 | | na_tuple_projection(Nr,Tuple,_,Span) :- !, |
| 420 | | add_error_with_span(csp_tuples,'Could not match na_tuple pattern: ', Nr/Tuple,Span),fail. |
| 421 | | |
| 422 | | :- block tuple_projection(-,?,?,?), tuple_projection(?,-,?,?). |
| 423 | | %tuple_projection(Nr,E,_,_) :- print(proj(Nr,E)),nl,fail. |
| 424 | | tuple_projection(Nr,tuple(List),Res,Span) :- !, |
| 425 | | (nth1(Nr,List,Res) -> |
| 426 | | true |
| 427 | | ; add_error_with_span(csp_tuples,'Tuple is too small for pattern: ',Nr/tuple(List),Span),fail |
| 428 | | ). |
| 429 | | %tuple_projection(Nr,list(List),Res,Span) :- !, |
| 430 | | % (nth1(Nr,List,Res) -> add_error_with_span(csp_tuples,'Warning: projecting on list: ',Nr/List,Span) |
| 431 | | % ; add_error_with_span(csp_tuples,'Could not project: ',Nr/list(List),Span),fail). |
| 432 | | tuple_projection(Nr,Tuple,_,Span) :- !, |
| 433 | | add_error_with_span(csp_tuples,'Could not match tuple pattern: ', Nr/Tuple,Span),fail. |
| 434 | | |