2130d79aa433527b2b8e56c81f84899f68606320
[sdk] / bindings / cpp / eC.hpp
1 // Preprocessor directives can be added at the beginning (Can't store them in AST)
2
3 /****************************************************************************
4 ===========================================================================
5    Core eC Library
6 ===========================================================================
7 ****************************************************************************/
8 #if !defined(__EC_HPP__)
9 #define __EC_HPP__
10
11 #include "eC.h"
12
13 // Syntactic Sugar (NOT GENERATED)
14 #define INSTANCEL(x, c) (*(void **)((char *)(x) + (c)->offset))
15 #define _INSTANCE(x, c) INSTANCEL((x) ? (x) : 0, c)
16
17 #define INSTANCE(x, c) ({c * _i = (c *)_INSTANCE(x, x->_class); _i ? *_i : c(x); })
18
19 #undef   newi
20 #define  newi(c) Instance_newEx(c, true)
21
22 #define _REGISTER_CLASS(n, ns, bs, a) \
23    (Class *)eC_registerClass(normalClass, ns, bs, sizeof(Instance *), 0, \
24       (eC_bool (*)(void *)) n::constructor, (void(*)(void *)) n::destructor, (a).impl, privateAccess, publicAccess)
25
26 // For defining _class and registereing together (single translation unit)
27 #define REGISTER_CLASS_DEF(n, b, a)    TCPPClass<n> n::_class(_REGISTER_CLASS(n,     #n, b::_class.impl->name, a));
28
29 // For defining _class and registering separately (multiple translation units)
30 #define CLASS_DEF(n)                   TCPPClass<n> n::_class;
31 #define REGISTER_CLASS(n, b, a)        n::_class.setup(_REGISTER_CLASS(n,       #n, b::_class.impl->name, a));
32
33 // For C++ classes proxying eC classes:
34 #define REGISTER_CPP_CLASS(n, a)       n::_class.setup(_REGISTER_CLASS(n, "CPP" #n, #n, a));
35
36 #define _CONSTRUCT(c, b) \
37    INSTANCE_VIRTUAL_METHODS(c) \
38    static TCPPClass<c> _class; \
39    static eC_bool constructor(eC_Instance i, eC_bool alloc) { return (alloc && !_INSTANCE(i, _class.impl)) ? new c(i, _class) != null : true; } \
40    static void destructor(eC_Instance i) { c * inst = (c *)_INSTANCE(i, _class.impl); if(_class.destructor) ((void (*)(c & self))_class.destructor)(*inst); delete inst; } \
41    explicit inline c(eC_Instance _impl, CPPClass & cl = _class) : b(_impl, cl)
42
43 #define CONSTRUCT(c, b) \
44    c() : c(Instance_newEx(_class.impl, false), _class) { } \
45    _CONSTRUCT(c, b)
46
47 #define DESTRUCT(c) \
48    ((TCPPClass<c> &)_class).destructor
49
50 #define REGISTER() \
51    static void class_registration(CPPClass & _class)
52
53 #define APP_CONSTRUCT(c, b) \
54    inline c() : c(eC_init_CALL) { } \
55    _CONSTRUCT(c, b)
56
57 #if !defined(__WIN32__) || defined(__CONSOLE_APP__)
58    #define APP_SET_ARGS(a) eC_setArgs(a.impl, argc, argv);
59 #else
60    #define APP_SET_ARGS(a)
61 #endif
62
63 #define MAIN_DEFINITION \
64    extern "C" MAIN_DECLARATION \
65    { \
66       APP_SET_ARGS(app); \
67       app.main(); \
68       unloadTranslatedStrings(MODULE_NAME); \
69       return app.exitCode; \
70    }
71
72 #define SELF(c, n)  c * self = ((c *)(((char *)this) + 0x10 - (char *)&((c *)0x10)->n))
73
74 #define _ARG ,
75
76 #define VIRTUAL_METHOD(n, c, b, r, p0, ep, p, d) \
77    struct c ## _ ## n ## _Functor \
78    { \
79       int _[0]; \
80       typedef r (* FunctionType)(p0 p); \
81       inline FunctionType operator= (FunctionType func) \
82       { \
83          SELF(c, n); \
84          if(self->vTbl == c::_class.vTbl) \
85          { \
86             uint size = c :: _class.impl->vTblSize; \
87             self->vTbl = (void (**)())newt(FunctionType, size); \
88             memcpy(self->vTbl, c::_class.vTbl, sizeof(FunctionType) * size); \
89          } \
90          ((FunctionType *)self->vTbl)[b ## _ ## n ## _vTblID] = func; \
91          return func; \
92       } \
93       inline r operator()(ep p) \
94       { \
95          \
96          SELF(c, n); \
97          d; \
98       } \
99    } n; \
100    inline static void register_ ## n(CPPClass & cl, c ## _ ## n ## _Functor::FunctionType func) \
101    { \
102       ((c ## _ ## n ## _Functor::FunctionType *)cl.vTbl)[b ## _ ## n ## _vTblID] = func; \
103    }
104
105 #define _REGISTER_METHOD(cp1, cp2, ns, n, bc, c, r, p, ocl, oi, code, ea, rv) \
106    addMethod(_class.impl, ns, (void *) +[]p \
107    { \
108       Class * cl = (ocl) ? (Class *)(ocl)->_class : null; \
109       cp1 \
110       c * i = (oi) ? (c *)_INSTANCE(oi, cl) : null; \
111       int vid = bc ## _ ## n ## _vTblID; \
112       bc ## _ ## n ## _Functor::FunctionType fn; \
113       if(i && i->vTbl && i->vTbl[vid]) \
114       { \
115          fn = (bc ## _ ## n ## _Functor::FunctionType) i->vTbl[vid]; \
116          code; \
117       } \
118       cp2 \
119       else \
120       { \
121          auto method = ((r (*) p)(class_ ## c->_vTbl)[bc ## _ ## n ## _vTblID]); \
122          if(method) return method ea; \
123          return rv; \
124       } \
125    })
126
127 #define REGISTER_METHOD(ns, n, bc, c, r, p, ocl, oi, code, ea, rv) \
128    _REGISTER_METHOD(,, ns, n, bc, c, r, p, ocl, oi, code, ea, rv)
129
130 #define REGISTER_TYPED_METHOD(ns, n, bc, c, r, p, ocl, oi, code, ea, rv) \
131    _REGISTER_METHOD(\
132       CPPClass * cppcl = _class ? (CPPClass *)_class->bindingsClass : null;, \
133       else if(cppcl && cppcl->vTbl && cppcl->vTbl[vid]) \
134       { \
135          fn = (bc ## _ ## n ## _Functor::FunctionType) cppcl->vTbl[vid]; \
136          code; \
137       }, \
138       ns, n, bc, c, r, p, ocl, oi, code, ea, rv)
139
140 #define property(n, sg) struct n ## Prop { n ## Prop() { }; int _[0]; sg } n;
141
142 #define _set(t, n, c, d) \
143    inline t operator= (t v) \
144    { \
145       SELF(c, n); \
146       d; \
147       return v; \
148    } \
149
150 #define set(t, n, c, d) \
151    _set(t, n, c, d) \
152    inline n ## Prop & operator= (n ## Prop & prop) \
153    { \
154       SELF(c, n); \
155       t v = prop; \
156       d; \
157       return prop; \
158    }
159
160 #define get(t, n, c, d) inline operator t () const { SELF(c, n); d; }
161
162 extern "C" eC_Module ecere_init(eC_Module fromModule);
163
164 class Class : public eC_Class { };
165
166 class CPPClass
167 {
168 public:
169    typedef void (* Function)(void);
170    Class * impl;
171    Function * vTbl;
172    inline CPPClass() { };
173    inline CPPClass(const CPPClass & c) = delete;
174    inline CPPClass(const CPPClass && c)
175    {
176       impl = c.impl;
177       vTbl = c.vTbl;
178    }
179 };
180
181 template <class T>
182 class TCPPClass : public CPPClass
183 {
184 public:
185    TCPPClass() { }
186    TCPPClass(Class * _impl)
187    {
188       setup(_impl);
189    }
190    void (*destructor)(T &);
191    void setup(Class * _impl)
192    {
193       impl = _impl;
194       if(impl)
195       {
196          _impl->bindingsClass = this;
197          if(vTbl) eC_delete(vTbl);
198          vTbl = newt(Function, impl->vTblSize);
199          memset(vTbl, 0, sizeof(Function) * impl->vTblSize);
200          T::class_registration(*this);
201       }
202    }
203    ~TCPPClass()
204    {
205       if(impl)
206          eC_delete(vTbl);
207    }
208 };
209
210 // GENERATED: (Instance, Module and Application might require some custom tweaks...)
211
212 #define Instance_onDisplay_vTblID               onDisplay_vTblID
213 #define Instance_onCompare_vTblID               onCompare_vTblID
214 #define Instance_onCopy_vTblID                  onCopy_vTblID
215 #define Instance_onFree_vTblID                  onFree_vTblID
216 #define Instance_onGetString_vTblID             onGetString_vTblID
217 #define Instance_onGetDataFromString_vTblID     onGetDataFromString_vTblID
218 #define Instance_onEdit_vTblID                  onEdit_vTblID
219 #define Instance_onSerialize_vTblID             onSerialize_vTblID
220 #define Instance_onUnserialize_vTblID           onUnserialize_vTblID
221 #define Instance_onSaveEdit_vTblID              onSaveEdit_vTblID
222
223 // Normal Class Definitions
224
225 #define Instance_class_registration(d) \
226    REGISTER_TYPED_METHOD("OnCompare", onCompare, Instance, d, int, (Class * _class, eC_Instance o, eC_Instance o2), \
227       o, o, return fn(*i, *(Instance *)INSTANCEL(o2, o2->_class)), (_class, o, o2), 1); \
228    REGISTER_TYPED_METHOD("OnDisplay", onDisplay, Instance, d, void, (Class * _class, eC_Instance o, eC_Instance /*eC_Surface */ s, int x, int y, int w, void * f, Alignment a, DataDisplayFlags df), \
229       o, o, Surface surface(s); fn(*i, surface, x, y, w, f, a, df), (_class, o, s, x, y, w, f, a, df), ); \
230    REGISTER_TYPED_METHOD("OnCopy", onCopy, Instance, d, void, (Class * _class, eC_Instance * dest, eC_Instance src), \
231       src, dest ? *dest : null, fn(*i, *(Instance *)INSTANCEL(src, src->_class) ), (_class, dest, src), ); \
232    REGISTER_TYPED_METHOD("OnFree", onFree, Instance, d, void, (Class * _class, eC_Instance o), \
233       o, o, fn(*i), (_class, o), ); \
234    REGISTER_TYPED_METHOD("OnGetString", onGetString, Instance, d, constString, (Class * _class, eC_Instance o, String tempString, void * fieldData, eC_bool * needClass), \
235       o, o, bool nc; constString r = fn(*i, tempString, fieldData, needClass ? &nc : null); if(needClass) *needClass = nc; return r;, (_class, o, tempString, fieldData, needClass), (constString)null); \
236    REGISTER_TYPED_METHOD("OnGetDataFromString", onGetDataFromString, Instance, d, bool, (Class * _class, eC_Instance * o, constString string), \
237       o ? *o : null, o ? *o : null, return fn(*i, string); , (_class, o, string), false); \
238    REGISTER_TYPED_METHOD("OnSerialize", onSerialize, Instance, d, void, (Class * _class, eC_Instance o, eC_Instance /*eC_IOChannel*/ c), \
239       o, o, IOChannel * ref = (IOChannel *)_INSTANCE(c, c->_class); if(ref) fn(*i, *ref); else { IOChannel channel(c); fn(*i, channel); }, (_class, o, c), ); \
240    REGISTER_TYPED_METHOD("OnUnserialize", onUnserialize, Instance, d, void, (Class * _class, eC_Instance * o, eC_Instance /*eC_IOChannel*/ c), \
241       o ? *o : null, o, IOChannel * ref = (IOChannel *)_INSTANCE(c, c->_class); if(ref) fn(*i, *ref); else { IOChannel channel(c); fn(*i, channel); }, (_class, o, c), ); \
242    REGISTER_TYPED_METHOD("OnSaveEdit", onSaveEdit, Instance, d, bool, (Class * _class, eC_Instance * o, eC_Instance /*eC_Window*/ w, void * object), \
243       o ? *o : null, o, Window * ref = (Window *)_INSTANCE(w, w->_class); if(ref) return fn(*i, *ref, object); else { Window window(w); return fn(*i, window, object); }, (_class, o, w, object), false); \
244    REGISTER_TYPED_METHOD("OnEdit", onEdit, Instance, d, eC_Window, (Class * _class, eC_Instance o, eC_Instance /*eC_DataBox */db, void * obsolete, int x, int y, int w, int h, void * userData), \
245       o, o, \
246       Window /*DataBox*/ * ref = (Window /*DataBox*/ *)_INSTANCE(db, db->_class); \
247       Window * ret; \
248       if(ref)                   ret = &fn(*i, *ref,    obsolete, x, y, w, h, userData); \
249       else { Window /*DataBox */dataBox(db); \
250       ret = &fn(*i, dataBox, obsolete, x, y, w, h, userData); } \
251       return ret ? ret->impl : null;, \
252       (_class, o, db, obsolete, x, y, w, h, userData), (eC_Window)null);
253
254 #define INSTANCE_VIRTUAL_METHODS(c) \
255    VIRTUAL_METHOD(onCompare, c, Instance, \
256       int, c & _ARG, , c & b, \
257       return Instance_onCompare(_class.impl, self ? self->impl : (eC_Instance)null, &b ? b.impl : (eC_Instance)null)); \
258    VIRTUAL_METHOD(onCopy, c, Instance, \
259       void, c & _ARG, , c & src, \
260       return Instance_onCopy(_class.impl, self->impl, &src ? src.impl : (eC_Instance)null)); \
261    VIRTUAL_METHOD(onDisplay, c, Instance, \
262       void, c & _ARG, , Surface & surface _ARG int x _ARG int y _ARG int w _ARG void * fieldData _ARG Alignment alignment _ARG DataDisplayFlags flags, \
263       Instance_onDisplay(_class.impl, self ? self->impl : (eC_Instance)null, &surface ? ((Instance *)&surface)->impl : (eC_Instance)null, x, y, w, fieldData, alignment, flags)); \
264    VIRTUAL_METHOD(onFree, c, Instance, \
265       void, c &, , , \
266       return Instance_onFree(_class.impl, self->impl)); \
267    VIRTUAL_METHOD(onGetString, c, Instance, \
268       constString, c & _ARG, , String tempString _ARG void * fieldData _ARG bool * needClass, \
269       return Instance_onGetString(_class.impl, self ? self->impl : (eC_Instance)null, tempString, fieldData, needClass)); \
270    VIRTUAL_METHOD(onGetDataFromString, c, Instance, \
271       bool, c & _ARG, , constString string, \
272       return Instance_onGetDataFromString(_class.impl, self->impl, string)); \
273    VIRTUAL_METHOD(onSerialize, c, Instance, \
274       void, c & _ARG, , IOChannel & channel, \
275       return Instance_onSerialize(_class.impl, self ? self->impl : (eC_Instance)null, &channel ? ((Instance *)&channel)->impl : (eC_Instance)null)); \
276    VIRTUAL_METHOD(onUnserialize, c, Instance, \
277       void, c & _ARG, , IOChannel & channel, \
278       return Instance_onUnserialize(_class.impl, self->impl, &channel ? ((Instance *)&channel)->impl : (eC_Instance)null)); \
279    VIRTUAL_METHOD(onSaveEdit, c, Instance, \
280       bool, c & _ARG, , Window & window _ARG void * object, \
281       return Instance_onSaveEdit(_class.impl, self->impl, &window ? ((Instance *)&window)->impl : (eC_Instance)null, object)); \
282    VIRTUAL_METHOD(onEdit, c, Instance, \
283       Window &, c & _ARG, , Window /*DataBox*/ & dataBox _ARG void * obsolete _ARG int x _ARG int y _ARG int w _ARG int h _ARG void * userData, \
284       eC_Window window = Instance_onEdit(_class.impl, self->impl, &dataBox ? ((Instance *)&dataBox)->impl : (eC_Instance)null, obsolete, x, y, w, h, userData); \
285       return *(Window *)_INSTANCE(window, window->_class); );
286
287 class Surface;
288 class IOChannel;
289 class Window;
290 class DataBox;
291
292 typedef eC_Window eC_DataBox;
293
294 typedef uint32 Alignment;
295 typedef uint32 DataDisplayFlags;
296
297 class Instance
298 {
299 public:
300    static TCPPClass<Instance> _class;
301    eC_Instance impl;
302    void (**vTbl)(void);
303
304    void * operator new   (uintsize count) { return eC_new(count); }
305    void * operator new [](uintsize count) { return eC_new(count); }
306    void operator delete   (void * ptr) { eC_delete(ptr); }
307    void operator delete [](void * ptr) { eC_delete(ptr); }
308
309    static eC_bool constructor(eC_Instance i, bool alloc)
310    {
311       if(alloc &&!_INSTANCE(i, _class.impl))
312          return new Instance(i, _class) != null;
313       return true;
314    }
315    static void destructor(eC_Instance i) { Instance * inst = (Instance *)_INSTANCE(i, _class.impl); delete inst; }
316    static void class_registration(CPPClass & _class);
317
318    INSTANCE_VIRTUAL_METHODS(Instance);
319
320    inline explicit Instance(eC_Instance _impl, CPPClass & cl = _class)
321    {
322       Class * c = cl.impl;
323       impl = _impl;
324       vTbl = cl.vTbl;
325       if(impl)
326       {
327          if(c && !_INSTANCE(impl, c))
328             _INSTANCE(impl, c) = this;
329          impl->_refCount++;
330       }
331    }
332    inline Instance()
333    {
334       impl = null;
335       vTbl = null;
336    }
337    inline ~Instance()
338    {
339       if(impl && impl->_class)
340       {
341          if(impl->_class->bindingsClass)
342          {
343             Instance ** i = (Instance **)&INSTANCEL(impl, impl->_class);
344             if(i && *i == this)
345                *i = null;
346             if(vTbl)
347             {
348                CPPClass * cl = (CPPClass *)impl->_class->bindingsClass;
349                if(cl && vTbl != cl->vTbl)
350                eC_delete(vTbl);
351             }
352          }
353          Instance_decref(impl);
354       }
355    }
356    inline Instance(const Instance & i) = delete;
357    inline Instance(const Instance && i)
358    {
359       impl = i.impl;
360       vTbl = i.vTbl;
361    }
362 };
363
364 class Module : public Instance
365 {
366 public:
367    static TCPPClass<Module> _class;
368    inline explicit Module(eC_Instance _impl, CPPClass & c = _class) : Instance(_impl, c) { }
369 };
370
371 void eC_cpp_init(Module & module);
372 void ecere_cpp_init(Module & module);
373
374 #define Application_class_registration(d) \
375    REGISTER_METHOD("Main", main, Application, d, void, (eC_Instance o), o, o, return fn(*i), (o), );
376
377 class Application : public Module
378 {
379 public:
380    APP_CONSTRUCT(Application, Module)
381    {
382       eC_cpp_init(*this);
383       _INSTANCE(impl, impl->_class) = this;
384       vTbl = _class.vTbl;
385       __thisModule = impl;
386
387       // TODO: Omit this if we're linking against eC rt only
388       ecere_init(impl);
389       ecere_cpp_init(*this);
390
391 #ifdef MODULE_NAME
392       loadTranslatedStrings(null, MODULE_NAME);
393 #endif
394    }
395
396    static void class_registration(CPPClass & _class) { Application_class_registration(Application); }
397
398    property(exitCode, get(int, exitCode, Application, return self ? _IPTR(self->impl, class_Application, class_members_Application)->exitCode : 0) );
399
400    VIRTUAL_METHOD(main, Application, Application, void, Application &, , ,
401       return Application_main(self->impl));
402 };
403
404 class Container : public Instance
405 {
406 public:
407    CONSTRUCT(Container, Instance) { }
408 /*
409    inline IteratorPointer getFirst(void) { return Container_getFirst(impl); }
410    inline IteratorPointer getLast(void)  { return Container_getLast(impl); }
411    inline IteratorPointer getPrev(IteratorPointer * pointer) { return Container_getPrev(impl, pointer); }
412    inline IteratorPointer getNext(IteratorPointer * pointer) { return Container_getNext(impl, pointer); }
413    inline Container_D getData(IteratorPointer * pointer) { return (return Container_getData(impl, pointer); }
414    inline bool setData(IteratorPointer * pointer, Container_D data) { return Container_setData(impl, pointer, data); }
415    inline IteratorPointer getAtPosition(const Container_I pos, bool create, bool * justAdded) { return Container_getAtPosition(impl, pos, create, justAdded); }
416    inline IteratorPointer insert(IteratorPointer * after, Container_T value) { return Container_insert(impl, after, value); }
417    inline IteratorPointer add(Container_T value) { return Container_add(impl, value) }
418    inline void remove(IteratorPointer * it) { Container_remove(impl, it); }
419    inline void move(IteratorPointer * it, IteratorPointer * after) { Container_move(impl, it, after); }
420    inline void removeAll() { Container_removeAll(impl); }
421    inline void copy(Container <T> source) { Container_copy(impl, source); }  // Container <T> source
422    inline IteratorPointer find(const Container_D value) { return Container_find(impl, value); }
423    inline void freeIterator(IteratorPointer * it) { Container_freeIterator(impl, it); }
424    inline int getCount() { return Container_getCount(impl); }
425    inline void free() { Container_free(impl); }
426    inline void deleteItem(IteratorPointer * i) { Container_deleteItem(impl, i); }
427    inline void takeOut(const Container_D d) { Container_takeOut(impl, d); }
428 */
429 };
430
431 // Non-Events like methods
432 //    1. The methods will call the eC methods through the C bindings
433 //    2. This shound end up calling static class virtual table if overriden
434 //    3. Registering a method (e.g. onRedraw) needs to call addMethod to update the virtual table, with C callback
435
436 class Array : public Container
437 {
438 public:
439    CONSTRUCT(Array, Container) { }
440 };
441
442 class CustomAVLTree : public Container
443 {
444 public:
445    CONSTRUCT(CustomAVLTree, Container) { }
446 };
447
448 class AVLTree : public CustomAVLTree
449 {
450 public:
451    CONSTRUCT(AVLTree, CustomAVLTree) { }
452 };
453
454 class Map : public CustomAVLTree
455 {
456 public:
457    CONSTRUCT(Map, CustomAVLTree) { }
458 };
459
460 class LinkList : public Container
461 {
462 public:
463    CONSTRUCT(LinkList, Container) { }
464 };
465
466 class List : public LinkList
467 {
468 public:
469    CONSTRUCT(List, LinkList) { }
470 };
471
472 class IOChannel : public Instance
473 {
474 public:
475    CONSTRUCT(IOChannel, Instance) { }
476 };
477
478 class SerialBuffer : public IOChannel
479 {
480 public:
481    CONSTRUCT(SerialBuffer, IOChannel) { }
482 };
483
484 class OldArray : public Instance
485 {
486 public:
487    CONSTRUCT(OldArray, Instance) { }
488 };
489
490 // How to handle inheritance from classes not loaded yet?
491 /*
492 class ClassDesignerBase : public Window
493 {
494 public:
495    CONSTRUCT(ClassDesignerBase, Window) { }
496 };
497 class DesignerBase : public Window
498 {
499 public:
500    CONSTRUCT(DesignerBase, Window) { }
501 };
502 */
503
504 #endif