Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (c) 2000-2014 Ericsson Telecom AB | |
3 | // All rights reserved. This program and the accompanying materials | |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include "Constraint.hh" | |
9 | #include "CompilerError.hh" | |
10 | #include "Int.hh" | |
11 | #include "Type.hh" | |
12 | #include "Value.hh" | |
13 | #include "subtype.hh" | |
14 | #include "Identifier.hh" | |
15 | #include "CompField.hh" | |
16 | #include "asn1/Block.hh" | |
17 | #include "asn1/TokenBuf.hh" | |
18 | ||
19 | namespace Common { | |
20 | ||
21 | // ================================= | |
22 | // ===== Constraints | |
23 | // ================================= | |
24 | ||
25 | Constraints::Constraints(const Constraints& p) | |
26 | : Node(p), cons(), my_type(0), subtype(0), extendable(false), extension(0) | |
27 | { | |
28 | size_t nof_cons = p.cons.size(); | |
29 | for (size_t i = 0; i < nof_cons; i++) cons.add(p.cons[i]->clone()); | |
30 | } | |
31 | ||
32 | Constraints::~Constraints() | |
33 | { | |
34 | size_t nof_cons = cons.size(); | |
35 | for (size_t i = 0; i < nof_cons; i++) delete cons[i]; | |
36 | cons.clear(); | |
37 | delete subtype; | |
38 | delete extension; | |
39 | } | |
40 | ||
41 | Constraints *Constraints::clone() const | |
42 | { | |
43 | return new Constraints(*this); | |
44 | } | |
45 | ||
46 | void Constraints::add_con(Constraint *p_con) | |
47 | { | |
48 | if (!p_con) FATAL_ERROR("Constraints::add_con()"); | |
49 | cons.add(p_con); | |
50 | if (my_type) p_con->set_my_type(my_type); | |
51 | } | |
52 | ||
53 | Constraint* Constraints::get_tableconstraint() const | |
54 | { | |
55 | size_t nof_cons = cons.size(); | |
56 | for (size_t i = 0; i < nof_cons; i++) { | |
57 | Constraint *con = cons[i]; | |
58 | if (con->get_constrtype() == Constraint::CT_TABLE) return con; | |
59 | } | |
60 | return 0; | |
61 | } | |
62 | ||
63 | void Constraints::set_my_type(Type *p_my_type) | |
64 | { | |
65 | my_type=p_my_type; | |
66 | size_t nof_cons = cons.size(); | |
67 | for (size_t i = 0; i < nof_cons; i++) cons[i]->set_my_type(p_my_type); | |
68 | } | |
69 | ||
70 | void Constraints::chk_table() | |
71 | { | |
72 | if(!my_type) FATAL_ERROR("Constraints::chk_table()"); | |
73 | size_t nof_cons = cons.size(); | |
74 | for (size_t i = 0; i < nof_cons; i++) { | |
75 | Error_Context cntxt(my_type, "In constraint #%lu of type `%s'", | |
76 | (unsigned long) (i + 1), my_type->get_typename().c_str()); | |
77 | Constraint::constrtype_t cst = cons[i]->get_constrtype(); | |
78 | if (cst==Constraint::CT_TABLE) cons[i]->chk(); | |
79 | } | |
80 | } | |
81 | ||
82 | void Constraints::chk(SubtypeConstraint* parent_subtype) | |
83 | { | |
84 | if(!my_type) FATAL_ERROR("Common::Constraints::chk()"); | |
85 | if (parent_subtype) { | |
86 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
87 | subtype->copy(parent_subtype); | |
88 | } | |
89 | size_t nof_cons = cons.size(); | |
90 | for (size_t i = 0; i < nof_cons; i++) { | |
91 | Error_Context cntxt(my_type, "In constraint #%lu of type `%s'", | |
92 | (unsigned long) (i + 1), my_type->get_typename().c_str()); | |
93 | cons[i]->set_fullname(my_type->get_fullname()+".<constraint_"+Int2string(i+1)+">.<"+string(cons[i]->get_name())+">"); | |
94 | cons[i]->set_my_cons(this); | |
95 | Constraint::constrtype_t cst = cons[i]->get_constrtype(); | |
96 | if (cst!=Constraint::CT_TABLE) cons[i]->chk(); | |
97 | if ( (cst==Constraint::CT_IGNORE) || (cst==Constraint::CT_TABLE) ) continue; // ignore | |
98 | SubtypeConstraint* sc = cons[i]->get_subtype(); | |
99 | SubtypeConstraint* sc_ext = cons[i]->get_extension(); | |
100 | if (!sc) break; // stop on error | |
101 | extendable = cons[i]->is_extendable(); | |
102 | if (extension) { // only the root part shall be kept | |
103 | delete extension; | |
104 | extension = 0; | |
105 | } | |
106 | if (subtype) { | |
107 | if (sc->is_subset(subtype)==TFALSE) { | |
108 | cons[i]->error("Constraint #%lu is %s, this is not a subset of %s", | |
109 | (unsigned long) (i + 1), | |
110 | sc->to_string().c_str(), | |
111 | subtype->to_string().c_str()); | |
112 | break; // stop on error | |
113 | } | |
114 | if (sc_ext && (sc_ext->is_subset(subtype)==TFALSE)) { | |
115 | cons[i]->error("Extension addition of constraint #%lu is %s, this is not a subset of %s", | |
116 | (unsigned long) (i + 1), | |
117 | sc_ext->to_string().c_str(), | |
118 | subtype->to_string().c_str()); | |
119 | break; // stop on error | |
120 | } | |
121 | if (sc_ext) { | |
122 | extension = new SubtypeConstraint(my_type->get_subtype_type()); | |
123 | extension->copy(sc_ext); | |
124 | extension->intersection(subtype); | |
125 | } | |
126 | subtype->intersection(sc); | |
127 | } else { | |
128 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
129 | subtype->copy(sc); | |
130 | if (sc_ext) { | |
131 | extension = new SubtypeConstraint(my_type->get_subtype_type()); | |
132 | extension->copy(sc_ext); | |
133 | } | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | // ================================= | |
139 | // ===== Constraint | |
140 | // ================================= | |
141 | ||
142 | Constraint::Constraint(const Constraint& p): | |
143 | Node(p), Location(p), constrtype(p.constrtype), | |
144 | my_type(0), my_scope(0), my_parent(0), my_cons(0), | |
145 | checked(false), subtype(0), extendable(false), extension(0) | |
146 | { | |
147 | } | |
148 | ||
149 | Constraint::Constraint(constrtype_t p_constrtype): | |
150 | Node(), Location(), constrtype(p_constrtype), | |
151 | my_type(0), my_scope(0), my_parent(0), my_cons(0), | |
152 | checked(false), subtype(0), extendable(false), extension(0) | |
153 | { | |
154 | } | |
155 | ||
156 | Constraint::~Constraint() | |
157 | { | |
158 | delete subtype; | |
159 | delete extension; | |
160 | } | |
161 | ||
162 | Scope* Constraint::get_my_scope() | |
163 | { | |
164 | if (!my_type) FATAL_ERROR("Constraint::get_my_scope()"); | |
165 | return my_scope ? my_scope : my_type->get_my_scope(); | |
166 | } | |
167 | ||
168 | void Constraint::set_my_cons(Constraints* p_my_cons) | |
169 | { | |
170 | my_cons = p_my_cons; | |
171 | } | |
172 | ||
173 | Constraints* Constraint::get_my_cons() | |
174 | { | |
175 | Constraint* c = this; | |
176 | while (c) { | |
177 | if (c->my_cons) return c->my_cons; | |
178 | c = c->my_parent; | |
179 | } | |
180 | FATAL_ERROR("Constraint::get_my_cons()"); | |
181 | return NULL; | |
182 | } | |
183 | ||
184 | bool Constraint::in_char_context() const | |
185 | { | |
186 | Constraint* parent = my_parent; | |
187 | while (parent) { | |
188 | if (parent->get_constrtype()==CT_PERMITTEDALPHABET) return true; | |
189 | parent = parent->get_my_parent(); | |
190 | } | |
191 | return false; | |
192 | } | |
193 | ||
194 | bool Constraint::in_inner_constraint() const | |
195 | { | |
196 | Constraint* parent = my_parent; | |
197 | while (parent) { | |
198 | switch (parent->get_constrtype()) { | |
199 | case CT_SINGLEINNERTYPE: | |
200 | case CT_MULTIPLEINNERTYPE: | |
201 | return true; | |
202 | default: | |
203 | break; | |
204 | } | |
205 | parent = parent->get_my_parent(); | |
206 | } | |
207 | return false; | |
208 | } | |
209 | ||
210 | // ================================= | |
211 | // ===== ElementSetSpecsConstraint | |
212 | // ================================= | |
213 | ||
214 | ElementSetSpecsConstraint::ElementSetSpecsConstraint(const ElementSetSpecsConstraint& p) | |
215 | : Constraint(p) | |
216 | { | |
217 | extendable = true; | |
218 | root_constr = p.root_constr ? p.root_constr->clone() : 0; | |
219 | ext_constr = p.ext_constr ? p.ext_constr->clone() : 0; | |
220 | } | |
221 | ||
222 | ElementSetSpecsConstraint::ElementSetSpecsConstraint(Constraint* p_root_constr, Constraint* p_ext_constr) | |
223 | : Constraint(CT_ELEMENTSETSPEC), root_constr(p_root_constr), ext_constr(p_ext_constr) | |
224 | { | |
225 | if (!p_root_constr) FATAL_ERROR("ElementSetSpecsConstraint::ElementSetSpecsConstraint()"); | |
226 | // p_ext_constr can be NULL | |
227 | extendable = true; | |
228 | } | |
229 | ||
230 | ElementSetSpecsConstraint::~ElementSetSpecsConstraint() | |
231 | { | |
232 | delete root_constr; | |
233 | delete ext_constr; | |
234 | } | |
235 | ||
236 | void ElementSetSpecsConstraint::chk() | |
237 | { | |
238 | if (checked) return; | |
239 | checked = true; | |
240 | if (!root_constr || !my_type) FATAL_ERROR("ElementSetSpecsConstraint::chk()"); | |
241 | Error_Context cntxt(this, "While checking ElementSetSpecs constraint"); | |
242 | root_constr->set_my_type(my_type); | |
243 | if (ext_constr) ext_constr->set_my_type(my_type); | |
244 | root_constr->set_my_scope(get_my_scope()); | |
245 | if (ext_constr) ext_constr->set_my_scope(get_my_scope()); | |
246 | root_constr->set_my_parent(this); | |
247 | if (ext_constr) ext_constr->set_my_parent(this); | |
248 | root_constr->chk(); | |
249 | if (ext_constr) ext_constr->chk(); | |
250 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); | |
251 | // naming ((r1,x1),...,(r2,x2)) according to X.680(11/2008) I.4.3.8 | |
252 | SubtypeConstraint* r1 = root_constr->get_subtype(); | |
253 | if (!r1) return; // root_constr is invalid, error already reported there | |
254 | SubtypeConstraint* x1 = root_constr->get_extension(); | |
255 | if (!ext_constr) { | |
256 | // only root part exists | |
257 | subtype = new SubtypeConstraint(my_subtype_type); | |
258 | subtype->copy(r1); | |
259 | if (x1) { | |
260 | extension = new SubtypeConstraint(my_subtype_type); | |
261 | extension->copy(x1); | |
262 | } | |
263 | return; | |
264 | } | |
265 | SubtypeConstraint* r2 = ext_constr->get_subtype(); | |
266 | if (!r2) return; // ext_constr is invalid, error already reported there | |
267 | SubtypeConstraint* x2 = ext_constr->get_extension(); | |
268 | subtype = new SubtypeConstraint(my_subtype_type); | |
269 | subtype->copy(r1); | |
270 | extension = new SubtypeConstraint(my_subtype_type); | |
271 | extension->copy(r2); | |
272 | if (x1) extension->union_(x1); | |
273 | if (x2) extension->union_(x2); | |
274 | extension->except(r1); | |
275 | } | |
276 | ||
277 | void ElementSetSpecsConstraint::set_fullname(const string& p_fullname) | |
278 | { | |
279 | Node::set_fullname(p_fullname); | |
280 | root_constr->set_fullname(p_fullname+".<root_part>.<"+string(root_constr->get_name())+">"); | |
281 | if (ext_constr) | |
282 | ext_constr->set_fullname(p_fullname+".<extension_part>.<"+string(ext_constr->get_name())+">"); | |
283 | } | |
284 | ||
285 | // ================================= | |
286 | // ===== IgnoredConstraint | |
287 | // ================================= | |
288 | ||
289 | IgnoredConstraint::IgnoredConstraint(const IgnoredConstraint& p) | |
290 | : Constraint(p), my_name(p.my_name) | |
291 | { | |
292 | } | |
293 | ||
294 | IgnoredConstraint::IgnoredConstraint(const char* p_name) | |
295 | : Constraint(CT_IGNORE), my_name(p_name) | |
296 | { | |
297 | if (p_name==NULL) FATAL_ERROR("IgnoredConstraint::IgnoredConstraint()"); | |
298 | } | |
299 | ||
300 | void IgnoredConstraint::chk() | |
301 | { | |
302 | if (checked) return; | |
303 | checked = true; | |
304 | if (!my_type) FATAL_ERROR("IgnoredConstraint::chk()"); | |
305 | if (in_char_context()) { | |
306 | error("%s not allowed inside a permitted alphabet constraint", get_name()); | |
307 | return; | |
308 | } else { | |
309 | if (my_parent) warning("%s inside a %s is treated as `ALL' (constraint is dropped)", get_name(), my_parent->get_name()); | |
310 | //else warning("%s is ignored", get_name()); | |
311 | } | |
312 | // ignored constraint does not constrain the type, set to full set | |
313 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
314 | } | |
315 | ||
316 | // ================================= | |
317 | // ===== SingleValueConstraint | |
318 | // ================================= | |
319 | ||
320 | SingleValueConstraint::SingleValueConstraint(const SingleValueConstraint& p) | |
321 | : Constraint(p) | |
322 | { | |
323 | value = p.value ? p.value->clone() : 0; | |
324 | } | |
325 | ||
326 | SingleValueConstraint::~SingleValueConstraint() | |
327 | { | |
328 | delete value; | |
329 | } | |
330 | ||
331 | SingleValueConstraint::SingleValueConstraint(Value* p_value) | |
332 | : Constraint(CT_SINGLEVALUE), value(p_value) | |
333 | { | |
334 | if (!p_value) FATAL_ERROR("SingleValueConstraint::SingleValueConstraint()"); | |
335 | } | |
336 | ||
337 | void SingleValueConstraint::chk() | |
338 | { | |
339 | if (checked) return; | |
340 | checked = true; | |
341 | if (!value || !my_type) FATAL_ERROR("SingleValueConstraint::chk()"); | |
342 | Error_Context cntxt(this, "While checking single value constraint"); | |
343 | value->set_my_scope(get_my_scope()); | |
344 | value->set_my_governor(my_type); | |
345 | my_type->chk_this_value_ref(value); | |
346 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, | |
347 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); | |
348 | if (in_char_context()) { | |
349 | subtype = SubtypeConstraint::create_from_asn_charvalues(my_type, value); | |
350 | } else { | |
351 | subtype = SubtypeConstraint::create_from_asn_value(my_type, value); | |
352 | } | |
353 | } | |
354 | ||
355 | void SingleValueConstraint::set_fullname(const string& p_fullname) | |
356 | { | |
357 | Node::set_fullname(p_fullname); | |
358 | value->set_fullname(p_fullname+".<value>"); | |
359 | } | |
360 | ||
361 | // ================================= | |
362 | // ===== ContainedSubtypeConstraint | |
363 | // ================================= | |
364 | ||
365 | ContainedSubtypeConstraint::ContainedSubtypeConstraint(const ContainedSubtypeConstraint& p) | |
366 | : Constraint(p) | |
367 | { | |
368 | type = p.type ? p.type->clone() : 0; | |
369 | } | |
370 | ||
371 | ContainedSubtypeConstraint::~ContainedSubtypeConstraint() | |
372 | { | |
373 | delete type; | |
374 | } | |
375 | ||
376 | ContainedSubtypeConstraint::ContainedSubtypeConstraint(Type* p_type, bool p_has_includes) | |
377 | : Constraint(CT_CONTAINEDSUBTYPE), type(p_type), has_includes(p_has_includes) | |
378 | { | |
379 | if (!p_type) FATAL_ERROR("ContainedSubtypeConstraint::ContainedSubtypeConstraint()"); | |
380 | } | |
381 | ||
382 | void ContainedSubtypeConstraint::chk() | |
383 | { | |
384 | if (checked) return; | |
385 | checked = true; | |
386 | if (!type || !my_type) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); | |
387 | Error_Context cntxt(this, "While checking contained subtype constraint"); | |
388 | ||
389 | type->set_my_scope(get_my_scope()); | |
390 | type->chk(); | |
391 | if (type->get_typetype()==Type::T_ERROR) return; | |
392 | ||
393 | if (my_type->get_type_refd_last()->get_typetype()==Type::T_OPENTYPE) { | |
394 | // TODO: open type and anytype should have their own ST_ANY subtype, now this is only ignored | |
395 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
396 | return; | |
397 | } | |
398 | ||
399 | if (!type->is_identical(my_type)) { | |
400 | error("Contained subtype constraint is invalid, constrained and constraining types have different root type"); | |
401 | return; | |
402 | } | |
403 | // check subtype of referenced type | |
404 | SubType* t_st = type->get_sub_type(); | |
405 | if (t_st==NULL) { | |
406 | error("Contained subtype constraint is invalid, the constraining type has no subtype constraint"); | |
407 | return; | |
408 | } | |
409 | ||
410 | // check circular subtype reference | |
411 | Type* my_owner = get_my_cons()->get_my_type(); | |
412 | if (!my_owner || !my_owner->get_sub_type()) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); | |
413 | if (!my_owner->get_sub_type()->add_parent_subtype(t_st)) return; | |
414 | ||
415 | if (t_st->get_subtypetype()==SubtypeConstraint::ST_ERROR) return; | |
416 | if (t_st->get_subtypetype()!=my_type->get_subtype_type()) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); | |
417 | ||
418 | subtype = SubtypeConstraint::create_from_contained_subtype(t_st->get_root(), in_char_context(), this); | |
419 | } | |
420 | ||
421 | void ContainedSubtypeConstraint::set_fullname(const string& p_fullname) | |
422 | { | |
423 | Node::set_fullname(p_fullname); | |
424 | type->set_fullname(p_fullname+".<type>"); | |
425 | } | |
426 | ||
427 | // ================================= | |
428 | // ===== RangeEndpoint | |
429 | // ================================= | |
430 | ||
431 | RangeEndpoint::RangeEndpoint(const RangeEndpoint& p): | |
432 | Node(p), Location(p), type(p.type), inclusive(p.inclusive) | |
433 | { | |
434 | value = p.value ? p.value->clone() : 0; | |
435 | } | |
436 | ||
437 | RangeEndpoint::~RangeEndpoint() | |
438 | { | |
439 | delete value; | |
440 | } | |
441 | ||
442 | RangeEndpoint::RangeEndpoint(endpoint_t p_type): | |
443 | Node(), Location(), type(p_type), value(0), inclusive(true) | |
444 | { | |
445 | if (type==VALUE) FATAL_ERROR("RangeEndpoint::RangeEndpoint()"); | |
446 | } | |
447 | ||
448 | RangeEndpoint::RangeEndpoint(Value* p_value): | |
449 | Node(), Location(), type(RangeEndpoint::VALUE), value(p_value), inclusive(true) | |
450 | { | |
451 | if (!p_value) FATAL_ERROR("RangeEndpoint::RangeEndpoint()"); | |
452 | } | |
453 | ||
454 | void RangeEndpoint::chk(Type* my_type, ValueRangeConstraint* constraint) | |
455 | { | |
456 | if (value) { | |
457 | value->set_my_scope(constraint->get_my_scope()); | |
458 | my_type->chk_this_value_ref(value); | |
459 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, | |
460 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); | |
461 | } | |
462 | } | |
463 | ||
464 | void RangeEndpoint::set_fullname(const string& p_fullname) | |
465 | { | |
466 | Node::set_fullname(p_fullname); | |
467 | if (value) value->set_fullname(p_fullname+".<value>"); | |
468 | } | |
469 | ||
470 | // ================================= | |
471 | // ===== ValueRangeConstraint | |
472 | // ================================= | |
473 | ||
474 | ValueRangeConstraint::ValueRangeConstraint(const ValueRangeConstraint& p) | |
475 | : Constraint(p) | |
476 | { | |
477 | lower_endpoint = p.lower_endpoint ? p.lower_endpoint->clone() : 0; | |
478 | upper_endpoint = p.upper_endpoint ? p.upper_endpoint->clone() : 0; | |
479 | } | |
480 | ||
481 | ValueRangeConstraint::ValueRangeConstraint(RangeEndpoint* p_lower, RangeEndpoint* p_upper) | |
482 | : Constraint(CT_VALUERANGE), lower_endpoint(p_lower), upper_endpoint(p_upper) | |
483 | { | |
484 | if (!p_lower || !p_upper) FATAL_ERROR("ValueRangeConstraint::ValueRangeConstraint()"); | |
485 | } | |
486 | ||
487 | void ValueRangeConstraint::chk() | |
488 | { | |
489 | if (checked) return; | |
490 | checked = true; | |
491 | if (!lower_endpoint || !upper_endpoint || !my_type) FATAL_ERROR("ValueRangeConstraint::chk()"); | |
492 | Error_Context cntxt(this, "While checking value range constraint"); | |
493 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); | |
494 | switch (my_subtype_type) { | |
495 | case SubtypeConstraint::ST_INTEGER: | |
496 | case SubtypeConstraint::ST_FLOAT: | |
497 | break; | |
498 | case SubtypeConstraint::ST_CHARSTRING: | |
499 | switch (my_type->get_type_refd_last()->get_typetype()) { | |
500 | case Type::T_NUMERICSTRING: | |
501 | case Type::T_PRINTABLESTRING: | |
502 | case Type::T_IA5STRING: | |
503 | case Type::T_VISIBLESTRING: | |
504 | if (!in_char_context()) { | |
505 | error("Value range constraint must be inside a permitted alphabet or size constraint"); | |
506 | return; | |
507 | } | |
508 | break; | |
509 | default: | |
510 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); | |
511 | return; | |
512 | } | |
513 | break; | |
514 | case SubtypeConstraint::ST_UNIVERSAL_CHARSTRING: | |
515 | switch (my_type->get_type_refd_last()->get_typetype()) { | |
516 | case Type::T_UTF8STRING: | |
517 | case Type::T_UNIVERSALSTRING: | |
518 | case Type::T_BMPSTRING: | |
519 | if (!in_char_context()) { | |
520 | error("Value range constraint must be inside a permitted alphabet or size constraint"); | |
521 | return; | |
522 | } | |
523 | break; | |
524 | default: | |
525 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); | |
526 | return; | |
527 | } | |
528 | break; | |
529 | default: | |
530 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); | |
531 | return; | |
532 | } | |
533 | lower_endpoint->chk(my_type, this); | |
534 | upper_endpoint->chk(my_type, this); | |
535 | Value* vmin = lower_endpoint->get_value(); | |
536 | if (vmin) vmin = vmin->get_value_refd_last(); | |
537 | Value* vmax = upper_endpoint->get_value(); | |
538 | if (vmax) vmax = vmax->get_value_refd_last(); | |
539 | // the subtype of the Constraints object at the time of calling this chk() | |
540 | // function is constructed from all the previously calculated constraints | |
541 | // (it is not yet the final subtype). This is needed to calculate the | |
542 | // current MIN and MAX values. | |
543 | SubtypeConstraint* parent_subtype = get_my_cons()->get_subtype(); | |
544 | subtype = SubtypeConstraint::create_from_asn_range( | |
545 | vmin, lower_endpoint->get_exclusive(), | |
546 | vmax, upper_endpoint->get_exclusive(), | |
547 | this, my_subtype_type, | |
548 | in_inner_constraint() ? NULL /*the parent is invalid for an inner field*/ : parent_subtype); | |
549 | } | |
550 | ||
551 | void ValueRangeConstraint::set_fullname(const string& p_fullname) | |
552 | { | |
553 | Node::set_fullname(p_fullname); | |
554 | lower_endpoint->set_fullname(p_fullname+".<lower_endpoint>"); | |
555 | upper_endpoint->set_fullname(p_fullname+".<upper_endpoint>"); | |
556 | } | |
557 | ||
558 | // ================================= | |
559 | // ===== SizeConstraint | |
560 | // ================================= | |
561 | ||
562 | SizeConstraint::SizeConstraint(const SizeConstraint& p) | |
563 | : Constraint(p) | |
564 | { | |
565 | constraint = p.constraint ? p.constraint->clone() : 0; | |
566 | } | |
567 | ||
568 | SizeConstraint::SizeConstraint(Constraint* p) | |
569 | : Constraint(CT_SIZE), constraint(p) | |
570 | { | |
571 | if (!p) FATAL_ERROR("SizeConstraint::SizeConstraint()"); | |
572 | } | |
573 | ||
574 | void SizeConstraint::chk() | |
575 | { | |
576 | if (checked) return; | |
577 | checked = true; | |
578 | if (!constraint || !my_type) FATAL_ERROR("SizeConstraint::chk()"); | |
579 | Error_Context cntxt(this, "While checking size constraint"); | |
580 | constraint->set_my_type(Type::get_pooltype(Type::T_INT_A)); | |
581 | constraint->set_my_scope(get_my_scope()); | |
582 | constraint->set_my_parent(this); | |
583 | constraint->chk(); | |
584 | subtype = SubtypeConstraint::create_asn_size_constraint( | |
585 | constraint->get_subtype(), in_char_context(), my_type, this); | |
586 | extendable = constraint->is_extendable(); | |
587 | if (constraint->get_extension()) { | |
588 | extension = SubtypeConstraint::create_asn_size_constraint( | |
589 | constraint->get_extension(), in_char_context(), my_type, this); | |
590 | } | |
591 | } | |
592 | ||
593 | void SizeConstraint::set_fullname(const string& p_fullname) | |
594 | { | |
595 | Node::set_fullname(p_fullname); | |
596 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); | |
597 | } | |
598 | ||
599 | // ================================= | |
600 | // ===== PermittedAlphabetConstraint | |
601 | // ================================= | |
602 | ||
603 | PermittedAlphabetConstraint::PermittedAlphabetConstraint(const PermittedAlphabetConstraint& p) | |
604 | : Constraint(p) | |
605 | { | |
606 | constraint = p.constraint ? p.constraint->clone() : 0; | |
607 | } | |
608 | ||
609 | PermittedAlphabetConstraint::PermittedAlphabetConstraint(Constraint* p) | |
610 | : Constraint(CT_PERMITTEDALPHABET), constraint(p) | |
611 | { | |
612 | if (!p) FATAL_ERROR("PermittedAlphabetConstraint::PermittedAlphabetConstraint()"); | |
613 | } | |
614 | ||
615 | void PermittedAlphabetConstraint::chk() | |
616 | { | |
617 | if (checked) return; | |
618 | checked = true; | |
619 | if (!constraint || !my_type) FATAL_ERROR("PermittedAlphabetConstraint::chk()"); | |
620 | Error_Context cntxt(this, "While checking permitted alphabet constraint"); | |
621 | constraint->set_my_type(my_type); | |
622 | constraint->set_my_scope(get_my_scope()); | |
623 | constraint->set_my_parent(this); | |
624 | constraint->chk(); | |
625 | subtype = SubtypeConstraint::create_permitted_alphabet_constraint( | |
626 | constraint->get_subtype(), in_char_context(), my_type, this); | |
627 | extendable = constraint->is_extendable(); | |
628 | if (constraint->get_extension()) { | |
629 | extension = SubtypeConstraint::create_permitted_alphabet_constraint( | |
630 | constraint->get_extension(), in_char_context(), my_type, this); | |
631 | } | |
632 | } | |
633 | ||
634 | void PermittedAlphabetConstraint::set_fullname(const string& p_fullname) | |
635 | { | |
636 | Node::set_fullname(p_fullname); | |
637 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); | |
638 | } | |
639 | ||
640 | // ================================= | |
641 | // ===== SetOperationConstraint | |
642 | // ================================= | |
643 | ||
644 | SetOperationConstraint::SetOperationConstraint(const SetOperationConstraint& p) | |
645 | : Constraint(p), operationtype(p.operationtype) | |
646 | { | |
647 | operand_a = p.operand_a ? p.operand_a->clone() : 0; | |
648 | operand_b = p.operand_b ? p.operand_b->clone() : 0; | |
649 | } | |
650 | ||
651 | void SetOperationConstraint::set_first_operand(Constraint* p_a) | |
652 | { | |
653 | if (operand_a || !p_a) FATAL_ERROR("SetOperationConstraint::set_first_operand()"); | |
654 | operand_a = p_a; | |
655 | } | |
656 | ||
657 | SetOperationConstraint::SetOperationConstraint(Constraint* p_a, operationtype_t p_optype, Constraint* p_b) | |
658 | : Constraint(CT_SETOPERATION), operationtype(p_optype), operand_a(p_a), operand_b(p_b) | |
659 | { | |
660 | // p_a can be null | |
661 | if (!p_b) FATAL_ERROR("SetOperationConstraint::SetOperationConstraint()"); | |
662 | } | |
663 | ||
664 | const char* SetOperationConstraint::get_operationtype_str() const | |
665 | { | |
666 | switch (operationtype) { | |
667 | case UNION: | |
668 | return "union"; | |
669 | case INTERSECTION: | |
670 | return "intersection"; | |
671 | case EXCEPT: | |
672 | return "except"; | |
673 | } | |
674 | return "<invalid>"; | |
675 | } | |
676 | ||
677 | void SetOperationConstraint::chk() | |
678 | { | |
679 | if (checked) return; | |
680 | checked = true; | |
681 | if (!operand_a || !operand_b || !my_type) FATAL_ERROR("SetOperationConstraint::chk()"); | |
682 | Error_Context cntxt(this, "While checking %s operation", get_operationtype_str()); | |
683 | operand_a->set_my_type(my_type); | |
684 | operand_b->set_my_type(my_type); | |
685 | operand_a->set_my_scope(get_my_scope()); | |
686 | operand_b->set_my_scope(get_my_scope()); | |
687 | operand_a->set_my_parent(this); | |
688 | operand_b->set_my_parent(this); | |
689 | operand_a->chk(); | |
690 | operand_b->chk(); | |
691 | ||
692 | extendable = (operationtype!=EXCEPT) ? | |
693 | (operand_a->is_extendable() || operand_b->is_extendable()) : | |
694 | operand_a->is_extendable(); | |
695 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); | |
696 | // naming ((r1,x1),...,(r2,x2)) according to X.680(11/2008) I.4.3.8 | |
697 | SubtypeConstraint* r1 = operand_a->get_subtype(); | |
698 | SubtypeConstraint* x1 = operand_a->get_extension(); | |
699 | SubtypeConstraint* r2 = operand_b->get_subtype(); | |
700 | SubtypeConstraint* x2 = operand_b->get_extension(); | |
701 | if (!r1 || !r2) return; // something invalid, error already reported there | |
702 | subtype = new SubtypeConstraint(my_subtype_type); | |
703 | subtype->copy(r1); | |
704 | switch (operationtype) { | |
705 | case UNION: | |
706 | subtype->union_(r2); | |
707 | if (x1 || x2) { | |
708 | extension = new SubtypeConstraint(my_subtype_type); | |
709 | if (x1 && x2) { | |
710 | extension->copy(subtype); | |
711 | extension->union_(x1); | |
712 | extension->union_(x2); | |
713 | extension->except(subtype); | |
714 | } else { | |
715 | extension->copy(x1?x1:x2); | |
716 | } | |
717 | } | |
718 | break; | |
719 | case INTERSECTION: | |
720 | subtype->intersection(r2); | |
721 | if (x1 || x2) { | |
722 | extension = new SubtypeConstraint(my_subtype_type); | |
723 | if (x1 && x2) { | |
724 | extension->copy(r1); | |
725 | extension->union_(x1); | |
726 | SubtypeConstraint* ext_tmp = new SubtypeConstraint(my_subtype_type); | |
727 | ext_tmp->copy(r2); | |
728 | ext_tmp->union_(x2); | |
729 | extension->intersection(ext_tmp); | |
730 | delete ext_tmp; | |
731 | extension->except(subtype); | |
732 | } else { | |
733 | extension->copy(r1); | |
734 | extension->intersection(x1?x1:x2); | |
735 | } | |
736 | } | |
737 | break; | |
738 | case EXCEPT: | |
739 | subtype->except(r2); | |
740 | if (x1) { | |
741 | extension = new SubtypeConstraint(my_subtype_type); | |
742 | if (x2) { | |
743 | extension->copy(x1); | |
744 | SubtypeConstraint* ext_tmp = new SubtypeConstraint(my_subtype_type); | |
745 | ext_tmp->copy(r2); | |
746 | ext_tmp->union_(x2); | |
747 | extension->except(ext_tmp); | |
748 | delete ext_tmp; | |
749 | extension->except(subtype); | |
750 | } else { | |
751 | extension->copy(x1); | |
752 | extension->except(r2); | |
753 | extension->except(subtype); | |
754 | } | |
755 | } | |
756 | break; | |
757 | default: | |
758 | FATAL_ERROR("SetOperationConstraint::chk()"); | |
759 | } | |
760 | } | |
761 | ||
762 | void SetOperationConstraint::set_fullname(const string& p_fullname) | |
763 | { | |
764 | Node::set_fullname(p_fullname); | |
765 | operand_a->set_fullname(p_fullname+".<first_operand>.<"+string(operand_a->get_name())+">"); | |
766 | operand_b->set_fullname(p_fullname+".<second_operand>.<"+string(operand_b->get_name())+">"); | |
767 | } | |
768 | ||
769 | // ================================= | |
770 | // ===== FullSetConstraint | |
771 | // ================================= | |
772 | ||
773 | void FullSetConstraint::chk() | |
774 | { | |
775 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); | |
776 | subtype = new SubtypeConstraint(my_subtype_type); | |
777 | } | |
778 | ||
779 | // ================================= | |
780 | // ===== PatternConstraint | |
781 | // ================================= | |
782 | ||
783 | PatternConstraint::PatternConstraint(const PatternConstraint& p) | |
784 | : Constraint(p) | |
785 | { | |
786 | value = p.value ? p.value->clone() : 0; | |
787 | } | |
788 | ||
789 | PatternConstraint::~PatternConstraint() | |
790 | { | |
791 | delete value; | |
792 | } | |
793 | ||
794 | PatternConstraint::PatternConstraint(Value* p_value) | |
795 | : Constraint(CT_PATTERN), value(p_value) | |
796 | { | |
797 | if (!p_value) FATAL_ERROR("PatternConstraint::PatternConstraint()"); | |
798 | } | |
799 | ||
800 | void PatternConstraint::chk() | |
801 | { | |
802 | if (checked) return; | |
803 | checked = true; | |
804 | if (!value || !my_type) FATAL_ERROR("PatternConstraint::chk()"); | |
805 | Error_Context cntxt(this, "While checking pattern constraint"); | |
806 | switch (my_type->get_subtype_type()) { | |
807 | case SubtypeConstraint::ST_CHARSTRING: | |
808 | case SubtypeConstraint::ST_UNIVERSAL_CHARSTRING: | |
809 | break; | |
810 | default: | |
811 | error("Pattern constraint is not allowed for type `%s'", my_type->get_typename().c_str()); | |
812 | return; | |
813 | } | |
814 | value->set_my_scope(get_my_scope()); | |
815 | value->set_my_governor(my_type); | |
816 | my_type->chk_this_value_ref(value); | |
817 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, | |
818 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); | |
819 | // ignore ASN.1 pattern constraint (9.1 Transformation rules, point 4.) | |
820 | if (in_char_context()) { | |
821 | error("%s not allowed inside a permitted alphabet constraint", get_name()); | |
822 | return; | |
823 | } else { | |
824 | if (my_parent) warning("%s inside a %s is treated as `ALL' (constraint is dropped)", | |
825 | get_name(), my_parent->get_name()); | |
826 | else warning("%s is ignored", get_name()); | |
827 | } | |
828 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
829 | } | |
830 | ||
831 | void PatternConstraint::set_fullname(const string& p_fullname) | |
832 | { | |
833 | Node::set_fullname(p_fullname); | |
834 | value->set_fullname(p_fullname+".<value>"); | |
835 | } | |
836 | ||
837 | // ================================= | |
838 | // ===== SingleInnerTypeConstraint | |
839 | // ================================= | |
840 | ||
841 | SingleInnerTypeConstraint::SingleInnerTypeConstraint(const SingleInnerTypeConstraint& p) | |
842 | : Constraint(p) | |
843 | { | |
844 | constraint = p.constraint ? p.constraint->clone() : 0; | |
845 | } | |
846 | ||
847 | SingleInnerTypeConstraint::SingleInnerTypeConstraint(Constraint* p) | |
848 | : Constraint(CT_SINGLEINNERTYPE), constraint(p) | |
849 | { | |
850 | if (!p) FATAL_ERROR("SingleInnerTypeConstraint::SingleInnerTypeConstraint()"); | |
851 | } | |
852 | ||
853 | void SingleInnerTypeConstraint::chk() | |
854 | { | |
855 | if (checked) return; | |
856 | checked = true; | |
857 | if (!constraint || !my_type) FATAL_ERROR("SingleInnerTypeConstraint::chk()"); | |
858 | Error_Context cntxt(this, "While checking inner type constraint"); | |
859 | Type* t = my_type->get_type_refd_last(); | |
860 | if (!t->is_seof()) { | |
861 | error("Single inner type constraint (WITH COMPONENT) cannot be used on type `%s'", my_type->get_typename().c_str()); | |
862 | return; | |
863 | } | |
864 | Type* field_type = t->get_ofType(); // determine the type of the field to which it refers | |
865 | constraint->set_my_type(field_type); | |
866 | constraint->set_my_scope(get_my_scope()); | |
867 | constraint->set_my_parent(this); | |
868 | constraint->chk(); | |
869 | //if (constraint->get_subtype()) { // if the constraint was not erroneous | |
870 | // TODO: this could be added to the a tree structure constraint on my_type, | |
871 | // tree structure needed because of set operations, constraint cannot | |
872 | // be added to field_type | |
873 | //} | |
874 | // inner subtype is ignored ( ETSI ES 201 873-7 V4.1.2 -> 9.1 Transformation rules ) | |
875 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
876 | } | |
877 | ||
878 | void SingleInnerTypeConstraint::set_fullname(const string& p_fullname) | |
879 | { | |
880 | Node::set_fullname(p_fullname); | |
881 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); | |
882 | } | |
883 | ||
884 | // ================================= | |
885 | // ===== NamedConstraint | |
886 | // ================================= | |
887 | ||
888 | NamedConstraint::NamedConstraint(Identifier* p_id, Constraint* p_value_constraint, presence_constraint_t p_presence_constraint): | |
889 | Constraint(CT_NAMED), id(p_id), value_constraint(p_value_constraint), presence_constraint(p_presence_constraint) | |
890 | { | |
891 | if (!id) FATAL_ERROR("NamedConstraint::NamedConstraint()"); | |
892 | } | |
893 | ||
894 | NamedConstraint::NamedConstraint(const NamedConstraint& p) | |
895 | : Constraint(p) | |
896 | { | |
897 | id = p.id->clone(); | |
898 | value_constraint = p.value_constraint ? p.value_constraint->clone() : 0; | |
899 | presence_constraint = p.presence_constraint; | |
900 | } | |
901 | ||
902 | NamedConstraint::~NamedConstraint() | |
903 | { | |
904 | delete id; | |
905 | delete value_constraint; | |
906 | } | |
907 | ||
908 | const char* NamedConstraint::get_presence_constraint_name() const | |
909 | { | |
910 | switch (presence_constraint) { | |
911 | case PC_NONE: return ""; | |
912 | case PC_PRESENT: return "PRESENT"; | |
913 | case PC_ABSENT: return "ABSENT"; | |
914 | case PC_OPTIONAL: return "OPTIONAL"; | |
915 | default: FATAL_ERROR("NamedConstraint::get_presence_constraint_name()"); | |
916 | } | |
917 | } | |
918 | ||
919 | void NamedConstraint::chk() | |
920 | { | |
921 | if (checked) return; | |
922 | checked = true; | |
923 | if (!my_type) FATAL_ERROR("NamedConstraint::chk()"); | |
924 | Error_Context cntxt(this, "While checking named constraint"); | |
925 | if (value_constraint) { | |
926 | value_constraint->set_my_type(my_type); | |
927 | value_constraint->set_my_scope(get_my_scope()); | |
928 | value_constraint->set_my_parent(this); | |
929 | value_constraint->chk(); | |
930 | } | |
931 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); // ignored | |
932 | } | |
933 | ||
934 | void NamedConstraint::set_fullname(const string& p_fullname) | |
935 | { | |
936 | Node::set_fullname(p_fullname); | |
937 | if (value_constraint) { | |
938 | value_constraint->set_fullname(p_fullname+".<"+string(value_constraint->get_name())+">"); | |
939 | } | |
940 | } | |
941 | ||
942 | // ================================= | |
943 | // ===== MultipleInnerTypeConstraint | |
944 | // ================================= | |
945 | ||
946 | MultipleInnerTypeConstraint::MultipleInnerTypeConstraint(const MultipleInnerTypeConstraint& p) | |
947 | : Constraint(p) | |
948 | { | |
949 | partial = p.partial; | |
950 | for (size_t i=0; i<p.named_con_vec.size(); i++) { | |
951 | named_con_vec.add( p.named_con_vec[i]->clone() ); | |
952 | } | |
953 | } | |
954 | ||
955 | MultipleInnerTypeConstraint::~MultipleInnerTypeConstraint() | |
956 | { | |
957 | named_con_map.clear(); | |
958 | for (size_t i=0; i<named_con_vec.size(); i++) { | |
959 | delete named_con_vec[i]; | |
960 | } | |
961 | named_con_vec.clear(); | |
962 | } | |
963 | ||
964 | void MultipleInnerTypeConstraint::addNamedConstraint(NamedConstraint* named_con) | |
965 | { | |
966 | if (!named_con) FATAL_ERROR("MultipleInnerTypeConstraint::addNamedConstraint()"); | |
967 | if (checked) FATAL_ERROR("MultipleInnerTypeConstraint::addNamedConstraint()"); | |
968 | named_con_vec.add(named_con); | |
969 | } | |
970 | ||
971 | void MultipleInnerTypeConstraint::chk() | |
972 | { | |
973 | if (checked) return; | |
974 | checked = true; | |
975 | if (!my_type) FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); | |
976 | Type* t = my_type->get_type_refd_last(); | |
977 | ||
978 | switch (t->get_typetype()) { | |
979 | case Type::T_REAL: { // associated ASN.1 type is a SEQUENCE | |
980 | Identifier t_id(Identifier::ID_ASN, string("REAL")); | |
981 | t = t->get_my_scope()->get_scope_asss()->get_local_ass_byId(t_id)->get_Type(); | |
982 | if (t->get_typetype()!=Type::T_SEQ_A) FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); | |
983 | } break; | |
984 | case Type::T_CHOICE_A: | |
985 | case Type::T_SEQ_A: // T_EXTERNAL, T_EMBEDDED_PDV, T_UNRESTRICTEDSTRING | |
986 | case Type::T_SET_A: | |
987 | break; | |
988 | default: | |
989 | FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); | |
990 | } | |
991 | // check that all NamedConstraints refer to an existing component | |
992 | // if it exists add it to the map<> and check uniqueness | |
993 | // for SEQUENCE check order of fields | |
994 | size_t max_idx = 0; // current highest field index, to detect invalid order | |
995 | bool invalid_order = false; | |
996 | size_t present_count = 0; | |
997 | size_t absent_count = 0; | |
998 | for (size_t i=0; i<named_con_vec.size(); i++) { | |
999 | const Identifier& id = named_con_vec[i]->get_id(); | |
1000 | if (t->has_comp_withName(id)) { | |
1001 | if (named_con_map.has_key(id)) { | |
1002 | named_con_vec[i]->error("Duplicate reference to field `%s' of type `%s'", | |
1003 | id.get_dispname().c_str(), my_type->get_typename().c_str()); | |
1004 | named_con_map[id]->note("Previous reference to field `%s' is here", | |
1005 | id.get_dispname().c_str()); | |
1006 | } else { | |
1007 | named_con_map.add(id, named_con_vec[i]); | |
1008 | if (t->get_typetype()==Type::T_SEQ_A) { | |
1009 | size_t curr_idx = t->get_comp_index_byName(id); | |
1010 | if (curr_idx<max_idx) invalid_order = true; | |
1011 | else max_idx = curr_idx; | |
1012 | } | |
1013 | switch (named_con_vec[i]->get_presence_constraint()) { | |
1014 | case NamedConstraint::PC_PRESENT: | |
1015 | present_count++; | |
1016 | break; | |
1017 | case NamedConstraint::PC_ABSENT: | |
1018 | absent_count++; | |
1019 | break; | |
1020 | default: | |
1021 | break; | |
1022 | } | |
1023 | } | |
1024 | CompField* cf = t->get_comp_byName(id); | |
1025 | switch (t->get_typetype()) { | |
1026 | case Type::T_SEQ_A: | |
1027 | case Type::T_SET_A: | |
1028 | if (!cf->get_is_optional() && (named_con_vec[i]->get_presence_constraint()!=NamedConstraint::PC_NONE)) { | |
1029 | named_con_vec[i]->error("Presence constraint `%s' cannot be used on mandatory field `%s'", | |
1030 | named_con_vec[i]->get_presence_constraint_name(), id.get_dispname().c_str()); | |
1031 | } | |
1032 | break; | |
1033 | default: | |
1034 | break; | |
1035 | } | |
1036 | Type* field_type = cf->get_type(); | |
1037 | named_con_vec[i]->set_my_type(field_type); | |
1038 | named_con_vec[i]->set_my_scope(get_my_scope()); | |
1039 | named_con_vec[i]->set_my_parent(this); | |
1040 | named_con_vec[i]->chk(); | |
1041 | } else { | |
1042 | named_con_vec[i]->error("Type `%s' does not have a field named `%s'", | |
1043 | my_type->get_typename().c_str(), id.get_dispname().c_str()); | |
1044 | } | |
1045 | } | |
1046 | if (invalid_order) { | |
1047 | error("The order of fields must be the same as in the definition of type `%s'", | |
1048 | my_type->get_typename().c_str()); | |
1049 | } | |
1050 | if (t->get_typetype()==Type::T_CHOICE_A) { | |
1051 | if (present_count>1) { | |
1052 | error("CHOICE type `%s' cannot have more than one `PRESENT' field", my_type->get_typename().c_str()); | |
1053 | } | |
1054 | // in FullSpecification all not listed fields that can be absent are implicitly ABSENT | |
1055 | size_t real_absent_count = absent_count + ((!get_partial())?(t->get_nof_comps()-named_con_map.size()):0); | |
1056 | if (real_absent_count>=t->get_nof_comps()) { | |
1057 | error("All fields of CHOICE type `%s' are `ABSENT'", my_type->get_typename().c_str()); | |
1058 | if (real_absent_count>absent_count) { | |
1059 | note("%ld not listed field%s implicitly `ABSENT' because FullSpecification was used", | |
1060 | (long)(real_absent_count-absent_count), ((real_absent_count-absent_count)>1)?"s are":" is"); | |
1061 | } | |
1062 | } | |
1063 | } | |
1064 | ||
1065 | // inner subtype is ignored ( ETSI ES 201 873-7 V4.1.2 -> 9.1 Transformation rules ) | |
1066 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); | |
1067 | } | |
1068 | ||
1069 | void MultipleInnerTypeConstraint::set_fullname(const string& p_fullname) | |
1070 | { | |
1071 | Node::set_fullname(p_fullname); | |
1072 | for (size_t i=0; i<named_con_vec.size(); i++) { | |
1073 | named_con_vec[i]->set_fullname(p_fullname+".<"+string(named_con_vec[i]->get_name())+" "+Int2string(i)+">"); | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | // ================================= | |
1078 | // ===== UnparsedMultipleInnerTypeConstraint | |
1079 | // ================================= | |
1080 | ||
1081 | UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint(const UnparsedMultipleInnerTypeConstraint& p) | |
1082 | : Constraint(p) | |
1083 | { | |
1084 | block = p.block ? p.block->clone() : 0; | |
1085 | constraint = 0; | |
1086 | } | |
1087 | ||
1088 | UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint(Block* p_block) | |
1089 | : Constraint(CT_UNPARSEDMULTIPLEINNERTYPE), block(p_block), constraint(0) | |
1090 | { | |
1091 | if (!block) FATAL_ERROR("UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint()"); | |
1092 | } | |
1093 | ||
1094 | UnparsedMultipleInnerTypeConstraint::~UnparsedMultipleInnerTypeConstraint() | |
1095 | { | |
1096 | delete block; | |
1097 | delete constraint; | |
1098 | } | |
1099 | ||
1100 | void UnparsedMultipleInnerTypeConstraint::chk() | |
1101 | { | |
1102 | if (checked) return; | |
1103 | checked = true; | |
1104 | if (!my_type) FATAL_ERROR("UnparsedMultipleInnerTypeConstraint::chk()"); | |
1105 | Error_Context cntxt(this, "While checking inner type constraint"); | |
1106 | Type* t = my_type->get_type_refd_last(); | |
1107 | switch (t->get_typetype()) { | |
1108 | case Type::T_REAL: // associated ASN.1 type is a SEQUENCE | |
1109 | case Type::T_CHOICE_A: | |
1110 | case Type::T_SEQ_A: // also refd by T_EXTERNAL, T_EMBEDDED_PDV and T_UNRESTRICTEDSTRING | |
1111 | case Type::T_SET_A: | |
1112 | break; | |
1113 | default: | |
1114 | error("Multiple inner type constraint (WITH COMPONENTS) cannot be used on type `%s'", my_type->get_typename().c_str()); | |
1115 | return; | |
1116 | } | |
1117 | Node *node = block->parse(KW_Block_MultipleTypeConstraints); | |
1118 | constraint = dynamic_cast<MultipleInnerTypeConstraint*>(node); | |
1119 | if (!constraint) { | |
1120 | delete node; | |
1121 | return; // parsing error was already reported | |
1122 | } | |
1123 | constraint->set_my_type(my_type); | |
1124 | constraint->set_my_scope(get_my_scope()); | |
1125 | constraint->set_my_parent(this); | |
1126 | constraint->chk(); | |
1127 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); // ignored | |
1128 | } | |
1129 | ||
1130 | void UnparsedMultipleInnerTypeConstraint::set_fullname(const string& p_fullname) | |
1131 | { | |
1132 | Node::set_fullname(p_fullname); | |
1133 | block->set_fullname(p_fullname); | |
1134 | if (constraint) constraint->set_fullname(p_fullname); | |
1135 | } | |
1136 | ||
1137 | } // namespace Common |