Commit 7c187762 authored by Botond Baranyi's avatar Botond Baranyi

JSON dec: implemented the 'default' attribute defined in the standard CR 7968 (issue #547)

Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 0863d2a6
...@@ -62,6 +62,10 @@ ...@@ -62,6 +62,10 @@
extern Ttcn::ExtensionAttributes * parse_extattributes( extern Ttcn::ExtensionAttributes * parse_extattributes(
Ttcn::WithAttribPath *w_attrib_path); Ttcn::WithAttribPath *w_attrib_path);
// implemented in compiler.y
extern Common::Value* ttcn3_parse_json_default(
const char* p_str, const Common::Location& str_loc);
namespace Common { namespace Common {
map<Type*, void> Type::RecursionTracker::types; map<Type*, void> Type::RecursionTracker::types;
...@@ -3168,9 +3172,12 @@ namespace Common { ...@@ -3168,9 +3172,12 @@ namespace Common {
} }
} }
if (NULL != jsonattrib->default_value) { if (jsonattrib->default_value.type == JsonAST::JD_STANDARD) {
chk_json_default(); chk_json_default();
} }
else if (jsonattrib->default_value.type == JsonAST::JD_LEGACY) {
chk_json_default_legacy();
}
const size_t nof_extensions = jsonattrib->schema_extensions.size(); const size_t nof_extensions = jsonattrib->schema_extensions.size();
if (0 != nof_extensions) { if (0 != nof_extensions) {
...@@ -3389,9 +3396,33 @@ namespace Common { ...@@ -3389,9 +3396,33 @@ namespace Common {
} }
} }
void Type::chk_json_default() void Type::chk_json_default()
{
if (jsonattrib->default_value.type != JsonAST::JD_STANDARD || jsonattrib->default_value.str == NULL ||
jsonattrib->default_value.loc == NULL) {
FATAL_ERROR("Type::chk_json_default");
}
Error_Context cntxt(this, "In JSON default value");
Value* val = ttcn3_parse_json_default(jsonattrib->default_value.str, *jsonattrib->default_value.loc);
if (val != NULL) {
val->set_my_governor(this);
val->set_my_scope(my_scope);
val->set_fullname(get_fullname() + ".<JSON_default_value>");
val->set_genname(get_genname_own() + "_json_defval");
chk_this_value_ref(val);
chk_this_value(val, NULL, EXPECTED_CONSTANT, INCOMPLETE_NOT_ALLOWED,
OMIT_NOT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT);
jsonattrib->default_value.val = val;
}
}
void Type::chk_json_default_legacy()
{ {
const char* dval = jsonattrib->default_value; if (jsonattrib->default_value.type != JsonAST::JD_LEGACY || jsonattrib->default_value.str == NULL) {
FATAL_ERROR("Type::chk_json_default");
}
Error_Context cntxt(this, "In JSON default value (legacy)");
const char* dval = jsonattrib->default_value.str;
const size_t dval_len = strlen(dval); const size_t dval_len = strlen(dval);
Type *last = get_type_refd_last(); Type *last = get_type_refd_last();
bool err = false; bool err = false;
......
...@@ -913,6 +913,7 @@ namespace Common { ...@@ -913,6 +913,7 @@ namespace Common {
void chk_json(); void chk_json();
void chk_json_default(); void chk_json_default();
void chk_json_default_legacy();
void chk_json_tag_list(); void chk_json_tag_list();
/** If the type does not have a jsonattrib, create one. */ /** If the type does not have a jsonattrib, create one. */
void force_json(); void force_json();
......
...@@ -1113,13 +1113,35 @@ void Type::generate_code_jsondescriptor(output_struct *target) ...@@ -1113,13 +1113,35 @@ void Type::generate_code_jsondescriptor(output_struct *target)
if (NULL == jsonattrib) { if (NULL == jsonattrib) {
target->source.global_vars = mputprintf(target->source.global_vars, target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, NULL, " "const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, "
"FALSE, FALSE, %s, 0, NULL, FALSE, ESCAPE_AS_SHORT };\n" "FALSE, FALSE, %s, 0, NULL, FALSE, ESCAPE_AS_SHORT };\n"
, get_genname_own().c_str(), as_map ? "TRUE" : "FALSE"); , get_genname_own().c_str(), as_map ? "TRUE" : "FALSE");
} else { } else {
char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL; char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
char* def_val = jsonattrib->default_value ? const char* def_type;
mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL; char* def_val = NULL;
switch (jsonattrib->default_value.type) {
case JsonAST::JD_UNSET:
def_type = "JD_UNSET";
break;
case JsonAST::JD_LEGACY:
def_type = "JD_LEGACY";
def_val = mprintf(".str = \"%s\"", jsonattrib->default_value.str);
break;
case JsonAST::JD_STANDARD:
def_type = "JD_STANDARD";
Value* v = jsonattrib->default_value.val;
const_def cdef;
Code::init_cdef(&cdef);
generate_code_object(&cdef, v, false);
// Generate the initialization of the default values in the post init function
// because the module parameters are not initialized in the pre init function
target->functions.post_init = v->generate_code_init(target->functions.post_init, v->get_lhs_name().c_str());
Code::merge_cdef(target, &cdef);
Code::free_cdef(&cdef);
def_val = mprintf(".val = &%s", v->get_lhs_name().c_str());
break;
}
char* enum_texts_name; char* enum_texts_name;
if (0 != jsonattrib->enum_texts.size()) { if (0 != jsonattrib->enum_texts.size()) {
...@@ -1139,13 +1161,13 @@ void Type::generate_code_jsondescriptor(output_struct *target) ...@@ -1139,13 +1161,13 @@ void Type::generate_code_jsondescriptor(output_struct *target)
} }
target->source.global_vars = mputprintf(target->source.global_vars, target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s, %s, %s, " "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, { %s, %s }, %s, %s, %s, "
"%d, %s, %s, %s };\n" "%d, %s, %s, %s };\n"
, get_genname_own().c_str() , get_genname_own().c_str()
, jsonattrib->omit_as_null ? "TRUE" : "FALSE" , jsonattrib->omit_as_null ? "TRUE" : "FALSE"
, alias ? alias : "NULL" , alias ? alias : "NULL"
, (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE" , (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE"
, def_val ? def_val : "NULL" , def_type, def_val ? def_val : "NULL"
, jsonattrib->metainfo_unbound ? "TRUE" : "FALSE" , jsonattrib->metainfo_unbound ? "TRUE" : "FALSE"
, jsonattrib->as_number ? "TRUE" : "FALSE" , jsonattrib->as_number ? "TRUE" : "FALSE"
, as_map ? "TRUE" : "FALSE" , as_map ? "TRUE" : "FALSE"
...@@ -1895,7 +1917,7 @@ void Type::generate_code_Se(output_struct *target) ...@@ -1895,7 +1917,7 @@ void Type::generate_code_Se(output_struct *target)
if (type->jsonattrib) { if (type->jsonattrib) {
cur.jsonOmitAsNull = type->jsonattrib->omit_as_null; cur.jsonOmitAsNull = type->jsonattrib->omit_as_null;
cur.jsonAlias = type->jsonattrib->alias; cur.jsonAlias = type->jsonattrib->alias;
cur.jsonDefaultValue = type->jsonattrib->default_value; cur.jsonDefaultValue = type->jsonattrib->default_value.str;
cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound; cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound;
if (type->jsonattrib->tag_list != NULL) { if (type->jsonattrib->tag_list != NULL) {
rawAST_tag_list* tag_list = type->jsonattrib->tag_list; rawAST_tag_list* tag_list = type->jsonattrib->tag_list;
...@@ -3811,18 +3833,18 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val ...@@ -3811,18 +3833,18 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
} }
// insert default value (if any) // insert default value (if any)
if (jsonattrib != NULL && jsonattrib->default_value != NULL) { if (jsonattrib != NULL && jsonattrib->default_value.str != NULL) {
json.put_next_token(JSON_TOKEN_NAME, "default"); json.put_next_token(JSON_TOKEN_NAME, "default");
switch (last->typetype) { switch (last->typetype) {
case T_BOOL: case T_BOOL:
json.put_next_token((jsonattrib->default_value[0] == 't') ? json.put_next_token((jsonattrib->default_value.str[0] == 't') ?
JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE); JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE);
break; break;
case T_INT: case T_INT:
case T_REAL: case T_REAL:
if (jsonattrib->default_value[0] != 'n' && jsonattrib->default_value[0] != 'i' if (jsonattrib->default_value.str[0] != 'n' && jsonattrib->default_value.str[0] != 'i'
&& jsonattrib->default_value[1] != 'i') { && jsonattrib->default_value.str[1] != 'i') {
json.put_next_token(JSON_TOKEN_NUMBER, jsonattrib->default_value); json.put_next_token(JSON_TOKEN_NUMBER, jsonattrib->default_value.str);
break; break;
} }
// no break, insert the special float values as strings // no break, insert the special float values as strings
...@@ -3833,7 +3855,7 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val ...@@ -3833,7 +3855,7 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
case T_USTR: case T_USTR:
case T_VERDICT: case T_VERDICT:
case T_ENUM_T: { case T_ENUM_T: {
char* default_str = mprintf("\"%s\"", jsonattrib->default_value); char* default_str = mprintf("\"%s\"", jsonattrib->default_value.str);
json.put_next_token(JSON_TOKEN_STRING, default_str); json.put_next_token(JSON_TOKEN_STRING, default_str);
Free(default_str); Free(default_str);
break; } break; }
......
...@@ -838,11 +838,16 @@ void defEnumClass(const enum_def *edef, output_struct *output) ...@@ -838,11 +838,16 @@ void defEnumClass(const enum_def *edef, output_struct *output)
" size_t value_len = 0;\n" " size_t value_len = 0;\n"
" boolean error = FALSE;\n" " boolean error = FALSE;\n"
" size_t dec_len = 0;\n" " size_t dec_len = 0;\n"
" boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();\n" " boolean use_default = FALSE;\n"
" if (use_default) {\n" " if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
" *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
" return dec_len;\n"
" }\n"
" if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
// No JSON data in the buffer -> use default value // No JSON data in the buffer -> use default value
" value = const_cast<char*>(p_td.json->default_value);\n" " value = const_cast<char*>(p_td.json->default_value.str);\n"
" value_len = strlen(value);\n" " value_len = strlen(value);\n"
" use_default = TRUE;\n"
" } else {\n" " } else {\n"
" dec_len = p_tok.get_next_token(&token, &value, &value_len);\n" " dec_len = p_tok.get_next_token(&token, &value, &value_len);\n"
" }\n" " }\n"
...@@ -902,7 +907,7 @@ void defEnumClass(const enum_def *edef, output_struct *output) ...@@ -902,7 +907,7 @@ void defEnumClass(const enum_def *edef, output_struct *output)
" }\n" " }\n"
" return (int)dec_len;\n" " return (int)dec_len;\n"
"}\n\n" "}\n\n"
, name, edef->elements[0].name, enum_type, unknown_value, enum_type , name, name, edef->elements[0].name, enum_type, unknown_value, enum_type
, unbound_value, unbound_value); , unbound_value, unbound_value);
} }
......
...@@ -3266,10 +3266,13 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) ...@@ -3266,10 +3266,13 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
char* generate_json_decoder(char* src, const struct_def* sdef) char* generate_json_decoder(char* src, const struct_def* sdef)
{ {
src = mputprintf(src, src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, " "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, "
"boolean p_silent, boolean p_parent_is_map, int)\n" "boolean p_silent, boolean p_parent_is_map, int)\n"
"{\n", sdef->name, "{\n"
((sdef->nElements == 1 && !sdef->jsonAsValue) || sdef->jsonAsMapPossible) ? " p_td" : ""); " if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
" *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
" return 0;\n"
" }\n", sdef->name, sdef->name);
if (sdef->nElements == 1) { if (sdef->nElements == 1) {
if (!sdef->jsonAsValue) { if (!sdef->jsonAsValue) {
...@@ -6897,10 +6900,14 @@ static void defEmptyRecordClass(const struct_def *sdef, ...@@ -6897,10 +6900,14 @@ static void defEmptyRecordClass(const struct_def *sdef,
src = mputprintf(src, src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n" "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n" "{\n"
" if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n" " if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
" *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
" return 0;\n"
" }\n"
" if (p_td.json->default_value.type != JD_UNSET && 0 == p_tok.get_buffer_length()) {\n"
// use the default value // use the default value
" bound_flag = TRUE;\n" " bound_flag = TRUE;\n"
" return strlen(p_td.json->default_value);\n" " return strlen(p_td.json->default_value.str);\n"
" }\n" " }\n"
" json_token_t token = JSON_TOKEN_NONE;\n" " json_token_t token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n" " size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
...@@ -6919,7 +6926,7 @@ static void defEmptyRecordClass(const struct_def *sdef, ...@@ -6919,7 +6926,7 @@ static void defEmptyRecordClass(const struct_def *sdef,
" bound_flag = TRUE;\n\n" " bound_flag = TRUE;\n\n"
" return (int)dec_len;\n" " return (int)dec_len;\n"
"}\n\n" "}\n\n"
, name); , name, name);
} }
if (oer_needed) { if (oer_needed) {
......
...@@ -1579,11 +1579,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1579,11 +1579,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
src = mputprintf(src, src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n" "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n" "{\n"
" if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n" " if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
" *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
" return 0;\n"
" }\n"
" if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
// use the default value (currently only the empty array can be set as // use the default value (currently only the empty array can be set as
// default value for this type) // default value for this type)
" set_size(0);\n" " set_size(0);\n"
" return strlen(p_td.json->default_value);\n" " return strlen(p_td.json->default_value.str);\n"
" }\n" " }\n"
" json_token_t token = JSON_TOKEN_NONE;\n" " json_token_t token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n" " size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
...@@ -1653,7 +1657,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1653,7 +1657,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" }\n\n" " }\n\n"
" return (int)dec_len;\n" " return (int)dec_len;\n"
"}\n\n" "}\n\n"
, name, type, type, type); , name, name, type, type, type);
} }
if (oer_needed) { if (oer_needed) {
// OER encode, RT1 // OER encode, RT1
...@@ -3105,6 +3109,16 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct ...@@ -3105,6 +3109,16 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
src = mputprintf(src, src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n" "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n" "{\n"
" if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
" *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
" return 0;\n"
" }\n"
" if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
// use the default value (currently only the empty array can be set as
// default value for this type)
" set_size(0);\n"
" return strlen(p_td.json->default_value.str);\n"
" }\n"
" json_token_t token = JSON_TOKEN_NONE;\n" " json_token_t token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n" " size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
" if (JSON_TOKEN_ERROR == token) {\n" " if (JSON_TOKEN_ERROR == token) {\n"
...@@ -3167,7 +3181,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct ...@@ -3167,7 +3181,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
" }\n\n" " }\n\n"
" return (int)dec_len;\n" " return (int)dec_len;\n"
"}\n\n" "}\n\n"
, name, type); , name, name, type);
} }
if (oer_needed) { if (oer_needed) {
// OER encode, RT1, mem. alloc. optimised // OER encode, RT1, mem. alloc. optimised
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "../../common/memory.h" #include "../../common/memory.h"
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include "../Value.hh"
void JsonSchemaExtension::init(char* p_key, char* p_value) void JsonSchemaExtension::init(char* p_key, char* p_value)
{ {
...@@ -38,7 +39,10 @@ void JsonAST::init_JsonAST() ...@@ -38,7 +39,10 @@ void JsonAST::init_JsonAST()
omit_as_null = false; omit_as_null = false;
alias = NULL; alias = NULL;
as_value = false; as_value = false;
default_value = NULL; default_value.type = JD_UNSET;
default_value.str = NULL;
default_value.val = NULL;
default_value.loc = NULL;
metainfo_unbound = false; metainfo_unbound = false;
as_number = false; as_number = false;
tag_list = NULL; tag_list = NULL;
...@@ -55,7 +59,9 @@ JsonAST::JsonAST(const JsonAST *other_val) ...@@ -55,7 +59,9 @@ JsonAST::JsonAST(const JsonAST *other_val)
omit_as_null = other_val->omit_as_null; omit_as_null = other_val->omit_as_null;
alias = (NULL != other_val->alias) ? mcopystr(other_val->alias) : NULL; alias = (NULL != other_val->alias) ? mcopystr(other_val->alias) : NULL;
as_value = other_val->as_value; as_value = other_val->as_value;
default_value = (NULL != other_val->default_value) ? mcopystr(other_val->default_value) : NULL; default_value.type = other_val->default_value.type;
default_value.str = (NULL != other_val->default_value.str) ? mcopystr(other_val->default_value.str) : NULL;
default_value.val = (NULL != other_val->default_value.val) ? other_val->default_value.val->clone() : NULL;
as_number = other_val->as_number; as_number = other_val->as_number;
for (size_t i = 0; i < other_val->schema_extensions.size(); ++i) { for (size_t i = 0; i < other_val->schema_extensions.size(); ++i) {
schema_extensions.add(new JsonSchemaExtension(*other_val->schema_extensions[i])); schema_extensions.add(new JsonSchemaExtension(*other_val->schema_extensions[i]));
...@@ -75,7 +81,9 @@ JsonAST::JsonAST(const JsonAST *other_val) ...@@ -75,7 +81,9 @@ JsonAST::JsonAST(const JsonAST *other_val)
JsonAST::~JsonAST() JsonAST::~JsonAST()
{ {
Free(alias); Free(alias);
Free(default_value); Free(default_value.str);
delete default_value.val;
delete default_value.loc;
for (size_t i = 0; i < schema_extensions.size(); ++i) { for (size_t i = 0; i < schema_extensions.size(); ++i) {
delete schema_extensions[i]; delete schema_extensions[i];
} }
...@@ -93,7 +101,7 @@ JsonAST::~JsonAST() ...@@ -93,7 +101,7 @@ JsonAST::~JsonAST()
boolean JsonAST::empty() const boolean JsonAST::empty() const
{ {
return omit_as_null == false && alias == NULL && as_value == false && return omit_as_null == false && alias == NULL && as_value == false &&
default_value == NULL && metainfo_unbound == false && as_number == false && default_value.type == JD_UNSET && metainfo_unbound == false && as_number == false &&
tag_list == NULL && as_map == false && enum_texts.size() == 0 && tag_list == NULL && as_map == false && enum_texts.size() == 0 &&
use_null == false && type_indicator != JSON_OBJECT && use_null == false && type_indicator != JSON_OBJECT &&
type_indicator != JSON_LITERAL && type_indicator != JSON_LITERAL &&
...@@ -167,8 +175,9 @@ void JsonAST::print_JsonAST() const ...@@ -167,8 +175,9 @@ void JsonAST::print_JsonAST() const
if (as_value) { if (as_value) {
printf("Encoding unions as JSON value\n\r"); printf("Encoding unions as JSON value\n\r");
} }
if (default_value) { if (default_value.type != JD_UNSET) {
printf("Default value: %s\n\r", default_value); printf("Default value%s: %s\n\r", default_value.type == JD_LEGACY ? " (legacy)" : "",
default_value.type == JD_LEGACY ? default_value.str : default_value.val->create_stringRepr().c_str());
} }
if (as_number) { if (as_number) {
printf("Encoding enumerated values as numbers\n\r"); printf("Encoding enumerated values as numbers\n\r");
......
...@@ -55,6 +55,11 @@ public: ...@@ -55,6 +55,11 @@ public:
ESCAPE_AS_USI, ESCAPE_AS_USI,
ESCAPE_AS_TRANSPARENT ESCAPE_AS_TRANSPARENT
}; };
enum json_default_type {
JD_UNSET, // no default value set
JD_LEGACY, // legacy default value set through the 'JSON: default' variant attribute
JD_STANDARD // standard-compliant default value set through the 'default' variant attribute
};
private: private:
void init_JsonAST(); void init_JsonAST();
JsonAST(const JsonAST&); JsonAST(const JsonAST&);
...@@ -63,7 +68,12 @@ public: ...@@ -63,7 +68,12 @@ public:
boolean omit_as_null; boolean omit_as_null;
char* alias; char* alias;
boolean as_value; boolean as_value;
char* default_value; struct {
json_default_type type;
char* str;
Common::Value* val;
Common::Location* loc;
} default_value;
vector<JsonSchemaExtension> schema_extensions; vector<JsonSchemaExtension> schema_extensions;
boolean metainfo_unbound; boolean metainfo_unbound;
boolean as_number; boolean as_number;
......
...@@ -197,6 +197,7 @@ LINEMARKER {NUMBER}{WHITESPACE}+\"([^\\\"\r\n]|\\[^\r\n])*\" ...@@ -197,6 +197,7 @@ LINEMARKER {NUMBER}{WHITESPACE}+\"([^\\\"\r\n]|\\[^\r\n])*\"
UID [uU][+]?[0-9A-Fa-f]{1,8} UID [uU][+]?[0-9A-Fa-f]{1,8}
TITAN "$#&&&(#TITANERRONEOUS$#&&^#% " TITAN "$#&&&(#TITANERRONEOUS$#&&^#% "
TITAN2 "$#&&&(#TITANJSONDEFAULT$#&&^#% "
%x SC_blockcomment SC_cstring %x SC_blockcomment SC_cstring
%x SC_binstring SC_binstring_bad %x SC_binstring SC_binstring_bad
...@@ -246,6 +247,10 @@ TITAN "$#&&&(#TITANERRONEOUS$#&&^#% " ...@@ -246,6 +247,10 @@ TITAN "$#&&&(#TITANERRONEOUS$#&&^#% "
} }
} }
{TITAN2} {
RETURN(TitanJsonDefaultHackKeyword);
}
/* Eat up comments and whitespaces */ /* Eat up comments and whitespaces */
"/*" { "/*" {
......
...@@ -76,11 +76,14 @@ const char *infile = NULL; ...@@ -76,11 +76,14 @@ const char *infile = NULL;
static Ttcn::Module *act_ttcn3_module = NULL; static Ttcn::Module *act_ttcn3_module = NULL;
static Ttcn::ErroneousAttributeSpec *act_ttcn3_erroneous_attr_spec = NULL; static Ttcn::ErroneousAttributeSpec *act_ttcn3_erroneous_attr_spec = NULL;
static Common::Value* act_json_default = NULL;
bool is_erroneous_parsed = false; bool is_erroneous_parsed = false;
bool is_json_default_parsed = false;
static void ttcn3_error(const char *str); static void ttcn3_error(const char *str);
static Group* act_group = NULL; static Group* act_group = NULL;
extern string anytype_field(const string& type_name); extern string anytype_field(const string& type_name);
static bool anytype_access = false; static bool anytype_access = false;
static bool parsing_error = false;
#ifndef NDEBUG #ifndef NDEBUG
...@@ -649,6 +652,7 @@ static const string anyname("anytype"); ...@@ -649,6 +652,7 @@ static const string anyname("anytype");
* This magic requires the presence of the unused keywords. * This magic requires the presence of the unused keywords.
* (It can return an ApplyKeyword if not preceded by a dot) */ * (It can return an ApplyKeyword if not preceded by a dot) */
%token TitanErroneousHackKeyword %token TitanErroneousHackKeyword
%token TitanJsonDefaultHackKeyword
%token ActionKeyword %token ActionKeyword
%token ActivateKeyword %token ActivateKeyword
%token AddressKeyword %token AddressKeyword
...@@ -2082,11 +2086,12 @@ reduce in case of conflicts. ...@@ -2082,11 +2086,12 @@ reduce in case of conflicts.
GrammarRoot: GrammarRoot:
TTCN3Module TTCN3Module
{ {
if (is_erroneous_parsed) { if (is_erroneous_parsed || is_json_default_parsed) {
delete act_ttcn3_module; delete act_ttcn3_module;
act_ttcn3_module = NULL; act_ttcn3_module = NULL;
Location loc(infile, @1); Location loc(infile, @1);
loc.error("The erroneous attribute cannot be a TTCN-3 module."); loc.error("The %s cannot be a TTCN-3 module.",
is_json_default_parsed ? "JSON default value" : "erroneous attribute");
} }
} }
| TitanErroneousHackKey