Use a stack to manage "where" location
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BaseAdapter.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #ifndef BASEADAPTER_HXX_
14 #define BASEADAPTER_HXX_
15
16 #include <cstring>
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <sstream>
22
23 #include "double.hxx"
24 #include "user.hxx"
25 #include "internal.hxx"
26 #include "tlist.hxx"
27 #include "mlist.hxx"
28 #include "string.hxx"
29 #include "callable.hxx"
30 #include "overload.hxx"
31 #include "scilabexception.hxx"
32
33 #include "Controller.hxx"
34 #include "Adapters.hxx"
35 #include "model/BaseObject.hxx"
36
37 namespace org_scilab_modules_scicos
38 {
39 namespace view_scilab
40 {
41
42 /**
43  * A property used as a getter/setter for a specific name
44  */
45 template<typename Adaptor>
46 struct property
47 {
48 public:
49     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
50     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
51
52     typedef std::vector< property<Adaptor> > props_t;
53     typedef typename props_t::iterator props_t_it;
54
55
56     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
57     ~property() {};
58
59     size_t original_index;
60     std::wstring name;
61     getter_t get;
62     setter_t set;
63
64     bool operator< (const std::wstring& v) const
65     {
66         return name < v;
67     }
68
69     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
70     {
71         return p1.original_index < p2.original_index;
72     }
73
74     /*
75      * Static properties accessors
76      */
77     static props_t fields;
78
79     /**
80      * @return true if the properties have already been setup, false otherwise.
81      */
82     static bool properties_have_not_been_set()
83     {
84         return fields.empty();
85     }
86
87     /**
88      * Add a property to an Adaptor
89      */
90     static void add_property(const std::wstring& name, getter_t g, setter_t s)
91     {
92         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
93         fields.insert(pos, property(name, g, s));
94     }
95 };
96
97 /**
98  * Base definition of the adapter pattern, implement the get / set dispatch.
99  *
100  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
101  */
102 template<typename Adaptor, typename Adaptee>
103 class BaseAdapter : public types::UserType
104 {
105
106 public:
107     BaseAdapter() : m_adaptee(nullptr) {};
108     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
109     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
110     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
111     {
112         Controller controller;
113         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren);
114         m_adaptee = controller.getObject< Adaptee >(id);
115     };
116     ~BaseAdapter()
117     {
118         if (m_adaptee != nullptr)
119         {
120             Controller controller;
121             controller.deleteObject(m_adaptee->id());
122         }
123     };
124
125     /*
126      * property accessors
127      */
128
129     bool hasProperty(const std::wstring& _sKey) const
130     {
131         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
132         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
133     }
134
135     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
136     {
137         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
138         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
139         {
140             return found->get(static_cast<Adaptor*>(this), controller);
141         }
142         return 0;
143     }
144
145     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
146     {
147         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
148         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
149         {
150             return found->set(*static_cast<Adaptor*>(this), v, controller);
151         }
152         return false;
153     }
154
155     /**
156      * property as TList accessors
157      */
158
159     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
160     {
161         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
162         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
163
164         // create the header
165         types::String* header = new types::String(1, 1 + (int)properties.size());
166         header->set(0, Adaptor::getSharedTypeStr().c_str());
167         int index = 1;
168         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
169         {
170             header->set(index, it->name.c_str());
171         }
172         tlist->append(header);
173
174         // set the tlist field value
175         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
176         {
177             tlist->append(it->get(*static_cast<Adaptor*>(this), controller));
178         }
179
180         return tlist;
181     }
182
183     bool setAsTList(types::InternalType* v, Controller& controller)
184     {
185         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
186         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
187
188         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
189         {
190             return false;
191         }
192         types::TList* current = v->getAs<types::TList>();
193         if (current->getSize() != static_cast<int>(1 + properties.size()))
194         {
195             return false;
196         }
197
198         // check the header
199         types::String* header = current->getFieldNames();
200         if (header->getSize() != static_cast<int>(1 + properties.size()))
201         {
202             return false;
203         }
204         if (header->get(0) != Adaptor::getSharedTypeStr())
205         {
206             return false;
207         }
208         int index = 1;
209         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
210         {
211             if (header->get(index) != it->name)
212             {
213                 return false;
214             }
215         }
216
217         // this is a valid tlist, get each tlist field value and pass it to the right property decoder
218         index = 1;
219         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
220         {
221             bool status = it->set(*static_cast<Adaptor*>(this), current->get(index), controller);
222             if (!status)
223             {
224                 return false;
225             }
226         }
227
228         return true;
229     }
230
231     /**
232      * @return the Adaptee
233      */
234     Adaptee* getAdaptee() const
235     {
236         return m_adaptee;
237     }
238
239     /*
240      * All following methods should be implemented by each template instance
241      */
242
243     virtual std::wstring getTypeStr() = 0;
244     virtual std::wstring getShortTypeStr() = 0;
245
246 private:
247     types::InternalType* clone()
248     {
249         return new Adaptor(*static_cast<Adaptor*>(this));
250     }
251
252     /*
253      * Implement a specific types::User
254      */
255
256     bool isAssignable()
257     {
258         return true;
259     }
260
261     bool extract(const std::wstring & name, types::InternalType *& out)
262     {
263         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
264         if (found != property<Adaptor>::fields.end() && !(name < found->name))
265         {
266             Controller controller = Controller();
267             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
268             if (value == 0)
269             {
270                 return false;
271             }
272
273             out = value;
274             return true;
275         }
276         return false;
277     }
278
279     types::InternalType* extract(types::typed_list* _pArgs)
280     {
281         if (_pArgs->size() == 0)
282         {
283             // call overload
284             return NULL;
285         }
286
287         if ((*_pArgs)[0]->isString())
288         {
289             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
290             types::InternalType* pOut = NULL;
291             extract(std::wstring(pStr->get(0)), pOut);
292             return pOut;
293         }
294         else
295         {
296             if ((*_pArgs)[0]->isDouble())
297             {
298                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
299
300                 if (index->get(0) == 1)
301                 {
302                     // When _pArgs is '1', return the list of the property names of the Adaptor
303
304                     // Sort the properties before extracting them
305                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
306                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
307
308                     // Allocate the return
309                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
310
311                     int i = 0;
312                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
313                     {
314                         pOut->set(i, it->name.data());
315                     }
316                     return pOut;
317                 }
318             }
319             else
320             {
321                 // TO DO : management other type for arguments like a scalar or matrix of double
322             }
323         }
324
325         return NULL;
326     }
327
328     types::InternalType* insert(types::typed_list* _pArgs, InternalType* _pSource)
329     {
330         for (size_t i = 0; i < _pArgs->size(); i++)
331         {
332             if ((*_pArgs)[i]->isString())
333             {
334                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
335                 std::wstring name = pStr->get(0);
336
337                 Controller controller = Controller();
338                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
339                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
340                 {
341                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
342                 }
343
344                 return this;
345             }
346             else
347             {
348                 return NULL;
349             }
350         }
351
352         // call overload
353         return NULL;
354     }
355
356     void whoAmI(void)
357     {
358         std::cout << "scicos object";
359     }
360
361     bool hasToString()
362     {
363         // Do not allow scilab to call toString of this class
364         return false;
365     }
366
367     bool toString(std::wostringstream& ostr)
368     {
369         // Deprecated, use the overload instead
370         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
371         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
372
373         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
374         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
375         {
376             ostr << L"  " << it->name << std::endl;
377         }
378         return true;
379     }
380
381     bool isInvokable() const
382     {
383         return true;
384     }
385
386     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, ast::ConstVisitor & execFunc, const ast::Exp & /*e*/)
387     {
388         if (in.size() == 0)
389         {
390             out.push_back(this);
391             return true;
392         }
393         else if (in.size() == 1)
394         {
395             types::InternalType* _out = nullptr;
396             types::InternalType*  arg = in[0];
397             if (arg->isString())
398             {
399                 types::String* pString = arg->getAs<types::String>();
400                 for (int i = 0; i < pString->getSize(); ++i)
401                 {
402                     if (!extract(pString->get(i), _out))
403                     {
404                         return false;
405                     }
406                     out.push_back(_out);
407                 }
408             }
409
410             if (!out.empty())
411             {
412                 return true;
413             }
414         }
415
416         types::Callable::ReturnValue ret;
417         // Overload of extraction needs the BaseAdapter from where we extract
418         this->IncreaseRef();
419         in.push_back(this);
420
421         try
422         {
423             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out, &execFunc);
424         }
425         catch (ast::ScilabError & /*se*/)
426         {
427             ret = Overload::call(L"%l_e", in, 1, out, &execFunc);
428         }
429
430         // Remove this from "in" to keep "in" unchanged.
431         this->DecreaseRef();
432         in.pop_back();
433
434         if (ret == types::Callable::Error)
435         {
436             throw ast::ScilabError();
437         }
438
439         return true;
440     }
441
442 private:
443     Adaptee* m_adaptee;
444 };
445
446
447 } /* namespace view_scilab */
448 } /* namespace org_scilab_modules_scicos */
449
450 #endif /* BASEADAPTER_HXX_ */