Statistics
| Branch: | Revision:

root / src / nedxml / nedtypeinfo.cc @ 68da4f12

History | View | Annotate | Download (29.5 KB)

1
//==========================================================================
2
// NEDTYPEINFO.CC -
3
//
4
//                     OMNeT++/OMNEST
5
//            Discrete System Simulation in C++
6
//
7
//==========================================================================
8

    
9
/*--------------------------------------------------------------*
10
  Copyright (C) 2002-2008 Andras Varga
11
  Copyright (C) 2006-2008 OpenSim Ltd.
12

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16

    
17
#include <stdio.h>
18
#include <string.h>
19
#include <sstream>
20
#include "stringutil.h"
21
#include "nederror.h"
22
#include "nedutil.h"
23
#include "nedexception.h"
24
#include "nedtypeinfo.h"
25
#include "nedresourcecache.h"
26
#include "ned2generator.h"
27

    
28
USING_NAMESPACE
29

    
30

    
31
NEDTypeInfo::NEDTypeInfo(NEDResourceCache *resolver, const char *qname, bool isInnerType, NEDElement *tree)
32
{
33
    this->resolver = resolver;
34
    this->qualifiedName = qname;
35
    this->isInner = isInnerType;
36
    this->tree = tree;
37
    this->flattenedTree = NULL;
38

    
39
    switch (tree->getTagCode()) {
40
        case NED_SIMPLE_MODULE: type = SIMPLE_MODULE; break;
41
        case NED_COMPOUND_MODULE: type = COMPOUND_MODULE; break;
42
        case NED_MODULE_INTERFACE: type = MODULEINTERFACE; break;
43
        case NED_CHANNEL: type = CHANNEL; break;
44
        case NED_CHANNEL_INTERFACE: type = CHANNELINTERFACE; break;
45
        default: throw NEDException("NEDTypeInfo: element of wrong type (<%s>) passed into constructor", tree->getTagName());
46
    }
47
    bool isInterface = type==MODULEINTERFACE || type==CHANNELINTERFACE;
48

    
49
    // add "extends" and "like" names, after resolving them
50
    NEDLookupContext context = NEDResourceCache::getParentContextOf(qname, tree);
51
    for (NEDElement *child=tree->getFirstChild(); child; child=child->getNextSibling())
52
    {
53
        if (child->getTagCode()==NED_EXTENDS) {
54
            // resolve and store base type name
55
            const char *extendsname = ((ExtendsElement *)child)->getName();
56
            std::string extendsqname = getResolver()->resolveNedType(context, extendsname);
57
            Assert(!extendsqname.empty());
58
            extendsnames.push_back(extendsqname);
59

    
60
            // check the type
61
            NEDTypeInfo *decl = getResolver()->lookup(extendsqname.c_str());
62
            Assert(decl);
63
            if (getType() != decl->getType())
64
                throw NEDException(getTree(), "a %s cannot extend a %s (%s)", getTree()->getTagName(), decl->getTree()->getTagName(), extendsqname.c_str());
65

    
66
            // collect interfaces from our base types
67
            if (isInterface)
68
                for (int i=0; i<decl->numExtendsNames(); i++)
69
                    extendsnames.push_back(decl->extendsName(i));
70
            else
71
                for (int i=0; i<decl->numInterfaceNames(); i++)
72
                    interfacenames.push_back(decl->interfaceName(i));
73
        }
74
        if (child->getTagCode()==NED_INTERFACE_NAME) {
75
            // resolve and store base type
76
            const char *interfacename = ((InterfaceNameElement *)child)->getName();
77
            std::string interfaceqname = getResolver()->resolveNedType(context, interfacename);
78
            Assert(!interfaceqname.empty());
79
            interfacenames.push_back(interfaceqname);
80

    
81
            // check the type (must be an interface)
82
            NEDTypeInfo *decl = getResolver()->lookup(interfaceqname.c_str());
83
            Assert(decl);
84
            if (decl->getType() != (getType()==CHANNEL ? CHANNELINTERFACE : MODULEINTERFACE))
85
                throw NEDException(getTree(), "base type %s is expected to be a %s interface", interfaceqname.c_str(), (getType()==CHANNEL ? "channel" : "module"));
86

    
87
            // we support all interfaces that our base interfaces extend
88
            for (int i=0; i<decl->numExtendsNames(); i++)
89
                interfacenames.push_back(decl->extendsName(i));
90
        }
91
    }
92

    
93
    if (!isInterface)
94
    {
95
        // check that we have all parameters and gates required by the interfaces we support
96
        for (int i=0; i<(int)interfacenames.size(); i++) {
97
            NEDTypeInfo *interfaceDecl = getResolver()->lookup(interfacenames[i].c_str());
98
            Assert(interfaceDecl);
99
            checkComplianceToInterface(interfaceDecl);
100
        }
101
    }
102

    
103
    // fill in enclosingTypeName for inner types
104
    if (isInner)
105
    {
106
        const char *lastDot = strrchr(qname, '.');
107
        Assert(lastDot); // if it's an inner type, must have a parent
108
        enclosingTypeName = std::string(qname, lastDot-qname);
109
    }
110

    
111
    // resolve C++ class name
112
    if (getType()==SIMPLE_MODULE || getType()==COMPOUND_MODULE || getType()==CHANNEL)
113
    {
114
        // Note: @class() be used to override inherited implementation class.
115
        // The @class property itself does NOT get inherited.
116
        const char *explicitClassName = NEDElementUtil::getLocalStringProperty(getTree(), "class");
117
        if (!opp_isempty(explicitClassName))
118
            implClassName = opp_join("::", getCxxNamespace().c_str(), explicitClassName);
119
        else if (numExtendsNames()!=0)
120
            implClassName = opp_nulltoempty(getSuperDecl()->implementationClassName());
121
        else if (getType()==COMPOUND_MODULE)
122
            implClassName = "cCompoundModule";
123
        else
124
            implClassName = opp_join("::", getCxxNamespace().c_str(), getName());
125
    }
126

    
127
    // this is a temporary way to get some validation...
128
    getFlattenedTree();
129
}
130

    
131
NEDTypeInfo::~NEDTypeInfo()
132
{
133
    // note: we don't delete "tree", as it belongs to resolver
134
    if (flattenedTree && flattenedTree!=tree)
135
        delete flattenedTree;
136
}
137

    
138
const char *NEDTypeInfo::getName() const
139
{
140
    // take substring after the last dot
141
    const char *qname = getFullName();
142
    const char *lastdot = strrchr(qname, '.');
143
    return !lastdot ? qname : lastdot + 1;
144
}
145

    
146
const char *NEDTypeInfo::getFullName() const
147
{
148
    return qualifiedName.c_str();
149
}
150

    
151
NEDElement *NEDTypeInfo::getTree() const
152
{
153
    return tree;
154
}
155

    
156
NEDElement *NEDTypeInfo::getFlattenedTree() const
157
{
158
    if (!flattenedTree)
159
        flattenedTree = buildFlattenedTree();
160
    return flattenedTree;
161
}
162

    
163
std::string NEDTypeInfo::getPackage() const
164
{
165
    NEDElement *nedfile = getTree()->getParentWithTag(NED_NED_FILE);
166
    PackageElement *packageDecl = nedfile ? (PackageElement *) nedfile->getFirstChildWithTag(NED_PACKAGE) : NULL;
167
    return packageDecl ? packageDecl->getName() : "";
168
}
169

    
170
std::string NEDTypeInfo::getPackageProperty(const char *propertyName) const
171
{
172
    // find first such property in the current file, then in package.ned of this package and parent packages
173
    for (NedFileElement *nedfile = (NedFileElement *)getTree()->getParentWithTag(NED_NED_FILE);
174
         nedfile != NULL;
175
         nedfile = getResolver()->getParentPackageNedFile(nedfile))
176
    {
177
        const char *propertyValue = NEDElementUtil::getLocalStringProperty(nedfile, propertyName);
178
        if (propertyValue)
179
            return propertyValue;
180
    }
181
    return "";
182
}
183

    
184
std::string NEDTypeInfo::getCxxNamespace() const
185
{
186
    return getPackageProperty("namespace");
187
}
188

    
189
std::string NEDTypeInfo::info() const
190
{
191
    std::stringstream out;
192
    if (numExtendsNames()>0)
193
    {
194
        out << "extends ";
195
        for (int i=0; i<numExtendsNames(); i++)
196
            out << (i?", ":"") << extendsName(i);
197
        out << "  ";
198
    }
199

    
200
    if (numInterfaceNames()>0)
201
    {
202
        out << "like ";
203
        for (int i=0; i<numInterfaceNames(); i++)
204
            out << (i?", ":"") << interfaceName(i);
205
        out << "  ";
206
    }
207

    
208
    if (!implClassName.empty())
209
        out << "C++ class: " << implClassName;
210

    
211
    return out.str();
212
}
213

    
214
std::string NEDTypeInfo::nedSource() const
215
{
216
    std::stringstream out;
217
    NEDErrorStore errors;
218
    generateNED2(out, getTree(), &errors);
219
    return out.str();
220
}
221

    
222
const char *NEDTypeInfo::interfaceName(int k) const
223
{
224
    if (k<0 || k>=(int)interfacenames.size())
225
        throw NEDException("NEDTypeInfo: interface index %d out of range 0..%d", k, interfacenames.size()-1);
226
    return interfacenames[k].c_str();
227
}
228

    
229
bool NEDTypeInfo::supportsInterface(const char *qname)
230
{
231
    // linear search is OK because #interfaces is typically just one or two
232
    for (int i=0; i<(int)interfacenames.size(); i++)
233
        if (interfacenames[i] == qname)
234
            return true;
235
    return false;
236
}
237

    
238
const char *NEDTypeInfo::extendsName(int k) const
239
{
240
    if (k<0 || k>=(int)extendsnames.size())
241
        throw NEDException("NEDTypeInfo: extendsName(): index %d out of range 0..%d", k, extendsnames.size()-1);
242
    return extendsnames[k].c_str();
243
}
244

    
245
const char *NEDTypeInfo::getEnclosingTypeName() const
246
{
247
    return isInner ? enclosingTypeName.c_str() : NULL;
248
}
249

    
250
const char *NEDTypeInfo::implementationClassName() const
251
{
252
    return implClassName.empty() ? NULL : implClassName.c_str();
253
}
254

    
255
NEDTypeInfo *NEDTypeInfo::getSuperDecl() const
256
{
257
    const char *superName = extendsName(0);
258
    return getResolver()->getDecl(superName);
259
}
260

    
261
bool NEDTypeInfo::isNetwork() const
262
{
263
    return NEDElementUtil::getLocalBoolProperty(getTree(), "isNetwork");
264
}
265

    
266
ParametersElement *NEDTypeInfo::getParametersElement() const
267
{
268
    return (ParametersElement *)getTree()->getFirstChildWithTag(NED_PARAMETERS);
269
}
270

    
271
GatesElement *NEDTypeInfo::getGatesElement() const
272
{
273
    return (GatesElement *)getTree()->getFirstChildWithTag(NED_GATES);
274
}
275

    
276
SubmodulesElement *NEDTypeInfo::getSubmodulesElement() const
277
{
278
    return (SubmodulesElement *)getTree()->getFirstChildWithTag(NED_SUBMODULES);
279
}
280

    
281
ConnectionsElement *NEDTypeInfo::getConnectionsElement() const
282
{
283
    return (ConnectionsElement *)getTree()->getFirstChildWithTag(NED_CONNECTIONS);
284
}
285

    
286
SubmoduleElement *NEDTypeInfo::getLocalSubmoduleElement(const char *subcomponentName) const
287
{
288
    SubmodulesElement *submodulesNode = getSubmodulesElement();
289
    if (submodulesNode)
290
    {
291
        NEDElement *submoduleNode = submodulesNode->getFirstChildWithAttribute(NED_SUBMODULE, "name", subcomponentName);
292
        if (submoduleNode)
293
            return (SubmoduleElement *)submoduleNode;
294
    }
295
    return NULL;
296
}
297

    
298
ConnectionElement *NEDTypeInfo::getLocalConnectionElement(long id) const
299
{
300
    if (id == -1)
301
        return NULL;  // "not a NED connection"
302

    
303
    ConnectionsElement *connectionsNode = getConnectionsElement();
304
    if (connectionsNode)
305
    {
306
        for (NEDElement *child=connectionsNode->getFirstChild(); child; child=child->getNextSibling())
307
        {
308
            if (child->getTagCode() == NED_CONNECTION) {
309
                if (child->getId() == id)
310
                    return (ConnectionElement *)child;
311
            }
312
            else if (child->getTagCode() == NED_CONNECTION_GROUP) {
313
                NEDElement *conngroup = child;
314
                for (NEDElement *child=conngroup->getFirstChild(); child; child=child->getNextSibling())
315
                    if (child->getId() == id && child->getTagCode() == NED_CONNECTION)
316
                        return (ConnectionElement *)child;
317
            }
318
        }
319
    }
320
    return NULL;
321
}
322

    
323
SubmoduleElement *NEDTypeInfo::getSubmoduleElement(const char *name) const
324
{
325
    SubmoduleElement *submodule = getLocalSubmoduleElement(name);
326
    if (submodule)
327
        return submodule;
328
    for (int i=0; i<numExtendsNames(); i++)
329
        if ((submodule = getResolver()->lookup(extendsName(i))->getSubmoduleElement(name))!=NULL)
330
            return submodule;
331
    return NULL;
332
}
333

    
334
ConnectionElement *NEDTypeInfo::getConnectionElement(long id) const
335
{
336
    ConnectionElement *conn = getLocalConnectionElement(id);
337
    if (conn)
338
        return conn;
339
    for (int i=0; i<numExtendsNames(); i++)
340
        if ((conn = getResolver()->lookup(extendsName(i))->getConnectionElement(id))!=NULL)
341
            return conn;
342
    return NULL;
343
}
344

    
345
ParamElement *NEDTypeInfo::findLocalParamDecl(const char *name) const
346
{
347
    ParametersElement *params = getParametersElement();
348
    if (params)
349
        for (ParamElement *param=params->getFirstParamChild(); param; param=param->getNextParamSibling())
350
            if (param->getType()!=NED_PARTYPE_NONE && opp_strcmp(param->getName(), name)==0)
351
                return param;
352
    return NULL;
353
}
354

    
355
ParamElement *NEDTypeInfo::findParamDecl(const char *name) const
356
{
357
    ParamElement *param = findLocalParamDecl(name);
358
    if (param)
359
        return param;
360
    for (int i=0; i<numExtendsNames(); i++)
361
        if ((param = getResolver()->lookup(extendsName(i))->findParamDecl(name))!=NULL)
362
            return param;
363
    return NULL;
364
}
365

    
366
GateElement *NEDTypeInfo::findLocalGateDecl(const char *name) const
367
{
368
    GatesElement *gates = getGatesElement();
369
    if (gates)
370
        for (GateElement *gate=gates->getFirstGateChild(); gate; gate=gate->getNextGateSibling())
371
            if (gate->getType()!=NED_PARTYPE_NONE && opp_strcmp(gate->getName(), name)==0)
372
                return gate;
373
    return NULL;
374
}
375

    
376
GateElement *NEDTypeInfo::findGateDecl(const char *name) const
377
{
378
    GateElement *gate = findLocalGateDecl(name);
379
    if (gate)
380
        return gate;
381
    for (int i=0; i<numExtendsNames(); i++)
382
        if ((gate = getResolver()->lookup(extendsName(i))->findGateDecl(name))!=NULL)
383
            return gate;
384
    return NULL;
385
}
386

    
387
void NEDTypeInfo::checkComplianceToInterface(NEDTypeInfo *idecl)
388
{
389
    // TODO check properties
390

    
391
    // check parameters
392
    ParametersElement *iparams = idecl->getParametersElement();
393
    if (iparams)
394
    {
395
        for (ParamElement *iparam=iparams->getFirstParamChild(); iparam; iparam=iparam->getNextParamSibling())
396
        {
397
            // find param decl
398
            ParamElement *param = findParamDecl(iparam->getName());
399
            if (!param)
400
                throw NEDException(getTree(), "%s type has no parameter `%s', required by interface `%s'",
401
                                   (getType()==CHANNEL ? "channel" : "module"), iparam->getName(), idecl->getFullName());
402

    
403
            // check parameter type
404
            if (param->getType()!=iparam->getType())
405
                throw NEDException(param, "type of parameter `%s' must be %s, as required by interface `%s'",
406
                                   param->getName(), iparam->getAttribute("type"), idecl->getFullName());
407

    
408
            // check parameter volatile flag
409
            if (param->getIsVolatile() && !iparam->getIsVolatile())
410
                throw NEDException(param, "parameter `%s' must not be volatile, as required by interface `%s'",
411
                                   param->getName(), idecl->getFullName());
412
            if (!param->getIsVolatile() && iparam->getIsVolatile())
413
                throw NEDException(param, "parameter `%s' must be volatile, as required by interface `%s'",
414
                                   param->getName(), idecl->getFullName());
415

    
416
            // TODO check properties
417
        }
418
    }
419

    
420
    // check gates
421
    GatesElement *igates = idecl->getGatesElement();
422
    if (igates)
423
    {
424
        for (GateElement *igate=igates->getFirstGateChild(); igate; igate=igate->getNextGateSibling())
425
        {
426
            // find gate decl
427
            GateElement *gate = findGateDecl(igate->getName());
428
            if (!gate)
429
                throw NEDException(getTree(), "%s type has no gate `%s', required by interface `%s'",
430
                                   (getType()==CHANNEL ? "channel" : "module"), igate->getName(), idecl->getFullName());
431

    
432
            // check gate type
433
            if (gate->getType()!=igate->getType())
434
                throw NEDException(gate, "type of gate `%s' must be %s, as required by interface `%s'",
435
                                   gate->getName(), igate->getAttribute("type"), idecl->getFullName());
436

    
437
            // check vector/nonvector
438
            if (!igate->getIsVector() && gate->getIsVector())
439
                throw NEDException(gate, "gate `%s' must not be a vector gate, as required by interface `%s'",
440
                                   gate->getName(), idecl->getFullName());
441
            if (igate->getIsVector() && !gate->getIsVector())
442
                throw NEDException(gate, "gate `%s' must be a vector gate, as required by interface `%s'",
443
                                   gate->getName(), idecl->getFullName());
444

    
445
            // if both are vectors, check vector size specs are compatible
446
            if (igate->getIsVector() && gate->getIsVector())
447
            {
448
                ExpressionElement *gatesizeExpr = (ExpressionElement *)gate->getFirstChildWithAttribute(NED_EXPRESSION, "target", "vector-size");
449
                ExpressionElement *igatesizeExpr = (ExpressionElement *)igate->getFirstChildWithAttribute(NED_EXPRESSION, "target", "vector-size");
450

    
451
                bool hasGatesize = !opp_isempty(gate->getVectorSize()) || gatesizeExpr!=NULL;
452
                bool ihasGatesize = !opp_isempty(igate->getVectorSize()) || igatesizeExpr!=NULL;
453

    
454
                if (hasGatesize && !ihasGatesize)
455
                    throw NEDException(gate, "size of gate vector `%s' must be left unspecified, as required by interface `%s'",
456
                                       gate->getName(), idecl->getFullName());
457
                if (!hasGatesize && ihasGatesize)
458
                    throw NEDException(gate, "size of gate vector `%s' must be specified as in interface `%s'",
459
                                       gate->getName(), idecl->getFullName());
460

    
461
                // if both gatesizes are given, check that they are actually the same
462
                if (hasGatesize && ihasGatesize)
463
                {
464
                    bool mismatch = (gatesizeExpr && igatesizeExpr) ?
465
                        NEDElementUtil::compareTree(gatesizeExpr, igatesizeExpr)!=0 : // with parsed expressions
466
                        opp_strcmp(gate->getVectorSize(), igate->getVectorSize())!=0;  // with unparsed expressions
467
                    if (mismatch)
468
                        throw NEDException(gate, "size of gate vector `%s' must be specified as in interface `%s'",
469
                                           gate->getName(), idecl->getFullName());
470
                }
471

    
472
            }
473

    
474
            // TODO check properties
475
        }
476
    }
477
}
478

    
479
//XXX note: we currently don't use this for anything
480
NEDElement *NEDTypeInfo::buildFlattenedTree() const
481
{
482
    NEDElement *result = NULL;
483
    NEDLookupContext context = NEDResourceCache::getParentContextOf(qualifiedName.c_str(), tree);
484
    for (NEDElement *child=tree->getFirstChildWithTag(NED_EXTENDS); child; child=child->getNextSiblingWithTag(NED_EXTENDS))
485
    {
486
        // resolve and store base type name
487
        const char *extendsname = ((ExtendsElement *)child)->getName();
488
        std::string extendsqname = getResolver()->resolveNedType(context, extendsname);
489
        Assert(!extendsqname.empty());
490
        //XXX extendsnames probably not needed, ever:
491
        //extendsnames.push_back(extendsqname);
492

    
493
        // check the type
494
        NEDTypeInfo *decl = getResolver()->lookup(extendsqname.c_str());
495
        Assert(decl);
496
        if (getType() != decl->getType())  //XXX currently duplicate check
497
            throw NEDException(getTree(), "a %s cannot extend a %s (%s)", getTree()->getTagName(), decl->getTree()->getTagName(), extendsqname.c_str());
498

    
499
        NEDElement *basetree = decl->getFlattenedTree();
500
        if (!result)
501
            result = basetree->dupTree();  //FIXME: does not copy srcloc, srcregion!
502
        else
503
            mergeNEDType(result, basetree);
504
    }
505
    if (!result)
506
        result = tree;
507
    else
508
        mergeNEDType(result, tree);
509
    return result;
510
}
511

    
512
inline bool isNEDType(NEDElement *node)
513
{
514
    int tag = node->getTagCode();
515
    return tag==NED_SIMPLE_MODULE || tag==NED_MODULE_INTERFACE || tag==NED_COMPOUND_MODULE || tag==NED_CHANNEL_INTERFACE || tag==NED_CHANNEL;
516
}
517

    
518
void NEDTypeInfo::mergeNEDType(NEDElement *basetree, const NEDElement *tree) const
519
{
520
    // TODO remove all "extends" causes (not needed)
521
    for (ExtendsElement *i=(ExtendsElement *)basetree->getFirstChildWithTag(NED_EXTENDS); i; i=(ExtendsElement *)i->getNextSiblingWithTag(NED_EXTENDS))
522
        delete basetree->removeChild(i);
523

    
524
    // merge interfaces ("like" clauses)
525
    for (InterfaceNameElement *i=(InterfaceNameElement *)tree->getFirstChildWithTag(NED_INTERFACE_NAME); i; i=(InterfaceNameElement *)i->getNextSiblingWithTag(NED_INTERFACE_NAME))
526
    {
527
        basetree->appendChild(i->dupTree());  //TODO convert to fully qualified name
528
    }
529

    
530
    // merge parameters
531
    ParametersElement *params = (ParametersElement *)tree->getFirstChildWithTag(NED_PARAMETERS);
532
    ParametersElement *baseparams = (ParametersElement *)basetree->getFirstChildWithTag(NED_PARAMETERS);
533
    if (params && !baseparams)
534
    {
535
        // just copy it
536
        basetree->appendChild(params->dupTree());
537
    }
538
    else if (params && baseparams)
539
    {
540
        // merge parameters
541
        for (ParamElement *param=params->getFirstParamChild(); param; param=param->getNextParamSibling())
542
        {
543
            // find existing param in base
544
            ParamElement *baseparam = (ParamElement *)baseparams->getFirstChildWithAttribute(NED_PARAM, "name", param->getName());
545
            if (!baseparam)
546
            {
547
                // just copy it
548
                baseparams->appendChild(param->dupTree());
549
            }
550
            else
551
            {
552
                // already exists -- must merge
553
                if (param->getType()!=NED_PARTYPE_NONE)
554
                    throw NEDException(param, "redeclaration of parameter `%s'", param->getName()); //XXX "declared at XXX"
555

    
556
                // take over value if exists
557
                if (!opp_isempty(param->getValue()))
558
                {
559
                    baseparam->setValue(param->getValue());
560
                    baseparam->setIsDefault(param->getIsDefault());
561
                }
562
                ExpressionElement *valueexpr = param->getFirstExpressionChild();
563
                if (valueexpr)
564
                {
565
                    delete baseparam->getFirstExpressionChild();
566
                    baseparam->appendChild(valueexpr->dupTree());
567
                    baseparam->setIsDefault(param->getIsDefault());
568
                }
569

    
570
                // merge properties
571
                mergeProperties(baseparam, param);
572
            }
573
        }
574

    
575
        //TODO merge PatternElements
576

    
577
        // merge properties
578
        mergeProperties(baseparams, params);
579
    }
580

    
581
    // merge gates
582
    GatesElement *gates = (GatesElement *)tree->getFirstChildWithTag(NED_GATES);
583
    GatesElement *basegates = (GatesElement *)basetree->getFirstChildWithTag(NED_GATES);
584
    if (gates && !basegates)
585
    {
586
        // just copy it
587
        basetree->appendChild(gates->dupTree());
588
    }
589
    else if (gates && basegates)
590
    {
591
        // merge
592
        for (GateElement *gate=gates->getFirstGateChild(); gate; gate=gate->getNextGateSibling())
593
        {
594
            // find existing gate in base
595
            GateElement *basegate = (GateElement *)basegates->getFirstChildWithAttribute(NED_GATE, "name", gate->getName());
596
            if (!basegate)
597
            {
598
                // just copy it
599
                basegates->appendChild(gate->dupTree());
600
            }
601
            else
602
            {
603
                // already exists -- must merge
604
                if (gate->getType()!=NED_GATETYPE_NONE)
605
                    throw NEDException(gate, "redeclaration of gate `%s'", gate->getName()); //XXX "declared at XXX"
606

    
607
                // take over gatesize if exists
608
                if (!opp_isempty(gate->getVectorSize()))
609
                {
610
                    basegate->setVectorSize(gate->getVectorSize());
611
                }
612
                ExpressionElement *gatesizeexpr = gate->getFirstExpressionChild();
613
                if (gatesizeexpr)
614
                {
615
                    delete basegate->getFirstExpressionChild();
616
                    basegate->appendChild(gatesizeexpr->dupTree());
617
                }
618

    
619
                //  merge properties
620
                mergeProperties(basegate, gate);
621
            }
622
        }
623
    }
624

    
625
    // merge inner types
626
    TypesElement *types = (TypesElement *)tree->getFirstChildWithTag(NED_TYPES);
627
    TypesElement *basetypes = (TypesElement *)basetree->getFirstChildWithTag(NED_TYPES);
628
    if (types && !basetypes)
629
    {
630
        // just copy it
631
        basetree->appendChild(types->dupTree());
632
    }
633
    else if (types && basetypes)
634
    {
635
        // merge
636
        for (NEDElement *type=types->getFirstChild(); type; type=type->getNextSibling())
637
        {
638
            if (isNEDType(type))
639
            {
640
                // find same type in base
641
                const char *name = type->getAttribute("name");
642
                NEDElement *basetype;
643
                for (basetype=basetypes->getFirstChild(); basetype; basetype=basetype->getNextSibling())
644
                    if (isNEDType(basetype) && opp_strcmp(name, basetype->getAttribute("name"))==0)
645
                        break;
646

    
647
                if (!basetype)
648
                {
649
                    // no such name yet, just copy it
650
                    basetypes->appendChild(type->dupTree());
651
                }
652
                else
653
                {
654
                    // already exists ==> error (types don't get merged)
655
                    throw NEDException(type, "redeclaration of inner type `%s'", name); //XXX "declared at XXX"
656
                }
657
            }
658
        }
659
    }
660

    
661
    // merge submodules
662
    SubmodulesElement *submodules = (SubmodulesElement *)tree->getFirstChildWithTag(NED_SUBMODULES);
663
    SubmodulesElement *basesubmodules = (SubmodulesElement *)basetree->getFirstChildWithTag(NED_SUBMODULES);
664
    if (submodules)
665
    {
666
        if (!basesubmodules)
667
            basetree->appendChild(basesubmodules=submodules->dup());
668

    
669
        for (SubmoduleElement *submodule=submodules->getFirstSubmoduleChild(); submodule; submodule=submodule->getNextSubmoduleSibling())
670
        {
671
            // find existing submodule in base
672
            SubmoduleElement *basesubmodule = (SubmoduleElement *)basesubmodules->getFirstChildWithAttribute(NED_SUBMODULE, "name", submodule->getName());
673
            if (!basesubmodule)
674
            {
675
                // just copy it
676
                // TODO change typename to fully qualified name!!!
677
                basesubmodules->appendChild(submodule->dupTree());
678
            }
679
            else
680
            {
681
                // already exists ==> error (submodules don't get merged)
682
                throw NEDException(submodule, "redeclaration of submodule `%s'", submodule->getName()); //XXX "declared at XXX"
683
            }
684
        }
685
    }
686

    
687
    // merge connections
688
    ConnectionsElement *connections = (ConnectionsElement *)tree->getFirstChildWithTag(NED_CONNECTIONS);
689
    ConnectionsElement *baseconnections = (ConnectionsElement *)basetree->getFirstChildWithTag(NED_CONNECTIONS);
690
    if (connections && !baseconnections)
691
    {
692
        // just copy it
693
        basetree->appendChild(connections->dupTree());
694
    }
695
    else if (connections && baseconnections)
696
    {
697
        // merge "allowunconnected" bit
698
        if (connections->getAllowUnconnected())
699
            baseconnections->setAllowUnconnected(true);
700

    
701
        // just copy existing connections
702
        for (NEDElement *connection=connections->getFirstChild(); connection; connection=connection->getNextSibling())
703
        {
704
            baseconnections->appendChild(connection->dupTree());
705
        }
706
    }
707

    
708
    // TODO put "parameters:", "gates:", "types:" etc elements in the correct order in the tree
709
}
710

    
711
void NEDTypeInfo::mergeProperties(NEDElement *basetree, const NEDElement *tree) const
712
{
713
    for (NEDElement *child=tree->getFirstChildWithTag(NED_PROPERTY); child; child=child->getNextSiblingWithTag(NED_PROPERTY))
714
    {
715
        PropertyElement *prop = (PropertyElement *)child;
716

    
717
        // find corresponding property in basetree, by name+index
718
        PropertyElement *baseprop = NULL;
719
        for (NEDElement *basechild=basetree->getFirstChildWithTag(NED_PROPERTY); basechild; basechild=basechild->getNextSiblingWithTag(NED_PROPERTY))
720
            if (opp_strcmp(prop->getName(), ((PropertyElement *)basechild)->getName())==0 &&
721
                opp_strcmp(prop->getIndex(), ((PropertyElement *)basechild)->getIndex())==0)
722
                {baseprop = (PropertyElement *)basechild; break;}
723

    
724
        // if not there, add it, else merge.
725
        if (!baseprop)
726
            basetree->appendChild(prop->dupTree());
727
        else
728
            mergeProperty(baseprop, prop);   //FIXME add special case for @display
729
    }
730
}
731

    
732
void NEDTypeInfo::mergeProperty(PropertyElement *baseprop, const PropertyElement *prop) const
733
{
734
    for (PropertyKeyElement *key=prop->getFirstPropertyKeyChild(); key; key=key->getNextPropertyKeySibling())
735
    {
736
        PropertyKeyElement *basekey = (PropertyKeyElement *)baseprop->getFirstChildWithAttribute(NED_PROPERTY_KEY, "name", key->getName());
737
        if (!basekey)
738
        {
739
            // just copy it
740
            baseprop->appendChild(key->dupTree());
741
        }
742
        else
743
        {
744
            // merge property
745
            mergePropertyKey(basekey, key);
746
        }
747
    }
748
}
749

    
750
void NEDTypeInfo::mergePropertyKey(PropertyKeyElement *basekey, const PropertyKeyElement *key) const
751
{
752
    // merge positional ones
753
    LiteralElement *baseliteral = basekey->getFirstLiteralChild();
754
    LiteralElement *literal = key->getFirstLiteralChild();
755
    while (baseliteral && literal)
756
    {
757
        LiteralElement *nextbaseliteral = baseliteral->getNextLiteralSibling();
758
        if (literal->getType()==NED_CONST_SPEC && opp_strcmp(literal->getValue(),"-")==0)
759
        {
760
            // antivalue
761
            LiteralElement *blank = new LiteralElement();
762
            blank->setType(NED_CONST_SPEC);
763
            basekey->insertChildBefore(baseliteral, blank);
764
            delete basekey->removeChild(baseliteral);
765
        }
766
        else
767
        {
768
            // replace
769
            basekey->insertChildBefore(baseliteral, literal->dupTree());
770
            delete basekey->removeChild(baseliteral);
771
        }
772
        baseliteral = nextbaseliteral;
773
        literal = literal->getNextLiteralSibling();
774
    }
775

    
776
    // copy the rest
777
    while (literal)
778
    {
779
        basekey->appendChild(literal->dupTree());
780
        literal = literal->getNextLiteralSibling();
781
    }
782
}
783