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(kernel_records,[is_a_record_wf/3, not_is_a_record_wf/3, | |
6 | construct_record_wf/3, | |
7 | access_record_wf/4, | |
8 | normalise_record_type/2, record_has_multiple_field_names/2, | |
9 | check_field_name_compatibility/2 | |
10 | ]). | |
11 | ||
12 | ||
13 | :- use_module(self_check). | |
14 | :- use_module(debug). | |
15 | :- use_module(tools). | |
16 | :- use_module(typechecker). | |
17 | :- use_module(error_manager). | |
18 | ||
19 | :- use_module(module_information,[module_info/2]). | |
20 | :- module_info(group,kernel). | |
21 | :- module_info(description,'This module contains predicates that operate on the record type.'). | |
22 | ||
23 | :- assert_must_succeed(( kernel_records:normalise_record_type( | |
24 | record([field(name,global('ID')),field(balance,integer)]),X), | |
25 | X= record([field(balance,integer),field(name,global('ID'))]) )). | |
26 | :- assert_must_succeed(( kernel_records:normalise_record_type( | |
27 | record([field(balance,integer),field(name,global('ID'))]),X), | |
28 | X= record([field(balance,integer),field(name,global('ID'))]) )). | |
29 | :- assert_must_succeed(( kernel_records:normalise_record_type( | |
30 | record([field(b,d),field(a,c)]),X), | |
31 | X= record([field(a,c),field(b,d)]) )). | |
32 | ||
33 | normalise_record_type(record(Fields),record(SortedFields)) :- | |
34 | check_known_field_names(Fields), | |
35 | sort(Fields,SortedFields). | |
36 | ||
37 | ||
38 | :- use_module(kernel_waitflags). | |
39 | :- assert_must_succeed(( kernel_waitflags:init_wait_flags(WF), | |
40 | kernel_records:is_a_record_wf(rec([field(balance,int(1)),field(name,fd(2,'Name'))]), | |
41 | rec([field(balance,global_set('NAT')),field(name,global_set('Name'))]),WF), | |
42 | kernel_waitflags:ground_wait_flags(WF))). | |
43 | :- assert_must_fail(( kernel_waitflags:init_wait_flags(WF), | |
44 | kernel_records:is_a_record_wf(rec([field(a,int(0)),field(b,fd(2,'Name'))]), | |
45 | rec([field(a,global_set('NAT1')),field(b,global_set('Name'))]),WF), | |
46 | kernel_waitflags:ground_wait_flags(WF))). | |
47 | :- assert_must_fail(( kernel_waitflags:init_wait_flags(WF), | |
48 | kernel_records:is_a_record_wf(rec([field(a,int(1)),field(b,fd(2,'Name')),field(c,int(0))]), | |
49 | rec([field(a,global_set('NAT1')),field(b,global_set('Name')),field(c,global_set('NAT1'))]),WF), | |
50 | kernel_waitflags:ground_wait_flags(WF))). | |
51 | ||
52 | ||
53 | is_a_record_wf(rec(Fields),rec(FieldSets),WF) :- %print_message(check_is_a_record(Record,FieldSets)), | |
54 | check_field_values(Fields,FieldSets,WF). | |
55 | ||
56 | ||
57 | :-use_module(kernel_objects,[check_element_of_wf/3, membership_test_wf/4]). | |
58 | ||
59 | :- block check_field_values(-,-,?). | |
60 | check_field_values([],[],_WF). | |
61 | check_field_values([field(Name,V)|ValueRest],[field(Name,VT)|TypeRest],WF) :- | |
62 | check_element_of_wf(V,VT,WF), | |
63 | check_field_values(ValueRest,TypeRest,WF). | |
64 | ||
65 | ||
66 | ||
67 | :- assert_must_succeed(( kernel_waitflags:init_wait_flags(WF), | |
68 | kernel_records:not_is_a_record_wf(rec([field(balance,int(0)),field(name,fd(2,'Name'))]), | |
69 | rec([field(balance,global_set('NAT1')),field(name,global_set('Name'))]),WF), | |
70 | kernel_waitflags:ground_wait_flags(WF))). | |
71 | :- assert_must_succeed(( kernel_waitflags:init_wait_flags(WF), | |
72 | kernel_records:not_is_a_record_wf(rec([field(a,int(1)),field(b,fd(2,'Name')),field(c,int(0))]), | |
73 | rec([field(a,global_set('NAT1')),field(b,global_set('Name')),field(c,global_set('NAT1'))]),WF), | |
74 | kernel_waitflags:ground_wait_flags(WF))). | |
75 | :- assert_must_fail(( kernel_waitflags:init_wait_flags(WF), | |
76 | kernel_records:not_is_a_record_wf(rec([field(a,int(1)),field(b,fd(2,'Name')),field(c,int(1))]), | |
77 | rec([field(a,global_set('NAT1')),field(b,global_set('Name')),field(c,global_set('NAT1'))]),WF), | |
78 | kernel_waitflags:ground_wait_flags(WF))). | |
79 | ||
80 | not_is_a_record_wf(rec(Fields),rec(FieldSets),WF) :- | |
81 | not_check_field_values(Fields,FieldSets,WF). | |
82 | %print_message(not_is_a_record(Record,FieldSets,WF)). | |
83 | ||
84 | ||
85 | :- block not_check_field_values(-,-,?). | |
86 | not_check_field_values([field(Name,V)|ValueRest],[field(Name,VT)|TypeRest],WF) :- | |
87 | membership_test_wf(VT,V,MemRes,WF), | |
88 | not_check_field_values2(MemRes,ValueRest,TypeRest,WF). | |
89 | ||
90 | :- block not_check_field_values2(-,?,?,?). | |
91 | not_check_field_values2(pred_false,_,_,_). | |
92 | not_check_field_values2(pred_true,ValueRest,TypeRest,WF) :- | |
93 | not_check_field_values(ValueRest,TypeRest,WF). | |
94 | ||
95 | ||
96 | ||
97 | ||
98 | ||
99 | :- assert_must_fail(( X = [field(b,int(33)),field(a,int(2))], kernel_records:construct_record_wf(X,rec(X),_WF) )). | |
100 | :- assert_must_succeed(( kernel_records:construct_record_wf(X,rec([field(a,int(2)),field(b,int(3))]),_WF), | |
101 | X = [field(b,int(3)),field(a,int(2))] )). | |
102 | :- assert_must_succeed(( kernel_records:construct_record_wf(X,rec([field(a,int(2)),field(b,int(3))]),_WF), | |
103 | X = [field(a,int(2)),field(b,int(3))] )). | |
104 | :- assert_must_succeed(( kernel_records:construct_record_wf(X,Y,_WF), | |
105 | X = [field(b,int(4)),field(a,int(2))], Y = rec([field(a,int(2)),field(b,int(4))]) )). | |
106 | :- assert_must_succeed(( kernel_records:construct_record_wf(X,rec([field(a,[int(2),int(3)]),field(b,int(3))]),_WF), X = [field(a,[int(3),int(2)]),field(b,int(3))] )). | |
107 | ||
108 | :- block construct_record_wf(-,?,?). | |
109 | construct_record_wf(Fields,Res,WF) :- | |
110 | check_known_field_names(Fields), | |
111 | sort(Fields,SortedFields), | |
112 | kernel_objects:equal_object_wf(Res,rec(SortedFields),WF). | |
113 | ||
114 | check_known_field_names(Var) :- var(Var), !, | |
115 | add_internal_error('Illegal var fields: ',check_known_field_names(Var)). | |
116 | check_known_field_names([]). | |
117 | check_known_field_names([field(Name,_)|T]) :- | |
118 | (var(Name) -> add_internal_error('Illegal var fields: ',check_known_field_names([field(Name,_)|T])) | |
119 | ; true), | |
120 | check_known_field_names(T). | |
121 | ||
122 | ||
123 | ||
124 | %instantiate output argument when all field names known + indicate whether sorted or not | |
125 | %:- block known_field_names(-,?). | |
126 | %known_field_names([],sorted). | |
127 | %known_field_names([field(Name,_)|T],Known) :- known_field_names4(T,Name,sorted,Known). | |
128 | % | |
129 | %:- block known_field_names4(-,?,?,?),known_field_names4(?,-,?,?). | |
130 | %known_field_names4([],_,K,K). | |
131 | %known_field_names4([field(Name,_)|T],PrevName,SortedSoFar,Known) :- | |
132 | % (PrevName @< Name -> S2=SortedSoFar ; S2=not_sorted), | |
133 | % known_field_names4(T,Name,S2,Known). | |
134 | ||
135 | ||
136 | ||
137 | % check if a sorted records has multiple field names | |
138 | record_has_multiple_field_names([field(N,_)|T],Res) :- multiple_fields_aux(T,N,Res). | |
139 | multiple_fields_aux([field(N,_)|T],N1,Res) :- | |
140 | (N1=N -> Res=N ; multiple_fields_aux(T,N,Res)). | |
141 | ||
142 | :- use_module(library(lists)). | |
143 | ||
144 | %%:- assert_must_fail(( kernel_records:access_record(rec([]),a,_) )). %% actually: must generate error; not just fail | |
145 | :- assert_must_fail(( kernel_records:access_record(rec([field(a,int(2))]),a,int(3)) )). | |
146 | :- assert_must_succeed(( kernel_records:access_record(rec(X),a,int(2)), X=[field(b,_),field(a,int(2))|_] )). | |
147 | :- assert_must_succeed(( kernel_records:access_record(rec(X),b,int(2)), X=[field(b,_),field(a,int(3))|_] )). | |
148 | ||
149 | access_record(Rec,Field,V) :- access_record_wf(Rec,Field,V,no_wf_available). | |
150 | ||
151 | %access_record(X,Y,Z) :- print_message(access_record(X,Y,Z)),fail. | |
152 | :- block access_record_wf(?,-,?,?). % when we add access_record_wf(-,?,?,?) we do not instantiate to rec(_), but PROB-356 runs slower. | |
153 | access_record_wf(rec(Fields),FieldName,Value,WF) :- | |
154 | % access_record2(Fields,FieldName,Value). | |
155 | %:- block access_record2(?,-,?). | |
156 | %access_record2(Fields,FieldName,Value) :- | |
157 | get_field(Fields,FieldName,Value,Fields,WF). | |
158 | ||
159 | :- block get_field(-,?,?,?,?). | |
160 | get_field([],FieldName,_Value,OrigFields,_WF) :- | |
161 | add_internal_error('Could not get field: ', FieldName:OrigFields),fail. | |
162 | get_field([field(SFieldName,SValue)|T], FieldName,Value,OrigFields,WF) :- | |
163 | get_field2(SFieldName,SValue,T, FieldName,Value,OrigFields,WF). | |
164 | ||
165 | :- block get_field2(-,?,?, ?,?,?,?). | |
166 | get_field2(SFieldName,SValue,T, FieldName,Value,OrigFields,WF) :- | |
167 | (SFieldName=FieldName | |
168 | -> kernel_objects:equal_object_wf(Value,SValue,get_field2,WF) | |
169 | ; get_field(T,FieldName,Value,OrigFields,WF) | |
170 | ). | |
171 | ||
172 | ||
173 | ||
174 | :- assert_must_succeed(( kernel_records:check_field_name_compatibility(a,a))). | |
175 | check_field_name_compatibility(Name1,Name2) :- | |
176 | nonvar(Name1), nonvar(Name2), Name1 \= Name2, !, | |
177 | add_internal_error('Incompatible fields: ',check_field_name_compatibility(Name1,Name2)), | |
178 | fail. | |
179 | check_field_name_compatibility(Name,Name). |