Commit 6e10281c authored by Jeno Attila Balasko's avatar Jeno Attila Balasko Committed by Gerrit Code Review
Browse files

Merge "Added JSON attribute 'chosen' (bug 528465)"

parents 2ffdfb5c f19a8e12
......@@ -52,6 +52,7 @@
#include "ttcn3/TtcnTemplate.hh"
#include "ttcn3/Templatestuff.hh"
#include "ttcn3/RawAST.hh"
#include "ttcn3/JsonAST.hh"
#include "../common/static_check.h"
#include "PredefFunc.hh"
......@@ -2155,6 +2156,10 @@ namespace Common {
size_t fieldnum;
for(int c=0;c<rawattrib->taglist.nElements;c++) { // check TAG
Identifier *idf=rawattrib->taglist.tag[c].fieldName;
if (idf == NULL) {
error("Field member in RAW parameter TAG cannot be 'omit'");
continue;
}
if(!has_comp_withName(*idf)){
error("Invalid field name `%s' in RAW parameter TAG "
"for type `%s'", idf->get_dispname().c_str(),
......@@ -2488,6 +2493,10 @@ namespace Common {
,field_id.get_dispname().c_str());
break;
}
if (idf == NULL) {
error("Field member in RAW parameter CROSSTAG cannot be 'omit'");
break;
}
if(!field_type_last->has_comp_withName(*idf)){
error("Invalid fieldmember name in RAW parameter CROSSTAG"
" for field %s: %s"
......@@ -2971,6 +2980,10 @@ namespace Common {
error("Invalid attribute, 'as number' is only allowed for enumerated "
"types");
}
if (NULL != jsonattrib->tag_list) {
chk_json_tag_list();
}
}
}
......@@ -3178,6 +3191,77 @@ namespace Common {
}
}
void Type::chk_json_tag_list()
{
Type* last = get_type_refd_last();
Type* parent = get_parent_type();
if (parent == NULL || last->get_typetype_ttcn3() != T_CHOICE_T ||
(parent->typetype != T_SEQ_T && parent->typetype != T_SET_T)) {
error("Invalid attribute, 'chosen' is only allowed for fields of records "
"and sets of union type");
return;
}
rawAST_tag_list* tag_list = jsonattrib->tag_list;
for (int i = 0; i < tag_list->nElements; ++i) {
Identifier* union_field_id = tag_list->tag[i].fieldName;
if (union_field_id == NULL) {
if (!is_optional_field()) {
error("Target of JSON attribute 'chosen' is a mandatory field and "
"cannot be set to 'omit'");
continue;
}
}
else if (!has_comp_withName(*union_field_id)) {
error("Reference to invalid union field name `%s' for type `%s', in JSON "
"attribute 'chosen'",
union_field_id->get_dispname().c_str(), get_typename().c_str());
continue;
}
for (int j = 0; j < tag_list->tag[i].nElements; ++j) {
bool erroneous = false;
Type* current_type = parent; // the first field name refers to the parent type
for (int k = 0; k < tag_list->tag[i].keyList[j].keyField->nElements; ++k) {
if (!current_type->is_secho()) {
error("Too many field references in JSON attribute 'chosen'. "
"Type `%s' doesn't have fields.",
current_type->get_typename().c_str());
erroneous = true;
break;
}
Identifier* current_field_id = tag_list->tag[i].keyList[j].keyField->names[k];
if (!current_type->has_comp_withName(*current_field_id)) {
error("Reference to invalid field name `%s' for type `%s', "
"in JSON attribute 'chosen'",
current_field_id->get_dispname().c_str(),
current_type->get_typename().c_str());
erroneous = true;
break;
}
CompField* current_field = current_type->get_comp_byName(*current_field_id);
current_type = current_field->get_type()->get_type_refd_last();
}
if (!erroneous) {
Error_Context cntx(this, "In JSON attribute 'choice'");
Value* value = tag_list->tag[i].keyList[j].v_value;
value->set_my_scope(get_my_scope());
value->set_my_governor(current_type);
current_type->chk_this_value_ref(value);
current_type->chk_this_value(value, 0, EXPECTED_CONSTANT,
INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK);
Value::valuetype_t value_type = value->get_valuetype();
if (value_type == Value::V_ENUM || value_type == Value::V_REFD) {
Free(tag_list->tag[i].keyList[j].value);
tag_list->tag[i].keyList[j].value =
mcopystr(value->get_single_expr().c_str());
}
}
}
}
}
void Type::force_json()
{
if (!jsonattrib)
......
......@@ -36,12 +36,12 @@
#include "ttcn3/rawASTspec.h"
#include "ttcn3/TextAST.hh"
#include "ttcn3/BerAST.hh"
#include "ttcn3/JsonAST.hh"
#include "ttcn3/OerAST.hh"
#include <float.h>
class XerAttributes;
class RawAST;
class JsonAST;
enum namedbool { INCOMPLETE_NOT_ALLOWED = 0, INCOMPLETE_ALLOWED = 1, WARNING_FOR_INCOMPLETE = 2,
NO_SUB_CHK = 0, SUB_CHK = 3,
OMIT_NOT_ALLOWED = 0, OMIT_ALLOWED = 4,
......@@ -897,6 +897,7 @@ namespace Common {
void chk_json();
void chk_json_default();
void chk_json_tag_list();
/** If the type does not have a jsonattrib, create one. */
void force_json();
......
......@@ -50,6 +50,7 @@
#include "asn1/Tag.hh"
#include "XerAttributes.hh"
#include "ttcn3/RawAST.hh"
#include "ttcn3/JsonAST.hh"
#include <ctype.h>
#include <stdlib.h> // for qsort
......
......@@ -37,6 +37,7 @@
#include "ttcn3/signature.h"
#include "XerAttributes.hh"
#include "ttcn3/RawAST.hh"
#include "ttcn3/JsonAST.hh"
#include "asn1/TableConstraint.hh"
#include "asn1/Object.hh"
......@@ -1071,7 +1072,7 @@ void Type::generate_code_jsondescriptor(output_struct *target)
, get_genname_own().c_str()
, jsonattrib->omit_as_null ? "TRUE" : "FALSE"
, alias ? alias : "NULL"
, jsonattrib->as_value ? "TRUE" : "FALSE"
, (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE"
, def_val ? def_val : "NULL"
, jsonattrib->metainfo_unbound ? "TRUE" : "FALSE"
, jsonattrib->as_number ? "TRUE" : "FALSE");
......@@ -1797,6 +1798,67 @@ void Type::generate_code_Se(output_struct *target)
cur.jsonAlias = type->jsonattrib->alias;
cur.jsonDefaultValue = type->jsonattrib->default_value;
cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound;
if (type->jsonattrib->tag_list != NULL) {
rawAST_tag_list* tag_list = type->jsonattrib->tag_list;
sdef.elements[i].jsonChosen = (rawAST_coding_taglist_list*)
Malloc(sizeof(rawAST_coding_taglist_list));
sdef.elements[i].jsonChosen->nElements = tag_list->nElements;
sdef.elements[i].jsonChosen->list = (rawAST_coding_taglist*)
Malloc(tag_list->nElements * sizeof(rawAST_coding_taglist));
for (int c = 0; c < tag_list->nElements; ++c) {
if (tag_list->tag[c].nElements != 0) {
sdef.elements[i].jsonChosen->list[c].fields =
(rawAST_coding_field_list*)Malloc(tag_list->tag[c].nElements *
sizeof(rawAST_coding_field_list));
}
else {
sdef.elements[i].jsonChosen->list[c].fields = NULL;
}
sdef.elements[i].jsonChosen->list[c].nElements =
tag_list->tag[c].nElements;
Identifier* union_field_id = tag_list->tag[c].fieldName;
sdef.elements[i].jsonChosen->list[c].fieldName = union_field_id != NULL ?
union_field_id->get_name().c_str() : NULL; // TODO: currently unused
sdef.elements[i].jsonChosen->list[c].fieldnum = union_field_id != NULL ?
type->get_type_refd_last()->get_comp_index_byName(
*tag_list->tag[c].fieldName) : -2;
for (int a = 0; a <tag_list->tag[c].nElements; ++a) {
rawAST_coding_field_list* key =
sdef.elements[i].jsonChosen->list[c].fields + a;
key->nElements = tag_list->tag[c].keyList[a].keyField->nElements;
key->value = tag_list->tag[c].keyList[a].value;
key->fields = (rawAST_coding_fields*)
Malloc(key->nElements * sizeof(rawAST_coding_fields));
Type *t = this;
for (int b = 0; b < key->nElements; ++b) {
Identifier* current_field_id =
tag_list->tag[c].keyList[a].keyField->names[b];
size_t current_field_index = t->get_comp_index_byName(*current_field_id);
CompField* current_field = t->get_comp_byIndex(current_field_index);
key->fields[b].nthfield = current_field_index;
key->fields[b].nthfieldname = current_field_id->get_name().c_str();
if (t->typetype == T_CHOICE_T) {
key->fields[b].fieldtype = UNION_FIELD;
}
else if (current_field->get_is_optional()) {
key->fields[b].fieldtype = OPTIONAL_FIELD;
}
else {
key->fields[b].fieldtype = MANDATORY_FIELD;
}
Type *field_type = current_field->get_type();
key->fields[b].type =
pool.add(field_type->get_genname_value(my_scope));
key->fields[b].typedescr =
pool.add(field_type->get_genname_typedescriptor(my_scope));
t = field_type->get_type_refd_last();
}
}
}
}
else {
sdef.elements[i].jsonChosen = NULL;
}
} // if jsonattrib
} // next element
......@@ -2085,6 +2147,17 @@ void Type::generate_code_Se(output_struct *target)
for(size_t i = 0; i < sdef.totalElements; i++) {
// free the array but not the strings
if (sdef.elements[i].xerAnyNum > 0) Free(sdef.elements[i].xerAnyUris);
if (sdef.elements[i].jsonChosen != NULL) {
for (int j = 0; j < sdef.elements[i].jsonChosen->nElements; ++j) {
for (int k = 0; k < sdef.elements[i].jsonChosen->list[j].nElements; ++k) {
Free(sdef.elements[i].jsonChosen->list[j].fields[k].fields);
}
Free(sdef.elements[i].jsonChosen->list[j].fields);
}
Free(sdef.elements[i].jsonChosen->list);
Free(sdef.elements[i].jsonChosen);
}
} // next i
if (sdef.hasRaw) {
......
......@@ -53,6 +53,7 @@
#include "ttcn3/Statement.hh"
 
#include "ttcn3/Attributes.hh"
#include "ttcn3/JsonAST.hh"
#include "../common/JSON_Tokenizer.hh"
#include "ttcn3/Ttcn2Json.hh"
 
......
......@@ -87,6 +87,7 @@ typedef struct {
boolean jsonMetainfoUnbound;
const char* jsonAlias;
const char* jsonDefaultValue;
rawAST_coding_taglist_list* jsonChosen;
/** true if the field is a record-of or set-of with optimized memory allocation */
boolean optimizedMemAlloc;
XSD_types xsd_type;
......
......@@ -81,7 +81,8 @@ void def_encdec(const char *p_classname,
if(json) {
def = mputprintf(def,
"int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const;\n"
"int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean);\n");
"int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean, "
"int p_chosen_field = CHOSEN_FIELD_UNSET);\n");
}
if(oer) {
def = mputprintf(def,
......
......@@ -809,7 +809,7 @@ void defEnumClass(const enum_def *edef, output_struct *output)
// JSON decode
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"{\n"
" json_token_t token = JSON_TOKEN_NONE;\n"
" char* value = 0;\n"
......
This diff is collapsed.
......@@ -1567,7 +1567,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
// JSON decode, RT1
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"{\n"
" if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n"
// use the default value (currently only the empty array can be set as
......@@ -3083,7 +3083,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
// JSON decode, RT1, mem. alloc. optimised
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"{\n"
" json_token_t token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
......
......@@ -35,6 +35,7 @@ void JsonAST::init_JsonAST()
default_value = NULL;
metainfo_unbound = false;
as_number = false;
tag_list = NULL;
}
JsonAST::JsonAST(const JsonAST *other_val)
......@@ -61,6 +62,10 @@ JsonAST::~JsonAST()
delete schema_extensions[i];
}
schema_extensions.clear();
if (tag_list != NULL) {
free_rawAST_tag_list(tag_list);
delete tag_list;
}
}
void JsonAST::print_JsonAST() const
......@@ -92,4 +97,26 @@ void JsonAST::print_JsonAST() const
if (metainfo_unbound) {
printf("Metainfo for unbound field(s)\n\r");
}
if (tag_list != NULL) {
printf("Chosen union fields:\n\r");
printf(" Number of rules: %d\n\r", tag_list->nElements);
for (int i = 0; i < tag_list->nElements; ++i) {
printf(" Rule #%d:\n\r", i);
printf(" Chosen field: %s\n\r", tag_list->tag[i].fieldName != NULL ?
tag_list->tag[i].fieldName->get_name().c_str() : "omit");
printf(" Number of conditions: %d\n\r", tag_list->tag[i].nElements);
for (int j = 0; j < tag_list->tag[i].nElements; ++j) {
printf(" Condition #%d:\n\r", j);
printf(" Value: %s\n\r", tag_list->tag[i].keyList[j].value);
printf(" Field: ");
for (int k = 0; k < tag_list->tag[i].keyList[j].keyField->nElements; ++k) {
if (k != 0) {
printf(".");
}
printf("%s", tag_list->tag[i].keyList[j].keyField->names[k]->get_name().c_str());
}
printf("\n\r");
}
}
}
}
......@@ -15,6 +15,7 @@
#include "../datatypes.h"
#include "../vector.hh"
#include "RawAST.hh"
class JsonSchemaExtension {
private:
......@@ -41,6 +42,7 @@ class JsonAST {
vector<JsonSchemaExtension> schema_extensions;
boolean metainfo_unbound;
boolean as_number;
rawAST_tag_list* tag_list;
JsonAST() { init_JsonAST(); }
JsonAST(const JsonAST *other_val);
......
......@@ -51,9 +51,9 @@ typedef struct {
} rawAST_tag_field_value;
typedef struct {
Common::Identifier* fieldName;
Common::Identifier* fieldName; // NULL == omit
int nElements;
rawAST_tag_field_value* keyList;
rawAST_tag_field_value* keyList; // NULL == otherwise/OTHERWISE
} rawAST_single_tag;
typedef struct {
......
......@@ -497,6 +497,8 @@ extend { BEGIN(jsoncodec); RETURN(XKWextend); }
metainfo RETURN(XKWmetainfo);
for RETURN(XKWfor);
unbound RETURN(XKWunbound);
chosen RETURN(XChosenKeyword);
otherwise RETURN(XJsonOtherwise);
}
<INITIAL>{
......
......@@ -294,6 +294,8 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value);
%token XJsonValueEnd ")"
%token XJsonValueSegment "JSON value"
%token XAsValueKeyword "asValue"
%token XChosenKeyword "chosen"
%token XJsonOtherwise "otherwise"
%type <enumval>
......@@ -618,7 +620,9 @@ XAssocList:
if ($3.nElements > 0) {
/* the otherwise element is never merged */
for (int i = 0; i < $1.nElements; i++)
if (*$1.tag[i].fieldName == *$3.fieldName) {
if (($1.tag[i].fieldName == NULL && $3.fieldName == NULL) ||
($1.tag[i].fieldName != NULL && $3.fieldName != NULL &&
*$1.tag[i].fieldName == *$3.fieldName)) {
dupl_id_index = i;
break;
}
......@@ -667,6 +671,30 @@ XAssocElement:
$$.nElements = 0;
$$.keyList = NULL;
}
| XIdentifier ',' XJsonOtherwise // JSON version
{
$$.fieldName = $1;
$$.nElements = 0;
$$.keyList = NULL;
}
| XOmitKeyword ',' XKeyIdOrIdList
{
$$.fieldName = NULL;
$$.nElements = $3.nElements;
$$.keyList = $3.keyList;
}
| XOmitKeyword ',' XOtherwise
{
$$.fieldName = NULL;
$$.nElements = 0;
$$.keyList = NULL;
}
| XOmitKeyword ',' XJsonOtherwise // JSON version
{
$$.fieldName = NULL;
$$.nElements = 0;
$$.keyList = NULL;
}
;
XKeyIdOrIdList:
......@@ -1760,6 +1788,7 @@ JSONattribute:
| JExtend
| JMetainfoForUnbound
| JAsNumber
| JChosen
;
JOmitAsNull:
......@@ -1787,6 +1816,19 @@ JAsNumber:
XKWas XKWnumber { jsonstruct->as_number = true; }
;
JChosen:
XChosenKeyword '(' XAssocList XoptSemiColon ')'
{
if (jsonstruct->tag_list == NULL) {
jsonstruct->tag_list = new rawAST_tag_list;
}
else {
free_rawAST_tag_list(jsonstruct->tag_list);
}
link_rawAST_tag_list(jsonstruct->tag_list, &$3);
}
;
%%
/* parse_rawAST(), which calls our rawAST_parse, is over in rawASST.l */
......
......@@ -58,7 +58,7 @@ typedef struct{
typedef struct{
const char* fieldName;
int fieldnum;
int fieldnum; /* -2 == omit (for JSON only) */
int nElements;
rawAST_coding_field_list* fields;
}rawAST_coding_taglist;
......
......@@ -2178,11 +2178,26 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
// JSON decode
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, boolean p_silent)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, "
"boolean p_silent, int p_chosen_field)\n"
"{\n"
, name, sdef->nElements > 0 && !sdef->jsonAsValue ? " p_td" : "");
if (sdef->nElements > 0) {
src = mputstr(src, " json_token_t j_token = JSON_TOKEN_NONE;\n");
src = mputprintf(src,
" if (0 <= p_chosen_field && %d > p_chosen_field) {\n"
" switch (p_chosen_field) {\n"
,(int)sdef->nElements);
for (i = 0; i < sdef->nElements; ++i) {
src = mputprintf(src,
" case %d:\n"
" return %s%s().JSON_decode(%s_descr_, p_tok, TRUE);\n"
, (int)i, at_field, sdef->elements[i].name
, sdef->elements[i].typedescrname);
}
src = mputstr(src,
" }\n"
" }\n"
" json_token_t j_token = JSON_TOKEN_NONE;\n");
if (!sdef->jsonAsValue) {
src = mputstr(src,
" if (NULL != p_td.json && p_td.json->as_value) {\n");
......
......@@ -318,7 +318,7 @@ int ASN_NULL::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) c
return p_tok.put_next_token(JSON_TOKEN_LITERAL_NULL);
}
int ASN_NULL::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent)
int ASN_NULL::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent, int)
{
json_token_t token = JSON_TOKEN_NONE;
size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);
......
......@@ -93,7 +93,7 @@ public:
/** Decodes accordingly to the JSON decoding rules.
* Returns the length of the encoded data. */
int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean);
int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean, int p_chosen_field = CHOSEN_FIELD_UNSET);
/** Encodes accordingly to the OER encoding rules.
* Returns the length of the encoded data. */
......
......@@ -967,7 +967,7 @@ public:
/** Decodes accordingly to the JSON encoding rules.
* Returns the length of the decoded data. */
int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean);
int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean, int p_chosen_field = CHOSEN_FIELD_UNSET);
// alt-status priority: ALT_YES (return immediately) > ALT_REPEAT > ALT_MAYBE > ALT_NO
alt_status done(VERDICTTYPE* value_redirect, Index_Redirect* index_redirect) const
......@@ -1355,7 +1355,7 @@ int VALUE_ARRAY<T_type,array_size,index_offset>::JSON_encode(
template <typename T_type, unsigned int array_size, int index_offset>
int VALUE_ARRAY<T_type,array_size,index_offset>::JSON_decode(
const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)
const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)
{
json_token_t token = JSON_TOKEN_NONE;
size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment