Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Arpad Lovassy
titan.core
Commits
3f84031e
Commit
3f84031e
authored
Jan 29, 2016
by
Elemer Lelik
Browse files
Sync with 5.4.2
parent
51fa56b9
Changes
344
Expand all
Hide whitespace changes
Inline
Side-by-side
Install/.gitignore
deleted
100644 → 0
View file @
51fa56b9
!Makefile
\ No newline at end of file
Install/Makefile
deleted
100644 → 0
View file @
51fa56b9
# Makefile for pseudoinstall
TOP
:=
..
include
$(TOP)/Makefile.cfg
all run
:
$(ABS_SRC)
/../pseudoinstall
# Should this delete ?
clean distclean
:
;
# definitely do-nothing
dep install
:
;
# All targets are phony
.PHONY
:
all run clean distclean dep install
export
OPENSSL_DIR
XMLDIR
common/JSON_Tokenizer.cc
View file @
3f84031e
...
...
@@ -379,6 +379,11 @@ int JSON_Tokenizer::put_next_token(json_token_t p_token, const char* p_token_str
return
buf_len
-
start_len
;
}
void
JSON_Tokenizer
::
put_raw_data
(
const
char
*
p_data
,
size_t
p_len
)
{
buf_ptr
=
mputstrn
(
buf_ptr
,
p_data
,
p_len
);
buf_len
+=
p_len
;
}
char
*
convert_to_json_string
(
const
char
*
str
)
{
...
...
common/JSON_Tokenizer.hh
View file @
3f84031e
...
...
@@ -158,6 +158,11 @@ public:
* @return The number of characters added to the JSON document */
int
put_next_token
(
json_token_t
p_token
,
const
char
*
p_token_str
=
0
);
/** Adds raw data to the end of the buffer.
* @param p_data [in] Pointer to the beginning of the data
* @param p_len [in] Length of the data in bytes */
void
put_raw_data
(
const
char
*
p_data
,
size_t
p_len
);
};
// class JSON_Tokenizer
// A dummy JSON tokenizer, use when there is no actual JSON document
...
...
common/version.h
View file @
3f84031e
...
...
@@ -11,7 +11,7 @@
/* Version numbers */
#define TTCN3_MAJOR 5
#define TTCN3_MINOR 4
#define TTCN3_PATCHLEVEL
1
#define TTCN3_PATCHLEVEL
2
//#define TTCN3_BUILDNUMBER 0
/* The aggregated version number must be set manually since some stupid
...
...
@@ -22,7 +22,7 @@
* TTCN3_VERSION = TTCN3_MAJOR * 1000000 + TTCN3_MINOR * 10000 +
* TTCN3_PATCHLEVEL * 100 + TTCN3_BUILDNUMBER
*/
#define TTCN3_VERSION 5040
1
#define TTCN3_VERSION 5040
2
/* A monotonically increasing version number.
* An official release is deemed to have the highest possible build number (99)
...
...
compiler2/AST.cc
View file @
3f84031e
...
...
@@ -32,6 +32,8 @@ namespace Common {
// =================================
// ===== Modules
// =================================
vector
<
Modules
::
type_enc_t
>
Modules
::
delayed_type_enc_v
;
Modules
::
Modules
()
:
Node
(),
mods_v
(),
mods_m
()
...
...
@@ -150,6 +152,14 @@ namespace Common {
mods_v
[
i
]
->
chk_recursive
(
checked_modules
);
}
checked_modules
.
clear
();
// run delayed Type::chk_coding() calls
if
(
!
delayed_type_enc_v
.
empty
())
{
for
(
size_t
i
=
0
;
i
<
delayed_type_enc_v
.
size
();
++
i
)
{
delayed_type_enc_v
[
i
]
->
t
->
chk_coding
(
delayed_type_enc_v
[
i
]
->
enc
,
true
);
delete
delayed_type_enc_v
[
i
];
}
delayed_type_enc_v
.
clear
();
}
}
void
Modules
::
chk_top_level_pdus
()
...
...
@@ -270,6 +280,14 @@ namespace Common {
mods_v
[
i
]
->
generate_json_schema
(
json
,
json_refs
);
}
}
void
Modules
::
delay_type_encode_check
(
Type
*
p_type
,
bool
p_encode
)
{
type_enc_t
*
elem
=
new
type_enc_t
;
elem
->
t
=
p_type
;
elem
->
enc
=
p_encode
;
delayed_type_enc_v
.
add
(
elem
);
}
// =================================
...
...
compiler2/AST.hh
View file @
3f84031e
...
...
@@ -77,6 +77,13 @@ namespace Common {
/** Containers to store the modules. */
vector
<
Module
>
mods_v
;
map
<
string
,
Module
>
mods_m
;
/** Contains info needed for delayed type encoding checks */
struct
type_enc_t
{
Type
*
t
;
bool
enc
;
};
static
vector
<
type_enc_t
>
delayed_type_enc_v
;
/** Not implemented */
Modules
(
const
Modules
&
p
);
...
...
@@ -125,6 +132,13 @@ namespace Common {
* @param json_refs map of JSON documents containing the references and function
* info related to each type */
void
generate_json_schema
(
JSON_Tokenizer
&
json
,
map
<
Type
*
,
JSON_Tokenizer
>&
json_refs
);
/** Called if a Type::chk_coding() call could not be resolved (because the
* needed custom coding function was not found yet, but it might be among
* the functions that have not been checked yet).
* This stores the info needed to call the function again after everything
* else has been checked. */
static
void
delay_type_encode_check
(
Type
*
p_type
,
bool
p_encode
);
};
/**
...
...
compiler2/Type.cc
View file @
3f84031e
This diff is collapsed.
Click to expand it.
compiler2/Type.hh
View file @
3f84031e
...
...
@@ -180,7 +180,8 @@ namespace Common {
CT_RAW
,
/**< TTCN-3 RAW */
CT_TEXT
,
/**< TTCN-3 TEXT */
CT_XER
,
/**< ASN.1 XER */
CT_JSON
/**< TTCN-3 JSON */
CT_JSON
,
/**< TTCN-3 JSON */
CT_CUSTOM
/**< user defined encoding */
};
/** selector for value checking algorithms */
...
...
@@ -548,10 +549,13 @@ namespace Common {
* \p p_right_chain are there to prevent infinite recursion.
* \p p_left_chain contains the type chain of the left operand from the
* "root" type to this point in the type's structure. \p p_right_chain
* is the same for the right operand. */
* is the same for the right operand.
* \p p_is_inline_template indicates that the conversion is requested for an
* inline template. Type conversion code is not needed in this case. */
bool
is_compatible
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
/** Check if the restrictions of a T_SEQOF/T_SETOF are "compatible" with
* the given type \a p_type. Can be called only as a T_SEQOF/T_SETOF.
* Currently, used for structured types only. \a p_type can be any kind
...
...
@@ -572,25 +576,33 @@ namespace Common {
* \p p_right_chain are there to prevent infinite recursion.
* \p p_left_chain contains the type chain of the left operand from the
* "root" type to this point in the type's structure. \p p_right_chain
* is the same for the right operand. */
* is the same for the right operand.
* \p p_is_inline_template indicates that the conversion is requested for an
* inline template. Type conversion code is not needed in this case. */
bool
is_compatible_record
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
bool
is_compatible_record_of
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
bool
is_compatible_set
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
bool
is_compatible_set_of
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
bool
is_compatible_array
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
bool
is_compatible_choice_anytype
(
Type
*
p_type
,
TypeCompatInfo
*
p_info
,
TypeChain
*
p_left_chain
=
NULL
,
TypeChain
*
p_right_chain
=
NULL
);
TypeChain
*
p_right_chain
=
NULL
,
bool
p_is_inline_template
=
false
);
public:
/** Returns whether this type is identical to \a p_type from TTCN-3 point
* of view. Note: This relation is symmetric. The function returns true
...
...
@@ -607,7 +619,10 @@ namespace Common {
/** Returns true if this is a list type (string, rec.of, set.of or array */
bool
is_list_type
(
bool
allow_array
);
void
chk_coding
(
bool
encode
);
/** Sets the encoding or decoding function for the type (in case of custom
* encoding). */
void
set_coding_function
(
bool
encode
,
const
string
&
function_name
);
void
chk_coding
(
bool
encode
,
bool
delayed
=
false
);
bool
is_coding_by_function
()
const
;
const
string
&
get_coding
(
bool
encode
)
const
;
private:
...
...
@@ -961,13 +976,13 @@ namespace Common {
bool
hasVariantAttrs
();
/** Returns whether the type has the encoding attribute specified by
* the parameter (either in its own 'with' statement or in the module's) */
bool
hasEncodeAttr
(
const
MessageEncodingType_t
encoding_
typ
e
);
bool
hasEncodeAttr
(
const
char
*
encoding_
nam
e
);
/** Returns whether \a this can be encoded according to rules
* \a p_encoding.
* @note Should be called only during code generation, after the entire
* AST has been checked, or else the compiler might choke on code like:
* type MyRecordOfType[-] ElementTypeAlias; */
bool
has_encoding
(
const
MessageEncodingType_t
encoding_type
);
bool
has_encoding
(
const
MessageEncodingType_t
encoding_type
,
const
string
*
custom_encoding
=
NULL
);
/** Generates the C++ equivalent class(es) of the type. */
void
generate_code
(
output_struct
*
target
);
size_t
get_codegen_index
(
size_t
index
);
...
...
@@ -1171,6 +1186,10 @@ namespace Common {
void
generate_json_schema_ref
(
JSON_Tokenizer
&
json
);
JsonAST
*
get_json_attributes
()
const
{
return
jsonattrib
;
}
/** Returns true if the type is a union with the JSON "as value" attribute, or
* if a union with this attribute is embedded in the type. */
bool
has_as_value_union
();
};
/** @} end of AST_Type group */
...
...
compiler2/Type_chk.cc
View file @
3f84031e
...
...
@@ -113,7 +113,7 @@ void Type::chk()
textattrib
=
new
TextAST
;
if
(
!
xerattrib
&&
hasVariantAttrs
()
&&
hasNeedofXerAttrs
())
xerattrib
=
new
XerAttributes
;
if
(
!
jsonattrib
&&
(
hasVariantAttrs
()
||
hasEncodeAttr
(
CT_JSON
)
||
hasNeedofJsonAttrs
()))
{
if
(
!
jsonattrib
&&
(
hasVariantAttrs
()
||
hasEncodeAttr
(
get_encoding_name
(
CT_JSON
)
)
||
hasNeedofJsonAttrs
()))
{
jsonattrib
=
new
JsonAST
;
}
break
;
...
...
@@ -1034,7 +1034,7 @@ void Type::chk_xer_embed_values(int num_attributes)
{
Type
*
const
last
=
get_type_refd_last
();
enum
complaint_type
{
ALL_GOOD
,
OPTIONAL_OR
_DEFAULT
,
UNTAGGED_EMBEDVAL
,
enum
complaint_type
{
ALL_GOOD
,
HAVE
_DEFAULT
,
UNTAGGED_EMBEDVAL
,
NOT_SEQUENCE
,
EMPTY_SEQUENCE
,
FIRST_NOT_SEQOF
,
SEQOF_NOT_STRING
,
SEQOF_BAD_LENGTH
,
UNTAGGED_OTHER
}
;
complaint_type
complaint
=
ALL_GOOD
;
...
...
@@ -1050,9 +1050,9 @@ void Type::chk_xer_embed_values(int num_attributes)
}
CompField
*
cf0
=
last
->
get_comp_byIndex
(
0
);
cf0t
=
cf0
->
get_type
()
->
get_type_refd_last
();
if
(
cf0
->
get_is_optional
()
||
cf0
->
has_default
())
{
complaint
=
OPTIONAL_OR
_DEFAULT
;
break
;
// 25.2.1 first component cannot
be optional or
have default
if
(
cf0
->
has_default
())
{
complaint
=
HAVE
_DEFAULT
;
break
;
// 25.2.1 first component cannot have default
}
switch
(
cf0t
->
get_typetype
())
{
// check the first component
...
...
@@ -1119,10 +1119,10 @@ void Type::chk_xer_embed_values(int num_attributes)
case
EMPTY_SEQUENCE
:
case
FIRST_NOT_SEQOF
:
case
SEQOF_NOT_STRING
:
case
OPTIONAL_OR
_DEFAULT
:
case
HAVE
_DEFAULT
:
error
(
"A type with EMBED-VALUES must be a sequence type. "
"The first component of the sequence shall be SEQUENCE OF UTF8String "
"and shall not be marked
OPTIONAL or
DEFAULT"
);
"and shall not be marked DEFAULT"
);
break
;
case
SEQOF_BAD_LENGTH
:
cf0t
->
error
(
"Wrong length of SEQUENCE-OF for EMBED-VALUES, should be %lu"
,
...
...
@@ -1139,7 +1139,6 @@ void Type::chk_xer_embed_values(int num_attributes)
}
// switch(complaint)
}
// if complaint and embedValues
}
/** Wraps a C string but compares by contents, not by pointer */
class
stringval
{
const
char
*
str
;
...
...
@@ -1559,11 +1558,14 @@ void Type::chk_xer_use_nil()
enum
complaint_type
{
ALL_GOOD
,
NO_CONTROLNS
,
NOT_SEQUENCE
,
EMPTY_SEQUENCE
,
UNTAGGED_USENIL
,
COMPONENT_NOT_ATTRIBUTE
,
LAST_IS_ATTRIBUTE
,
LAST_NOT_OPTIONAL
,
INCOMPATIBLE
,
WRONG_OPTIONAL_TYPE
,
EMBED_CHARENC
};
LAST_NOT_OPTIONAL
,
INCOMPATIBLE
,
WRONG_OPTIONAL_TYPE
,
EMBED_CHARENC
,
NOT_COMPATIBLE_WITH_USEORDER
,
BAD_ENUM
,
FIRST_OPTIONAL
,
NOTHING_TO_ORDER
,
FIRST_NOT_RECORD_OF_ENUM
,
ENUM_GAP
};
complaint_type
complaint
=
ALL_GOOD
;
CompField
*
cf
=
0
;
CompField
*
cf_last
=
0
;
const
char
*
ns
,
*
prefix
;
Type
*
the_enum
=
0
;
my_scope
->
get_scope_mod
()
->
get_controlns
(
ns
,
prefix
);
if
(
!
prefix
)
complaint
=
NO_CONTROLNS
;
// don't bother checking further
...
...
@@ -1605,6 +1607,57 @@ void Type::chk_xer_use_nil()
if
(
!
cf_last
->
get_is_optional
())
{
complaint
=
LAST_NOT_OPTIONAL
;
}
if
(
xerattrib
->
useOrder_
&&
cft
->
get_type_refd_last
()
->
get_typetype
()
!=
T_SEQ_A
&&
cft
->
get_type_refd_last
()
->
get_typetype
()
!=
T_SEQ_T
){
complaint
=
NOT_COMPATIBLE_WITH_USEORDER
;
}
else
if
(
xerattrib
->
useOrder_
)
{
//This check needed, because if the record that has useOrder only
//has one field that is a sequence type, then the useNilPossible
//would be always true, that would lead to incorrect code generation.
Type
*
inner
=
cft
->
get_type_refd_last
();
size_t
useorder_index
=
xerattrib
->
embedValues_
;
CompField
*
uo_field
=
last
->
get_comp_byIndex
(
useorder_index
);
Type
*
uot
=
uo_field
->
get_type
();
if
(
uot
->
get_type_refd_last
()
->
typetype
==
T_SEQOF
)
{
the_enum
=
uot
->
get_ofType
()
->
get_type_refd_last
();
if
(
the_enum
->
typetype
!=
T_ENUM_A
&&
the_enum
->
typetype
!=
T_ENUM_T
){
complaint
=
FIRST_NOT_RECORD_OF_ENUM
;
break
;
}
else
if
(
uo_field
->
get_is_optional
()
||
uo_field
->
get_defval
()
!=
0
)
{
complaint
=
FIRST_OPTIONAL
;
break
;
}
size_t
expected_enum_items
=
inner
->
get_nof_comps
();
size_t
enum_index
=
0
;
if
(
expected_enum_items
==
0
)
complaint
=
NOTHING_TO_ORDER
;
else
if
(
the_enum
->
u
.
enums
.
eis
->
get_nof_eis
()
!=
expected_enum_items
)
complaint
=
BAD_ENUM
;
else
for
(
size_t
i
=
0
;
i
<
expected_enum_items
;
++
i
)
{
CompField
*
inner_cf
=
inner
->
get_comp_byIndex
(
i
);
Type
*
inner_cft
=
inner_cf
->
get_type
();
if
(
inner_cft
->
xerattrib
&&
inner_cft
->
xerattrib
->
attribute_
)
continue
;
// Found a non-attribute component. Its name must match an enumval
const
Identifier
&
field_name
=
inner_cf
->
get_name
();
const
EnumItem
*
ei
=
the_enum
->
get_ei_byIndex
(
enum_index
);
const
Identifier
&
enum_name
=
ei
->
get_name
();
if
(
field_name
!=
enum_name
)
{
// X.693amd1 35.2.2.1 and 35.2.2.2
complaint
=
BAD_ENUM
;
break
;
}
Value
*
v
=
ei
->
get_value
();
const
int_val_t
*
ival
=
v
->
get_val_Int
();
const
Int
enumval
=
ival
->
get_val
();
if
((
size_t
)
enumval
!=
enum_index
)
{
complaint
=
ENUM_GAP
;
// 35.2.2.3
break
;
}
++
enum_index
;
}
}
}
if
(
cft
->
xerattrib
)
{
if
(
cft
->
xerattrib
->
attribute_
...
...
@@ -1615,9 +1668,10 @@ void Type::chk_xer_use_nil()
if
(
has_ae
(
cft
->
xerattrib
)
||
has_aa
(
cft
->
xerattrib
)
||
cft
->
xerattrib
->
defaultForEmpty_
!=
0
||
cft
->
xerattrib
->
embedValues_
||
cft
->
xerattrib
->
untagged_
||
cft
->
xerattrib
->
useNil_
||
cft
->
xerattrib
->
useOrder_
||
cft
->
xerattrib
->
defaultForEmpty_
!=
0
||
cft
->
xerattrib
->
untagged_
||
cft
->
xerattrib
->
useNil_
||
cft
->
xerattrib
->
useOrder_
||
cft
->
xerattrib
->
useType_
)
{
// or PI-OR-COMMENT
complaint
=
INCOMPATIBLE
;
// 33.2.3
}
...
...
@@ -1683,7 +1737,7 @@ void Type::chk_xer_use_nil()
case
INCOMPATIBLE
:
cf_last
->
error
(
"The OPTIONAL component of USE-NIL cannot have any of the "
"following encoding instructions: ANY-ATTRIBUTES, ANY-ELEMENT, "
"DEFAULT-FOR-EMPTY,
EMBED-VALUES,
PI-OR-COMMENT, UNTAGGED, "
"DEFAULT-FOR-EMPTY, PI-OR-COMMENT, UNTAGGED, "
"USE-NIL, USE-ORDER, USE-TYPE."
);
break
;
case
WRONG_OPTIONAL_TYPE
:
...
...
@@ -1696,6 +1750,33 @@ void Type::chk_xer_use_nil()
"the optional component supporting USE-NIL shall not be "
"a character-encodable type."
);
break
;
case
NOT_COMPATIBLE_WITH_USEORDER
:
cf_last
->
error
(
"The OTIONAL component of USE-NIL must be "
"a SEQUENCE/record when USE-ORDER is set for the parent type."
);
break
;
case
BAD_ENUM
:
if
(
!
the_enum
)
FATAL_ERROR
(
"Type::chk_xer_use_order()"
);
the_enum
->
error
(
"Enumeration items should match the"
" non-attribute components of the field %s"
,
cf_last
->
get_name
().
get_dispname
().
c_str
());
break
;
case
FIRST_OPTIONAL
:
error
(
"The record-of for USE-ORDER shall not be marked"
" OPTIONAL or DEFAULT"
);
// X.693amd1 35.2.3
break
;
case
NOTHING_TO_ORDER
:
error
(
"The component (%s) should have at least one non-attribute"
" component if USE-ORDER is present"
,
cf_last
->
get_name
().
get_dispname
().
c_str
());
break
;
case
FIRST_NOT_RECORD_OF_ENUM
:
error
(
"The type with USE-ORDER should have a component "
"which is a record-of enumerated"
);
break
;
case
ENUM_GAP
:
if
(
!
the_enum
)
FATAL_ERROR
(
"Type::chk_xer_use_order()"
);
the_enum
->
error
(
"Enumeration values must start at 0 and have no gaps"
);
break
;
}
// switch
}
// if USE-NIL
}
...
...
@@ -1740,7 +1821,7 @@ void Type::chk_xer_use_order(int num_attributes)
if
(
xerattrib
->
useNil_
)
{
// useNil in addition to useOrder
// This is an additional complication because USE-ORDER
// will affect the optional component, rather than the type itself
CompField
*
cf
=
get_comp_byIndex
(
ncomps
-
1
);
CompField
*
cf
=
last
->
get_comp_byIndex
(
ncomps
-
1
);
sequence_type
=
cf
->
get_type
()
->
get_type_refd_last
();
if
(
sequence_type
->
typetype
==
T_SEQ_T
||
sequence_type
->
typetype
==
T_SEQ_A
)
{
...
...
compiler2/Type_codegen.cc
View file @
3f84031e
...
...
@@ -2081,7 +2081,8 @@ void Type::generate_code_Fat(output_struct *target)
}
fdef
.
runs_on_self
=
u
.
fatref
.
runs_on
.
self
?
TRUE
:
FALSE
;
fdef
.
is_startable
=
u
.
fatref
.
is_startable
;
fdef
.
formal_par_list
=
u
.
fatref
.
fp_list
->
generate_code
(
memptystr
());
fdef
.
formal_par_list
=
u
.
fatref
.
fp_list
->
generate_code
(
memptystr
(),
u
.
fatref
.
fp_list
->
get_nof_fps
());
u
.
fatref
.
fp_list
->
generate_code_defval
(
target
);
fdef
.
actual_par_list
=
u
.
fatref
.
fp_list
->
generate_code_actual_parlist
(
memptystr
(),
""
);
...
...
compiler2/Value.cc
View file @
3f84031e
...
...
@@ -31,6 +31,7 @@
#include
"ttcn3/Attributes.hh"
#include
"../common/JSON_Tokenizer.hh"
#include
"ttcn3/Ttcn2Json.hh"
#include
<math.h>
#include
<regex.h>
...
...
@@ -9786,8 +9787,8 @@ error:
case
Ttcn
::
Template
::
TEMPLATE_INVOKE
:
break
;
// assume self-ref can't happen
case
Ttcn
::
Template
::
TEMPLATE_ERROR
:
FATAL_ERROR
(
"Value::chk_expr_self_ref_templ()"
);
break
;
// not reached
//
FATAL_ERROR("Value::chk_expr_self_ref_templ()");
break
;
// default:
// FATAL_ERROR("todo ttype %d", t->get_templatetype());
// break; // and hope for the best
...
...
@@ -12306,8 +12307,9 @@ error:
if
(
expr2
.
postamble
)
expr
->
postamble
=
mputstr
(
expr
->
postamble
,
expr2
.
postamble
);
}
else
expr
->
expr
=
mputprintf
(
expr
->
expr
,
"%s(%s)"
,
gov_last
->
get_coding
(
true
).
c_str
(),
expr2
.
expr
);
expr
->
expr
=
mputprintf
(
expr
->
expr
,
"%s(%s%s)"
,
gov_last
->
get_coding
(
true
).
c_str
(),
expr2
.
expr
,
is_templ
?
".valueof()"
:
""
);
Code
::
free_expr
(
&
expr2
);
}
...
...
@@ -12626,49 +12628,10 @@ error:
return
str
;
}
/** This type contains the JSON encoding type of an omitted optional field */
enum
omitted_json_value_t
{
NOT_OMITTED
,
// the field is not omitted
OMITTED_ABSENT
,
// the omitted field is not present in the JSON object
OMITTED_NULL
// the omitted field is set to 'null' in the JSON object
};
/** JSON code for omitted optional fields of can be generated in 2 ways:
* - the field is not present in the JSON object or
* - the field is present and its value is 'null'.
* Because of this all record/set values containing omitted fields have 2^N
* possible JSON encodings, where N is the number of omitted fields.
*
* This function helps go through all the possible encodings, by generating
* the next combination from a previous one.
*
* The algorithm is basically adding 1 to a binary number (where OMITTED_ABSENT
* is zero, OMITTED_NULL is one, all NOT_OMITTEDs are ignored and the first bit
* is the least significant bit).
*
* Usage: generate the first combination, where all omitted fields are absent
* (=all zeros), and keep calling this function until the last combination
* (where all omitted fields are 'null', = all ones) is reached.
*
* @return true, if the next combination was successfully generated, or
* false, when called with the last combination */
static
bool
next_omitted_json_combo
(
int
*
omitted_fields
,
size_t
len
)
{
for
(
size_t
i
=
0
;
i
<
len
;
++
i
)
{
if
(
omitted_fields
[
i
]
==
OMITTED_ABSENT
)
{
omitted_fields
[
i
]
=
OMITTED_NULL
;
for
(
size_t
j
=
0
;
j
<
i
;
++
j
)
{
if
(
omitted_fields
[
j
]
==
OMITTED_NULL
)
{
omitted_fields
[
j
]
=
OMITTED_ABSENT
;
}
}
return
true
;
}
}
return
false
;
}
void
Value
::
generate_json_value
(
JSON_Tokenizer
&
json
,
bool
allow_special_float
/* = true */
)
void
Value
::
generate_json_value
(
JSON_Tokenizer
&
json
,
bool
allow_special_float
,
/* = true */
bool
union_value_list
,
/* = false */
Ttcn
::
JsonOmitCombination
*
omit_combo
/* = NULL */
)
{
switch
(
valuetype
)
{
case
V_INT
:
...
...
@@ -12727,7 +12690,8 @@ error:
json
.
put_next_token
(
JSON_TOKEN_ARRAY_START
);
if
(
!
u
.
val_vs
->
is_indexed
())
{
for
(
size_t
i
=
0
;
i
<
u
.
val_vs
->
get_nof_vs
();
++
i
)
{
u
.
val_vs
->
get_v_byIndex
(
i
)
->
generate_json_value
(
json
);
u
.
val_vs
->
get_v_byIndex
(
i
)
->
generate_json_value
(
json
,
allow_special_float
,
union_value_list
,
omit_combo
);
}
}
else
{
...
...
@@ -12735,7 +12699,8 @@ error:
// look for the entry with index equal to i
for
(
size_t
j
=
0
;
j
<
u
.
val_vs
->
get_nof_ivs
();
++
j
)
{
if
(
u
.
val_vs
->
get_iv_byIndex
(
j
)
->
get_index
()
->
get_val_Int
()
->
get_val
()
==
(
Int
)
i
)
{
u
.
val_vs
->
get_iv_byIndex
(
j
)
->
get_value
()
->
generate_json_value
(
json
);
u
.
val_vs
->
get_iv_byIndex
(
j
)
->
get_value
()
->
generate_json_value
(
json
,
allow_special_float
,
union_value_list
,
omit_combo
);
break
;
}
}
...
...
@@ -12748,49 +12713,41 @@ error:
// omitted fields have 2 possible JSON values (the field is absent, or it's
// present with value 'null'), each combination of omitted values must be
// generated
if
(
omit_combo
==
NULL
)
{
FATAL_ERROR
(
"Value::generate_json_value - no combo"
);
}
size_t
len
=
get_nof_comps
();
int
*
omitted_fields
=
new
int
[
len
];
// stores one combination
// generate the JSON object from the present combination
json
.
put_next_token
(
JSON_TOKEN_OBJECT_START
);
for
(
size_t
i
=
0
;
i
<
len
;
++
i
)
{
if
(
get_se_comp_byIndex
(
i
)
->
get_value
()
->
valuetype
==
V_OMIT
)
{
// all omitted fields are absent in the first combination
omitted_fields
[
i
]
=
OMITTED_ABSENT
;
Ttcn
::
JsonOmitCombination
::
omit_state_t
state
=
omit_combo
->
get_state
(
this
,
i
);
if
(
state
==
Ttcn
::
JsonOmitCombination
::
OMITTED_ABSENT
)
{
// the field is absent, don't insert anything
continue
;
}
// use the field's alias, if it has one
const
char
*
alias
=
NULL
;
if
(
my_governor
!=
NULL
)
{
JsonAST
*
field_attrib
=
my_governor
->
get_comp_byName
(
get_se_comp_byIndex
(
i
)
->
get_name
())
->
get_type
()
->
get_json_attributes
();
if
(
field_attrib
!=
NULL
)
{
alias
=
field_attrib
->
alias
;
}
}
json
.
put_next_token
(
JSON_TOKEN_NAME
,
(
alias
!=
NULL
)
?
alias
:
get_se_comp_byIndex
(
i
)
->
get_name
().
get_ttcnname
().
c_str
());
if
(
state
==
Ttcn
::
JsonOmitCombination
::
OMITTED_NULL
)
{
json
.
put_next_token
(
JSON_TOKEN_LITERAL_NULL
);
}
else
{
omitted_fields
[
i
]
=
NOT_OMITTED
;
get_se_comp_byIndex
(
i
)
->
get_value
()
->
generate_json_value
(
json
,
allow_special_float
,
union_value_list
,
omit_combo
);
}
}
do
{
// generate the JSON object from the present combination
json
.
put_next_token
(
JSON_TOKEN_OBJECT_START
);
for
(
size_t
i
=
0
;
i
<
len
;
++
i
)
{
if
(
omitted_fields
[
i
]
==
OMITTED_ABSENT
)
{
// the field is absent, don't insert anything
continue
;
}
// use the field's alias, if it has one
const
char
*
alias
=
NULL
;
if
(
my_governor
!=
NULL
)
{
JsonAST
*
field_attrib
=
my_governor
->
get_comp_byName
(
get_se_comp_byIndex
(
i
)
->
get_name
())
->
get_type
()
->
get_json_attributes
();
if
(
field_attrib
!=
NULL
)
{
alias
=
field_attrib
->
alias
;
}
}
json
.
put_next_token
(
JSON_TOKEN_NAME
,
(
alias
!=
NULL
)
?
alias
:
get_se_comp_byIndex
(
i
)
->
get_name
().
get_ttcnname
().
c_str
());
if
(
omitted_fields
[
i
]
==
OMITTED_NULL
)
{
json
.
put_next_token
(
JSON_TOKEN_LITERAL_NULL
);
}
else
{
get_se_comp_byIndex
(
i
)
->
get_value
()
->
generate_json_value
(
json
);
}
}
json
.
put_next_token
(
JSON_TOKEN_OBJECT_END
);
}
// generate the next combination, until all combinations have been processed
while
(
next_omitted_json_combo
(
omitted_fields
,
len
));
json
.
put_next_token
(
JSON_TOKEN_OBJECT_END
);
break
;
}
case
V_CHOICE
:
{
bool
as_value
=
my_governor
!=
NULL
&&
bool
as_value
=
!
union_value_list
&&
my_governor
!=
NULL
&&