Titan Core Initial Contribution
[deliverable/titan.core.git] / xsdconvert / SimpleType.cc
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 "SimpleType.hh"
9
10 #include "GeneralFunctions.hh"
11
12 #include "TTCN3ModuleInventory.hh"
13 #include "TTCN3Module.hh"
14 #include "ComplexType.hh"
15 #include "FieldType.hh"
16
17
18 SimpleType::SimpleType(XMLParser * a_parser, TTCN3Module * a_module, ConstructType a_construct)
19 : RootType(a_parser, a_module, a_construct)
20 , builtInBase()
21 , length(this)
22 , pattern(this)
23 , enumeration(this)
24 , whitespace(this)
25 , value(this)
26 , element_form_as(notset)
27 , attribute_form_as(notset)
28 , mode(noMode)
29 , outside_reference()
30 , in_name_only(false)
31 {}
32
33 SimpleType::SimpleType(const SimpleType& other)
34 : RootType(other)
35 , builtInBase(other.builtInBase)
36 , length(other.length)
37 , pattern(other.pattern)
38 , enumeration(other.enumeration)
39 , whitespace(other.whitespace)
40 , value(other.value)
41 , element_form_as(other.element_form_as)
42 , attribute_form_as(other.attribute_form_as)
43 , mode(other.mode)
44 , outside_reference(other.outside_reference)
45 , in_name_only(other.in_name_only)
46 {
47 length.parent = this;
48 pattern.parent = this;
49 enumeration.parent = this;
50 whitespace.p_parent = this;
51 value.parent = this;
52 }
53
54 void SimpleType::loadWithValues()
55 {
56 const XMLParser::TagAttributes & atts = parser->getActualTagAttributes();
57
58 switch (parser->getActualTagName())
59 {
60 case XMLParser::n_restriction:
61 type.upload(atts.base);
62 setReference(atts.base);
63 mode = restrictionMode;
64 break;
65 case XMLParser::n_list:
66 type.upload(atts.itemType);
67 setReference(atts.itemType);
68 minOccurs = 0;
69 maxOccurs = ULLONG_MAX;
70 addVariant(V_list);
71 mode = listMode;
72 break;
73 case XMLParser::n_union: { // generating complextype from simpletype
74 ComplexType * new_complextype = new ComplexType(*this, ComplexType::fromTagUnion);
75 new_complextype->loadWithValues();
76 break; }
77 case XMLParser::n_element:
78 name.upload(atts.name);
79 type.upload(atts.type);
80 setReference(atts.type, true);
81 applyDefaultAttribute(atts.default_);
82 applyFixedAttribute(atts.fixed);
83 applyNillableAttribute(atts.nillable);
84 break;
85 case XMLParser::n_attribute:
86 name.upload(atts.name);
87 type.upload(atts.type);
88 setReference(atts.type, true);
89 applyDefaultAttribute(atts.default_);
90 applyFixedAttribute(atts.fixed);
91 break;
92 case XMLParser::n_simpleType:
93 name.upload(atts.name);
94 break;
95 case XMLParser::n_complexType: { // generating complextype from simpletype
96 ComplexType * new_complextype = new ComplexType(*this, ComplexType::fromTagComplexType);
97 new_complextype->loadWithValues();
98 break; }
99 case XMLParser::n_length:
100 if (mode == listMode) {
101 minOccurs = strtoull(atts.value.c_str(), NULL, 0);
102 maxOccurs = strtoull(atts.value.c_str(), NULL, 0);
103 break;
104 }
105 length.facet_minLength = strtoull(atts.value.c_str(), NULL, 0);
106 length.facet_maxLength = strtoull(atts.value.c_str(), NULL, 0);
107 length.modified = true;
108 break;
109 case XMLParser::n_minLength:
110 if (mode == listMode) {
111 minOccurs = strtoull(atts.value.c_str(), NULL, 0);
112 break;
113 }
114 length.facet_minLength = strtoull(atts.value.c_str(), NULL, 0);
115 length.modified = true;
116 break;
117 case XMLParser::n_maxLength:
118 if (mode == listMode) {
119 maxOccurs = strtoull(atts.value.c_str(), NULL, 0);
120 break;
121 }
122 length.facet_maxLength = strtoull(atts.value.c_str(), NULL, 0);
123 length.modified = true;
124 break;
125 case XMLParser::n_pattern:
126 pattern.facet = atts.value;
127 pattern.modified = true;
128 break;
129 case XMLParser::n_enumeration:
130 enumeration.facets.push_back(atts.value);
131 enumeration.modified = true;
132 break;
133 case XMLParser::n_whiteSpace:
134 whitespace.facet = atts.value;
135 whitespace.modified = true;
136 break;
137 case XMLParser::n_minInclusive:
138 if (atts.value == "NaN") {}
139 else if (atts.value == "-INF") {
140 value.facet_minInclusive = -DBL_MAX;
141 }
142 else if (atts.value == "INF") {
143 value.facet_minInclusive = DBL_MAX;
144 }
145 else {
146 value.facet_minInclusive = stringToLongDouble(atts.value.c_str());
147 }
148 value.modified = true;
149 break;
150 case XMLParser::n_maxInclusive:
151 if (atts.value == "NaN") {}
152 else if (atts.value == "-INF") {
153 value.facet_maxInclusive = -DBL_MAX;
154 }
155 else if (atts.value == "INF") {
156 value.facet_maxInclusive = DBL_MAX;
157 }
158 else {
159 value.facet_maxInclusive = stringToLongDouble(atts.value.c_str());
160 }
161 value.modified = true;
162 break;
163 case XMLParser::n_minExclusive:
164 if (atts.value == "NaN") {}
165 else if (atts.value == "-INF") {
166 value.facet_minExclusive = -DBL_MAX;
167 }
168 else if (atts.value == "INF") {
169 value.facet_minExclusive = DBL_MAX;
170 }
171 else {
172 value.facet_minExclusive = stringToLongDouble(atts.value.c_str());
173 }
174 value.modified = true;
175 value.lowerExclusive = true;
176 break;
177 case XMLParser::n_maxExclusive:
178 if (atts.value == "NaN") {}
179 else if (atts.value == "-INF") {
180 value.facet_maxExclusive = -DBL_MAX;
181 }
182 else if (atts.value == "INF") {
183 value.facet_maxExclusive = DBL_MAX;
184 }
185 else {
186 value.facet_maxExclusive = stringToLongDouble(atts.value.c_str());
187 }
188 value.modified = true;
189 value.upperExclusive = true;
190 break;
191 case XMLParser::n_totalDigits:
192 value.facet_totalDigits = strtoul(atts.value.c_str(), NULL, 0);
193 value.modified = true;
194 break;
195 case XMLParser::n_annotation:
196 case XMLParser::n_documentation:
197 break;
198 case XMLParser::n_label:
199 addComment(Mstring("LABEL:"));
200 break;
201 case XMLParser::n_definition:
202 addComment(Mstring("DEFINITION:"));
203 break;
204 default:
205 break;
206 }
207 }
208
209 void SimpleType::applyDefaultAttribute(const Mstring& default_value)
210 {
211 if (!default_value.empty()) {
212 value.default_value = default_value;
213 addVariant(V_defaultForEmpty, default_value);
214 }
215 }
216
217 void SimpleType::applyFixedAttribute(const Mstring& fixed_value)
218 {
219 if (!fixed_value.empty()) {
220 value.fixed_value = fixed_value;
221 addVariant(V_defaultForEmpty, fixed_value);
222 }
223 }
224
225 void SimpleType::applyNillableAttribute(bool nillable)
226 {
227 if (nillable)
228 {
229 ComplexType * new_complextype = new ComplexType(*this, ComplexType::fromTagNillable); // generating complextype from simpletype
230 new_complextype->loadWithValues();
231 }
232 }
233
234 void SimpleType::setReference(const Mstring& ref, bool only_name_dependency)
235 {
236 if (ref.empty()) {
237 return;
238 }
239 if (isBuiltInType(ref)) {
240 builtInBase = ref.getValueWithoutPrefix(':');
241 return;
242 }
243
244 Mstring refPrefix = ref.getPrefix(':');
245 Mstring refValue = ref.getValueWithoutPrefix(':');
246 Mstring refUri;
247 // Find the URI amongst the known namespace URIs
248 List<NamespaceType>::iterator declNS;
249 for (declNS = module->getDeclaredNamespaces().begin(); declNS; declNS = declNS->Next)
250 {
251 if (refPrefix == declNS->Data.prefix) {
252 refUri = declNS->Data.uri;
253 break;
254 }
255 }
256
257 // FIXME: can this part be moved above the search ?
258 if (refUri.empty()) { // not found
259 if (refPrefix == "xml") {
260 refUri = "http://www.w3.org/XML/1998/namespace";
261 }
262 else if (refPrefix == "xmlns") {
263 refUri = "http://www.w3.org/2000/xmlns";
264 }
265 else if (refPrefix.empty() && module->getTargetNamespace() == "NoTargetNamespace") {
266 refUri = "NoTargetNamespace";
267 }
268 }
269
270 if (refUri.empty()) { // something is incorrect - unable to find the uri to the given prefix
271 if (refPrefix.empty()) {
272 printError(module->getSchemaname(), parser->getActualLineNumber(),
273 Mstring("The absent namespace must be imported because "
274 "it is not the same as the target namespace of the current schema."));
275 parser->incrNumErrors();
276 return;
277 }
278 else {
279 printError(module->getSchemaname(), parser->getActualLineNumber(),
280 "The value \'" + ref + "\' is incorrect: "
281 "A namespace prefix does not denote any URI.");
282 parser->incrNumErrors();
283 return;
284 }
285 }
286
287 if (only_name_dependency) {
288 //name_dependency = refUri + "|" + refValue;
289 in_name_only = true;
290 }
291
292 //reference_for_other = refUri + "|" + refValue;
293 outside_reference.load(refUri, refValue, &declNS->Data);
294 }
295
296 void SimpleType::referenceResolving()
297 {
298 if (outside_reference.empty()) return;
299 if (outside_reference.is_resolved()) return;
300
301 SimpleType * found_ST = static_cast<SimpleType*>(
302 TTCN3ModuleInventory::getInstance().lookup(this, want_ST));
303 ComplexType * found_CT = static_cast<ComplexType*>(
304 TTCN3ModuleInventory::getInstance().lookup(this, want_CT));
305 // It _is_ possible to find both
306
307 if (found_ST != NULL) {
308 referenceForST(found_ST);
309 found_ST->addToNameDepList(this);
310 }
311 else if (found_CT != NULL) {
312 referenceForCT(found_CT);
313 found_CT->addToNameDepList(this);
314 }
315 else {
316 printError(module->getSchemaname(), name.convertedValue,
317 "Reference for a non-defined type: " + outside_reference.repr());
318 TTCN3ModuleInventory::getInstance().incrNumErrors();
319 outside_reference.set_resolved(NULL);
320 }
321 }
322
323 void SimpleType::referenceForST(SimpleType const * const found_ST)
324 {
325 outside_reference.set_resolved(found_ST);
326
327 if (in_name_only)
328 return;
329
330 if (construct == c_element)
331 return;
332
333 if (mode == listMode)
334 return;
335
336 builtInBase = found_ST->builtInBase;
337
338 length.applyReference(found_ST->length);
339 pattern.applyReference(found_ST->pattern);
340 enumeration.applyReference(found_ST->enumeration);
341 whitespace.applyReference(found_ST->whitespace);
342 value.applyReference(found_ST->value);
343
344 mode = found_ST->mode;
345 }
346
347 void SimpleType::referenceForCT(ComplexType const * const found_CT)
348 {
349 outside_reference.set_resolved(found_CT);
350
351 if (in_name_only)
352 return;
353
354 enumeration.modified = false;
355 for (List<Mstring>::iterator itemMisc = enumeration.items_misc.begin(); itemMisc; itemMisc = itemMisc->Next)
356 {
357 if (isdigit(itemMisc->Data[0]))
358 {
359 for (List<FieldType*>::iterator field = found_CT->getFields().begin(); field; field = field->Next)
360 {
361 if (isIntegerType(field->Data->getType().convertedValue))
362 {
363 expstring_t tmp_string = mprintf("{%s:=%d}",
364 field->Data->getName().convertedValue.c_str(), atoi(itemMisc->Data.c_str()));
365 value.items_with_value.push_back(Mstring(tmp_string));
366 }
367 else if (isFloatType(field->Data->getType().convertedValue))
368 {
369 expstring_t tmp_string = mprintf("{%s:=%f}",
370 field->Data->getName().convertedValue.c_str(), atof(itemMisc->Data.c_str()));
371 value.items_with_value.push_back(Mstring(tmp_string));
372 }
373 else if (isTimeType(field->Data->getType().convertedValue))
374 {
375 expstring_t tmp_string = mprintf("{%s;=%s}",
376 field->Data->getName().convertedValue.c_str(), itemMisc->Data.c_str());
377 value.items_with_value.push_back(Mstring(tmp_string));
378 }
379 }
380 }
381 else {
382 for (List<FieldType*>::iterator field = found_CT->getFields().begin(); field; field = field->Next)
383 {
384 if (isStringType(field->Data->getType().convertedValue))
385 {
386 expstring_t tmp_string = mprintf("{%s:=\"%s\"}",
387 field->Data->getName().convertedValue.c_str(), itemMisc->Data.c_str());
388 value.items_with_value.push_back(Mstring(tmp_string));
389 }
390 }
391 }
392 }
393 }
394
395
396 void SimpleType::nameConversion(NameConversionMode conversion_mode, const List<NamespaceType> & ns)
397 {
398 switch (conversion_mode)
399 {
400 case nameMode:
401 nameConversion_names();
402 break;
403 case typeMode:
404 nameConversion_types(ns);
405 break;
406 case fieldMode:
407 break;
408 }
409 }
410
411 void SimpleType::nameConversion_names()
412 {
413 Mstring res, var(module->getTargetNamespace());
414 XSDName2TTCN3Name(name.convertedValue, TTCN3ModuleInventory::getInstance().getTypenames(), type_name, res, var);
415 name.convertedValue = res;
416 addVariant(V_onlyValue, var);
417 for (List<SimpleType*>::iterator st = nameDepList.begin(); st; st = st->Next) {
418 st->Data->setTypeValue(res);
419 }
420 }
421
422 void SimpleType::nameConversion_types(const List<NamespaceType> & ns)
423 {
424 if (type.convertedValue == "record" || type.convertedValue == "set"
425 ||type.convertedValue == "union" || type.convertedValue == "enumerated") return;
426
427 Mstring prefix = type.convertedValue.getPrefix(':');
428 Mstring value_str = type.convertedValue.getValueWithoutPrefix(':');
429
430 Mstring uri;
431 for (List<NamespaceType>::iterator namesp = ns.begin(); namesp; namesp = namesp->Next)
432 {
433 if (prefix == namesp->Data.prefix) {
434 uri = namesp->Data.uri;
435 break;
436 }
437 }
438
439 QualifiedName tmp(uri, value_str);
440
441 QualifiedNames::iterator origTN = TTCN3ModuleInventory::getInstance().getTypenames().begin();
442 for ( ; origTN; origTN = origTN->Next)
443 {
444 if (tmp == origTN->Data) {
445 QualifiedName tmp_name(module->getTargetNamespace(), name.convertedValue);
446 if (tmp_name == origTN->Data)
447 continue; // get a new type name
448 else
449 break;
450 }
451 }
452 if (origTN != NULL) {
453 setTypeValue(origTN->Data.name);
454 // This ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ is always value_str
455 // The only effect here is to remove the "xs:" prefix from type.convertedValue,
456 // otherwise the new value is always the same as the old.
457 }
458 else {
459 Mstring res, var;
460 XSDName2TTCN3Name(value_str, TTCN3ModuleInventory::getInstance().getTypenames(), type_reference_name, res, var);
461 setTypeValue(res);
462 }
463 }
464
465 void SimpleType::finalModification()
466 {
467 value.applyFacets();
468 length.applyFacets();
469 pattern.applyFacet();
470 whitespace.applyFacet();
471 enumeration.applyFacets();
472
473 if (module->getElementFormDefault() == qualified &&
474 element_form_as == unqualified) {
475 addVariant(V_formAs, Mstring("unqualified"));
476 }
477 if (module->getAttributeFormDefault() == qualified &&
478 attribute_form_as == unqualified) {
479 addVariant(V_formAs, Mstring("unqualified"));
480 }
481 }
482
483 bool SimpleType::hasUnresolvedReference()
484 {
485 if (!outside_reference.empty() && !outside_reference.is_resolved())
486 return true;
487 else
488 return false;
489 }
490
491
492 void SimpleType::printToFile(FILE * file)
493 {
494 if (!visible) return;
495
496 printComment(file);
497
498 fputs("type ", file);
499 if (enumeration.modified) {
500 if (isFloatType(builtInBase)) {
501 fprintf(file, "%s %s (", type.convertedValue.c_str(), name.convertedValue.c_str());
502 enumeration.sortFacets();
503 enumeration.printToFile(file);
504 fputc(')', file);
505 }
506 else {
507 fprintf(file, "enumerated %s\n{\n", name.convertedValue.c_str());
508 enumeration.sortFacets();
509 enumeration.printToFile(file);
510 fputs("\n}", file);
511 }
512 }
513 else {
514 printMinOccursMaxOccurs(file, false);
515
516 int multiplicity = multi(module, outside_reference, this);
517 const RootType *type_ref = outside_reference.get_ref();
518 if ((multiplicity > 1) && type_ref
519 && type_ref->getModule() != module) {
520 fprintf(file, "%s.", type_ref->getModule()->getModulename().c_str());
521 }
522
523 fprintf(file, "%s %s",
524 type.convertedValue.c_str(), name.convertedValue.c_str());
525 pattern.printToFile(file);
526 value.printToFile(file);
527 length.printToFile(file);
528 }
529 printVariant(file);
530 fputs(";\n\n\n", file);
531 }
532
533 void SimpleType::dump(unsigned int depth) const
534 {
535 static const char *modes[] = {
536 "", "restriction", "extension", "list"
537 };
538 fprintf(stderr, "%*s SimpleType '%s' -> '%s' at %p\n", depth * 2, "",
539 name.originalValueWoPrefix.c_str(), name.convertedValue.c_str(),
540 (const void*)this);
541 fprintf(stderr, "%*s type '%s' -> '%s'\n", depth * 2, "",
542 type.originalValueWoPrefix.c_str(), type.convertedValue.c_str());
543
544 if (mode != noMode) {
545 fprintf(stderr, "%*s %s, base='%s'\n", depth * 2, "", modes[mode], builtInBase.c_str());
546 }
547
548 // fprintf (stderr, "%*s rfo='%s' n_d='%s'\n", depth * 2, "",
549 // reference_for_other.c_str(), name_dependency.c_str());
550 }
551
552 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
553
554 LengthType::LengthType(SimpleType * a_simpleType)
555 : parent(a_simpleType)
556 , modified(false)
557 , facet_minLength(0)
558 , facet_maxLength(ULLONG_MAX)
559 , lower(0)
560 , upper(ULLONG_MAX)
561 {}
562
563 void LengthType::applyReference(const LengthType & other)
564 {
565 if (!modified) modified = other.modified;
566 if (other.facet_minLength > facet_minLength) facet_minLength = other.facet_minLength;
567 if (other.facet_maxLength < facet_maxLength) facet_maxLength = other.facet_maxLength;
568 }
569
570 void LengthType::applyFacets() // only for string types and list types without QName
571 {
572 if (!modified) return;
573
574 switch (parent->getMode())
575 {
576 case SimpleType::restrictionMode: {
577 const Mstring & base = parent->getBuiltInBase();
578 if ((isStringType(base) || (isSequenceType(base) && base != "QName") || isAnyType(base)) || base.empty() )
579 {
580 lower = facet_minLength;
581 upper = facet_maxLength;
582 }
583 else
584 {
585 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
586 Mstring("Length restriction is not supported on type '") + base + Mstring("'."));
587 TTCN3ModuleInventory::getInstance().incrNumWarnings();
588 }
589 break; }
590 case SimpleType::extensionMode:
591 break;
592 case SimpleType::listMode:
593 lower = facet_minLength;
594 upper = facet_maxLength;
595 break;
596 case SimpleType::noMode:
597 break;
598 }
599 if (lower > upper) {
600 printError(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
601 Mstring("The upper boundary of length restriction cannot be smaller than the lower boundary."));
602 TTCN3ModuleInventory::getInstance().incrNumErrors();
603 return;
604 }
605 }
606
607 void LengthType::printToFile(FILE * file) const
608 {
609 if (!modified) return;
610 if (parent->getEnumeration().modified) return;
611
612 if (lower == upper)
613 {
614 fprintf(file, " length(%llu)", lower);
615 }
616 else
617 {
618 fprintf(file, " length(%llu .. ", lower);
619
620 if (upper == ULLONG_MAX)
621 {
622 fputs("infinity", file);
623 }
624 else
625 {
626 fprintf(file, "%llu", upper);
627 }
628
629 fputc(')', file);
630 }
631 }
632
633 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
634
635 PatternType::PatternType(SimpleType * a_simpleType)
636 : parent(a_simpleType)
637 , modified(false)
638 , facet()
639 , value()
640 {}
641
642 void PatternType::applyReference(const PatternType & other)
643 {
644 if (!modified) modified = other.modified;
645 if (facet.empty()) facet = other.facet;
646 }
647
648 void PatternType::applyFacet() // only for time types and string types without hexBinary
649 {
650 if (!modified) return;
651
652 const Mstring & base = parent->getBuiltInBase();
653 if (((isStringType(base) && base != "hexBinary") || isTimeType(base) || isAnyType(base)) || base.empty())
654 {
655 // XSD pattern to TTCN-3 pattern; ETSI ES 201 873-9 clause 6.1.4
656 // FIXME a proper scanner is needed, e.g. from flex
657 int charclass = 0;
658 for (size_t i = 0; i != facet.size(); ++i)
659 {
660 char c = facet[i];
661 switch (c) {
662 case '(': case ')': case '/': case '^':
663 value += c;
664 break;
665 case '[':
666 value += c;
667 ++charclass;
668 break;
669 case ']':
670 value += c;
671 --charclass;
672 break;
673 case '.': // any character
674 value += '?';
675 break;
676 case '*': // 0 or more
677 value += '*'; //#(0,)
678 break;
679 case '+':
680 value += '+'; //#(1,)
681 break;
682 case '?':
683 value += "#(0,1)";
684 break;
685 case '"':
686 value += "\"\"";
687 case '{': {
688 Mstring s;
689 int k = 1;
690 while (facet[i + k] != '}') {
691 s += facet[i + k];
692 ++k;
693 }
694 if (s.isFound(',')) {
695 value += "#(";
696 value += s;
697 value += ')';
698 }
699 else {
700 value += '#';
701 value += s;
702 }
703 i = i + k;
704 break; }
705 case '\\': {
706 // Appendix G1.1 of XML Schema Datatypes: Character class escapes;
707 // specifically, http://www.w3.org/TR/xmlschema11-2/#nt-MultiCharEsc
708 char cn = facet[i+1];
709 switch (cn) {
710 case 'c':
711 value += charclass ? "\\w\\d.\\-_:"
712 : "[\\w\\d.\\-_:]";
713 break;
714 case 'C':
715 value += charclass ? "^\\w\\d.\\-_:"
716 : "[^\\w\\d.\\-_:]";
717 break;
718 case 'D':
719 value += charclass ? "^\\d"
720 : "[^\\d]";
721 break;
722 case 'i':
723 value += charclass ? "\\w\\d:"
724 : "[\\w\\d:]";
725 break;
726 case 'I':
727 value += charclass ? "^\\w\\d:"
728 : "[^\\w\\d:]";
729 break;
730 case 's':
731 value += charclass ? "\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r"
732 : "[\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r]";
733 break;
734 case 'S':
735 value += charclass ? "^\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r"
736 : "[^\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r]";
737 break;
738 case 'W':
739 value += charclass ? "^\\w"
740 : "[^\\w]";
741 break;
742 case 'p':
743 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
744 Mstring("Character categories and blocks are not supported."));
745 TTCN3ModuleInventory::getInstance().incrNumWarnings();
746 parent->addComment(
747 Mstring("Pattern is not converted due to using character categories and blocks in patterns is not supported."));
748 value.clear();
749 return;
750
751 case '.':
752 value += '.';
753 break;
754 default:
755 // backslash + another: pass unmodified; this also handles \d and \w
756 value += c;
757 value += cn;
758 break;
759 }
760 ++i;
761 break; }
762 case '&':
763 if (facet[i + 1] == '#') { // &#....;
764 Mstring s;
765 int k = 2;
766 while (facet[i + k] != ';') {
767 s += facet[i + k];
768 ++k;
769 }
770 long long int d = atoll(s.c_str());
771 if (d < 0 || d > 2147483647) {
772 printError(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
773 Mstring("Invalid unicode character."));
774 TTCN3ModuleInventory::getInstance().incrNumErrors();
775 }
776 unsigned char group = (d >> 24) & 0xFF;
777 unsigned char plane = (d >> 16) & 0xFF;
778 unsigned char row = (d >> 8) & 0xFF;
779 unsigned char cell = d & 0xFF;
780
781 expstring_t res = mprintf("\\q{%d, %d, %d, %d}", group, plane, row, cell);
782 value += res;
783 Free(res);
784 i = i + k;
785 }
786 // else fall through
787 default: //just_copy:
788 value += c;
789 break;
790 } // switch(c)
791 } // next i
792 }
793 else
794 {
795 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
796 Mstring("Pattern restriction is not supported on type '") + base + Mstring("'."));
797 TTCN3ModuleInventory::getInstance().incrNumWarnings();
798 }
799 }
800
801 void PatternType::printToFile(FILE * file) const
802 {
803 if (!modified || value.empty()) return;
804 if (parent->getEnumeration().modified) return;
805
806 fprintf(file, " (pattern \"%s\")", value.c_str());
807 }
808
809 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
810
811 EnumerationType::EnumerationType(SimpleType * a_simpleType)
812 : parent(a_simpleType)
813 , modified(false)
814 , facets()
815 , items_string()
816 , items_int()
817 , items_float()
818 , items_time()
819 , items_misc()
820 {}
821
822 void EnumerationType::applyReference(const EnumerationType & other)
823 {
824 if (!modified) modified = other.modified;
825 for (List<Mstring>::iterator facet = other.facets.begin(); facet; facet = facet->Next)
826 {
827 facets.push_back(facet->Data);
828 }
829 }
830
831 void EnumerationType::applyFacets() // string types, integer types, float types, time types
832 {
833 if (!modified) return;
834
835 const Mstring & base = parent->getBuiltInBase();
836
837 if (isStringType(base)) // here length restriction is applicable
838 {
839 List<Mstring> text_variants;
840 for (List<Mstring>::iterator facet = facets.begin(); facet; facet = facet->Next)
841 {
842 const LengthType & length = parent->getLength();
843 if (length.lower <= facet->Data.size() && facet->Data.size() <= length.upper)
844 {
845 Mstring res, var;
846 XSDName2TTCN3Name(facet->Data, items_string, enum_id_name, res, var);
847 text_variants.push_back(var);
848 }
849 }
850 text_variants.sort();
851 for (List<Mstring>::iterator var = text_variants.end(); var; var = var->Prev) {
852 parent->addVariant(V_onlyValue, var->Data);
853 }
854 }
855 else if (isIntegerType(base)) // here value restriction is applicable
856 {
857 for (List<Mstring>::iterator facet = facets.begin(); facet; facet = facet->Next)
858 {
859 int int_value = atoi(facet->Data.c_str());
860 const ValueType & value = parent->getValue();
861 if (value.lower <= int_value && int_value <= value.upper)
862 {
863 bool found = false;
864 for (List<int>::iterator itemInt = items_int.begin(); itemInt; itemInt = itemInt->Next)
865 {
866 if (int_value == itemInt->Data) {
867 found = true;
868 break;
869 }
870 }
871 if (!found) items_int.push_back(int_value);
872
873 if (parent->getVariant().empty() || parent->getVariant().back() != "\"useNumber\"") {
874 parent->addVariant(V_useNumber);
875 }
876 }
877 }
878 }
879 else if (isFloatType(base)) // here value restriction is applicable
880 {
881 for (List<Mstring>::iterator facet = facets.begin(); facet; facet = facet->Next)
882 {
883 double float_value = atof(facet->Data.c_str());
884 const ValueType & value = parent->getValue();
885 if (value.lower <= float_value && float_value <= value.upper)
886 {
887 bool found = false;
888 for (List<double>::iterator itemFloat = items_float.begin(); itemFloat; itemFloat = itemFloat->Next)
889 {
890 if (float_value == itemFloat->Data) {
891 found = true;
892 break;
893 }
894 }
895 if (!found) {
896 items_float.push_back(float_value);
897
898 }
899 }
900 }
901 }
902 else if (isTimeType(base))
903 {
904 List<Mstring> text_variants;
905 for (List<Mstring>::iterator facet = facets.begin(); facet; facet = facet->Next)
906 {
907 Mstring res, var;
908 XSDName2TTCN3Name(facet->Data, items_time, enum_id_name, res, var);
909 text_variants.push_back(var);
910 }
911 text_variants.sort();
912 for (List<Mstring>::iterator var = text_variants.end(); var; var = var->Prev) {
913 parent->addVariant(V_onlyValue, var->Data);
914 }
915 }
916 else if (isAnyType(base))
917 {}
918 else if (base.empty())
919 {}
920 else
921 {
922 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
923 Mstring("Enumeration restriction is not supported on type '") + base + Mstring("'."));
924 TTCN3ModuleInventory::getInstance().incrNumWarnings();
925 parent->setInvisible();
926 }
927 }
928
929 void EnumerationType::sortFacets()
930 {
931 items_string.sort();
932 items_int.sort();
933 items_float.sort();
934 items_time.sort();
935 }
936
937 void EnumerationType::printToFile(FILE * file, unsigned int indent_level) const
938 {
939 if (!modified) return;
940
941 const Mstring & base = parent->getBuiltInBase();
942 if (isStringType(base))
943 {
944 for (QualifiedNames::iterator itemString = items_string.begin(); itemString; itemString = itemString->Next)
945 {
946 if (itemString != items_string.begin()) fputs(",\n", file);
947 for (unsigned int l = 0; l != indent_level; ++l) fputs("\t", file);
948 fprintf(file, "\t%s", itemString->Data.name.c_str());
949 }
950 }
951 else if (isIntegerType(base))
952 {
953 for (List<int>::iterator itemInt = items_int.begin(); itemInt; itemInt = itemInt->Next)
954 {
955 if (itemInt != items_int.begin()) fputs(",\n", file);
956 for (unsigned int l = 0; l != indent_level; ++l) fputs("\t", file);
957 if (itemInt->Data < 0) {
958 fprintf(file, "\tint_%d(%d)", abs(itemInt->Data), itemInt->Data);
959 }
960 else {
961 fprintf(file, "\tint%d(%d)", itemInt->Data, itemInt->Data);
962 }
963 }
964 }
965 else if (isFloatType(base))
966 {
967 for (List<double>::iterator itemFloat = items_float.begin(); itemFloat; itemFloat = itemFloat->Next)
968 {
969 if (itemFloat != items_float.begin()) fputs(", ", file);
970
971 double intpart = 0;
972 double fracpart = 0;
973 fracpart = modf(itemFloat->Data, &intpart);
974 if (fracpart == 0) {
975 fprintf(file, "%lld.0", (long long int)(itemFloat->Data));
976 }
977 else {
978 fprintf(file, "%g", itemFloat->Data);
979 }
980 }
981 }
982 else if (isTimeType(base))
983 {
984 for (QualifiedNames::iterator itemTime = items_time.begin(); itemTime; itemTime = itemTime->Next)
985 {
986 if (itemTime != items_time.begin()) fputs(",\n", file);
987 for (unsigned int l = 0; l != indent_level; ++l) fputs("\t", file);
988 fprintf(file, "\t%s", itemTime->Data.name.c_str());
989 }
990 }
991 }
992
993 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
994
995 WhitespaceType::WhitespaceType(SimpleType * a_simpleType)
996 : p_parent(a_simpleType)
997 , modified(false)
998 , facet()
999 , value()
1000 {}
1001
1002 void WhitespaceType::applyReference(const WhitespaceType & other)
1003 {
1004 if (!modified) modified = other.modified;
1005 if (facet.empty()) facet = other.facet;
1006 }
1007
1008 void WhitespaceType::applyFacet() // only for string types: string, normalizedString, token, Name, NCName, language
1009 {
1010 if (!modified) return;
1011
1012 const Mstring & base = p_parent->getBuiltInBase();
1013 if (base == "string" || base == "normalizedString" || base == "token" || base == "language" ||
1014 base == "Name" || base == "NCName" || isAnyType(base) || base.empty())
1015 {
1016 p_parent->addVariant(V_whiteSpace, facet);
1017 }
1018 else
1019 {
1020 printWarning(p_parent->getModule()->getSchemaname(), p_parent->getName().convertedValue,
1021 Mstring("Facet 'whiteSpace' is not applicable for type '") + base + Mstring("'."));
1022 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1023 }
1024 }
1025
1026 ValueType::ValueType(SimpleType * a_simpleType)
1027 : parent(a_simpleType)
1028 , modified(false)
1029 , facet_minInclusive(-DBL_MAX)
1030 , facet_maxInclusive(DBL_MAX)
1031 , facet_minExclusive(-DBL_MAX)
1032 , facet_maxExclusive(DBL_MAX)
1033 , facet_totalDigits(0)
1034 , lower(-DBL_MAX)
1035 , upper(DBL_MAX)
1036 , lowerExclusive(false)
1037 , upperExclusive(false)
1038 , fixed_value()
1039 , default_value()
1040 , items_with_value()
1041 {}
1042
1043 void ValueType::applyReference(const ValueType & other)
1044 {
1045 if (!modified) modified = other.modified;
1046 if (other.facet_minInclusive > facet_minInclusive) facet_minInclusive = other.facet_minInclusive;
1047 if (other.facet_maxInclusive < facet_maxInclusive) facet_maxInclusive = other.facet_maxInclusive;
1048 if (other.facet_minExclusive > facet_minExclusive) facet_minExclusive = other.facet_minExclusive;
1049 if (other.facet_maxExclusive < facet_maxExclusive) facet_maxExclusive = other.facet_maxExclusive;
1050 if (other.facet_totalDigits < facet_totalDigits) facet_totalDigits = other.facet_totalDigits;
1051 }
1052
1053 void ValueType::applyFacets() // only for integer and float types
1054 {
1055 if (!modified) return;
1056
1057 const Mstring & base = parent->getBuiltInBase();
1058 /*
1059 * Setting of default value range of built-in types
1060 */
1061 if (base == "positiveInteger")
1062 {
1063 lower = 1;
1064 }
1065 else if (base == "nonPositiveInteger")
1066 {
1067 upper = 0;
1068 }
1069 else if (base == "negativeInteger")
1070 {
1071 upper = -1;
1072 }
1073 else if (base == "nonNegativeInteger")
1074 {
1075 lower = 0;
1076 }
1077 else if (base == "unsignedLong")
1078 {
1079 lower = 0;
1080 upper = ULLONG_MAX;
1081 }
1082 else if (base == "int")
1083 {
1084 lower = INT_MIN;
1085 upper = INT_MAX;
1086 }
1087 else if (base == "unsignedInt")
1088 {
1089 lower = 0;
1090 upper = UINT_MAX;
1091 }
1092 else if (base == "short")
1093 {
1094 lower = SHRT_MIN;
1095 upper = SHRT_MAX;
1096 }
1097 else if (base == "unsignedShort")
1098 {
1099 lower = 0;
1100 upper = USHRT_MAX;
1101 }
1102 else if (base == "byte")
1103 {
1104 lower = CHAR_MIN;
1105 upper = CHAR_MAX;
1106 }
1107 else if (base == "unsignedByte")
1108 {
1109 lower = 0;
1110 upper = UCHAR_MAX;
1111 }
1112
1113 if (isIntegerType(base))
1114 {
1115 if (facet_minInclusive != -DBL_MAX && facet_minInclusive > lower) lower = facet_minInclusive;
1116 if (facet_maxInclusive != DBL_MAX && upper > facet_maxInclusive) upper = facet_maxInclusive;
1117 if (facet_minExclusive != -DBL_MAX && lower < facet_minExclusive) lower = facet_minExclusive;
1118 if (facet_maxExclusive != DBL_MAX && upper > facet_maxExclusive) upper = facet_maxExclusive;
1119 }
1120 else if (isFloatType(base))
1121 {
1122 if (facet_minInclusive != -DBL_MAX && lower < facet_minInclusive) lower = facet_minInclusive;
1123 if (facet_maxInclusive != DBL_MAX && upper > facet_maxInclusive) upper = facet_maxInclusive;
1124 if (facet_minExclusive != -DBL_MAX && lower < facet_minExclusive) lower = facet_minExclusive;
1125 if (facet_maxExclusive != DBL_MAX && upper > facet_maxExclusive) upper = facet_maxExclusive;
1126 }
1127 else if (isAnyType(base))
1128 {}
1129 else if (base.empty())
1130 {}
1131 else
1132 {
1133 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
1134 Mstring("Value restriction is not supported on type '") + base + Mstring("'."));
1135 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1136 }
1137
1138 // totalDigits facet is only for integer types and decimal
1139 if (facet_totalDigits != 0) // if this facet is used
1140 {
1141 double r = pow(10.0, facet_totalDigits);
1142
1143 if (base == "integer")
1144 {
1145 lower = (int) -(r-1);
1146 upper = (int) (r-1);
1147 }
1148 else if (base == "positiveInteger")
1149 {
1150 lower = 1;
1151 upper = (int) (r-1);
1152 }
1153 else if (base == "nonPositiveInteger")
1154 {
1155 lower = (int) -(r-1);
1156 upper = 0;
1157 }
1158 else if (base == "negativeInteger")
1159 {
1160 lower = (int) -(r-1);
1161 upper = -1;
1162 }
1163 else if (base == "nonNegativeInteger")
1164 {
1165 lower = 0;
1166 upper = (int) (r-1);
1167 }
1168 else if (base == "long" ||
1169 base == "unsignedLong" ||
1170 base == "int" ||
1171 base == "unsignedInt" ||
1172 base == "short" ||
1173 base == "unsignedShort" ||
1174 base == "byte" ||
1175 base == "unsignedByte")
1176 {
1177 lower = (int) -(r-1);
1178 upper = (int) (r-1);
1179 }
1180 else if (base == "decimal")
1181 {
1182 lower = (int) -(r-1);
1183 upper = (int) (r-1);
1184 }
1185 else {
1186 printWarning(parent->getModule()->getSchemaname(), parent->getName().convertedValue,
1187 Mstring("Facet 'totalDigits' is not applicable for type '") + base + Mstring("'."));
1188 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1189 }
1190 }
1191 }
1192
1193 void ValueType::printToFile(FILE * file) const
1194 {
1195 if (!modified) return;
1196 if (parent->getEnumeration().modified) return;
1197
1198 if (!fixed_value.empty())
1199 {
1200 fprintf(file, " (\"%s\")", fixed_value.c_str());
1201 return;
1202 }
1203 if (!items_with_value.empty())
1204 {
1205 fputs(" (", file);
1206 for (List<Mstring>::iterator itemWithValue = items_with_value.begin(); itemWithValue; itemWithValue = itemWithValue->Next)
1207 {
1208 if (itemWithValue != items_with_value.begin()) fputs(", ", file);
1209 fprintf(file, "%s", itemWithValue->Data.c_str());
1210 }
1211 fputc(')', file);
1212 return;
1213 }
1214
1215 if (lower == -DBL_MAX && upper == DBL_MAX) return;
1216
1217 fputs(" (", file);
1218
1219 if (isIntegerType(parent->getBuiltInBase()))
1220 {
1221 if (lowerExclusive) {
1222 fputc('!', file);
1223 }
1224
1225 if (lower == -DBL_MAX)
1226 {
1227 fputs("-infinity", file);
1228 }
1229 else if (lower < 0)
1230 {
1231 long double temp_lower = -lower;
1232 fprintf(file, "-%.0Lf", temp_lower);
1233 }
1234 else
1235 {
1236 fprintf(file, "%.0Lf", lower);
1237 }
1238
1239 fputs(" .. ", file);
1240 if (upperExclusive) {
1241 fputc('!', file);
1242 }
1243
1244 if (upper == DBL_MAX)
1245 {
1246 fputs("infinity", file);
1247 }
1248 else if (upper < 0)
1249 {
1250 long double temp_upper = -upper;
1251 fprintf(file, "-%.0Lf", temp_upper);
1252 }
1253 else
1254 {
1255 fprintf(file, "%.0Lf", upper);
1256 }
1257 }
1258 else if (isFloatType(parent->getBuiltInBase()))
1259 {
1260 if (lowerExclusive) {
1261 fputc('!', file);
1262 }
1263
1264 if (lower == -DBL_MAX)
1265 {
1266 fputs("-infinity", file);
1267 }
1268 else
1269 {
1270 double intpart = 0;
1271 double fracpart = 0;
1272 fracpart = modf(lower, &intpart);
1273 if (fracpart == 0) {
1274 fprintf(file, "%.1Lf", lower);
1275 }
1276 else {
1277 fprintf(file, "%Lg", lower);
1278 }
1279 }
1280
1281 fputs(" .. ", file);
1282 if (upperExclusive) {
1283 fputc('!', file);
1284 }
1285
1286 if (upper == DBL_MAX)
1287 {
1288 fputs("infinity", file);
1289 }
1290 else
1291 {
1292 double intpart = 0;
1293 double fracpart = 0;
1294 fracpart = modf(upper, &intpart);
1295 if (fracpart == 0) {
1296 fprintf(file, "%.1Lf", upper);
1297 }
1298 else {
1299 fprintf(file, "%Lg", upper);
1300 }
1301 }
1302 }
1303
1304 fputc(')', file);
1305 }
This page took 0.09204 seconds and 5 git commands to generate.