1 | % (c) 2009-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
2 | % Heinrich Heine Universitaet Duesseldorf | |
3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
4 | ||
5 | :- module(haskell_csp,[%clear_cspm_spec/0, % triggerred by clear specification event | |
6 | parse_and_load_cspm_file/1, load_cspm_pl_file/1, | |
7 | ||
8 | cspm_trans_enum/3, | |
9 | animatable_process/1, animatable_process_cli/1,animatable_process_without_arguments/1, | |
10 | channel/2, %cspPrintCompiled/2, | |
11 | evaluate_argument/2, force_evaluate_argument/2, evaluate_int_argument/2, | |
12 | force_evaluate_argument_for_member_check/2, | |
13 | check_boolean_expression/1, | |
14 | ||
15 | enumerate_channel_input_value/4, | |
16 | enumerate_datatype_el/5, | |
17 | ||
18 | is_a_datatype/2, csp_constructor/3, | |
19 | %% csp_full_type_constructor/3,csp_full_type_constant/2, % exported by haskell_csp_analyzer.pl | |
20 | dataTypeDef/2, | |
21 | channel_type_list/2, | |
22 | agent_compiled/3, % called in slicer_csp.pl ??? | |
23 | is_not_infinite_type/1, | |
24 | channel_type_is_finite/2, | |
25 | get_symbol_span/2, | |
26 | extract_span_from_event/4, extract_span_info/2, | |
27 | get_internal_csp_representation/1, | |
28 | get_csp_assertions_as_string/2,get_csp_assertions/1, get_csp_processes/1, | |
29 | translate_csp_assertion/2, %translate_csp_assertions/2, %get_csp_assertions_enum/2, | |
30 | parse_and_load_cspm_file_into_specific_pl_file/2, | |
31 | evaluate_type_list/2, | |
32 | %% get_formula_from_cspm_file/2, | |
33 | filter_formulas_from_pragmas/3, | |
34 | add_error_with_span/4,add_internal_error_with_span/4, | |
35 | evaluate_csp_expression/2,evaluate_csp_expression/3, parse_single_csp_expression/3, | |
36 | parse_single_csp_declaration/3, | |
37 | add_symbol_error/4, | |
38 | bindval/3, agent/3, agent_curry/3, subTypeDef/2, nameType/2, | |
39 | symbol/4, cspTransparent/1, cspPrint/1, valid_constant/1, | |
40 | parse_single_csp_expression_file/3, | |
41 | %% perform_csp_self_check/0, | |
42 | normalise_cspm_state/2, | |
43 | check_compiled_term/1 | |
44 | ]). | |
45 | ||
46 | ||
47 | :- use_module(probsrc(module_information)). | |
48 | :- module_info(group,csp). | |
49 | :- module_info(description,'Interpreter for CSP.'). | |
50 | ||
51 | :- use_module(library(lists)). | |
52 | :- use_module(library(file_systems)). | |
53 | %% :- use_module(library(process)). | |
54 | %% :- use_module(library(system)). | |
55 | ||
56 | /* the new CSP interpreter using the format produced by | |
57 | Marc's Haskell compiler fecsp/cspcomp */ | |
58 | ||
59 | /********* PROB modules *********/ | |
60 | :- use_module(probsrc(error_manager)). | |
61 | :- use_module(probsrc(self_check)). | |
62 | :- use_module(probsrc(debug)). | |
63 | :- use_module(probsrc(typechecker)). | |
64 | :- use_module(probsrc(kernel_objects),[top_level_dif/2,enumerate_basic_type/3]). | |
65 | :- use_module(probsrc(tools),[string_concatenate/3,flatten/2,split_atom/3]). | |
66 | :- use_module(probsrc(preferences),[preference/2, set_preference/2, get_preference/2,init_preferences/0]). | |
67 | :- use_module(probsrc(system_call),[system_call/4,system_call/5, get_writable_compiled_filename/3]). | |
68 | :- use_module(probsrc(kernel_waitflags)). | |
69 | :- use_module(probsrc(translate),[translate_cspm_state/2,translate_cspm_expression/2]). | |
70 | :- use_module(probsrc(specfile),[process_algebra_mode/0,csp_with_bz_mode/0,currently_opened_file/1]). | |
71 | /******** ------------ *********/ | |
72 | ||
73 | /* Predicate for performing self check for all CSP modules */ | |
74 | ||
75 | :- public perform_general_csp_self_check/0. | |
76 | perform_general_csp_self_check :- | |
77 | perform_csp_self_check, | |
78 | get_preference(use_clpfd_solver,Value), | |
79 | (Value=false -> | |
80 | NewValue = true | |
81 | ; NewValue = false), | |
82 | set_preference(use_clpfd_solver,NewValue), | |
83 | perform_csp_self_check, | |
84 | % reverting to the old use_clpfd_solver preference | |
85 | set_preference(use_clpfd_solver,Value). | |
86 | ||
87 | perform_csp_self_check :- | |
88 | init_preferences, | |
89 | perform_self_check(csp_basic), | |
90 | perform_self_check(csp_tuples), | |
91 | perform_self_check(csp_sequences), | |
92 | perform_self_check(csp_sets), | |
93 | perform_self_check(haskell_csp), | |
94 | perform_self_check(haskell_csp_analyzer). | |
95 | ||
96 | /* ------------------------------------- */ | |
97 | ||
98 | ||
99 | :- dynamic channel/2, bindval/3, agent/3, agent_curry/3, dataTypeDef/2, subTypeDef/2. | |
100 | :- dynamic nameType/2, symbol/4, cspTransparent/1, cspPrint/1, assertRef/5. | |
101 | :- dynamic assertModelCheck/3, assertModelCheckExt/4, pragma/1. | |
102 | %:- dynamic assertLtl/4, assertCtl/4. % dynamic declarations still generated by parser it seems, but not used | |
103 | ||
104 | :- discontiguous channel/2, agent/3, bindval/3, assertModelCheck/3. | |
105 | ||
106 | :- use_module(probcspsrc(haskell_csp_analyzer)). | |
107 | :- use_module(probcspsrc(csp_tuples)). | |
108 | :- use_module(probcspsrc(csp_sets)). | |
109 | :- use_module(probcspsrc(csp_basic)). | |
110 | ||
111 | /* ------------------------------------- */ | |
112 | /* Sample .pl Translation of a CSP file */ | |
113 | ||
114 | dataTypeDef('FRUIT',[constructor(apples),constructor(oranges),constructor(pears)]). | |
115 | channel(left,type(dotTupleType(['FRUIT']))). | |
116 | bindval('SEND',prefix(span,[in(_x)],left,prefix(span,[out(_x)],mid,prefix(span,[],ack,val_of('SEND',no_loc_info_available))),span2),span). | |
117 | symbol('SEND','SEND',src,'Process'). | |
118 | ||
119 | ||
120 | :- use_module(probsrc(eventhandling),[register_event_listener/3]). | |
121 | :- register_event_listener(start_unit_tests,reset_for_selfcheck,'Setup CSP dataTypeDef, channel,..'). | |
122 | %:- register_event_listener(stop_unit_tests, set_silent(false), 'Printing wf warnings again'). | |
123 | ||
124 | reset_for_selfcheck :- % TO DO: reset all facts and link with event_handling | |
125 | clear_cspm_spec, | |
126 | retractall(dataTypeDef(_,_)), | |
127 | assert( dataTypeDef('FRUIT',[constructor(apples),constructor(oranges),constructor(pears)])), | |
128 | /* for testing is_not_infinite_type predicate */ | |
129 | assert( dataTypeDef('Msg',[constructor('A'),constructor('B'),constructorC('con',dotTupleType(['SubMsg']))]) ), | |
130 | assert( dataTypeDef('Msg1',[constructor('A'),constructor('B')]) ), | |
131 | assert( dataTypeDef('SubMsg',[constructor('KA'), | |
132 | constructorC(conc,dotTupleType(['Msg'])),constructorC(ste,dotTupleType([builtin_call('Seq'('Msg'))]))]) ), | |
133 | assert( dataTypeDef('Inf',[constructorC(ste,dotTupleType([builtin_call('Seq'('FRUIT'))]))]) ), | |
134 | retractall( channel(_,_)), | |
135 | assert( channel(left,type(dotTupleType(['FRUIT']))) ), | |
136 | assert( channel(right,type(dotTupleType(['FRUIT']))) ), | |
137 | assert( channel(mid,type(dotTupleType(['FRUIT']))) ), | |
138 | assert( channel(receive,type(dotTupleType(['Msg']))) ), | |
139 | assert( channel(infinite,type(dotTupleType(['Inf']))) ), | |
140 | retractall( bindval(_,_,_) ), | |
141 | assert( bindval('SEND', | |
142 | prefix(no_loc_info_available,[in(_x)],left, | |
143 | prefix(no_loc_info_available,[out(_x)],mid, | |
144 | prefix(no_loc_info_available,[],ack,val_of('SEND',no_loc_info_available),no_loc_info_available), | |
145 | no_loc_info_available), | |
146 | no_loc_info_available),no_loc_info_available) ), | |
147 | assert( bindval('REC',prefix(no_loc_info_available,[in(_x)],mid, | |
148 | prefix(no_loc_info_available,[out(_x)],right, | |
149 | prefix(no_loc_info_available,[],ack,val_of('REC',no_loc_info_available),no_loc_info_available), | |
150 | no_loc_info_available),no_loc_info_available),no_loc_info_available) ), | |
151 | assert( bindval('SYSTEM',sharing(closure([mid,ack]),val_of('SEND',no_loc_info_available), | |
152 | val_of('REC',no_loc_info_available),no_loc_info_available),no_loc_info_available) ), | |
153 | assert( bindval('GEN1', | |
154 | prefix(no_loc_info_available,[out(oranges)], | |
155 | left, | |
156 | prefix(no_loc_info_available,[out(oranges)],right,val_of('GEN2',no_loc_info_available),no_loc_info_available), | |
157 | no_loc_info_available),no_loc_info_available) ), | |
158 | assert( bindval('GEN2', | |
159 | prefix(no_loc_info_available,[out(pears)],left, | |
160 | prefix(no_loc_info_available,[out(pears)], | |
161 | right,val_of('GEN1',no_loc_info_available),no_loc_info_available),no_loc_info_available),no_loc_info_available) ), | |
162 | assert( bindval('MAIN',sharing(closure([left,right]),val_of('SYSTEM',no_loc_info_available),val_of('GEN1',no_loc_info_available),no_loc_info_available),no_loc_info_available) ), | |
163 | assert( bindval('P1',agent_call(no_loc_info_available,'Q',[int(10)]),no_loc_info_available) ), | |
164 | retractall(agent(_,_,_)), | |
165 | assert( agent('P'(_),'prefix'('src_span'(8,8,8,9,87,1),['in'(_i2)],'c', | |
166 | 'prefix'('src_span'(8,15,8,16,94,1),['out'(_i2)],'c', | |
167 | 'stop'('src_span'(8,22,8,26,101,4)),'src_span'(8,19,8,21,97,10)), | |
168 | 'src_span'(8,12,8,14,90,17)),'src_span'(8,8,8,26,87,18)) ), | |
169 | %assert( agent('P2'(_n),agent_call(no_loc_info_available,'Q',['-'(_n, int(10))]),no_loc_info_available) ), | |
170 | %assert( agent('P1',agent_call(no_loc_info_available,'Q',[int(10)]),no_loc_info_available) ), | |
171 | assert( agent('Q'(_n),ifte('=='(_n,int(0)),stop(no_loc_info_available), | |
172 | prefix(no_loc_info_available,[],'a', | |
173 | agent_call(no_loc_info_available,'Q',['-'(_n,'int'(1))]),no_loc_info_available), | |
174 | no_loc_info_available,no_loc_info_available,no_loc_info_available),no_loc_info_available) ), | |
175 | retractall(symbol(_,_,_,_)), | |
176 | assert( symbol('SEND','SEND',src,'Process') ), | |
177 | assert( symbol('REC','REC',src(8,1,8,4,4,3),'Procsess') ), | |
178 | assert( symbol('SYSTEM','SYSTEM',src,'Process') ), | |
179 | assert( symbol('GEN1','GEN1',src,'Process') ), | |
180 | assert( symbol('GEN2','GEN2',src,'Process') ), | |
181 | assert( symbol('MAIN','MAIN',src(3,1,3,5,20,4),'Process') ), | |
182 | retractall(assertRef(_,_,_,_,_)), | |
183 | assert( assertRef('False','val_of'('MAIN',no_loc_info_available),'Trace', | |
184 | 'val_of'('PROB_TEST_TRACE',no_loc_info_available),no_loc_info_available) ), | |
185 | assert( assertRef('True', 'val_of'('PROB_TEST_TRACE',no_loc_info_available), | |
186 | 'Trace', 'val_of'('MAIN',no_loc_info_available),no_loc_info_available) ), | |
187 | retractall(assertModelCheckExt(_,_,_,_)), | |
188 | assert( assertModelCheckExt('False', | |
189 | sharing(closure([left,right]),val_of('SYSTEM',no_loc_info_available), | |
190 | val_of('GEN1',no_loc_info_available),no_loc_info_available), 'Deterministic','F') ), | |
191 | assert( assertModelCheckExt('True', | |
192 | sharing(closure([left,right]),val_of('SYSTEM',no_loc_info_available), | |
193 | val_of('GEN1',no_loc_info_available),no_loc_info_available), 'DeadlockFree','FD') ), | |
194 | retractall(assertModelCheck(_,_,_)), | |
195 | assert( assertModelCheck('False', | |
196 | 'prefix'(no_loc_info_available,[],'dotTuple'(['a','int'(1)]), | |
197 | 'val_of'('P',no_loc_info_available),no_loc_info_available),'LivelockFree')), | |
198 | retractall(pragma(_)), | |
199 | assert(pragma('assert_ltl "GF(a)"')), | |
200 | assert(pragma('ASSERT_LTL "GF(b)"')), | |
201 | assert(pragma('ASSERT_LTL_TRUE "true"')), | |
202 | haskell_csp_analyzer:analyze. | |
203 | ||
204 | ||
205 | % these predicates are generated by the csp analyzer, there are not the standard generated predicates from the translation | |
206 | % process csp -> pl | |
207 | ||
208 | /* ------------------------------------- */ | |
209 | ||
210 | /* ------------------------------------- */ | |
211 | ||
212 | animatable_process_without_arguments(X) :- | |
213 | symbol(RenamedX,X,_,_), | |
214 | (is_csp_process(RenamedX);is_possible_csp_process(RenamedX)). | |
215 | ||
216 | animatable_process(X) :- | |
217 | (symbol(RenamedX,X,_,_),(is_csp_process(RenamedX);is_possible_csp_process(RenamedX))) ; | |
218 | (nonvar(X), X=agent_call(_Src,_F,_Args)) ; | |
219 | (nonvar(X), X=agent_call_curry(_F,_Args)) ; | |
220 | (agent(F,_,_),is_csp_process(F),animatable_process_with_arguments(F,proc(FName,N)),proc_with_arguments_to_string(FName,N,X)). | |
221 | ||
222 | animatable_process_cli(X) :- | |
223 | symbol(RenamedX,X,_,_), | |
224 | (is_csp_process(RenamedX) ; is_possible_csp_process(RenamedX)). | |
225 | ||
226 | animatable_process_with_arguments(X,proc(F,N)) :- | |
227 | functor(X,F,N),N>0. | |
228 | ||
229 | check_compiled_term(Term) :- | |
230 | nonvar(Term),!, | |
231 | Term=agent_call(_Src,F,Args), | |
232 | length(Args,N), | |
233 | ( (symbol(RenamedF,F,_,_),functor(P,RenamedF,N),is_csp_process(P)) -> | |
234 | true | |
235 | ; translate_cspm_state(Term,Proc), | |
236 | add_error_fail(check_compiled_term, 'There is no such process in file: ',Proc) | |
237 | ). | |
238 | ||
239 | /* ------------------------------------- */ | |
240 | ||
241 | /* Predicates for calling the CSPM Parser and loading the corresponding to the Csp File Prolog File */ | |
242 | ||
243 | parse_and_load_cspm_file(CSPFile) :- | |
244 | get_writable_compiled_filename(CSPFile,'.pl',PrologFile), | |
245 | print_message(informational,reading_cspm_file(CSPFile,PrologFile)), | |
246 | debug_println(15,reading_cspm_file(CSPFile)), | |
247 | get_cspm_parser_command(AbsParseCmd), | |
248 | print_message(informational,system_call(AbsParseCmd)), | |
249 | debug_println(5,parsecmd(AbsParseCmd)), | |
250 | string_concatenate('--prologOut=', PrologFile, PrologFileOutArg), | |
251 | debug_stats(parsing(AbsParseCmd,'translate',PrologFileOutArg, CSPFile)), | |
252 | system_call(AbsParseCmd, ['translate',PrologFileOutArg, CSPFile], Text,JExit), debug_stats(done_parsing), | |
253 | debug_println(15,parse_exit(JExit)), | |
254 | (JExit=exit(0) | |
255 | -> load_cspm_pl_file(PrologFile,CSPFile) | |
256 | ; add_error(parse_and_load_cspm_file,'Error while parsing CSP file: ',CSPFile), | |
257 | atom_codes(T,Text), | |
258 | add_error_fail(parse_and_load_cspm_file,'Std error: ',T) | |
259 | ). | |
260 | ||
261 | %% parse_and_load_cspm_file(CSPFile) :- | |
262 | %% (parsercall: call_cspmj_parser(CSPFile,PrologFile) | |
263 | %% -> load_cspm_pl_file(PrologFile,CSPFile) | |
264 | %% ; add_error(parse_and_load_cspm_file,'Error while parsing CSP file: ',CSPFile), | |
265 | %% add_error_fail(parse_and_load_cspm_file,'Std error: ','to be added') | |
266 | %% ). | |
267 | ||
268 | /* Specific predicate for parsing and re-writting the Parse-Output into already existing prolog file.*/ | |
269 | % It will be needed by parsing a temporary files when the Csp Assertion Viewer is used. | |
270 | parse_and_load_cspm_file_into_specific_pl_file(CSPFile, PrologFile) :- | |
271 | get_cspm_parser_command(AbsParseCmd), | |
272 | string_concatenate('--prologOut=', PrologFile, PrologFileOutArg), | |
273 | system_call(AbsParseCmd, ['translate',PrologFileOutArg, CSPFile], Text,JExit), | |
274 | debug_println(15,parse_exit(JExit)), | |
275 | (JExit=exit(0) | |
276 | -> load_cspm_pl_file(PrologFile,CSPFile) | |
277 | ; add_internal_error('Error while parsing CSP file: ',CSPFile), | |
278 | atom_codes(T,Text), | |
279 | add_error_fail(parse_and_load_cspm_file,'Std error: ',T) | |
280 | ). | |
281 | ||
282 | parse_single_csp_declaration(Decl,CSPFile,Result) :- | |
283 | get_cspm_parser_command(Cmd), | |
284 | string_concatenate('--declarationToPrologTerm=', Decl, DeclarationArgument), | |
285 | system_call(Cmd, ['translate', DeclarationArgument, CSPFile],Text,ErrText,JExit), | |
286 | (JExit=exit(0) | |
287 | -> read_from_codes(Text,Result) | |
288 | ; atom_codes(ErrT,ErrText), | |
289 | add_error_fail(parsing_csp_declaration,'Std error: ',ErrT) | |
290 | ). | |
291 | ||
292 | :- use_module(probsrc(xtl_interface),[last_opened_cspm_file/1]). | |
293 | parse_single_csp_expression(Context,Expr,Res) :- | |
294 | ( Context==eval -> Filename='no-file' | |
295 | ; Context==ltl -> | |
296 | (csp_with_bz_mode | |
297 | -> last_opened_cspm_file(Filename) | |
298 | ; currently_opened_file(Filename) | |
299 | ) | |
300 | ; otherwise -> add_internal_error('Internal Error: Unknown context argument: ', Context),fail | |
301 | ), | |
302 | parse_single_csp_expression_file(Expr,Filename,Res). | |
303 | ||
304 | :- use_module(library(codesio)). | |
305 | parse_single_csp_expression_file(Expr,CSPFile,Res) :- | |
306 | get_cspm_parser_command(Cmd), | |
307 | string_concatenate('--expressionToPrologTerm=', Expr, ExpressionArgument), | |
308 | system_call(Cmd, ['translate', ExpressionArgument, CSPFile],Text,ErrText,JExit), | |
309 | (JExit=exit(0) | |
310 | -> read_from_codes(Text,Result), | |
311 | translate_expression(Result,Res) | |
312 | ; atom_codes(ErrT,ErrText), | |
313 | add_error_fail(parsing_csp_expression,'Std error: ',ErrT) | |
314 | ). | |
315 | ||
316 | evaluate_csp_expression(Expr,Result) :- | |
317 | ( parse_single_csp_expression(eval,Expr,ParsedExpr) -> | |
318 | evaluate_parsed_csp_expression(ParsedExpr,Expr,Result) | |
319 | ; add_error_fail(parsing_csp_expression, 'Error while parsing expression: ', Expr) | |
320 | ). | |
321 | ||
322 | evaluate_parsed_csp_expression(ParsedExpr,Expr,Result) :- | |
323 | debug_println(9,parsed_csp_expression(ParsedExpr)), | |
324 | haskell_csp_analyzer:compile_body(ParsedExpr,'evaluate',[],[],CompiledExpr), | |
325 | ( evaluate_expression_with_timing(CompiledExpr,Res) -> | |
326 | ( translate_cspm_expression(Res, R) -> R=Result | |
327 | ; add_error_fail(pretty_printing_evaluated_expression, 'Error while pretty-printing result: ', Res) | |
328 | ) | |
329 | ; add_error_fail(evaluating_expression, 'Error while evaluating expression: ',Expr) | |
330 | ). | |
331 | ||
332 | evaluate_csp_expression(Expr,CSPFile,Result) :- | |
333 | ( parse_single_csp_expression_file(Expr, CSPFile,ParsedExpr) -> | |
334 | evaluate_parsed_csp_expression(ParsedExpr,Expr,Result) | |
335 | ; add_error_fail(parsing_csp_expression, 'Error while parsing typed expression: ', Expr) | |
336 | ). | |
337 | ||
338 | :- use_module(probsrc(tools),[cputime/1]). | |
339 | evaluate_expression_with_timing(ParsedExpr,Res) :- | |
340 | cputime(T1), | |
341 | evaluate_expression(ParsedExpr,Res), | |
342 | cputime(T2), | |
343 | D is T2-T1, | |
344 | print('% Time to evaluate expression: '),print(D), print(' ms.%'),nl. | |
345 | ||
346 | % TODO: Which are the expressions allowed to be written in events | |
347 | translate_expression(listExp(rangeEnum(List)),list(List)). | |
348 | translate_expression(setExp(rangeEnum(List)),setValue(List)). | |
349 | translate_expression(dotTuple(List),dotTuple(Res)) :- | |
350 | maplist(translate_expression,List,Res). | |
351 | translate_expression(X,X). | |
352 | ||
353 | :- meta_predicate read_compiled_prolog_file(-,-,1). | |
354 | /* Predicates for reading a Prolog file (usually generated after translating the appropriate Csp file with the CSPM-Tool) | |
355 | and filtering the asssertion declarations from it. Needed for the 'Check Csp Assertions' window in Tcl_Tk. */ | |
356 | read_compiled_prolog_file(CSPFile,Result,PredName) :- | |
357 | get_writable_compiled_filename(CSPFile,'.pl', PrologFile), | |
358 | debug_print(9,'opening Prolog file: '), debug_println(9,PrologFile), | |
359 | my_see(PrologFile), | |
360 | call(PredName,Result), | |
361 | !,seen,debug_println(9,done). | |
362 | ||
363 | my_see(File) :- | |
364 | on_exception(error(existence_error(_,_),_), | |
365 | see(File), | |
366 | add_error_fail(my_see,'File does not exist: ',File)). | |
367 | ||
368 | filter_assertion_declarations(Assertions) :- | |
369 | read(Term), !, | |
370 | ((Term = end_of_file) -> (Assertions = []) | |
371 | ; (is_assertion(Term) | |
372 | -> (Assertions = [Term|T]) | |
373 | ; (Assertions = T) | |
374 | ), filter_assertion_declarations(T) | |
375 | ). | |
376 | ||
377 | :- assert_must_succeed((is_assertion(assertRef(_,_,_,_,_)),is_assertion(assertModelCheck(_,_,_)), is_assertion(assertModelCheckExt(_,_,_,_)))). | |
378 | ||
379 | is_assertion(assertRef(_,_,_,_,_)). | |
380 | is_assertion(assertModelCheck(_,_,_)). | |
381 | is_assertion(assertModelCheckExt(_,_,_,_)). | |
382 | is_assertion(assertLtl(_,_,_,_)). | |
383 | is_assertion(assertCtl(_,_,_,_)). | |
384 | ||
385 | filter_formulas_from_pragmas(Type,FlNList,FlFList) :- | |
386 | findall(Formulas,(pragma(S),get_formulas_from_pragma(Type,pragma(S),_Names,Formulas)),FList), | |
387 | findall(Names,(pragma(S),get_formulas_from_pragma(Type,pragma(S),Names,_Formulas)),NList), | |
388 | flatten(NList,FlNList), | |
389 | flatten(FList,FlFList). | |
390 | ||
391 | get_formula_from_cspm_file(Type,Formula) :- | |
392 | filter_formulas_from_pragmas(Type,_Ns,[String|_]), | |
393 | (var(String) -> | |
394 | Formula = '' | |
395 | ; Formula=String | |
396 | ). | |
397 | ||
398 | get_formulas_from_cspm_file(Type,String) :- | |
399 | filter_formulas_from_pragmas(Type,_Ns,Formulas), | |
400 | convert_string_list_to_string(Formulas,String). | |
401 | ||
402 | string_concatenate_sep(Sep,Atom,R) :- | |
403 | string_concatenate(Atom,Sep,R). | |
404 | ||
405 | convert_string_list_to_string(L,Res) :- | |
406 | maplist(string_concatenate_sep(';'),L,LRes), | |
407 | concatenate_string_list(LRes,Res). | |
408 | ||
409 | get_formulas_from_pragma(Type,pragma(Str),Names,Formulas) :- | |
410 | atom_codes(Str,CodeList), | |
411 | (Type = ltl -> | |
412 | ltl_equations(Names,Formulas,CodeList,[]) | |
413 | ;Type = ctl -> | |
414 | ctl_equations(Names,Formulas,CodeList,[]) | |
415 | ; otherwise -> | |
416 | Names=[], Formulas=[] | |
417 | ). | |
418 | ||
419 | %%%%%%%%%%%%%%%%%% Tests for the ASSERT_LTL Equations Parser below %%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
420 | ||
421 | :- assert_must_succeed((haskell_csp:reset_for_selfcheck)). | |
422 | :- assert_must_succeed((haskell_csp: get_formulas_from_pragma(ltl,pragma('ASSERT_LTL_123=="F(e(a))" "Checking simple LTL property."'), | |
423 | Names,Formulas),Names==[123],Formulas==['F(e(a))'])). | |
424 | :- assert_must_fail((haskell_csp: get_formulas_from_pragma(ltl,pragma('ASSERT_LTL_0123=="F(e(a))" "First digit in number must be nonzero."'), | |
425 | _Names,_Formulas))). | |
426 | :- assert_must_succeed((haskell_csp: get_formulas_from_pragma(ltl,pragma('ASSERT_LTL=="F(e(a))"'), | |
427 | Names,Formulas),Names==[[95]],Formulas==['F(e(a))'])). | |
428 | :- assert_must_succeed((haskell_csp: get_formulas_from_pragma(ltl,pragma('assert_ltl "F(e(a))" "Checking simple LTL property."'), | |
429 | Names,Formulas),Names==[[95]],Formulas==['F(e(a))'])). | |
430 | :- assert_must_succeed((haskell_csp: get_formulas_from_pragma(ctl,pragma('assert_ctl "true" "Checking simple CTL property."'), | |
431 | Names,Formulas),Names==[[95]],Formulas==['true'])). | |
432 | :- assert_must_succeed((haskell_csp: get_formulas_from_pragma(ltl,pragma('assert_ltl "F(e(a))" "Parsing multiple LTL equations."; ASSERT_LTL_TRUE "F(e(b))"; ASSERT_LTL_2=="F(e(c))"; ASSERT_LTL "F(e(d))"'), | |
433 | Names,Formulas),Names==[[95],[84,82,85,69],2,[95]],Formulas==['F(e(a))','F(e(b))','F(e(c))','F(e(d))'])). | |
434 | :- assert_must_succeed(( | |
435 | haskell_csp: get_formulas_from_cspm_file(ltl,S), S == 'GF(a);GF(b);true;')). | |
436 | :- assert_must_succeed(( | |
437 | haskell_csp: get_formula_from_cspm_file(ltl,S), S == 'GF(a)')). | |
438 | ||
439 | %%%%%%%%%%%%%%%%%% Simple Parser for Parsing ASSERT_LTL Equations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
440 | ||
441 | %%%%%%%%%%%%% CTL assertions %%%%%%%%%%%%%%% | |
442 | ctl_equations([N|Ns],[F|Fs]) --> ctl_equation(N,F),ctl_equations2(Ns,Fs). | |
443 | ctl_equations2(Ns,Fs) --> ows,sep,ows,ctl_equations(Ns,Fs),{Fs\=[],Ns\=[]}. | |
444 | ctl_equations2([],[]) --> ows. | |
445 | ||
446 | ctl_equation(N,F) --> ows,assert_id_ctl(N), ows, eq,!, ows, string(F), ows, optional_string. | |
447 | ||
448 | assert_id_ctl(N) --> ass_ctl,!,name(N). | |
449 | assert_id_ctl(N) --> "assert_ctl",{N="_"},!. | |
450 | assert_id_ctl(N) --> "ASSERT_CTL",{N="_"},!. | |
451 | ||
452 | ass_ctl --> "ASSERT_CTL_". | |
453 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
454 | ||
455 | ltl_equations([N|Ns],[F|Fs]) --> ltl_equation(N,F),ltl_equations2(Ns,Fs). | |
456 | ltl_equations2(Ns,Fs) --> ows,sep,ows,ltl_equations(Ns,Fs),{Fs\=[],Ns\=[]}. | |
457 | ltl_equations2([],[]) --> ows. | |
458 | ||
459 | ltl_equation(N,F) --> ows,assert_id_ltl(N), ows, eq,!, ows, string(F), ows, optional_string. | |
460 | ||
461 | string(Atom) --> [34], stringcontent(String), [34], {atom_codes(Atom,String)}. %34 is Ascii Code of " | |
462 | ||
463 | optional_string --> [34], stringcontent(_String), [34],!. | |
464 | optional_string --> "",!. | |
465 | ||
466 | stringcontent([C|Rest]) --> [C], {C \= 34}, !, stringcontent(Rest). | |
467 | stringcontent([]) --> []. | |
468 | ||
469 | assert_id_ltl(N) --> ass,!,name(N). | |
470 | assert_id_ltl(N) --> "assert_ltl",{N="_"},!. | |
471 | assert_id_ltl(N) --> "ASSERT_LTL",{N="_"},!. | |
472 | ||
473 | name(N) --> num(N),{number(N)},!. | |
474 | name(N) --> ident(N),!. | |
475 | ||
476 | ident([C|Cs]) --> [C],{member(C,"0123456789"); ("A" =< C,C =< "Z");("a" =< C,C =< "z");C="_"},ident(Cs),!. | |
477 | ident([]) --> [],!. | |
478 | ||
479 | num(Number) --> nonzerodigit(D), num2(Rest),{number_codes(Number,[D|Rest])}. | |
480 | num(Number) --> digit(D),{number_codes(Number,[D])}. | |
481 | num2([D|Rest]) --> digit(D),!,num2(Rest). | |
482 | num2([]) --> []. | |
483 | ||
484 | digit(D) --> [D], {member(D,"0123456789")},!. | |
485 | nonzerodigit(ND) --> [ND], {member(ND,"123456789")},!. | |
486 | ||
487 | sep --> [C],{member(C,";,")}. | |
488 | ||
489 | ows --> [C], {member(C," \t\n\r")}, !, ows. | |
490 | ows --> "". | |
491 | ||
492 | eq --> "==",!. | |
493 | eq --> [32],!. | |
494 | eq --> "",!. | |
495 | ||
496 | ass --> "ASSERT_LTL_",!. | |
497 | ||
498 | /* ------------------------------------------------------------------------------------------------------------- */ | |
499 | ||
500 | /* Predicates for getting the CSPM-Tool command from the library and loading cspm Prolog files.*/ | |
501 | get_cspm_parser_command(AbsParseCmd) :- | |
502 | debug_println(9,getting_parser_cmd), | |
503 | on_exception(error(E,_), | |
504 | absolute_file_name(prob_lib(cspmf),AbsParseCmd,[access(exist),extensions(['.exe',''])]), | |
505 | add_error_fail(haskell_csp,'Could not find CSP-M Parser. Be sure to install cspmf in your ProB lib directory. ',E)), | |
506 | debug_println(9,parser(AbsParseCmd)). | |
507 | ||
508 | ||
509 | :- dynamic parseResult/5. | |
510 | load_cspm_pl_file(PFile) :- load_cspm_pl_file(PFile,PFile). | |
511 | load_cspm_pl_file(PrologFile,CSPFile) :- clear_cspm_spec, | |
512 | \+ file_exists(PrologFile),!, | |
513 | add_error(haskell_csp,'Could not generate Prolog encoding of CSP file: ',CSPFile),fail. | |
514 | load_cspm_pl_file(PrologFile,CSPFile) :- | |
515 | debug_println(15,consulting(PrologFile)), | |
516 | cia_consult_without_redefine_warning(PrologFile), debug_stats(done_loading_pl_file), | |
517 | /* TO DO: replace by safer load which checks that | |
518 | only correct facts are loaded !!!! */ | |
519 | parseResult(ParseResult,ErrorMsg,StartLine,SC,Off), | |
520 | (ParseResult='ok' -> analyze ; | |
521 | add_error(haskell_csp,'Error while parsing CSP-M: ',ParseResult:CSPFile), | |
522 | add_error(haskell_csp,'Error message: ',ErrorMsg,src_position(StartLine,SC,Off,1)) | |
523 | ). | |
524 | ||
525 | /* ------------------------------------------------------------------------------------------------------------ */ | |
526 | ||
527 | % A small pretty-printer for printing assert declarations | |
528 | refinement_operator('Trace',' [T= ') :- !. | |
529 | refinement_operator('Failure', ' [F= ') :- !. | |
530 | refinement_operator('FailureDivergence',' [FD= ') :- !. | |
531 | refinement_operator('RefusalTesting',' [R= ') :- !. | |
532 | refinement_operator('RefusalTestingDiv',' [RD= ') :- !. | |
533 | refinement_operator('RevivalTesting',' [V= ') :- !. | |
534 | refinement_operator('RevivalTestingDiv',' [VD= ') :- !. | |
535 | /* the clauses below will be called if we check the particular assertion direct from the command line and not from the .pl file */ | |
536 | refinement_operator('[T=',' [T= ') :- !. | |
537 | refinement_operator('[F=', ' [F= ') :- !. | |
538 | refinement_operator('[FD=',' [FD= ') :- !. | |
539 | refinement_operator('[R=',' [R= ') :- !. | |
540 | refinement_operator('[RD=',' [RD= ') :- !. | |
541 | refinement_operator('[V=',' [V= ') :- !. | |
542 | refinement_operator('[VD=',' [VD= ') :- !. | |
543 | refinement_operator(A, _) :- add_error_fail(haskell_csp, 'Error while pretty-printing assert declaration. Invalid or unsupported refinement operator: ', A). | |
544 | ||
545 | adding_not('True', 'not ') :- !. | |
546 | adding_not('False', '') :- !. | |
547 | adding_not(A,_) :- add_error_fail(haskell_csp,'Error while pretty-printing assert declaration. Unexpected argument infront the assertion declaration: ',A). | |
548 | ||
549 | fdr_model('Deterministic', ' :[ deterministic ') :- !. | |
550 | fdr_model('DeadlockFree', ' :[ deadlock free ') :- !. | |
551 | fdr_model('LivelockFree', ' :[ livelock free ') :- !. | |
552 | fdr_model(A,_) :- add_error_fail(haskell_csp, 'Error while pretty-printing assert declaration. Invalid or unsupported model inside of process assertion: ', A). | |
553 | ||
554 | fdr_single_model('Deterministic', ' :[ deterministic [FD] ]') :- !. | |
555 | fdr_single_model('DeadlockFree', ' :[ deadlock free [FD] ]') :- !. | |
556 | fdr_single_model('LivelockFree', ' :[ livelock free ]') :- !. | |
557 | fdr_single_model(A,_) :- add_error_fail(haskell_csp, 'Error while pretty-printing assert declaration. Invalid or unsupported model inside of process assertion: ', A). | |
558 | ||
559 | fdr_ext('F', '[F] ]') :- !. | |
560 | fdr_ext('FD', '[FD] ]') :- !. | |
561 | fdr_ext(Ext, _) :- add_error_fail(haskell_csp, 'Not supported assertion type model: ',Ext). | |
562 | ||
563 | :- assert_must_fail(proc_with_arguments_to_string('P',0,_)). | |
564 | :- assert_must_fail(proc_with_arguments_to_string('P',-10,_)). | |
565 | :- assert_must_succeed((proc_with_arguments_to_string('P',1,String), String=='P(-)')). | |
566 | :- assert_must_succeed((proc_with_arguments_to_string('P',3,String), String=='P(-,-,-)')). | |
567 | ||
568 | proc_with_arguments_to_string(Fun,N,FunRes) :- | |
569 | ( N>1 -> | |
570 | count_proc_arguments(N,R), | |
571 | concatenate_string_list([Fun,'('|R],FunRes) | |
572 | ; N =:= 1 -> | |
573 | string_concatenate(Fun,'(-)',FunRes) | |
574 | ). | |
575 | ||
576 | count_proc_arguments(N,Res) :- | |
577 | count_proc_arguments(N,['-',')'],Res). | |
578 | ||
579 | count_proc_arguments(N,L,Res) :- | |
580 | (N =:= 1 -> | |
581 | Res=L | |
582 | ; N>1 -> | |
583 | N1 is N-1, | |
584 | count_proc_arguments(N1,['-',','|L],Res) | |
585 | ). | |
586 | ||
587 | :- assert_must_succeed((string_to_proc_term('P(-,-,-)',Term), Term = 'P'(_A,_B,_C))). | |
588 | :- assert_must_succeed((string_to_proc_term('P(-)',Term), Term = 'P'(_X))). | |
589 | :- assert_must_succeed((string_to_proc_term('P',Term), Term = 'P')). | |
590 | :- assert_must_succeed((string_to_proc_term(p(1,2),Term), Term == p(1,2))). | |
591 | ||
592 | string_to_proc_term(Proc,Term) :- | |
593 | atom(Proc),!, | |
594 | split_atom(Proc,['(',',',')'],[Fun|A]), | |
595 | length(A,N), | |
596 | gen_vars(N,Args), | |
597 | Term =.. [Fun|Args]. | |
598 | string_to_proc_term(X,X). | |
599 | ||
600 | :- assert_must_succeed((string_to_proc_term('P(-,-,-)',Term), functor(Term,F,N), proc_with_arguments_to_string(F,N,Str), Str == 'P(-,-,-)')). | |
601 | ||
602 | gen_vars(N,Vars) :- | |
603 | ( N>0 -> N1 is N-1, gen_vars(N1,T),Vars=[_X|T] | |
604 | ; N =:= 0 -> Vars = []). | |
605 | ||
606 | :- assert_must_succeed(string_term_with_args('Fun(1,2,-)')). | |
607 | :- assert_must_fail(string_term_with_args('Fun(1,2,3)')). | |
608 | :- assert_must_fail(string_term_with_args('Fun(X,_,_Y)')). | |
609 | :- assert_must_fail(string_term_with_args(_Fun)). | |
610 | ||
611 | string_term_with_args(StrTerm) :- | |
612 | atom(StrTerm),!, | |
613 | split_atom(StrTerm,['(',',',')'],[_Fun|A]), | |
614 | A\=[],member(-,A). | |
615 | ||
616 | :- assert_must_succeed((haskell_csp:concatenate_string_list(['A','B','C'],'ABC'))). | |
617 | :- assert_must_succeed((haskell_csp:concatenate_string_list([],''))). | |
618 | ||
619 | concatenate_string_list(L,Res) :- | |
620 | concatenate_string_list(L,'',Res). | |
621 | ||
622 | concatenate_string_list([],Res,Res). | |
623 | concatenate_string_list([H|T],Str,Res) :- | |
624 | string_concatenate(Str,H,StrRes), | |
625 | concatenate_string_list(T,StrRes,Res). | |
626 | ||
627 | translate_csp_assertions(L,Res) :- | |
628 | maplist(translate_csp_assertion_with_sep,L,LRes), | |
629 | concatenate_string_list(LRes,Res). | |
630 | ||
631 | translate_csp_assertion_with_sep(Ass,AssStrWithSep) :- | |
632 | translate_with_sep(translate_csp_assertion,Ass,'$',AssStrWithSep). | |
633 | ||
634 | % Sep must be an atom | |
635 | translate_with_sep(TranslationPredicate,Arg,Sep,ArgStrSep) :- | |
636 | functor(Fun,TranslationPredicate,2),arg(1,Fun,Arg),arg(2,Fun,ArgStr), | |
637 | %Fun =.. [TranslationPredicate,Arg,ArgStr], | |
638 | call(Fun), | |
639 | string_concatenate(ArgStr,Sep,ArgStrSep). | |
640 | ||
641 | translate_csp_assertion(AssertionExpr,ConcRes) :- | |
642 | /* assert not? P [Op= Q */ | |
643 | (AssertionExpr = assertRef(N,P,Op,Q,_) -> | |
644 | refinement_operator(Op,Operator), | |
645 | translate_cspm_state(Q,Proc_2), | |
646 | L=[Operator,Proc_2] | |
647 | /* assert P |= LTL: "ltl-formula" */ | |
648 | ;AssertionExpr = assertLtl(N,P,Formula,_) -> | |
649 | L = [' |= ', 'LTL: ', '\"', Formula, '\"'] | |
650 | /* assert P |= CTL: "ctl-formula" */ | |
651 | ;AssertionExpr = assertCtl(N,P,Formula,_) -> | |
652 | L = [' |= ', 'CTL: ', '\"', Formula, '\"'] | |
653 | /* assert not? P :[Mod [E]] */ | |
654 | ;AssertionExpr = assertModelCheckExt(N,P,Mod,E) -> | |
655 | fdr_model(Mod,Model), | |
656 | fdr_ext(E,Ext), | |
657 | L=[Model,Ext] | |
658 | /* assert not? P :[Mod] */ | |
659 | ;AssertionExpr = assertModelCheck(N,P,Mod) -> | |
660 | fdr_single_model(Mod,Model), | |
661 | L=[Model] | |
662 | ; otherwise -> | |
663 | add_internal_error('Internal Error (CSP-M Parser): Unexpected assertion predicate: ', | |
664 | translate_csp_assertion(AssertionExpr,ConcRes)) | |
665 | ), | |
666 | adding_not(N,Not), | |
667 | translate_cspm_state(P,Proc), | |
668 | concatenate_string_list([Not, Proc|L], ConcRes). | |
669 | ||
670 | %%%%%%%%%%%%%%%%%%%%%%%%%%% Testing get_csp_processes/1, get_csp_process/2 and translate_csp_assertions/2 predicates %%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
671 | find_and_assert_all_csp_processes_from_arity_zero :- | |
672 | findall(P,(bindval(P,Body,_),definite_cspm_process_expression(Body),assert(is_csp_process(P))),_L). | |
673 | ||
674 | clear_all_is_csp_process_facts :- retractall(is_csp_process(_)). | |
675 | ||
676 | :- assert_must_succeed((find_and_assert_all_csp_processes_from_arity_zero, | |
677 | get_csp_processes(Res), %print(Res),nl, | |
678 | clear_all_is_csp_process_facts, | |
679 | Res==list(['P(-)','Q(-)','SEND','REC','SYSTEM','GEN1','GEN2','MAIN']))). | |
680 | :- assert_must_succeed((findall(assertRef(A,B,C,D,S), | |
681 | haskell_csp: assertRef(A,B,C,D,S),L),haskell_csp: translate_csp_assertions(L,String), | |
682 | String == 'CSP: MAIN [T= CSP: PROB_TEST_TRACE$not CSP: PROB_TEST_TRACE [T= CSP: MAIN$')). | |
683 | :- assert_must_succeed((findall(assertModelCheckExt(A,B,C,D), | |
684 | haskell_csp: assertModelCheckExt(A,B,C,D),L), | |
685 | findall(assertModelCheck(A,B,C),haskell_csp:assertModelCheck(A,B,C),L1,L), | |
686 | haskell_csp: translate_csp_assertions(L1,String), | |
687 | String == 'CSP: a.1->P :[ livelock free ]$CSP: SYSTEM [|{|left,right|}|] GEN1 :[ deterministic [F] ]$not CSP: SYSTEM [|{|left,right|}|] GEN1 :[ deadlock free [FD] ]$')). | |
688 | ||
689 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
690 | ||
691 | /* Tcl_Tk cannot handle complicated prolog strings, that's why we have to convert the from the Csp prolog file filtered assertions | |
692 | into simple string. Assertions will be separated with the '$' symbol. */ | |
693 | get_csp_assertions_as_string(CSPFile,R) :- | |
694 | read_compiled_prolog_file(CSPFile,A,filter_assertion_declarations), | |
695 | translate_csp_assertions(A,R),debug_print(9,'string_for_tcl: '),debug_println(9,R). | |
696 | ||
697 | /* The same as above for the processes, these will be separate by '$' as well. Needed for the process comboboxes in the | |
698 | 'Check Csp Assertions' window in Tcl_Tk. */ | |
699 | get_csp_processes(list(R1)) :- | |
700 | nl,print(getting_csp_processes),nl, | |
701 | findall(bindval(P,_,_),bindval(P,_,_),L), | |
702 | findall(agent(F,Body,_),agent(F,Body,_),L1,L), | |
703 | get_processes(L1,R1), | |
704 | print(R1),nl,nl. | |
705 | ||
706 | get_processes([],[]). | |
707 | get_processes([bindval(A,_,_)|T],R) :- !, | |
708 | ( animatable_process(A) -> R=[A|Res] ; R=Res), | |
709 | get_processes(T,Res). | |
710 | get_processes([agent(Fun,Body,_)|T],R) :- !, | |
711 | ( (definite_cspm_process_expression(Body),animatable_process_with_arguments(Fun,proc(F,N))) | |
712 | -> proc_with_arguments_to_string(F,N,FunRes),R = [FunRes|Res] | |
713 | ; R=Res | |
714 | ), | |
715 | get_processes(T,Res). | |
716 | ||
717 | /* ------------------------------------------------------------------------------------------------------------------------- */ | |
718 | ||
719 | clear_cspm_spec :- % nl,print('RESET CSPM'),nl,nl, | |
720 | %reset_profiler, | |
721 | retractall(parseResult(_,_,_,_,_)), | |
722 | retractall(channel(_,_)), | |
723 | retractall(bindval(_,_,_)), | |
724 | retractall(cspTransparent(_)), | |
725 | retractall(agent(_,_,_)), | |
726 | retractall(dataTypeDef(_,_)), | |
727 | retractall(subTypeDef(_,_)), | |
728 | retractall(nameType(_,_)), | |
729 | retractall(assertRef(_,_,_,_,_)), | |
730 | % retractall(assertTauTrio(_,_,_,_,_,_)), | |
731 | retractall(assertModelCheckExt(_,_,_,_)), | |
732 | retractall(assertModelCheck(_,_,_)), | |
733 | retractall(channel_type_list(_,_)), | |
734 | retractall(csp_full_type_constructor(_,_,_)), | |
735 | retractall(pragma(_)). | |
736 | %retractall(csp_full_expanded_type(_,_)), | |
737 | %retractall(expanded_setFromTo(_,_,_)). | |
738 | ||
739 | %:- use_module(probsrc(eventhandling),[register_event_listener/3]). | |
740 | :- register_event_listener(clear_specification,clear_cspm_spec, | |
741 | 'Clearing any CSPM Specification.'). | |
742 | ||
743 | is_a_datatype(DT,L) :- | |
744 | (dataTypeDef(DT,L) ; subTypeDef(DT,L)). | |
745 | ||
746 | /* Tests for the is_not_infinite_type/1 predicate (see .pl translation sample on lines 68-106 ) */ | |
747 | ||
748 | :- assert_must_fail((assert(csp_full_type_constructor(_,'SubMsg',[dataType('Msg')])), | |
749 | assert(csp_full_type_constructor(_,'Msg',[dataType('SubMsg')])), | |
750 | haskell_csp:is_not_infinite_type(closure([tuple([receive])])))). | |
751 | :- assert_must_succeed((assert(csp_full_type_constructor(_,'FRUIT', | |
752 | [constructor(apples),construcor(oranges),constructor(pears)])), | |
753 | haskell_csp:is_not_infinite_type(closure([tuple([left])])))). | |
754 | :- assert_must_fail((assert(csp_full_type_constructor(_,'FRUIT', | |
755 | [constructor(apples),construcor(oranges),constructor(pears)])), | |
756 | assert(csp_full_type_constructor(_,'SubMsg',[dataType('Msg')])), | |
757 | assert(csp_full_type_constructor(_,'Msg',[dataType('SubMsg')])), | |
758 | haskell_csp:is_not_infinite_type(closure([tuple([left]), | |
759 | tuple([mid]),tuple([right]),tuple([receive])])))). | |
760 | :- assert_must_fail((assert(csp_full_type_constructor(ste,'Inf',['Seq'(dataType('FRUIT'))])), | |
761 | assert(csp_full_type_constructor(_,'FRUIT', | |
762 | [constructor(apples),construcor(oranges),constructor(pears)])), | |
763 | haskell_csp:is_not_infinite_type(closure([tuple([infinite])])))). | |
764 | :- assert_must_succeed((assert(csp_full_type_constructor(_,'FRUIT', | |
765 | [constructor(apples),construcor(oranges),constructor(pears)])), | |
766 | haskell_csp:is_not_infinite_type(closure([tuple([left]),tuple([mid]),tuple([right])])))). | |
767 | :- assert_must_fail((assert(csp_full_type_constructor(_,'FRUIT', | |
768 | [constructor(apples),construcor(oranges),constructor(pears)])), | |
769 | assert(csp_full_type_constructor(_,'SubMsg',[dataType('Msg')])), | |
770 | assert(csp_full_type_constructor(_,'Msg',[dataType('SubMsg')])), | |
771 | assert(csp_full_type_constructor(ste,'Inf',['Seq'(dataType('FRUIT'))])), | |
772 | haskell_csp:is_not_infinite_type(closure([tuple([left]),tuple([mid]), | |
773 | tuple([right]),tuple([infinite]),tuple([receive])])))). | |
774 | ||
775 | :- assert_must_fail(haskell_csp:is_not_infinite_type(setFrom(1))). | |
776 | :- assert_must_fail(haskell_csp:channel_type_is_finite('dotTupleType'([setValue([int(1),int(2)]), setFrom(1)]),2)). | |
777 | :- assert_must_succeed((assert(name_type('S', setFromTo(1,3))), haskell_csp: channel_type_is_finite('S',2))). | |
778 | ||
779 | /* is_not_infinite_type/1 */ | |
780 | /* check if the Event set is from infinite type */ | |
781 | /* needed for the refinement checker, when generating counter-examples, TODO: re-implement predicate */ | |
782 | is_not_infinite_type(X) :- var(X),!,fail. | |
783 | % at first we are only interesting of checking the whole closure for infinite types | |
784 | is_not_infinite_type(closure(X)) :- !, | |
785 | closure_is_finite_set(X). | |
786 | %% TODO: Cover all other cases for this predicate (like setValue, setFrom, ...) | |
787 | ||
788 | ||
789 | closure_is_finite_set(L) :- | |
790 | maplist(single_element_closure_is_finite,L). | |
791 | ||
792 | % the closure is basically the set of all channels in a specification | |
793 | single_element_closure_is_finite(tuple([Ch|_List])) :- | |
794 | (channel_type_list(Ch,ChannelTypeList) -> true | |
795 | ; print(no_channel_type(Ch))), | |
796 | !, | |
797 | l_channel_type_is_finite(ChannelTypeList,2). | |
798 | single_element_closure_is_finite(_X). | |
799 | ||
800 | channel_type_is_finite(intType,_Rec) :- !,fail. | |
801 | channel_type_is_finite(boolType,_Rec) :- !. | |
802 | channel_type_is_finite(setFromTo(_L,_U),_Rec) :- !. | |
803 | channel_type_is_finite(setFrom(_L),_Rec) :- !,fail. % endless set | |
804 | % we got a dot tuple of types, we need to check for infinity all types in the tuple. | |
805 | channel_type_is_finite('dotTupleType'(List),Rec):-!, | |
806 | l_channel_type_is_finite(List,Rec). | |
807 | channel_type_is_finite('typeTuple'(List),Rec) :- !, | |
808 | l_channel_type_is_finite(List,Rec). % the same as last clausel | |
809 | channel_type_is_finite(setValue(_L),_Rec) :- !. | |
810 | channel_type_is_finite(dataType(DT),Rec) :- | |
811 | is_a_datatype(DT,_),!, | |
812 | check_datatype_el(DT,Rec). | |
813 | channel_type_is_finite('Seq'(setValue([])),_Rec) :- !. % Seq({}) is the empty sequence <> | |
814 | channel_type_is_finite('Seq'(_Type),_Rec) :- !, fail. % e.g. Seq({a,b,c}) indicator for endless datatype (there are endless numbers of sequences) | |
815 | channel_type_is_finite(X,Rec) :- | |
816 | name_type(X,Type),!, | |
817 | channel_type_is_finite(Type,Rec). | |
818 | channel_type_is_finite(_X,_Rec). | |
819 | ||
820 | check_datatype_el(DT,MaxRec) :- | |
821 | (MaxRec > 0 -> M1 is MaxRec -1, | |
822 | (csp_constructor(_Cons,DT,ArgSubTypes) -> /* Subtypes recursion. */ l_channel_type_is_finite(ArgSubTypes,M1) | |
823 | ; /* constructors from finite type (there is no recursion)*/ true)). | |
824 | /* ending recursion of datatypes (recursion doesn't mean infinite type) */ | |
825 | ||
826 | channel_type_is_finite_rec(Rec,HType) :- | |
827 | channel_type_is_finite(HType,Rec). | |
828 | ||
829 | l_channel_type_is_finite(L,Rec) :- | |
830 | maplist(channel_type_is_finite_rec(Rec),L). | |
831 | ||
832 | /* | |
833 | l_channel_type_is_finite([],_Rec). | |
834 | l_channel_type_is_finite([HType|T],Rec) :- | |
835 | (channel_type_is_finite(HType,Rec) -> | |
836 | l_channel_type_is_finite(T,Rec)). | |
837 | */ | |
838 | ||
839 | /* end of the implementation of is_not_infinite_type/1 predicate */ | |
840 | ||
841 | get_csp_assertions(CSP_Assertions) :- | |
842 | findall(Ass, (is_assertion(Ass),Ass), CSP_Assertions), | |
843 | debug_println(9,CSP_Assertions). | |
844 | ||
845 | /* | |
846 | get_csp_assertions_enum(CSPFile, Result) :- | |
847 | read_compiled_prolog_file(CSPFile,CSP_Assertions,filter_assertion_declarations), | |
848 | enumerate_assertions(CSP_Assertions,Result). | |
849 | ||
850 | :- assert_must_succeed(haskell_csp:enumerate_assertions([a,b,c,d,e,f],[(a,0),(b,1),(c,2),(d,3),(e,4),(f,5)])). | |
851 | :- assert_must_succeed(haskell_csp:enumerate_assertions([],[])). | |
852 | enumerate_assertions(L,R) :- enumerate_assertions_acc(L,R,0). | |
853 | enumerate_assertions_acc([],[],_). | |
854 | enumerate_assertions_acc([H|T],[(H,Acc)|R],Acc) :- New_Acc is Acc +1, enumerate_assertions_acc(T,R,New_Acc). | |
855 | */ | |
856 | ||
857 | cia_consult_without_redefine_warning(File) :- | |
858 | (file_exists(File) -> true ; (add_error(haskell_csp,'CSP-M PL File does not exist: ',File),fail)), | |
859 | debug_println(15,consult_without_redefine(File)), | |
860 | prolog_flag(redefine_warnings, Old, off), | |
861 | prolog_flag(single_var_warnings, Old2, off), | |
862 | prolog_flag(discontiguous_warnings, Old3, off), | |
863 | (load_files(File,[compilation_mode(assert_all)]) %consult(File) | |
864 | -> OK=true ; OK=false), | |
865 | prolog_flag(redefine_warnings, _, Old), | |
866 | prolog_flag(single_var_warnings, _, Old2), | |
867 | prolog_flag(discontiguous_warnings, _, Old3), | |
868 | OK=true. | |
869 | ||
870 | /* ------------------------------------- */ | |
871 | ||
872 | ||
873 | /* THE CSP OPERATIONAL SEMANTICS */ | |
874 | ||
875 | ||
876 | /* ------------------------------------- */ | |
877 | % | |
878 | %trans_pre_compute(X,Results) :- | |
879 | % findall(res(X,A,X1,Residue),call_residue(cspm_trans(X,A,X1),Residue), Results). | |
880 | % | |
881 | % | |
882 | %trans_cont(Results,X,A,X1) :- | |
883 | % member(res(X,A,X1,Residue),Results), | |
884 | % % print(trans_cont(X,A,X1,Residue)),nl, | |
885 | % call(Residue). | |
886 | ||
887 | /* ------------------------------------- */ | |
888 | ||
889 | %cspm_trans(E,_,_) :- print(cspm_trans(E)),nl,fail. | |
890 | ||
891 | :- assert_must_succeed(( haskell_csp:functor_dif(X,f), X=g(_) )). | |
892 | :- assert_must_fail(( haskell_csp:functor_dif(X,f), X=f(_) )). | |
893 | ||
894 | :- block functor_dif(-,?). | |
895 | functor_dif(X,FY) :- functor(X,FX,_), FX\=FY. | |
896 | ||
897 | :- assert_pre(haskell_csp:cspm_trans(E,_,_,_), nonvar(E)). | |
898 | :- assert_post(haskell_csp:cspm_trans(_,A,NE,_), (nonvar(A),nonvar(NE))). | |
899 | :- block cspm_trans(-,?,?,?). | |
900 | % TO DO: comment out for efficiency: | |
901 | /* ------ */ | |
902 | %cspm_trans(X,_,_) :- debug_println(9,cspm_trans(X)), var(X), | |
903 | % add_error(csp_interpreter,'### Variable process expression in cspm_trans !!',X), fail. | |
904 | cspm_trans(X,_,_,_) :- undefined_process_construct(X), | |
905 | (get_preference(cspm_animate_all_processes,true),string_term_with_args(X) -> | |
906 | add_message(cspm_trans,'Warning: Tried to expand a process with non-ground arguments: ',X),fail | |
907 | ;add_error_fail(csp_interpreter,'### Undefined Construct in cspm_trans !! ',X) | |
908 | ). | |
909 | /* ------ */ | |
910 | ||
911 | cspm_trans(stop(_),_,_,_) :- fail. | |
912 | cspm_trans(omega,_,_,_) :- fail. | |
913 | ||
914 | cspm_trans(skip(SrcSpan),tick(SrcSpan),omega,_). | |
915 | %cspm_trans(skip(SrcSpan),tick(SrcSpan),stop(SrcSpan),_). | |
916 | ||
917 | %cspm_trans(cspPrint(X),io(V1,print,no_loc_info_available),cspPrint(X)) :- evaluate_argument(X,V1). | |
918 | ||
919 | cspm_trans('CHAOS'(SrcSpan,_Set),tau(chaos_stop(SrcSpan)),stop(SrcSpan),_). | |
920 | cspm_trans('CHAOS'(SrcSpan,Set),io(V1,Ch,SrcSpan),'CHAOS'(SrcSpan,Set),_WF) :- /* or should we add an intermediate tau ?? */ | |
921 | % print(evaluate_argument(Set,S)),nl, | |
922 | evaluate_argument(Set,S), | |
923 | % print(chaos(S)),nl, | |
924 | ~~mnf(haskell_csp:expand_channel_pattern_expression(S,ECList,SrcSpan)), | |
925 | % print(setup_channel_skeleton(io(V1,Ch,SrcSpan))),nl, | |
926 | setup_channel_skeleton(io(V1,Ch,SrcSpan)), | |
927 | % print(chaos(io(V1,Ch),ECList)),nl, | |
928 | hidden(io(V1,Ch,SrcSpan),ECList). | |
929 | ||
930 | % print(hidden(io(V1,Ch,SrcSpan),ECList)),nl. | |
931 | ||
932 | /* external choice */ | |
933 | cspm_trans('[]'(X,Y,Span),NA,Res,WF) :- cspm_trans(X,A,X1,WF), | |
934 | shift_span_for_left_branch(Span,LSpan), | |
935 | merge_span_into_event(A,LSpan,NA), | |
936 | ( top_level_dif(A,tau(_)), Res=X1 | |
937 | ; | |
938 | A=tau(_), tl_normalise('[]'(X1,Y,Span),Res) ). | |
939 | cspm_trans('[]'(X,Y,Span),NA,Res,WF) :- cspm_trans(Y,A,Y1,WF), | |
940 | shift_span_for_right_branch(Span,RSpan), | |
941 | merge_span_into_event(A,RSpan,NA), | |
942 | ( top_level_dif(A,tau(_)), Res=Y1 | |
943 | ; | |
944 | A=tau(_), tl_normalise('[]'(X,Y1,Span),Res) ). | |
945 | ||
946 | /* internal choice */ | |
947 | cspm_trans('|~|'(X,_Y,SrcSpan),tau(int_choice_left(SrcSpan,LSpan)),X,_WF) :- | |
948 | shift_span_for_left_branch(SrcSpan,LSpan). | |
949 | cspm_trans('|~|'(_X,Y,SrcSpan),tau(int_choice_right(SrcSpan,RSpan)),Y,_WF) :- | |
950 | shift_span_for_right_branch(SrcSpan,RSpan). | |
951 | ||
952 | /* -> PREFIX */ | |
953 | /* Note: set restrictions on values are encoded as inGuard Expressions */ | |
954 | cspm_trans(prefix(SPAN1,Values,ChannelExpr,CSP,SPAN2), io(EV,Channel,SPAN), NormCSP,WF) :- | |
955 | evaluate_channel_outputs(Values,ChannelExpr,EV,Channel,SPAN,WF), | |
956 | unify_spans(SPAN1,SPAN2,SPAN), | |
957 | full_normalise_csp_process(CSP,NormCSP). % ,print(prefix(io(EV,Channel))),nl. | |
958 | ||
959 | ||
960 | /* interleave */ | |
961 | %cspm_trans('|||'(X,Y,Span),A,R,WF) :- cspm_trans(sharing(setValue([]),X,Y),A,R). | |
962 | /* Firing rules for the |||-operator: | |
963 | ||
964 | P -a> P' | |
965 | ---------------------------- | |
966 | P ||| Q -a> P' ||| Q | |
967 | ||
968 | Q -a> Q' | |
969 | ---------------------------- | |
970 | P ||| Q -a> P ||| Q' | |
971 | ||
972 | ||
973 | P -tick> P' | |
974 | ---------------------------- | |
975 | P ||| Q -tau> Omega ||| Q | |
976 | ||
977 | ||
978 | Q -tick> Q' | |
979 | ---------------------------- | |
980 | P ||| Q -tau> P ||| Omega | |
981 | ||
982 | */ | |
983 | ||
984 | cspm_trans('|||'(omega,omega,Span),tick(Span),omega,_). | |
985 | cspm_trans('|||'(X,Y,ISpan),A,Res,WF) :- | |
986 | cspm_trans(X, ActionX, X1,WF), | |
987 | shift_span_for_left_branch(ISpan,LSpan), | |
988 | ( ActionX=tick(_), X2=omega | |
989 | ; functor_dif(ActionX,tick), X2=X1 | |
990 | ), | |
991 | merge_span_into_event(ActionX,LSpan,MA), | |
992 | (ActionX=tick(_) -> A=tau(MA); A=MA), | |
993 | tl_normalise('|||'(X2,Y,ISpan),Res). | |
994 | cspm_trans('|||'(X,Y,ISpan),A,Res,WF) :- | |
995 | cspm_trans(Y, ActionY, Y1,WF), | |
996 | shift_span_for_right_branch(ISpan,RSpan), | |
997 | ( ActionY=tick(_), Y2=omega | |
998 | ; functor_dif(ActionY,tick), Y2=Y1 | |
999 | ), | |
1000 | merge_span_into_event(ActionY,RSpan,MA), | |
1001 | (ActionY=tick(_) -> A=tau(MA); A=MA), | |
1002 | tl_normalise('|||'(X,Y2,ISpan),Res). | |
1003 | ||
1004 | /* sequential composition */ | |
1005 | cspm_trans(';'(P,Q,SeqSpan),AX,Res,WF) :- | |
1006 | cspm_trans(P,A,P1,WF), | |
1007 | ( A=tick(_), | |
1008 | merge_span_into_event(A,SeqSpan,MA), | |
1009 | AX = tau(MA), | |
1010 | full_normalise_csp_process(Q,Res) /* is this required ?? */ | |
1011 | ; functor_dif(A,tick), AX=A, | |
1012 | tl_normalise(';'(P1,Q,SeqSpan),Res) | |
1013 | ). | |
1014 | ||
1015 | ||
1016 | /* Sharing: [| a |] */ | |
1017 | cspm_trans(sharing(CList,X,Y,SrcSpan),A,Res,WF) :- | |
1018 | evaluate_argument(CList,EvCList), | |
1019 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCList,ECList,SrcSpan)), | |
1020 | cspm_trans(esharing(ECList,X,Y,SrcSpan),A,Res,WF). | |
1021 | cspm_trans(esharing(_,omega,omega,SrcSpan), tick(SrcSpan), omega ,_WF). | |
1022 | cspm_trans(esharing(CList,X,Y,SrcSpan), Action, Result,WF) :- | |
1023 | cspm_trans(X, ActionX, X1,WF), | |
1024 | ( (ActionX=tick(TS), | |
1025 | shift_span_for_left_branch(SrcSpan,LSpan), | |
1026 | merge_span_into_event(tau(tick(TS)),LSpan,Action), | |
1027 | Result = esharing(CList,omega,Y,SrcSpan)) | |
1028 | ; (functor_dif(ActionX,tick), | |
1029 | shift_span_for_left_branch(SrcSpan,LSpan), | |
1030 | merge_span_into_event(ActionX,LSpan,Action), | |
1031 | not_hidden(ActionX,CList), /* covers tau */ | |
1032 | Result = esharing(CList,X1,Y,SrcSpan)) | |
1033 | ; (ActionX=io(V1,Ch,Sp1), Action = io(V,Ch,Span), | |
1034 | %((transferReq,[int(3),ac1,ac2,true])=(Ch,V1) -> trace ; true), | |
1035 | Result = esharing(CList,X1,Y1,SrcSpan), | |
1036 | unify_spans(Sp1,SrcSpan,SP1b), | |
1037 | hidden(Action,CList), | |
1038 | unify_values(V1,V2,V,Ch,SP1b), % try and also incorporate Sp2 Span, without compromising speed | |
1039 | % print(call_cspm_transY_B1(Y,io(V2,Ch),Y1)),nl, | |
1040 | cspm_trans(Y, io(V2,Ch,Sp2), Y1,WF), /* <---- Y will be recomputed for every solution of X !!! */ | |
1041 | unify_spans(SP1b,Sp2,Span3), | |
1042 | Span = span_info(sharing,Span3) | |
1043 | ) | |
1044 | ). | |
1045 | cspm_trans(esharing(CList,X,Y,SrcSpan), Action2, Result,WF) :- | |
1046 | shift_span_for_right_branch(SrcSpan,RSpan), | |
1047 | % print(esharing_call_cspm_transY_B2(Y,ActionY,Y1)),nl, | |
1048 | cspm_trans(Y,ActionY,Y1,WF), /* this gets computed a second time; is there a way to avoid this? */ | |
1049 | %print(esharing_cspm_transY_B2(Y,ActionY)),nl, | |
1050 | ( ActionY = tick(TS), Action=tau(tick(TS)), Result=esharing(CList,X,omega,SrcSpan) | |
1051 | ; functor_dif(ActionY,tick), ActionY = Action, | |
1052 | %print(try_non_sharing(ActionY)),nl, | |
1053 | not_hidden(ActionY,CList), /* covers tau */ | |
1054 | Result = esharing(CList,X,Y1,SrcSpan) | |
1055 | ), | |
1056 | merge_span_into_event(Action,RSpan,Action2). | |
1057 | ||
1058 | ||
1059 | /* Linked Parallel [ l <-> r,.. ] */ | |
1060 | cspm_trans(lParallel(LinkList,X,Y,Span), Action,Result,WF) :- | |
1061 | evaluate_link_list(LinkList,EvLinkRenameList), | |
1062 | %print(evlinklist(LinkList,EvLinkRenameList)),nl, % | |
1063 | cspm_trans(elinkParallel(EvLinkRenameList,X,Y,Span),Action,Result,WF). | |
1064 | cspm_trans(elinkParallel(_,omega,omega,Span), tick(Span), omega ,_WF). | |
1065 | cspm_trans(elinkParallel(EvLinkRenameList,X,Y,LinkSpan),Action,Result,WF) :- | |
1066 | cspm_trans(X,AX,X2,WF), % print(elink_x(X,AX,X2,EvLinkRenameList)),nl, print('State: '),print(X),nl, | |
1067 | ( AX = tick(TS), | |
1068 | shift_span_for_left_branch(LinkSpan,LSpan), | |
1069 | merge_span_into_event(tau(tick(TS)),LSpan,Action), | |
1070 | Result=elinkParallel(EvLinkRenameList,omega,Y,LinkSpan) | |
1071 | ; | |
1072 | functor_dif(AX,tick), | |
1073 | ( shift_span_for_left_branch(LinkSpan,LSpan), | |
1074 | merge_span_into_event(AX,LSpan,Action), | |
1075 | Result = elinkParallel(EvLinkRenameList,X2,Y,LinkSpan), | |
1076 | not_renamed(AX,EvLinkRenameList) | |
1077 | % ,print(not_renamed(AX,EvLinkRenameList)),nl %% | |
1078 | ; | |
1079 | Action=tau(link(AX,io(V,Ch,Span))), | |
1080 | Result = elinkParallel(EvLinkRenameList,X2,Y2,LinkSpan), | |
1081 | force_rename_action(AX,EvLinkRenameList,io(V1,Ch,Sp0)), | |
1082 | unify_spans(LinkSpan,Sp0,Sp1), | |
1083 | %% print(renamed(AX,io(V1,Ch),EvLinkRenameList)),nl, %% | |
1084 | unify_values(V1,V2,V,Ch,Sp1), % try and also incorporate Sp2 Span, without compromising speed | |
1085 | % MAYBE TO DO ?: instantiate V2 as much as possible ! --> in()/dot issues | |
1086 | %% print(cspm_trans(Y,io(V2,Ch,Sp2),Y2)),nl, %% | |
1087 | cspm_trans(Y,io(V2,Ch,Sp2),Y2,WF), /* <---- Y will be recomputed for every solution of X !!! */ | |
1088 | unify_spans(Sp1,Sp2,Span3), | |
1089 | %% print(unify(Sp1,Sp2,Span3)),nl, %% | |
1090 | Span = span_info(sharing,Span3) | |
1091 | ) | |
1092 | ). | |
1093 | cspm_trans(elinkParallel(EvLinkRenameList,X,Y,LinkSpan),Action2, | |
1094 | elinkParallel(EvLinkRenameList,X,YR,LinkSpan),WF) :- | |
1095 | shift_span_for_right_branch(LinkSpan,RSpan), | |
1096 | rev_rename_list(EvLinkRenameList,RevList), | |
1097 | cspm_trans(Y,ActionY,Y2,WF), /* TO DO: try and avoid recomputation of cspm_trans(Y) ?! */ | |
1098 | ( ActionY=tick(TS), Action=tau(tick(TS)), YR=omega | |
1099 | ; | |
1100 | functor_dif(ActionY,tick),ActionY=Action,YR=Y2,not_renamed(Action,RevList) | |
1101 | ), | |
1102 | merge_span_into_event(Action,RSpan,Action2). | |
1103 | ||
1104 | cspm_trans(aParallel(CListX,X,CListY,Y,SrcSpan),A,NewState,WF) :- %print(expanding_aparx),nl, | |
1105 | evaluate_argument(CListX,EvCListX), | |
1106 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCListX,ECListX,SrcSpan)), %print(expanding_apary),nl, | |
1107 | evaluate_argument(CListY,EvCListY), | |
1108 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCListY,ECListY,SrcSpan)), | |
1109 | Expanded = eaParallel(ECListX,X,ECListY,Y,SrcSpan), | |
1110 | %we have expanded the channel synchronisation sets; avoid recomputing them every time | |
1111 | % TO DO: investigate whether it also makes sense to precompute intersection | |
1112 | cspm_trans(Expanded,A,NewState,WF). | |
1113 | cspm_trans(eaParallel(_,omega,_,omega,SrcSpan), tick(SrcSpan), omega ,_WF). | |
1114 | cspm_trans(eaParallel(ECListX,X,ECListY,Y,SrcSpan),A,eaParallel(ECListX,X2,ECListY,Y1,SrcSpan),WF) :- | |
1115 | %trans_pre_compute(Y,Results), | |
1116 | cspm_trans(X, AX, X1,WF), | |
1117 | % print(apar_x(AX, from(X))),nl, | |
1118 | ( X2=X1,Y1=Y, | |
1119 | hidden_or_tau(AX,ECListX), | |
1120 | not_hidden(AX,ECListY), | |
1121 | shift_span_for_left_branch(SrcSpan,LSpan), | |
1122 | merge_span_into_event(AX,LSpan,A) | |
1123 | ; | |
1124 | AX=tick(_TS), X2=omega,Y1=Y, | |
1125 | shift_span_for_left_branch(SrcSpan,LSpan), | |
1126 | merge_span_into_event(tau(AX),LSpan,A) | |
1127 | ; | |
1128 | AX=io(V1,Ch,Sp1), X2=X1, A = io(V,Ch,Span), | |
1129 | % nl,print(try_apar_sync(V1,Ch)),nl, | |
1130 | hidden(io(V1,Ch,Sp1),ECListX), % print(left_ok),nl, % do V1 instead of V ? | |
1131 | hidden(io(V,Ch,Span),ECListY), % print(right_ok),nl, % V2 instead of V | |
1132 | % Synchronisation possible | |
1133 | unify_spans(Sp1,SrcSpan,SP1b), | |
1134 | unify_values(V1,V2,V,Ch,SP1b), % try and also incorporate Sp2 Span, without compromising speed | |
1135 | %print(trying(aparY(io(V2,Ch,Sp2)))),nl, % | |
1136 | cspm_trans(Y, io(V2,Ch,Sp2), Y1,WF), /* <---- Y will be recomputed for every solution of X !!! */ | |
1137 | % trans_cont(Results,Y, io(V2,Ch,Sp2), Y1), | |
1138 | % print(done(aparY(io(V2,Ch,Sp2)))),nl, % | |
1139 | unify_spans(SP1b,Sp2,Span3), | |
1140 | Span = span_info(sharing,Span3) | |
1141 | ). | |
1142 | cspm_trans(eaParallel(ECListX,X,ECListY,Y,SrcSpan),AS,eaParallel(ECListX,X,ECListY,Y2,SrcSpan),WF) :- | |
1143 | cspm_trans(Y, AY, Y1,WF), /* To do: try and avoid recomputation of cspm_trans(Y) ?! */ | |
1144 | ( AY=A, Y2=Y1, | |
1145 | hidden_or_tau(A,ECListY), not_hidden(A,ECListX) | |
1146 | ; | |
1147 | AY=tick(_TS), A = tau(AY), Y2=omega | |
1148 | ), | |
1149 | shift_span_for_right_branch(SrcSpan,RSpan), | |
1150 | merge_span_into_event(A,RSpan,AS). | |
1151 | ||
1152 | /* only used for outside xtl_interface ; not used internally anymore */ | |
1153 | cspm_trans(val_of(X,Span),A,NewExpr,WF) :- (symbol(RenamedX,X,_,_) -> cspm_trans(agent_call(Span,RenamedX,[]),A,NewExpr,WF); | |
1154 | cspm_trans(X,A,NewExpr,WF)). | |
1155 | cspm_trans(agent_call(Span,F,Par),NA,NNewExpr,WF) :- | |
1156 | unfold_function_call_once(F,Par,Value,Span), | |
1157 | ~~pp_cll(cspm_trans(Value,A,NewExpr,WF)), | |
1158 | full_normalise_csp_process(NewExpr,NNewExpr), | |
1159 | % print(merge_agcall(A,Span)),nl, | |
1160 | merge_span_into_event(A,Span,NA). | |
1161 | ||
1162 | % Par = [[x],[y]] | |
1163 | cspm_trans(agent_call_curry(F,Par),NA,NNewExpr,WF) :- | |
1164 | Span=no_loc_info_available, | |
1165 | unfold_function_call_curry_once(F,Par,Value,Span), | |
1166 | ~~pp_cll(cspm_trans(Value,A,NewExpr,WF)), | |
1167 | full_normalise_csp_process(NewExpr,NNewExpr), | |
1168 | % print(merge_agcall(A,Span)),nl, | |
1169 | merge_span_into_event(A,Span,NA). | |
1170 | ||
1171 | cspm_trans(builtin_call(X),Action,NewExpr,WF) :- % builtin_call is normally removed by precompilation; but can remain, e.g., for assertions | |
1172 | cspm_trans(X,Action,NewExpr,WF). | |
1173 | cspm_trans(head(X),Action,NewExpr,WF) :- force_evaluate_argument(X,EX),head_list(EX,Result), | |
1174 | cspm_trans(Result,Action,NewExpr,WF). | |
1175 | ||
1176 | /* hiding '\\' */ | |
1177 | ||
1178 | cspm_trans('\\'(Expr,CList,Span), A, Res ,WF) :- | |
1179 | evaluate_argument(CList,EvCList), | |
1180 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCList,ECList,no_loc_info_available)), | |
1181 | % print(ehide(Expr,ECList,Span)),nl, | |
1182 | cspm_trans(ehide(Expr,ECList,Span),A,Res,WF). | |
1183 | ||
1184 | cspm_trans(ehide(Expr,CList,Span), A, Res ,WF) :- | |
1185 | % (nonvar(A) -> ((A=io(_,_,_);A=tick(_)) -> ActionX=A ; A=tau(hide(ActionX))) | |
1186 | % ; true), | |
1187 | cspm_trans(Expr,ActionX,X,WF), | |
1188 | cspm_hide_action(ActionX,X, CList,Span, A,Res). | |
1189 | ||
1190 | ||
1191 | cspm_trans(exception(CList,X,Y,Span), A, Res ,WF) :- | |
1192 | evaluate_argument(CList,EvCList), | |
1193 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCList,ECList,no_loc_info_available)), | |
1194 | %print(exception(ECList,X,Y)),nl, | |
1195 | cspm_trans(eexception(ECList,X,Y,Span),A,Res,WF). | |
1196 | ||
1197 | cspm_trans(eexception(CList,X,Y,Span),A,Res,WF) :- % expanded version of exception | |
1198 | cspm_trans(X, ActionX, X1,WF), | |
1199 | ( functor_dif(ActionX,tick), ActionX=A, | |
1200 | Res = eexception(CList,X1,Y,Span), | |
1201 | not_hidden(A,CList) | |
1202 | ; merge_span_into_event(ActionX,Span,A), | |
1203 | Res = Y, | |
1204 | hidden(ActionX,CList) | |
1205 | ; A=tick(TS), ActionX=tick(TS), Res=omega % is this correct ?? | |
1206 | ). | |
1207 | ||
1208 | ||
1209 | /* timeout */ | |
1210 | cspm_trans('[>'(P,Q,SrcSpan),AS,Res,WF) :- cspm_trans(P,A,P1,WF), | |
1211 | ( A=tau(_), Res='[>'(P1,Q,SrcSpan) | |
1212 | ; | |
1213 | top_level_dif(A,tau(_)), % a transition which can be removed by the tau below | |
1214 | Res=P1 ), | |
1215 | shift_span_for_left_branch(SrcSpan,LSpan), | |
1216 | merge_span_into_event(A,LSpan,AS). | |
1217 | cspm_trans('[>'(_P,Q,SrcSpan),tau(timeout(SrcSpan)),Q,_WF). | |
1218 | ||
1219 | ||
1220 | /* interrupt */ | |
1221 | ||
1222 | cspm_trans('/\\'(X,Y,Span),NA,Res,WF) :- | |
1223 | cspm_trans(X,A,X1,WF), %%print(interrupt_left(X,A,X1)),nl, | |
1224 | shift_span_for_left_branch(Span,LSpan), | |
1225 | merge_span_into_event(A,LSpan,NA), | |
1226 | ( A=tick(_), Res=X1 | |
1227 | ; functor_dif(A,tick), tl_normalise('/\\'(X1,Y,Span),Res) | |
1228 | ). | |
1229 | cspm_trans('/\\'(X,Y,Span),NA,Res,WF) :- | |
1230 | cspm_trans(Y,A,Y1,WF), | |
1231 | shift_span_for_right_branch(Span,RSpan), | |
1232 | merge_span_into_event(A,RSpan,NA), | |
1233 | ( top_level_dif(A,tau(_)), Res=Y1 | |
1234 | ; A=tau(_), tl_normalise('/\\'(X,Y1,Span),Res) | |
1235 | ). | |
1236 | ||
1237 | /* renaming [[ old <- new,... | Generators ]] */ | |
1238 | cspm_trans(procRenamingComp(X,GeneratorList,RenameList),RA,Res,WF) :- | |
1239 | % print(procCompRenaming(GeneratorList)),nl, %% | |
1240 | % warning: does not have the rangeEnum wrapper expected | |
1241 | expand_set_comprehension(rangeEnum(RenameList),GeneratorList,setValue(ExpandedRenames)), | |
1242 | %print(exp(ExpandedRenames)),nl, | |
1243 | cspm_trans(procRenaming(ExpandedRenames,X,no_loc_info_available),RA,Res,WF). | |
1244 | ||
1245 | /* renaming [[ old <- new,... ]] */ | |
1246 | cspm_trans(procRenaming(RenameList,X,Span),RA,Res,WF) :- %print(procRename(RenameList)),nl, | |
1247 | evaluate_rename_list(RenameList,ERenameList), | |
1248 | cspm_trans(eprocRenaming(ERenameList,X,Span),RA,Res,WF). | |
1249 | cspm_trans(eprocRenaming(RenameList,X,Span),RAS,Res,WF) :- | |
1250 | %print('RENAME: '), translate:print_cspm_state(X),nl, | |
1251 | cspm_trans(X,A,X2,WF), | |
1252 | tl_normalise(eprocRenaming(RenameList,X2,Span),Res), | |
1253 | %print(try_rename(A,RenameList,RA,Span)),nl, %% | |
1254 | % it's still possible that A is non-ground term, i.e. there are a non-ground variables (c?x?y) in the sub-process, | |
1255 | % which have to be unified before applying renaming on them. | |
1256 | (ground(A) -> true; enumerate_action(A)), | |
1257 | rename_action(A,RenameList,RA), | |
1258 | %%% print(done_rename_action(A,RenameList,RA)),nl, | |
1259 | merge_span_into_event(RA,Span,RAS). | |
1260 | % print(merge_span(RA,Span,RAS)),nl, | |
1261 | ||
1262 | /* if then else */ | |
1263 | cspm_trans(ifte(Test,Then,Else,S1,S2,S3),A,X1,WF) :- | |
1264 | %nl,print(checking_if_test(Test,Then,Else)),nl, | |
1265 | ~~mnf(haskell_csp:evaluate_boolean_expression(Test,Res)), | |
1266 | % print(if_evaluated_boolean_expression(Test,Res)),nl,nl, | |
1267 | cspm_if_trans(Res,Then,Else,A,X1,S1,S2,S3,WF). | |
1268 | ||
1269 | cspm_trans('&'(Test,Then),A,X1,WF) :- S=no_loc_info_available, | |
1270 | cspm_trans(ifte(Test,Then,stop(S),S,S,S),A,X1,WF). | |
1271 | ||
1272 | ||
1273 | cspm_trans(repChoice(GeneratorList,Body,Span), Action,X1,WF) :- | |
1274 | %% nl,print(repChoice(GeneratorList,Body)),nl, | |
1275 | replicate_expand_set_comprehension([Body],GeneratorList,setValue(Bodies)), | |
1276 | %% print(bodies(Bodies)),nl, | |
1277 | convert_into_choice(Bodies,Span,CHOICE), | |
1278 | %% print(choice(CHOICE)),nl, | |
1279 | cspm_trans(CHOICE,Action,X1,WF). | |
1280 | ||
1281 | cspm_trans(repInternalChoice(GeneratorList,Body,Span), tau(rep_int_choice(Span)),Res,_WF) :- | |
1282 | % print(repInternalChoice(GeneratorList,Span)),nl, | |
1283 | replicate_expand_set_comprehension([Body],GeneratorList,Bodies), | |
1284 | % print(bodies(Bodies)),nl,nl, | |
1285 | (is_empty_set(Bodies,true) | |
1286 | -> add_error(cspm_trans,'Empty set for replicated internal choice: ',Bodies,Span),fail | |
1287 | ; is_member_set(Res,Bodies)). | |
1288 | ||
1289 | cspm_trans(repInterleave(GeneratorList,Body,Span), A, X,WF) :- | |
1290 | %% tools:print_bt_message(repInterleave(GeneratorList)), %% | |
1291 | % multiplicity is relevant for |||, so add variables to Body below in case Variables are not used | |
1292 | extract_variables_from_generator_list(GeneratorList,Variables), | |
1293 | replicate_expand_set_comprehension([na_tuple([Body|Variables])],GeneratorList,setValue(Bodies)), | |
1294 | convert_into_interleave(Bodies,Span,INTLV), | |
1295 | %% tools:print_bt_message(intlv(INTLV)), %% | |
1296 | cspm_trans(INTLV,A,X,WF). %, tools:print_bt_message(sol(A,X)). | |
1297 | ||
1298 | ||
1299 | cspm_trans(repSequence(GeneratorList,Body,Span),A,X,WF) :- | |
1300 | % print(repSequence(GeneratorList)),nl, %% | |
1301 | expand_listcomprehension(rangeEnum([Body]),GeneratorList,list(Bodies)), | |
1302 | % print(bodies(Bodies)),nl, %% | |
1303 | convert_into_seqcomp(Bodies,Span,SEQ), %print(sequential(SEQ)),nl, | |
1304 | cspm_trans(SEQ,A,X,WF). | |
1305 | ||
1306 | ||
1307 | cspm_trans(procRepAParallel(GeneratorList,pair(SyncSet,Body),Span), A, X,WF) :- | |
1308 | %print(procRepAParallel(GeneratorList,SyncSet)),nl, | |
1309 | % multiplicity is relevant for sharing (it makes a difference if 1 or 2 copies are present), so add variables to Body below in case Variables are not used | |
1310 | extract_variables_from_generator_list(GeneratorList,Variables), | |
1311 | %print(extractedVars(Variables)),nl, | |
1312 | replicate_expand_set_comprehension([list([SyncSet,Body,Variables])],GeneratorList,setValue(Bodies)), | |
1313 | % print(bodies_repA(Bodies)),nl, | |
1314 | convert_into_eaParallel(Bodies,Span,APAR,_ALPH), % nl,print(eapar(APAR)),nl, | |
1315 | cspm_trans(APAR,A,X,WF). | |
1316 | ||
1317 | ||
1318 | cspm_trans(procRepLinkParallel(SyncSet,GeneratorList,Body,Span), A, X,WF) :- | |
1319 | % print(procRepLinkParallel(GeneratorList)),nl, | |
1320 | expand_listcomprehension(rangeEnum([Body]),GeneratorList,list(Bodies)), | |
1321 | % print(bodies(Bodies)),nl, | |
1322 | convert_into_linkParallel(Bodies,SyncSet,Span,APAR,Body), %print(linkpar(APAR)),nl, | |
1323 | %when((ground(APAR)), | |
1324 | cspm_trans(APAR,A,X,WF). | |
1325 | ||
1326 | cspm_trans(procRepSharing(SyncSet,GeneratorList,Body,Span), A, X,WF) :- | |
1327 | % print(procRepSharing(GeneratorList)),nl, | |
1328 | % multiplicity is relevant for sharing, so add variables to Body below in case Variables are not used | |
1329 | extract_variables_from_generator_list(GeneratorList,Variables), | |
1330 | replicate_expand_set_comprehension([na_tuple([Body|Variables])],GeneratorList,setValue(Bodies)), | |
1331 | % print(bodies(Bodies)),nl, | |
1332 | convert_into_Sharing(Bodies,SyncSet,Span,APAR), %print(repshare(APAR)),nl, | |
1333 | cspm_trans(APAR,A,X,WF). | |
1334 | ||
1335 | % ---------- | |
1336 | ||
1337 | cspm_hide_action(ActionX,X, CList,Span, ActionAfterHiding,ResultingCSPExpr) :- | |
1338 | ( functor_dif(ActionX,tick), ActionX=ActionAfterHiding, | |
1339 | tl_normalise(ehide(X,CList,Span),ResultingCSPExpr), | |
1340 | not_hidden(ActionAfterHiding,CList) | |
1341 | ; merge_span_into_event(ActionX,Span,NActionX), | |
1342 | ActionAfterHiding=tau(hide(NActionX)), | |
1343 | tl_normalise(ehide(X,CList,Span),ResultingCSPExpr), | |
1344 | hidden(ActionX,CList) | |
1345 | ; ActionAfterHiding=tick(TS), ActionX=tick(TS), ResultingCSPExpr=omega | |
1346 | ). | |
1347 | ||
1348 | :- block cspm_if_trans(-,?,?,?, ?,?,?,?,?). | |
1349 | cspm_if_trans(true,Then,_Else,AS,X1,_S1,S2,_S3,WF) :- !, %print(ifte_true(Then)),nl, | |
1350 | full_normalise_csp_process(Then,NThen), | |
1351 | cspm_trans(NThen,A,X1,WF), | |
1352 | merge_span_into_event(A,S2,AS). | |
1353 | cspm_if_trans(false,_Then,Else,AS,X1,_S1,_S2,S3,WF) :- !, %print(ifte_false(Else)),nl, | |
1354 | full_normalise_csp_process(Else,NElse), cspm_trans(NElse,A,X1,WF), | |
1355 | merge_span_into_event(A,S3,AS). | |
1356 | cspm_if_trans(Other,Then,Else,AS,X1,S1,S2,S3,WF) :- | |
1357 | add_internal_error('Internal Error: Not a boolean value inside if-then-else: ', | |
1358 | cspm_if_trans(Other,Then,Else,AS,X1,S1,S2,S3,WF)), | |
1359 | fail. | |
1360 | ||
1361 | :- block convert_into_interleave(-,-,?). | |
1362 | convert_into_interleave([],Span,skip(Span)). | |
1363 | convert_into_interleave([na_tuple([H|_])|T],Span,R) :- convert_into_interleave3(T,H,Span,R). | |
1364 | :- block convert_into_interleave3(-,?,?,?). | |
1365 | convert_into_interleave3([],X,_Span,X). | |
1366 | convert_into_interleave3([na_tuple([H2|_])|T],H1,Span,'|||'(H1,Rest,Span)) :- | |
1367 | convert_into_interleave3(T,H2,Span,Rest). | |
1368 | ||
1369 | ||
1370 | :- block convert_into_choice(-,-,?). | |
1371 | convert_into_choice([],Span,stop(Span)). | |
1372 | convert_into_choice([H|T],Span,R) :- convert_into_choice3(T,H,Span,R). | |
1373 | :- block convert_into_choice3(-,?,?,?). | |
1374 | convert_into_choice3([],X,_Span,X). | |
1375 | convert_into_choice3([H2|T],H1,Span,'[]'(H1,Rest,Span)) :- convert_into_choice3(T,H2,Span,Rest). | |
1376 | ||
1377 | :- block convert_into_seqcomp(-,-,?). | |
1378 | convert_into_seqcomp(Bodies,Span,Res) :- convert_into_seqcomp2(Bodies,Span,Res). | |
1379 | convert_into_seqcomp2([],Span,skip(Span)) :- print(convert_into_seqcomp2([],Span,skip(Span))),nl. | |
1380 | convert_into_seqcomp2([H|T],Span,R) :- convert_into_seqcomp3(T,H,Span,R). | |
1381 | :- block convert_into_seqcomp3(-,?,?,?). | |
1382 | convert_into_seqcomp3([],X,_Span,X). | |
1383 | convert_into_seqcomp3([H2|T],H1,Span,';'(H1,Rest,Span)) :- | |
1384 | convert_into_seqcomp2([H2|T],Span,Rest). | |
1385 | ||
1386 | ||
1387 | :- block convert_into_eaParallel(-,-,?,?). | |
1388 | convert_into_eaParallel([],Span,skip(Span),setValue([])). | |
1389 | convert_into_eaParallel([H|T],Span,APAR,ALPH) :- | |
1390 | when(nonvar(T),convert_into_eaParallel3([H|T],Span,APAR,ALPH)). | |
1391 | convert_into_eaParallel3([list([Sync,X,_])],_Span,X,ESync) :- !, evaluate_argument(Sync,ESync). | |
1392 | convert_into_eaParallel3([list([CListX,X,_]),L2|T], Span,AlphPar, Alphabet ) :- | |
1393 | when(nonvar(T),(convert_into_eaParallel3([L2|T],Span, Rest,RestAlphabet), | |
1394 | evaluate_argument(CListX,ECListX), | |
1395 | evaluate_argument(union(RestAlphabet,ECListX),Alphabet), | |
1396 | /* put more complicated process onto the left: better efficiency for cspm_trans */ | |
1397 | % TO DO: we could think about splitting the list in two | |
1398 | AlphPar = aParallel(RestAlphabet,Rest,ECListX,X,Span))). % only aParallel | |
1399 | ||
1400 | ||
1401 | ||
1402 | :- block convert_into_Sharing(-,?,-,?). | |
1403 | convert_into_Sharing([],_,Span,skip(Span)). | |
1404 | convert_into_Sharing([na_tuple([H|_])|T],SyncSet,Span,R) :- convert_into_Sharing3([H|T],SyncSet,Span,R). | |
1405 | :- block convert_into_Sharing3(-,?,?,?). | |
1406 | convert_into_Sharing3([X],_Sync,_Span,Res) :- !, Res=X. | |
1407 | convert_into_Sharing3([X|T],CListX,Span,sharing(CListX,Rest,X,Span) ) :- | |
1408 | /* put more complicated process onto the left: better efficiency for cspm_trans */ | |
1409 | convert_into_Sharing(T,CListX,Span,Rest). | |
1410 | ||
1411 | :- block convert_into_linkParallel(-,?,-,?,?). | |
1412 | convert_into_linkParallel([],_,Span,skip(Span),Body) :- | |
1413 | add_error(haskell_csp,'Empty Set in Replicated Linked Parallel: ',Body). | |
1414 | convert_into_linkParallel([H|T],SyncSet,Span,APAR,Body) :- | |
1415 | convert_into_linkParallel3([H|T],SyncSet,Span,APAR,Body). | |
1416 | :- block convert_into_linkParallel3(-,?,?,?,?). | |
1417 | convert_into_linkParallel3([X],_Sync,_Span,Res,_) :- !, Res=X. | |
1418 | convert_into_linkParallel3([X|T],CListX,Span,lParallel(CListX,Rest,X,Span),Body ) :- | |
1419 | /* put more complicated process onto the left: better efficiency for cspm_trans */ | |
1420 | convert_into_linkParallel(T,CListX,Span,Rest,Body). | |
1421 | ||
1422 | /* ------------------------------------- */ | |
1423 | ||
1424 | /* top_level_normalise */ | |
1425 | /* Just check the top-level of the csp expression to see if it can | |
1426 | be simplified/normalised */ | |
1427 | tl_normalise('[]'(X,Y,Span),R) :- !, %print(tl(X)),nl,print(t2(Y)),nl,nl, | |
1428 | (X=Y -> R=X | |
1429 | ; is_stop(X,_) -> R=Y | |
1430 | ; is_stop(Y,_) -> R=X | |
1431 | ; Y='[]'(X,Y2,_) -> tl_normalise('[]'(X,Y2,Span),R) % X [] X [] Y == X [] Y ; relevant e.g. for ASTD library example | |
1432 | ; Y='[]'(Y2,X,_) -> tl_normalise('[]'(X,Y2,Span),R) | |
1433 | ; X='[]'(Y,X2,_) -> tl_normalise('[]'(Y,X2,Span),R) | |
1434 | ; X='[]'(X2,Y,_) -> tl_normalise('[]'(Y,X2,Span),R) | |
1435 | ; R='[]'(X,Y,Span) | |
1436 | ). /* TO DO: also sort X,Y !? */ | |
1437 | tl_normalise('|||'(X,Y,Span),R) :- !, | |
1438 | (is_stop(X,S),is_stop(Y,_) | |
1439 | -> R=stop(S) | |
1440 | ; ((X==omega;is_skip(X)) -> R=Y /* law 6.16 on page 142 of Roscoe's book */ | |
1441 | ; ((Y==omega;is_skip(Y)) -> R=X /* same law, for RHS */ | |
1442 | ; % this leads to performance loss: tl_normalise should only do top-level normalisation full_normalise_csp_process(X,XR), full_normalise_csp_process(Y,YR), | |
1443 | ((preference(cspm_detailed_animation,true);X @=<Y) | |
1444 | -> R='|||'(X,Y,Span) | |
1445 | ; R='|||'(Y,X,Span)) %% Warning: this can invalidate left-right Span information | |
1446 | ) | |
1447 | ) | |
1448 | ). % we could replace skip|||P by P | |
1449 | % (X==stop -> R=Y ; (Y==stop -> R=X ; R='|||'(X,Y))). P ||| stop not equal to stop (because of omega) | |
1450 | tl_normalise(ehide(X,CList,Span),R) :- !, | |
1451 | (is_stop(X,S) -> R=stop(S) % Concealement law L4 | |
1452 | ; is_skip(X,S) -> R=skip(S) % Concealement law L5 | |
1453 | ; CList == [] -> R=X % Concealement law L1 | |
1454 | ; try_tl_normalise(X,NX),R=ehide(NX,CList,Span)). | |
1455 | tl_normalise(eprocRenaming(RL,X,Span),R) :- !, | |
1456 | (is_stop(X,S) -> R=stop(S) | |
1457 | ; is_skip(X,S) -> R=skip(S) | |
1458 | ; try_tl_normalise(X,NX),R=eprocRenaming(RL,NX,Span)). | |
1459 | tl_normalise(';'(X,Y,SPAN),R) :- !, | |
1460 | (is_skip(X) -> R=Y /* Law on page 140 of Roscoe */ | |
1461 | ; is_stop(X,S) -> R=stop(S) | |
1462 | ; is_skip(Y) -> R=X | |
1463 | ; R = ';'(X,Y,SPAN) ). | |
1464 | tl_normalise('/\\'(X,Y,Span),R) :- !, | |
1465 | (is_stop(X,_) -> R=Y ; (is_stop(Y,_) -> R=X ; R='/\\'(X,Y,Span))). | |
1466 | tl_normalise(ifte(A,B,C,_,_,_),R) :- !, % print(norm_ifte(A)),nl, | |
1467 | ~~mnf(haskell_csp:evaluate_boolean_expression(A,ARes)), | |
1468 | % print(res(ARes)),nl, | |
1469 | tl_normalise_ifte(ARes,B,C,R). | |
1470 | ||
1471 | is_stop(X,S) :- nonvar(X),X=stop(S). | |
1472 | ||
1473 | :- block tl_normalise_ifte(-,?,?,?). | |
1474 | tl_normalise_ifte(true,B,_C,R) :- !,full_normalise_csp_process(B,R). | |
1475 | tl_normalise_ifte(false,_,C,R) :- !, full_normalise_csp_process(C,R). | |
1476 | % evaluate_boolean_expression/2 will always throw an exception if A is not a boolean test | |
1477 | % probably this case will never occur | |
1478 | % tl_normalise_ifte(A,B,C,_R) :- add_error(tl_normalise,'Not a boolean test: ',A:B:C). | |
1479 | ||
1480 | try_tl_normalise(A,R) :- (tl_normalise(A,B) -> R=B ; R=A). | |
1481 | ||
1482 | is_skip(X) :- nonvar(X), X=skip(_). | |
1483 | is_skip(X,Y) :- nonvar(X), X=skip(Y). | |
1484 | % TO DO: add rules esharing(_,stop(S),stop(_),_) -> stop(S), | |
1485 | ||
1486 | % P [] STOP = P | |
1487 | :- assert_must_succeed(( | |
1488 | P='[]'(skip(_),stop(span1),span2), | |
1489 | haskell_csp: full_normalise_csp_process(P,NormP), | |
1490 | NormP=skip(_))). | |
1491 | % P [] P = P | |
1492 | :- assert_must_succeed(( | |
1493 | P='[]'(skip(span1),skip(span1),span3), | |
1494 | haskell_csp: full_normalise_csp_process(P,NormP), | |
1495 | NormP=skip(span1))). | |
1496 | % P ||| STOP = STOP | |
1497 | :- assert_must_succeed(( | |
1498 | P='|||'(skip(_),stop(span1),span2), | |
1499 | haskell_csp: full_normalise_csp_process(P,NormP), | |
1500 | NormP=stop(span1))). | |
1501 | % SKIP; (P [] STOP) = P | |
1502 | :- assert_must_succeed(( | |
1503 | P=';'(skip(_),'[]'(skip(span1),stop(span3),span4),span2), | |
1504 | haskell_csp: full_normalise_csp_process(P,NormP), | |
1505 | NormP='[]'(skip(span1),stop(span3),span4))). | |
1506 | % P; SKIP = P | |
1507 | :- assert_must_succeed(( | |
1508 | P=';'(stop(_),skip(span1),span2), | |
1509 | haskell_csp: full_normalise_csp_process(P,NormP), | |
1510 | NormP=stop(_))). | |
1511 | ||
1512 | /* ------------------------------------- */ | |
1513 | %full_normalise_csp_process(P,_) :- print(full_normalise_csp_process(P)),nl,fail. | |
1514 | /* TO DO: add other procRep,... intermediate operators */ | |
1515 | full_normalise_csp_process(P,NormP) :- full_normalise_csp_process(P,NormP,outer). | |
1516 | :- block full_normalise_csp_process(-,?,?). | |
1517 | full_normalise_csp_process('|||'(X,Y,Span),Res,_) :- !, | |
1518 | %full_normalise_csp_process(X,NX,inner), full_normalise_csp_process(Y,NY,inner), | |
1519 | full_normalise_csp_process(X,NX,outer), full_normalise_csp_process(Y,NY,outer), | |
1520 | tl_normalise('|||'(NX,NY,Span),Res). | |
1521 | % both clausels below will be probably never executed. procRenamingComp/3 and procRepAParallel/3 as | |
1522 | % replicated process expressions will be translated to agent_calls in the compiling/analyzing stage | |
1523 | % of loading the respective CSP model. DEAD CODE: | |
1524 | /*full_normalise_csp_process(procRenamingComp(X,GeneratorList,RenameList),Res,_) :- !, | |
1525 | %print(normalise_procCompRenaming(GeneratorList)),nl, | |
1526 | replicate_expand_set_comprehension(RenameList,GeneratorList,setValue(ExpandedRenames)), | |
1527 | %print(exp(ExpandedRenames)),nl, | |
1528 | Res = procRenaming(ExpandedRenames,X,no_loc_info_available). | |
1529 | full_normalise_csp_process(procRepAParallel(GeneratorList,pair(SyncSet,Body),Span), Res,_) :- !, | |
1530 | %print(procRepAParallel(GeneratorList,SyncSet)),nl, | |
1531 | extract_variables_from_generator_list(GeneratorList,Variables), | |
1532 | replicate_expand_set_comprehension([list([SyncSet,Body,Variables])],GeneratorList,setValue(Bodies)), | |
1533 | %print(bodies(Bodies)),nl, | |
1534 | convert_into_eaParallel(Bodies,Span,APAR,_ALPH), %print(apar(APAR,_ALPH)),nl, | |
1535 | full_normalise_csp_process(APAR,Res,inner). */ | |
1536 | full_normalise_csp_process(repInterleave(GeneratorList,Body,Span),Res,_) :- !, | |
1537 | extract_variables_from_generator_list(GeneratorList,Variables), | |
1538 | replicate_expand_set_comprehension([na_tuple([Body|Variables])],GeneratorList,setValue(Bodies)), | |
1539 | convert_into_interleave(Bodies,Span,Res). | |
1540 | full_normalise_csp_process(sharing(CList,X,Y,SrcSpan),Res,_) :- !, %trace, | |
1541 | evaluate_argument(CList,EvCList), | |
1542 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCList,ECList,SrcSpan)), | |
1543 | full_normalise_csp_process(X,NX,outer), | |
1544 | full_normalise_csp_process(Y,NY,outer), | |
1545 | Res = esharing(ECList,NX,NY,SrcSpan). | |
1546 | full_normalise_csp_process(aParallel(CListX,X,CListY,Y,SrcSpan),Res,_) :- !, | |
1547 | evaluate_argument(CListX,EvCListX), | |
1548 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCListX,ECListX,SrcSpan)), | |
1549 | evaluate_argument(CListY,EvCListY), | |
1550 | ~~mnf(haskell_csp:expand_channel_pattern_expression(EvCListY,ECListY,SrcSpan)), | |
1551 | full_normalise_csp_process(X,NX,outer), | |
1552 | full_normalise_csp_process(Y,NY,outer), | |
1553 | %print(eaParallel(ECListX,NX,ECListY,NY,SrcSpan)),nl, | |
1554 | Res = eaParallel(ECListX,NX,ECListY,NY,SrcSpan). | |
1555 | /* Unfold if Par ground and unfolded value ground ?? */ | |
1556 | full_normalise_csp_process(agent_call(Span,F,Par),Res,outer) :- % only allow outer agent_calls to be unfolded to avoid infinite expansion for e.g. P(1) = P(1) ||| P(1) | |
1557 | preference(cspm_detailed_animation,false), | |
1558 | %% fail, %% fail: agent_calls are not expanded here, which means better source location feedback in animator | |
1559 | %% WE COULD MAKE THIS AN OPTION IN THE PREFERENCES; I am not sure what the performance impact is | |
1560 | %% for scheduler this leads to a substantial increase in the number of states | |
1561 | !, | |
1562 | ((ground(Par),unfold_function_call_once(F,Par,Value,Span), | |
1563 | (ground(Value) ; | |
1564 | agent_can_be_unfolded(Value) | |
1565 | ) | |
1566 | ) | |
1567 | -> full_normalise_csp_process(Value,Res,outer) | |
1568 | ; Res = agent_call(Span,F,Par) | |
1569 | ). | |
1570 | full_normalise_csp_process(val_of(RenamedX,Span),NormState,_) :- !, | |
1571 | (symbol(RenamedX,_X,_,_) -> | |
1572 | full_normalise_csp_process(agent_call(Span,RenamedX,[]),NormState,_) | |
1573 | ; otherwise -> | |
1574 | % does this occur in some case (see coverage info) | |
1575 | full_normalise_csp_process(RenamedX,NormState,_) | |
1576 | ). | |
1577 | full_normalise_csp_process(ifte(Test,Then,Else,S1,S2,S3),R,_) :- | |
1578 | ground(Test),!, | |
1579 | evaluate_boolean_expression(Test,Res), | |
1580 | (Res == true -> | |
1581 | full_normalise_csp_process(Then,R) | |
1582 | ; Res == false -> | |
1583 | full_normalise_csp_process(Else,R) | |
1584 | ; otherwise -> | |
1585 | add_internal_error('Internal Error: Not a boolean value inside if-then-else: ', | |
1586 | full_normalise_csp_process(ifte(Test,Then,Else,S1,S2,S3),R,_)),fail | |
1587 | ). | |
1588 | full_normalise_csp_process(ifte(Test,Then,Else,S1,S2,S3),R,_) :- !, | |
1589 | R = ifte(Test,Then,Else,S1,S2,S3). % test could be false or true; top-level test could be evaluated ?! | |
1590 | full_normalise_csp_process('&'(Test,Then),R,_) :- !, R = '&'(Test,Then). % test could be false; don't unfold agent_calls inside Then | |
1591 | full_normalise_csp_process(';'(P,Q,SPAN),R,Scope) :- !, | |
1592 | full_normalise_csp_process(P,NP,Scope), | |
1593 | tl_normalise(';'(NP,Q,SPAN),R). | |
1594 | full_normalise_csp_process(prefix(SPAN,Values,ChannelExpr,CSP,SPAN2),R,_) :- !, | |
1595 | (empty_inGuard_set(Values) -> | |
1596 | R=stop(SPAN) % (STOP-step) ?x:{} -> P = STOP (law 1.15) | |
1597 | ; otherwise -> | |
1598 | R = prefix(SPAN,Values,ChannelExpr,CSP,SPAN2) | |
1599 | ). | |
1600 | full_normalise_csp_process(head(List),R,_) :- !, R=head(List). % should we evaluate ?? | |
1601 | full_normalise_csp_process(agent_call(Span,A,Par),R,_) :- !, R=agent_call(Span,A,Par). | |
1602 | % DEAD CODE!!! agent_call_curry/2 will be translated into nested agent_call in the precompiling phase. | |
1603 | %full_normalise_csp_process(agent_call_curry(A,Par),R,_) :- !, print(agent_call_curry(A,Par)),nl,R=agent_call_curry(A,Par). | |
1604 | full_normalise_csp_process(ehide(X,CList,Span),R,_) :- !, | |
1605 | full_normalise_csp_process(X,NX,inner), | |
1606 | tl_normalise(ehide(NX,CList,Span),R). | |
1607 | full_normalise_csp_process(eprocRenaming(RL,X,Span),R,_) :- !, | |
1608 | full_normalise_csp_process(X,NX,inner), | |
1609 | tl_normalise(eprocRenaming(RL,NX,Span),R). | |
1610 | full_normalise_csp_process(Proc,Res,_) :- | |
1611 | binary_top_level_process_operator_possible_to_be_normalised(Proc,F,X,Y,Span),!, | |
1612 | full_normalise_csp_process(X,NX,inner), | |
1613 | full_normalise_csp_process(Y,NY,inner), | |
1614 | functor(NTerm,F,3),arg(1,NTerm,NX),arg(2,NTerm,NY),arg(3,NTerm,Span), | |
1615 | tl_normalise(NTerm,Res). | |
1616 | full_normalise_csp_process(Proc,Res,_) :- definite_cspm_process_construct(Proc,Spans,Rest,RecCSP), !, | |
1617 | functor(Proc,F,N), functor(Res,F,N), | |
1618 | maplist(full_normalise_csp_process_inner(inner),RecCSP,NormRecCSP), | |
1619 | definite_cspm_process_construct(Res,Spans,Rest,NormRecCSP). | |
1620 | full_normalise_csp_process(P,R,_) :- !, | |
1621 | add_warning(full_normalise_csp_process,'Could not normalise: ',P),R=P. | |
1622 | ||
1623 | full_normalise_csp_process_inner(ProcLabel,Proc,NProc) :- | |
1624 | full_normalise_csp_process(Proc,NProc,ProcLabel). | |
1625 | ||
1626 | binary_top_level_process_operator_possible_to_be_normalised(ProcessTerm,F,X,Y,Span) :- | |
1627 | functor(ProcessTerm,F,3), | |
1628 | memberchk(F,['|||','[]','/\\']), | |
1629 | arg(1,ProcessTerm,X),arg(2,ProcessTerm,Y),arg(3,ProcessTerm,Span). | |
1630 | ||
1631 | empty_inGuard_set(Values) :- | |
1632 | member(inGuard(_X,Set),Values), | |
1633 | is_empty_set(Set,true),!. | |
1634 | ||
1635 | normalise_cspm_state(State,NormState) :- | |
1636 | full_normalise_csp_process(State,NormState). | |
1637 | ||
1638 | %% Probably DEAD CODE !!! (wait for the next coverage release to prove this assumption) | |
1639 | :- assert_must_succeed((agent_can_be_unfolded(X), X=procRenamingComp(_,_,_))). | |
1640 | :- assert_must_succeed((agent_can_be_unfolded(X), X=aParallel(_,_,_,_,_))). | |
1641 | agent_can_be_unfolded(procRenamingComp(_,_,_)). | |
1642 | agent_can_be_unfolded(aParallel(_,_,_,_,_)). | |
1643 | agent_can_be_unfolded(repInterleave(_,_,_)). | |
1644 | ||
1645 | /* ------------------------------------- */ | |
1646 | ||
1647 | ||
1648 | /* EVALUATING Agent Call arguments */ | |
1649 | ||
1650 | evaluate_agent_call_parameters(AgentName,Par,_) :- var(AgentName),!, | |
1651 | add_internal_error('Internal Error: Trying to call VARIABLE function: ',evaluate_agent_call_parameters(AgentName,Par,_)),fail. | |
1652 | evaluate_agent_call_parameters(AgentName,Par,_) :- var(Par),!, | |
1653 | add_internal_error('Internal Error: Trying to call VARIABLE parameters: ',evaluate_agent_call_parameters(AgentName,Par,_)),fail. | |
1654 | %evaluate_agent_call_parameters(agent_call(AName,[]),Par,EAgentCall) :- atomic(AName),!, | |
1655 | % /* then AName must represent a lambda function which has been compiled ?!!? */ | |
1656 | % l_evaluate_arguments(Par,EPar), | |
1657 | % EAgentCall =.. [AName|EPar]. | |
1658 | evaluate_agent_call_parameters(_Call,Par,EPar) :- Par==[],!, EPar=[]. % nothing to evaluate | |
1659 | evaluate_agent_call_parameters(AgentNameExpr,Par,_EAgentCall) :- \+ atomic(AgentNameExpr),!, | |
1660 | add_error(haskell_csp,'Trying to call non-atomic function: ',agent_call(AgentNameExpr,Par),AgentNameExpr),fail. | |
1661 | %print(non_atomic_funcall(AgentNameExpr)),nl, | |
1662 | % ~~mnf(haskell_csp:evaluate_argument(AgentNameExpr,AName)), print(function(AName)),nl, | |
1663 | % l_evaluate_arguments(Par,EPar), EAgentCall = apply(AName,EPar). | |
1664 | evaluate_agent_call_parameters(AName,Par,EPar) :- | |
1665 | length(Par,Arity), | |
1666 | (agent_parameters(AName,Arity,LazyStrictList) | |
1667 | -> true | |
1668 | ; add_error(evaluate_agent_call_parameters,'Unknown function call: ',(AName/Arity)) | |
1669 | ), | |
1670 | l_evaluate_arguments(Par,LazyStrictList,EPar). | |
1671 | % EAgentCall =.. [AName|EPar]. | |
1672 | ||
1673 | ||
1674 | l_evaluate_arguments([],[],[]). | |
1675 | l_evaluate_arguments([A|T],[Lazy|TL],[EA|ET]) :- | |
1676 | %% print(eval_arg(A,Lazy)),nl, %% | |
1677 | (Lazy=lazy -> ~~mnf(haskell_csp:evaluate_argument(A,EA)) | |
1678 | ; ~~mnf(haskell_csp:force_evaluate_argument(A,EA)) | |
1679 | ), | |
1680 | %% print(arg_res(A,EA)),nl, %% | |
1681 | l_evaluate_arguments(T,TL,ET). | |
1682 | ||
1683 | ||
1684 | evaluate_lambda_arguments([],[],[]). | |
1685 | evaluate_lambda_arguments([A|T],[FormalPar|FT],[EA|ET]) :- | |
1686 | %% print(eval_arg(A,Lazy)),nl, | |
1687 | (var(FormalPar) -> A=EA % will be copied into lambda body and evaluated then ~~mnf(haskell_csp:evaluate_argument(A,EA)) | |
1688 | ; ~~mnf(haskell_csp:force_evaluate_argument(A,EA)) % it is a pattern; we need to evaluate argument | |
1689 | ), | |
1690 | %% print(arg_res(A,EA)),nl, | |
1691 | evaluate_lambda_arguments(T,FT,ET). | |
1692 | /* ------------------------------------- */ | |
1693 | ||
1694 | /* EVALUATING Channel arguments */ | |
1695 | ||
1696 | setup_skel(_,in(_)). | |
1697 | ||
1698 | setup_channel_skeleton(io(V,Ch,_)) :- | |
1699 | channel_type_list(Ch,ChannelTypes), | |
1700 | maplist(setup_skel,ChannelTypes,V). | |
1701 | ||
1702 | /* ------------------------------------- */ | |
1703 | ||
1704 | /* enumerate_action(A) : if part of the inputs of A are not determined: enumerate | |
1705 | possible values */ | |
1706 | ||
1707 | cspm_trans_enum(E,A,E2) :- | |
1708 | init_wait_flags(WF), | |
1709 | cspm_trans(E,A,E2,WF), | |
1710 | % tools:print_bt_message(grounding_waitflags(A)), %% | |
1711 | ground_wait_flags(WF), | |
1712 | % TO DO: we could also add enumerate_action to the WF store: in principle sets inGuards should be smaller | |
1713 | % tools:print_bt_message(enumerate_action(E,A)), %% | |
1714 | enumerate_action(A) | |
1715 | % ,tools:print_bt_message(finished_enumerate_action(A)),nl %% | |
1716 | . | |
1717 | ||
1718 | ||
1719 | /* TO DO: add enumeration to hide + removed values by rename; use tau(V,Ch) ?? */ | |
1720 | ||
1721 | enumerate_action(X) :- X \= tick(_), X\=tau(_), X\= io(_,_,_), !, | |
1722 | add_internal_error('Internal error: Unknown CSP event: ', enumerate_action(X)). | |
1723 | enumerate_action(tick(_)). | |
1724 | enumerate_action(tau(X)) :- (nonvar(X) -> enumerate_tau_argument(X) ; true). | |
1725 | enumerate_action(io(Vals,Channel,Span)) :- | |
1726 | if((channel_type_list(Channel,ChannelTypes)), | |
1727 | (enume_ch_vals(ChannelTypes,Vals,Channel,Span,io(Vals,Channel,Span))), | |
1728 | add_error(enumerate_action,'Channel not declared: ',Channel,Span)). | |
1729 | ||
1730 | enumerate_tau_argument(io(V,C,S)) :- !,enumerate_action(io(V,C,S)). | |
1731 | enumerate_tau_argument(hide(X)) :- !,enumerate_action(X). | |
1732 | enumerate_tau_argument(link(_AX,AY)) :- !,enumerate_action(AY). | |
1733 | enumerate_tau_argument(_). | |
1734 | ||
1735 | :- use_module(probsrc(translate),[translate_event/2]). | |
1736 | %% enume_ch_vals(T,V,C,_Span,FullEvent) :- print(enume_ch_vals(T,V,C)),nl,fail. %% | |
1737 | enume_ch_vals([],[],_,_Span,_) :- !. | |
1738 | enume_ch_vals([],Vals,_Channel,Span,FullEvent) :- !, | |
1739 | (Vals = [in(V)] | |
1740 | -> empty_tuple(V) /* the empty dotTuple */ | |
1741 | ; translate_event(FullEvent,ES), | |
1742 | add_error(enumerate_action,'Too many output values on channel: ',ES:Vals, Span) | |
1743 | ). | |
1744 | enume_ch_vals([Type|RestTypes],Vals,Channel,Span,FullEvent) :- % T \= [], | |
1745 | enume_ch_vals2(Vals,Type,RestTypes,Channel,Span,FullEvent). | |
1746 | ||
1747 | enume_ch_vals2(X,Type,_RestTypes,_Channel,Span,FullEvent) :- % print(ecv2(X,Type,RestTypes,Channel)),nl, | |
1748 | var(X),!, | |
1749 | translate_event(FullEvent,ES), | |
1750 | add_error(haskell_csp,'Variable value list on channel: ',ES:X:Type,Span),fail. | |
1751 | enume_ch_vals2([],Type,RestTypes,_Channel,Span,FullEvent) :- !, | |
1752 | translate_event(FullEvent,ES), | |
1753 | add_error(enumerate_action,'Too few output values on channel: ',ES:[Type:RestTypes], Span). | |
1754 | enume_ch_vals2([in(V)|TAIL],Type,RestTypes,Channel,Span,FullEvent) :- nonvar(V), | |
1755 | V=tuple(X),nonvar(X),X=[H|T], \+ csp_constructor(H,_,_), | |
1756 | !, % sometimes an in contains dot tuples; test above not very elegant; can we simplify this ?? | |
1757 | (T==[] -> | |
1758 | enume_ch_vals2([in(H)|TAIL],Type,RestTypes,Channel,Span,FullEvent) | |
1759 | ; enume_ch_vals2([in(H),in(tuple(T))|TAIL],Type,RestTypes,Channel,Span,FullEvent)). | |
1760 | enume_ch_vals2([in(V)|TAIL],Type,RestTypes,Channel,Span,_FullEvent) :- | |
1761 | TAIL==[],!, /* only treat it as a tail_in(X) if it is definitely at the end of the list | |
1762 | see example LetTestChannel -> TEST(2) process for complication if we do | |
1763 | not check that TAIL==[] */ | |
1764 | (RestTypes=[] | |
1765 | -> enumerate_channel_input_value(Type,V,Channel,Span) | |
1766 | ; enumerate_channel_input_value('dotTupleType'([Type|RestTypes]),V,Channel,Span) | |
1767 | ). | |
1768 | enume_ch_vals2([IODVal|TV],Type,RestTypes,Channel,Span,FullEvent) :- !, | |
1769 | enumerate_channel_value_type(IODVal,Type,Channel,Span), | |
1770 | enume_ch_vals(RestTypes,TV,Channel,Span,FullEvent). | |
1771 | ||
1772 | ||
1773 | enumerate_channel_value_type(IOD,Type,Channel,Span) :- | |
1774 | %print(enumerate_channel_value_type(IOD,Type,Channel,Span)),nl, | |
1775 | (IOD=in(HX) %; IOD=dot(HX)) | |
1776 | -> enumerate_channel_input_value(Type,HX,Channel,Span) | |
1777 | ; (ground(IOD) | |
1778 | -> check_channel_input_output_value(IOD,Type,Channel,Span,'Type error in channel input: ') | |
1779 | ; enumerate_channel_input_value(Type,IOD,Channel,Span) | |
1780 | ) | |
1781 | ). | |
1782 | ||
1783 | check_channel_input_output_value(X,Type,Ch,Span,ErrMsg) :- | |
1784 | when(ground(X), ((peel_in(X,PX),is_member_set_alsoPat(PX,Type)) -> true | |
1785 | ; add_error(check_channel_output_value,ErrMsg,(Ch:(val(X):type(Type))),Span))). | |
1786 | ||
1787 | /* peel input values which may lurk inside datavalues, especially records */ | |
1788 | peel_in(in(X),R) :- !, R=X. | |
1789 | peel_in(record(F,L),R) :- !, | |
1790 | R=record(F,PL), | |
1791 | maplist(peel_in,L,PL). | |
1792 | peel_in(X,X). | |
1793 | ||
1794 | :- assert_must_succeed(( haskell_csp:enumerate_channel_input_value(setFromTo(1,3),R,c,unknown), | |
1795 | R==int(2) )). | |
1796 | ||
1797 | enumerate_channel_input_value(Type,Val,Ch,Span) :- | |
1798 | MAXRECURSIONDEPTH = 2, | |
1799 | enumerate_channel_input_value(Type,Val,Ch,MAXRECURSIONDEPTH,Span). | |
1800 | ||
1801 | ||
1802 | enumerate_channel_input_value(Type,Val,Ch,MaxRec,Span) :- | |
1803 | (ground(Val) | |
1804 | -> check_channel_input_output_value(Val,Type,Ch,Span,'Type error in channel output: ') | |
1805 | ; enumerate_channel_input_value1(Type,Val,Ch,MaxRec,Span) | |
1806 | ). | |
1807 | ||
1808 | enumerate_channel_input_value1(Type,Val,Ch,MaxRec,Span) :- | |
1809 | ((nonvar(Val),Val=in(VX)) /* can happen when question marks occur inside records, ... */ | |
1810 | -> enumerate_channel_input_value1_1(Type,VX,Ch,MaxRec,Span) | |
1811 | ; enumerate_channel_input_value1_1(Type,Val,Ch,MaxRec,Span) | |
1812 | ). | |
1813 | ||
1814 | enumerate_channel_input_value1_1(Type,Val,Ch,MaxRec,Span) :- | |
1815 | ( (nonvar(Val),Val=alsoPat(X,Y)) -> | |
1816 | enumerate_channel_input_value2(Type,X,Ch,MaxRec,Span), | |
1817 | %enumerate_channel_input_value2(Type,Y,Ch,MaxRec,Span), | |
1818 | unify_also_patterns(X,Y,_R) | |
1819 | ; (nonvar(Val),Val=appendPat(X,FunHead)) -> | |
1820 | agent_compiled(FunHead,_Value,_SRCSPAN), | |
1821 | enumerate_channel_input_value2(Type,X,Ch,MaxRec,Span) | |
1822 | ; enumerate_channel_input_value2(Type,Val,Ch,MaxRec,Span) | |
1823 | ). | |
1824 | ||
1825 | %enumerate_channel_input_value2(T,V,Ch,_MaxRec) :- print(enumerate_channel_input_value(T,V,Ch)),nl,fail. | |
1826 | :- use_module(probsrc(refinement_checker),[ignore_infinite_datatypes/0]). | |
1827 | :- assert_must_succeed((findall(Res, enumerate_channel_input_value2('Set'(setValue([int(1),int(2)])),Res,_Ch,_MaxRec,_Span),L), | |
1828 | L == [setValue([int(1),int(2)]),setValue([int(1)]),setValue([int(2)]),setValue([])])). | |
1829 | ||
1830 | enumerate_channel_input_value2(intType,X,Ch,_MaxRec,_Span) :- !, | |
1831 | enumerate_basic_type(X,integer,trigger_true(Ch)). % NOTE : this uses MAXINT preference value! | |
1832 | enumerate_channel_input_value2(boolType,X,_Ch,_MaxRec,_Span) :- !,(X=true ; X=false). | |
1833 | enumerate_channel_input_value2(setFromTo(Low,Up),Res,Ch,_MaxRec,Span) :- !, | |
1834 | set_enumeration_result(Res,int(X),Ch,setFromTo(Low,Up),Span), | |
1835 | enumerate_csp_int(X,Low,Up). | |
1836 | /*(preference(use_clpfd_solver,true),clpfd_interface: fd_var(Res) -> | |
1837 | clpfd_interface: csp_clpfd_labeling([ffc,enum],[Res]) | |
1838 | ; set_enumeration_result(Res,int(X),Ch,setFromTo(Low,Up),Span), | |
1839 | enumerate_csp_int(X,Low,Up) | |
1840 | ).*/ | |
1841 | enumerate_channel_input_value2(setFrom(Low),V,Ch,_MaxRec,Span) :- !, | |
1842 | add_symbol_span(Ch,Span,CSpan), | |
1843 | add_error(enumerate_channel_input_value,'Cannot enumerate infinite Type: ',(Ch,(setFrom(Low),V)),CSpan). | |
1844 | enumerate_channel_input_value2('Set'(X),Res,_Ch,_MaxRec,_Span) :- !, /* Probably DEAD CODE */ | |
1845 | enum_subset(X,Res). | |
1846 | enumerate_channel_input_value2('dotTupleType'(List),Res,Ch,MaxRec,Span) :- !, | |
1847 | set_enumeration_tuple_result(Res,RR,Ch,'dotTupleType'(List),Span), | |
1848 | l_enumerate_channel_input_value2(List,RR,Ch,dot_tuple,MaxRec,Span). | |
1849 | enumerate_channel_input_value2('typeTuple'(List),Res,Ch,MaxRec,Span) :- !, | |
1850 | set_enumeration_result(Res,na_tuple(RR),Ch,'typeTuple'(List),Span), | |
1851 | % print(enum_tuple('typeTuple'(List),Res,Ch)),nl, | |
1852 | l_enumerate_channel_input_value2(List,RR,Ch,type_tuple,MaxRec,Span). | |
1853 | enumerate_channel_input_value2(setValue(L),R,_Ch,_MaxRec,_Span) :- !,member(R,L). /* R should be list skeleton at least */ | |
1854 | enumerate_channel_input_value2(dataType(DT),C,Channel,MaxRec,Span) :- is_a_datatype(DT,_), !, | |
1855 | enumerate_datatype_el(DT,C,Channel,MaxRec,Span). | |
1856 | % TO DO: add all other types supported by is_member_set | |
1857 | enumerate_channel_input_value2('Seq'(setValue([])),V,_Ch,_MaxRec,_Span) :- !, V= list([]). | |
1858 | enumerate_channel_input_value2('Seq'(Type),V,Ch,_MaxRec,Span) :- !, | |
1859 | (ignore_infinite_datatypes -> V=sequence % needed for the Trace Debugger in Tcl/Tk | |
1860 | ; add_symbol_span(Ch,Span,CSpan), | |
1861 | add_error(enumerate_channel_input_value,'Cannot enumerate infinite Seq Type: ',(Ch,('Seq'(Type),V)),CSpan)). | |
1862 | enumerate_channel_input_value2(agent_call(_Src, Name,Patterns),Val,Ch,_MaxRec,Span) :- !, | |
1863 | unfold_function_call_once(Name,Patterns,Res,Span), | |
1864 | evaluate_argument(Res,Res1), | |
1865 | enumerate_channel_input_value(Res1,Val,Ch,Span). | |
1866 | enumerate_channel_input_value2(Type,V,Ch,_MaxRec,Span) :- | |
1867 | add_symbol_span(Ch,Span,CSpan), | |
1868 | add_error(enumerate_channel_input_value,'Illegal type for channel: ',(Ch,(Type,V)),CSpan). | |
1869 | ||
1870 | enumerate_datatype_el(DT,C,Channel,_MaxRec,Span) :- | |
1871 | if(csp_constant(C,DT),true, | |
1872 | (nonvar(C),C \= record(_,_), | |
1873 | add_error(enumerate_datatype_el,'Type error for channel input variable: ', Channel:(C,type(DT)),Span), | |
1874 | fail)). | |
1875 | enumerate_datatype_el(DT,C,Channel,MaxRec,Span) :- | |
1876 | ((MaxRec>0 ; nonvar(C)) | |
1877 | ->((nonvar(C) -> M1 = MaxRec ; M1 is MaxRec-1), | |
1878 | C=record(Cons,Fields), | |
1879 | csp_constructor(Cons,DT,ArgSubTypes), | |
1880 | % print(recurse_enum_rec(Cons,DT,ArgSubTypes,Fields)),nl, | |
1881 | l_enumerate_channel_input_value2(ArgSubTypes,Fields,Channel,dot_tuple,M1,Span)) | |
1882 | ; (ignore_infinite_datatypes -> | |
1883 | print('### WARNING: Maximum Recursion Depth reached for enumeration at '), | |
1884 | translate: print_span(Span) | |
1885 | ; print('### Maximum Recursion Depth reached for enumeration at '), | |
1886 | translate:print_span(Span), | |
1887 | fail) | |
1888 | ). | |
1889 | ||
1890 | % ensure that ResVar is a tuple and flatten the tuple | |
1891 | set_enumeration_tuple_result(ResVar,ResultTerm,Channel,ExpectedType,Span) :- | |
1892 | ((tuple(TL)=ResVar;dotTuple(TL)=ResVar) -> | |
1893 | %print(flattening(ResVar)),nl, | |
1894 | flatten_tuple_value(TL,ResultTerm) /* ok, no type error */ | |
1895 | ; add_symbol_span(Channel,Span,CSpan), | |
1896 | add_error(set_enumeration_tuple_result,'Type error for instantiated channel input variable: ',Channel:(ResVar,type(ExpectedType)),CSpan), | |
1897 | fail). | |
1898 | ||
1899 | %%%%%%%%%%%%%%%%%%%%% UNIT TESTS FOR flatten_tuple_value/2, flatten_inner_tuple_value/2 and flatten2/3 %%%%%%%%%%%%%%%%%%%%%%%%%% | |
1900 | :- assert_must_succeed((haskell_csp: flatten_tuple_value(X,R), R == X)). | |
1901 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([],R), R == [])). | |
1902 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([X,tuple([int(1),int(2)])],R), R == [X,int(1),int(2)])). | |
1903 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([tuple([]),tuple([int(1),int(2)]),X,Y,tuple([int(10)])],R), R == [int(1),int(2),X,Y,int(10)])). | |
1904 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([X,tuple([int(1),Y,int(2),Z])],R), R == [X,int(1),Y,int(2),Z])). | |
1905 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([X,tuple([int(1),Y,int(2),Z]),int(3)],R), R == [X,int(1),Y,int(2),Z,int(3)])). | |
1906 | :- assert_must_succeed((haskell_csp: flatten_tuple_value([],[]))). | |
1907 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
1908 | ||
1909 | flatten_tuple_value(X,R) :- var(X),!, R=X. % this can happen if we have a single in(X) representing ch?x | |
1910 | flatten_tuple_value([],[]). | |
1911 | flatten_tuple_value([H|T],R) :- flatten2(H,T,R). | |
1912 | ||
1913 | flatten_inner_tuple_value(X,R) :- var(X),!, print(variable_inner_tuple(X)),nl, R=[X]. | |
1914 | flatten_inner_tuple_value([],[]). | |
1915 | flatten_inner_tuple_value([H|T],R) :- flatten2(H,T,R). | |
1916 | ||
1917 | flatten2(VAR,T,Res) :- var(VAR),!, Res=[VAR|TR],flatten_inner_tuple_value(T,TR). | |
1918 | flatten2(tuple(LH),T,R) :- !, flatten_inner_tuple_value(LH,FLH), | |
1919 | append(FLH,TR,R), flatten_inner_tuple_value(T,TR). | |
1920 | flatten2(H,T,[H|TR]) :- flatten_inner_tuple_value(T,TR). | |
1921 | ||
1922 | set_enumeration_result(ResVar,ResultTerm,Channel,ExpectedType,Span) :- | |
1923 | (ResVar=ResultTerm -> true /* ok, no type error */ | |
1924 | ; | |
1925 | add_symbol_span(Channel,Span,CSpan), | |
1926 | add_error(set_enumeration_result,'Type error for instantiated channel input variable: ',Channel:(val(ResVar),type(ExpectedType)),CSpan), | |
1927 | fail). | |
1928 | ||
1929 | l_enumerate_channel_input_value2([],R,Ch,_SType,_MaxRec,Span) :- !, | |
1930 | (var(R) -> R=[] | |
1931 | ; R=[] -> true | |
1932 | ; add_error(l_enumerate_channel_input_value,'Too many arguments on channel: ',(Ch,R),Span),fail). | |
1933 | l_enumerate_channel_input_value2([HType|T],[HVal|TV],Ch,SType,MaxRec,Span) :- !, | |
1934 | ((TV==[],SType=dot_tuple) -> % enume the rest of the channel types to HVal (only for dotTuple types) | |
1935 | enume_ch_vals([HType|T],[in(HVal)],Ch,Span,io([],Ch)) % TO DO: full event | |
1936 | ; otherwise -> | |
1937 | enumerate_channel_input_value(HType,HVal,Ch,MaxRec,Span), %% <-- add Span | |
1938 | l_enumerate_channel_input_value2(T,TV,Ch,SType,MaxRec,Span) | |
1939 | ). | |
1940 | l_enumerate_channel_input_value2([HType|T],[],Ch,_SType,_MaxRec,Span) :- !, | |
1941 | add_error(l_enumerate_channel_input_value,'Not enough arguments on channel: ',(Ch,[HType|T]),Span),fail. | |
1942 | l_enumerate_channel_input_value2(X,Y,Ch,SType,MR,Span) :- | |
1943 | add_internal_error('Illegal arguments: ',l_enumerate_channel_input_value2(X,Y,Ch,SType,MR,Span)),fail. | |
1944 | ||
1945 | get_symbol_span(S,SPAN) :- atomic(S),symbol(S,_,SPAN,_),!. | |
1946 | get_symbol_span(S,SPAN) :- nonvar(S),functor(S,FS,_),symbol(FS,_,SPAN,_),!. | |
1947 | get_symbol_span(_S,no_loc_info_available). | |
1948 | ||
1949 | ||
1950 | add_symbol_error(Src,Msg,Term,Ch) :- | |
1951 | get_symbol_span(Ch,Span), | |
1952 | add_error(Src,Msg,Term,Span). | |
1953 | ||
1954 | add_symbol_span(Ch,Span,OutSpan) :- get_symbol_span(Ch,SSpan), | |
1955 | \+ (SSpan=no_loc_info_available),!, unify_spans(Span,SSpan,OutSpan). | |
1956 | add_symbol_span(_,S,S). | |
1957 | ||
1958 | % just like above, but can also be called with ordinary spans | |
1959 | add_error_with_span(Src,Msg,Term,Span) :- | |
1960 | (Span=symbol(S) -> get_symbol_span(S,Span2) ; Span2=Span), | |
1961 | add_error(Src,Msg,Term,Span2). | |
1962 | ||
1963 | add_internal_error_with_span(Src,Msg,Term,Span) :- | |
1964 | (Span=symbol(S) -> get_symbol_span(S,Span2) ; Span2 = Span), | |
1965 | add_internal_error(Src,Msg,Term,Span2). | |
1966 | ||
1967 | /* ------------------------------------- */ | |
1968 | /* BOOLEAN EXPRESSIONS */ | |
1969 | /* ------------------------------------- */ | |
1970 | ||
1971 | %%%%%%%% UNIT TESTS FOR TESTING check_boolean_expressions/1,cond_check_boolean_expression/2,ifte_check_boolean_expression/3 %%%%%%% | |
1972 | ||
1973 | :- assert_must_succeed((haskell_csp: check_boolean_expression(true))). | |
1974 | :- assert_must_fail((haskell_csp: check_boolean_expression(X), X = false)). | |
1975 | :- assert_must_succeed((haskell_csp: check_boolean_expression(bool_not(false)))). | |
1976 | :- assert_must_fail((haskell_csp: check_boolean_expression(X), X = false)). | |
1977 | :- assert_must_succeed((haskell_csp: check_boolean_expression(bool_or(true,_X)))). | |
1978 | :- assert_must_succeed((haskell_csp: check_boolean_expression(bool_not('<='(int(1),int(0)))))). | |
1979 | :- assert_must_fail((haskell_csp: check_boolean_expression(bool_not('<='(int(1),int(10)))))). | |
1980 | :- assert_must_succeed((haskell_csp: check_boolean_expression(bool_and('<='(int(1),int(10)), true)))). | |
1981 | :- assert_must_fail((haskell_csp: check_boolean_expression(bool_and(false,'<='(int(1),int(10)))))). | |
1982 | :- assert_must_succeed((haskell_csp: check_boolean_expression(bool_or('<='(int(1),int(0)), true)))). | |
1983 | :- assert_must_fail((haskell_csp: check_boolean_expression(bool_or(false,'<='(int(1),int(0)))))). | |
1984 | :- assert_must_succeed((haskell_csp: check_boolean_expression('<='(int(10),int(X))), X = 30)). | |
1985 | :- assert_must_succeed((haskell_csp: check_boolean_expression('>='(int(10),int(X))), X = 3)). | |
1986 | :- assert_must_succeed((haskell_csp: check_boolean_expression('<='(int(10),int(X))), X = 10)). | |
1987 | :- assert_must_succeed((haskell_csp: check_boolean_expression('>='(int(10),int(X))), X = 10)). | |
1988 | :- assert_must_succeed((haskell_csp: check_boolean_expression('<'(int(10),int(X))), X = 30)). | |
1989 | :- assert_must_succeed((haskell_csp: check_boolean_expression('>'(int(10),int(X))), X = 3)). | |
1990 | :- assert_must_fail((haskell_csp: check_boolean_expression('<'(int(10),int(X))), X = 10)). | |
1991 | :- assert_must_fail((haskell_csp: check_boolean_expression('>'(int(10),int(X))), X = 10)). | |
1992 | :- assert_must_succeed((haskell_csp: check_boolean_expression(ifte('<='(int(3),int(20)),'>='(int(2),int(1)),'<='(int(3),int(1)),span,span,span)))). | |
1993 | :- assert_must_succeed((haskell_csp: check_boolean_expression(ifte('<='(int(3),int(2)),'>='(int(2),int(1)),'<='(int(3),int(10)),span,span,span)))). | |
1994 | :- assert_must_succeed((haskell_csp: check_boolean_expression(ifte('<='(int(3),int(2)),'>='(int(2),int(1)),'<='(int(3),int(10)),span,span,span)))). | |
1995 | :- assert_must_succeed((haskell_csp: check_boolean_expression(ifte(X,'>='(int(2),int(1)),'<='(int(3),int(1)),span,span,span)), | |
1996 | X = head(listExp(rangeEnum(['<='(int(2),int(3)),'>'(int(2),int(3))]))))). | |
1997 | :- assert_must_fail((haskell_csp: check_boolean_expression(ifte(X,'>='(int(2),int(1)),'<='(int(3),int(1)),span,span,span)), | |
1998 | X = head(listExp(rangeEnum(['<='(int(2),int(1)),'>'(int(2),int(3))]))))). | |
1999 | :- assert_must_succeed((haskell_csp: check_boolean_expression(head(listExp(rangeEnum(['<'(int(2),int(3)),'>'(int(2),int(3))])))))). | |
2000 | :- assert_must_succeed((haskell_csp: check_boolean_expression(head(listExp(rangeEnum([true,false])))))). | |
2001 | :- assert_must_fail((haskell_csp: check_boolean_expression(head(listExp(rangeEnum([false,false])))))). | |
2002 | :- assert_must_fail((haskell_csp: check_boolean_expression(head(listExp(rangeEnum([false,true])))))). | |
2003 | :- assert_must_fail((haskell_csp: check_boolean_expression((head(listExp(rangeEnum([null(listExp(rangeEnum([false,true])))]))))))). | |
2004 | :- assert_must_fail((haskell_csp: check_boolean_expression((head(listExp(rangeEnum([empty(setValue([int(1),int(2)]))]))))))). | |
2005 | :- assert_must_succeed((haskell_csp: check_boolean_expression(empty(setExp(rangeEnum([])))))). | |
2006 | :- assert_must_succeed((haskell_csp: check_boolean_expression(head(listExp(rangeEnum([bool_not(false)])))))). | |
2007 | :- assert_must_succeed((haskell_csp: check_boolean_expression(head(listExp(rangeEnum([bool_or(true,false)])))))). | |
2008 | :- assert_must_succeed((haskell_csp: check_boolean_expression(head(listExp(rangeEnum(['<='(int(2),int(3)),'>'(int(2),int(3))])))))). | |
2009 | :- assert_must_fail((haskell_csp: check_boolean_expression(head(listExp(rangeEnum(['<='(int(2),int(1)),'>'(int(2),int(3))])))))). | |
2010 | :- assert_must_succeed((haskell_csp: check_boolean_expression(null(listExp(rangeEnum([])))))). | |
2011 | :- assert_must_fail((haskell_csp: check_boolean_expression(null(listExp(rangeEnum([int(1),int(2),int(3)])))))). | |
2012 | :- assert_must_succeed((haskell_csp: check_boolean_expression(empty(setExp(rangeEnum([])))))). | |
2013 | :- assert_must_fail((haskell_csp: check_boolean_expression(empty(setExp(rangeEnum([int(1),int(2),int(3)])))))). | |
2014 | :- assert_must_succeed((haskell_csp: is_boolean_expression(true), haskell_csp: is_boolean_expression(false))). | |
2015 | ||
2016 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
2017 | ||
2018 | :- block check_boolean_expression(-). | |
2019 | ||
2020 | %check_boolean_expression(E) :- %print(check_boolean_expression(E)),nl, | |
2021 | % var(E),add_error(check_boolean_expression,'Variable boolean expression:',E),fail. | |
2022 | check_boolean_expression(true) :- !. | |
2023 | check_boolean_expression(false) :- !, fail. | |
2024 | check_boolean_expression(bool_not(BExpr1)) :- !, | |
2025 | evaluate_boolean_expression(BExpr1,false). /* provide custom check_not_... predicate ?? */ | |
2026 | check_boolean_expression(bool_and(BExpr1,BExpr2)) :- !, | |
2027 | check_boolean_expression(BExpr1), | |
2028 | check_boolean_expression(BExpr2). | |
2029 | check_boolean_expression(bool_or(BExpr1,BExpr2)) :- !, | |
2030 | evaluate_boolean_expression(BExpr1,R1), | |
2031 | cond_check_boolean_expression(R1,BExpr2). | |
2032 | check_boolean_expression(ifte(Test,Then,Else,_,_,_)) :- !, | |
2033 | evaluate_boolean_expression(Test,TestRes), %print(check_bool_ifte(Test,TestRes)),nl, | |
2034 | ifte_check_boolean_expression(TestRes,Then,Else). | |
2035 | check_boolean_expression(head(X)) :- !, force_evaluate_argument(X,EX),head_list(EX,HResult), | |
2036 | check_boolean_expression(HResult). | |
2037 | check_boolean_expression(null(Arg1)) :- !, force_evaluate_argument(Arg1,EX), is_null_list(EX,true). | |
2038 | check_boolean_expression(empty(Arg1)) :- !, force_evaluate_argument(Arg1,EX), is_empty_set(EX,true). | |
2039 | check_boolean_expression(agent_call(Span,F,Par)) :- !, /* in this context we need the result of the function call */ | |
2040 | unfold_function_call_once(F,Par,Body,Span), | |
2041 | %when(nonvar(Body), | |
2042 | check_boolean_expression(Body). | |
2043 | check_boolean_expression('member'(Arg1,Arg2)) :- !, % after bool_binary_op: there is a special rule for member there | |
2044 | force_evaluate_argument(Arg1,EX), | |
2045 | force_evaluate_argument_for_member_check(Arg2,EY), %print(lazy_member(EX,EY)),nl, | |
2046 | % causes 10 % slowdown on basin_olderog_bank, but code is probably required similar to evaluate_boolean_expression below | |
2047 | % when(ground(EX), (ground(EY) -> is_member_set(EX,EY) | |
2048 | % ; /* exploring lazy expression */ force_evaluate_argument(EY,REY),is_member_set(EX,REY))). | |
2049 | when((ground(EX),ground(EY)), is_member_set(EX,EY)). | |
2050 | check_boolean_expression(BExpr) :- %covering all boolean expression with relational operators instead of '==' and '!='% | |
2051 | relational_binary_op(BExpr,Arg1,Arg2,EX,EY,Call),!, | |
2052 | evaluate_int_argument(Arg1,EX), | |
2053 | evaluate_int_argument(Arg2,EY), | |
2054 | Call. | |
2055 | check_boolean_expression(BExpr) :- | |
2056 | bool_binary_op(BExpr,Arg1,Arg2,EX,EY,Call), !, | |
2057 | %print(bool_binary_op(Arg1,Arg2,Call)),nl, % | |
2058 | force_evaluate_argument(Arg1,EX), | |
2059 | force_evaluate_argument(Arg2,EY), | |
2060 | when((ground(EX),ground(EY)), Call). | |
2061 | check_boolean_expression(X) :- | |
2062 | add_error(haskell_csp,'Not a boolean expression: ',X), | |
2063 | fail. | |
2064 | ||
2065 | ||
2066 | :- block cond_check_boolean_expression(-,?). | |
2067 | cond_check_boolean_expression(true,_). | |
2068 | cond_check_boolean_expression(false,BExpr2) :- check_boolean_expression(BExpr2). | |
2069 | ||
2070 | :- block ifte_check_boolean_expression(-,?,?). | |
2071 | ifte_check_boolean_expression(true,Then,_) :- !, check_boolean_expression(Then). | |
2072 | ifte_check_boolean_expression(false,_,Else) :- !, check_boolean_expression(Else). | |
2073 | % evaluate_boolean_expression/3 will raise an error if the boolean expression in the ifte-condition cannot be evaluated to true or false => Internal Error | |
2074 | ifte_check_boolean_expression(Other,Then,Else) :- add_internal_error(/*ifte_check_boolean_expression,*/ | |
2075 | 'Internal Error: Not a boolean inside if-then-else test: ', | |
2076 | ifte_check_boolean_expression(Other,Then,Else)),fail. | |
2077 | ||
2078 | :- block evaluate_boolean_expression(-,?). | |
2079 | %evaluate_boolean_expression(E,_) :- %print(evaluate_boolean_expression(E)),nl, | |
2080 | % var(E),add_error(evaluate_boolean_expression,'Variable boolean expression:',E),fail. | |
2081 | evaluate_boolean_expression(true,R) :- !, R=true. | |
2082 | evaluate_boolean_expression(false,R) :- !, R=false. | |
2083 | evaluate_boolean_expression(bool_not(BExpr1),Res) :- !, | |
2084 | evaluate_boolean_expression(BExpr1,R1), | |
2085 | negate(R1,Res). | |
2086 | evaluate_boolean_expression(bool_and(BExpr1,BExpr2),Res) :- !, | |
2087 | evaluate_boolean_expression(BExpr1,R1), | |
2088 | cond_evalf_boolean_expression(R1,BExpr2,Res). | |
2089 | evaluate_boolean_expression(bool_or(BExpr1,BExpr2),Res) :- !, | |
2090 | evaluate_boolean_expression(BExpr1,R1), | |
2091 | cond_evalt_boolean_expression(R1,BExpr2,Res). | |
2092 | % when(ground(R1), | |
2093 | % (R1=true -> Res = true | |
2094 | % ; evaluate_boolean_expression(BExpr2,Res))). | |
2095 | evaluate_boolean_expression('<'(Arg1,Arg2),Res) :- !, | |
2096 | evaluate_int_argument(Arg1,EX),evaluate_int_argument(Arg2,EY),safe_less_than(EX,EY,Res). | |
2097 | evaluate_boolean_expression('>'(Arg1,Arg2),Res) :- !, | |
2098 | evaluate_int_argument(Arg1,EX),evaluate_int_argument(Arg2,EY),safe_less_than(EY,EX,Res). | |
2099 | evaluate_boolean_expression('<='(Arg1,Arg2),Res) :- !, | |
2100 | evaluate_int_argument(Arg1,EX),evaluate_int_argument(Arg2,EY),safe_less_than_equal(EX,EY,Res). | |
2101 | evaluate_boolean_expression('>='(Arg1,Arg2),Res) :- !, | |
2102 | evaluate_int_argument(Arg1,EX),evaluate_int_argument(Arg2,EY),safe_less_than_equal(EY,EX,Res). | |
2103 | evaluate_boolean_expression(ifte(Test,Then,Else,_,_,_),R) :- !, | |
2104 | evaluate_boolean_expression(Test,TestRes), | |
2105 | ifte_eval_boolean_expression(TestRes,Then,Else,R). | |
2106 | evaluate_boolean_expression(head(X),R) :- !, force_evaluate_argument(X,EX),head_list(EX,HResult), | |
2107 | evaluate_boolean_expression(HResult,R). | |
2108 | evaluate_boolean_expression(agent_call(Span,F,Par),R) :- !, /* in this context we need the result of the function call */ | |
2109 | unfold_function_call_once(F,Par,Body,Span), | |
2110 | %when(nonvar(Body), | |
2111 | evaluate_boolean_expression(Body,R). | |
2112 | evaluate_boolean_expression(prolog_constraint(C),Res) :- !, %% print(prolog_constraint(C)),nl, | |
2113 | (call(C) -> Res = true ; Res = false). | |
2114 | evaluate_boolean_expression(null(Arg1),Res) :- !, force_evaluate_argument(Arg1,EX), is_null_list(EX,Res). | |
2115 | evaluate_boolean_expression(empty(Arg1),Res) :- !, force_evaluate_argument(Arg1,EX), is_empty_set(EX,Res). | |
2116 | evaluate_boolean_expression(BExpr,Res) :- | |
2117 | bool_binary_op(BExpr,Arg1,Arg2,EX,EY,Call), !, % print(binop(BExpr,Arg1,Arg2)),nl, | |
2118 | force_evaluate_argument(Arg1,EX), | |
2119 | force_evaluate_argument(Arg2,EY), %print(ebe(Call)),nl, | |
2120 | when((ground(EX),ground(EY)), | |
2121 | (Call -> Res = true ; Res = false)). | |
2122 | evaluate_boolean_expression('member'(Arg1,Arg2),Res) :- !, % after bool_binary_op: there is a special rule for member there | |
2123 | force_evaluate_argument(Arg1,EX), | |
2124 | force_evaluate_argument_for_member_check(Arg2,EY), %print(lazy_member(EX,EY)),nl, | |
2125 | when(ground(EX), | |
2126 | (ground(EY) -> (is_member_set(EX,EY) -> Res = true ; Res = false) | |
2127 | ; /* exploring lazy expression */ force_evaluate_argument(EY,REY),(is_member_set(EX,REY) -> Res = true ; Res = false))). | |
2128 | evaluate_boolean_expression(builtin_call(X),Res) :- !, evaluate_boolean_expression(X,Res). | |
2129 | evaluate_boolean_expression(X,_R) :- | |
2130 | add_error(haskell_csp,'Not a boolean expression: ',X), | |
2131 | fail. | |
2132 | ||
2133 | ||
2134 | :- block negate(-,?). | |
2135 | negate(true,false). | |
2136 | negate(false,true). | |
2137 | ||
2138 | :- block cond_evalt_boolean_expression(-,?,?). | |
2139 | cond_evalt_boolean_expression(true,_,true). | |
2140 | cond_evalt_boolean_expression(false,BExpr2,Res) :- evaluate_boolean_expression(BExpr2,Res). | |
2141 | ||
2142 | :- block cond_evalf_boolean_expression(-,?,?). | |
2143 | cond_evalf_boolean_expression(false,_,false). | |
2144 | cond_evalf_boolean_expression(true,BExpr2,Res) :- evaluate_boolean_expression(BExpr2,Res). | |
2145 | ||
2146 | :- block ifte_eval_boolean_expression(-,?,?,?). | |
2147 | ifte_eval_boolean_expression(true,Then,_,Res) :- !, evaluate_boolean_expression(Then,Res). | |
2148 | ifte_eval_boolean_expression(false,_,Else,Res) :- !, evaluate_boolean_expression(Else,Res). | |
2149 | ifte_eval_boolean_expression(Other,Then,Else,Res) :- /* evaluate_boolean_expression/2 will catch the error if there | |
2150 | is no boolean expression test, thus internal_error must be generated for this clause. */ | |
2151 | add_internal_error('Not a boolean inside if-then-else boolean expression test: ', | |
2152 | ifte_eval_boolean_expression(Other,Then,Else,Res)),fail. | |
2153 | ||
2154 | bool_binary_int_op('<'(X,Y),X,Y,EX,EY,'<'(EX,EY)). | |
2155 | bool_binary_int_op('>'(X,Y),X,Y,EX,EY,'>'(EX,EY)). | |
2156 | bool_binary_int_op('>='(X,Y),X,Y,EX,EY,'>='(EX,EY)). | |
2157 | bool_binary_int_op('<='(X,Y),X,Y,EX,EY,'=<'(EX,EY)). | |
2158 | ||
2159 | relational_binary_op('<'(X,Y),X,Y,EX,EY,safe_less_than(EX,EY)). | |
2160 | relational_binary_op('>'(X,Y),X,Y,EX,EY,safe_less_than(EY,EX)). | |
2161 | relational_binary_op('<='(X,Y),X,Y,EX,EY,safe_less_than_equal(EX,EY)). | |
2162 | relational_binary_op('>='(X,Y),X,Y,EX,EY,safe_less_than_equal(EY,EX)). | |
2163 | ||
2164 | bool_binary_op('elem'(X,Y),X,Y,EX,EY,is_elem_list(EX,EY)). | |
2165 | %bool_binary_op('member'(X,Y),X,Y,EX,EY,is_member_set(EX,EY)) :- (X=setValue(_) -> false;true). | |
2166 | bool_binary_op('member'(X,'Set'(Y)),X,Y,EX,EY,is_subset_of(EX,EY)) :- | |
2167 | (X\=setValue(_) -> false; \+ground(X) -> false; otherwise -> true). | |
2168 | bool_binary_op('=='(X,Y),X,Y,EX,EY,equal_element(EX,EY)). | |
2169 | bool_binary_op('!='(X,Y),X,Y,EX,EY,not_equal_element(EX,EY)). | |
2170 | ||
2171 | bool_binary_op_symbolic('member'(X,Y),X,Y,EX,EY,is_member_set(EX,EY)). % dealt with separately | |
2172 | ||
2173 | unary_op(null(X),X,EX,is_null_list(EX)). | |
2174 | unary_op(empty(X),X,EX,is_empty_set(EX,true)). | |
2175 | ||
2176 | is_boolean_expression(true). | |
2177 | is_boolean_expression(false). | |
2178 | is_boolean_expression(bool_not(_)). | |
2179 | is_boolean_expression(bool_and(_,_)). | |
2180 | is_boolean_expression(bool_or(_,_)). | |
2181 | is_boolean_expression(X) :- | |
2182 | (unary_op(X,_,_,_) ; bool_binary_op(X,_,_,_,_,_) ; bool_binary_op_symbolic(X,_,_,_,_,_) ; bool_binary_int_op(X,_,_,_,_,_)). | |
2183 | ||
2184 | ||
2185 | /* ------------------------------------- */ | |
2186 | /* SEQUENCES */ | |
2187 | /* ------------------------------------- */ | |
2188 | ||
2189 | :- use_module(probcspsrc(csp_sequences)). | |
2190 | ||
2191 | /* ------------------------------------- */ | |
2192 | /* VALUE EXPRESSIONS */ | |
2193 | /* ------------------------------------- */ | |
2194 | ||
2195 | :- type channelio +--> (atomic ; dotTuple(list(atomic))). | |
2196 | ||
2197 | :- type channel_set +--> (setValue(list(channelio)) ; closure(list(channelio))). | |
2198 | ||
2199 | :- type cspm_expr +--> (type(cspm_arith_expr) ; type(channel_set) ; atomic ; agent_call(ground,nonvar,list(any)) ). | |
2200 | ||
2201 | :- type cspm_arith_expr +--> (int(integer) ; | |
2202 | '+'(cspm_arith_expr,cspm_arith_expr) ; | |
2203 | '-'(cspm_arith_expr,cspm_arith_expr) ; | |
2204 | '*'(cspm_arith_expr,cspm_arith_expr) ; | |
2205 | '/'(cspm_arith_expr,cspm_arith_expr) ; | |
2206 | '%'(cspm_arith_expr,cspm_arith_expr) ). | |
2207 | ||
2208 | % forcing arguments in the context of a member check; will be used as second arg to is_member_set | |
2209 | % This means that certain things do not need to be computed (Union for example) | |
2210 | :- block force_evaluate_argument_for_member_check(-,?). | |
2211 | force_evaluate_argument_for_member_check(agent_call(Span,F,Par),R) :- !, | |
2212 | %print(unfold(F,Par,Body)),nl, | |
2213 | unfold_function_call_once(F,Par,Body,Span), | |
2214 | force_evaluate_argument_for_member_check(Body,R). | |
2215 | % keep the following symbolic: | |
2216 | force_evaluate_argument_for_member_check(setExp(rangeEnum(T),G),R) :- nonvar(T),T=[H|TT],TT==[], var(H), !, | |
2217 | % if the tuples T have more than one element, we currently cannot check membership symbolically | |
2218 | R=setExp(rangeEnum(T),G). % TO DO expand for rangeClosed,... | |
2219 | force_evaluate_argument_for_member_check('Union'(L),R) :- !, | |
2220 | force_evaluate_argument_for_member_check_into_list(L,LL), %print(evalUnion(L,LL)),nl, | |
2221 | R='Union'(LL). | |
2222 | force_evaluate_argument_for_member_check('Inter'(L),R) :- !, | |
2223 | force_evaluate_argument_for_member_check_into_list(L,LL), R='Inter'(LL). | |
2224 | force_evaluate_argument_for_member_check('Seq'(L),R) :- !, R='Seq'(L). | |
2225 | ||
2226 | force_evaluate_argument_for_member_check(X,EX) :- force_evaluate_argument(X,EX). | |
2227 | ||
2228 | % force evaluating a set into a list of elements; do not worry about checking duplicates in list | |
2229 | :- block force_evaluate_argument_for_member_check_into_list(-,?). | |
2230 | %force_evaluate_argument_for_member_check_into_list(A,R) :- print(force_evaluate_argument_for_member_check_into_list(A,R)),nl,fail. | |
2231 | force_evaluate_argument_for_member_check_into_list(agent_call(Span,F,Par),R) :- !, | |
2232 | /* in this context we need the result of the function call */ | |
2233 | unfold_function_call_once(F,Par,Body,Span), | |
2234 | force_evaluate_argument_for_member_check_into_list(Body,R). | |
2235 | force_evaluate_argument_for_member_check_into_list(setExp(rangeEnum(L)),R) :- !, | |
2236 | force_evaluate_list_for_member_check(L,LL),R=setExp(rangeEnum(LL)). | |
2237 | force_evaluate_argument_for_member_check_into_list(X,EX) :- force_evaluate_argument(X,EX). | |
2238 | ||
2239 | :- block force_evaluate_list_for_member_check(-,?). | |
2240 | force_evaluate_list_for_member_check([],R) :- !,R=[]. | |
2241 | force_evaluate_list_for_member_check([H|T],R) :- !, R=[EH|ET], | |
2242 | force_evaluate_argument_for_member_check(H,EH), | |
2243 | force_evaluate_list_for_member_check(T,ET). | |
2244 | force_evaluate_list_for_member_check(X,R) :- | |
2245 | add_internal_error('Iternal Error: Could not evaluate list: ',force_evaluate_list_for_member_check(X,R)),R=X. | |
2246 | ||
2247 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% UNIT TESTS FOR force_evaluate_argument/2, evaluate_argument/2 and evaluate_expression/2 %%%%%%%%%%%%%%%%%%%%%%% | |
2248 | :- assert_must_succeed((haskell_csp: force_evaluate_argument(listFromTo(1,3),R), R == list([int(1),int(2),int(3)]))). | |
2249 | :- assert_must_succeed((haskell_csp: evaluate_argument(listFromTo(1,3),R), R == list([int(1),int(2),int(3)]))). | |
2250 | :- assert_must_succeed((haskell_csp: evaluate_argument(listFrom(1),R), R == listFrom(1))). | |
2251 | :- assert_must_succeed((haskell_csp: evaluate_argument(setFromTo(1,3),R), R == setFromTo(1,3))). | |
2252 | :- assert_must_succeed((haskell_csp: evaluate_argument(list([int(1),int(2)]),R), R == list([int(1),int(2)]))). | |
2253 | :- assert_must_succeed((haskell_csp: force_evaluate_argument(listPat([int(1),int(2)]),R), R == list([int(1),int(2)]))). | |
2254 | :- assert_must_succeed((haskell_csp: evaluate_argument(ifte('<='(int(3),int(20)),'>='(int(2),int(1)),'<='(int(3),int(1)),span,span,span),R) ,R == true)). | |
2255 | :- assert_must_succeed(( | |
2256 | haskell_csp: evaluate_argument(ifte('<='(int(3),int(2)),'>='(int(2),int(1)),'<='(int(3),int(1)),span,span,span),R), R ==false)). | |
2257 | :- assert_must_succeed((haskell_csp: evaluate_argument(ifte('<='(int(3),int(2)),int(1),int(2),span,span,span),R), R == int(2))). | |
2258 | :- assert_must_succeed((haskell_csp: evaluate_argument(dataType('FRUIT'),R), R == dataType('FRUIT'))). | |
2259 | :- assert_must_succeed((haskell_csp: evaluate_argument(concat(listExp(rangeEnum([listFromTo(1,3),listExp(rangeEnum([int(4)]))]))),R), | |
2260 | R == list([int(1),int(2),int(3),int(4)]))). | |
2261 | :- assert_must_succeed((haskell_csp: evaluate_argument(listPat([int(1),int(2)]),R), R == list([int(1),int(2)]))). | |
2262 | :- assert_must_succeed((haskell_csp: evaluate_argument(tuplePat([int(1),int(2)]),R), R == na_tuple([int(1),int(2)]))). | |
2263 | :- assert_must_succeed((haskell_csp: evaluate_expression(setExp(rangeEnum([int(1),int(2)])),R), R == setValue([int(1),int(2)]))). | |
2264 | :- assert_must_succeed((haskell_csp: evaluate_expression(setFromTo(1,3),R), R == setValue([int(1),int(2),int(3)]))). | |
2265 | :- assert_must_succeed((haskell_csp: evaluate_expression(stop(src),R), R == 'Typed expression is a process construct.')). | |
2266 | :- assert_must_succeed((haskell_csp: evaluate_expression(left,R), R == 'Typed expression is a channel name.')). | |
2267 | :- assert_must_succeed((haskell_csp: evaluate_expression('Msg1',R), R == setValue(['A','B']))). | |
2268 | :- assert_must_succeed((haskell_csp: evaluate_expression('Msg1',R), R == setValue(['A','B']))). | |
2269 | :- assert_must_succeed((haskell_csp: evaluate_expression(builtin_call(set(listExp(rangeEnum([int(1),int(1)])))),R), R == setValue([int(1)]))). | |
2270 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
2271 | ||
2272 | evaluate_expression(X,R) :- var(X),!, | |
2273 | add_internal_error('Internal Error: Variable expression to evaluate: ',evaluate_expression(X,R)), | |
2274 | fail. | |
2275 | evaluate_expression('Events',R) :- !, | |
2276 | findall(Channel,is_a_channel_name(Channel),CL), | |
2277 | evaluate_list(CL,CLL), closure_expand(CLL,R). | |
2278 | evaluate_expression(closure(X),R) :- !, | |
2279 | evaluate_list(X,XL), closure_expand(XL,R). | |
2280 | evaluate_expression(builtin_call(X),R) :- !, evaluate_expression(X,R). | |
2281 | evaluate_expression(setExp(X),R) :- !, evaluate_set_expression(X,EX),expand_symbolic_set(EX,R,evaluate_expression). | |
2282 | evaluate_expression(setFromTo(Low,Up),R) :- !, expand_symbolic_set(setFromTo(Low,Up),R,evaluate_expression). | |
2283 | evaluate_expression(val_of(X,Src),R) :- !, evaluate_argument2(val_of(X,Src),R). | |
2284 | evaluate_expression(DT,R) :- is_a_datatype(DT,_),!, | |
2285 | expand_symbolic_set(dataType(DT),R,eval). | |
2286 | evaluate_expression(Proc,R) :- definite_cspm_process_expression(Proc),!, R='Typed expression is a process construct.'. | |
2287 | evaluate_expression(Ch,R) :- is_a_channel_name(Ch),!, R='Typed expression is a channel name.'. | |
2288 | evaluate_expression(E,R) :- force_evaluate_argument(E,R). | |
2289 | ||
2290 | :- block force_evaluate_argument(-,?). | |
2291 | force_evaluate_argument(Num,R) :- number(Num),!,R=int(Num). | |
2292 | force_evaluate_argument(agent_call(Span,F,Par),R) :- !, /* in this context we need the result of the function call */ | |
2293 | unfold_function_call_once(F,Par,Body,Span), | |
2294 | force_evaluate_argument(Body,R). | |
2295 | force_evaluate_argument(setExp(RangeExpr,Generators),R) :- !, | |
2296 | expand_set_comprehension(RangeExpr,Generators,R). | |
2297 | %force_evaluate_argument(comprehensionGenerator(Var,Set),R) :- !, | |
2298 | % R = comprehensionGenerator(Var,ESet), | |
2299 | % force_evaluate_argument(Set,ESet). | |
2300 | force_evaluate_argument(ifte(Test,Then,Else,_S1,_S2,_S3),R) :- !, | |
2301 | evaluate_boolean_expression(Test,TestRes), % print(force_ifte(Test,TestRes)),nl, | |
2302 | ifte_force_evaluate_argument(TestRes,Then,Else,R). | |
2303 | force_evaluate_argument(list(X),R) :- !, %print(eval_list(X)),nl, | |
2304 | force_evaluate_list(X,EX), % use force_evaluate_list_skel ??; perf. problem in misusing_lists | |
2305 | R=list(EX). | |
2306 | force_evaluate_argument(listPat(X),R) :- !, %print(eval_list(X)),nl, | |
2307 | force_evaluate_list(X,EX), % use force_evaluate_list_skel ??; perf. problem in misusing_lists | |
2308 | R=list(EX). | |
2309 | force_evaluate_argument(listFromTo(X,Y),Res) :- !, expand_sequence(listFromTo(X,Y),Res). | |
2310 | force_evaluate_argument(listExp(S),ERes) :- !, evaluate_list_expression(S,Res), expand_sequence(Res,ERes). | |
2311 | %force_evaluate_argument(setValue(X),R) :- !, force_evaluate_set(X,R), print(fes(X,R)),nl. | |
2312 | % Maybe we should ensure that setValues are always force evaluated: we only need to | |
2313 | % take care when using set operations for replicated operators | |
2314 | force_evaluate_argument(Destr,Result) :- destructor(Destr),!, % we may need to further evaluate result | |
2315 | evaluate_argument2(Destr,EX), % do ordinary evaluation | |
2316 | force_evaluate_argument(EX,Result). | |
2317 | force_evaluate_argument(E,R) :- evaluate_argument2(E,R). /* could there be lazy constructs lurking deep inside E ??? */ | |
2318 | ||
2319 | destructor(head(_)). | |
2320 | destructor(na_tuple_projection(_,_,_)). | |
2321 | destructor(tuple_projection(_,_,_)). | |
2322 | %destructor(record(_,_)). | |
2323 | % records ? | |
2324 | ||
2325 | ||
2326 | :- block ifte_force_evaluate_argument(-,?,?,?). | |
2327 | ifte_force_evaluate_argument(true,Then,_,Res) :- !, force_evaluate_argument(Then,Res). | |
2328 | ifte_force_evaluate_argument(false,_,Else,Res) :- !, force_evaluate_argument(Else,Res). | |
2329 | /* See comment for the error clause of the ifte_evaluate_argument/4 predicate. Same argument as below | |
2330 | for assuming the error clause as caused by internal call only. */ | |
2331 | ifte_force_evaluate_argument(Other,Then,Else,Res) :- | |
2332 | add_internal_error('Internal Error: Not a boolean inside if-then-else test: ', | |
2333 | ifte_force_evaluate_argument(Other,Then,Else,Res) ),fail. | |
2334 | ||
2335 | :- block ifte_evaluate_argument(-,?,?,?). | |
2336 | ifte_evaluate_argument(true,Then,_,Res) :- !, evaluate_argument(Then,Res). | |
2337 | ifte_evaluate_argument(false,_,Else,Res) :- !, evaluate_argument(Else,Res). | |
2338 | /* evaluate_boolean_expression/2 predicate is called before ifte_evaluate_argument/4. | |
2339 | evaluate_boolean_expression/2 provides as result either true or false, that's why only internal call can | |
2340 | raise error for this predicate. */ | |
2341 | ifte_evaluate_argument(Other,Then,Else,Res) :- | |
2342 | add_internal_error('Internal Error: Not a boolean inside if-then-else test: ', | |
2343 | ifte_evaluate_argument(Other,Then,Else,Res)),fail. | |
2344 | ||
2345 | %evaluate_argument(E,R) :- print(evaluate_argument(E,R)),nl, | |
2346 | %(nonvar(R) -> true ; when(nonvar(R),(print(inst_eval(E,R)),nl,trace))), evaluate_argument1(E,R). | |
2347 | :- block evaluate_argument(-,?). | |
2348 | evaluate_argument(Expr,Res) :- evaluate_argument2(Expr,Res). | |
2349 | ||
2350 | evaluate_argument2(ifte(Test,Then,Else,_S1,_S2,_S3),R) :- !, | |
2351 | evaluate_boolean_expression(Test,TestRes), %print(ifte(Test,TestRes)),nl, | |
2352 | ifte_evaluate_argument(TestRes,Then,Else,R). | |
2353 | % when(ground(TestRes),(TestRes=true -> evaluate_argument(Then,R) ; evaluate_argument(Else,R))). | |
2354 | evaluate_argument2(int(X),R) :- !,R=int(X). | |
2355 | % case should be added because of the clpfd-library | |
2356 | evaluate_argument2(Num,R) :- number(Num),!,R=int(Num). | |
2357 | evaluate_argument2(true,R) :- !,R=true. | |
2358 | evaluate_argument2(false,R) :- !,R=false. | |
2359 | evaluate_argument2(negate(X),Result) :- !, Result = int(Res), | |
2360 | evaluate_int_argument(X,EX), | |
2361 | safe_is(Res,-(EX)). | |
2362 | evaluate_argument2('+'(X,Y),Result) :- !, Result = int(Res), | |
2363 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2364 | safe_is(Res,EX+EY). | |
2365 | evaluate_argument2('-'(X,Y),Result) :- !, Result = int(Res), | |
2366 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2367 | safe_is(Res,EX-EY). | |
2368 | evaluate_argument2('*'(X,Y),Result) :- !, Result = int(Res), | |
2369 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2370 | safe_is(Res,EX * EY). | |
2371 | evaluate_argument2('/'(X,Y),Result) :- !, Result = int(Res), | |
2372 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2373 | safe_is(Res,EX // EY). | |
2374 | evaluate_argument2('%'(X,Y),Result) :- !, Result = int(Res), | |
2375 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2376 | safe_is(Res,EX mod EY). | |
2377 | evaluate_argument2(length(X),Result) :- !, force_evaluate_argument(X,EX),length_list(EX,Result). | |
2378 | evaluate_argument2('#'(X),Result) :- !, force_evaluate_argument(X,EX),length_list(EX,Result). | |
2379 | evaluate_argument2(head(X),Result) :- !, force_evaluate_argument(X,EX), | |
2380 | head_list(EX,Result). | |
2381 | evaluate_argument2(tail(X),Result) :- !, force_evaluate_argument(X,EX),tail_list(EX,Result). | |
2382 | evaluate_argument2('^'(X,Y),Result) :- !, | |
2383 | force_evaluate_argument(X,EX),force_evaluate_argument(Y,EY), | |
2384 | %print('^'(X,EX,Y,EY)),nl, | |
2385 | append_list(EX,EY,Result). %, print(append_list(EX,EY,Result)),nl. | |
2386 | evaluate_argument2(concat(X),Result) :- !, force_evaluate_argument(X,EX), | |
2387 | concat_lists(EX,Result). | |
2388 | evaluate_argument2(listFromTo(X,Y),Res) :- !, | |
2389 | %evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2390 | expand_sequence(listFromTo(X,Y),Res). | |
2391 | evaluate_argument2(listFrom(X),Res) :- !, Res = listFrom(X). % already evaluated | |
2392 | evaluate_argument2(listExp(S),Res) :- !, evaluate_list_expression(S,Res). | |
2393 | evaluate_argument2(listExp(RangeExpr,Generators),R) :- !, %print(listExp(Generators,RangeExpr)),nl, | |
2394 | expand_listcomprehension(RangeExpr,Generators,R). %, print(res(R)),nl. | |
2395 | %evaluate_argument2(listComp(Generators,Tuples),R) :- !, %force_evaluate_list(Generators,EGen), | |
2396 | % expand_sequence(listComp(Generators,Tuples),R). | |
2397 | evaluate_argument2(set(X),Res) :- !, evaluate_argument2(seq_to_set(X),Res). | |
2398 | evaluate_argument2(seq(X),Res) :- !, evaluate_argument2(set_to_seq(X),Res). | |
2399 | evaluate_argument2(set_to_seq(X),Res) :- !, | |
2400 | force_evaluate_argument(X,EX), | |
2401 | convert_set_to_seq(EX,Res). | |
2402 | evaluate_argument2(seq_to_set(X),Res) :- !, | |
2403 | force_evaluate_argument(X,EX), | |
2404 | convert_seq_to_set(EX,Res). | |
2405 | evaluate_argument2(setFromTo(X,Y),Res) :- !, Res = setFromTo(X,Y). % already computed set expression | |
2406 | evaluate_argument2(setExp(S),Res) :- !, evaluate_set_expression(S,Res). | |
2407 | evaluate_argument2(setExp(RangeExpr,Generators),R) :- !, %print(setExp(Generators,RangeExpr)),nl, | |
2408 | expand_set_comprehension(RangeExpr,Generators,R). | |
2409 | evaluate_argument2(setValue(X),R) :- !, R=setValue(X). | |
2410 | evaluate_argument2(singleSetPatValue(X,Span),R) :- !, force_evaluate_argument(X,EX), | |
2411 | %print(singleSetPatValue(X,EX,R)),nl, | |
2412 | singleSetElement(EX,R,Span). | |
2413 | evaluate_argument2('Seq'(X),R) :- !, evaluate_argument(X,EX),R='Seq'(EX). | |
2414 | evaluate_argument2(intType,R) :- !, R=intType. | |
2415 | evaluate_argument2(boolType,R) :- !, R=boolType. | |
2416 | %evaluate_argument2(setEnum(X),R) :- !, evaluate_list(X,XL), evaluate_set(XL,R). | |
2417 | ||
2418 | evaluate_argument2(closureComp(Generators,Tuples),R) :- !, | |
2419 | % print(closureComp(Generators,Tuples)),nl, | |
2420 | expand_symbolic_set(setExp(rangeEnum(Tuples),Generators),setValue(List),evaluate_argument_closureComp), | |
2421 | % print(closureset(List)),nl, | |
2422 | evaluate_argument2(closure(List),R). %print(doneclosureComp(R)),nl. | |
2423 | evaluate_argument2(closure(X),R) :- !, %print(eval(closure(X))),nl, | |
2424 | evaluate_list(X,XL), % print(evaluate_closure(XL,R)),nl, | |
2425 | evaluate_closure(XL,R). | |
2426 | %mnf(haskell_csp:expand_channel_pattern_expression(closure(X),R,no_loc_info_available)). | |
2427 | evaluate_argument2('Events',R) :- !, | |
2428 | findall(Channel,is_a_channel_name(Channel),CL), | |
2429 | evaluate_argument2(closure(CL),R). | |
2430 | evaluate_argument2(union(X,Y),Result) :- !, force_evaluate_argument(X,EX), force_evaluate_argument(Y,EY), | |
2431 | union_set(EX,EY,Result). | |
2432 | evaluate_argument2('Union'(X),Result) :- !, force_evaluate_argument(X,EX), | |
2433 | big_union(EX,Result). | |
2434 | evaluate_argument2('Inter'(X),Result) :- !, force_evaluate_argument(X,EX), | |
2435 | big_inter(EX,Result). | |
2436 | evaluate_argument2(diff(X,Y),Result) :- !, force_evaluate_argument(X,EX), force_evaluate_argument(Y,EY), | |
2437 | %print(diff_set(X,EX,Y,EY)),nl, | |
2438 | diff_set(EX,EY,Result). | |
2439 | evaluate_argument2(inter(X,Y),Result) :- !, force_evaluate_argument(X,EX), force_evaluate_argument(Y,EY), | |
2440 | inter_set(EX,EY,Result). | |
2441 | evaluate_argument2(card(X),Result) :- !, evaluate_argument(X,EX), | |
2442 | cardinality(EX,Result). | |
2443 | evaluate_argument2('Set'(X),Result) :- !, %print(subsets(X)),nl, | |
2444 | evaluate_argument(X,EX), | |
2445 | %print(calling_subsets(EX)),nl, | |
2446 | subsets(EX,Result). %, print(subset_result(Result)),nl. | |
2447 | evaluate_argument2(agent_call(Span,F,Par),R) :- !, | |
2448 | evaluate_agent_call(F,Par,R,Span). | |
2449 | evaluate_argument2(agent_call_curry(F,Par),R) :- !, | |
2450 | Span=no_loc_info_available, | |
2451 | unfold_function_call_curry_once(F,Par,Value,Span), | |
2452 | evaluate_argument(Value,R). | |
2453 | evaluate_argument2(val_of(VAR,Span),R) :- !, /* this can only happen inside channel type expressions; | |
2454 | other val_of's are compiled away by haskell_csp_analyzer */ | |
2455 | unfold_function_call_once(VAR,[],Body,Span), | |
2456 | evaluate_argument(Body,R). | |
2457 | evaluate_argument2([],R) :- !,R=[]. | |
2458 | evaluate_argument2([H|T],R) :- !,R=[H|T]. /* list of channel outputs */ | |
2459 | evaluate_argument2(builtin_call(X),R) :- !, evaluate_argument(X,R). | |
2460 | evaluate_argument2(dotTuple(X),R) :- !, evaluate_dot_tuple(X,R). | |
2461 | evaluate_argument2(dotTupleType(TupleArgs),R) :- !, | |
2462 | evaluate_list(TupleArgs,ETupleArgs), R = dotTupleType(ETupleArgs). | |
2463 | evaluate_argument2(dotpat(X),R) :- !, evaluate_dot_tuple(X,R). | |
2464 | evaluate_argument2(tuple(F),R) :- !, R=tuple(F). | |
2465 | evaluate_argument2(alsoPat(X,Y),R) :- !, | |
2466 | evaluate_argument2(X,EX), | |
2467 | evaluate_argument2(Y,EY), | |
2468 | R=alsoPat(EX,EY). | |
2469 | evaluate_argument2(lambda(A,B),R) :- !, %print(eval(lambda(A,B))),nl, | |
2470 | R=lambda(A,B), | |
2471 | (ground(A) -> true ; | |
2472 | mynumbervars(A)). /* numbervars to avoid nonvar states for ProB (slows down hashing,...) */ | |
2473 | evaluate_argument2(tuplePat(TupleArgs),R) :- !, /* a non-associative tuple */ | |
2474 | R = na_tuple(EA),force_evaluate_list(TupleArgs,EA). | |
2475 | evaluate_argument2(tupleExp(TupleArgs),R) :- !, /* a non-associative tuple; same as tuplePat but not in pattern position */ | |
2476 | R = na_tuple(EA),force_evaluate_list(TupleArgs,EA). | |
2477 | evaluate_argument2(typeTuple(TupleArgs),R) :- !, | |
2478 | evaluate_list(TupleArgs,ETupleArgs), R = typeTuple(ETupleArgs). | |
2479 | evaluate_argument2(na_tuple(F),R) :- !, R=na_tuple(F). /* non-associative tuple */ | |
2480 | evaluate_argument2(na_tuple_projection(Nr,Tuple,Span),R) :- !, | |
2481 | evaluate_int_argument(Nr,ENr,Span), | |
2482 | force_evaluate_argument(Tuple,ETuple), | |
2483 | na_tuple_projection(ENr,ETuple,R,Span). | |
2484 | evaluate_argument2(list_projection(Nr,Len,List,Span),R) :- !, | |
2485 | evaluate_int_argument(Nr,ENr,Span), | |
2486 | evaluate_int_argument(Len,ELen,Span), | |
2487 | force_evaluate_argument(List,EList), | |
2488 | list_projection(ENr,ELen,EList,R,Span). | |
2489 | evaluate_argument2(tuple_projection(Nr,Tuple,Span),R) :- !, | |
2490 | evaluate_int_argument(Nr,ENr,Span), | |
2491 | force_evaluate_argument(Tuple,ETuple), | |
2492 | tuple_projection(ENr,ETuple,R,Span). | |
2493 | evaluate_argument2(record(C,F),R) :- !, R=record(C,F). | |
2494 | evaluate_argument2(list(X),R) :- !, %print(eval_list(X)),nl, | |
2495 | %evaluate_list(X,EX), | |
2496 | R=list(X). % TO DO: check if we also need listPat | |
2497 | evaluate_argument2(listPat(X),R) :- !, | |
2498 | evaluate_list(X,EX), R=list(EX). | |
2499 | evaluate_argument2(rename(X,Y),R) :- !, | |
2500 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(X,RX)), /* should we evaluate ??? */ | |
2501 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(Y,RY)), | |
2502 | R=rename(RX,RY). | |
2503 | evaluate_argument2(link(X,Y),R) :- !, | |
2504 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(X,RX)), /* should we evaluate ??? */ | |
2505 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(Y,RY)), | |
2506 | R=link(RX,RY). | |
2507 | evaluate_argument2(dataType(DT),R) :- !, R=dataType(DT). | |
2508 | evaluate_argument2(Channel,R) :- | |
2509 | atomic(Channel),is_a_channel_name(Channel),!,R=tuple([Channel]). | |
2510 | evaluate_argument2(DT,R) :- name_type(DT,DT_Def), !, R=DT_Def. | |
2511 | evaluate_argument2(DT,R) :- dataTypeDef(DT,_), !, R=dataType(DT). | |
2512 | evaluate_argument2(DT,R) :- subTypeDef(DT,_), !, R=dataType(DT). | |
2513 | evaluate_argument2(X,R) :- valid_constant(X),!,R=X. | |
2514 | evaluate_argument2(X,R) :- agent_functor(X,_),!,R=X. /* when a function name is passed */ | |
2515 | evaluate_argument2(X,R) :- | |
2516 | is_csp_constructor(X),!,R=X. /* FDR does not allow this as a valid value; but can be fed into closure */ | |
2517 | evaluate_argument2(X,R) :- | |
2518 | (undefined_process_construct(X) -> | |
2519 | (is_boolean_expression(X) -> evaluate_boolean_expression(X,R) | |
2520 | /* we have a boolean value; we could also decide not to evaluate the argument and put R=X*/ | |
2521 | ; add_error(evaluate_argument2,'Cannot evaluate expression: ',X), R=X | |
2522 | ) | |
2523 | ; R=X /* we have a process description which is simply kept as is */ | |
2524 | ). | |
2525 | ||
2526 | % setExp(.) | |
2527 | evaluate_set_expression(rangeEnum(List),Res) :- !, %evaluate_list(List,XL), | |
2528 | evaluate_set(List,Res).%evaluate_set(List,Res,evaluate_argument). | |
2529 | evaluate_set_expression(rangeClosed(X,Y),Res) :- !, | |
2530 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2531 | ((number(X),number(Y),X>Y) -> Res= setValue([]) ; Res = setFromTo(EX,EY)). | |
2532 | evaluate_set_expression(rangeOpen(X),Res) :- !,Res = setFrom(EX), | |
2533 | evaluate_int_argument(X,EX). | |
2534 | evaluate_set_expression(A,Res) :- | |
2535 | add_internal_error('Internal Error: Unknown setExp: ',evaluate_set_expression(A,Res)),Res=[]. | |
2536 | ||
2537 | % listExp(.) | |
2538 | evaluate_list_expression(rangeEnum(List),Res) :- !, Res=list(LR), evaluate_list(List,LR). | |
2539 | evaluate_list_expression(rangeClosed(X,Y),Res) :- !, % print(evaluate_rangeClosed(X,Y)),nl, | |
2540 | evaluate_int_argument(X,EX),evaluate_int_argument(Y,EY), | |
2541 | ((number(X),number(Y),X>Y) -> Res= list([]) ; Res = listFromTo(EX,EY)). | |
2542 | evaluate_list_expression(rangeOpen(X),Res) :- !,Res = listFrom(EX), | |
2543 | evaluate_int_argument(X,EX). | |
2544 | evaluate_list_expression(A,Res) :- /* CSP-M Parser cannot generate list expression, | |
2545 | which is not of the type rangeEnum/1, rangeClosed/2, rangeOpen/1. | |
2546 | That's why we can assume that in this case we have internal error. */ | |
2547 | add_internal_error('Internal Error: Unknown listExp: ',evaluate_list_expression(A,Res)),Res=[]. | |
2548 | ||
2549 | ||
2550 | ||
2551 | evaluate_function_name(F,EF) :- | |
2552 | (atomic(F) -> EF=F ; force_evaluate_argument(F,EF)). | |
2553 | ||
2554 | evaluate_agent_call(F,Par,Res,Span) :- % print(eval_agent_call(F,Par)),nl, | |
2555 | evaluate_function_name(F,EF),evaluate_agent_call2(EF,Par,Res,Span). | |
2556 | ||
2557 | evaluate_agent_call2(lambda(Args,Body),Par,R,Span) :- !, | |
2558 | unfold_function_call_once2(lambda(Args,Body),Par,NBody,Span), | |
2559 | evaluate_argument(NBody,R). | |
2560 | evaluate_agent_call2(F,Par,R,Span) :- !, | |
2561 | (atomic(F) -> true | |
2562 | ; add_error(evaluate_argument,'Illegal function name for function application: ',agent_call(F,Par),Span),fail), | |
2563 | X =.. [F|Par], | |
2564 | ((is_csp_process(X) ; is_possible_csp_process(X)) % ATTENTION: the parameter in is_possible_csp_process/1 can be a function call, which can be missunderstood as process | |
2565 | % a reimplementation of the is_possible_csp_process/1 is needed. | |
2566 | -> R=agent_call(Span,F,Par) %%%, print(keeping(X)),nl) | |
2567 | /* keep agent_calls lazily; they are processes. If we unfold then the variables will be | |
2568 | propagated into the term; causing problems by instantiation (see e.g. Repeat(Proc) = Proc ; Repeat(Proc)) */ | |
2569 | /* QUESTION: what about is_possible_csp_process ??? */ | |
2570 | ; unfold_function_call_once2(F,Par,Body,Span), | |
2571 | evaluate_argument(Body,R) /* TO DO: avoid re-checking when(nonvar ... for recursive calls ?*/ | |
2572 | % force_evaluate_argument(Body,R) | |
2573 | ). | |
2574 | ||
2575 | % -------------------------------------------------------- | |
2576 | % integer expressions | |
2577 | % -------------------------------------------------------- | |
2578 | ||
2579 | % -------------------------------------------------------- | |
2580 | ||
2581 | evaluate_int_argument(A,Res) :- evaluate_int_argument(A,Res,no_loc_info_available). | |
2582 | ||
2583 | :- block evaluate_int_argument(-,?,?). | |
2584 | ||
2585 | evaluate_int_argument(int(X),R,_) :- !, R=X. | |
2586 | evaluate_int_argument(agent_call(Span,F,Par),R,Span) :- !, /* in this context we need the result of the function call */ | |
2587 | unfold_function_call_once(F,Par,Body,Span), | |
2588 | %print(unfolded(F,Par,Body)),nl, | |
2589 | evaluate_int_argument(Body,R,Span). | |
2590 | evaluate_int_argument(Expr,IntRes,Span) :- | |
2591 | force_evaluate_argument(Expr,Res), % because we need an integer, i.e., agent_calls need to be unfolded | |
2592 | (Res = int(IntRes) -> true | |
2593 | ; (Res \= int(_), add_error(haskell_csp,'Expression does not evaluate to integer: ','='(Expr,Res),Span), | |
2594 | fail) | |
2595 | ). | |
2596 | ||
2597 | :- block evaluate_list(-,?). | |
2598 | evaluate_list([],R) :- !,R=[]. | |
2599 | evaluate_list([H|T],R) :- !, R=[EH|ET],evaluate_argument(H,EH), evaluate_list(T,ET). | |
2600 | evaluate_list(X,R) :- add_internal_error('Internal Error: Could not evaluate: ',evaluate_list(X,R)),R=X. | |
2601 | ||
2602 | :- block evaluate_type_list(-,?). | |
2603 | evaluate_type_list([],R) :- !,R=[]. | |
2604 | evaluate_type_list([H|T],R) :- !, R=[EH|ET], | |
2605 | translate_to_type_expr(H,TypeH), | |
2606 | evaluate_argument(TypeH,EH), | |
2607 | evaluate_type_list(T,ET). | |
2608 | evaluate_type_list(X,R) :- | |
2609 | add_internal_error('Internal Error: Could not evaluate: ',evaluate_type_list(X,R)),R=X. | |
2610 | ||
2611 | translate_to_type_expr(tupleExp(TupleArgs),R) :- !, | |
2612 | R = typeTuple(TupleArgsRes), | |
2613 | compile_tuple_args(TupleArgs,TupleArgsRes). | |
2614 | translate_to_type_expr(dotTuple(TupleArgs),R) :- !, | |
2615 | R = dotTupleType(TupleArgsRes), | |
2616 | compile_tuple_args(TupleArgs,TupleArgsRes). | |
2617 | translate_to_type_expr(X,CX) :- | |
2618 | haskell_csp_analyzer:compile_body(X,'compile_tuple_args',[],[],CX). | |
2619 | ||
2620 | compile_tuple_args([],R) :- !,R=[]. | |
2621 | compile_tuple_args([H|T],R) :- !, | |
2622 | R=[CH|RH], | |
2623 | haskell_csp_analyzer:compile_body(H,'compile_tuple_args',[],[],CH), | |
2624 | compile_tuple_args(T,RH). | |
2625 | ||
2626 | % ----------------------------------------------------- | |
2627 | ||
2628 | ||
2629 | ||
2630 | ||
2631 | force_evaluate_list(L,_EL) :- %print(force_evaluate_list(L,_EL)),nl, | |
2632 | var(L),!, add_error(haskell_csp,'Trying to force evaluation of variable: ',L),fail. | |
2633 | force_evaluate_list([],R) :- !,R=[]. | |
2634 | force_evaluate_list([H|T],R) :- !, R=[EH|ET], | |
2635 | force_evaluate_argument(H,EH), %force_evaluate_argument(H,EH), | |
2636 | force_evaluate_list(T,ET). | |
2637 | force_evaluate_list(X,R) :- | |
2638 | add_internal_error('Could not (force) evaluate list: ',force_evaluate_list(X,R)),R=X. | |
2639 | ||
2640 | unfold_function_call_curry_once(F,[],F,_Span). | |
2641 | unfold_function_call_curry_once(F,[Args|As],Value,Span) :- | |
2642 | unfold_function_call_once(F,Args,Val,Span),!, | |
2643 | % Val is a lambda-function | |
2644 | unfold_function_call_curry_once(Val,As,Value,Span). | |
2645 | ||
2646 | unfold_function_call_once(F,Par,Res,Span) :- | |
2647 | evaluate_function_name(F,EF), | |
2648 | unfold_function_call_once2(EF,Par,Res,Span). | |
2649 | ||
2650 | unfold_function_call_once2(lambda(Args,Body),Parameters,R,Span) :- !, | |
2651 | %print(unfold_lambda(Args,Parameters,Body,R)),nl, | |
2652 | % varnumbers(lambda(Args,Body),lambda(CA,CB)), /* lift the frozen parameter-vars back to real-variables; we should only lift variables in Args ! */ | |
2653 | lift(Args,CA,Body,CB), | |
2654 | % print(lifted_lambda(CA,CB)),nl, | |
2655 | evaluate_lambda_arguments(Parameters,CA,EvalParas), | |
2656 | (CA=EvalParas -> R = CB | |
2657 | ; add_error(cspm_trans,'Could not unify lambda args: ', lambda(CA,Parameters,body(Body)),Span),fail). | |
2658 | unfold_function_call_once2(FunName,Parameters,R,Span) :- %print(unfold(FunName,Parameters)),nl, | |
2659 | evaluate_agent_call_parameters(FunName,Parameters,EvalParas), | |
2660 | %%print(call_agent_compiled(FunName,Parameters,EX)),nl, | |
2661 | call_agent_compiled(FunName,Parameters,EvalParas,R,Span). | |
2662 | ||
2663 | :- block call_agent_compiled(-,?,?,?,?),call_agent_compiled(?,?,-,?,?). | |
2664 | call_agent_compiled(FunCall,_,[],Res,Span) :- !, % no parameters | |
2665 | call_agent_compiled2(FunCall,Res,Span). | |
2666 | call_agent_compiled(FunName,_Parameters,EvalParas,Res,Span) :- | |
2667 | EX =.. [FunName|EvalParas], | |
2668 | (ground(EvalParas) -> call_agent_compiled2(EX,Res,Span) | |
2669 | ; %print(not_ground_call(FunName,Parameters,EvalParas)),nl, %typechecker:debug_non_ground_term(EX), | |
2670 | is_nonvar_list_skel(EvalParas,OK), % was when(ground(EX),...) | |
2671 | call_agent_compiled1(EX,Res,OK,Span) | |
2672 | ). | |
2673 | :- block is_nonvar_list_skel(-,?). | |
2674 | %is_nonvar_list_skel([],true). % clause not coverable, [] is always ground (see ground(EvalParas) -> .. in the body of last clause of call_agent_compiled/5) | |
2675 | is_nonvar_list_skel([H|T],R) :- is_nonvar_list_skel(T,H,R). | |
2676 | :- block is_nonvar_list_skel(-,?,?),is_nonvar_list_skel(?,-,?). | |
2677 | is_nonvar_list_skel([],_,true). | |
2678 | is_nonvar_list_skel([H|T],_,R) :- is_nonvar_list_skel(T,H,R). | |
2679 | ||
2680 | :- block call_agent_compiled1(?,?,-,?). | |
2681 | call_agent_compiled1(EX,Res,_,Span) :- call_agent_compiled2(EX,Res,Span). | |
2682 | ||
2683 | call_agent_compiled2(EX,Res,Span) :- | |
2684 | (agent_compiled(EX,Value,_SRCSPAN) | |
2685 | -> %print(unfolded(Value,Res,EX)),nl, | |
2686 | %(EX='OZS@__25'(_,_) -> trace ; true), | |
2687 | Res=Value /* local cut imposes functional interpetation */ | |
2688 | ; functor(EX,F,N), functor(Skel,F,N), | |
2689 | (is_defined_agent(Skel) -> add_cspm_error(cspm_trans,'No matching case for function call: ',EX,Span) | |
2690 | ; add_cspm_error(cspm_trans,'Trying to apply undefined process/function: ',EX,Span)), | |
2691 | fail | |
2692 | ). | |
2693 | ||
2694 | safe_is(X,Expr) :- when(ground(Expr), X is Expr). | |
2695 | ||
2696 | add_cspm_error(Source,Msg,CSPE,Span) :- | |
2697 | (translate_cspm_state(CSPE,Transl) -> true ; Transl=CSPE), | |
2698 | add_error(Source,Msg,Transl,Span). | |
2699 | ||
2700 | /* ------------------------------------- */ | |
2701 | /* Renaming related predicates */ | |
2702 | /* ------------------------------------- */ | |
2703 | ||
2704 | ||
2705 | :- assert_must_succeed(( | |
2706 | retractall(csp_full_type_constructor(_,_,_)), | |
2707 | haskell_csp:rename_action(io([int(1)],left,unknown(test)),[rename(right,left),rename(left,mid)],Res), | |
2708 | Res== io([int(1)],mid,unknown(test)) )). | |
2709 | :- assert_must_succeed(( | |
2710 | retractall(csp_full_type_constructor(_,_,_)), | |
2711 | haskell_csp:rename_action(io([int(1)],ack,unknown(test)),[rename(right,left),rename(left,mid)],Res), | |
2712 | Res== io([int(1)],ack,unknown(test)) )). | |
2713 | :- assert_must_succeed(( | |
2714 | retractall(csp_full_type_constructor(_,_,_)), | |
2715 | haskell_csp:rename_action(io([int(1)],right,unknown(test)),[rename(ack,right),rename(right,dotTuple([mid,int(2)]))],Res), | |
2716 | Res== io([int(2),int(1)],mid,unknown(test)) )). | |
2717 | :- assert_must_succeed(( | |
2718 | retractall(csp_full_type_constructor(_,_,_)), | |
2719 | haskell_csp:rename_action(io([int(1)],ack,unknown(test)),[rename(ack,left),rename(ack,right)],Res), | |
2720 | Res== io([int(1)],left,unknown(test)) )). | |
2721 | :- assert_must_succeed(( | |
2722 | retractall(csp_full_type_constructor(_,_,_)), | |
2723 | haskell_csp:rename_action(io([int(1)],ack,unknown(test)),[rename(ack,left),rename(ack,right)],Res), | |
2724 | Res== io([int(1)],right,unknown(test)) )). | |
2725 | % :- assert_must_succeed(( | |
2726 | % haskell_csp:haskell_csp:rename_action(io([int(0)],gen,unknown(test)), | |
2727 | % [rename(gen,gen1),rename(gen,dotTuple([gen2,int(1)])), | |
2728 | % rename(dotTuple([gen,int(0)]),dotTuple([gen2,int(9),int(9)])), | |
2729 | % rename(stop(no_loc_info_available),dotTuple([gen2,int(2)+int(3)]))],R), | |
2730 | % R == io([int(1),int(0)],gen2,unknown(test)) )). | |
2731 | ||
2732 | :- block rename_action(-,?,-). | |
2733 | rename_action(tick(TS),_,tick(TS)). | |
2734 | rename_action(tau(X),_,tau(X)). | |
2735 | rename_action(io(V,Ch,Span),RenamePatternList,Res) :- Res=io(_,_,_), | |
2736 | match_pattern_list(RenamePatternList,V,Ch,Span,Res,false). | |
2737 | ||
2738 | force_rename_action(io(V,Ch,Span),RenamePatternList,Res) :- /* as above; but renaming must occur */ | |
2739 | match_pattern_list(RenamePatternList,V,Ch,Span,Res,true). % true: means MatchOccured: not allowed to not rename | |
2740 | ||
2741 | %not_renamed(tick(_),_). % case cannot occur, functor_dif(AX,tick) is always called before the not_renamed/2 predicate | |
2742 | not_renamed(tau(_X),_). | |
2743 | not_renamed(io(V,Ch,_Span),RenamePatternList) :- | |
2744 | not_covered_action(RenamePatternList,V,Ch). | |
2745 | ||
2746 | not_covered_action([],_,_). | |
2747 | not_covered_action([rename(ChPat,_NewCh)|T],V,Ch) :- | |
2748 | (ChPat= tuple([Ch2|TPat2]) %dotTuple([Ch2|T2]) | |
2749 | -> (dif(Ch,Ch2) ; Ch=Ch2,no_match_list(TPat2,V))%,print(nca_dif(V,T2)),nl | |
2750 | ; dif(Ch,ChPat) | |
2751 | ), not_covered_action(T,V,Ch). | |
2752 | ||
2753 | :- assert_must_succeed(( haskell_csp:no_match_list([int(1)],[int(2)]) )). | |
2754 | :- assert_must_succeed(( haskell_csp:no_match_list([int(2)],[int(1),int(2)]) )). | |
2755 | :- assert_must_fail(( haskell_csp:no_match_list([],[int(1),int(2)]) )). | |
2756 | :- assert_must_fail(( haskell_csp:no_match_list([int(2),int(3)],[int(2),int(3)]) )). | |
2757 | %% :- assert_must_fail(( haskell_csp:no_match_list([out(int(2)),out(int(3))],[int(2),int(3)]) )). | |
2758 | :- assert_must_succeed(( haskell_csp:no_match_list(X,[int(2),int(1)]), | |
2759 | X=[int(2),int(2)])). | |
2760 | ||
2761 | % check if a rename pattern matches a value on a channel: | |
2762 | no_match_list(RenPattern,ChValue) :- % print(no_match_list(A,B)),nl, | |
2763 | l_match_pattern_value(RenPattern,ChValue,match_false). | |
2764 | ||
2765 | % check if a value matches an entry in the ChannelPatternList | |
2766 | match_list(ChannelPatternList,V,Ch,Span) :- | |
2767 | match_pattern_list(ChannelPatternList,V,Ch,Span,true,true). | |
2768 | ||
2769 | :- block match_pattern_value(-,?,?), match_pattern_value(?,-,?). | |
2770 | match_pattern_value(record(C,PatArgs),record(VC,ValArgs),Res) :- !, | |
2771 | match_record(C,PatArgs,VC,ValArgs,Res). | |
2772 | match_pattern_value(tuple(L1),tuple(L2),Res) :- !, | |
2773 | l_match_pattern_value(L1,L2,Res). | |
2774 | match_pattern_value(X,tuple([H|Rest]),Res) :- !,(H=X -> Res = match_true(Rest); Res=match_false). | |
2775 | match_pattern_value(X,dotTuple([H|Rest]),Res) :- !,(H=X -> Res = match_true(Rest); Res=match_false). | |
2776 | match_pattern_value(X,record([X|Rest]),Res) :- !, Res = match_true(Rest). | |
2777 | match_pattern_value(Pat,Val,Res) :- | |
2778 | when(?=(Pat,Val),(unify_check(Pat,Val) | |
2779 | -> Res=match_true([]) ; Res=match_false)). | |
2780 | ||
2781 | unify_check(int(V1),I2) :- !, | |
2782 | (I2=int(V2) -> V1=V2 | |
2783 | %; preference(use_clpfd_solver,true), number(I2) -> V1 = I2 | |
2784 | ; add_internal_error('Type error in unification of values: ',unify_check(int(V1),I2)),fail). | |
2785 | unify_check(true,I2) :- !, | |
2786 | (I2=true -> true ; I2=false -> fail | |
2787 | ; add_internal_error('Type error in unification of values: ',unify_check(true,I2)),fail). | |
2788 | unify_check(false,I2) :- !, | |
2789 | (I2=false -> true ; I2=true -> fail | |
2790 | ; add_internal_error('Type error in unification of values: ',unify_check(false,I2)),fail). | |
2791 | unify_check(V,V). | |
2792 | ||
2793 | ||
2794 | ||
2795 | :- block match_record(-,?,?,?,?), match_record(?,?,-,?,?). | |
2796 | match_record(C1,_,C2,_,Res) :- C1\=C2,!, Res=match_false. | |
2797 | match_record(C,PatArgs,C,ValArgs,Res) :- l_match_pattern_value(PatArgs,ValArgs,Res). | |
2798 | ||
2799 | :- block l_match_pattern_value(-,?,?). | |
2800 | l_match_pattern_value(vclosure,_T,R) :- !, R=match_true(vclosure). | |
2801 | l_match_pattern_value([],T,R) :- !, R=match_true(T). | |
2802 | l_match_pattern_value([H|T],Y,R) :- !, l_match_pattern_value1(Y,H,T,R). | |
2803 | l_match_pattern_value(I,V,R) :- | |
2804 | add_internal_error('Could not evaluate: ',l_match_pattern_value(I,V,R)),fail. | |
2805 | ||
2806 | :- block l_match_pattern_value1(-,?,?,?). | |
2807 | l_match_pattern_value1([],H,T,R) :- !, add_error(haskell_csp,'Too many values in rename pattern: ',[H|T]), R=match_false. | |
2808 | l_match_pattern_value1([IODVal|IT],Pat,TPat,R) :- !, | |
2809 | get_value_alsoPat(IODVal,PV), | |
2810 | match_pattern_value(Pat,PV,Res), | |
2811 | % print(matched(Pat,PV,Res,TPat,IT)),nl, % | |
2812 | l_match_pattern_value2(Res,TPat,IT,R). | |
2813 | ||
2814 | :- block l_match_pattern_value2(-,?,?,?). | |
2815 | l_match_pattern_value2(match_true(M),TailPat,TailValue,Res) :- | |
2816 | ((TailPat=[],TailValue==[]) -> Res=match_true(M) % avoid error message in conjoin | |
2817 | ; TailPat=vclosure -> Res = match_true([]) % ignore match M; | |
2818 | % there could be strange pattern match, but | |
2819 | % it can happen that a partial record was provided (e.g., [|{|c_s.c_picks, in philosophers.csp) | |
2820 | ; (is_list(M),M\=[]) -> % one of the list arguments was a tuple, we need to pattern match the rest of the tuple arguments | |
2821 | append(TailValue,M,TailValue1), | |
2822 | l_match_pattern_value(TailPat,TailValue1,Res) | |
2823 | ; otherwise -> | |
2824 | l_match_pattern_value(TailPat,TailValue,RT), % print(conjoin(RT,match_true(M),Res)),nl, | |
2825 | conjoin_match(RT,match_true(M),Res)). | |
2826 | l_match_pattern_value2(match_false,_,_,match_false). | |
2827 | ||
2828 | :- block get_value_alsoPat(-,?). | |
2829 | get_value_alsoPat(X,Res) :- | |
2830 | get_value(X,R), | |
2831 | (nonvar(R),R=alsoPat(V1,_V2) -> | |
2832 | Res=V1 | |
2833 | ; otherwise -> | |
2834 | Res=R | |
2835 | ). | |
2836 | ||
2837 | :- block conjoin_match(-,?,?), conjoin_match(?,-,?). | |
2838 | conjoin_match(match_false,_,match_false). | |
2839 | conjoin_match(match_true(_T),match_false,match_false). | |
2840 | conjoin_match(match_true(T1),match_true(T2),Res) :- %append(T1,T2,TT). | |
2841 | (T2==[] -> Res=match_true(T1) /* note T2: is the first match, T1 the later one */ | |
2842 | ; T2==vclosure -> Res=match_true(T1) /* vclosure can propagate to the next level up */ | |
2843 | ; conjoin_error(T2,T1,ResMatch), Res=match_true(ResMatch)). | |
2844 | ||
2845 | % note: records (for example) are gradually enumerated; hence delay error message until we know the value of the inner match | |
2846 | % check if we have a pattern match like rec.a.?.b.? -> this cannot be handled by us nor by FDR | |
2847 | :- block conjoin_error(-,?,?). | |
2848 | conjoin_error([],T1,M) :- !, M=T1. | |
2849 | conjoin_error(vclosure,T1,M) :- !, M=T1. | |
2850 | conjoin_error(T2,T1,T1) :- add_error(conjoin_match,'Rename pattern is incomplete in the middle. Ignoring first match: ',T2:T1). | |
2851 | ||
2852 | :- assert_must_succeed(( | |
2853 | haskell_csp:match_pattern_list([tuple([c,int(0)|vclosure]),tuple([d|vclosure]),tuple([a,int(0),int(0),int(2)|vclosure])],[in(X),in(dotTuple([Y,Z]))],a,span,true,true), | |
2854 | X=int(0), Y=int(0), Z=int(2))). | |
2855 | :- assert_must_succeed(( | |
2856 | haskell_csp:match_pattern_list([tuple([c,int(0)|vclosure]),tuple([d|vclosure]),tuple([a,int(0),int(0),int(2)|vclosure])],[in(X),in(Y)],a,span,true,true), | |
2857 | X=int(0), Y=tuple([int(0),int(2)]))). | |
2858 | :- assert_must_succeed(( | |
2859 | haskell_csp:match_pattern_list([tuple([c,int(0)|vclosure]),tuple([d|vclosure]),tuple([a,int(0),int(0),int(2)]),tuple([d|vclosure])],[in(X),in(Y)],a,span,true,true), | |
2860 | X=int(0), Y=tuple([int(0),int(2)]))). | |
2861 | :- assert_must_fail(( | |
2862 | haskell_csp:match_pattern_list([tuple([a,int(0),int(0),int(2)]),tuple([c,int(0)|vclosure]),tuple([d|vclosure])],[in(X),in(Y)],a,span,true,true), | |
2863 | X=int(0), Y=tuple([int(0),int(3)]))). | |
2864 | :- assert_must_fail(( | |
2865 | haskell_csp:match_pattern_list([tuple([c,int(0)|vclosure]),tuple([d|vclosure]),tuple([a,int(0),int(0),int(2)])],[in(X),in(Y)],a,span,true,true), | |
2866 | X=int(0), Y=tuple([int(0),int(3),int(2)]))). | |
2867 | ||
2868 | % match_pattern_list(PatOrRenameList, Value,Channel,Span, Rename/MatchResult, HasMatchAlreadyOccured) | |
2869 | match_pattern_list([],V,Ch,Span,io(V,Ch,SpanV),MatchOccured) :- %print(no_match(V,Ch,MatchOccured)),nl, | |
2870 | set_span(SpanV,Span,match_pattern_list(Ch,V)), | |
2871 | MatchOccured=false. % only allow unrenamed action if no match occured earlier | |
2872 | match_pattern_list([rename(ChPat,NewCh)|T],V,Ch,Span,Res,MatchOccured) :- !, | |
2873 | % print(checking_pat_match(ChPat,Ch,V)),nl, %% | |
2874 | match_pattern_value(ChPat,tuple([Ch|V]),MatchRes), | |
2875 | rename_action3(MatchRes,T,NewCh,V,Ch,Span,Res,MatchOccured). | |
2876 | match_pattern_list([ChPat|T],V,Ch,Span,Res,MatchOccured) :- % for aParallel | |
2877 | % print(checking_pat_match(ChPat,Ch,V)),nl, %% | |
2878 | match_pattern_value(ChPat,tuple([Ch|V]),MatchRes), | |
2879 | pat_match_action3(MatchRes,T,V,Ch,Span,Res,MatchOccured). | |
2880 | ||
2881 | :- block pat_match_action3(-, ?,?,?,?, ?,?). | |
2882 | pat_match_action3(match_true(Rest), _T, _V,_Ch,_Span, Res,_MatchOccured) :- | |
2883 | (Rest=[] -> Res=true ; Rest=vclosure -> Res=true). % when doing a pat_match: we only allow full matches | |
2884 | %pat_match_action3(match_true(_),T,V,Ch,Span,Res,_) :- match_pattern_list(T,V,Ch,Span,Res,true). | |
2885 | pat_match_action3(match_false,T,V,Ch,Span,Res,MatchOccured) :- match_pattern_list(T,V,Ch,Span,Res,MatchOccured). | |
2886 | ||
2887 | :- block rename_action3(-, ?,?, ?,?,?, ?,?). | |
2888 | rename_action3(match_true(Rest), _T,NewCh, _V,_Ch,Span, Res,_MatchOccured) :- | |
2889 | r_compose(NewCh,Rest,Span,Res). | |
2890 | rename_action3(match_true(_),T,_NewCh,V,Ch,Span,Res,_) :- match_pattern_list(T,V,Ch,Span,Res,true). | |
2891 | rename_action3(match_false,T,_NewCh,V,Ch,Span,Res,MatchOccured) :- match_pattern_list(T,V,Ch,Span,Res,MatchOccured). | |
2892 | ||
2893 | r_compose(NewCh,Rest,Span,io(VRes,ResultingChannel,VSpan)) :- | |
2894 | set_span(VSpan,Span,r_compose(NewCh)), | |
2895 | %% print(rename_match(NewCh,Rest)),nl, %% | |
2896 | evaluate_argument(dotTuple([NewCh|Rest]), ResultTuple), | |
2897 | (ResultTuple = tuple([TCh|TV]) | |
2898 | -> ResultingChannel=TCh,VRes=TV | |
2899 | ; add_internal_error('Illegal result tuple: ', evaluate_argument(dotTuple([NewCh|Rest]), ResultTuple)), | |
2900 | ResultingChannel=NewCh, VRes=Rest | |
2901 | ). | |
2902 | ||
2903 | ||
2904 | evaluate_rename_list([],[]). | |
2905 | evaluate_rename_list([rename(X,Y)|T],[rename(EX,EY)|ET]) :- | |
2906 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(X,EX)), | |
2907 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(Y,EY)), | |
2908 | evaluate_rename_list(T,ET). | |
2909 | ||
2910 | evaluate_link_list('linkList'(L),R) :- !,evaluate_link_list2(L,R). | |
2911 | evaluate_link_list('linkListComp'(GeneratorList,LinkList),R) :- !, | |
2912 | %print(procCompLinkList(GeneratorList,LinkList)),nl, | |
2913 | % warning: LinkList does not have the rangeEnum wrapper expected | |
2914 | expand_set_comprehension(rangeEnum(LinkList),GeneratorList,setValue(ExpandedLinks)), | |
2915 | evaluate_link_list2(ExpandedLinks,R). | |
2916 | evaluate_link_list(LL,R) :- | |
2917 | add_internal_error('Cannot evaluate: ',evaluate_link_list(LL,R)),fail. | |
2918 | ||
2919 | evaluate_link_list2([],[]). | |
2920 | evaluate_link_list2([link(X,Y)|T],[rename(EX,EY)|ET]) :- /* note: link becomes rename */ | |
2921 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(X,EX)), | |
2922 | ~~mnf(haskell_csp:evaluate_rename_channel_expression(Y,EY)), | |
2923 | evaluate_link_list2(T,ET). | |
2924 | ||
2925 | rev_rename_list([],[]). | |
2926 | rev_rename_list([rename(X,Y)|T],[rename(Y,X)|RT]) :- rev_rename_list(T,RT). | |
2927 | ||
2928 | ||
2929 | evaluate_rename_channel_expression(E,RE) :- evaluate_argument(E,RE). | |
2930 | % (E=dotTuple([CH|V]) | |
2931 | % -> (RE=dotTuple([CH|EV]), | |
2932 | % l_evaluate_arguments(V,EV)) | |
2933 | % ; RE=E | |
2934 | % ). | |
2935 | ||
2936 | %%%%%%%%% DEAD CODE %%%%%%%%%%%% | |
2937 | /* | |
2938 | get_renamelist_range([],[]). | |
2939 | get_renamelist_range([rename(_X,Y)|T],[Y|DT]) :- | |
2940 | get_renamelist_range(T,DT). | |
2941 | */ | |
2942 | ||
2943 | /* ------------------------------------- */ | |
2944 | ||
2945 | /* hidden(Action, ChannelPatternList) */ | |
2946 | /* check whether an Action is covered by a CSP Channel Pattern List */ | |
2947 | ||
2948 | hidden(tau(_),_) :- fail. | |
2949 | hidden(tick(_),_) :- fail. | |
2950 | hidden(io(V,Ch,Span), ChannelPatternList) :- match_list(ChannelPatternList,V,Ch,Span). | |
2951 | ||
2952 | /* same as hidden but allows tau; useful for alphab. parallel */ | |
2953 | :- block hidden_or_tau(-,?). | |
2954 | hidden_or_tau(tau(_),_). | |
2955 | hidden_or_tau(tick(_),_) :- fail. | |
2956 | hidden_or_tau(io(V,Ch,Span), ChannelPatternList) :- match_list(ChannelPatternList,V,Ch,Span). | |
2957 | ||
2958 | ||
2959 | expand_channel_pattern_expression(X,_,SrcSpan) :- | |
2960 | % nl,print(expand_channel_pattern_expression(X)),nl, | |
2961 | var(X), !, | |
2962 | add_error(haskell_csp,'VARIABLE in expand_channel_pattern_expression: ',X,SrcSpan),fail. | |
2963 | expand_channel_pattern_expression(agent_call(Span,F,Par),Res,SrcSpan) :- !, | |
2964 | unfold_function_call_once(F,Par,Body,Span), expand_channel_pattern_expression(Body,Res,SrcSpan). | |
2965 | expand_channel_pattern_expression(setValue(List),EList,SrcSpan) :- !,l_expand(List,EList,SrcSpan). | |
2966 | expand_channel_pattern_expression(closure(List),EList,_SrcSpan) :- !, | |
2967 | %print(haskell_csp:l_cexpand(List,EList)),nl, | |
2968 | l_cexpand(List,EList). | |
2969 | %% this two clauses are already computed by expanding the setValue(-) and closure(-) predicates above (DEAD CODE) | |
2970 | /* expand_channel_pattern_expression([],R,_SrcSpan) :- !, R=[]. */ /* already computed */ | |
2971 | /*expand_channel_pattern_expression([tuple([C|T])|T2],R,SrcSpan) :- !,*/ /* already computed */ | |
2972 | /* (check_channel_value_is_complete(C,T,SrcSpan) | |
2973 | -> R=[tuple([C|T])|R2] ; R=R2), | |
2974 | expand_channel_pattern_expression(T2,R2,SrcSpan). | |
2975 | */ | |
2976 | expand_channel_pattern_expression(Exp,_,SrcSpan) :- | |
2977 | add_error(haskell_csp,'Unknown expand_channel_pattern_expression: ',Exp,SrcSpan),fail. | |
2978 | ||
2979 | /* translate a list of channel pattern expr. into uniform format */ | |
2980 | l_expand(X,R,SrcSpan) :- var(X), | |
2981 | add_internal_error_with_span(haskell_csp,'Variable List for l_expand',X,SrcSpan), R=[]. | |
2982 | l_expand(List,Res,SrcSpan) :- | |
2983 | convlist(expand_1(SrcSpan),List,Res). | |
2984 | ||
2985 | expand_1(SrcSpan,El,R) :- | |
2986 | expand(El,R,SrcSpan),!. | |
2987 | ||
2988 | /* | |
2989 | l_expand([],[],_). | |
2990 | l_expand([H|T],Res,SrcSpan) :- | |
2991 | (expand(H,EH,SrcSpan)->Res=[EH|ET];Res=ET), | |
2992 | l_expand(T,ET,SrcSpan). | |
2993 | */ | |
2994 | ||
2995 | expand(tuple([Ch|List]),R,SrcSpan) :- !,R=tuple([Ch|List]), | |
2996 | check_channel_value_is_complete(Ch,List,SrcSpan). | |
2997 | expand(Channel,R,SrcSpan) :- | |
2998 | (atomic(Channel) -> R=tuple([Channel]) | |
2999 | ; add_error(haskell_csp,'Non-atomic argument: ',expand(Channel,R,SrcSpan)),fail). | |
3000 | ||
3001 | check_channel_value_is_complete(Ch,List,SrcSpan) :- | |
3002 | (channel_type_list(Ch,ChannelTypes) | |
3003 | -> | |
3004 | (same_length(ChannelTypes,List) -> true | |
3005 | ; length(ChannelTypes,CL), length(List,L), | |
3006 | (CL>L -> add_error(check_channel_value,'Incomplete event: ','.'(Ch,List),SrcSpan) | |
3007 | ; add_error(check_channel_value,'Too many values for event: ','.'(Ch,List),SrcSpan) | |
3008 | ), fail | |
3009 | ) | |
3010 | ; add_error(haskell_csp,'Undefined channel: ','.'(Ch,List),SrcSpan),fail | |
3011 | ). | |
3012 | ||
3013 | ||
3014 | /* translate a list of channel pattern expr. into uniform format and add closure at end of list */ | |
3015 | l_cexpand(X,R) :- var(X), add_error(l_cexpand,'Variable List',X), R=[]. | |
3016 | l_cexpand(L,EL) :- maplist(cl_expand,L,EL). | |
3017 | ||
3018 | % what about pat(_,_) | |
3019 | cl_expand(tuple([Ch|List]),R) :- !, R = tuple([Ch|EL]),append_vclosure(List,EL). %, print(app_vcl(Ch,List,EL)),nl. | |
3020 | cl_expand(Channel,R) :- | |
3021 | (atomic(Channel) -> R = tuple([Channel|vclosure]) | |
3022 | ; add_error(haskell_csp, 'Non-atomic argument: ',cl_expand(Channel,R)),fail). | |
3023 | ||
3024 | ||
3025 | append_vclosure([record(X,Fields)],Res) :- incomplete_record(record(X,Fields),[_|_],_),!, | |
3026 | Res = [record(X,EFields)|vclosure], | |
3027 | append_vclosure(Fields,EFields). | |
3028 | append_vclosure([],vclosure). | |
3029 | append_vclosure([H|T],[H|VT]) :- append_vclosure(T,VT). | |
3030 | ||
3031 | ||
3032 | /* not_hidden(Action, ChannelPatternList) */ | |
3033 | /* check whether an Action is *not* covered by a CSP Channel Pattern List */ | |
3034 | ||
3035 | /* not_hidden_test(io(tail_in(X),outf), | |
3036 | [pat([int(2)],outf),pat([int(3)],outf),pat([int(8)],outf)]) */ | |
3037 | ||
3038 | :- block not_hidden(-,?). | |
3039 | not_hidden(tau(_),_). | |
3040 | not_hidden(tick(_),_). | |
3041 | not_hidden(io(V,Ch,Span),ChannelPatternList) :- % print(not_hidden_test(V,Ch,ChannelPatternList)),nl, % | |
3042 | %not_hidden_test(ChannelPatternList,V,Ch,Span). | |
3043 | match_pattern_list(ChannelPatternList,V,Ch,Span,io(_,_,_),false). % Result is true in case match occurs with list | |
3044 | ||
3045 | ||
3046 | /* ------------------------------------- */ | |
3047 | ||
3048 | :- block get_value(-,?). | |
3049 | ||
3050 | get_value(in(V),R) :- !,R=V. | |
3051 | get_value(out(V),R) :- !, add_internal_error('Obsolete out: ',get_value(out(V),R)), R=V. | |
3052 | get_value(dot(V),R) :- !, add_internal_error('Obsolete dot: ',get_value(out(V),R)), R=V. | |
3053 | get_value(record(Constructor,Fields),R) :- !, R = record(Constructor,ValueFields), | |
3054 | l_get_value(Fields,ValueFields). | |
3055 | get_value(V,V). | |
3056 | ||
3057 | :- block l_get_value(-,?). | |
3058 | l_get_value(L,VL) :- maplist(get_value,L,VL). | |
3059 | ||
3060 | valid_constant(X) :- atomic(X), (csp_constant(X,_) -> true ; fail). | |
3061 | ||
3062 | ||
3063 | /* ------------------------------------------ */ | |
3064 | /* SPAN Utilities */ | |
3065 | /* ------------------------------------------ */ | |
3066 | ||
3067 | %%%%%%%%%%%%%%%%%%%%% UNIT TESTS FOR THE SPAN UTILITIES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
3068 | :- assert_must_succeed((haskell_csp: extract_span_info(_S,Info),Info == [])). | |
3069 | :- assert_must_succeed((haskell_csp: extract_span_info(span_info(info,src_span(3,9,3,12,45,3)),R),R == [info])). | |
3070 | :- assert_must_succeed((haskell_csp: extract_span_info(src_position(3,9,3,12), R),R == [])). | |
3071 | :- assert_must_succeed((haskell_csp: extract_span_info(src_span(3,9,3,12,45,3), R),R == [])). | |
3072 | :- assert_must_succeed((haskell_csp: extract_span_info(unknown(_), R),R == [])). | |
3073 | :- assert_must_succeed((haskell_csp: extract_span_info(multi_span(3,9,3,12,45,3,span_info(info,src_span(3,9,3,12,45,3))), R), | |
3074 | R == [info])). | |
3075 | :- assert_must_succeed((haskell_csp: extract_span_info(src_span_operator(span_info(info, | |
3076 | src_span(94417,10,94421,21,1496266,98)),src_span(94421,2,94421,4,1496345,2)),R), R == [info])). | |
3077 | :- assert_must_succeed((haskell_csp: extract_span_info(no_loc_info_available,R), R == [])). | |
3078 | ||
3079 | :- assert_must_succeed((haskell_csp: unify_spans(src_span(3,9,3,12,45,3),S,R),S== src_span(3,9,3,12,45,3), R == src_span(3,9,3,12,45,3))). | |
3080 | :- assert_must_succeed((haskell_csp: unify_spans(src_span(3,9,3,12,45,3),src_span(4,9,5,16,40,5),R), | |
3081 | R == multi_span(3,9,3,12,45,3,src_span(4,9,5,16,40,5)))). | |
3082 | :- assert_must_succeed((haskell_csp: unify_spans(src_span_operator(src_span(94417,10,94421,21,1496266,98),src_span(94421,2,94421,4,1496345,2)),SP2, R), SP2 == src_span(94421,2,94421,4,1496345,2), | |
3083 | R == src_span_operator(src_span(94417,10,94421,21,1496266,98),src_span(94421,2,94421,4,1496345,2)))). | |
3084 | :- assert_must_succeed((haskell_csp: unify_spans(unknown(_),SP2,R), SP2 == R)). | |
3085 | :- assert_must_succeed((haskell_csp: unify_spans(no_loc_info_available,SP2,R), SP2 == R)). | |
3086 | :- assert_must_succeed((haskell_csp: unify_spans(src_span(3,9,3,12,12,3), no_loc_info_available,R), R == src_span(3,9,3,12,12,3))). | |
3087 | :- assert_must_succeed((haskell_csp: unify_spans(span_info(info,src_span(3,9,3,12,45,3)),src_span(3,9,3,12,45,3),R), | |
3088 | R == span_info(info,src_span(3,9,3,12,45,3)))). | |
3089 | :- assert_must_succeed((haskell_csp: unify_spans(src_position(3,9,3,12),src_span(4,9,4,15,45,6),R), | |
3090 | R == multi_span(3,9,3,21,3,12,src_span(4,9,4,15,45,6)))). | |
3091 | :- assert_must_succeed((extract_span_from_event2(start_cspm_MAIN,SPAN, start_cspm_MAIN,_), SPAN == src(3,1,3,5,20,4))). | |
3092 | :- assert_must_succeed((extract_span_from_event2(start_cspm('REC'),SPAN,start_cspm('REC'),_), SPAN == src(8,1,8,4,4,3))). | |
3093 | :- assert_must_fail((extract_span_from_event(_X,_Span,_T,_NS))). | |
3094 | :- assert_must_succeed((extract_span_info(src_position(_,_,_,_),R1), R1 ==[], extract_span_info(unknown(_),R2), R2 ==[])). | |
3095 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
3096 | ||
3097 | % span can already be set: | |
3098 | % problem: rename_action in eprocRenaming has to instantiate Span; in other contexts hidden should not instantiate span | |
3099 | set_span(SpanVar,SpanValue,PP) :- nonvar(SpanVar),!, | |
3100 | debug_println(9,span_already_set(PP,SpanValue)). | |
3101 | % print('*** Span already set to: '), print(SpanVar),nl, | |
3102 | % print('*** tried to assign value: '),print(SpanValue),nl,print('*** Context: '), print(PP),nl. | |
3103 | set_span(S,S,_C). % :- print(setting_span(S,_C)),nl. | |
3104 | ||
3105 | extract_span_info(Span,Info) :- var(Span),!,Info=[]. | |
3106 | extract_span_info(span_info(Info,Span),[Info|T]) :- extract_span_info(Span,T). | |
3107 | extract_span_info(src_position(_,_,_,_),[]). | |
3108 | extract_span_info(src_span(_,_,_,_,_,_),[]). | |
3109 | extract_span_info(src_span_operator(WholeSP1,_JustOperatorSP2),T) :- extract_span_info(WholeSP1,T). | |
3110 | extract_span_info(unknown(_),[]). | |
3111 | extract_span_info(multi_span(_,_,_,_,_,_,SP1),T) :- extract_span_info(SP1,T). | |
3112 | extract_span_info(no_loc_info_available,[]). | |
3113 | ||
3114 | :- block unify_spans(-,?,?). | |
3115 | %unify_spans(S,_,R) :- !,R=S. % commenting this in gains 10 % performance, e.g., on crossing.csp benchmark | |
3116 | unify_spans(SP1,SP2,R) :- ( unify_spans1(SP1,SP2,R) -> true | |
3117 | ; add_internal_error('Failed: ',unify_spans(SP1,SP2,R)),set_span(SP1,R,unify_spans)). | |
3118 | :- block unify_spans1(-,?,?). | |
3119 | unify_spans1(SP1,SP2,R) :- nonvar(R),!, | |
3120 | debug_println(9,span_already_computed(R,unify_spans(SP1,SP2))). | |
3121 | unify_spans1(span_info(Info,SP1),SP2,R) :- !, R=span_info(Info,RS), | |
3122 | unify_spans1(SP1,SP2,RS). | |
3123 | unify_spans1(src_position(StartLine,SC,OffsetByte,LenBytes),SP2,R) :- number(SC), number(LenBytes),!, | |
3124 | EndLine = StartLine, EC is SC+LenBytes, | |
3125 | gen_multi_span(SP2, StartLine,SC,EndLine,EC,OffsetByte,LenBytes, R). | |
3126 | unify_spans1(src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes),S,R) :- !, | |
3127 | unify_spans2(src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes),S,R). | |
3128 | unify_spans1(src_span_operator(SP1,SP2),SP3,R) :- !, R=src_span_operator(SP1,SP23), | |
3129 | unify_spans1(SP2,SP3,SP23). | |
3130 | unify_spans1(multi_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes,SP1),SP2,R) :- !, | |
3131 | unify_spans1(SP1,SP2,TailS), | |
3132 | gen_multi_span(TailS, StartLine,SC,EndLine,EC,OffsetByte,LenBytes, R). | |
3133 | unify_spans1(unknown(_),S,R) :- !, R=S. | |
3134 | unify_spans1(no_loc_info_available,S,R) :- !, R=S. | |
3135 | unify_spans1(S,_,S) :- add_error(unify_spans1,'Unknown Span: ',S). | |
3136 | ||
3137 | ||
3138 | :- block unify_spans2(-,?,?). | |
3139 | unify_spans2(src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes),S,R) :- | |
3140 | S=src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes),!, R=S. | |
3141 | unify_spans2(src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes),SP2,R) :- !, | |
3142 | gen_multi_span(SP2, StartLine,SC,EndLine,EC,OffsetByte,LenBytes, R). | |
3143 | ||
3144 | ||
3145 | :- block gen_multi_span(-, ?,?,?,?, ?,?,?). | |
3146 | gen_multi_span(no_loc_info_available, StartLine,SC,EndLine,EC, OffsetByte,LenBytes, R) :- !, | |
3147 | R = src_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes). | |
3148 | gen_multi_span(Span2,StartLine,SC,EndLine,EC,OffsetByte,LenBytes,R) :- | |
3149 | R = multi_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes, Span2),!. | |
3150 | % repeated clause | |
3151 | /*gen_multi_span(Span2,StartLine,SC,EndLine,EC,OffsetByte,LenBytes,R) :- | |
3152 | nl,print(gen_multi_span_failed),nl, %trace, | |
3153 | R = multi_span(StartLine,SC,EndLine,EC,OffsetByte,LenBytes, Span2),!. | |
3154 | */ | |
3155 | ||
3156 | :- block merge_span_into_event(?,-,?). | |
3157 | merge_span_into_event(Event,no_loc_info_available,NewEvent) :- !, | |
3158 | NewEvent=Event. | |
3159 | merge_span_into_event(Event,AdditionalSpan,NewEvent) :- | |
3160 | (extract_span_from_event(Event,SPAN,Templ,NewSPAN) | |
3161 | -> Templ = NewEvent, unify_spans(SPAN,AdditionalSpan,NewSPAN) | |
3162 | ; (%add_error(merge_span_into_event,'Unknown Event: ',Event), | |
3163 | % sometimes we cannot extract a source span, e.g., tau(repInternalChoice ...) | |
3164 | NewEvent = Event) | |
3165 | ). | |
3166 | ||
3167 | %type_of_event(io( or colour_of_event ... | |
3168 | extract_span_from_event(Event,_Span,_Template,_NewSpan) :- var(Event), | |
3169 | print('### extract_span_from_event variable'),nl,!,fail. | |
3170 | extract_span_from_event(Event,Span,Template,NewSpan) :- process_algebra_mode,!, | |
3171 | extract_span_from_event2(Event,Span,Template,NewSpan). | |
3172 | ||
3173 | %:- block extract_span_from_event2(-,?,?,?). | |
3174 | extract_span_from_event2(start_cspm_MAIN,SPAN,start_cspm_MAIN,_) :- !,get_symbol_span('MAIN',SPAN). | |
3175 | extract_span_from_event2(start_cspm(S),SPAN,start_cspm(S),_) :- !,get_symbol_span(S,SPAN). | |
3176 | extract_span_from_event2(io(Ev,Ch,SPAN),SPAN,io(Ev,Ch,NewSPAN),NewSPAN). | |
3177 | extract_span_from_event2(tau(link(Left,Right)),SPAN,Templ,NS) :- !, Templ = tau(link(Left,RTempl)), | |
3178 | extract_span_from_event2(Right,SPAN,RTempl,NS). % the linking code already puts info into right branch | |
3179 | %extract_span_from_event2(Left,RS,LTempl,RS), | |
3180 | %unify_spans(LS,RS,NS). | |
3181 | extract_span_from_event2(tau(hide(Event)),SPAN,Templ,NS) :- !, Templ = tau(hide(ETempl)), | |
3182 | extract_span_from_event2(Event,SPAN,ETempl,NS). | |
3183 | %extract_span_from_event2(tau(repInternalChoice(X)),no_loc_info_available,Templ,NS) :- !, Templ = tau(repInternalChoice(X)). | |
3184 | extract_span_from_event2(tau(int_choice_left(S,LSpan)),SPAN,Templ,NS) :- !, | |
3185 | Templ = tau(int_choice_left(S,NS)), | |
3186 | SPAN = LSpan. | |
3187 | extract_span_from_event2(tau(int_choice_right(S,RSpan)),SPAN,Templ,NS) :- !, | |
3188 | Templ = tau(int_choice_right(S,NS)), | |
3189 | SPAN = RSpan. | |
3190 | extract_span_from_event2(tau(Event),SPAN,tau(Templ),NS) :- simple_tau_event(Event,Constructor,SPAN),!, | |
3191 | functor(Templ,Constructor,1), | |
3192 | arg(1,Templ,NS). | |
3193 | %%extract_span_from_event2(i(SPAN),SPAN,i(NS),NS). %% deprecated | |
3194 | extract_span_from_event2(tick(SPAN),SPAN,tick(NS),NS). | |
3195 | ||
3196 | simple_tau_event(chaos_stop(Span),chaos_stop,Span). | |
3197 | simple_tau_event(timeout(Span),timeout,Span). | |
3198 | %simple_tau_event(int_choice_left(_,SrcSpan),int_choice_left,SrcSpan). | |
3199 | %shift_span_for_left_branch(SrcSpan,LSpan). | |
3200 | %simple_tau_event(int_choice_right(_,SrcSpan),int_choice_right,SrcSpan). | |
3201 | %shift_span_for_right_branch(SrcSpan,RSpan). | |
3202 | simple_tau_event(rep_int_choice(Span),rep_int_choice,Span). | |
3203 | simple_tau_event(tick(Span),tick,Span). | |
3204 | ||
3205 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(src_span(3,1,_,_,4,_),R), | |
3206 | R == src_span(3,1,3,2,4,1))). | |
3207 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(src_position(3,1,3,_),R), | |
3208 | R == src_position(3,1,3,1))). | |
3209 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(src_span_operator(_SP,src_span(3,1,_,_,4,_)),R), | |
3210 | R == src_span(3,1,3,2,4,1))). | |
3211 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(no_loc_info_available,R), | |
3212 | R == no_loc_info_available)). | |
3213 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(unknown,R), | |
3214 | R == unknown)). | |
3215 | :- assert_must_succeed((haskell_csp: shift_span_for_left_branch(src,R), | |
3216 | R == src)). | |
3217 | :- block shift_span_for_left_branch(-,?). | |
3218 | shift_span_for_left_branch(src_span(StartLine,SC,_EndLine,_EC,Off,_LenBytes),R) :- !, | |
3219 | NEC is SC+1, | |
3220 | R=src_span(StartLine,SC,StartLine,NEC,Off,1). | |
3221 | shift_span_for_left_branch(src_position(StartLine,SC,Off,_LenBytes),R) :- !, | |
3222 | R = src_position(StartLine,SC,Off,1). | |
3223 | shift_span_for_left_branch(src_span_operator(_WholeSpan,JustOperator),R) :- !, | |
3224 | shift_span_for_left_branch(JustOperator,R). | |
3225 | shift_span_for_left_branch(no_loc_info_available,R) :- !, R=no_loc_info_available. | |
3226 | shift_span_for_left_branch(unknown(I),R) :- !, R=unknown(I). | |
3227 | shift_span_for_left_branch(X,X):- print(not_shifting_left(X)),nl. | |
3228 | ||
3229 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(src_span(_,_,3,2,6,5),R), | |
3230 | R == src_span(3,1,3,2,10,1))). | |
3231 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(src_position(3,1,3,4),R), | |
3232 | R == src_position(3,4,6,1))). | |
3233 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(src_span_operator(_SP,src_span(_,_,3,2,6,5)),R), | |
3234 | R == src_span(3,1,3,2,10,1))). | |
3235 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(no_loc_info_available,R), | |
3236 | R == no_loc_info_available)). | |
3237 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(unknown,R), | |
3238 | R == unknown)). | |
3239 | :- assert_must_succeed((haskell_csp: shift_span_for_right_branch(src,R), | |
3240 | R == src)). | |
3241 | ||
3242 | :- block shift_span_for_right_branch(-,?). | |
3243 | shift_span_for_right_branch(src_span(_StartLine,_SC,EndLine,EC,Off,LenBytes),R) :- !, | |
3244 | NL is 1, NSC is EC-1, NO is Off+LenBytes-1, | |
3245 | R=src_span(EndLine,NSC,EndLine,EC,NO,NL). | |
3246 | shift_span_for_right_branch(src_position(StartLine,SC,Off,LenBytes),R) :- !, | |
3247 | NL is 1, NSC is SC+LenBytes-1, NO is Off+LenBytes-1, | |
3248 | R = src_position(StartLine,NSC,NO,NL). | |
3249 | shift_span_for_right_branch(src_span_operator(_WholeSpan,JustOperator),R) :- !, | |
3250 | shift_span_for_right_branch(JustOperator,R). | |
3251 | shift_span_for_right_branch(no_loc_info_available,R) :- !, R=no_loc_info_available. | |
3252 | shift_span_for_right_branch(unknown(I),R) :- !, R=unknown(I). | |
3253 | shift_span_for_right_branch(X,X):- print(not_shifting_right(X)),nl. |