Command line debugger first version
[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 "bool.hxx"
24 #include "double.hxx"
25 #include "user.hxx"
26 #include "internal.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "string.hxx"
30 #include "callable.hxx"
31 #include "overload.hxx"
32 #include "configvariable.hxx"
33 #include "exp.hxx"
34
35 #include "view_scilab/Adapters.hxx"
36 #include "controller_helpers.hxx"
37 #include "utilities.hxx"
38 #include "Controller.hxx"
39 #include "model/BaseObject.hxx"
40
41 extern "C" {
42 #include "localization.h"
43 }
44
45 namespace org_scilab_modules_scicos
46 {
47 namespace view_scilab
48 {
49
50 /**
51  * A property used as a getter/setter for a specific name
52  */
53 template<typename Adaptor>
54 struct property
55 {
56 public:
57     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
58     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
59
60     typedef std::vector< property<Adaptor> > props_t;
61     typedef typename props_t::iterator props_t_it;
62
63
64     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
65     ~property() {};
66
67     size_t original_index;
68     std::wstring name;
69     getter_t get;
70     setter_t set;
71
72     bool operator< (const std::wstring& v) const
73     {
74         return name < v;
75     }
76
77     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
78     {
79         return p1.original_index < p2.original_index;
80     }
81
82     /*
83      * Static properties accessors
84      */
85     static props_t fields;
86
87     /**
88      * @return true if the properties have already been setup, false otherwise.
89      */
90     static bool properties_have_not_been_set()
91     {
92         return fields.empty();
93     }
94
95     /**
96      * Add a property to an Adaptor
97      */
98     static void add_property(const std::wstring& name, getter_t g, setter_t s)
99     {
100         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
101         fields.insert(pos, property(name, g, s));
102     }
103 };
104
105 /**
106  * Base definition of the adapter pattern, implement the get / set dispatch.
107  *
108  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
109  */
110 template<typename Adaptor, typename Adaptee>
111 class BaseAdapter : public types::UserType
112 {
113
114 public:
115     BaseAdapter() : m_adaptee(nullptr) {};
116     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
117     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
118     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
119     {
120         Controller controller;
121         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren);
122         m_adaptee = controller.getObject< Adaptee >(id);
123     };
124     ~BaseAdapter()
125     {
126         if (m_adaptee != nullptr)
127         {
128             Controller controller;
129             controller.deleteObject(m_adaptee->id());
130         }
131     };
132
133     /*
134      * property accessors
135      */
136
137     bool hasProperty(const std::wstring& _sKey) const
138     {
139         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
140         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
141     }
142
143     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
144     {
145         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
146         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
147         {
148             return found->get(static_cast<Adaptor*>(this), controller);
149         }
150         return 0;
151     }
152
153     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
154     {
155         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
156         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
157         {
158             return found->set(*static_cast<Adaptor*>(this), v, controller);
159         }
160         return false;
161     }
162
163     /**
164      * property as TList accessors
165      */
166
167     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
168     {
169         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
170         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
171
172         // create the header
173         types::String* header = new types::String(1, 1 + (int)properties.size());
174         header->set(0, Adaptor::getSharedTypeStr().c_str());
175         int index = 1;
176         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
177         {
178             header->set(index, it->name.c_str());
179         }
180         tlist->append(header);
181
182         // set the tlist field value
183         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
184         {
185             tlist->append(it->get(*static_cast<Adaptor*>(this), controller));
186         }
187
188         return tlist;
189     }
190
191     bool setAsTList(types::InternalType* v, Controller& controller)
192     {
193         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
194         {
195             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
196             return false;
197         }
198         types::TList* current = v->getAs<types::TList>();
199         // The input TList cannot be empty
200         if (current->getSize() < 1)
201         {
202             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
203             return false;
204         }
205
206         // Check the header
207         types::String* header = current->getFieldNames();
208         if (header->getSize() < 1)
209         {
210             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for header of field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
211             return false;
212         }
213         // Make sure it is the same type as the Adapter
214         if (header->get(0) != Adaptor::getSharedTypeStr())
215         {
216             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for header of field %s: %s expected.\n"), Adaptor::getSharedTypeStr().c_str(), Adaptor::getSharedTypeStr().c_str());
217             return false;
218         }
219
220         // Retrieve the Adapter's properties
221         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
222
223         // For each input property, if it corresponds to an Adapter's property, set it.
224         for (int index = 1; index < header->getSize(); ++index)
225         {
226             typename property<Adaptor>::props_t_it found = std::lower_bound(properties.begin(), properties.end(), header->get(index));
227             if (found != properties.end() && !(header->get(index) < found->name))
228             {
229                 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
230                 if (!status)
231                 {
232                     return false;
233                 }
234             }
235         }
236
237         return true;
238     }
239
240     /**
241      * property comparison
242      */
243
244     types::Bool* equal(types::UserType*& ut)
245     {
246         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
247         // Check that 'ut' is an Adapter of the same type as *this
248         if (adapter_index == Adapters::INVALID_ADAPTER)
249         {
250             return new types::Bool(false);
251         }
252         if (this->getTypeStr() != ut->getTypeStr())
253         {
254             return new types::Bool(false);
255         }
256
257         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
258         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
259
260         types::Bool* ret = new types::Bool(1, 1 + properties.size());
261         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
262
263         Controller controller;
264         int index = 1;
265         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
266         {
267             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
268             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
269             ret->set(index, *ith_prop1 == *ith_prop2);
270
271             // Getting a property allocates data, so free it
272             ith_prop1->killMe();
273             ith_prop2->killMe();
274         }
275
276         return ret;
277     }
278
279     /**
280      * @return the Adaptee
281      */
282     Adaptee* getAdaptee() const
283     {
284         return m_adaptee;
285     }
286
287     /*
288      * All following methods should be implemented by each template instance
289      */
290
291     virtual std::wstring getTypeStr() = 0;
292     virtual std::wstring getShortTypeStr() = 0;
293
294 private:
295     types::InternalType* clone()
296     {
297         return new Adaptor(*static_cast<Adaptor*>(this));
298     }
299
300     /*
301      * Implement a specific types::User
302      */
303
304     bool isAssignable()
305     {
306         return true;
307     }
308
309     bool extract(const std::wstring & name, types::InternalType *& out)
310     {
311         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
312         if (found != property<Adaptor>::fields.end() && !(name < found->name))
313         {
314             Controller controller;
315             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
316             if (value == 0)
317             {
318                 return false;
319             }
320
321             out = value;
322             return true;
323         }
324
325         // specific case : to ease debugging let the user retrieve the model ID
326         if (name == L"modelID")
327         {
328             out = new types::Double(m_adaptee->id());
329             return true;
330         }
331
332         return false;
333     }
334
335     types::InternalType* extract(types::typed_list* _pArgs)
336     {
337         if (_pArgs->size() == 0)
338         {
339             // call overload
340             return NULL;
341         }
342
343         if ((*_pArgs)[0]->isString())
344         {
345             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
346             types::InternalType* pOut = NULL;
347             extract(std::wstring(pStr->get(0)), pOut);
348             return pOut;
349         }
350         else
351         {
352             if ((*_pArgs)[0]->isDouble())
353             {
354                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
355
356                 if (index->get(0) == 1)
357                 {
358                     // When _pArgs is '1', return the list of the property names of the Adaptor
359
360                     // Sort the properties before extracting them
361                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
362                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
363
364                     // Allocate the return
365                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
366
367                     int i = 0;
368                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
369                     {
370                         pOut->set(i, it->name.data());
371                     }
372                     return pOut;
373                 }
374             }
375             else
376             {
377                 // TO DO : management other type for arguments like a scalar or matrix of double
378             }
379         }
380
381         return NULL;
382     }
383
384     types::InternalType* insert(types::typed_list* _pArgs, types::InternalType* _pSource)
385     {
386         for (size_t i = 0; i < _pArgs->size(); i++)
387         {
388             if ((*_pArgs)[i]->isString())
389             {
390                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
391                 std::wstring name = pStr->get(0);
392
393                 Controller controller;
394                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
395                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
396                 {
397                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
398                 }
399
400                 return this;
401             }
402             else
403             {
404                 return NULL;
405             }
406         }
407
408         // call overload
409         return NULL;
410     }
411
412     void whoAmI(void)
413     {
414         std::cout << "scicos object";
415     }
416
417     bool hasToString()
418     {
419         // Do not allow scilab to call toString of this class
420         return false;
421     }
422
423     bool toString(std::wostringstream& ostr)
424     {
425         // Deprecated, use the overload instead
426         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
427         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
428
429         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
430         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
431         {
432             ostr << L"  " << it->name << std::endl;
433         }
434         return true;
435     }
436
437     bool isInvokable() const
438     {
439         return true;
440     }
441
442     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override
443     {
444         if (in.size() == 0)
445         {
446             out.push_back(this);
447             return true;
448         }
449         else if (in.size() == 1)
450         {
451             types::InternalType* _out = nullptr;
452             types::InternalType*  arg = in[0];
453             if (arg->isString())
454             {
455                 types::String* pString = arg->getAs<types::String>();
456                 for (int i = 0; i < pString->getSize(); ++i)
457                 {
458                     if (!extract(pString->get(i), _out))
459                     {
460                         return false;
461                     }
462                     out.push_back(_out);
463                 }
464             }
465
466             if (!out.empty())
467             {
468                 return true;
469             }
470         }
471
472         types::Callable::ReturnValue ret;
473         // Overload of extraction needs the BaseAdapter from where we extract
474         this->IncreaseRef();
475         in.push_back(this);
476
477         try
478         {
479             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
480         }
481         catch (ast::InternalError & /*se*/)
482         {
483             ret = Overload::call(L"%l_e", in, 1, out);
484         }
485
486         // Remove this from "in" to keep "in" unchanged.
487         this->DecreaseRef();
488         in.pop_back();
489
490         if (ret == types::Callable::Error)
491         {
492             throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
493         }
494
495         return true;
496     }
497
498 private:
499     Adaptee* m_adaptee;
500 };
501
502
503 } /* namespace view_scilab */
504 } /* namespace org_scilab_modules_scicos */
505
506 #endif /* BASEADAPTER_HXX_ */