Commit 3abe9331 authored by Elemer Lelik's avatar Elemer Lelik
Browse files

Sync with 5.4.0

parent f99e8b7f
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......@@ -1591,6 +1591,10 @@ namespace Common {
Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
switch (ref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF: {
if (t->typetype == T_OPENTYPE) {
// allow the alternatives of open types as both lower and upper identifiers
ref->set_field_name_to_lowercase();
}
const Identifier& id = *ref->get_id();
switch (t->typetype) {
case T_CHOICE_A:
......@@ -2006,7 +2010,7 @@ namespace Common {
}
break;
case T_SEQ_T:
case T_SET_T:
case T_SET_T: {
if(rawattrib){
size_t fieldnum;
for(int c=0;c<rawattrib->taglist.nElements;c++) { // check TAG
......@@ -2175,6 +2179,7 @@ namespace Common {
}
}
}
int used_bits = 0; // number of bits used to store all previous fields
for(size_t i = 0; i < get_nof_comps(); i++) { // field attributes
CompField *cf = get_comp_byIndex(i);
const Identifier& field_id = cf->get_name();
......@@ -2183,6 +2188,27 @@ namespace Common {
field_type->force_raw();
RawAST *rawpar = field_type->rawattrib;
if (rawpar) {
if (rawpar->prepadding != 0) {
used_bits = (used_bits + rawpar->prepadding - 1) / rawpar->prepadding *
rawpar->prepadding;
}
if (rawpar->intx && field_type_last->get_typetype() == T_INT) { // IntX
if (used_bits % 8 != 0 &&
(!rawattrib || rawattrib->fieldorder != XDEFMSB)) {
error("Using RAW parameter IntX in a record/set with FIELDORDER "
"set to 'lsb' is only supported if the IntX field starts at "
"the beginning of a new octet. There are %d unused bits in the "
"last octet before field %s.", 8 - (used_bits % 8),
field_id.get_dispname().c_str());
}
}
else {
used_bits += rawpar->fieldlength;
}
if (rawpar->padding != 0) {
used_bits = (used_bits + rawpar->padding - 1) / rawpar->padding *
rawpar->padding;
}
for (int j = 0; j < rawpar->lengthto_num; j++) { // LENGTHTO
Identifier *idf = rawpar->lengthto[j];
if (!has_comp_withName(*idf)) {
......@@ -2400,7 +2426,7 @@ namespace Common {
}
}
}
break;
break; }
case T_BSTR:
if(rawattrib->fieldlength==0 && rawattrib->length_restrition!=-1){
rawattrib->fieldlength=rawattrib->length_restrition;
......@@ -2447,8 +2473,14 @@ namespace Common {
"(64)", rawattrib->fieldlength, get_fullname().c_str());
}
break;
case T_ENUM_T:
case T_INT:
if (rawattrib->intx) {
rawattrib->bitorderinfield = XDEFMSB;
rawattrib->bitorderinoctet = XDEFMSB;
rawattrib->byteorder = XDEFMSB;
}
break;
case T_ENUM_T:
case T_BOOL:
default:
// nothing to do, ASN1 types or types without defined raw attribute
......@@ -2617,6 +2649,17 @@ namespace Common {
chk_text();
}
static const char* JSON_SCHEMA_KEYWORDS[] = {
// built-in JSON schema keywords
"$ref", "type", "properties", "items", "anyOf", "enum", "pattern",
"default", "minItems", "maxItems", "additionalProperties", "fieldOrder",
"required", "$schema", "minLength", "maxLength", "minimum", "maximum",
"excludeMinimum", "excludeMaximum", "allOf"
// TITAN-specific keywords
"originalName", "unusedAlias", "subType", "numericValues", "omitAsNull",
"encoding", "decoding"
};
void Type::chk_json()
{
if (json_checked) return;
......@@ -2637,6 +2680,7 @@ namespace Common {
break; }
case T_SEQOF:
case T_SETOF:
case T_ARRAY:
get_ofType()->force_json();
break;
default:
......@@ -2671,6 +2715,71 @@ namespace Common {
if (NULL != jsonattrib->default_value) {
chk_json_default();
}
const size_t nof_extensions = jsonattrib->schema_extensions.size();
if (0 != nof_extensions) {
const size_t nof_keywords = sizeof(JSON_SCHEMA_KEYWORDS) / sizeof(char*);
// these keep track of erroneous extensions so each warning is only
// displayed once
char* checked_extensions = new char[nof_extensions];
char* checked_keywords = new char[nof_keywords];
memset(checked_extensions, 0, nof_extensions);
memset(checked_keywords, 0, nof_keywords);
for (size_t i = 0; i < nof_extensions; ++i) {
for (size_t j = 0; j < nof_keywords; ++j) {
if (0 == checked_extensions[i] && 0 == checked_keywords[j] &&
0 == strcmp(jsonattrib->schema_extensions[i]->key,
JSON_SCHEMA_KEYWORDS[j])) {
// only report the warning once for each keyword
warning("JSON schema keyword '%s' should not be used as the key of "
"attribute 'extend'", JSON_SCHEMA_KEYWORDS[j]);
checked_keywords[j] = 1;
checked_extensions[i] = 1;
break;
}
}
if (0 == checked_extensions[i]) {
for (size_t k = i + 1; k < nof_extensions; ++k) {
if (0 == strcmp(jsonattrib->schema_extensions[i]->key,
jsonattrib->schema_extensions[k]->key)) {
if (0 == checked_extensions[i]) {
// only report the warning once for each unique key
warning("Key '%s' is used multiple times in 'extend' attributes "
"of type '%s'", jsonattrib->schema_extensions[i]->key,
get_typename().c_str());
checked_extensions[i] = 1;
}
checked_extensions[k] = 1;
}
}
}
}
delete[] checked_extensions;
delete[] checked_keywords;
}
if (jsonattrib->metainfo_unbound) {
Type* parent = get_parent_type();
if (T_SEQ_T == get_type_refd_last()->typetype ||
T_SET_T == get_type_refd_last()->typetype) {
// if it's set for the record/set, pass it onto its fields
size_t nof_comps = get_nof_comps();
for (size_t i = 0; i < nof_comps; i++) {
Type* comp_type = get_comp_byIndex(i)->get_type();
if (NULL == comp_type->jsonattrib) {
comp_type->jsonattrib = new JsonAST;
}
comp_type->jsonattrib->metainfo_unbound = true;
}
}
else if (NULL == parent || (T_SEQ_T != parent->typetype &&
T_SET_T != parent->typetype)) {
// only allowed if it's a field of a record/set
error("Invalid attribute 'metainfo for unbound', requires record, set, "
"or field of a record or set");
}
}
}
}
......@@ -5258,9 +5367,6 @@ end_ext:
const string& spec = s.get_attribSpec().get_spec();
if (spec == get_encoding_name(encoding_type)) {
return true;
} else {
// if it has an encode other than the one we're looking for, quit now
return false;
}
} // if ENCODE
} // for
......@@ -5512,8 +5618,6 @@ end_ext:
if (spec == ex_emm_ell // the right answer
||spec == ex_ee_arr) // the acceptable answer
return memory.remember(t, ANSWER_YES);
else // if it has an encode other than XER, quit now
return memory.remember(t, ANSWER_NO);
} // if ENCODE
} // for
} // next a
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......@@ -1169,6 +1169,8 @@ namespace Common {
/** Generates a reference to this type's schema segment and inserts it into
* the given schema. */
void generate_json_schema_ref(JSON_Tokenizer& json);
JsonAST* get_json_attributes() const { return jsonattrib; }
};
/** @} end of AST_Type group */
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......@@ -1522,7 +1522,7 @@ void Type::chk_xer_untagged()
// found the component
if (cf->get_is_optional() || cf->get_defval() != 0) {
error("Type with final encoding attribute UNTAGGED"
" shall not have OPIONAL or DEFAULT");
" shall not have OPTIONAL or DEFAULT");
}
break;
}
......@@ -3938,6 +3938,10 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs,
}
// no break
case Value::V_CHOICE: {
if (!value->is_asn1() && typetype == T_OPENTYPE) {
// allow the alternatives of open types as both lower and upper identifiers
value->set_alt_name_to_lowercase();
}
const Identifier& alt_name = value->get_alt_name();
if(!has_comp_withName(alt_name)) {
if (value->is_asn1()) {
......@@ -5354,7 +5358,8 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed,
t_comp->set_my_governor(this);
chk_this_template_ref(t_comp);
self_ref |= chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED,
allow_omit, ANY_OR_OMIT_ALLOWED, sub_chk, implicit_omit, lhs);
omit_in_value_list ? OMIT_ALLOWED : OMIT_NOT_ALLOWED,
ANY_OR_OMIT_ALLOWED, sub_chk, implicit_omit, lhs);
if(temptype==Ttcn::Template::COMPLEMENTED_LIST &&
t_comp->get_template_refd_last()->get_templatetype() ==
Ttcn::Template::ANY_OR_OMIT)
......@@ -5724,10 +5729,10 @@ void Type::chk_this_template_Int_Real(Template *t)
FATAL_ERROR("Type::chk_this_template_Int_Real()");
}
}
if (v_lower && !v_upper) {
if (v_lower && !vr->get_max_v()) {
chk_range_boundary_infinity(v_lower, true);
}
if (!v_lower && v_upper) {
if (!vr->get_min_v() && v_upper) {
chk_range_boundary_infinity(v_upper, false);
}
break;}
......@@ -5761,6 +5766,10 @@ bool Type::chk_this_template_Choice(Template *t, namedbool is_modified,
// to have more than one here.
for (size_t i = 0; i < nof_nts; i++) {
Ttcn::NamedTemplate *nt = t->get_namedtemp_byIndex(i);
if (typetype == T_OPENTYPE) {
// allow the alternatives of open types as both lower and upper identifiers
nt->set_name_to_lowercase();
}
const Identifier& nt_name = nt->get_name();
if (!has_comp_withName(nt_name)) {
......
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2014 Ericsson Telecom AB
// Copyright (c) 2000-2015 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
......@@ -650,7 +650,12 @@ void Type::generate_code_rawdescriptor(output_struct *target)
"extern const TTCN_RAWdescriptor_t %s_raw_;\n", gennameown_str);
char *str = mprintf("const TTCN_RAWdescriptor_t %s_raw_ = {",
gennameown_str);
str = mputprintf(str, "%d,", rawattrib->fieldlength);
if (rawattrib->intx) {
str = mputstr(str, "RAW_INTX,");
}
else {
str = mputprintf(str, "%d,", rawattrib->fieldlength);
}
if (rawattrib->comp == XDEFCOMPL) str = mputstr(str, "SG_2COMPL,");
else if (rawattrib->comp == XDEFSIGNBIT) str = mputstr(str, "SG_SG_BIT,");
else str = mputstr(str, "SG_NO,");
......@@ -967,19 +972,20 @@ void Type::generate_code_jsondescriptor(output_struct *target)
if (NULL == jsonattrib) {
target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { false, NULL, false, NULL };\n"
"const TTCN_JSONdescriptor_t %s_json_ = { false, NULL, false, NULL, false };\n"
, get_genname_own().c_str());
} else {
char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
char* def_val = jsonattrib->default_value ?
mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL;
target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s };\n"
"const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s };\n"
, get_genname_own().c_str()
, jsonattrib->omit_as_null ? "true" : "false"
, alias ? alias : "NULL"
, jsonattrib->as_value ? "true" : "false"
, def_val ? def_val : "NULL");
, def_val ? def_val : "NULL"
, jsonattrib->metainfo_unbound ? "true" : "false");
Free(alias);
Free(def_val);
}
......@@ -1098,6 +1104,25 @@ void Type::generate_code_Choice(output_struct *target)
sdef.opentype_outermost = get_is_opentype_outermost();
sdef.ot = generate_code_ot(pool);
sdef.nElements = get_nof_comps();
sdef.isOptional = false;
if (parent_type != NULL) {
switch (parent_type->typetype) {
case T_SEQ_T:
case T_SEQ_A:
case T_SET_T:
case T_SET_A:
for (size_t x = 0; x < parent_type->get_nof_comps(); ++x) {
CompField * cf = parent_type->get_comp_byIndex(x);
if (cf->get_type() == this && cf->get_is_optional()) {
sdef.isOptional = true;
break; // from the for loop
}
}
break;
default:
break;
}
}
sdef.elements = (struct_field*)
Malloc(sdef.nElements*sizeof(*sdef.elements));
memset(sdef.elements, 0, sdef.nElements*sizeof(*sdef.elements));
......@@ -1124,30 +1149,56 @@ void Type::generate_code_Choice(output_struct *target)
typetype_t tt = cftype->get_type_refd_last()->typetype;
switch(tt) {
case T_INT:
case T_INT_A:
sdef.elements[i].jsonValueType = JSON_NUMBER;
break;
case T_REAL:
sdef.elements[i].jsonValueType = JSON_NUMBER | JSON_STRING;
break;
case T_BOOL:
sdef.elements[i].jsonValueType = JSON_LITERAL;
sdef.elements[i].jsonValueType = JSON_BOOLEAN;
break;
case T_NULL:
sdef.elements[i].jsonValueType = JSON_NULL;
break;
case T_BSTR:
case T_BSTR_A:
case T_HSTR:
case T_OSTR:
case T_CSTR:
case T_USTR:
case T_UTF8STRING:
case T_NUMERICSTRING:
case T_PRINTABLESTRING:
case T_TELETEXSTRING:
case T_VIDEOTEXSTRING:
case T_IA5STRING:
case T_GRAPHICSTRING:
case T_VISIBLESTRING:
case T_GENERALSTRING:
case T_UNIVERSALSTRING:
case T_BMPSTRING:
case T_VERDICT:
case T_ENUM_T:
case T_ENUM_A:
case T_OID:
case T_ROID:
case T_ANY:
sdef.elements[i].jsonValueType = JSON_STRING;
break;
case T_SEQ_T:
case T_SEQ_A:
case T_SET_T:
case T_SET_A:
case T_CHOICE_T:
case T_CHOICE_A:
case T_ANYTYPE:
case T_OPENTYPE:
sdef.elements[i].jsonValueType = JSON_OBJECT;
break;
case T_SEQOF:
case T_SETOF:
case T_ARRAY:
sdef.elements[i].jsonValueType = JSON_ARRAY;
break;
default:
......@@ -1531,6 +1582,7 @@ void Type::generate_code_Se(output_struct *target)
cur.jsonOmitAsNull = type->jsonattrib->omit_as_null;
cur.jsonAlias = type->jsonattrib->alias;
cur.jsonDefaultValue = type->jsonattrib->default_value;
cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound;
} // if jsonattrib
} // next element
......@@ -1845,7 +1897,7 @@ void Type::generate_code_SeOf(output_struct *target)
case T_UNIVERSALSTRING:
case T_BMPSTRING:
case T_OBJECTDESCRIPTOR:
target->header.typedefs = mputprintf(target->header.typedefs,
target->header.class_decls = mputprintf(target->header.class_decls,
"typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s %s;\n"
"typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s_template %s_template;\n",
(typetype == T_SEQOF) ? "RECORD" : "SET",
......@@ -1854,7 +1906,9 @@ void Type::generate_code_SeOf(output_struct *target)
optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str());
return;
default:
target->header.typedefs = mputprintf(target->header.typedefs,
// generate these in the class declarations part, they need to be
// outside of the include guard in case of circular imports
target->header.class_decls = mputprintf(target->header.class_decls,
"typedef PreGenRecordOf::PREGEN__%s__OF__%s%s %s;\n"
"typedef PreGenRecordOf::PREGEN__%s__OF__%s%s_template %s_template;\n",
(typetype == T_SEQOF) ? "RECORD" : "SET", oftypename.c_str(),
......@@ -2172,7 +2226,7 @@ void Type::generate_code_done(output_struct *target)
"component_reference.log();\n"
"TTCN_Logger::log_event_str(\" failed: Return value does not match "
"the template: \");\n"
"value_template.log_match(return_value);\n"
"value_template.log_match(return_value%s);\n"
"TTCN_Logger::end_event();\n"
"}\n"
"return ALT_NO;\n"
......@@ -2180,7 +2234,7 @@ void Type::generate_code_done(output_struct *target)
"} else return ret_val;\n"
"}\n\n",
genname_str, genname_str, dispname_str, genname_str, dispname_str,
dispname_str);
dispname_str, omit_in_value_list ? ", TRUE" : "");
}
bool Type::ispresent_anyvalue_embedded_field(Type* t,
......@@ -2352,8 +2406,9 @@ void Type::generate_code_ispresentbound(expression_struct *expr,
is_template?"_template":"", tmp_id_str);
expr->expr = mputprintf(expr->expr,
"%s = %s.%s();\n", global_id.c_str(),
tmp_id2_str, isbound ? "is_bound" : "is_present");
"%s = %s.%s(%s);\n", global_id.c_str(),
tmp_id2_str, isbound ? "is_bound" : "is_present",
(!isbound && is_template && omit_in_value_list) ? "TRUE" : "");
Free(tmp_generalid_str);
tmp_generalid_str = mcopystr(tmp_id2_str);
......@@ -2409,8 +2464,9 @@ void Type::generate_code_ispresentbound(expression_struct *expr,
id.get_name().c_str());
expr->expr = mputprintf(expr->expr,
"%s = %s.%s();\n", global_id.c_str(),
tmp_id_str, isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present");
"%s = %s.%s(%s);\n", global_id.c_str(),
tmp_id_str, isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
(!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
Free(tmp_generalid_str);
tmp_generalid_str = mcopystr(tmp_id_str);
}
......@@ -2496,9 +2552,10 @@ void Type::generate_code_ispresentbound(expression_struct *expr,
if (is_string_element) {
expr->expr = mputprintf(expr->expr,
"%s = %s[%s].%s();\n", global_id.c_str(),
"%s = %s[%s].%s(%s);\n", global_id.c_str(),
tmp_generalid_str, tmp_index_id_str,
isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present");
isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
(!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
} else {
if (is_template) {
expr->expr = mputprintf(expr->expr,
......@@ -2515,8 +2572,9 @@ void Type::generate_code_ispresentbound(expression_struct *expr,
}
expr->expr = mputprintf(expr->expr,
"%s = %s.%s();\n", global_id.c_str(), tmp_id_str,
isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present");
"%s = %s.%s(%s);\n", global_id.c_str(), tmp_id_str,
isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
(!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
}
Free(tmp_generalid_str);
......@@ -2689,22 +2747,56 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
Free(alias_str);
}
}
// get the type at the end of the reference chain
Type* last = get_type_refd_last();
// if the type has its own definition and it's embedded in another type, then
// its schema already exists, only add a reference to it
// check if this is a reference to another type that has its own definition
Type* refd_type = NULL;
if (is_ref()) {
Type* iter = this;
while (iter->is_ref()) {
iter = iter->get_type_refd();
if (iter->ownertype == OT_TYPE_DEF || /* TTCN-3 type definition */
iter->ownertype == OT_TYPE_ASS) { /* ASN.1 type assignment */
refd_type = iter;
break;
}
}
}
// check if there are any type restrictions
boolean has_restrictions = sub_type != NULL && sub_type->has_json_schema();
// if it's a referenced type, then its schema already exists, only add a pointer to it
// exception: instances of ASN.1 parameterized types, always embed their schemas
if (embedded && (!is_ref() || !get_type_refd()->pard_type_instance) &&
(last->ownertype == OT_TYPE_DEF /* TTCN-3 type definition */
|| last->ownertype == OT_TYPE_ASS /* ASN.1 type assignment */ )) {
if (refd_type != NULL && !get_type_refd()->pard_type_instance) {
if (has_restrictions) {
// an 'allOf' structure is needed if this is a subtype,
// insert the pointer in the first part
json.put_next_token(JSON_TOKEN_NAME, "allOf");
json.put_next_token(JSON_TOKEN_ARRAY_START);
json.put_next_token(JSON_TOKEN_OBJECT_START);
}
json.put_next_token(JSON_TOKEN_NAME, "$ref");
char* ref_str = mprintf("\"#/definitions/%s/%s\"",
last->my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(),
(is_ref() && last->pard_type_instance) ? get_type_refd()->get_dispname().c_str() : last->get_dispname().c_str());
refd_type->my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(),
refd_type->get_dispname().c_str());
json.put_next_token(JSON_TOKEN_STRING, ref_str);
Free(ref_str);
if (has_restrictions) {
// close the first part of the 'allOf' and insert the type restrictions
// in the second part
json.put_next_token(JSON_TOKEN_OBJECT_END);
json.put_next_token(JSON_TOKEN_OBJECT_START);
// pass the tokenizer to the subtype to insert the type restrictions' schema
sub_type->generate_json_schema(json);
// close the second part and the 'allOf' structure itself
json.put_next_token(JSON_TOKEN_OBJECT_END);
json.put_next_token(JSON_TOKEN_ARRAY_END);
}
} else {
// generate the schema for the referenced type
switch (last->typetype) {
......@@ -2720,22 +2812,32 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
json.put_next_token(JSON_TOKEN_STRING, "\"integer\"");
break;
case T_REAL:
// any of: JSON number or the special values as strings (in an enum)
json.put_next_token(JSON_TOKEN_NAME, "anyOf");
json.put_next_token(JSON_TOKEN_ARRAY_START);
json.put_next_token(JSON_TOKEN_OBJECT_START);
json.put_next_token(JSON_TOKEN_NAME, "type");
json.put_next_token(JSON_TOKEN_STRING, "\"number\"");
json.put_next_token(JSON_TOKEN_OBJECT_END);
json.put_next_token(JSON_TOKEN_OBJECT_START);
json.put_next_token(JSON_TOKEN_NAME, "enum");
json.put_next_token(JSON_TOKEN_ARRAY_START);
json.put_next_token(JSON_TOKEN_STRING, "\"not_a_number\"");
json.put_next_token(JSON_TOKEN_STRING, "\"infinity\"");