mirror of https://github.com/KLayout/klayout.git
WIP: Allowing extension (mixin) classes
Needed to represent QIODeviceBase as a second base class for QIOdevice, QFile etc. Additional base classes are supported but in a rather limited way. They only contribute constants like enums. No methods can be provided this way (a limitation of the method enumeration scheme which only supports one base classe)
This commit is contained in:
parent
6f9fa7a4a2
commit
9c0e94e63c
|
|
@ -807,6 +807,13 @@ include "QVector4D", [ "<QVector4D>", "<QVector2D>", "<QMatrix4x4>" ]
|
|||
include "QAction", [ "<QAction>", "<QActionGroup>", "<QGraphicsWidget>", "<QMenu>" ]
|
||||
include "QCursor", [ "<QCursor>", "<QScreen>", "<QBitmap>" ]
|
||||
include "QGraphicsItem", [ "<QGraphicsItem>", "<QGraphicsTransform>", "<QGraphicsScene>", "<QStyleOptionGraphicsItem>", "<QGraphicsEffect>", "<QGraphicsWidget>", "<QGraphicsSceneContextMenuEvent>", "<QGraphicsSceneDragDropEvent>", "<QGraphicsSceneHoverEvent>", "<QGraphicsSceneMouseEvent>", "<QGraphicsSceneWheelEvent>", "<QPainter>" ]
|
||||
include "QGraphicsObject", [ "<QGraphicsObject>", "<QChildEvent>", "<QCursor>", "<QEvent>", "<QFocusEvent>", "<QGraphicsEffect>",
|
||||
"<QGraphicsItem>", "<QGraphicsItemGroup>", "<QGraphicsScene>", "<QGraphicsSceneContextMenuEvent>", "<QGraphicsSceneDragDropEvent>",
|
||||
"<QGraphicsSceneHoverEvent>", "<QGraphicsSceneMouseEvent>", "<QGraphicsSceneWheelEvent>", "<QGraphicsWidget>",
|
||||
"<QInputMethodEvent>", "<QKeyEvent>", "<QMetaMethod>", "<QObject>", "<QPainter>", "<QPainterPath>", "<QPointF>",
|
||||
"<QPolygonF>", "<QRectF>", "<QRegion>", "<QSize>", "<QStyleOptionGraphicsItem>", "<QThread>",
|
||||
"<QTimerEvent>", "<QTransform>", "<QWidget>",
|
||||
"<QGraphicsTransform>" ]
|
||||
include "QGraphicsScene", [ "<QGraphicsScene>", "<QGraphicsView>", "<QGraphicsItem>", "<QGraphicsWidget>", "<QGraphicsEllipseItem>", "<QGraphicsLineItem>", "<QGraphicsPathItem>", "<QGraphicsPixmapItem>", "<QGraphicsPolygonItem>", "<QGraphicsRectItem>", "<QGraphicsSimpleTextItem>", "<QGraphicsTextItem>", "<QGraphicsProxyWidget>", "<QGraphicsItemGroup>", "<QStyle>", "<QGraphicsSceneContextMenuEvent>", "<QGraphicsSceneDragDropEvent>", "<QGraphicsSceneHelpEvent>", "<QGraphicsSceneMouseEvent>", "<QGraphicsSceneWheelEvent>" ]
|
||||
include "QGuiApplication", [ "<QGuiApplication>", "<QScreen>", "<QSessionManager>", "<QClipboard>", "<QWindow>", "<QStyleHints>", "<QFont>", "<QPalette>" ]
|
||||
include "QApplication", [ "<QApplication>", "<QSessionManager>", "<QStyle>", "<QWindow>", "<QScreen>", "<QFont>", "<QFontMetrics>", "<QWidget>" ]
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ class CPPStruct
|
|||
|
||||
cls = self.id.to_s
|
||||
|
||||
# collect enums from inner classes
|
||||
# collect used enums from inner classes
|
||||
(self.body_decl || []).each do |bd|
|
||||
decl = nil
|
||||
if bd.is_a?(CPPStructDeclaration) && bd.visibility == :public && bd.struct.body_decl && bd.myself != "" && !conf.is_class_dropped?(cls, bd.myself)
|
||||
|
|
@ -273,6 +273,14 @@ class CPPStruct
|
|||
end
|
||||
end
|
||||
|
||||
# collect used enums from base classes
|
||||
(self.base_classes || []).each do |bc|
|
||||
bc_obj = self.parent.resolve_qid(bc.class_id)
|
||||
if bc_obj.is_a?(CPPStructDeclaration) && bc_obj.visibility == :public && bc_obj.struct.body_decl && bc_obj.myself != "" && !conf.is_class_dropped?(cls, bc_obj.myself)
|
||||
bc_obj.struct.collect_used_enums(map, conf)
|
||||
end
|
||||
end
|
||||
|
||||
methods = {}
|
||||
self.collect_all_methods(methods, conf)
|
||||
|
||||
|
|
@ -315,7 +323,7 @@ class CPPStruct
|
|||
|
||||
end
|
||||
|
||||
def collect_methods(map)
|
||||
def collect_methods(map, weak = false)
|
||||
|
||||
mmap = {}
|
||||
|
||||
|
|
@ -355,6 +363,7 @@ class CPPStruct
|
|||
end
|
||||
|
||||
# take non-duplicates (by call signature) for the map
|
||||
# weak ones do not redefine methods
|
||||
mmap.each do |mn,decls|
|
||||
|
||||
seen = {}
|
||||
|
|
@ -362,7 +371,9 @@ class CPPStruct
|
|||
s = d.call_sig
|
||||
if !seen[s]
|
||||
seen[s] = true
|
||||
(map[mn] ||= []) << d
|
||||
if !weak || !map[mn]
|
||||
(map[mn] ||= []) << d
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1907,6 +1918,10 @@ END
|
|||
base_cls = base_classes[0] && base_classes[0].class_id.to_s
|
||||
base_clsn = base_cls && make_cls_name(base_cls)
|
||||
|
||||
# as we only support single base classes (a tribute to Ruby), we treat all other base classes as
|
||||
# mixins
|
||||
mixin_base_classes = base_classes[1..] || []
|
||||
|
||||
methods_by_name = {}
|
||||
all_methods_by_name = {}
|
||||
enum_decls_by_name = {}
|
||||
|
|
@ -1918,8 +1933,8 @@ END
|
|||
end
|
||||
|
||||
mmap = {}
|
||||
struct.collect_methods(methods_by_name)
|
||||
struct.collect_all_methods(all_methods_by_name, conf)
|
||||
struct.collect_methods(methods_by_name)
|
||||
struct.collect_enum_decls(enum_decls_by_name) { |bd| self.is_enum_used?(bd) || conf.is_enum_included?(cls, bd.myself) }
|
||||
|
||||
# if one method is abstract, omit ctors for example
|
||||
|
|
@ -2365,35 +2380,35 @@ END
|
|||
|
||||
base_classes.each do |bc|
|
||||
|
||||
bc_name = bc.class_id.to_s
|
||||
bc_name = bc.class_id.to_s
|
||||
|
||||
ofile.puts("// base class cast for #{bc_name}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _init_f_#{clsn}_as_#{bc_name} (qt_gsi::GenericMethod *decl)")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" decl->set_return<#{bc_name} *> ();")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _call_f_#{clsn}_as_#{bc_name} (const qt_gsi::GenericMethod *, void *cls, gsi::SerialArgs &, gsi::SerialArgs &ret) ")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" ret.write<#{bc_name} *> ((#{bc_name} *)(#{cls} *)cls);")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("// base class cast for #{bc_name}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _init_f_#{clsn}_as_#{bc_name} (qt_gsi::GenericMethod *decl)")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" decl->set_return<#{bc_name} *> ();")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _call_f_#{clsn}_as_#{bc_name} (const qt_gsi::GenericMethod *, void *cls, gsi::SerialArgs &, gsi::SerialArgs &ret) ")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" ret.write<#{bc_name} *> ((#{bc_name} *)(#{cls} *)cls);")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
|
||||
mdecl_bcc << "new qt_gsi::GenericMethod (\"as#{bc_name}\", \"@brief Delivers the base class interface #{bc_name} of #{cls}\\nClass #{cls} is derived from multiple base classes. This method delivers the #{bc_name} base class aspect.\", false, &_init_f_#{clsn}_as_#{bc_name}, &_call_f_#{clsn}_as_#{bc_name});"
|
||||
mdecl_bcc << "new qt_gsi::GenericMethod (\"as#{bc_name}\", \"@brief Delivers the base class interface #{bc_name} of #{cls}\\nClass #{cls} is derived from multiple base classes. This method delivers the #{bc_name} base class aspect.\", false, &_init_f_#{clsn}_as_#{bc_name}, &_call_f_#{clsn}_as_#{bc_name});"
|
||||
|
||||
ofile.puts("static void _init_f_#{clsn}_as_const_#{bc_name} (qt_gsi::GenericMethod *decl)")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" decl->set_return<const #{bc_name} *> ();")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _call_f_#{clsn}_as_const_#{bc_name} (const qt_gsi::GenericMethod *, void *cls, gsi::SerialArgs &, gsi::SerialArgs &ret) ")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" ret.write<const #{bc_name} *> ((const #{bc_name} *)(const #{cls} *)cls);")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _init_f_#{clsn}_as_const_#{bc_name} (qt_gsi::GenericMethod *decl)")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" decl->set_return<const #{bc_name} *> ();")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
ofile.puts("static void _call_f_#{clsn}_as_const_#{bc_name} (const qt_gsi::GenericMethod *, void *cls, gsi::SerialArgs &, gsi::SerialArgs &ret) ")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" ret.write<const #{bc_name} *> ((const #{bc_name} *)(const #{cls} *)cls);")
|
||||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
|
||||
mdecl_bcc << "new qt_gsi::GenericMethod (\"asConst#{bc_name}\", \"@brief Delivers the base class interface #{bc_name} of #{cls}\\nClass #{cls} is derived from multiple base classes. This method delivers the #{bc_name} base class aspect.\\n\\nUse this version if you have a const reference.\", true, &_init_f_#{clsn}_as_const_#{bc_name}, &_call_f_#{clsn}_as_const_#{bc_name});"
|
||||
mdecl_bcc << "new qt_gsi::GenericMethod (\"asConst#{bc_name}\", \"@brief Delivers the base class interface #{bc_name} of #{cls}\\nClass #{cls} is derived from multiple base classes. This method delivers the #{bc_name} base class aspect.\\n\\nUse this version if you have a const reference.\", true, &_init_f_#{clsn}_as_const_#{bc_name}, &_call_f_#{clsn}_as_const_#{bc_name});"
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -2474,6 +2489,23 @@ END
|
|||
|
||||
end
|
||||
|
||||
# Produce the mixin base classes
|
||||
|
||||
if ! mixin_base_classes.empty?
|
||||
ofile.puts("// Additional base classes")
|
||||
ofile.puts("")
|
||||
mixin_base_classes.each do |bc|
|
||||
bc_name = bc.class_id.to_s
|
||||
ofile.puts("gsi::Class<#{bc_name}> &qtdecl_#{bc_name} ();")
|
||||
end
|
||||
ofile.puts("")
|
||||
end
|
||||
|
||||
mixin_base_classes.each do |bc|
|
||||
bc_name = bc.class_id.to_s
|
||||
ofile.puts("gsi::ClassExt<#{cls}> base_class_#{bc_name}_in_#{clsn} (qtdecl_#{bc_name} ());")
|
||||
end
|
||||
|
||||
ofile.puts("")
|
||||
ofile.puts("GSI_#{modn.upcase}_PUBLIC gsi::Class<#{cls}> &qtdecl_#{clsn} () { return decl_#{clsn}; }")
|
||||
ofile.puts("")
|
||||
|
|
@ -3213,7 +3245,7 @@ bp.read(input_file)
|
|||
puts("Collecting used enums ..")
|
||||
l = bp.prod_list(conf)
|
||||
l.each_with_index do |decl_obj,i|
|
||||
puts "#{decl_obj.myself}: #{i+1}/#{l.size}"
|
||||
decl_obj.myself && puts("#{decl_obj.myself}: #{i+1}/#{l.size}")
|
||||
bp.collect_used_enums(conf, decl_obj)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ module QualifiedNameResolver
|
|||
@id2obj && @id2obj[id]
|
||||
end
|
||||
|
||||
def resolve_qid(qid)
|
||||
def resolve_qid(qid, stop = nil, include_other = true)
|
||||
|
||||
qid.is_a?(CPPQualifiedId) || raise("Argument of resolve_qid must be a CPPQualifiedId object")
|
||||
|
||||
|
|
@ -206,22 +206,30 @@ module QualifiedNameResolver
|
|||
while root.parent
|
||||
root = root.parent
|
||||
end
|
||||
obj = root.resolve_qid(qid)
|
||||
obj = root.resolve_qid(qid, nil, false)
|
||||
else
|
||||
obj = id2obj(qid.parts[0].id)
|
||||
if obj && qid.parts.size > 1
|
||||
# The part may be a typedef: resolve it in that case before we proceed
|
||||
while obj && obj.is_a?(CPPTypedef)
|
||||
obj = obj.type.concrete.is_a?(CPPQualifiedId) && self.resolve_qid(obj.type.concrete)
|
||||
obj = obj.type.concrete.is_a?(CPPQualifiedId) && self.resolve_qid(obj.type.concrete, stop, include_other)
|
||||
end
|
||||
if obj
|
||||
qid_new = qid.dup
|
||||
qid_new.parts = qid.parts[1 .. -1]
|
||||
obj = obj.respond_to?(:resolve_qid) && obj.resolve_qid(qid_new)
|
||||
obj = obj.respond_to?(:resolve_qid) && obj.resolve_qid(qid_new, stop, include_other)
|
||||
end
|
||||
end
|
||||
if ! obj && self.parent
|
||||
obj = self.parent.resolve_qid(qid)
|
||||
if ! obj && include_other
|
||||
# try base classes
|
||||
self.other_children.each do |bc|
|
||||
if bc != self && bc.respond_to?(:resolve_qid)
|
||||
(obj = bc.resolve_qid(qid, self, false)) && break
|
||||
end
|
||||
end
|
||||
end
|
||||
if ! obj && self.parent && self.parent != stop
|
||||
obj = self.parent.resolve_qid(qid, stop, include_other)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -281,6 +289,10 @@ class CPPDeclaration
|
|||
[]
|
||||
end
|
||||
|
||||
def other_children
|
||||
[]
|
||||
end
|
||||
|
||||
def myself
|
||||
self.type.name
|
||||
end
|
||||
|
|
@ -295,6 +307,10 @@ class CPPEnumDeclaration
|
|||
[]
|
||||
end
|
||||
|
||||
def other_children
|
||||
[]
|
||||
end
|
||||
|
||||
def myself
|
||||
# exclude forward declarations
|
||||
self.enum.specs && self.enum.name.to_s
|
||||
|
|
@ -310,6 +326,10 @@ class CPPEnumSpec
|
|||
[]
|
||||
end
|
||||
|
||||
def other_children
|
||||
[]
|
||||
end
|
||||
|
||||
def myself
|
||||
self.name.to_s
|
||||
end
|
||||
|
|
@ -353,6 +373,10 @@ class CPPTypedef
|
|||
[]
|
||||
end
|
||||
|
||||
def other_children
|
||||
[]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class CPPStructDeclaration
|
||||
|
|
@ -395,7 +419,7 @@ class CPPStructDeclaration
|
|||
# The parent may be null for template base classes which are
|
||||
# forward-declared .. we're not interested in this case.
|
||||
if self.parent
|
||||
bc_obj = self.parent.resolve_qid(bc.class_id)
|
||||
bc_obj = self.parent.resolve_qid(bc.class_id, nil, false)
|
||||
# NOTE: it may look strange to test whether the base class is the class itself but
|
||||
# since we do a half-hearted job of resolving template variants, this may happen
|
||||
# if we derive a template specialization from another one (specifically
|
||||
|
|
@ -524,6 +548,10 @@ class CPPModule
|
|||
|
||||
end
|
||||
|
||||
def other_children
|
||||
[]
|
||||
end
|
||||
|
||||
def remove(d)
|
||||
self.decls.delete(d)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ public:
|
|||
* This feature is not quite useful usually and is reserved for special use cases
|
||||
* such as including enums into a declaration namespace.
|
||||
*/
|
||||
ClassExt (const ClassBase &import, const std::string &name, const std::string &doc = std::string ())
|
||||
ClassExt (const ClassBase &import, const std::string &name = std::string (), const std::string &doc = std::string ())
|
||||
: ClassBase (doc, Methods ()), mp_declaration (&import)
|
||||
{
|
||||
set_name (name);
|
||||
|
|
|
|||
|
|
@ -1664,5 +1664,32 @@ static gsi::Class<GFactory_P> decl_gfactory (decl_gfactory_base, "", "GFactory",
|
|||
gsi::factory_callback ("f", &GFactory_P::f, &GFactory_P::f_cb)
|
||||
);
|
||||
|
||||
static gsi::Class<B1> decl_b1 ("", "B1",
|
||||
gsi::method ("get1", &B1::get1) +
|
||||
gsi::method ("set1", &B1::set1) +
|
||||
gsi::constant ("C1", 42)
|
||||
);
|
||||
|
||||
static gsi::Class<B2> decl_b2 ("", "B2",
|
||||
gsi::constant ("C2", 17)
|
||||
);
|
||||
|
||||
static gsi::Class<B3> decl_b3 ("", "B3",
|
||||
gsi::constant ("C3", -1)
|
||||
);
|
||||
|
||||
gsi::EnumIn<B3, B3::E> enum_in_b3 ("", "E",
|
||||
gsi::enum_const ("E3A", B3::E3A) +
|
||||
gsi::enum_const ("E3B", B3::E3B) +
|
||||
gsi::enum_const ("E3C", B3::E3C)
|
||||
);
|
||||
|
||||
// 3 base classes
|
||||
static gsi::Class<BB> decl_bb (decl_b1, "", "BB",
|
||||
gsi::method ("d3", &BB::d3)
|
||||
);
|
||||
gsi::ClassExt<BB> b2_in_bb (decl_b2);
|
||||
gsi::ClassExt<BB> b3_in_bb (decl_b3);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1397,6 +1397,37 @@ private:
|
|||
int m_tag;
|
||||
};
|
||||
|
||||
class B1
|
||||
{
|
||||
public:
|
||||
B1 () : m_value (0) {}
|
||||
|
||||
int get1 () { return m_value; }
|
||||
void set1 (int v) { m_value = v; }
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
class B2
|
||||
{
|
||||
public:
|
||||
B2 () {}
|
||||
};
|
||||
|
||||
class B3
|
||||
{
|
||||
public:
|
||||
B3 () {}
|
||||
enum E { E3A = 100, E3B = 101, E3C = 102 };
|
||||
};
|
||||
|
||||
class BB
|
||||
: public B1, public B2, public B3
|
||||
{
|
||||
public:
|
||||
int d3 (B3::E a, B3::E b) { return b - a; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -846,6 +846,11 @@ qt_gsi::QtNativeClass<QIODevice> decl_QIODevice (qtdecl_QObject (), "QtCore", "Q
|
|||
methods_QIODevice (),
|
||||
"@qt\n@brief Binding of QIODevice");
|
||||
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QIODeviceBase> &qtdecl_QIODeviceBase ();
|
||||
|
||||
gsi::ClassExt<QIODevice> base_class_QIODeviceBase_in_QIODevice (qtdecl_QIODeviceBase ());
|
||||
|
||||
GSI_QTCORE_PUBLIC gsi::Class<QIODevice> &qtdecl_QIODevice () { return decl_QIODevice; }
|
||||
|
||||
|
|
|
|||
|
|
@ -776,6 +776,19 @@ gsi::Class<QXmlContentHandler> &qtdecl_QXmlContentHandler ();
|
|||
gsi::Class<QXmlDefaultHandler> decl_QXmlDefaultHandler (qtdecl_QXmlContentHandler (), "QtCore5Compat", "QXmlDefaultHandler_Native",
|
||||
methods_QXmlDefaultHandler (),
|
||||
"@hide\n@alias QXmlDefaultHandler");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QXmlErrorHandler> &qtdecl_QXmlErrorHandler ();
|
||||
gsi::Class<QXmlDTDHandler> &qtdecl_QXmlDTDHandler ();
|
||||
gsi::Class<QXmlEntityResolver> &qtdecl_QXmlEntityResolver ();
|
||||
gsi::Class<QXmlLexicalHandler> &qtdecl_QXmlLexicalHandler ();
|
||||
gsi::Class<QXmlDeclHandler> &qtdecl_QXmlDeclHandler ();
|
||||
|
||||
gsi::ClassExt<QXmlDefaultHandler> base_class_QXmlErrorHandler_in_QXmlDefaultHandler (qtdecl_QXmlErrorHandler ());
|
||||
gsi::ClassExt<QXmlDefaultHandler> base_class_QXmlDTDHandler_in_QXmlDefaultHandler (qtdecl_QXmlDTDHandler ());
|
||||
gsi::ClassExt<QXmlDefaultHandler> base_class_QXmlEntityResolver_in_QXmlDefaultHandler (qtdecl_QXmlEntityResolver ());
|
||||
gsi::ClassExt<QXmlDefaultHandler> base_class_QXmlLexicalHandler_in_QXmlDefaultHandler (qtdecl_QXmlLexicalHandler ());
|
||||
gsi::ClassExt<QXmlDefaultHandler> base_class_QXmlDeclHandler_in_QXmlDefaultHandler (qtdecl_QXmlDeclHandler ());
|
||||
|
||||
GSI_QTCORE5COMPAT_PUBLIC gsi::Class<QXmlDefaultHandler> &qtdecl_QXmlDefaultHandler () { return decl_QXmlDefaultHandler; }
|
||||
|
||||
|
|
|
|||
|
|
@ -313,6 +313,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QOffscreenSurface> decl_QOffscreenSurface (qtdecl_QObject (), "QtGui", "QOffscreenSurface_Native",
|
||||
methods_QOffscreenSurface (),
|
||||
"@hide\n@alias QOffscreenSurface");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QSurface> &qtdecl_QSurface ();
|
||||
|
||||
gsi::ClassExt<QOffscreenSurface> base_class_QSurface_in_QOffscreenSurface (qtdecl_QSurface ());
|
||||
|
||||
GSI_QTGUI_PUBLIC gsi::Class<QOffscreenSurface> &qtdecl_QOffscreenSurface () { return decl_QOffscreenSurface; }
|
||||
|
||||
|
|
|
|||
|
|
@ -297,6 +297,11 @@ gsi::Class<QWindow> &qtdecl_QWindow ();
|
|||
qt_gsi::QtNativeClass<QPaintDeviceWindow> decl_QPaintDeviceWindow (qtdecl_QWindow (), "QtGui", "QPaintDeviceWindow_Native",
|
||||
methods_QPaintDeviceWindow (),
|
||||
"@hide\n@alias QPaintDeviceWindow");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QPaintDevice> &qtdecl_QPaintDevice ();
|
||||
|
||||
gsi::ClassExt<QPaintDeviceWindow> base_class_QPaintDevice_in_QPaintDeviceWindow (qtdecl_QPaintDevice ());
|
||||
|
||||
GSI_QTGUI_PUBLIC gsi::Class<QPaintDeviceWindow> &qtdecl_QPaintDeviceWindow () { return decl_QPaintDeviceWindow; }
|
||||
|
||||
|
|
|
|||
|
|
@ -382,6 +382,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QPdfWriter> decl_QPdfWriter (qtdecl_QObject (), "QtGui", "QPdfWriter_Native",
|
||||
methods_QPdfWriter (),
|
||||
"@hide\n@alias QPdfWriter");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QPagedPaintDevice> &qtdecl_QPagedPaintDevice ();
|
||||
|
||||
gsi::ClassExt<QPdfWriter> base_class_QPagedPaintDevice_in_QPdfWriter (qtdecl_QPagedPaintDevice ());
|
||||
|
||||
GSI_QTGUI_PUBLIC gsi::Class<QPdfWriter> &qtdecl_QPdfWriter () { return decl_QPdfWriter; }
|
||||
|
||||
|
|
|
|||
|
|
@ -2206,6 +2206,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QWindow> decl_QWindow (qtdecl_QObject (), "QtGui", "QWindow_Native",
|
||||
methods_QWindow (),
|
||||
"@hide\n@alias QWindow");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QSurface> &qtdecl_QSurface ();
|
||||
|
||||
gsi::ClassExt<QWindow> base_class_QSurface_in_QWindow (qtdecl_QSurface ());
|
||||
|
||||
GSI_QTGUI_PUBLIC gsi::Class<QWindow> &qtdecl_QWindow () { return decl_QWindow; }
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,11 @@ gsi::Class<QAccessibleWidget> decl_QAccessibleWidget (qtdecl_QAccessibleObject (
|
|||
methods_QAccessibleWidget (),
|
||||
"@qt\n@brief Binding of QAccessibleWidget");
|
||||
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QAccessibleActionInterface> &qtdecl_QAccessibleActionInterface ();
|
||||
|
||||
gsi::ClassExt<QAccessibleWidget> base_class_QAccessibleActionInterface_in_QAccessibleWidget (qtdecl_QAccessibleActionInterface ());
|
||||
|
||||
GSI_QTWIDGETS_PUBLIC gsi::Class<QAccessibleWidget> &qtdecl_QAccessibleWidget () { return decl_QAccessibleWidget; }
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#include <QTimerEvent>
|
||||
#include <QTransform>
|
||||
#include <QWidget>
|
||||
#include <QGraphicsTransform>
|
||||
#include "gsiQt.h"
|
||||
#include "gsiQtWidgetsCommon.h"
|
||||
#include <memory>
|
||||
|
|
@ -242,6 +243,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QGraphicsObject> decl_QGraphicsObject (qtdecl_QObject (), "QtWidgets", "QGraphicsObject_Native",
|
||||
methods_QGraphicsObject (),
|
||||
"@hide\n@alias QGraphicsObject");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QGraphicsItem> &qtdecl_QGraphicsItem ();
|
||||
|
||||
gsi::ClassExt<QGraphicsObject> base_class_QGraphicsItem_in_QGraphicsObject (qtdecl_QGraphicsItem ());
|
||||
|
||||
GSI_QTWIDGETS_PUBLIC gsi::Class<QGraphicsObject> &qtdecl_QGraphicsObject () { return decl_QGraphicsObject; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1374,6 +1374,11 @@ gsi::Class<QGraphicsObject> &qtdecl_QGraphicsObject ();
|
|||
qt_gsi::QtNativeClass<QGraphicsWidget> decl_QGraphicsWidget (qtdecl_QGraphicsObject (), "QtWidgets", "QGraphicsWidget_Native",
|
||||
methods_QGraphicsWidget (),
|
||||
"@hide\n@alias QGraphicsWidget");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QGraphicsLayoutItem> &qtdecl_QGraphicsLayoutItem ();
|
||||
|
||||
gsi::ClassExt<QGraphicsWidget> base_class_QGraphicsLayoutItem_in_QGraphicsWidget (qtdecl_QGraphicsLayoutItem ());
|
||||
|
||||
GSI_QTWIDGETS_PUBLIC gsi::Class<QGraphicsWidget> &qtdecl_QGraphicsWidget () { return decl_QGraphicsWidget; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1013,6 +1013,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QLayout> decl_QLayout (qtdecl_QObject (), "QtWidgets", "QLayout_Native",
|
||||
methods_QLayout (),
|
||||
"@hide\n@alias QLayout");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QLayoutItem> &qtdecl_QLayoutItem ();
|
||||
|
||||
gsi::ClassExt<QLayout> base_class_QLayoutItem_in_QLayout (qtdecl_QLayoutItem ());
|
||||
|
||||
GSI_QTWIDGETS_PUBLIC gsi::Class<QLayout> &qtdecl_QLayout () { return decl_QLayout; }
|
||||
|
||||
|
|
|
|||
|
|
@ -4981,6 +4981,11 @@ gsi::Class<QObject> &qtdecl_QObject ();
|
|||
qt_gsi::QtNativeClass<QWidget> decl_QWidget (qtdecl_QObject (), "QtWidgets", "QWidget_Native",
|
||||
methods_QWidget (),
|
||||
"@hide\n@alias QWidget");
|
||||
// Additional base classes
|
||||
|
||||
gsi::Class<QPaintDevice> &qtdecl_QPaintDevice ();
|
||||
|
||||
gsi::ClassExt<QWidget> base_class_QPaintDevice_in_QWidget (qtdecl_QPaintDevice ());
|
||||
|
||||
GSI_QTWIDGETS_PUBLIC gsi::Class<QWidget> &qtdecl_QWidget () { return decl_QWidget; }
|
||||
|
||||
|
|
|
|||
|
|
@ -2384,6 +2384,10 @@ PythonModule::make_classes (const char *mod_name)
|
|||
PYASignal::make_class (module);
|
||||
|
||||
std::list<const gsi::ClassBase *> sorted_classes = gsi::ClassBase::classes_in_definition_order (mod_name);
|
||||
|
||||
// ... @@@ find all extensions for a class ...
|
||||
|
||||
// ... @@@ reverse this order ...
|
||||
for (std::list<const gsi::ClassBase *>::const_iterator c = sorted_classes.begin (); c != sorted_classes.end (); ++c) {
|
||||
|
||||
if (mod_name && (*c)->module () != mod_name) {
|
||||
|
|
@ -2398,6 +2402,7 @@ PythonModule::make_classes (const char *mod_name)
|
|||
// duplication of enums into child classes). In this case we create a constant inside the
|
||||
// target class.
|
||||
if ((*c)->declaration () != *c) {
|
||||
// ... @@@ continue if named ...
|
||||
tl_assert ((*c)->parent () != 0); // top-level classes should be merged
|
||||
PyTypeObject *parent_type = PythonClassClientData::py_type (*(*c)->parent ()->declaration ());
|
||||
PyTypeObject *type = PythonClassClientData::py_type (*(*c)->declaration ());
|
||||
|
|
@ -2414,6 +2419,7 @@ PythonModule::make_classes (const char *mod_name)
|
|||
m_classes.push_back (*c);
|
||||
|
||||
PythonRef bases;
|
||||
// ... @@@ collect bases (from this base and extensions) ...
|
||||
if ((*c)->base () != 0) {
|
||||
bases = PythonRef (PyTuple_New (1));
|
||||
PyTypeObject *pt = PythonClassClientData::py_type (*(*c)->base ());
|
||||
|
|
@ -2465,6 +2471,8 @@ PythonModule::make_classes (const char *mod_name)
|
|||
PyModule_AddObject (module, (*c)->name ().c_str (), (PyObject *) type);
|
||||
}
|
||||
|
||||
// ... @@@ add the named extensions as attributes (see above) ...
|
||||
|
||||
// Build the attributes now ...
|
||||
|
||||
MethodTable *mt = MethodTable::method_table_by_class (*c);
|
||||
|
|
|
|||
|
|
@ -1111,7 +1111,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
}
|
||||
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// break encountered
|
||||
}
|
||||
|
||||
|
|
@ -1521,52 +1521,112 @@ rba_add_path (const std::string &path)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rba_init (RubyInterpreterPrivateData *d)
|
||||
namespace
|
||||
{
|
||||
VALUE module = rb_define_module ("RBA");
|
||||
|
||||
// initialize the locked object vault as a fast replacement for rb_gc_register_address/rb_gc_unregister_address.
|
||||
rba::make_locked_object_vault (module);
|
||||
class RubyClassGenerator
|
||||
{
|
||||
public:
|
||||
RubyClassGenerator (VALUE module)
|
||||
: m_module (module)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
// save all constants for later (we cannot declare them while we are still producing classes
|
||||
// because of the enum representative classes and enum constants are important)
|
||||
std::vector <RubyConstDescriptor> constants;
|
||||
// needs to be called before for each extension before the classes are made
|
||||
void register_extension (const gsi::ClassBase *cls)
|
||||
{
|
||||
if (cls->name ().empty ()) {
|
||||
|
||||
std::list<const gsi::ClassBase *> sorted_classes = gsi::ClassBase::classes_in_definition_order ();
|
||||
for (std::list<const gsi::ClassBase *>::const_iterator c = sorted_classes.begin (); c != sorted_classes.end (); ++c) {
|
||||
// got an extension
|
||||
tl_assert (cls->parent ());
|
||||
m_extensions_for [cls->parent ()->declaration ()].push_back (cls->declaration ());
|
||||
m_extensions.insert (cls->declaration ());
|
||||
|
||||
// we might encounter a child class which is a reference to a top-level class (e.g.
|
||||
// duplication of enums into child classes). In this case we create a constant inside the
|
||||
// target class.
|
||||
if ((*c)->declaration () != *c) {
|
||||
tl_assert ((*c)->parent () != 0); // top-level classes should be merged
|
||||
rb_define_const (ruby_cls ((*c)->parent ()->declaration ()), (*c)->name ().c_str (), ruby_cls ((*c)->declaration ()));
|
||||
continue;
|
||||
} else {
|
||||
|
||||
m_links_for [cls->parent ()->declaration ()].push_back (std::make_pair (cls->name (), cls->declaration ()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VALUE make_class (const gsi::ClassBase *cls)
|
||||
{
|
||||
if (is_registered (cls)) {
|
||||
return ruby_cls (cls);
|
||||
}
|
||||
|
||||
bool is_extension = (m_extensions.find (cls) != m_extensions.end ());
|
||||
|
||||
bool base_class_is_extension = (m_extensions.find (cls->base ()) != m_extensions.end ());
|
||||
|
||||
VALUE super = rb_cObject;
|
||||
if ((*c)->base () != 0) {
|
||||
tl_assert (is_registered ((*c)->base ()));
|
||||
super = ruby_cls ((*c)->base ());
|
||||
if (cls->base () != 0) {
|
||||
super = make_class (cls->base ());
|
||||
}
|
||||
|
||||
VALUE klass;
|
||||
if ((*c)->parent ()) {
|
||||
tl_assert (is_registered ((*c)->parent ()->declaration ()));
|
||||
VALUE parent_class = ruby_cls ((*c)->parent ()->declaration ());
|
||||
klass = rb_define_class_under (parent_class, (*c)->name ().c_str (), super);
|
||||
if (is_extension) {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << tl::to_string (tr ("Registering class as Ruby module:) ")) << cls->name ();
|
||||
}
|
||||
if (cls->base () && ! base_class_is_extension) {
|
||||
tl::warn << tl::to_string (tr ("Base class of mixin module ignored: ")) << cls->name ();
|
||||
}
|
||||
|
||||
if (cls->parent ()) {
|
||||
VALUE parent_class = make_class (cls->parent ()->declaration ());
|
||||
klass = rb_define_module_under (parent_class, cls->name ().c_str ());
|
||||
} else {
|
||||
klass = rb_define_module_under (m_module, cls->name ().c_str ());
|
||||
}
|
||||
|
||||
} else {
|
||||
klass = rb_define_class_under (module, (*c)->name ().c_str (), super);
|
||||
|
||||
VALUE direct_super = base_class_is_extension ? rb_cObject : super;
|
||||
if (cls->parent ()) {
|
||||
VALUE parent_class = make_class (cls->parent ()->declaration ());
|
||||
klass = rb_define_class_under (parent_class, cls->name ().c_str (), direct_super);
|
||||
} else {
|
||||
klass = rb_define_class_under (m_module, cls->name ().c_str (), direct_super);
|
||||
}
|
||||
|
||||
rb_define_alloc_func (klass, alloc_proxy);
|
||||
|
||||
}
|
||||
|
||||
register_class (klass, *c);
|
||||
// if the base class is an extension (mixin), we cannot use it as superclass because it's a module
|
||||
if (cls->base () != 0 && base_class_is_extension) {
|
||||
rb_include_module (klass, super);
|
||||
}
|
||||
|
||||
rb_define_alloc_func (klass, alloc_proxy);
|
||||
register_class (klass, cls);
|
||||
|
||||
MethodTable *mt = MethodTable::method_table_by_class (*c, true /*force init*/);
|
||||
// mix-in unnamed extensions
|
||||
|
||||
for (gsi::ClassBase::method_iterator m = (*c)->begin_methods (); m != (*c)->end_methods (); ++m) {
|
||||
auto exts = m_extensions_for.find (cls);
|
||||
if (exts != m_extensions_for.end ()) {
|
||||
for (auto ie = exts->second.begin (); ie != exts->second.end (); ++ie) {
|
||||
VALUE ext_module = make_class (*ie);
|
||||
rb_include_module (klass, ext_module);
|
||||
rb_extend_object (klass, ext_module);
|
||||
}
|
||||
}
|
||||
|
||||
// add named extensions
|
||||
|
||||
auto links = m_links_for.find (cls);
|
||||
if (links != m_links_for.end ()) {
|
||||
for (auto il = links->second.begin (); il != links->second.end (); ++il) {
|
||||
VALUE linked_class = make_class (il->second);
|
||||
rb_define_const (klass, il->first.c_str (), linked_class);
|
||||
}
|
||||
}
|
||||
|
||||
MethodTable *mt = MethodTable::method_table_by_class (cls, true /*force init*/);
|
||||
|
||||
for (auto m = (cls)->begin_methods (); m != (cls)->end_methods (); ++m) {
|
||||
|
||||
if (! (*m)->is_callback ()) {
|
||||
|
||||
|
|
@ -1582,7 +1642,7 @@ rba_init (RubyInterpreterPrivateData *d)
|
|||
|
||||
if (! drop_method) {
|
||||
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
for (auto syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
if (syn->is_predicate) {
|
||||
mt->add_method (syn->name, *m);
|
||||
mt->add_method (syn->name + "?", *m);
|
||||
|
|
@ -1597,17 +1657,17 @@ rba_init (RubyInterpreterPrivateData *d)
|
|||
|
||||
} else {
|
||||
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
for (auto syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
|
||||
if (isupper (syn->name [0]) && (*m)->begin_arguments () == (*m)->end_arguments ()) {
|
||||
|
||||
// Static const methods are constants.
|
||||
// Methods without arguments which start with a capital letter are treated as constants
|
||||
// for backward compatibility
|
||||
constants.push_back (RubyConstDescriptor ());
|
||||
constants.back ().klass = klass;
|
||||
constants.back ().meth = *m;
|
||||
constants.back ().name = (*m)->begin_synonyms ()->name;
|
||||
m_constants.push_back (RubyConstDescriptor ());
|
||||
m_constants.back ().klass = klass;
|
||||
m_constants.back ().meth = *m;
|
||||
m_constants.back ().name = (*m)->begin_synonyms ()->name;
|
||||
|
||||
} else if ((*m)->ret_type ().type () == gsi::T_object && (*m)->ret_type ().pass_obj () && syn->name == "new") {
|
||||
|
||||
|
|
@ -1640,96 +1700,150 @@ rba_init (RubyInterpreterPrivateData *d)
|
|||
// clean up the method table
|
||||
mt->finish ();
|
||||
|
||||
// Hint: we need to do static methods before the non-static ones because
|
||||
// rb_define_module_function creates an private instance method.
|
||||
// If we do the non-static methods afterwards we will make it a public once again.
|
||||
// The order of the names will be "name(non-static), name(static), ..." because
|
||||
// the static flag is the second member of the key (string, bool) pair.
|
||||
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
||||
// NOTE: extensions can't carry methods - this is due to the method numbering scheme
|
||||
// which can only handle direct base classes. So only constants are carried forward.
|
||||
if (! is_extension) {
|
||||
|
||||
if (mt->is_static (mid)) {
|
||||
// Hint: we need to do static methods before the non-static ones because
|
||||
// rb_define_module_function creates an private instance method.
|
||||
// If we do the non-static methods afterwards we will make it a public once again.
|
||||
// The order of the names will be "name(non-static), name(static), ..." because
|
||||
// the static flag is the second member of the key (string, bool) pair.
|
||||
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors) / sizeof (method_adaptors [0])));
|
||||
if (mt->is_static (mid)) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors) / sizeof (method_adaptors [0])));
|
||||
|
||||
/* Note: Ruby does not support static protected functions, hence we have them (i.e. QThread::usleep).
|
||||
* Do we silently create public ones from them:
|
||||
if (mt->is_protected (mid)) {
|
||||
tl::warn << "static '" << mt->name (mid) << "' method cannot be protected in class " << c->name ();
|
||||
}
|
||||
*/
|
||||
|
||||
rb_define_module_function (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
|
||||
/* Note: Ruby does not support static protected functions, hence we have them (i.e. QThread::usleep).
|
||||
* Do we silently create public ones from them:
|
||||
if (mt->is_protected (mid)) {
|
||||
tl::warn << "static '" << mt->name (mid) << "' method cannot be protected in class " << c->name ();
|
||||
}
|
||||
*/
|
||||
|
||||
rb_define_module_function (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
}
|
||||
|
||||
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
||||
|
||||
if (mt->is_ctor (mid)) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors_ctor) / sizeof (method_adaptors_ctor [0])));
|
||||
|
||||
if (! mt->is_protected (mid)) {
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
} else {
|
||||
// a protected constructor needs to be provided in both protected and non-protected mode
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
rb_define_protected_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
}
|
||||
|
||||
} else if (! mt->is_static (mid)) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors) / sizeof (method_adaptors [0])));
|
||||
|
||||
if (! mt->is_protected (mid)) {
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
} else {
|
||||
rb_define_protected_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mt->is_signal (mid)) {
|
||||
|
||||
// We alias the signal name to an assignment, so the following can be done:
|
||||
// x = object with signal "signal"
|
||||
// x.signal = proc
|
||||
// this will basically map to
|
||||
// x.signal(proc)
|
||||
// which will make proc the only receiver for the signal
|
||||
rb_define_alias (klass, (mt->name (mid) + "=").c_str (), mt->name (mid).c_str ());
|
||||
|
||||
}
|
||||
|
||||
if (mt->name (mid) == "to_s") {
|
||||
#if HAVE_RUBY_VERSION_CODE>=20000 && defined(GSI_ALIAS_INSPECT)
|
||||
// Ruby 2.x does no longer alias "inspect" to "to_s" automatically, so we have to do this:
|
||||
rb_define_alias (klass, "inspect", "to_s");
|
||||
#endif
|
||||
} else if (mt->name (mid) == "==") {
|
||||
rb_define_alias (klass, "eql?", "==");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
||||
return klass;
|
||||
}
|
||||
|
||||
if (mt->is_ctor (mid)) {
|
||||
void make_constants ()
|
||||
{
|
||||
for (auto c = m_constants.begin (); c != m_constants.end (); ++c) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors_ctor) / sizeof (method_adaptors_ctor [0])));
|
||||
try {
|
||||
|
||||
if (! mt->is_protected (mid)) {
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
} else {
|
||||
// a protected constructor needs to be provided in both protected and non-protected mode
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
rb_define_protected_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors_ctor[mid], -1);
|
||||
}
|
||||
gsi::SerialArgs retlist (c->meth->retsize ());
|
||||
gsi::SerialArgs arglist (c->meth->argsize ());
|
||||
c->meth->call (0, arglist, retlist);
|
||||
tl::Heap heap;
|
||||
VALUE ret = pop_arg (c->meth->ret_type (), 0, retlist, heap);
|
||||
rb_define_const (c->klass, c->name.c_str (), ret);
|
||||
|
||||
} else if (! mt->is_static (mid)) {
|
||||
|
||||
tl_assert (mid < size_t (sizeof (method_adaptors) / sizeof (method_adaptors [0])));
|
||||
|
||||
if (! mt->is_protected (mid)) {
|
||||
rb_define_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
} else {
|
||||
rb_define_protected_method (klass, mt->name (mid).c_str (), (ruby_func) method_adaptors[mid], -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mt->is_signal (mid)) {
|
||||
// We alias the signal name to an assignment, so the following can be done:
|
||||
// x = object with signal "signal"
|
||||
// x.signal = proc
|
||||
// this will basically map to
|
||||
// x.signal(proc)
|
||||
// which will make proc the only receiver for the signal
|
||||
rb_define_alias (klass, (mt->name (mid) + "=").c_str (), mt->name (mid).c_str ());
|
||||
}
|
||||
|
||||
if (mt->name (mid) == "to_s") {
|
||||
#if HAVE_RUBY_VERSION_CODE>=20000 && defined(GSI_ALIAS_INSPECT)
|
||||
// Ruby 2.x does no longer alias "inspect" to "to_s" automatically, so we have to do this:
|
||||
rb_define_alias (klass, "inspect", "to_s");
|
||||
#endif
|
||||
} else if (mt->name (mid) == "==") {
|
||||
rb_define_alias (klass, "eql?", "==");
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << "Got exception '" << ex.msg () << "' while defining constant " << c->name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VALUE m_module;
|
||||
std::vector <RubyConstDescriptor> m_constants;
|
||||
std::map<const gsi::ClassBase *, std::vector<const gsi::ClassBase *> > m_extensions_for;
|
||||
std::set<const gsi::ClassBase *> m_extensions;
|
||||
std::map<const gsi::ClassBase *, std::vector<std::pair<std::string, const gsi::ClassBase *> > > m_links_for;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
rba_init (RubyInterpreterPrivateData *d)
|
||||
{
|
||||
VALUE module = rb_define_module ("RBA");
|
||||
|
||||
// initialize the locked object vault as a fast replacement for rb_gc_register_address/rb_gc_unregister_address.
|
||||
rba::make_locked_object_vault (module);
|
||||
|
||||
// save all constants for later (we cannot declare them while we are still producing classes
|
||||
// because of the enum representative classes and enum constants are important)
|
||||
std::vector <RubyConstDescriptor> constants;
|
||||
|
||||
std::list<const gsi::ClassBase *> sorted_classes = gsi::ClassBase::classes_in_definition_order ();
|
||||
|
||||
RubyClassGenerator gen (module);
|
||||
|
||||
// first pass: register the extensions
|
||||
for (auto c = sorted_classes.begin (); c != sorted_classes.end (); ++c) {
|
||||
if ((*c)->declaration () != *c) {
|
||||
gen.register_extension (*c);
|
||||
}
|
||||
}
|
||||
|
||||
// second pass: make the classes
|
||||
for (auto c = sorted_classes.begin (); c != sorted_classes.end (); ++c) {
|
||||
if ((*c)->declaration () == *c) {
|
||||
gen.make_class (*c);
|
||||
}
|
||||
}
|
||||
|
||||
// now make the constants
|
||||
for (std::vector <RubyConstDescriptor>::const_iterator c = constants.begin (); c != constants.end (); ++c) {
|
||||
|
||||
try {
|
||||
|
||||
gsi::SerialArgs retlist (c->meth->retsize ());
|
||||
gsi::SerialArgs arglist (c->meth->argsize ());
|
||||
c->meth->call (0, arglist, retlist);
|
||||
tl::Heap heap;
|
||||
VALUE ret = pop_arg (c->meth->ret_type (), 0, retlist, heap);
|
||||
rb_define_const (c->klass, c->name.c_str (), ret);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << "Got exception '" << ex.msg () << "' while defining constant " << c->name;
|
||||
}
|
||||
|
||||
}
|
||||
gen.make_constants ();
|
||||
|
||||
// define a signal representative class RBASignal
|
||||
SignalHandler::define_class (module, "RBASignal");
|
||||
|
|
|
|||
|
|
@ -3012,6 +3012,23 @@ class Basic_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Tests multi-base mixins (only constants and enums available)
|
||||
def test_multiBaseMixins
|
||||
|
||||
bb = RBA::BB::new # base classes B1,B2,B3
|
||||
bb.set1(17) # B1
|
||||
assert_equal(bb.get1, 17) # B1
|
||||
bb.set1(21) # B1
|
||||
|
||||
assert_equal(bb.get1, 21) # B1
|
||||
assert_equal(RBA::BB::C2, 17) # B2
|
||||
assert_equal(RBA::BB::C3, -1) # B3
|
||||
assert_equal(RBA::BB::E::E3B.to_i, 101) # B3
|
||||
assert_equal(bb.d3(RBA::BB::E::E3C, RBA::BB::E::E3A), -2) # BB with B3 enums
|
||||
assert_equal(bb.d3(RBA::BB::E::E3A, RBA::BB::E::E3C), 2) # BB with B3 enums
|
||||
|
||||
end
|
||||
|
||||
# Custom factory implemented in Ruby
|
||||
def test_80
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue