Commit bb4951ea authored by BenceJanosSzabo's avatar BenceJanosSzabo
Browse files

Implement ports with translation capability (part4) port variables and port clause (Bug 512359)



Change-Id: I6596a91c1ea4a5f8ee0bbccb95788db17a92e47d
Signed-off-by: default avatarBenceJanosSzabo <bence.janos.szabo@ericsson.com>
parent 582847f5
......@@ -1927,6 +1927,11 @@ namespace Common {
{
return 0;
}
Type *Assignment::get_PortType()
{
return 0;
}
void Assignment::chk_ttcn_id()
{
......
......@@ -18,6 +18,7 @@
* Kovacs, Ferenc
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Szalai, Gabor
* Zalanyi, Balazs Andor
......@@ -588,6 +589,9 @@ namespace Common {
/** Returns the component type referred by the 'runs on' clause of a
* TTCN-3 definition */
virtual Type *get_RunsOnType();
/** Returns the port type referred by the 'port' clause of a
* TTCN-3 function definition */
virtual Type *get_PortType();
/** Semantic check */
virtual void chk() = 0;
/** Checks whether the assignment has a valid TTCN-3 identifier,
......
......@@ -18,6 +18,7 @@
* Kovacs, Ferenc
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Tatarka, Gabor
*
......@@ -571,6 +572,12 @@ namespace Common {
if (parent_scope) return parent_scope->get_scope_runs_on();
else return 0;
}
Ttcn::PortScope *Scope::get_scope_port()
{
if (parent_scope) return parent_scope->get_scope_port();
else return 0;
}
Assignments *Scope::get_scope_asss()
{
......
......@@ -18,6 +18,7 @@
* Kovacs, Ferenc
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Tatarka, Gabor
* Zalanyi, Balazs Andor
......@@ -55,6 +56,7 @@ namespace Ttcn {
class FieldOrArrayRefs;
class ActualParList;
class RunsOnScope;
class PortScope;
class StatementBlock;
struct ErroneousDescriptor;
class ErroneousDescriptors;
......@@ -597,6 +599,9 @@ public:
/** Returns the scope unit of the hierarchy that belongs to a
* 'runs on' clause. */
virtual Ttcn::RunsOnScope *get_scope_runs_on();
/** Returns the scope unit of the hierarchy that belongs to a
* 'port' clause. */
virtual Ttcn::PortScope *get_scope_port();
/** Returns the assignments/module definitions scope. */
virtual Assignments *get_scope_asss();
/** Gets the module scope. This function returns this scope or a
......
......@@ -4556,7 +4556,7 @@ namespace Common {
maps = encode ? maps : inmaps;
maps->set_my_scope(this->get_my_scope());
// The first param should be true, the other is not important if the first is true
maps->chk(true, false);
maps->chk(this, true, false);
// look for coding settings
t = encode ? this : Type::get_pooltype(T_BSTR);
mapping = maps->get_mapping_byType(t);
......
......@@ -259,6 +259,7 @@ namespace Common {
OT_OCFT, ///< another Type (T_OCFT), ASN.1 obj.class field type
OT_TEMPLATE_INST, ///< a TemplateInstance (TTCN-3)
OT_RUNSON_SCOPE, ///< a RunsOnScope (TTCN-3)
OT_PORT_SCOPE, ///< a port scope
OT_EXC_SPEC, ///< exception Specification (ExcSpec)
OT_SIG_PAR, ///< signature parameter (SignatureParam)
OT_POOL ///< It's a pool type, owned by the type pool
......
......@@ -1212,6 +1212,77 @@ namespace Ttcn {
|| parent_scope->has_ass_withId(p_id);
}
// =================================
// ===== PortScope
// =================================
PortScope::PortScope(Type *p_porttype)
: Scope(), port_type(p_porttype)
{
if (!p_porttype || p_porttype->get_typetype() != Type::T_PORT)
FATAL_ERROR("PortScope::PortScope()");
port_type->set_ownertype(Type::OT_PORT_SCOPE, this);
PortTypeBody* ptb = p_porttype->get_PortBody();
if (!ptb)
FATAL_ERROR("PortScope::PortScope()");
vardefs = ptb->get_vardefs();
set_scope_name("port `" + p_porttype->get_fullname() + "'");
}
PortScope *PortScope::clone() const
{
FATAL_ERROR("PortScope::clone()");
}
void PortScope::chk_uniq()
{
if (!vardefs) return;
if (vardefs->get_nof_asss() == 0) return;
// do not perform this check if the port type is defined in the same
// module as the 'port' clause
if (parent_scope->get_scope_mod() == vardefs->get_scope_mod())
return;
size_t nof_defs = vardefs->get_nof_asss();
for (size_t i = 0; i < nof_defs; i++) {
Common::Assignment *vardef = vardefs->get_ass_byIndex(i);
const Identifier& id = vardef->get_id();
if (parent_scope->has_ass_withId(id)) {
vardef->warning("Imported port element definition `%s' hides a "
"definition at module scope", vardef->get_fullname().c_str());
Reference ref(0, id.clone());
Common::Assignment *hidden_ass = parent_scope->get_ass_bySRef(&ref);
hidden_ass->warning("Hidden definition `%s' is here",
hidden_ass->get_fullname().c_str());
}
}
}
PortScope *PortScope::get_scope_port()
{
return this;
}
Common::Assignment *PortScope::get_ass_bySRef(Ref_simple *p_ref)
{
if (!p_ref) FATAL_ERROR("Ttcn::PortScope::get_ass_bySRef()");
if (p_ref->get_modid()) return parent_scope->get_ass_bySRef(p_ref);
else {
const Identifier& id = *p_ref->get_id();
if (vardefs->has_local_ass_withId(id)) {
Common::Assignment* ass = vardefs->get_local_ass_byId(id);
if (!ass) FATAL_ERROR("Ttcn::PortScope::get_ass_bySRef()");
return ass;
} else return parent_scope->get_ass_bySRef(p_ref);
}
}
bool PortScope::has_ass_withId(const Identifier& p_id)
{
return vardefs->has_ass_withId(p_id)
|| parent_scope->has_ass_withId(p_id);
}
// =================================
// ===== FriendMod
// =================================
......@@ -2238,6 +2309,9 @@ namespace Ttcn {
for (size_t i = 0; i < runs_on_scopes.size(); i++)
delete runs_on_scopes[i];
runs_on_scopes.clear();
for (size_t i = 0; i < port_scopes.size(); i++)
delete port_scopes[i];
port_scopes.clear();
delete w_attrib_path;
}
......@@ -2766,7 +2840,15 @@ namespace Ttcn {
ret_val->chk_uniq();
return ret_val;
}
PortScope *Module::get_port_scope(Type *porttype)
{
PortScope *ret_val = new PortScope(porttype);
port_scopes.add(ret_val);
ret_val->set_parent_scope(asss);
ret_val->chk_uniq();
return ret_val;
}
void Module::dump(unsigned level) const
{
......@@ -6178,13 +6260,15 @@ namespace Ttcn {
// =================================
Def_Function::Def_Function(Identifier *p_id, FormalParList *p_fpl,
Reference *p_runs_on_ref, Type *p_return_type,
Reference *p_runs_on_ref, Reference *p_port_ref,
Type *p_return_type,
bool returns_template,
template_restriction_t p_template_restriction,
StatementBlock *p_block)
: Def_Function_Base(false, p_id, p_fpl, p_return_type, returns_template,
p_template_restriction),
runs_on_ref(p_runs_on_ref), runs_on_type(0), block(p_block),
runs_on_ref(p_runs_on_ref), runs_on_type(0),
port_ref(p_port_ref), port_type(0), block(p_block),
is_startable(false), transparent(false)
{
if (!p_block) FATAL_ERROR("Def_Function::Def_Function()");
......@@ -6194,6 +6278,7 @@ namespace Ttcn {
Def_Function::~Def_Function()
{
delete runs_on_ref;
delete port_ref;
delete block;
}
......@@ -6206,6 +6291,7 @@ namespace Ttcn {
{
Def_Function_Base::set_fullname(p_fullname);
if (runs_on_ref) runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>");
if (port_ref) port_ref->set_fullname(p_fullname + ".<port_type>");
block->set_fullname(p_fullname + ".<statement_block>");
}
......@@ -6216,6 +6302,7 @@ namespace Ttcn {
Def_Function_Base::set_my_scope(&bridgeScope);
if (runs_on_ref) runs_on_ref->set_my_scope(&bridgeScope);
if (port_ref) port_ref->set_my_scope(&bridgeScope);
block->set_my_scope(fp_list);
}
......@@ -6224,6 +6311,12 @@ namespace Ttcn {
if (!checked) chk();
return runs_on_type;
}
Type *Def_Function::get_PortType()
{
if (!checked) chk();
return port_type;
}
RunsOnScope *Def_Function::get_runs_on_scope(Type *comptype)
{
......@@ -6232,12 +6325,23 @@ namespace Ttcn {
return my_module->get_runs_on_scope(comptype);
}
PortScope *Def_Function::get_port_scope(Type *porttype)
{
Module *my_module = dynamic_cast<Module*>(my_scope->get_scope_mod());
if (!my_module) FATAL_ERROR("Def_Function::get_port_scope()");
return my_module->get_port_scope(porttype);
}
void Def_Function::chk()
{
if (checked) return;
checked = true;
Error_Context cntxt(this, "In function definition `%s'",
id->get_dispname().c_str());
// `runs on' clause and `port' clause are mutually exclusive
if (runs_on_ref && port_ref) {
runs_on_ref->error("A `runs on' and a `port' clause cannot be present at the same time.");
}
// checking the `runs on' clause
if (runs_on_ref) {
Error_Context cntxt2(runs_on_ref, "In `runs on' clause");
......@@ -6249,39 +6353,7 @@ namespace Ttcn {
fp_list->set_my_scope(runs_on_scope);
}
}
// checking the formal parameter list
fp_list->chk(asstype);
// checking of return type
if (return_type) {
Error_Context cntxt2(return_type, "In return type");
return_type->chk();
return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL,"function");
}
// decision of startability
is_startable = runs_on_ref != 0;
if (is_startable && !fp_list->get_startability()) is_startable = false;
if (is_startable && return_type && return_type->is_component_internal())
is_startable = false;
// checking of statement block
block->chk();
if (return_type) {
// checking the presence of return statements
switch (block->has_return()) {
case StatementBlock::RS_NO:
error("The function has return type, but it does not have any return "
"statement");
break;
case StatementBlock::RS_MAYBE:
error("The function has return type, but control might leave it "
"without reaching a return statement");
default:
break;
}
}
if (!semantic_check_only) {
fp_list->set_genname(get_genname());
block->set_code_section(GovernedSimple::CS_INLINE);
}
if (w_attrib_path) {
w_attrib_path->chk_global_attrib();
w_attrib_path->chk_no_qualif();
......@@ -6325,8 +6397,65 @@ namespace Ttcn {
}
}
chk_prototype();
// checking the `port' clause
if (port_ref) {
Error_Context cntxt2(port_ref, "In `port' clause");
Assignment *ass = port_ref->get_refd_assignment();
if (ass) {
port_type = ass->get_Type();
if (port_type) {
switch (port_type->get_typetype()) {
case Type::T_PORT: {
Scope *port_scope = get_port_scope(port_type);
port_scope->set_parent_scope(my_scope);
fp_list->set_my_scope(port_scope);
break; }
default:
port_ref->error(
"Reference `%s' does not refer to a port type.",
port_ref->get_dispname().c_str());
}
} else {
FATAL_ERROR("Def_Function::chk()");
}
}
}
// checking the formal parameter list
fp_list->chk(asstype);
// checking of return type
if (return_type) {
Error_Context cntxt2(return_type, "In return type");
return_type->chk();
return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL,"function");
}
// decision of startability
is_startable = runs_on_ref != 0;
if (is_startable && !fp_list->get_startability()) is_startable = false;
if (is_startable && return_type && return_type->is_component_internal())
is_startable = false;
// checking of statement block
block->chk();
if (return_type) {
// checking the presence of return statements
switch (block->has_return()) {
case StatementBlock::RS_NO:
error("The function has return type, but it does not have any return "
"statement");
break;
case StatementBlock::RS_MAYBE:
error("The function has return type, but control might leave it "
"without reaching a return statement");
default:
break;
}
}
if (!semantic_check_only) {
fp_list->set_genname(get_genname());
block->set_code_section(GovernedSimple::CS_INLINE);
}
}
bool Def_Function::chk_startable()
{
if (!checked) chk();
......@@ -6346,8 +6475,14 @@ namespace Ttcn {
return false;
}
void Def_Function::generate_code(output_struct *target, bool)
void Def_Function::generate_code(output_struct *target, bool clean_up)
{
// Functions with 'port' clause are generated into the port type's class def
// Reuse of clean_up variable to allow or disallow the generation.
// clean_up is true when it is called from PortTypeBody::generate_code())
if (port_type && !clean_up) {
return;
}
transparency_holder glass(*this);
const string& t_genname = get_genname();
const char *genname_str = t_genname.c_str();
......@@ -6384,15 +6519,21 @@ namespace Ttcn {
fp_list->generate_code_defval(target);
// function prototype
target->header.function_prototypes =
mputprintf(target->header.function_prototypes, "extern %s %s(%s);\n",
mputprintf(target->header.function_prototypes, "%s%s %s(%s);\n",
get_PortType() && clean_up ? "" : "extern ",
return_type_str, genname_str, formal_par_list);
// function body
target->source.function_bodies = mputprintf(target->source.function_bodies,
"%s %s(%s)\n"
"%s %s%s%s%s(%s)\n"
"{\n"
"%s"
"}\n\n", return_type_str, genname_str, formal_par_list, body);
"}\n\n",
return_type_str,
port_type && clean_up ? port_type->get_genname_own().c_str() : "",
port_type && clean_up && port_type->get_PortBody()->get_testport_type() != PortTypeBody::TP_INTERNAL ? "_BASE" : "",
port_type && clean_up ? "::" : "",
genname_str, formal_par_list, body);
Free(formal_par_list);
Free(body);
......
......@@ -457,6 +457,37 @@ namespace Ttcn {
virtual Common::Assignment *get_ass_bySRef(Ref_simple *p_ref);
virtual bool has_ass_withId(const Identifier& p_id);
};
/**
* Class Ttcn::PortScope.
* Implements the scoping rules for functions that
* have a 'port' clause. First looks for the variable definitions in the given
* port type first then it searches in its parent scope.
* Note: This scope unit cannot access the parent scope of the port type.
*/
class PortScope : public Scope {
/** Points to the port type. */
Type *port_type;
/** Shortcut to the definitions within \a port_type. */
Definitions *vardefs;
/** Not implemented. Causes \a FATAL_ERROR. */
PortScope(const PortScope& p);
/** %Assignment not implemented */
PortScope& operator=(const PortScope& p);
public:
PortScope(Type *p_porttype);
virtual PortScope *clone() const;
Type *get_port_type() const { return port_type; }
/** Checks the uniqueness of definitions within \a portdefs and
* reports warnings in case of hiding. */
void chk_uniq();
virtual PortScope *get_scope_port();
virtual Common::Assignment *get_ass_bySRef(Ref_simple *p_ref);
virtual bool has_ass_withId(const Identifier& p_id);
};
/**
* Class Ttcn::Definitions.
......@@ -599,8 +630,9 @@ namespace Ttcn {
Imports *imp;
ControlPart* controlpart;
/** For caching the scope objects that are created in
* \a get_runs_on_scope(). */
* \a get_runs_on_scope() and get_port_scope(). */
vector<RunsOnScope> runs_on_scopes;
vector<PortScope> port_scopes;
private:
/** Copy constructor not implemented */
Module(const Module& p);
......@@ -638,6 +670,10 @@ namespace Ttcn {
* object has been created for a component type it will be returned later
* instead of creating a new one. */
RunsOnScope *get_runs_on_scope(Type *comptype);
/* The same as get_runs_on_scope except that the returned scope can access
* the port types definitions.
*/
PortScope *get_port_scope(Type *porttype);
virtual void dump(unsigned level) const;
void set_language_spec(const char *p_language_spec);
void add_ass(Definition* p_ass);
......@@ -858,7 +894,6 @@ namespace Ttcn {
: Common::Assignment(p), genname(), parentgroup(0),
w_attrib_path(0), erroneous_attrs(0), local_scope(false)
{ }
virtual string get_genname() const;
namedbool has_implicit_omit_attr() const;
private:
......@@ -879,13 +914,14 @@ namespace Ttcn {
/** Marks the (template) definition as local to a func/altstep/default */
inline void set_local() { local_scope = true; }
virtual string get_genname() const;
void set_genname(const string& p_genname) { genname = p_genname; }
/** Check if two definitions are (almost) identical, the type and dimensions
* must always be identical, the initial values can be different depending
* on the definition type. If error was reported the return value is false.
* The initial values (if applicable) may be present/absent, different or
* unfoldable. The function must be overridden to be used.
*/
*/
virtual bool chk_identical(Definition *p_def);
/** Parse and check the erroneous attribute data,
* returns erroneous attributes or NULL */
......@@ -1366,6 +1402,14 @@ namespace Ttcn {
* It is NULL if the function has no 'runs on' clause or \a runs_on_ref is
* erroneous. */
Type *runs_on_type;
/** The 'port' clause (i.e. a reference to a TTCN-3 port type)
* It is NULL if the function has no 'port' clause. */
Reference *port_ref;
/** Points to the object describing the port type referred by
* 'port' clause.
* It is NULL if the function has no 'port' clause or \a port_ref is
* erroneous. */
Type *port_type;
/** The body of the function */
StatementBlock *block;
/** Indicates whether the function is startable. That is, it can be
......@@ -1389,13 +1433,15 @@ namespace Ttcn {
* @param p_id function name
* @param p_fpl formal parameter list
* @param p_runs_on_ref "runs on", else NULL
* @param p_port_ref "port", else NULL
* @param p_return_type return type, may be NULL
* @param returns_template true if the return value is a template
* @param p_template_restriction restriction type
* @param p_block the body of the function
*/
Def_Function(Identifier *p_id, FormalParList *p_fpl,
Reference *p_runs_on_ref, Type *p_return_type,
Reference *p_runs_on_ref, Reference *p_port_ref,
Type *p_return_type,
bool returns_template,
template_restriction_t p_template_restriction,
StatementBlock *p_block);
......@@ -1404,9 +1450,13 @@ namespace Ttcn {
virtual void set_fullname(const string& p_fullname);
virtual void set_my_scope(Scope *p_scope);
virtual Type *get_RunsOnType();
virtual Type *get_PortType();
/** Returns a scope that can access the definitions within component type
* \a comptype and its parent is \a parent_scope.*/
RunsOnScope *get_runs_on_scope(Type *comptype);
/** Returns a scope that can access the definitions within port type
* \a porttype and its parent is \a parent_scope.*/
PortScope *get_port_scope(Type *porttype);
virtual void chk();
/** Checks and returns whether the function is startable.
* Reports the appropriate error message(s) if not. */
......@@ -1414,6 +1464,8 @@ namespace Ttcn {
bool is_transparent() const { return transparent; }
// Reuse of clean_up variable to allow or disallow the generation.
// clean_up is true when it is called from PortTypeBody::generate_code()
virtual void generate_code(output_struct *target, bool clean_up = false);
virtual void generate_code(CodeGenHelper& cgh);
virtual void dump_internal(unsigned level) const;
......
......@@ -3121,10 +3121,13 @@ error:
{
Error_Context cntxt(this, "In function instance");
Common::Assignment *t_ass = ref_pard->get_refd_assignment();
if (t_ass->get_PortType()) {
ref_pard->error("Function with `port' clause cannot be called directly.");
}
my_sb->chk_runs_on_clause(t_ass, *ref_pard, "call");
if (t_ass->get_Type())
ref_pard->warning("The value returned by %s is not used",
t_ass->get_description().c_str());
t_ass->get_description().c_str());
}
void Statement::chk_block()
......
......@@ -375,7 +375,7 @@ namespace Ttcn {
}
}
void TypeMappingTarget::chk_function(Type *source_type, bool legacy, bool incoming)
void TypeMappingTarget::chk_function(Type *source_type, Type *port_type, bool legacy, bool incoming)
{
Error_Context cntxt(this, "In `function' mapping");
Assignment *t_ass = u.func.function_ref->get_refd_assignment(false);
......@@ -478,6 +478,17 @@ namespace Ttcn {
output_type->get_typename().c_str());
}
}
// Check that if the function has a port clause it matches the port type
// that it is defined in.
Type *port_clause = u.func.function_ptr->get_PortType();
if (!legacy && port_clause && port_clause != port_type) {
u.func.function_ref->error("The function %s has a port clause of `%s'"
" but referenced in another port `%s'",
u.func.function_ptr->get_description().c_str(),
port_type->get_dispname().c_str(),
port_clause->get_dispname().c_str());
}
}
}
......@@ -517,7 +528,7 @@ namespace Ttcn {
if (u.encdec.eb_list) u.encdec.eb_list->chk();
}
void TypeMappingTarget::chk(Type *source_type, bool legacy, bool incoming)
void TypeMappingTarget::chk(Type *source_type, Type *port_type, bool legacy, bool incoming)
{
if (checked) return;
checked = true;
......@@ -532,7 +543,7 @@ namespace Ttcn {
case TM_DISCARD:
break;
case TM_FUNCTION: