Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cnedfunction.cc @ fbe00e73

History | View | Annotate | Download (6.49 KB)

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

    
9
/*--------------------------------------------------------------*
10
  Copyright (C) 1992-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 <math.h>
18
#include <string.h>
19
#include <sstream>
20
#include "cnedfunction.h"
21
#include "globals.h"
22
#include "cexception.h"
23
#include "stringutil.h"
24
#include "stringtokenizer.h"
25
#include "opp_ctype.h"
26

    
27
USING_NAMESPACE
28

    
29
//XXX also: wrap invocation of function, so that cNEDFunction checks arg types etc
30
//XXX also: old Define_Function be implemented with cNEDFunction (ie an adapter func)
31

    
32
cNEDFunction::cNEDFunction(NEDFunction f, const char *signature,
33
                           const char *category, const char *description) :
34
  cNoncopyableOwnedObject(NULL,false)
35
{
36
    ASSERT(f);
37
    signature = opp_nulltoempty(signature);
38

    
39
    this->f = f;
40
    this->sign = opp_nulltoempty(signature);
41

    
42
    this->categ = opp_nulltoempty(category);
43
    this->desc = opp_nulltoempty(description);
44

    
45
    parseSignature(signature);
46
}
47

    
48
static bool contains(const std::string& str, const std::string& substr)
49
{
50
    return str.find(substr) != std::string::npos;
51
}
52

    
53
static std::string substringBefore(const std::string& str, const std::string& substr)
54
{
55
    size_t pos = str.find(substr);
56
    return pos==std::string::npos ? "" : str.substr(0,pos);
57
}
58

    
59
static std::string substringAfter(const std::string& str, const std::string& substr)
60
{
61
    size_t pos = str.find(substr);
62
    return pos==std::string::npos ? "" : str.substr(pos+substr.size());
63
}
64

    
65
static char parseType(const std::string& str)
66
{
67
    if (str=="bool")
68
        return 'B';
69
    if (str=="long")
70
        return 'L';
71
    if (str=="double")
72
        return 'D';
73
    if (str=="quantity")
74
        return 'Q';
75
    if (str=="string")
76
        return 'S';
77
    if (str=="xml")
78
        return 'X';
79
    if (str=="any")
80
        return '*';
81
    return 0;
82
}
83

    
84
static bool splitTypeAndName(const std::string& pair, char& type, std::string& name)
85
{
86
    std::vector<std::string> v = StringTokenizer(pair.c_str()).asVector();
87
    if (v.size()!=2)
88
        return false;
89
    type = parseType(v[0]);
90
    name = v[1];
91
    return type!=0;
92
}
93

    
94
static const char *syntaxErrorMessage =
95
        "Define_NED_Function(): syntax error in signature \"%s\": "
96
        "should be <rettype> name(<argtype> argname,...), "
97
        "where types can be bool, long, double, quantity, string, xml, any; "
98
        "names of optional args end in '?'";
99

    
100
void cNEDFunction::parseSignature(const char *signature)
101
{
102
    std::string str = opp_nulltoempty(signature);
103
    std::string typeAndName = opp_trim(substringBefore(str, "(").c_str());
104
    char type;
105
    std::string name;
106
    if (!splitTypeAndName(typeAndName, type, name))
107
        throw cRuntimeError(syntaxErrorMessage, signature);
108
    setName(name.c_str());
109
    rettype = type;
110

    
111
    std::string rest = opp_trim(substringAfter(str, "(").c_str());
112
    bool missingRParen = !contains(rest, ")");
113
    std::string argList = opp_trim(substringBefore(rest, ")").c_str());
114
    std::string trailingGarbage = opp_trim(substringAfter(rest, ")").c_str());
115
    if (missingRParen || trailingGarbage.size()!=0)
116
        throw cRuntimeError(syntaxErrorMessage, signature);
117

    
118
    minargc = -1;
119
    std::vector<std::string> args = StringTokenizer(argList.c_str(), ",").asVector();
120
    for (int i=0; i < (int)args.size(); i++)
121
    {
122
        char argType;
123
        std::string argName;
124
        if (!splitTypeAndName(args[i], argType, argName))
125
            throw cRuntimeError(syntaxErrorMessage, signature);
126
        argtypes += argType;
127
        if (contains(argName,"?") && minargc==-1)
128
            minargc = i;
129
    }
130
    maxargc = argtypes.size();
131
    if (minargc==-1)
132
        minargc = maxargc;
133
}
134

    
135
void cNEDFunction::checkArgs(cDynamicExpression::Value argv[], int argc)
136
{
137
    if (argc<minargc || argc>maxargc)
138
        throw cRuntimeError("%s: called with wrong number of arguments", getName());
139

    
140
    for (int i=0; i<argc; i++) {
141
        char declType = argtypes[i];
142
        if (declType=='D' || declType=='L') {
143
            if (argv[i].type != 'D')
144
                throw cRuntimeError(eEBADARGS, getName());
145
            if (!opp_isempty(argv[i].dblunit))
146
                throw cRuntimeError(eDIMLESS, getName()); //XXX better msg! only arg i is dimless
147
        }
148
        else if (declType=='Q') {
149
            if (argv[i].type != 'D')
150
                throw cRuntimeError(eEBADARGS, getName());
151
        }
152
        else if (declType!='*' && argv[i].type!=declType) {
153
            throw cRuntimeError(eEBADARGS, getName());
154
        }
155
    }
156
}
157

    
158
cDynamicExpression::Value cNEDFunction::invoke(cComponent *context, cDynamicExpression::Value argv[], int argc)
159
{
160
    checkArgs(argv, argc);
161
    return f(context, argv, argc);
162
}
163

    
164
static const char *getTypeName(char t)
165
{
166
    switch (t)
167
    {
168
        case 'B': return "bool";
169
        case 'L': return "long";
170
        case 'D': return "double";
171
        case 'Q': return "quantity";
172
        case 'S': return "string";
173
        case 'X': return "xml";
174
        case '*': return "any";
175
        default:  return "?";
176
    }
177
}
178

    
179
std::string cNEDFunction::info() const
180
{
181
    return getSignature();
182
}
183

    
184
cNEDFunction *cNEDFunction::find(const char *name, int argcount)
185
{
186
    cRegistrationList *a = nedFunctions.getInstance();
187
    for (int i=0; i<a->size(); i++) {
188
        cNEDFunction *f = dynamic_cast<cNEDFunction *>(a->get(i));
189
        if (f && f->isName(name) && f->getMinArgs()<=argcount && f->getMaxArgs()>=argcount)
190
            return f;
191
    }
192
    return NULL;
193
}
194

    
195
cNEDFunction *cNEDFunction::get(const char *name, int argcount)
196
{
197
    cNEDFunction *p = find(name, argcount);
198
    if (!p)
199
        throw cRuntimeError("NED function \"%s\" with %d args not found -- perhaps it wasn't registered "
200
                            "with the Define_NED_Function() macro, or its code is not linked in",
201
                            name, argcount);
202
    return p;
203
}
204

    
205
cNEDFunction *cNEDFunction::findByPointer(NEDFunction f)
206
{
207
    cRegistrationList *a = nedFunctions.getInstance();
208
    for (int i=0; i<a->size(); i++) {
209
        cNEDFunction *ff = dynamic_cast<cNEDFunction *>(a->get(i));
210
        if (ff && ff->getFunctionPointer() == f)
211
            return ff;
212
    }
213
    return NULL;
214
}
215

    
216