diff --git a/compiler2/CompField.cc b/compiler2/CompField.cc index 7ed20f9c9196a7f1fa81c90d6cca3f1016b0ff57..30c2127f6623e9d34921c6e995e6a4a77dad6d8f 100644 --- a/compiler2/CompField.cc +++ b/compiler2/CompField.cc @@ -14,6 +14,7 @@ #include "Type.hh" #include "Value.hh" #include "CompilerError.hh" +#include "ttcn3/RawAST.hh" namespace Common { diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 05f0a578a3496b73616a53a74eab688c6a6bf713..bd5d1fc495aea7ea5c1afda2f06b460724905be0 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -51,6 +51,7 @@ #include "ttcn3/Ttcnstuff.hh" #include "ttcn3/TtcnTemplate.hh" #include "ttcn3/Templatestuff.hh" +#include "ttcn3/RawAST.hh" #include "../common/static_check.h" #include "PredefFunc.hh" diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 7ff7db19273068390de53696ac205c564f724b11..de9bfd29fccecfce82004533a37ad620d257f552 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -34,7 +34,6 @@ #include "Int.hh" #include "subtype.hh" #include "ttcn3/rawASTspec.h" -#include "ttcn3/RawAST.hh" #include "ttcn3/TextAST.hh" #include "ttcn3/BerAST.hh" #include "ttcn3/JsonAST.hh" @@ -42,6 +41,7 @@ #include <float.h> class XerAttributes; +class RawAST; 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, diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 9f27487b7f1a9db02d6068dec95253e448697ab3..bb0227ceab31ec6071d4faf8a5568a7c9cb9f873 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -49,6 +49,7 @@ #include "asn1/Tag.hh" #include "XerAttributes.hh" +#include "ttcn3/RawAST.hh" #include <ctype.h> #include <stdlib.h> // for qsort @@ -1043,7 +1044,7 @@ void Type::chk_this_variant(const Ttcn::SingleWithAttrib* swa, bool global) } int ret = parse_rawAST(rawattrib, textattrib, xerattrib, berattrib, jsonattrib, swa->get_attribSpec(), get_length_multiplier(), my_scope->get_scope_mod(), - raw_found, text_found, xer_found, ber_found, json_found); + raw_found, text_found, xer_found, ber_found, json_found, coding); bool mismatch = false; if (ber_found || raw_found || text_found || xer_found || json_found) { switch (coding) { diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index f6125fe50bb8b736301a44ca71bddf61f0d42e67..8add56f5df3e926b7d89362143f05bb7f4eb5420 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -36,6 +36,7 @@ #include "ttcn3/Attributes.hh" #include "ttcn3/signature.h" #include "XerAttributes.hh" +#include "ttcn3/RawAST.hh" #include "asn1/TableConstraint.hh" #include "asn1/Object.hh" diff --git a/compiler2/ttcn3/RawAST.hh b/compiler2/ttcn3/RawAST.hh index 99c3421ebbfd0feafc4adbdb9f0351eeb4c2bca9..4a60952f1673bfb62839cc95aee326cda83a6569 100644 --- a/compiler2/ttcn3/RawAST.hh +++ b/compiler2/ttcn3/RawAST.hh @@ -22,6 +22,7 @@ #include "../Setting.hh" #include "../Identifier.hh" #include "../../common/CharCoding.hh" +#include "../Type.hh" class XerAttributes; class TextAST; @@ -154,13 +155,16 @@ public: * @param[out] text_found set to \c true if a TEXT attribute was found * @param[out] xer_found set to \c true if a XER attribute was found * @param[out] json_found set to \c true if a JSON attribute was found + * @param[in] sel_codec indicates which codec to use for attributes that + * belong to multiple codecs * @return the return value of rawAST_parse: 0 for success, 1 for error, * 2 for out of memory. */ extern int parse_rawAST(RawAST *par, TextAST *textpar, XerAttributes *xerpar, BerAST *berpar, JsonAST* jsonpar, const Ttcn::AttributeSpec& attrib, int l_multip, const Common::Module* mod, bool &raw_found, bool &text_found, - bool &xer_found, bool &ber_found, bool &json_found); + bool &xer_found, bool &ber_found, bool &json_found, + Common::Type::MessageEncodingType_t par_codec = Common::Type::CT_UNDEF); extern void copy_rawAST_to_struct(RawAST *from, raw_attrib_struct *to); extern void free_raw_attrib_struct(raw_attrib_struct *raw); extern int compare_raw_attrib(RawAST *a, RawAST *b); diff --git a/compiler2/ttcn3/rawAST.l b/compiler2/ttcn3/rawAST.l index c69f4144f60bc4e9ba33dea6b1592705fd26d650..75928146491e53b6ad225891c128622cbddea0aa 100644 --- a/compiler2/ttcn3/rawAST.l +++ b/compiler2/ttcn3/rawAST.l @@ -59,6 +59,7 @@ bool xer_f; bool ber_f; bool json_f; int length_multiplier; +Common::Type::MessageEncodingType_t selected_codec; extern void rawAST_error(const char *str); /* defined in this file */ extern int rawAST_parse(); /* in rawAST.tab.cc, generated from rawAST.y */ @@ -450,8 +451,10 @@ anyType RETURN(XSDanyType); } /* end XER keywords in INITIAL */ + /* prefix for legacy JSON attributes */ JSON { BEGIN(jsoncodec); RETURN(XKWjson); } + /* legacy JSON attributes */ <jsoncodec>{ [: \t] RETURN(*yytext); omit RETURN(XKWomit); @@ -483,6 +486,17 @@ number RETURN(XKWnumber); [)] { BEGIN(jsoncodec); RETURN(XJsonValueEnd); } [\"][\"] { yylval.str = mcopystr("\\\""); RETURN(XJsonValueSegment); } [^\"\\)]+ { yylval.str = mcopystr(yytext); RETURN(XJsonValueSegment); } +} + + /* tokens for new JSON attributes (standard-compliant) */ +<INITIAL>{ +asValue RETURN(XAsValueKeyword); +default { BEGIN(jsoncodec); RETURN(XKWdefault); } +number RETURN(XKWnumber); +extend { BEGIN(jsoncodec); RETURN(XKWextend); } +metainfo RETURN(XKWmetainfo); +for RETURN(XKWfor); +unbound RETURN(XKWunbound); } <INITIAL>{ @@ -656,7 +670,8 @@ void free_rawAST_tag_list(rawAST_tag_list* spec){ int parse_rawAST(RawAST *par, TextAST *textpar, XerAttributes *xerpar, BerAST* berpar, JsonAST* jsonpar, const Ttcn::AttributeSpec& attrib, int l_multip, const Common::Module* mod, bool &raw_found, bool &text_found, - bool &xer_found, bool &ber_found, bool &json_found) + bool &xer_found, bool &ber_found, bool &json_found, + Common::Type::MessageEncodingType_t par_codec /* = Common::Type::CT_UNDEF */) { rawstruct=par; textstruct=textpar; @@ -665,6 +680,7 @@ int parse_rawAST(RawAST *par, TextAST *textpar, XerAttributes *xerpar, jsonstruct = jsonpar; length_multiplier=l_multip; + selected_codec = par_codec; infile = attrib.get_filename(); current_line = attrib.get_first_line(); /* skip the leading " of the attribute value */ diff --git a/compiler2/ttcn3/rawAST.y b/compiler2/ttcn3/rawAST.y index 4f4031512f46b9a8605ac9ed1a3920e874274fe7..791b38b787ae4ff46a22fcf463a3b3ed24b466ca 100644 --- a/compiler2/ttcn3/rawAST.y +++ b/compiler2/ttcn3/rawAST.y @@ -31,6 +31,7 @@ #include "../XerAttributes.hh" #include "BerAST.hh" #include "JsonAST.hh" +#include "../main.hh" extern void rawAST_error(const char *str); extern int rawAST_lex(); @@ -38,6 +39,7 @@ extern int rawAST_lex(); extern RawAST* rawstruct; extern Common::Module *mymod; extern int length_multiplier; +extern Common::Type::MessageEncodingType_t selected_codec; extern TextAST *textstruct; extern bool raw_f; extern bool text_f; @@ -291,6 +293,7 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value); %token XJsonValueStart "(" %token XJsonValueEnd ")" %token XJsonValueSegment "JSON value" +%token XAsValueKeyword "asValue" %type <enumval> @@ -427,6 +430,8 @@ XAttribSpec : /* Empty */ { } | XBERattributes { } + | JSONattributes + { } ; XBERattributes : @@ -1355,18 +1360,54 @@ XERattribute: | fractionDigits { xerstruct->fractionDigits_ = $1; xerstruct->has_fractionDigits_ = true; } | XKWlist { xerstruct->list_ = true; } | name - { /* overwrites any previous name */ - switch (xerstruct->name_.kw_) { - case NamespaceSpecification::NO_MANGLING: - case NamespaceSpecification::CAPITALIZED: - case NamespaceSpecification::UNCAPITALIZED: - case NamespaceSpecification::UPPERCASED: - case NamespaceSpecification::LOWERCASED: - break; // nothing to do - default: // real string, must be freed - Free(xerstruct->name_.nn_); + { + // this handles the "name as '...' " attributes for both the XER and + // JSON codecs + // (overwrites any previously set name) + if (selected_codec == Common::Type::CT_XER) { + switch (xerstruct->name_.kw_) { + case NamespaceSpecification::NO_MANGLING: + case NamespaceSpecification::CAPITALIZED: + case NamespaceSpecification::UNCAPITALIZED: + case NamespaceSpecification::UPPERCASED: + case NamespaceSpecification::LOWERCASED: + break; // nothing to do + default: // real string, must be freed + Free(xerstruct->name_.nn_); + } + xerstruct->name_.nn_ = $1; + } + else { + // treat XML special values and real strings separately + XerAttributes::NameChange special; + special.nn_ = $1; + switch (special.kw_) { + case NamespaceSpecification::NO_MANGLING: + case NamespaceSpecification::CAPITALIZED: + case NamespaceSpecification::UNCAPITALIZED: + case NamespaceSpecification::UPPERCASED: + case NamespaceSpecification::LOWERCASED: + // it's a special value + // JSON: display an error (if using the new codec handling) + // otherwise ignore + if (!legacy_codec_handling && + selected_codec == Common::Type::CT_JSON) { + Common::Location loc(infile, @$); + loc.error("This format is not supported for the JSON codec"); + } + break; + default: // it's a real string + if (selected_codec == Common::Type::CT_JSON) { + Free(jsonstruct->alias); + jsonstruct->alias = $1; + json_f = true; + } + else { + Free($1); + } + break; + } } - xerstruct->name_.nn_ = $1; } | namespace { /* overwrites any previous namespace */ @@ -1612,7 +1653,7 @@ xsddata: /* XSD:something */ ; -// JSON encoder +// JSON attributes, with 'JSON:' prefix (legacy attributes) XJsonDef: XOptSpaces XKWjson XOptSpaces ':' XOptSpaces XJsonAttribute XOptSpaces ; @@ -1632,7 +1673,10 @@ XOmitAsNull: ; XNameAs: - XKWname XSpaces XKWas XSpaces XJsonAlias { jsonstruct->alias = $5; } + XKWname XSpaces XKWas XSpaces XJsonAlias { + Free(jsonstruct->alias); + jsonstruct->alias = $5; + } ; XJsonAlias: // include all keywords, so they can be used as aliases for fields, too @@ -1694,6 +1738,47 @@ XSpace: | '\t' ; + +// JSON attributes with no prefix (standard-compliant attributes) +JSONattributes: + JSONattribute { json_f = true; } +; + +JSONattribute: + JOmitAsNull +/* the name as '...' is handled in the XER attributes section */ +| JAsValue +| JDefault +| JExtend +| JMetainfoForUnbound +| JAsNumber +; + +JOmitAsNull: + XOmitKeyword XKWas XNullKeyword { jsonstruct->omit_as_null = true; } +; + +JAsValue: + XAsValueKeyword { jsonstruct->as_value = true; } +; + +JDefault: + XKWdefault XOptSpaces XJsonValue XOptSpaces { jsonstruct->default_value = $3; } +; + +JExtend: + XKWextend XOptSpaces XJsonValue XOptSpaces ':' XOptSpaces XJsonValue XOptSpaces + { jsonstruct->schema_extensions.add(new JsonSchemaExtension($3, $7)); } +; + +JMetainfoForUnbound: + XKWmetainfo XKWfor XKWunbound { jsonstruct->metainfo_unbound = true; } +; + +JAsNumber: + XKWas XKWnumber { jsonstruct->as_number = true; } +; + %% /* parse_rawAST(), which calls our rawAST_parse, is over in rawASST.l */ diff --git a/function_test/Semantic_Analyser/encode/encode_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_SE.ttcn index c592d113bc97510439d27d5047f921a5ee462144..b9014b54cb96ffa314219e4aeaaa6af3980d863e 100644 --- a/function_test/Semantic_Analyser/encode/encode_SE.ttcn +++ b/function_test/Semantic_Analyser/encode/encode_SE.ttcn @@ -32,7 +32,8 @@ type record Rec3 { //^In type definition// } with { encode "JSON"; - variant "name as uncapitalized"; //Variant attribute is not related to JSON encoding// + variant "attribute"; //Variant attribute is not related to JSON encoding// + variant "name as uncapitalized"; //Variant attribute is not related to JSON encoding// //This format is not supported for the JSON codec// } type record Rec4 { //^In type definition// diff --git a/regression_test/json/Types.ttcn b/regression_test/json/Types.ttcn index c08d85680238c069e13461af087773a9e6f11746..e802689d21e618c6edf978ce34d0585e58ada78c 100644 --- a/regression_test/json/Types.ttcn +++ b/regression_test/json/Types.ttcn @@ -160,7 +160,7 @@ type union Thing { } prod2val } with { variant "JSON:as value"; - variant (prod2val.productID) "JSON:name as code"; + variant (prod2val.productID) "name as 'code'"; variant(unival) "JSON:as value"; } @@ -213,8 +213,8 @@ type record OptionalUnions { Thing uniTtcn optional, AsnThing uniAsn optional } with { - variant(uniTtcn) "JSON: omit as null"; - variant(uniAsn) " JSON: omit as null "; + variant(uniTtcn) "omit as null"; + variant(uniAsn) " omit as null "; } type record MetainfoRecord { @@ -262,7 +262,7 @@ type set of MetainfoRecord MetainfoSetOf with { variant "JSON: metainfo for unbound"; } type float MetainfoArray[3] -with { variant "JSON: metainfo for unbound"; } +with { variant "metainfo for unbound"; } type record RecAsValue { integer field @@ -288,7 +288,7 @@ type set SetWithAsValueFields { with { variant (uni) "JSON: as value"; variant (rec) "JSON: as value"; - variant (list[-]) "JSON: as value"; + variant (list[-]) "asValue"; } type record RecWithAsNumber { @@ -297,7 +297,7 @@ type record RecWithAsNumber { } with { variant (lengths[-]) "JSON: as number"; - variant (days[-]) "JSON: as number"; + variant (days[-]) "as number"; } type union Uni522660 { @@ -313,8 +313,8 @@ type record DefaultEmptyStructs { } with { variant (r) "JSON: default({})"; - variant (s) "JSON: default({})"; - variant (ro) "JSON: default({})"; + variant (s) "default({})"; + variant (ro) "default({})"; variant (so) "JSON: default({})"; } diff --git a/regression_test/portTranslation/PortTranslation.ttcn b/regression_test/portTranslation/PortTranslation.ttcn index ad8db749bf631da956ac3b920f4eda3d64b9b1c6..314cf21914d56dbb215a9d21683caf4bb96487b4 100644 --- a/regression_test/portTranslation/PortTranslation.ttcn +++ b/regression_test/portTranslation/PortTranslation.ttcn @@ -758,4 +758,4 @@ module PortTranslation { execute(tc_receive_fragmented()); } -} \ No newline at end of file +} diff --git a/regression_test/ttcn2json/one.ttcn b/regression_test/ttcn2json/one.ttcn index 7164a19cdfa2389661f1496759cd7e303fe9a143..e44dd799fb1859f40394aa876abefa1815e92635 100644 --- a/regression_test/ttcn2json/one.ttcn +++ b/regression_test/ttcn2json/one.ttcn @@ -29,7 +29,7 @@ type set Set { } with { variant(numbr) " JSON : default (-infinity) "; variant(buul) " JSON:omit as null "; - variant(os) "JSON:extend(MSB):(first) "; + variant(os) "extend(MSB):(first) "; } type union Uni {