You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3634 lines
126 KiB
3634 lines
126 KiB
#***************************************************************************
|
|
# kalyptusCxxToKimono.pm - Generates *.cs files for a Custom RealProxy
|
|
# based smoke adaptor
|
|
# -------------------
|
|
# begin : Thurs Feb 19 12:00:00 2004
|
|
# copyright : (C) 2004, Richard Dale. All Rights Reserved.
|
|
# email : Richard_Dale@tipitina.demon.co.uk
|
|
# author : Richard Dale, based on the SMOKE generation code
|
|
#***************************************************************************/
|
|
|
|
#/***************************************************************************
|
|
# * *
|
|
# * This program is free software; you can redistribute it and/or modify *
|
|
# * it under the terms of the GNU General Public License as published by *
|
|
# * the Free Software Foundation; either version 2 of the License, or *
|
|
# * (at your option) any later version. *
|
|
# * *
|
|
#***************************************************************************/
|
|
|
|
package kalyptusCxxToKimono;
|
|
|
|
use File::Path;
|
|
use File::Basename;
|
|
|
|
use Carp;
|
|
use Ast;
|
|
use kdocAstUtil;
|
|
use kdocUtil;
|
|
use Iter;
|
|
use kalyptusDataDict;
|
|
|
|
use strict;
|
|
no strict "subs";
|
|
|
|
use vars qw/
|
|
$libname $rootnode $outputdir $opt $debug
|
|
$qapplicationExtras $qbitmapExtras $qbytearrayExtras
|
|
$qlistviewExtras $qlistviewitemExtras
|
|
$qdragobjectExtras $qdropeventExtras $qmimesourceExtras
|
|
$qtExtras $qobjectExtras $qwidgetExtras
|
|
$qpixmapExtras $qpaintdeviceExtras
|
|
$qdragobjectExtras $qiodeviceExtras $qpointarrayExtras
|
|
$qtextcodecExtras $qsizepolicyExtras $quridragExtras
|
|
$kapplicationExtras $kmainwindowExtras
|
|
$methodNumber
|
|
%builtins %typeunion %allMethods %allTypes %enumValueToType %typedeflist %mungedTypeMap %csharpImports
|
|
%skippedClasses %operatorNames /;
|
|
|
|
BEGIN
|
|
{
|
|
|
|
# Types supported by the StackItem union
|
|
# Key: C++ type Value: Union field of that type
|
|
%typeunion = (
|
|
'void*' => 's_voidp',
|
|
'bool' => 's_bool',
|
|
'char' => 's_char',
|
|
'uchar' => 's_uchar',
|
|
'short' => 's_short',
|
|
'ushort' => 's_ushort',
|
|
'int' => 's_int',
|
|
'uint' => 's_uint',
|
|
'long' => 's_long',
|
|
'ulong' => 's_ulong',
|
|
'float' => 's_float',
|
|
'double' => 's_double',
|
|
'enum' => 's_enum',
|
|
'class' => 's_class'
|
|
);
|
|
|
|
# Mapping for iterproto, when making up the munged method names
|
|
%mungedTypeMap = (
|
|
'TQString' => '$',
|
|
'TQString*' => '$',
|
|
'TQString&' => '$',
|
|
'TQCString' => '$',
|
|
'TQCString*' => '$',
|
|
'TQCString&' => '$',
|
|
'char*' => '$',
|
|
'TQCOORD*' => '?',
|
|
'TQRgb*' => '?',
|
|
'TQ_UINT64' => '$',
|
|
'TQ_INT64' => '$',
|
|
'TQ_LLONG' => '$',
|
|
'tquint64' => '$',
|
|
'qint64' => '$',
|
|
'long long' => '$',
|
|
'qulonglong' => '$',
|
|
);
|
|
|
|
# Yes some of this is in kalyptusDataDict's ctypemap
|
|
# but that one would need to be separated (builtins vs normal classes)
|
|
%typedeflist =
|
|
(
|
|
'signed char' => 'char',
|
|
'unsigned char' => 'uchar',
|
|
'signed short' => 'short',
|
|
'unsigned short' => 'ushort',
|
|
'signed' => 'int',
|
|
'signed int' => 'int',
|
|
'unsigned' => 'uint',
|
|
'unsigned int' => 'uint',
|
|
'KIO::filesize_t' => 'long',
|
|
'signed long' => 'long',
|
|
'unsigned long' => 'ulong',
|
|
|
|
# Anything that is not known is mapped to void*, so no need for those here anymore
|
|
# 'TQWSEvent*' => 'void*',
|
|
# 'TQDiskFont*' => 'void*',
|
|
# 'XEvent*' => 'void*',
|
|
# 'FILE*' => 'void*',
|
|
# 'TQUnknownInterface*' => 'void*',
|
|
# 'GDHandle' => 'void*',
|
|
# '_NPStream*' => 'void*',
|
|
# 'TQTextFormat*' => 'void*',
|
|
# 'TQTextDocument*' => 'void*',
|
|
# 'TQTextCursor*' => 'void*',
|
|
# 'TQTextParag**' => 'void*',
|
|
# 'TQTextParag*' => 'void*',
|
|
# 'TQRemoteInterface*' => 'void*',
|
|
# 'TQSqlRecordPrivate*' => 'void*',
|
|
# 'TQTSMFI' => 'void*', # TQTextStream's TQTSManip
|
|
# 'const GUID&' => 'void*',
|
|
# 'TQWidgetMapper*' => 'void*',
|
|
# 'MSG*' => 'void*',
|
|
# 'const TQSqlFieldInfoList&' => 'void*', # TQSqlRecordInfo - TODO (templates)
|
|
|
|
'TQStyleHintReturn*' => 'void*',
|
|
'TQPtrCollection::Item' => 'void*', # to avoid a warning
|
|
|
|
'mode_t' => 'long',
|
|
'TQProcess::PID' => 'long',
|
|
'size_type' => 'int', # TQSqlRecordInfo
|
|
'TQt::ComparisonFlags' => 'uint',
|
|
'TQt::ToolBarDock' => 'int', # compat thing, Qt shouldn't use it
|
|
'TQIODevice::Offset' => 'ulong',
|
|
'WState' => 'int',
|
|
'WId' => 'ulong',
|
|
'TQRgb' => 'uint',
|
|
'ksocklen_t' => 'uint',
|
|
'TQCOORD' => 'int',
|
|
'TQTSMFI' => 'int',
|
|
'TQt::WState' => 'int',
|
|
'TQt::WFlags' => 'int',
|
|
'TQt::HANDLE' => 'uint',
|
|
'TQEventLoop::ProcessEventsFlags' => 'uint',
|
|
'TQStyle::SCFlags' => 'int',
|
|
'TQStyle::SFlags' => 'int',
|
|
'TQ_INT16' => 'short',
|
|
'qint16' => 'short',
|
|
'TQ_INT32' => 'int',
|
|
'qint32' => 'int',
|
|
'qint32&' => 'int&',
|
|
'TQ_INT8' => 'char',
|
|
'qint8' => 'char',
|
|
'TQ_LONG' => 'long',
|
|
'TQ_UINT16' => 'ushort',
|
|
'tquint16' => 'ushort',
|
|
'TQ_UINT32' => 'uint',
|
|
'tquint32' => 'uint',
|
|
'TQ_UINT8' => 'uchar',
|
|
'tquint8' => 'uchar',
|
|
'TQ_ULONG' => 'long',
|
|
'qreal' => 'double',
|
|
'pid_t' => 'int',
|
|
'size_t' => 'int',
|
|
'pid_t' => 'int',
|
|
'time_t' => 'int',
|
|
'short int' => 'short',
|
|
'signed long int' => 'long',
|
|
'unsigned long int' => 'ulong',
|
|
'unsigned short int' => 'ushort',
|
|
'TQt::Alignment' => 'int',
|
|
'TQt::Orientations' => 'int',
|
|
'TQt::DockWidgetAreas' => 'int',
|
|
'TQt::DropActions' => 'int',
|
|
'TQt::ImageConversionFlags' => 'int',
|
|
'TQt::ItemFlags' => 'int',
|
|
'TQt::KeyboardModifiers' => 'int',
|
|
'TQt::MatchFlags' => 'int',
|
|
'TQt::MouseButtons' => 'int',
|
|
'TQt::ToolBarAreas' => 'int',
|
|
'TQt::WindowFlags' => 'int',
|
|
'TQt::WindowStates' => 'int',
|
|
'AutoFormatting' => 'int',
|
|
'DirtyFlags' => 'int',
|
|
'EditTriggers' => 'int',
|
|
'FindFlags' => 'int',
|
|
'Flags' => 'int',
|
|
'FormattingOptions' => 'int',
|
|
'GLenum' => 'int',
|
|
'GLint' => 'int',
|
|
'GLuint' => 'uint',
|
|
'LoadOperator' => 'int',
|
|
'NumberFlags' => 'int',
|
|
'OpenMode' => 'int',
|
|
'Options' => 'int',
|
|
'PaintEngineFeatures' => 'int',
|
|
'Permissions' => 'int',
|
|
'PrintDialogOptions' => 'int',
|
|
'ProcessEventsFlags' => 'int',
|
|
'TQDir::Filters' => 'int',
|
|
'TQDir::SortFlags' => 'int',
|
|
'TQFile::Permissions' => 'int',
|
|
'TQGL::FormatOptions' => 'int',
|
|
'TQIODevice::OpenMode' => 'int',
|
|
'TQImageReader::ImageReaderError' => 'int',
|
|
'TQItemSelectionModel::SelectionFlags' => 'int',
|
|
'TQPaintEngine::DirtyFlags' => 'int',
|
|
'TQPainter::RenderHints' => 'int',
|
|
'TQSql::ParamType' => 'int',
|
|
'TQTextDocument::FindFlags' => 'int',
|
|
'Q_PID' => 'int',
|
|
'TQt::DropActions' => 'int',
|
|
'TQt::ImageConversionFlags' => 'int',
|
|
'TQt::ItemFlags' => 'int',
|
|
'TQt::KeyboardModifiers' => 'int',
|
|
'TQt::MatchFlags' => 'int',
|
|
'TQt::MouseButtons' => 'int',
|
|
'TQt::ToolBarAreas' => 'int',
|
|
'TQt::WindowFlags' => 'int',
|
|
'TQt::WindowStates' => 'int',
|
|
'RenderFlags' => 'int',
|
|
'RenderHints' => 'int',
|
|
'SortFlags' => 'int',
|
|
'StepEnabled' => 'int',
|
|
'Sections' => 'int',
|
|
'Filters' => 'int',
|
|
'SortFlags' => 'int',
|
|
'TQDir::Filters' => 'int',
|
|
'TQDir::SortFlags' => 'int',
|
|
'TQStyle::State' => 'int',
|
|
'TQValidator::State' => 'int',
|
|
'TQAbstractSpinBox::StepEnabled' => 'int',
|
|
'TQDockWidget::DockWidgetFeatures' => 'int',
|
|
'TQStyle::SubControls' => 'int',
|
|
'TQSocket::State' => 'int',
|
|
);
|
|
|
|
%operatorNames =
|
|
(
|
|
'operator^' => 'op_xor',
|
|
'operator^=' => 'op_xor_assign',
|
|
'operator<' => 'op_lt',
|
|
'operator<<' => 'op_write',
|
|
'operator<=' => 'op_lte',
|
|
'operator=' => 'op_assign',
|
|
'operator==' => 'op_equals',
|
|
'operator>' => 'op_gt',
|
|
'operator>=' => 'op_gte',
|
|
'operator>>' => 'op_read',
|
|
'operator|' => 'op_or',
|
|
'operator|=' => 'op_or_assign',
|
|
'operator-' => 'op_minus',
|
|
'operator-=' => 'op_minus_assign',
|
|
'operator--' => 'op_decr',
|
|
'operator!' => 'op_not',
|
|
'operator!=' => 'op_not_equals',
|
|
'operator/' => 'op_div',
|
|
'operator/=' => 'op_div_assign',
|
|
'operator()' => 'op_expr',
|
|
'operator[]' => 'op_at',
|
|
'operator*' => 'op_mult',
|
|
'operator*=' => 'op_mult_assign',
|
|
'operator&' => 'op_and',
|
|
'operator&=' => 'op_and_assign',
|
|
'operator+' => 'op_plus',
|
|
'operator+=' => 'op_plus_assign',
|
|
'operator++' => 'op_incr',
|
|
);
|
|
|
|
$qapplicationExtras = <<EOF;
|
|
/* Constructor #1 */
|
|
public TQApplication(string[] argv) : this((Type) null) {
|
|
Qyoto.Init_qyoto();
|
|
CreateProxy();
|
|
CreateSignalProxy();
|
|
Qt.qApp = this;
|
|
|
|
string[] args = new string[argv.Length + 1];
|
|
args[0] = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
argv.CopyTo(args, 1);
|
|
|
|
NewTQApplication(args);
|
|
}
|
|
private void NewTQApplication(string[] argv) {
|
|
ProxyTQApplication().NewTQApplication(argv.Length, argv);
|
|
}
|
|
[SmokeMethod("TQApplication(int&, char**)")]
|
|
private void NewTQApplication(int argc, string[] argv) {
|
|
ProxyTQApplication().NewTQApplication(argc, argv);
|
|
}
|
|
/* end Constructor #1 */
|
|
|
|
/* Constructor #2 */
|
|
public TQApplication(string[] argv, bool GUIenabled) : this((Type) null) {
|
|
Qyoto.Init_qyoto();
|
|
CreateProxy();
|
|
CreateSignalProxy();
|
|
Qt.qApp = this;
|
|
|
|
string[] args = new string[argv.Length + 1];
|
|
args[0] = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
argv.CopyTo(args, 1);
|
|
|
|
NewTQApplication(args,GUIenabled);
|
|
}
|
|
private void NewTQApplication(string[] argv, bool GUIenabled) {
|
|
ProxyTQApplication().NewTQApplication(argv.Length, argv,GUIenabled);
|
|
}
|
|
[SmokeMethod("TQApplication(int&, char**, bool)")]
|
|
private void NewTQApplication(int argc, string[] argv, bool GUIenabled) {
|
|
ProxyTQApplication().NewTQApplication(argc, argv,GUIenabled);
|
|
}
|
|
/* end Constructor #2 */
|
|
|
|
/* Constructor #3 */
|
|
public TQApplication(string[] argv, int arg3) : this((Type) null) {
|
|
Qyoto.Init_qyoto();
|
|
CreateProxy();
|
|
CreateSignalProxy();
|
|
Qt.qApp = this;
|
|
|
|
string[] args = new string[argv.Length + 1];
|
|
args[0] = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
argv.CopyTo(args, 1);
|
|
|
|
NewTQApplication(args,arg3);
|
|
}
|
|
private void NewTQApplication(string[] argv, int arg3) {
|
|
ProxyTQApplication().NewTQApplication(argv.Length,argv,arg3);
|
|
}
|
|
[SmokeMethod("TQApplication(int&, char**, TQApplication::Type)")]
|
|
private void NewTQApplication(int argc, string[] argv, int arg3) {
|
|
ProxyTQApplication().NewTQApplication(argc,argv,arg3);
|
|
}
|
|
/* end Constructor #3 */
|
|
|
|
// public string[] args(return Argv());
|
|
|
|
EOF
|
|
|
|
|
|
$qbitmapExtras = <<EOF;
|
|
// public TQBitmap(TQPixmap arg1) {
|
|
// super((Class) null);
|
|
// newTQBitmap(arg1);
|
|
// }
|
|
// private native void newTQBitmap(TQPixmap arg1);
|
|
// public TQBitmap(TQImage arg1) {
|
|
// super((Class) null);
|
|
// newTQBitmap(arg1);
|
|
// }
|
|
// private native void newTQBitmap(TQImage arg1);
|
|
|
|
EOF
|
|
|
|
$qbytearrayExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
|
|
$qlistviewExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
$qlistviewitemExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
$qtExtras = <<EOF;
|
|
public const int IO_Direct = 0x0100;
|
|
public const int IO_Sequential = 0x0200;
|
|
public const int IO_Combined = 0x0300;
|
|
public const int IO_TypeMask = 0x0f00;
|
|
public const int IO_Raw = 0x0040;
|
|
public const int IO_Async = 0x0080;
|
|
public const int IO_ReadOnly = 0x0001;
|
|
public const int IO_WriteOnly = 0x0002;
|
|
public const int IO_ReadWrite = 0x0003;
|
|
public const int IO_Append = 0x0004;
|
|
public const int IO_Truncate = 0x0008;
|
|
public const int IO_Translate = 0x0010;
|
|
public const int IO_ModeMask = 0x00ff;
|
|
public const int IO_Open = 0x1000;
|
|
public const int IO_StateMask = 0xf000;
|
|
public const int IO_Ok = 0;
|
|
public const int IO_ReadError = 1;
|
|
public const int IO_WriteError = 2;
|
|
public const int IO_FatalError = 3;
|
|
public const int IO_ResourceError = 4;
|
|
public const int IO_OpenError = 5;
|
|
public const int IO_ConnectError = 5;
|
|
public const int IO_AbortError = 6;
|
|
public const int IO_TimeOutError = 7;
|
|
public const int IO_UnspecifiedError= 8;
|
|
|
|
public static TQApplication tqApp = null;
|
|
|
|
public static string SIGNAL(string signal) {
|
|
return "2"+ signal;
|
|
}
|
|
|
|
public static string SLOT(string slot) {
|
|
return "1" + slot;
|
|
}
|
|
EOF
|
|
|
|
$qobjectExtras = <<EOF;
|
|
|
|
protected Object Q_EMIT = null;
|
|
EOF
|
|
|
|
$qwidgetExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
|
|
$qpixmapExtras = <<EOF;
|
|
// public native bool loadFromData(char[] data);
|
|
|
|
EOF
|
|
|
|
$qpaintdeviceExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
|
|
$qdragobjectExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
|
|
$qdropeventExtras = <<EOF;
|
|
EOF
|
|
|
|
|
|
$qmimesourceExtras = <<EOF;
|
|
EOF
|
|
|
|
|
|
$qiodeviceExtras = <<EOF;
|
|
|
|
|
|
EOF
|
|
|
|
$qpointarrayExtras = <<EOF;
|
|
// public native int size();
|
|
// public native int count();
|
|
// public native bool isEmpty();
|
|
// public native bool isNull();
|
|
// public native bool resize( int size);
|
|
// public native bool truncate( int pos);
|
|
// public native int begin();
|
|
// public native int end();
|
|
// public native TQPoint at(int index);
|
|
|
|
EOF
|
|
|
|
$qsizepolicyExtras = <<EOF;
|
|
|
|
public const int HSize = 6;
|
|
public const int HMask = 0x3f;
|
|
public const int VMask = HMask<<HSize;
|
|
public const int MayGrow = 1;
|
|
public const int ExpMask = 2;
|
|
public const int MayShrink = 4;
|
|
EOF
|
|
|
|
$quridragExtras = <<EOF;
|
|
// public static native bool decode(TQMimeSourceInterface e, ArrayList i);
|
|
// public static native bool decodeToUnicodeUris(TQMimeSourceInterface e, ArrayList i);
|
|
// public static native bool decodeLocalFiles(TQMimeSourceInterface e, ArrayList i);
|
|
|
|
EOF
|
|
|
|
|
|
$kapplicationExtras = <<EOF;
|
|
/**
|
|
Used internally by the KDE Kimono CSharp bindings runtime
|
|
*/
|
|
// public static native void setCSharpSlotFactory();
|
|
|
|
EOF
|
|
|
|
|
|
$kmainwindowExtras = <<EOF;
|
|
|
|
EOF
|
|
|
|
|
|
}
|
|
|
|
sub csharpImport($)
|
|
{
|
|
my ( $classname ) = @_;
|
|
my $classname_ptr = $classname . "*";
|
|
if ( cplusplusToCSharp($classname_ptr) eq "" or $classname eq $main::globalSpaceClassName ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "ArrayList" ) {
|
|
return "System.Collections";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "DateTime" ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "StringBuilder" ) {
|
|
return "System.Text";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "string" ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "string[][]" ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "string[]" ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) eq "DateTime" ) {
|
|
return "";
|
|
} elsif ( cplusplusToCSharp($classname_ptr) =~ /^[a-z]/ ) {
|
|
return "";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
sub cplusplusToCSharp
|
|
{
|
|
my ( $cplusplusType ) = @_;
|
|
my $isConst = ($cplusplusType =~ /const / or $cplusplusType !~ /[*&]/ ? 1 : 0);
|
|
$cplusplusType =~ s/const //;
|
|
$cplusplusType =~ s/^signed//;
|
|
my $className = $cplusplusType;
|
|
$className =~ s/[*&]//;
|
|
|
|
if ( $cplusplusType =~ /void\*|KHTMLPart::PageSecurity|TQFileInfoList|TQValueList<TQIconDragItem>|TQValueList<TQCString>|TQValueList<TQVariant>|TQValueList<TQPixmap>|TQValueListConstIterator<TQString>|TQMap|EditMode|TQPtrList<TQPixmap>|TQPtrList<TQPoint>|TQTextFormat|TQTextCursor|TQTextDocument|TQNetworkProtocolFactoryBase|TQDomNodePrivate|TQSqlDriverCreatorBase|TQSqlFieldInfoList|TQObjectUserData|TQUObject|TQTextParag|TQWidgetMapper|TQMemArray<int>|TQBitArray|TQLayoutIterator|TQAuBucket|TQUnknownInterface|TQConnectionList/ ) {
|
|
return ""; # Unsupported type
|
|
} elsif ( $cplusplusType =~ /bool/ && kalyptusDataDict::ctypemap($cplusplusType) eq "int" ) {
|
|
return "bool";
|
|
} elsif ( $cplusplusType =~ /bool\s*[*&]/ ) {
|
|
return "out bool";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^void\s*\*/ ) {
|
|
return "int";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^qt_QIntValueList\*/ )
|
|
{
|
|
return "int[]";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*(unsigned )?int\s*\*/
|
|
|| $cplusplusType =~ /^int[*&]$/ )
|
|
{
|
|
return "out int";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*double\s*\*/ ) {
|
|
return "out double";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*(unsigned )?short\s*\*/ ) {
|
|
return "out short";
|
|
} elsif ( $cplusplusType =~ /KCmdLineOptions/ ) {
|
|
return "string[][]";
|
|
} elsif ( $cplusplusType =~ /char\s*\*\*/ || $cplusplusType =~ /TQStringList/|| $cplusplusType =~ /TQStrList/) {
|
|
return "string[]";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QUrlInfoValueList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QVariantValueList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QIconDragItemValueList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QPixmapValueList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_QCStringList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QObjectList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDomNodeList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QWidgetList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KURLList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KMainWindow\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KFileItemList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KFileViewItemList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_DOMNodeList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_StyleSheetList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_MediaList\s*\*/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_OfferList\s*\*/
|
|
|| $cplusplusType =~ /TQMemArray<TQRect>/
|
|
|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QCanvasItemList\s*\*/ ) {
|
|
return "ArrayList"
|
|
} elsif ( $cplusplusType =~ /uchar\s*\*/ ) {
|
|
return "char[]";
|
|
} elsif ( $cplusplusType =~ /QC?String/ and !$isConst ) {
|
|
return "StringBuilder"
|
|
} elsif ( $cplusplusType =~ /(DOM::)?DOMString/ || $cplusplusType =~ /TQString/ || $cplusplusType =~ /TQCString/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /^(const )?char\s*\*/ ) {
|
|
return "string"
|
|
} elsif ( $cplusplusType =~ /TQChar\s*[&\*]?/ || $cplusplusType =~ /^char$/ ) {
|
|
return "char"
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QTime\s*\*/ ) {
|
|
return "DateTime"
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDateTime\s*\*/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDate\s*\*/ ) {
|
|
return "DateTime"
|
|
} elsif ( $cplusplusType =~ /TQPaintDevice/ ) {
|
|
return "ITQPaintDevice"
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_([^\*\s]*)(.*)$/ and !$skippedClasses{$className}) {
|
|
if ( defined interfaceForClass($1) ) {
|
|
return interfaceForClass($1);
|
|
} else {
|
|
return $1;
|
|
}
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_([^\*\s]*)(.*)$/ and !$skippedClasses{$className}) {
|
|
if ( defined interfaceForClass($1) ) {
|
|
return interfaceForClass($1);
|
|
} else {
|
|
return $1;
|
|
}
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /unsigned char/ ) {
|
|
return "ushort";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /ulong/ ) {
|
|
return "ulong";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /long/ ) {
|
|
return "long";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /uint/ ) {
|
|
return "uint";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /int/ or $cplusplusType =~ /^int\&$/ ) {
|
|
return "int";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /ushort/ ) {
|
|
return "ushort";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /short/ ) {
|
|
return "short";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /float/ ) {
|
|
return "float";
|
|
} elsif ( $typedeflist{$cplusplusType} =~ /double/ ) {
|
|
return "double";
|
|
} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /(unsigned )(.*)/ ) {
|
|
return "u" . $2;
|
|
} else {
|
|
my $node;
|
|
my $item;
|
|
if ($className =~ /^(\w+)::(\w+)$/) {
|
|
$node = kdocAstUtil::findRef( $rootnode, $1 );
|
|
$item = kdocAstUtil::findRef( $node, $2 ) if defined $node;
|
|
if (defined $item && $item->{NodeType} eq 'enum') {
|
|
if ($2 eq 'Type') {
|
|
return "$1.E_$2";
|
|
} else {
|
|
return "$1.$2";
|
|
}
|
|
|
|
} elsif (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
|
|
return $skippedClasses{$className} ? "" : $2;
|
|
}
|
|
}
|
|
|
|
if ($className =~ /^\w+$/) {
|
|
$item = kdocAstUtil::findRef( $rootnode, $className );
|
|
if (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
|
|
return $skippedClasses{$className} ? "" : $className;
|
|
}
|
|
}
|
|
return kalyptusDataDict::ctypemap($cplusplusType);
|
|
}
|
|
|
|
}
|
|
|
|
sub writeDoc
|
|
{
|
|
( $libname, $rootnode, $outputdir, $opt ) = @_;
|
|
|
|
print STDERR "Starting writeDoc for $libname...\n";
|
|
|
|
$debug = $main::debuggen;
|
|
|
|
mkpath( $outputdir ) unless -f $outputdir;
|
|
|
|
# Define TQPtrCollection::Item, for resolveType
|
|
unless ( kdocAstUtil::findRef( $rootnode, "TQPtrCollection::Item" ) ) {
|
|
my $cNode = kdocAstUtil::findRef( $rootnode, "TQPtrCollection" );
|
|
warn "TQPtrCollection not found" if (!$cNode);
|
|
my $node = Ast::New( 'Item' );
|
|
$node->AddProp( "NodeType", "Forward" );
|
|
$node->AddProp( "Source", $cNode->{Source} ) if ($cNode);
|
|
kdocAstUtil::attachChild( $cNode, $node ) if ($cNode);
|
|
$node->AddProp( "Access", "public" );
|
|
}
|
|
|
|
print STDERR "Preparsing...\n";
|
|
|
|
# Preparse everything, to prepare some additional data in the classes and methods
|
|
Iter::LocalCompounds( $rootnode, sub { preParseClass( shift ); } );
|
|
|
|
# Have a look at each class again, to propagate CanBeCopied
|
|
Iter::LocalCompounds( $rootnode, sub { propagateCanBeCopied( shift ); } );
|
|
|
|
# Write out smokedata.cpp
|
|
writeSmokeDataFile($rootnode);
|
|
|
|
print STDERR "Writing *.cs...\n";
|
|
|
|
# Generate *cs file for each class
|
|
Iter::LocalCompounds( $rootnode, sub { writeClassDoc( shift ); } );
|
|
|
|
print STDERR "Done.\n";
|
|
}
|
|
|
|
=head2 preParseClass
|
|
Called for each class
|
|
=cut
|
|
sub preParseClass
|
|
{
|
|
my( $classNode ) = @_;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
|
|
if( $#{$classNode->{Kids}} < 0 ||
|
|
$classNode->{Access} eq "private" ||
|
|
$classNode->{Access} eq "protected" || # e.g. TQPixmap::TQPixmapData
|
|
exists $classNode->{Tmpl} ||
|
|
# Don't generate standard bindings for TQString, this class is handled as a native type
|
|
$className eq 'TQString' ||
|
|
$className eq 'TQConstString' ||
|
|
$className eq 'TQCString' ||
|
|
$className eq 'TQLatin1String' ||
|
|
# Don't map classes which are really arrays
|
|
$className eq 'TQStringList' ||
|
|
$className eq 'TQCanvasItemList' ||
|
|
$className eq 'TQWidgetList' ||
|
|
$className eq 'TQObjectList' ||
|
|
$className eq 'TQStrList' ||
|
|
# Those are template related
|
|
$className eq 'TQTSManip' || # cause compiler errors with several gcc versions
|
|
$className eq 'TQIconFactory' ||
|
|
$className eq 'TQGDict' ||
|
|
$className eq 'TQGList' ||
|
|
$className eq 'TQGVector' ||
|
|
$className eq 'TQStrIList' ||
|
|
$className eq 'TQStrIVec' ||
|
|
$className eq 'TQBitArray' ||
|
|
$className eq 'TQWExtra' ||
|
|
$className eq 'TQTLWExtra' ||
|
|
($className eq 'TQAbstractUndoItem' and $main::qt4) ||
|
|
($className eq 'TQDebug' and $main::qt4) ||
|
|
($className eq 'TQNoDebug' and $main::qt4) ||
|
|
($className eq 'TQObjectData' and $main::qt4) ||
|
|
($className eq 'TQSysInfo' and $main::qt4) ||
|
|
($className eq 'TQPNGImageWriter' and $main::qt4) ||
|
|
($className eq 'TQPNGImagePacker' and $main::qt4) ||
|
|
($className eq 'TQTextCodec::ConverterState' and $main::qt4) ||
|
|
($className eq 'TQTextLayout::Selection' and $main::qt4) ||
|
|
($className eq 'TQTextStreamManipulator' and $main::qt4) ||
|
|
($className eq 'iterator' and $main::qt4) ||
|
|
$className eq 'TQMetaEnum::Item' ||
|
|
$className eq 'TQWidgetContainerPlugin' ||
|
|
$className eq 'TQGArray::array_data' ||
|
|
$className eq 'KBookmarkMenu::DynMenuInfo' ||
|
|
$className eq 'KCompletionMatches' ||
|
|
$className eq 'KDEDesktopMimeType::Service' ||
|
|
$className eq 'TDEGlobalSettings::KMouseSettings' ||
|
|
$className eq 'KMimeType::Format' ||
|
|
$className eq 'KNotifyClient::Instance' ||
|
|
$className eq 'KParts::Plugin::PluginInfo' ||
|
|
$className eq 'KProtocolInfo::ExtraField' ||
|
|
$className eq 'KXMLGUIClient::StateChange' ||
|
|
$className eq 'KIconTheme' ||
|
|
$className eq 'KEditListBox::CustomEditor' ||
|
|
$className eq 'KIO::KBookmarkMenuNSImporter' ||
|
|
$className eq 'KPerDomainSettings' ||
|
|
$className eq 'TDEApplicationPropsPlugin' ||
|
|
$className eq 'KPrinter' ||
|
|
$className eq 'KPty' ||
|
|
$className eq 'KOpenWithHandler' ||
|
|
$className eq 'KFileOpenWithHandler' ||
|
|
$className eq 'KBindingPropsPlugin' ||
|
|
$className eq 'KPropsDlgPlugin' ||
|
|
$className eq 'KFileSharePropsPlugin' ||
|
|
$className eq 'KBookmarkMenuNSImporter' ||
|
|
$className eq 'KDevicePropsPlugin' ||
|
|
$className eq 'KWin::WindowInfo' ||
|
|
$className eq 'KDEDModule' ||
|
|
$className eq 'KFileMetaInfoProvider' ||
|
|
$className eq 'KFileMimeTypeInfo' ||
|
|
$className eq 'KExecPropsPlugin' ||
|
|
$className eq 'KFilePermissionsPropsPlugin' ||
|
|
$className eq 'KImageFilePreview' ||
|
|
$className eq 'KBookmarkManager' ||
|
|
$className eq 'KBookmarkNotifier' ||
|
|
$className eq 'KOCRDialogFactory' ||
|
|
$className eq 'KExtendedBookmarkOwner' ||
|
|
$className eq 'KSharedPixmap' ||
|
|
$className eq 'KSocket' ||
|
|
$className eq 'KLibrary' ||
|
|
$className eq 'KScanDialogFactory' ||
|
|
$className eq 'KDictSpellingHighlighter' ||
|
|
$className eq 'KPropertiesDialog' ||
|
|
$className eq 'ProgressItem' ||
|
|
$className eq 'KIO::ChmodInfo' ||
|
|
$className eq 'KIO::MetaData' ||
|
|
$className eq 'KFileMimeTypeInfo::ItemInfo' ||
|
|
$className eq 'KIO::UDSAtom' ||
|
|
$className eq 'khtml::DrawContentsEvent' || # the khtml:: classes build, but don't link
|
|
$className eq 'khtml::MouseDoubleClickEvent' ||
|
|
$className eq 'khtml::MouseMoveEvent' ||
|
|
$className eq 'khtml::MousePressEvent' ||
|
|
$className eq 'khtml::MouseReleaseEvent' ||
|
|
$className eq 'khtml::MouseEvent' ||
|
|
$className eq 'KURL::List' ||
|
|
$className eq 'KWin::Info' ||
|
|
$className eq 'TerminalInterface' ||
|
|
$className eq 'TQForeachContainerBase' || # Qt4
|
|
$className eq 'TQInputMethodEvent::Attribute' || # Qt4
|
|
$className eq 'TQAbstractTextDocumentLayout::PaintContext' || # Qt4
|
|
$className eq 'TQAbstractTextDocumentLayout::Selection' || # Qt4
|
|
$className eq 'TQBrushData' || # Qt4
|
|
$className eq 'TQIPv6Address' || # Qt4
|
|
$className eq 'TQImageTextKeyLang' || # Qt4
|
|
$className eq 'TQMap' || # Qt4
|
|
$className eq 'TQMap::const_iterator' || # Qt4
|
|
$className eq 'TQMap::iterator' || # Qt4
|
|
$className eq 'TQMapData' || # Qt4
|
|
$className eq 'TQMapData::Node' || # Qt4
|
|
$className eq 'TQSharedData' || # Qt4
|
|
$className eq 'TQPainterPath::Element' || # Qt4
|
|
$className eq 'TQThreadStorageData' || # Qt4
|
|
$className eq 'TQVFbHeader' || # Qt4
|
|
$className eq 'TQStyleOptionQ3DockWindow' || # Qt4
|
|
$className eq 'TQStyleOptionQ3ListView' || # Qt4
|
|
$className eq 'TQStyleOptionQ3ListViewItem' || # Qt4
|
|
$className eq 'TQStyleOptionQ3ListView' || # Qt4
|
|
$className eq 'TQTextLayout::FormatRange' || # Qt4
|
|
$className eq 'TQVFbKeyData' || # Qt4
|
|
$className eq 'TQVariant::Handler' || # Qt4
|
|
$className eq 'TQVariant::PrivateShared' || # Qt4
|
|
$className eq 'TQVectorData' || # Qt4
|
|
$className eq 'TQWidgetData' || # Qt4
|
|
$className =~ /.*Private$/ || # Ignore any classes which aren't for public consumption
|
|
$className =~ /.*Impl$/ ||
|
|
$className =~ /.*Internal.*/ ||
|
|
# $classNode->{Deprecated} ||
|
|
$classNode->{NodeType} eq 'union' # Skip unions for now, e.g. TQPDevCmdParam
|
|
) {
|
|
print STDERR "Skipping $className\n" if ($debug);
|
|
print STDERR "Skipping union $className\n" if ( $classNode->{NodeType} eq 'union');
|
|
$skippedClasses{$className} = 1;
|
|
delete $classNode->{Compound}; # Cheat, to get it excluded from Iter::LocalCompounds
|
|
return;
|
|
}
|
|
|
|
my $signalCount = 0;
|
|
my $eventHandlerCount = 0;
|
|
my $defaultConstructor = 'none'; # none, public, protected or private. 'none' will become 'public'.
|
|
my $constructorCount = 0; # total count of _all_ ctors
|
|
# If there are ctors, we need at least one public/protected one to instanciate the class
|
|
my $hasPublicProtectedConstructor = 0;
|
|
# We need a public dtor to destroy the object --- ### aren't protected dtors ok too ??
|
|
my $hasPublicDestructor = 1; # by default all classes have a public dtor!
|
|
#my $hasVirtualDestructor = 0;
|
|
my $hasDestructor = 0;
|
|
my $hasPrivatePureVirtual = 0;
|
|
my $hasCopyConstructor = 0;
|
|
my $hasPrivateCopyConstructor = 0;
|
|
# Note: no need for hasPureVirtuals. $classNode{Pure} has that.
|
|
|
|
my $doPrivate = $main::doPrivate;
|
|
$main::doPrivate = 1;
|
|
# Look at each class member (looking for methods and enums in particular)
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub {
|
|
|
|
my( $classNode, $m ) = @_;
|
|
my $name = $m->{astNodeName};
|
|
|
|
if( $m->{NodeType} eq "method" ) {
|
|
if ( $m->{ReturnType} eq 'typedef' # TQFile's EncoderFn/DecoderFn callback, very badly parsed
|
|
) {
|
|
$m->{NodeType} = 'deleted';
|
|
next;
|
|
}
|
|
|
|
print STDERR "preParseClass: looking at $className\::$name $m->{Params}\n" if ($debug);
|
|
|
|
if ( $name eq $classNode->{astNodeName} ) {
|
|
if ( $m->{ReturnType} =~ /~/ ) {
|
|
# A destructor
|
|
$hasPublicDestructor = 0 if $m->{Access} ne 'public';
|
|
#$hasVirtualDestructor = 1 if ( $m->{Flags} =~ "v" && $m->{Access} ne 'private' );
|
|
$hasDestructor = 1;
|
|
} else {
|
|
# A constructor
|
|
$constructorCount++;
|
|
$defaultConstructor = $m->{Access} if ( $m->{Params} eq '' );
|
|
$hasPublicProtectedConstructor = 1 if ( $m->{Access} ne 'private' );
|
|
|
|
# Copy constructor?
|
|
if ( $#{$m->{ParamList}} == 0 ) {
|
|
my $theArgType = @{$m->{ParamList}}[0]->{ArgType};
|
|
if ($theArgType =~ /$className\s*\&/) {
|
|
$hasCopyConstructor = 1;
|
|
$hasPrivateCopyConstructor = 1 if ( $m->{Access} eq 'private' );
|
|
}
|
|
}
|
|
# Hack the return type for constructors, since constructors return an object pointer
|
|
$m->{ReturnType} = $className."*";
|
|
}
|
|
}
|
|
|
|
if ( $name =~ /~$classNode->{astNodeName}/ && $m->{Access} ne "private" ) { # not used
|
|
$hasPublicDestructor = 0 if $m->{Access} ne 'public';
|
|
#$hasVirtualDestructor = 1 if ( $m->{Flags} =~ "v" );
|
|
$hasDestructor = 1;
|
|
}
|
|
|
|
if ( $m->{Flags} =~ "p" && $m->{Access} =~ /private/ ) {
|
|
$hasPrivatePureVirtual = 1; # ouch, can't inherit from that one
|
|
}
|
|
|
|
# All we want from private methods is to check for virtuals, nothing else
|
|
next if ( $m->{Access} =~ /private/ );
|
|
|
|
# Don't generate code for deprecated methods,
|
|
# or where the code won't compile/link for obscure reasons. Or even obvious reasons..
|
|
if ( ($classNode->{astNodeName} eq 'KCharSelectTable' and $name eq 'paintCell')
|
|
|| ($classNode->{astNodeName} eq 'KAnimWidget' and $name eq 'KAnimWidget' and @{$m->{ParamList}} == 2)
|
|
|| ($classNode->{astNodeName} eq 'KDCOPActionProxy' and $name eq 'actions')
|
|
|| ($classNode->{astNodeName} eq 'KFileDialog' and $name eq 'addDirEntry')
|
|
|| ($classNode->{astNodeName} eq 'KFileDialog' and $name eq 'getDirEntry')
|
|
|| ($classNode->{astNodeName} eq 'KFileView' and $name eq 'selectionMode')
|
|
|| ($classNode->{astNodeName} eq 'KFind' and $name eq 'KFind' and @{$m->{ParamList}} == 4)
|
|
|| ($classNode->{astNodeName} eq 'TDEGlobalAccel' and $name eq 'setEnabled')
|
|
|| ($classNode->{astNodeName} eq 'KCharsets' and $name eq 'encodingsForLanguage')
|
|
|| ($classNode->{astNodeName} eq 'KInputDialog' and $name eq 'getInteger')
|
|
|| ($classNode->{astNodeName} eq 'KIO' and $name eq 'buildHTMLErrorString')
|
|
|| ($classNode->{astNodeName} eq 'SlaveBase' and $name eq 'checkCachedAuthentication')
|
|
|| ($classNode->{astNodeName} eq 'SlaveBase' and $name eq 'cacheAuthentication')
|
|
|| ($classNode->{astNodeName} eq 'KInputDialog' and $name eq 'getDouble')
|
|
|| ($classNode->{astNodeName} eq 'KToolBar' and $name eq 'enable')
|
|
|| ($classNode->{astNodeName} eq 'KAccel' and $name eq 'insert' and @{$m->{ParamList}} == 2)
|
|
|| ($classNode->{astNodeName} eq 'KAccel' and $name eq 'autoupdate')
|
|
|| ($classNode->{astNodeName} eq 'KAccel' and $name eq 'getAutoUpdate')
|
|
|| ($classNode->{astNodeName} eq 'KStdAccel' and $name eq 'insert')
|
|
|| ($classNode->{astNodeName} eq 'KBookmarkMenu' and $name eq 'invalid')
|
|
|| ($classNode->{astNodeName} eq 'KCharsets' and $name eq 'languages')
|
|
|| ($classNode->{astNodeName} eq 'KCombiView' and $name eq 'setDropOptions')
|
|
|| ($classNode->{astNodeName} eq 'KFileMetaInfoItem' and $name eq 'unit')
|
|
|| ($classNode->{astNodeName} eq 'TDEInstance' and $name eq 'charsets')
|
|
|| ($classNode->{astNodeName} eq 'TDEInstance' and $name eq 'TDEInstance' and $m->{Access} =~ /protected/)
|
|
|| ($classNode->{astNodeName} eq 'KKey' and $name eq 'isValidQt')
|
|
|| ($classNode->{astNodeName} eq 'KKey' and $name eq 'isValidNative')
|
|
|| ($classNode->{astNodeName} eq 'KKeySequence' and $name eq 'init')
|
|
|| ($classNode->{astNodeName} eq 'KKeySequence' and $name eq 'setTriggerOnRelease')
|
|
|| ($classNode->{astNodeName} eq 'KEMailSettings' and $name eq 'getExtendedSetting')
|
|
|| ($classNode->{astNodeName} eq 'KEMailSettings' and $name eq 'setExtendedSetting')
|
|
|| ($classNode->{astNodeName} eq 'KProtocolManager' and $name eq 'defaultConnectTimeout')
|
|
|| ($classNode->{astNodeName} eq 'KMD5' and $name eq 'transform')
|
|
|| ($classNode->{astNodeName} eq 'KSSLCertificate' and $name eq 'operator!=')
|
|
|| ($classNode->{astNodeName} eq 'KSSLPKCS7' and $name eq 'validate')
|
|
|| ($classNode->{astNodeName} eq 'KSSLPKCS7' and $name eq 'revalidate')
|
|
|| ($classNode->{astNodeName} eq 'KSSLSession' and $name eq 'KSSLSession' and @{$m->{ParamList}} == 1)
|
|
|| ($classNode->{astNodeName} eq 'KSimpleFileFilter' and $name eq 'nameFilters')
|
|
|| ($classNode->{astNodeName} eq 'KTabWidget' and $name eq 'isTabReorderingEnabled')
|
|
|| ($classNode->{astNodeName} eq 'KTabWidget' and $name eq 'hoverCloseButton')
|
|
|| ($classNode->{astNodeName} =~ /^TQUrl/ and $name eq 'operator==')
|
|
|| ($classNode->{astNodeName} eq 'TQUriDrag' and $name =~ /^decode$|decodeLocalFiles|decodeToUnicodeUris/)
|
|
|| ($name eq 'virtual_hook')
|
|
|| ($name =~ /_KShared_/)
|
|
|| ($name eq 'qObject')
|
|
|| ($name =~ /argv/)
|
|
|| ($name =~ /argc/)
|
|
|| ($name eq 'qt_emit')
|
|
|| ($name eq 'qt_invoke')
|
|
|| ($name eq 'qt_cast')
|
|
|| ($name eq 'qt_property')
|
|
|| ($name eq 'staticMetaObject')
|
|
|| ($name eq 'type')
|
|
|| ($classNode->{astNodeName} eq 'KTar' and $name eq 'writeFile_impl')
|
|
|| ($classNode->{astNodeName} eq 'TQApplication' and $name eq 'TQApplication')
|
|
# Assume only Qt classes have tr() and trUtf8() in their Q_OBJECT macro
|
|
|| ($classNode->{astNodeName} !~ /^Q/ and $name eq 'tr')
|
|
|| ($classNode->{astNodeName} !~ /^Q/ and $name eq 'trUtf8')
|
|
|
|
|| ($main::qt4
|
|
&& ( ($classNode->{astNodeName} eq 'TQWidgetListItem' and $name eq 'operator=')
|
|
|| ($classNode->{astNodeName} eq 'TQColormap' and $name eq 'operator=')
|
|
|| ($classNode->{astNodeName} eq 'TQMatrix' and $name eq 'operator*=')
|
|
|| ($classNode->{astNodeName} eq 'TQListWidget' and $name eq 'setItemPosition')
|
|
|| ($classNode->{astNodeName} eq 'TQFontMetricsF' and $name eq 'operator=')
|
|
|| ($classNode->{astNodeName} eq 'TQFontMetricsF' and $name eq 'TQFontMetricsF'
|
|
and $#{$m->{ParamList}} == 0 && $m->{ParamList}[0]->{ArgType} eq 'const TQFontMetrics&')
|
|
|| ($classNode->{astNodeName} eq 'TQHttp' and $name eq 'supportedOperations')
|
|
|| ($classNode->{astNodeName} eq 'TQRectF' and $name eq 'setX')
|
|
|| ($classNode->{astNodeName} eq 'TQRectF' and $name eq 'setY')
|
|
|| ($classNode->{astNodeName} eq 'TQTextObject' and $name eq 'formatType')
|
|
|| ($classNode->{astNodeName} eq 'TQUrl' and $name eq 'TQUrl'
|
|
and $#{$m->{ParamList}} == 0 && $m->{ParamList}[0]->{ArgType} eq 'TQUrlPrivate&')
|
|
|| ($classNode->{astNodeName} eq 'TQGlobalSpace' and $name eq 'operator<<' and $m->{ParamList}[0]->{ArgType} =~ /TQDebug/)
|
|
|| ($classNode->{astNodeName} eq 'TQGlobalSpace' and $#{$m->{ParamList}} > 0 and $name =~ /operator/ and $m->{ParamList}[1]->{ArgType} =~ /TQVariant::Type/)
|
|
|| ($#{$m->{ParamList}} > 0 and $m->{ParamList}[0]->{ArgType} =~ /Private/)
|
|
|| ($m->{ReturnType} =~ /iterator/)
|
|
|| ($m->{ReturnType} =~ /QT3_SUPPORT/) ) )
|
|
|
|
|| $m->{Deprecated} ) {
|
|
$m->{NodeType} = 'deleted';
|
|
next;
|
|
}
|
|
|
|
my $argId = 0;
|
|
my $firstDefaultParam;
|
|
foreach my $arg ( @{$m->{ParamList}} ) {
|
|
# Look for first param with a default value
|
|
if ( defined $arg->{DefaultValue} && !defined $firstDefaultParam ) {
|
|
$firstDefaultParam = $argId;
|
|
}
|
|
|
|
if ( $arg->{ArgType} eq '...' # refuse a method with variable arguments
|
|
or $arg->{ArgType} eq 'image_io_handler' # TQImage's callback
|
|
or $arg->{ArgType} eq 'DecoderFn' # TQFile's callback
|
|
or $arg->{ArgType} eq 'EncoderFn' # TQFile's callback
|
|
or $arg->{ArgType} =~ /bool \(\*\)\(TQObject/ # TQMetaObject's ctor
|
|
or $arg->{ArgType} eq 'QtStaticMetaObjectFunction' # TQMetaObjectCleanUp's ctor with func pointer
|
|
or $arg->{ArgType} eq 'const TQTextItem&' # ref to a private class in 3.2.0b1
|
|
or $arg->{ArgType} eq 'FILE*' # won't be able to handle that I think
|
|
or $arg->{ArgType} eq 'const KKeyNative&' #
|
|
) {
|
|
$m->{NodeType} = 'deleted';
|
|
}
|
|
else
|
|
{
|
|
# Resolve type in full, e.g. for TQSessionManager::RestartHint
|
|
# (TQSessionManagerJBridge doesn't inherit TQSessionManager)
|
|
$arg->{ArgType} = kalyptusDataDict::resolveType($arg->{ArgType}, $classNode, $rootnode);
|
|
registerType( $arg->{ArgType} );
|
|
$argId++;
|
|
}
|
|
}
|
|
$m->AddProp( "FirstDefaultParam", $firstDefaultParam );
|
|
$m->{ReturnType} = kalyptusDataDict::resolveType($m->{ReturnType}, $classNode, $rootnode) if ($m->{ReturnType});
|
|
registerType( $m->{ReturnType} );
|
|
}
|
|
elsif( $m->{NodeType} eq "enum" ) {
|
|
if ( ! $m->{astNodeName} ) {
|
|
$m->{Access} = 'protected';
|
|
}
|
|
my $fullEnumName = $className."::".$m->{astNodeName};
|
|
if ( ($fullEnumName eq 'KMimeType::Format' and $name eq 'compression')
|
|
|| $m->{Deprecated} ) {
|
|
$m->{NodeType} = 'deleted';
|
|
next;
|
|
}
|
|
|
|
$classNode->{enumerations}{$m->{astNodeName}} = $fullEnumName;
|
|
# if $m->{astNodeName} and $m->{Access} ne 'private';
|
|
# if $m->{astNodeName} ;
|
|
|
|
# Define a type for this enum
|
|
registerType( $fullEnumName );
|
|
|
|
# Remember that it's an enum
|
|
findTypeEntry( $fullEnumName )->{isEnum} = 1;
|
|
}
|
|
elsif( $m->{NodeType} eq 'var' ) {
|
|
my $varType = $m->{Type};
|
|
# We are interested in public static vars, like TQColor::blue
|
|
if ( $varType =~ s/static\s+// && $m->{Access} ne 'private'
|
|
&& $className."::".$m->{astNodeName} ne "KSpell::modalListText" )
|
|
{
|
|
$varType =~ s/const\s+(.*)\s*&/$1/;
|
|
$varType =~ s/\s*$//;
|
|
print STDERR "var: $m->{astNodeName} '$varType'\n" if ($debug);
|
|
|
|
# Register the type
|
|
registerType( $varType );
|
|
|
|
} else {
|
|
# To avoid duplicating the above test, we just get rid of any other var
|
|
$m->{NodeType} = 'deleted';
|
|
}
|
|
}
|
|
},
|
|
undef
|
|
);
|
|
$main::doPrivate = $doPrivate;
|
|
|
|
print STDERR "$className: ctor count: $constructorCount, hasPublicProtectedConstructor: $hasPublicProtectedConstructor, hasCopyConstructor: $hasCopyConstructor:, defaultConstructor: $defaultConstructor, hasPublicDestructor: $hasPublicDestructor, hasPrivatePureVirtual:$hasPrivatePureVirtual\n" if ($debug);
|
|
|
|
# Note that if the class has _no_ constructor, the default ctor applies. Let's even generate it.
|
|
if ( !$constructorCount && $defaultConstructor eq 'none' && !$hasPrivatePureVirtual ) {
|
|
# Create a method node for the constructor
|
|
my $methodNode = Ast::New( $classNode->{astNodeName} );
|
|
$methodNode->AddProp( "NodeType", "method" );
|
|
$methodNode->AddProp( "Flags", "" );
|
|
$methodNode->AddProp( "Params", "" );
|
|
$methodNode->AddProp( "ParamList", [] );
|
|
kdocAstUtil::attachChild( $classNode, $methodNode );
|
|
|
|
# Hack the return type for constructors, since constructors return an object pointer
|
|
$methodNode->AddProp( "ReturnType", $className."*" );
|
|
registerType( $className."*" );
|
|
$methodNode->AddProp( "Access", "public" ); # after attachChild
|
|
$defaultConstructor = 'public';
|
|
$hasPublicProtectedConstructor = 1;
|
|
}
|
|
|
|
# Also, if the class has no explicit destructor, generate a default one.
|
|
if ( !$hasDestructor && !$hasPrivatePureVirtual ) {
|
|
my $methodNode = Ast::New( "$classNode->{astNodeName}" );
|
|
$methodNode->AddProp( "NodeType", "method" );
|
|
$methodNode->AddProp( "Flags", "" );
|
|
$methodNode->AddProp( "Params", "" );
|
|
$methodNode->AddProp( "ParamList", [] );
|
|
kdocAstUtil::attachChild( $classNode, $methodNode );
|
|
|
|
$methodNode->AddProp( "ReturnType", "~" );
|
|
$methodNode->AddProp( "Access", "public" );
|
|
}
|
|
|
|
# If we have a private pure virtual, then the class can't be instanciated (e.g. TQCanvasItem)
|
|
# Same if the class has only private constructors (e.g. TQInputDialog)
|
|
$classNode->AddProp( "CanBeInstanciated", $hasPublicProtectedConstructor
|
|
# && !$hasPrivatePureVirtual
|
|
&& (!$classNode->{Pure} or $classNode->{astNodeName} eq 'TQValidator')
|
|
&& !($classNode->{NodeType} eq 'namespace')
|
|
&& ($classNode->{astNodeName} !~ /^DrawContentsEvent$|^MouseEvent$|^MouseDoubleClickEvent$|^MouseMoveEvent$|^MouseReleaseEvent$|^MousePressEvent$/)
|
|
&& ($classNode->{astNodeName} !~ /TQMetaObject|TQDragObject|Slave|CopyJob|KMdiChildFrm|KNamedCommand/) );
|
|
|
|
# We will derive from the class only if it has public or protected constructors.
|
|
# (_Even_ if it has pure virtuals. But in that case the *.cpp class can't be instantiated either.)
|
|
$classNode->AddProp( "BindingDerives", $hasPublicProtectedConstructor );
|
|
|
|
# We need a public dtor to destroy the object --- ### aren't protected dtors ok too ??
|
|
$classNode->AddProp( "HasPublicDestructor", $hasPublicDestructor );
|
|
|
|
# Hack for TQAsyncIO. We don't implement the "if a class has no explicit copy ctor,
|
|
# then all of its member variables must be copiable, otherwise the class isn't copiable".
|
|
$hasPrivateCopyConstructor = 1 if ( $className eq 'TQAsyncIO' );
|
|
|
|
# Remember if this class can't be copied - it means all its descendants can't either
|
|
$classNode->AddProp( "CanBeCopied", !$hasPrivateCopyConstructor );
|
|
$classNode->AddProp( "HasCopyConstructor", $hasCopyConstructor );
|
|
}
|
|
|
|
sub propagateCanBeCopied($)
|
|
{
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
my @super = superclass_list($classNode);
|
|
# A class can only be copied if none of its ancestors have a private copy ctor.
|
|
for my $s (@super) {
|
|
if (!$s->{CanBeCopied}) {
|
|
$classNode->{CanBeCopied} = 0;
|
|
print STDERR "$classNode->{astNodeName} cannot be copied\n" if ($debug);
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Prepare the {case} dict for the class
|
|
prepareCaseDict( $classNode );
|
|
}
|
|
|
|
=head2 writeClassDoc
|
|
|
|
Called by writeDoc for each class to be written out
|
|
|
|
=cut
|
|
|
|
sub writeClassDoc
|
|
{
|
|
my( $node ) = @_;
|
|
my $className = join( "::", kdocAstUtil::heritage($node) );
|
|
my $csharpClassName = $node->{astNodeName};
|
|
# Makefile doesn't like '::' in filenames, so use __
|
|
my $fileName = $node->{astNodeName};
|
|
# my $fileName = join( "__", kdocAstUtil::heritage($node) );
|
|
print "Enter: $className\n" if $debug;
|
|
|
|
my $typeprefix = ($className =~ /^Q/ ? "qt_" : "kde_");
|
|
my $packagename = ($typeprefix eq 'qt_' ? "Qt" : "KDE");
|
|
|
|
# Write out the *.csharp file
|
|
my $classFile = "$outputdir/$fileName.cs";
|
|
open( CLASS, ">$classFile" ) || die "Couldn't create $classFile\n";
|
|
print STDERR "Writing $fileName.csharp\n" if ($debug);
|
|
|
|
print CLASS "//Auto-generated by $0. DO NOT EDIT.\n";
|
|
|
|
print CLASS "namespace $packagename {\n\n";
|
|
|
|
print CLASS "\tusing System;\n";
|
|
|
|
my %csharpMethods = ();
|
|
my %addImport = ();
|
|
|
|
my @ancestors = ();
|
|
my @ancestor_nodes = ();
|
|
Iter::Ancestors( $node, $rootnode, undef, undef, sub {
|
|
my ( $ances, $name, $type, $template ) = @_;
|
|
if ( $name ne "TQMemArray" and $name ne "TQSqlFieldInfoList" ) {
|
|
push @ancestor_nodes, $ances;
|
|
push @ancestors, $name;
|
|
}
|
|
},
|
|
undef
|
|
);
|
|
|
|
my ($methodCode, $interfaceCode, $proxyInterfaceCode, $signalCode) = generateAllMethods( $node, $#ancestors + 1,
|
|
\%csharpMethods,
|
|
$node,
|
|
1,
|
|
\%addImport );
|
|
|
|
my $tempMethodNumber = $methodNumber;
|
|
|
|
# Add method calls for the interfaces implemented by the class
|
|
foreach my $ancestor_node ( @ancestor_nodes ) {
|
|
if ( defined interfaceForClass($ancestor_node->{astNodeName}) && ($#ancestors > 0) ) {
|
|
my ($meth, $interf, $proxyInterf, $sig) = generateAllMethods( $ancestor_node, 0, \%csharpMethods, $node, 0, \%addImport );
|
|
$methodCode .= $meth;
|
|
$interfaceCode .= $interf;
|
|
$proxyInterfaceCode .= $proxyInterf;
|
|
}
|
|
}
|
|
|
|
if ( $className eq 'Qt' or $className eq 'KDE' ) {
|
|
my $globalSpace = kdocAstUtil::findRef( $rootnode, $main::globalSpaceClassName );
|
|
my ($meth, $interf, $proxyInterf, $sig) = generateAllMethods( $globalSpace, 0, \%csharpMethods, $node, 0, \%addImport );
|
|
$methodCode .= $meth;
|
|
$interfaceCode .= $interf;
|
|
$proxyInterfaceCode .= $proxyInterf;
|
|
}
|
|
|
|
$methodNumber = $tempMethodNumber;
|
|
|
|
if ( $className eq 'Qt' ) {
|
|
;
|
|
} else {
|
|
if ( $className eq 'TQListView' or $className eq 'TQListViewItem' or $className eq 'TQUriDrag' ) {
|
|
# Special case these two classes as they have methods that use ArrayList added as 'extras'
|
|
print CLASS "using System.Collections;\n";
|
|
}
|
|
}
|
|
|
|
foreach my $imp (keys %addImport) {
|
|
die if $imp eq '';
|
|
# Ignore any imports for classes in the same package as the current class
|
|
if ($imp !~ /$packagename/) {
|
|
print CLASS "\tusing $imp;\n";
|
|
}
|
|
}
|
|
|
|
if ( defined interfaceForClass($csharpClassName) ) {
|
|
print CLASS "\n\tpublic interface " . interfaceForClass($csharpClassName) . " {\n";
|
|
print CLASS $interfaceCode;
|
|
print CLASS "\t}\n";
|
|
}
|
|
|
|
my $classdec;
|
|
my $parentClassName = "";
|
|
|
|
if ($node->{NodeType} eq 'namespace') {
|
|
$classdec = "\tpublic class $csharpClassName {\n";
|
|
$classdec .= "\t\tprotected Object _interceptor = null;\n";
|
|
} elsif ( $#ancestors < 0 ) {
|
|
$classdec = "\t[SmokeClass(\"$className\")]\n";
|
|
$classdec .= "\tpublic class $csharpClassName : MarshalByRefObject";
|
|
if ( defined interfaceForClass($csharpClassName) ) {
|
|
$classdec .= ", " . interfaceForClass($csharpClassName);
|
|
}
|
|
|
|
if ($node->{CanBeInstanciated} and $node->{HasPublicDestructor}) {
|
|
$classdec .= ", IDisposable";
|
|
}
|
|
|
|
$classdec .= " {\n\t\tprotected Object _interceptor = null;\n";
|
|
$classdec .= " \n\t\tprivate IntPtr _smokeObject;\n";
|
|
$classdec .= " \t\tprotected $csharpClassName(Type dummy) {}\n";
|
|
} else {
|
|
$classdec = "\t[SmokeClass(\"$className\")]\n";
|
|
$classdec .= "\tpublic class $csharpClassName : ";
|
|
my $ancestor;
|
|
foreach $ancestor ( @ancestors ) {
|
|
if ( !defined interfaceForClass($ancestor) or $ancestor eq @ancestors[$#ancestors] ) {
|
|
$ancestor =~ s/^.*:://;
|
|
$parentClassName .= "$ancestor";
|
|
$classdec .= "$ancestor";
|
|
last;
|
|
}
|
|
}
|
|
|
|
my @implements = ();
|
|
if ( $#ancestors >= 1 ) {
|
|
$classdec .= ", ";
|
|
foreach $ancestor ( @ancestors ) {
|
|
if ( defined interfaceForClass($ancestor) ) {
|
|
push(@implements, interfaceForClass($ancestor));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($#implements >= 0) {
|
|
$classdec .= join(", ", @implements);
|
|
}
|
|
|
|
if ($node->{CanBeInstanciated} and $node->{HasPublicDestructor}) {
|
|
$classdec .= ", IDisposable";
|
|
}
|
|
|
|
$classdec .= " {\n";
|
|
$classdec .= " \t\tprotected $csharpClassName(Type dummy) : base((Type) null) {}\n";
|
|
}
|
|
|
|
print CLASS "\n";
|
|
if ( $csharpClassName !~ /^Q/ or $signalCode ne '' ) {
|
|
my $signalLink = '';
|
|
if ( $signalCode ne '' ) {
|
|
$signalLink = " See <see cref=\"I$csharpClassName" . "Signals\"></see> for signals emitted by $csharpClassName\n";
|
|
}
|
|
my $docnode = $node->{DocNode};
|
|
if ( defined $docnode ) {
|
|
print CLASS printCSharpdocComment( $docnode, "", "\t///", $signalLink ) . "\n"
|
|
} else {
|
|
print CLASS "\t///$signalLink";
|
|
}
|
|
}
|
|
|
|
print CLASS $classdec;
|
|
|
|
print CLASS "\t\tinterface I$csharpClassName" . "Proxy {\n";
|
|
print CLASS $proxyInterfaceCode;
|
|
print CLASS "\t\t}\n\n";
|
|
|
|
print CLASS "\t\tprotected new void CreateProxy() {\n";
|
|
print CLASS "\t\t\tSmokeInvocation realProxy = new SmokeInvocation(typeof($csharpClassName), this);\n";
|
|
print CLASS "\t\t\t_interceptor = ($csharpClassName) realProxy.GetTransparentProxy();\n\t\t}\n";
|
|
|
|
print CLASS $methodCode;
|
|
|
|
if ( $className eq 'Qt' and ! $main::qt4 ) {
|
|
print CLASS $qtExtras;
|
|
} elsif ( $className eq 'TQApplication' and ! $main::qt4 ) {
|
|
print CLASS $qapplicationExtras;
|
|
} elsif ( $className eq 'TQBitmap' ) {
|
|
print CLASS $qbitmapExtras;
|
|
} elsif ( $className eq 'TQByteArray' and ! $main::qt4) {
|
|
print CLASS $qbytearrayExtras;
|
|
} elsif ( $className eq 'TQDropEvent' ) {
|
|
print CLASS $qdropeventExtras;
|
|
} elsif ( $className eq 'TQDragObject' ) {
|
|
print CLASS $qdragobjectExtras;
|
|
} elsif ( $className eq 'TQObject' ) {
|
|
print CLASS $qobjectExtras;
|
|
} elsif ( $className eq 'TQListView' ) {
|
|
print CLASS $qlistviewExtras;
|
|
} elsif ( $className eq 'TQListViewItem' ) {
|
|
print CLASS $qlistviewitemExtras;
|
|
} elsif ( $className eq 'TQMimeSource' ) {
|
|
print CLASS $qmimesourceExtras;
|
|
} elsif ( $className eq 'TQWidget' ) {
|
|
print CLASS $qwidgetExtras;
|
|
} elsif ( $className eq 'TQPaintDevice' ) {
|
|
print CLASS $qpaintdeviceExtras;
|
|
} elsif ( $className eq 'TQPixmap' ) {
|
|
print CLASS $qpixmapExtras;
|
|
} elsif ( $className eq 'TQIODevice' ) {
|
|
print CLASS $qiodeviceExtras;
|
|
} elsif ( $className eq 'TQPointArray' ) {
|
|
print CLASS $qpointarrayExtras;
|
|
} elsif ( $className eq 'TQSizePolicy' ) {
|
|
print CLASS $qsizepolicyExtras;
|
|
} elsif ( $className eq 'TQUriDrag' ) {
|
|
print CLASS $quridragExtras;
|
|
} elsif ( $className eq 'TDEApplication' ) {
|
|
print CLASS $kapplicationExtras;
|
|
} elsif ( $className eq 'KMainWindow' ) {
|
|
print CLASS $kmainwindowExtras;
|
|
}
|
|
|
|
|
|
if ( is_kindof($node, "TQObject") ) {
|
|
print CLASS "\t\tprotected new void CreateSignalProxy() {\n";
|
|
print CLASS "\t\t\tSignalInvocation realProxy = new SignalInvocation(typeof(I" . $csharpClassName . "Signals), this);\n";
|
|
print CLASS "\t\t\tQ_EMIT = (I" . $csharpClassName . "Signals) realProxy.GetTransparentProxy();\n";
|
|
print CLASS "\t\t}\n";
|
|
print CLASS "\t\tprotected new I" . $csharpClassName . "Signals Emit() {\n";
|
|
print CLASS "\t\t\treturn (I" . $csharpClassName . "Signals) Q_EMIT;\n";
|
|
print CLASS "\t\t}\n";
|
|
print CLASS "\t}\n";
|
|
|
|
print CLASS "\n\tpublic interface I$csharpClassName" . "Signals";
|
|
print CLASS " : I" . $parentClassName . "Signals" unless $parentClassName eq "Qt";
|
|
print CLASS " {\n";
|
|
print CLASS $signalCode;
|
|
print CLASS "\t}\n";
|
|
} else {
|
|
print CLASS "\t}\n";
|
|
}
|
|
|
|
print CLASS "}\n";
|
|
close CLASS;
|
|
}
|
|
|
|
|
|
# Generate the prototypes for a method (one per arg with a default value)
|
|
# Helper for makeprotos
|
|
sub iterproto($$$$$) {
|
|
my $classidx = shift; # to check if a class exists
|
|
my $method = shift;
|
|
my $proto = shift;
|
|
my $idx = shift;
|
|
my $protolist = shift;
|
|
|
|
my $argcnt = scalar @{ $method->{ParamList} } - 1;
|
|
if($idx > $argcnt) {
|
|
push @$protolist, $proto;
|
|
return;
|
|
}
|
|
if(defined $method->{FirstDefaultParam} and $method->{FirstDefaultParam} <= $idx) {
|
|
push @$protolist, $proto;
|
|
}
|
|
|
|
my $arg = $method->{ParamList}[$idx]->{ArgType};
|
|
|
|
my $typeEntry = findTypeEntry( $arg );
|
|
my $realType = $typeEntry->{realType};
|
|
|
|
# A scalar ?
|
|
$arg =~ s/\bconst\b//g;
|
|
$arg =~ s/\s+//g;
|
|
if($typeEntry->{isEnum} || $allTypes{$realType}{isEnum} || exists $typeunion{$realType} || exists $mungedTypeMap{$arg})
|
|
{
|
|
my $id = '$'; # a 'scalar
|
|
$id = '?' if $arg =~ /[*&]{2}/;
|
|
$id = $mungedTypeMap{$arg} if exists $mungedTypeMap{$arg};
|
|
iterproto($classidx, $method, $proto . $id, $idx + 1, $protolist);
|
|
return;
|
|
}
|
|
|
|
# A class ?
|
|
if(exists $classidx->{$realType}) {
|
|
iterproto($classidx, $method, $proto . '#', $idx + 1, $protolist);
|
|
return;
|
|
}
|
|
|
|
# A non-scalar (reference to array or hash, undef)
|
|
iterproto($classidx, $method, $proto . '?', $idx + 1, $protolist);
|
|
return;
|
|
}
|
|
|
|
# Generate the prototypes for a method (one per arg with a default value)
|
|
sub makeprotos($$$) {
|
|
my $classidx = shift;
|
|
my $method = shift;
|
|
my $protolist = shift;
|
|
iterproto($classidx, $method, $method->{astNodeName}, 0, $protolist);
|
|
}
|
|
|
|
# Return the string containing the signature for this method (without return type).
|
|
# If the 2nd arg is not the size of $m->{ParamList}, this method returns a
|
|
# partial signature (this is used to handle default values).
|
|
sub methodSignature($$) {
|
|
my $method = shift;
|
|
my $last = shift;
|
|
my $sig = $method->{astNodeName};
|
|
my @argTypeList;
|
|
my $argId = 0;
|
|
foreach my $arg ( @{$method->{ParamList}} ) {
|
|
last if $argId > $last;
|
|
push @argTypeList, $arg->{ArgType};
|
|
$argId++;
|
|
}
|
|
$sig .= "(". join(", ",@argTypeList) .")";
|
|
$sig .= " const" if $method->{Flags} =~ "c";
|
|
return $sig;
|
|
}
|
|
|
|
# Return the string containing the csharp signature for this method (without return type).
|
|
# If the 2nd arg is not the size of $m->{ParamList}, this method returns a
|
|
# partial signature (this is used to handle default values).
|
|
sub csharpMethodSignature($$) {
|
|
my $method = shift;
|
|
my $last = shift;
|
|
my $sig = $method->{astNodeName};
|
|
my @argTypeList;
|
|
my $argId = 0;
|
|
foreach my $arg ( @{$method->{ParamList}} ) {
|
|
$argId++;
|
|
last if $argId > $last;
|
|
push @argTypeList, "arg" . "$argId ". cplusplusToCSharp( $arg->{ArgType} );
|
|
}
|
|
$sig .= "(". join(", ",@argTypeList) .")";
|
|
return $sig;
|
|
}
|
|
|
|
sub coerce_type($$$$) {
|
|
#my $m = shift;
|
|
my $union = shift;
|
|
my $var = shift;
|
|
my $type = shift;
|
|
my $new = shift; # 1 if this is a return value, 0 for a normal param
|
|
|
|
my $typeEntry = findTypeEntry( $type );
|
|
my $realType = $typeEntry->{realType};
|
|
|
|
my $unionfield = $typeEntry->{typeId};
|
|
# die "$type" unless defined( $unionfield );
|
|
if ( ! defined( $unionfield ) ) {
|
|
print STDERR "type field not defined: $type\n";
|
|
return "";
|
|
}
|
|
|
|
$unionfield =~ s/t_/s_/;
|
|
|
|
$type =~ s/\s+const$//; # for 'char* const'
|
|
$type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
|
|
|
|
my $code = "$union.$unionfield = ";
|
|
if($type =~ /&$/) {
|
|
$code .= "(void*)&$var;\n";
|
|
} elsif($type =~ /\*$/) {
|
|
$code .= "(void*)$var;\n";
|
|
} else {
|
|
if ( $unionfield eq 's_class'
|
|
or ( $unionfield eq 's_voidp' and $type ne 'void*' )
|
|
or $type eq 'TQString' ) { # hack
|
|
$type =~ s/^const\s+//;
|
|
if($new) {
|
|
$code .= "(void*)new $type($var);\n";
|
|
} else {
|
|
$code .= "(void*)&$var;\n";
|
|
}
|
|
} else {
|
|
$code .= "$var;\n";
|
|
}
|
|
}
|
|
|
|
return $code;
|
|
}
|
|
|
|
# Generate the list of args casted to their real type, e.g.
|
|
# (TQObject*)x[1].s_class,(TQEvent*)x[2].s_class,x[3].s_int
|
|
sub makeCastedArgList
|
|
{
|
|
my @castedList;
|
|
my $i = 1; # The args start at x[1]. x[0] is the return value
|
|
my $arg;
|
|
foreach $arg (@_) {
|
|
my $type = $arg;
|
|
my $cast;
|
|
|
|
my $typeEntry = findTypeEntry( $type );
|
|
my $unionfield = $typeEntry->{typeId};
|
|
# die "$type" unless defined( $unionfield );
|
|
if ( ! defined( $unionfield ) ) {
|
|
print STDERR "type field not defined: $type\n";
|
|
return "";
|
|
}
|
|
$unionfield =~ s/t_/s_/;
|
|
|
|
$type =~ s/\s+const$//; # for 'char* const'
|
|
$type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
|
|
|
|
my $v .= " arg$i";
|
|
if($type =~ /&$/) {
|
|
$cast = "*($type *)";
|
|
} elsif($type =~ /\*$/) {
|
|
$cast = "($type)";
|
|
} elsif($type =~ /\(\*\)\s*\(/) { # function pointer ... (*)(...)
|
|
$cast = "($type)";
|
|
} else {
|
|
if ( $unionfield eq 's_class'
|
|
or ( $unionfield eq 's_voidp' and $type ne 'void*' )
|
|
or $type eq 'TQString' ) { # hack
|
|
$cast = "*($type *)";
|
|
} else {
|
|
$cast = "($type)";
|
|
}
|
|
}
|
|
push @castedList, "$type$v";
|
|
$i++;
|
|
}
|
|
return @castedList;
|
|
}
|
|
|
|
|
|
# Adds the import for node $1 to be imported in $2 if not already there
|
|
# Prints out debug stuff if $3
|
|
sub addImportForClass($$$)
|
|
{
|
|
my ( $node, $addImport, $debugMe ) = @_;
|
|
my $importname = csharpImport( $node->{astNodeName} );
|
|
# print " Importing $importname for node name: " . $node->{astNodeName} . "\n";
|
|
# No import needed, so return
|
|
return if ( $importname eq '' );
|
|
unless ( defined $addImport->{$importname} ) {
|
|
print " Importing $importname\n" if ($debugMe);
|
|
$addImport->{$importname} = 1;
|
|
}
|
|
else { print " $importname already imported.\n" if ($debugMe); }
|
|
}
|
|
|
|
sub checkImportsForObject($$)
|
|
{
|
|
my $type = shift;
|
|
my $addImport = shift;
|
|
|
|
my $debugCI = 0; #$debug
|
|
# print "checkImportsForObject $type\n";
|
|
$type =~ s/const\s+//;
|
|
my $it = $type;
|
|
if (!($it and exists $typeunion{$it}) and $type ne ""
|
|
#and $type !~ /&/ # in fact we also want refs, due to the generated code
|
|
) {
|
|
$type =~ s/&//;
|
|
$type =~ s/[*]//;
|
|
print " Detecting an object by value/ref: $type\n" if ($debugCI);
|
|
my $node = kdocAstUtil::findRef( $rootnode, $type );
|
|
if ($node and $node->{NodeType} eq "class" ) {
|
|
print " NodeType: " . $node->{NodeType} . "\n" if ($debugCI);
|
|
addImportForClass( $node, $addImport, $debugCI );
|
|
}
|
|
else {
|
|
if ( cplusplusToCSharp($it) eq 'ArrayList' ) {
|
|
$addImport->{"System.Collections"} = 1;
|
|
} else {
|
|
print " No import found for $type\n" if ($debugCI);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub generateVirtualMethod($$$$$)
|
|
{
|
|
# Generating methods for $class.
|
|
# $m: method node. $methodClass: the node of the class in which the method is really declared
|
|
# (can be different from $class when the method comes from a super class)
|
|
# This is important because of $allMethods, which has no entry for class::method in that case.
|
|
|
|
my( $classNode, $signature, $m, $methodClass, $addImport ) = @_;
|
|
my $methodCode = ''; # output
|
|
my $returnType = $m->{ReturnType};
|
|
return ('', '') if $returnType eq '~'; # skip destructors
|
|
|
|
my $className = $classNode->{astNodeName};
|
|
my $flags = $m->{Flags};
|
|
my @argList = @{$m->{ParamList}};
|
|
|
|
print "generateVirtualMethod $className: $signature ($m->{Access})\n" if ($debug);
|
|
|
|
# Detect objects returned by value
|
|
checkImportsForObject( $returnType, $addImport ) if ($returnType ne 'void');
|
|
|
|
# Generate a matching virtual method in the x_ class
|
|
$methodCode .= "\t\tvirtual $returnType $m->{astNodeName}(";
|
|
my $i = 0;
|
|
foreach my $arg ( @argList ) {
|
|
$methodCode .= ", " if $i++;
|
|
$methodCode .= $arg->{ArgType};
|
|
$methodCode .= " x$i";
|
|
|
|
# Detect objects passed by value
|
|
checkImportsForObject( $arg->{ArgType}, $addImport );
|
|
}
|
|
$methodCode .= ") ";
|
|
$methodCode .= "const " if ($flags =~ "c");
|
|
$methodCode .= "\{\n";
|
|
|
|
# Now the code of the method
|
|
my $this = $classNode->{BindingDerives} > 0 ? "this" : "xthis";
|
|
|
|
$i++; # Now the number of args
|
|
$methodCode .= "\tSmoke::StackItem x[$i];\n";
|
|
$i = 1;
|
|
for my $arg (@argList) {
|
|
$methodCode .= "\t";
|
|
$methodCode .= coerce_type("x[$i]", "x$i", $arg->{ArgType}, 0);
|
|
$i++;
|
|
}
|
|
|
|
my $sig = $methodClass->{astNodeName} . "::" . $signature;
|
|
my $idx = $allMethods{$sig};
|
|
# die "generateVirtualMethod: $className: No method found for $sig\n" if !defined $idx;
|
|
if ( !defined $idx ) {
|
|
print STDERR "generateVirtualMethod: $className: No method found for $sig\n";
|
|
return "";
|
|
}
|
|
|
|
if($flags =~ "p") { # pure virtual
|
|
$methodCode .= "\t${libname}_Smoke->binding->callMethod($idx, (void*)$this, x, true /*pure virtual*/);\n";
|
|
} else {
|
|
$methodCode .= "\tif(${libname}_Smoke->binding->callMethod($idx, (void*)$this, x)) ";
|
|
}
|
|
|
|
$returnType = undef if ($returnType eq 'void');
|
|
if($returnType) {
|
|
my $arg = $returnType;
|
|
my $it = $arg;
|
|
my $cast;
|
|
my $v = "x[0]";
|
|
my $indent = ($flags =~ "p") ? "\t" : "";
|
|
if($it and exists $typeunion{$it}) {
|
|
$v .= ".$typeunion{$it}";
|
|
$cast = "($arg)";
|
|
$methodCode .= "${indent}return $cast$v;\n";
|
|
} else {
|
|
$v .= ".s_class";
|
|
if($arg =~ s/&//) {
|
|
$cast = "*($arg *)";
|
|
$methodCode .= "${indent}return $cast$v;\n";
|
|
} elsif($arg !~ /\*/) {
|
|
unless($flags =~ "p") {
|
|
$indent = "\t ";
|
|
$methodCode .= "{\n";
|
|
}
|
|
# we assume it's a new thing, and handle it
|
|
$methodCode .= "${indent}$arg *xptr = ($arg *)$v;\n";
|
|
$methodCode .= "${indent}$arg xret(*xptr);\n";
|
|
$methodCode .= "${indent}delete xptr;\n";
|
|
$methodCode .= "${indent}return xret;\n";
|
|
$methodCode .= "\t}\n" unless $flags =~ "p";
|
|
} else {
|
|
$cast = "($arg)";
|
|
$methodCode .= "${indent}return $cast$v;\n";
|
|
}
|
|
}
|
|
} else {
|
|
$methodCode .= "\t" if $flags =~ "p";
|
|
$methodCode .= "return;\n";
|
|
}
|
|
if($flags =~ "p") {
|
|
$methodCode .= "\t// ABSTRACT\n";
|
|
$methodCode .= " }\n";
|
|
return ( $methodCode );
|
|
}
|
|
$methodCode .= "\t";
|
|
if($returnType) {
|
|
$methodCode .= "return ";
|
|
}
|
|
$methodCode .= "$this\->$methodClass->{astNodeName}\::$m->{astNodeName}(";
|
|
$i = 0;
|
|
for my $arg (@argList) {
|
|
$methodCode .= ", " if $i++;
|
|
$methodCode .= "x$i";
|
|
}
|
|
$methodCode .= ");\n";
|
|
$methodCode .= "\t}\n";
|
|
return ( $methodCode );
|
|
}
|
|
|
|
sub interfaceForClass($)
|
|
{
|
|
my ( $ancestor ) = @_;
|
|
if ( kalyptusDataDict::interfacemap($ancestor) eq () ) {
|
|
return undef;
|
|
} else {
|
|
return "I". $ancestor;
|
|
}
|
|
}
|
|
|
|
sub generateMethod($$$$$$$)
|
|
{
|
|
my( $classNode, $m, $addImport, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors ) = @_; # input
|
|
my $methodCode = ''; # output
|
|
my $interfaceCode = ''; # output
|
|
my $proxyInterfaceCode = ''; # output
|
|
my $signalCode = ''; # output
|
|
|
|
my $name = $m->{astNodeName}; # method name
|
|
|
|
my @heritage = kdocAstUtil::heritage($classNode);
|
|
my $className = join( "::", @heritage );
|
|
|
|
@heritage = kdocAstUtil::heritage($mainClassNode);
|
|
my $mainClassName = join( "::", @heritage );
|
|
|
|
# The csharpClassName might be 'TQWidget', while currentClassName is 'TQRangeControl'
|
|
# and the TQRangeControl methods are being copied into TQWidget.
|
|
my $csharpClassName = $mainClassNode->{astNodeName};
|
|
my $currentClassName = $classNode->{astNodeName};
|
|
|
|
my $firstUnknownArgType = 99;
|
|
my $returnType = $m->{ReturnType};
|
|
|
|
# Don't use $className here, it's never the fully qualified (A::B) name for a ctor.
|
|
my $isConstructor = ($name eq $classNode->{astNodeName} );
|
|
my $isDestructor = ($returnType eq '~');
|
|
|
|
# Don't generate anything for destructors, or constructors for namespaces
|
|
return if $isDestructor
|
|
or ($classNode->{NodeType} eq 'namespace' and $isConstructor)
|
|
or (!$mainClassNode->{CanBeInstanciated} and $m->{Access} =~ /protected/)
|
|
or $name =~ /^operator\s*(=|(\[\])|([|&^+-]=)|(!=))\s*$/;
|
|
|
|
if ($classNode->{astNodeName} eq $main::globalSpaceClassName) {
|
|
my $sourcename = $m->{Source}->{astNodeName};
|
|
# Only put Global methods which came from sources beginning with q into class Qt
|
|
if ($csharpClassName eq 'Qt' and ( $sourcename !~ /\/q[^\/]*$/ or $sourcename =~ /string.h$/ )) {
|
|
return;
|
|
}
|
|
# ..and any other global methods into KDE
|
|
if ($csharpClassName eq 'KDE' and $m->{Source}->{astNodeName} =~ /\/q[^\/]*$/) {
|
|
return;
|
|
}
|
|
|
|
if ( $sourcename !~ s!.*(kio/|kparts/|dom/|kabc/|ksettings/|kjs/|ktexteditor/|tdeprint/|tdesu/)(.*)!$1$2!m ) {
|
|
$sourcename =~ s!.*/(.*)!$1!m;
|
|
}
|
|
if ( $sourcename eq '' ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($returnType eq 'void') {
|
|
$returnType = undef;
|
|
} else {
|
|
# Detect objects returned by value
|
|
checkImportsForObject( $returnType, $addImport );
|
|
}
|
|
|
|
my $hasDuplicateSignature = 0;
|
|
my $isStatic = $m->{Flags} =~ "s";
|
|
my $isPure = $m->{Flags} =~ "p";
|
|
|
|
return if ( $m->{SkipFromSwitch} && $m->{Flags} !~ "p" );
|
|
|
|
# # Skip internal methods, which return unknown types
|
|
# # Hmm, the C# bindings have a list of those too.
|
|
# return if ( $returnType =~ m/TQGfx\s*\*/ );
|
|
# return if ( $returnType eq 'CGContextRef' );
|
|
# return if ( $returnType eq 'TQWSDisplay *' );
|
|
# # This stuff needs callback, or **
|
|
# return if ( $name eq 'defineIOHandler' or $name eq 'qt_init_internal' );
|
|
# # Skip casting operators, but not == < etc.
|
|
# return if ( $name =~ /operator \w+/ );
|
|
# # TQFile's EncoderFn/DecoderFn
|
|
# return if ( $name =~ /set[ED][ne]codingFunction/ );
|
|
# # How to implement this? (TQXmlDefaultHandler/TQXmlEntityResolver::resolveEntity, needs A*&)
|
|
# return if ( $name eq 'resolveEntity' and $className =~ /^TQXml/ );
|
|
# return if ( $className eq 'TQBitArray' && $m->{Access} eq 'protected' );
|
|
|
|
#print STDERR "Tests passed, generating.\n";
|
|
|
|
|
|
my $argId = 0;
|
|
|
|
my @argTypeList=();
|
|
my @csharpArgTypeList=();
|
|
my @csharpArgList = ();
|
|
my @namedArgTypeList=();
|
|
|
|
foreach my $arg ( @{$m->{ParamList}} ) {
|
|
$argId++;
|
|
|
|
if ( $arg->{ArgName} =~ /^super$|^int$|^env$|^cls$|^obj$|^byte$|^event$|^base$|^object$|^in$|^out$|^checked$|^delegate$|^string$/ ) {
|
|
$arg->{ArgName} = "";
|
|
}
|
|
|
|
if ( $arg->{ArgName} =~ /^short$|^long$/ ) {
|
|
# Oops looks like a parser error
|
|
$arg->{ArgType} = $arg->{ArgName};
|
|
$arg->{ArgName} = "";
|
|
}
|
|
|
|
print STDERR " Param ".$arg->{astNodeName}." type: ".$arg->{ArgType}." name:".$arg->{ArgName}." default: ".$arg->{DefaultValue}." csharp: ".cplusplusToCSharp($arg->{ArgType})."\n" if ($debug);
|
|
|
|
my $argType = $arg->{ArgType};
|
|
my $namedArgType;
|
|
my $csharpArgType;
|
|
my $csharpArg;
|
|
my $argName;
|
|
|
|
if ( cplusplusToCSharp($argType) eq "" && $firstUnknownArgType > $argId ) {
|
|
$firstUnknownArgType = $argId;
|
|
}
|
|
|
|
$csharpArg = ($arg->{ArgName} eq "" ? "arg" . $argId : $arg->{ArgName});
|
|
$namedArgType = $argType . " " . $csharpArg;
|
|
$csharpArgType = cplusplusToCSharp($argType) . " " . $csharpArg;
|
|
|
|
push @argTypeList, $argType;
|
|
push @csharpArgTypeList, $csharpArgType;
|
|
if ( $csharpArgType =~ /^((out)|(ref)) / ) {
|
|
push @csharpArgList, "$1 " . $csharpArg;
|
|
} else {
|
|
push @csharpArgList, $csharpArg;
|
|
}
|
|
push @namedArgTypeList, $namedArgType;
|
|
|
|
# Detect objects passed by value
|
|
checkImportsForObject( $argType, $addImport );
|
|
}
|
|
|
|
if ( $name eq 'TQApplication' or ($csharpClassName eq 'TDECmdLineArgs' and $name eq 'init' and scalar(@csharpArgList) > 1) ) {
|
|
# Junk the 'int argc' parameter
|
|
shift @csharpArgTypeList;
|
|
shift @csharpArgList;
|
|
}
|
|
|
|
my @castedArgList = makeCastedArgList( @argTypeList );
|
|
|
|
# We iterate as many times as we have default params
|
|
my $firstDefaultParam = $m->{FirstDefaultParam};
|
|
$firstDefaultParam = scalar(@argTypeList) unless defined $firstDefaultParam;
|
|
my $iterationCount = scalar(@argTypeList) - $firstDefaultParam;
|
|
|
|
my $csharpReturnType = cplusplusToCSharp($m->{ReturnType});
|
|
$csharpReturnType =~ s/^(out)|(ref) //;
|
|
$csharpReturnType =~ s/StringBuilder/string/;
|
|
if ( $csharpReturnType =~ s/string\[\]/ArrayList/ ) {
|
|
$addImport->{"System.Collections"} = 1;
|
|
}
|
|
|
|
if ($m->{ReturnType} =~ /^int\&/) {
|
|
$csharpReturnType = 'int';
|
|
}
|
|
|
|
if ($csharpReturnType eq "") {
|
|
$firstUnknownArgType = 0;
|
|
}
|
|
|
|
print STDERR " ". ($iterationCount+1). " iterations for $name\n" if ($debug);
|
|
|
|
my $csharpSignature = csharpMethodSignature( $m, @argTypeList );
|
|
|
|
if ( defined $csharpMethods->{$csharpSignature} ) {
|
|
$hasDuplicateSignature = 1;
|
|
}
|
|
|
|
my $docnode = $m->{DocNode};
|
|
if ( $firstUnknownArgType >= 0 && $m->{Access} !~ /signals/ && ! $hasDuplicateSignature
|
|
&& defined $docnode && ($generateConstructors || !$isConstructor) )
|
|
{
|
|
my $csharpdocComment = printCSharpdocComment( $docnode, "", "\t\t///", "" );
|
|
$methodCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
|
|
}
|
|
|
|
while($iterationCount >= 0) {
|
|
|
|
$csharpMethods->{$csharpSignature} = 1;
|
|
|
|
local($") = ",";
|
|
my $signature = methodSignature( $m, $#argTypeList );
|
|
|
|
if($firstUnknownArgType <= scalar(@argTypeList) || $hasDuplicateSignature || ($name =~ /^qObject$/) || $m->{Access} =~ /dcop/ ) {
|
|
if ( $firstUnknownArgType <= scalar(@argTypeList) || $m->{Access} =~ /dcop/ ) {
|
|
my $failedConversion = "\t\t// " . $m->{ReturnType} . " $name(@castedArgList[0..$#argTypeList]); >>>> NOT CONVERTED\n";
|
|
if ( $m->{Access} =~ /signals/ ) {
|
|
$signalCode .= $failedConversion;
|
|
} else {
|
|
$methodCode .= $failedConversion;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
if ($name eq 'find' and $csharpClassName eq 'TQButtonGroup') {
|
|
# Can't override a static method find() in TQWidget
|
|
$name = "findButton";
|
|
} elsif ( $name eq 'null' ) {
|
|
$name = "nil";
|
|
} elsif ( $name eq 'form' and $csharpClassName =~ /^HTML/ ) {
|
|
$name = "formElement";
|
|
} elsif ( $name eq 'wait' and $csharpClassName eq 'TDEProcess' ) {
|
|
$name = "waitThread";
|
|
} elsif ( $name eq 'icon' and $csharpClassName eq 'TQMessageBox' ) {
|
|
$name = "iconId";
|
|
} elsif ( $name eq 'icon' and $csharpClassName eq 'KURLBarItemDialog' ) {
|
|
$name = "iconName";
|
|
} elsif ( $name eq 'iconText' and $csharpClassName eq 'KToolBar' ) {
|
|
$name = "iconTextId";
|
|
} elsif ( $name eq 'reset' and $csharpClassName eq 'KExtendedSocket' ) {
|
|
$name = "resetSocket";
|
|
} elsif ( $name eq 'palette' and $csharpClassName eq 'KPaletteTable' ) {
|
|
$name = "paletteName";
|
|
} elsif ( $name eq 'size' and $csharpClassName eq 'KFontCombo' ) {
|
|
$name = "pointSize";
|
|
} elsif ($csharpSignature eq "icon()" and $csharpClassName eq 'KIconButton') {
|
|
$name = "iconName";
|
|
} elsif ($csharpSignature eq "close()" and $csharpClassName eq 'KDirOperator') {
|
|
$name = "closeLoading";
|
|
} elsif ($csharpSignature eq "font()" and $csharpClassName eq 'KCharSelect') {
|
|
$name = "fontName";
|
|
} elsif ($csharpSignature eq "layout()" and $csharpReturnType eq 'void') {
|
|
$name = "updateLayout";
|
|
} elsif ( $name eq 'sorting' and $csharpReturnType eq 'bool' ) {
|
|
$name = "sortOnInsert";
|
|
}
|
|
|
|
my $csharpparams = join( ", ", @csharpArgTypeList );
|
|
my $cplusplusparams;
|
|
my $i = 0;
|
|
for my $arg (@argTypeList) {
|
|
$cplusplusparams .= "," if $i++;
|
|
$cplusplusparams .= "arg" . $i;
|
|
}
|
|
|
|
my $access = $m->{Access};
|
|
$access =~ s/_slots//;
|
|
|
|
if ($isConstructor) {
|
|
if ( $generateConstructors ) {
|
|
# $proxyInterfaceCode .= "\t\t\tvoid new$csharpClassName($csharpparams);\n";
|
|
$methodCode .= "\t\tpublic $csharpClassName($csharpparams) : this((Type) null) {\n";
|
|
$methodCode .= "\t\t\tCreateProxy();\n";
|
|
|
|
if ( is_kindof($classNode, "TQObject") ) {
|
|
$methodCode .= "\t\t\tCreateSignalProxy();\n";
|
|
}
|
|
|
|
$methodCode .= "\t\t\tNew$csharpClassName(@csharpArgList[0..$#csharpArgTypeList]);\n";
|
|
$methodCode .= "\t\t}\n";
|
|
|
|
$methodCode .= "\t\t[SmokeMethod(\"" . $signature . "\")]\n";
|
|
$methodCode .= "\t\tprivate void New$csharpClassName($csharpparams) {\n";
|
|
$methodCode .= "\t\t\tProxy$csharpClassName().New$csharpClassName(@csharpArgList[0..$#csharpArgTypeList]);\n";
|
|
$methodCode .= "\t\t}\n";
|
|
}
|
|
} elsif ($name =~ /^operator.*/) {
|
|
$name =~ s/ //;
|
|
$name =~ s!([|&*/+^-])=!$1!;
|
|
if (!$isStatic) {
|
|
# In C# operator methods must be static, so if the C++ version isn't
|
|
# static, then add another arg 'lhs', the value of 'this'.
|
|
$csharpparams = "$csharpClassName lhs" . ($csharpparams eq "" ? "" : ", ") . $csharpparams;
|
|
unshift @csharpArgTypeList, $csharpClassName;
|
|
unshift @csharpArgList, "lhs";
|
|
}
|
|
|
|
$proxyInterfaceCode .= "\t\t\t$csharpReturnType $operatorNames{$name}($csharpparams);\n";
|
|
|
|
$methodCode .= "\t\t[SmokeMethod(\"" . $signature . "\")]\n";
|
|
$methodCode .= "\t\t" . $access . " static ";
|
|
$methodCode .= $csharpReturnType;
|
|
|
|
if ($classNode->{astNodeName} eq $main::globalSpaceClassName
|
|
|| $name eq 'operator<<'
|
|
|| $name eq 'operator>>' )
|
|
{
|
|
# In C# an operator method must be in the same class as its first operand,
|
|
# so any operator methods in TQGlobalSpace must be left as ordinary method
|
|
# calls. eg op_write()
|
|
# 'operator<<' and 'operator>>' can only have int types as the second
|
|
# arg in C#, so convert them to op_read() and op_write() calls
|
|
$methodCode .= " $operatorNames{$name}($csharpparams) \{\n";
|
|
} else {
|
|
$methodCode .= " $name($csharpparams) \{\n";
|
|
}
|
|
|
|
$methodCode .= "\t\t\treturn ";
|
|
$methodCode .= "Static" . "$csharpClassName().$operatorNames{$name}(@csharpArgList[0..$#csharpArgTypeList]);\n";
|
|
$methodCode .= "\t\t}\n";
|
|
|
|
if ( $name =~ /operator==/
|
|
&& $classNode->{astNodeName} ne $main::globalSpaceClassName )
|
|
{
|
|
# Add a 'operator!=' method defined in terms of 'operator=='
|
|
$methodCode .= "\t\t" . $access . " static bool";
|
|
$methodCode .= " operator!=($csharpparams) \{\n";
|
|
|
|
$methodCode .= "\t\t\treturn ";
|
|
$methodCode .= "!Static" . "$csharpClassName().$operatorNames{$name}(@csharpArgList[0..$#csharpArgTypeList]);\n";
|
|
$methodCode .= "\t\t}\n";
|
|
|
|
$methodCode .= "\t\tpublic override bool Equals(object o) \{\n";
|
|
$methodCode .= "\t\t\tif (!(o is $csharpClassName)) { return false; }\n";
|
|
|
|
$methodCode .= "\t\t\treturn this == ($csharpClassName) o;\n";
|
|
$methodCode .= "\t\t}\n";
|
|
|
|
$methodCode .= "\t\tpublic override int GetHashCode() \{\n";
|
|
$methodCode .= "\t\t\treturn Proxy$csharpClassName().GetHashCode();\n";
|
|
$methodCode .= "\t\t}\n";
|
|
}
|
|
} else {
|
|
if ( $access eq 'public' or $access eq 'protected' ) {
|
|
if ( $name =~ /^takeItem$|^setPixmap$|^clearCell$|^setItem$|^item$|^minimumSize$/
|
|
or $name =~ /^stepUp$|^stepDown$|^sectionFormattedText$|^addNumber$|^removeLastNumber$/
|
|
or $name =~ /^cancel$|^setSource$|^paintCell$|^updateContents$|^sizeHint$|^setFocusSection$/
|
|
or $name =~ /^event$|^eventFilter$|^copy$|^detach$|^showEvent$|^format$|^encodedData$/
|
|
or $name =~ /^styleChange$|^insertItem$|^setStatus$|^setState$|^minimumSizeHint$/
|
|
or $name =~ /^updateGeometry$|^setState$|^exec$|^pixmap$|^areaPoints$|^draw$|^writeDir$/ ) {
|
|
# These methods are public in some places, but protected in others,
|
|
# so make them all public.
|
|
$access = "public";
|
|
}
|
|
|
|
|
|
my $altReturnType = undef;
|
|
if ($name =~ /^xForm$/ ) {
|
|
$csharpReturnType = "Object";
|
|
} elsif ($csharpSignature eq "layout()" and $csharpReturnType ne 'void') {
|
|
$altReturnType = "TQLayout";
|
|
} elsif ($csharpSignature eq "defaultFactory()" and $csharpReturnType eq 'TQSqlEditorFactory') {
|
|
$csharpReturnType = "TQEditorFactory";
|
|
} elsif ($csharpSignature eq "statusBar()") {
|
|
$altReturnType = "TQStatusBar";
|
|
} elsif ($csharpSignature eq "menuBar()") {
|
|
$altReturnType = "TQMenuBar";
|
|
} elsif ($csharpSignature =~ /^bits|^scanLine/) {
|
|
$csharpReturnType = "byte[]";
|
|
} elsif ($csharpSignature eq "at()" and $csharpClassName eq 'KFilterDev') {
|
|
$csharpReturnType = "long";
|
|
} elsif ($csharpSignature =~ /copyTo/ and $csharpClassName eq "KDesktopFile" ) {
|
|
$altReturnType = "KConfig";
|
|
}
|
|
|
|
|
|
if ($name =~ /^([a-z])(.*)/) {
|
|
$name = uc($1) . $2;
|
|
|
|
# Only change the method name to start with an upper case letter
|
|
# if it doesn't clash with an enum with the same name
|
|
my $item = kdocAstUtil::findRef( $classNode, $name );
|
|
if ( defined $item && $item->{NodeType} eq 'enum' && $name =~ /^([A-Z])(.*)/) {
|
|
$name = lc($1) . $2;
|
|
}
|
|
|
|
if ($classNode->{astNodeName} eq 'TQIODevice' and $name eq 'State') {
|
|
$name = 'state';
|
|
}
|
|
}
|
|
|
|
if ( defined $altReturnType ) {
|
|
checkImportsForObject( $altReturnType, $addImport );
|
|
$csharpReturnType = $altReturnType;
|
|
}
|
|
|
|
if ($access eq 'public' && ! $isStatic) {
|
|
$interfaceCode .= "\t\t\t$csharpReturnType $name($csharpparams);\n";
|
|
}
|
|
|
|
if (($isStatic or $classNode->{NodeType} eq 'namespace')) {
|
|
$proxyInterfaceCode .= "\t\t\t$csharpReturnType $name($csharpparams);\n";
|
|
}
|
|
|
|
if ( $m->{Access} =~ /_slots/ ) {
|
|
$methodCode .= "\t\t[Q_SLOT(\"". $m->{ReturnType} . " $signature" . "\")]\n";
|
|
}
|
|
|
|
$methodCode .= "\t\t[SmokeMethod(\"" . $signature . "\")]\n";
|
|
$methodCode .= "\t\t" . $access . (($isStatic or $classNode->{NodeType} eq 'namespace') ? " static " : " ");
|
|
|
|
my $overrideNode = kdocAstUtil::findOverride( $rootnode, $classNode, $m->{astNodeName} );
|
|
|
|
if ( ( $generateConstructors
|
|
&& defined $overrideNode
|
|
&& ( $ancestorCount == 1
|
|
|| !defined interfaceForClass($overrideNode->{astNodeName}) ) )
|
|
|| $name eq 'ToString' )
|
|
{
|
|
$methodCode .= "new ";
|
|
}
|
|
|
|
if ($m->{Flags} =~ "v") {
|
|
$methodCode .= "virtual ";
|
|
}
|
|
|
|
$methodCode .= $csharpReturnType;
|
|
$methodCode .= " $name($csharpparams) \{\n";
|
|
|
|
$methodCode .= "\t\t\t" . ($csharpReturnType ne "void" ? "return " : "");
|
|
$methodCode .= (($isStatic or $classNode->{NodeType} eq 'namespace') ? "Static" : "Proxy") . "$csharpClassName().$name(@csharpArgList[0..$#csharpArgTypeList]);\n";
|
|
$methodCode .= "\t\t}\n";
|
|
} else {
|
|
if ( $access =~ /signals/ ) {
|
|
if ($name =~ /^([a-z])(.*)/) {
|
|
$name = uc($1) . $2;
|
|
}
|
|
my $docnode = $m->{DocNode};
|
|
if ( defined $docnode ) {
|
|
my $csharpdocComment = printCSharpdocComment( $docnode, "", "\t\t///", "" );
|
|
$signalCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
|
|
}
|
|
$signalCode .= "\t\t[Q_SIGNAL(\"" . $m->{ReturnType} . " $signature" . "\")]\n";
|
|
$signalCode .= "\t\tvoid $name($csharpparams);\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pop @argTypeList;
|
|
pop @csharpArgTypeList;
|
|
pop @csharpArgList;
|
|
|
|
$csharpSignature = csharpMethodSignature( $m, @argTypeList );
|
|
$hasDuplicateSignature = (defined $csharpMethods->{$csharpSignature} ? 1 : 0);
|
|
|
|
$methodNumber++;
|
|
$iterationCount--;
|
|
} # Iteration loop
|
|
|
|
return ( $methodCode, $interfaceCode, $proxyInterfaceCode, $signalCode );
|
|
}
|
|
|
|
|
|
sub generateEnum($$$)
|
|
{
|
|
my( $classNode, $m, $generateAnonymous ) = @_; # input
|
|
my $methodCode = ''; # output
|
|
|
|
my @heritage = kdocAstUtil::heritage($classNode);
|
|
my $className = join( "::", @heritage );
|
|
my $csharpClassName = $classNode->{astNodeName};
|
|
|
|
if ( ($generateAnonymous and $m->{astNodeName} ) or (! $generateAnonymous and ! $m->{astNodeName}) ) {
|
|
return;
|
|
}
|
|
|
|
if ( defined $m->{DocNode} ) {
|
|
my $csharpdocComment = printCSharpdocComment( $m->{DocNode}, "", "\t\t///", "" );
|
|
$methodCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
|
|
}
|
|
|
|
# In C# enums must have names, so anonymous C++ enums become constants
|
|
if (! $m->{astNodeName}) {
|
|
return generateConst($classNode, $m, $generateAnonymous);
|
|
}
|
|
|
|
$m->{astNodeName} =~ /(.)(.*)/;
|
|
if ($m->{astNodeName} eq 'Type') {
|
|
$methodCode .= "\t\tpublic enum E_Type {\n";
|
|
} else {
|
|
$methodCode .= "\t\tpublic enum " . $m->{astNodeName} . " {\n";
|
|
}
|
|
|
|
my @enums = split(",", $m->{Params});
|
|
my $enumCount = 0;
|
|
foreach my $enum ( @enums ) {
|
|
$enum =~ s/\s//g;
|
|
$enum =~ s/::/./g;
|
|
$enum =~ s/::([a-z])/./g;
|
|
$enum =~ s/\(mode_t\)//;
|
|
$enum =~ s/internal/_internal/;
|
|
$enum =~ s/fixed/_fixed/;
|
|
if ( $enum =~ /(.*)=([-0-9]+)$/ ) {
|
|
$methodCode .= "\t\t\t$1 = $2,\n";
|
|
$enumCount = $2;
|
|
$enumCount++;
|
|
} elsif ( $enum =~ /(.*)=(.*)/ ) {
|
|
$methodCode .= "\t\t\t$1 = $2,\n";
|
|
if ($2 =~ /(0xf0000000)|(0xffffffff)/) {
|
|
$methodCode =~ s/enum ((E_)?[^\s]*)/enum $1 : uint/;
|
|
}
|
|
} else {
|
|
$methodCode .= "\t\t\t$enum = $enumCount,\n";
|
|
$enumCount++;
|
|
}
|
|
}
|
|
|
|
$methodCode .= "\t\t}\n";
|
|
$methodNumber++;
|
|
|
|
return ( $methodCode );
|
|
}
|
|
|
|
sub generateConst($$$)
|
|
{
|
|
my( $classNode, $m, $generateAnonymous ) = @_; # input
|
|
my $methodCode = ''; # output
|
|
|
|
my @heritage = kdocAstUtil::heritage($classNode);
|
|
my $className = join( "::", @heritage );
|
|
my $csharpClassName = $classNode->{astNodeName};
|
|
|
|
my @enums = split(",", $m->{Params});
|
|
my $enumCount = 0;
|
|
foreach my $enum ( @enums ) {
|
|
$enum =~ s/\s//g;
|
|
$enum =~ s/::/./g;
|
|
$enum =~ s/\(mode_t\)//;
|
|
$enum =~ s/internal/_internal/;
|
|
$enum =~ s/fixed/_fixed/;
|
|
$enum =~ s/IsActive/_IsActive/;
|
|
if ( $enum =~ /(.*)=([-0-9]+)$/ ) {
|
|
$methodCode .= "\t\tpublic const int $1 = $2;\n";
|
|
$enumCount = $2;
|
|
$enumCount++;
|
|
} elsif ( $enum =~ /(.*)=(.*)/ ) {
|
|
$methodCode .= "\t\tpublic const int $1 = $2;\n";
|
|
} else {
|
|
$methodCode .= "\t\tpublic const int $enum = $enumCount;\n";
|
|
$enumCount++;
|
|
}
|
|
}
|
|
|
|
$methodCode .= "\n";
|
|
$methodNumber++;
|
|
|
|
return ( $methodCode );
|
|
}
|
|
|
|
sub generateVar($$$)
|
|
{
|
|
my( $classNode, $m, $addImport ) = @_; # input
|
|
my $methodCode = ''; # output
|
|
my $interfaceCode = ''; # output
|
|
|
|
my @heritage = kdocAstUtil::heritage($classNode);
|
|
my $className = join( "::", @heritage );
|
|
my $csharpClassName = $classNode->{astNodeName};
|
|
|
|
my $name = $m->{astNodeName};
|
|
my $varType = $m->{Type};
|
|
$varType =~ s/static\s//;
|
|
$varType =~ s/const\s+(.*)\s*&/$1/;
|
|
$varType =~ s/\s*$//;
|
|
my $fullName = "$className\::$name";
|
|
|
|
checkImportsForObject( $varType, $addImport );
|
|
|
|
# die "Invalid index for $fullName: $classNode->{case}{$fullName} instead of $methodNumber" if $classNode->{case}{$fullName} != $methodNumber;
|
|
# $methodCode .= " static void x_$methodNumber(Smoke::Stack x) {\n";
|
|
# $methodCode .= "\tx[0].s_class = (void*)new $varType($fullName);\n";
|
|
# $methodCode .= " }\n";
|
|
|
|
# if ( ($name !~ /^null$/) && (cplusplusToCSharp($varType) ne "") ) {
|
|
if ( ($name !~ /^null$/) && (cplusplusToCSharp($varType) ne "" ) ) {
|
|
# $interfaceCode .= "\t\t". cplusplusToCSharp($varType) . " $name();\n";
|
|
|
|
# $methodCode .= "\tpublic native static ". cplusplusToCSharp($varType) . " $name();\n";
|
|
}
|
|
|
|
$methodNumber++;
|
|
return ( $methodCode, $interfaceCode );
|
|
}
|
|
|
|
## Called by writeClassDoc
|
|
sub generateAllMethods($$$$$$)
|
|
{
|
|
my ($classNode, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors, $addImport) = @_;
|
|
my $methodCode = '';
|
|
my $interfaceCode = '';
|
|
my $proxyInterfaceCode = '';
|
|
my $signalCode = '';
|
|
$methodNumber = 0;
|
|
#my $className = $classNode->{astNodeName};
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
my $csharpClassName = $mainClassNode->{astNodeName};
|
|
# If the C++ class had multiple inheritance, then the code for all but one of the
|
|
# parents must be copied into the code for csharpClassName. Hence, for TQWidget current
|
|
# classname might be TQPaintDevice, as its methods are needed in TQWidget.
|
|
my $currentClassName = join( ".", kdocAstUtil::heritage($classNode) );
|
|
|
|
my $sourcename = $classNode->{Source}->{astNodeName};
|
|
|
|
if ( $sourcename !~ s!.*(kio/|kparts/|dom/|kabc/|ksettings/|kjs/|ktexteditor/|tdeprint/|tdesu/)(.*)!$1$2!m ) {
|
|
$sourcename =~ s!.*/(.*)!$1!m;
|
|
}
|
|
die "Empty source name for $classNode->{astNodeName}" if ( $sourcename eq '' );
|
|
|
|
if ($generateConstructors) {
|
|
$methodCode .= "\t\tprivate $csharpClassName Proxy$csharpClassName() {\n";
|
|
$methodCode .= "\t\t\treturn ($csharpClassName) _interceptor;\n\t\t}\n";
|
|
|
|
$methodCode .= "\t\tprivate static Object _staticInterceptor = null;\n";
|
|
$methodCode .= "\t\tstatic $csharpClassName() {\n";
|
|
$methodCode .= "\t\t\tSmokeInvocation realProxy = new SmokeInvocation(typeof(I$csharpClassName" . "Proxy), null);\n";
|
|
$methodCode .= "\t\t\t_staticInterceptor = (I$csharpClassName" . "Proxy) realProxy.GetTransparentProxy();\n";
|
|
$methodCode .= "\t\t}\n";
|
|
|
|
$methodCode .= "\t\tprivate static I$csharpClassName" . "Proxy Static$csharpClassName() {\n";
|
|
$methodCode .= "\t\t\treturn (I$csharpClassName". "Proxy) _staticInterceptor;\n\t\t}\n\n";
|
|
}
|
|
|
|
if ($classNode->{astNodeName} ne $main::globalSpaceClassName) {
|
|
# my $s;
|
|
# for my $sn( @{$classNode->{Sources}} ) {
|
|
# if ( ($s = $sn->{astNodeName}) !~ s!.*(kio/|kparts/|dom/|kabc/|ksettings/|kjs/|ktexteditor/|tdeprint/|tdesu/)(.*)!$1$2!m ) {
|
|
# $s =~ s!.*/(.*)!$1!m;
|
|
# }
|
|
# $addInclude->{$s} = 1;
|
|
# }
|
|
}
|
|
|
|
$addImport->{"Qt"} = 1;
|
|
|
|
# Do all enums first, anonymous ones and then named enums
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $methodNode ) = @_;
|
|
|
|
if ( $methodNode->{NodeType} eq 'enum' and $currentClassName eq $csharpClassName ) {
|
|
my ($meth) = generateEnum( $classNode, $methodNode, 1 );
|
|
$methodCode .= $meth;
|
|
}
|
|
}, undef );
|
|
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $methodNode ) = @_;
|
|
|
|
if ( $methodNode->{NodeType} eq 'enum' and $currentClassName eq $csharpClassName ) {
|
|
my ($meth) = generateEnum( $classNode, $methodNode, 0 );
|
|
$methodCode .= $meth;
|
|
}
|
|
}, undef );
|
|
|
|
# Then all static vars
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $methodNode ) = @_;
|
|
|
|
if ( $methodNode->{NodeType} eq 'var' and $currentClassName eq $csharpClassName ) {
|
|
my ($meth, $interface) = generateVar( $classNode, $methodNode, $addImport );
|
|
$methodCode .= $meth;
|
|
# $interfaceCode .= $interface;
|
|
}
|
|
}, undef );
|
|
|
|
# Then all methods
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $methodNode ) = @_;
|
|
|
|
if ( $methodNode->{NodeType} eq 'method' ) {
|
|
my ($meth, $interface, $proxyInterface, $signals) = generateMethod( $classNode, $methodNode, $addImport, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors );
|
|
$methodCode .= $meth;
|
|
$interfaceCode .= $interface;
|
|
$proxyInterfaceCode .= $proxyInterface;
|
|
$signalCode .= $signals;
|
|
}
|
|
}, undef );
|
|
|
|
# Virtual methods
|
|
# if ($classNode->{BindingDerives}) {
|
|
# my %virtualMethods;
|
|
# allVirtualMethods( $classNode, \%virtualMethods );
|
|
|
|
# for my $sig (sort keys %virtualMethods) {
|
|
# my ($meth) = generateVirtualMethod( $classNode, $sig, $virtualMethods{$sig}{method}, $virtualMethods{$sig}{class}, \%addImport );
|
|
# $methodCode .= $meth;
|
|
# }
|
|
# }
|
|
|
|
# Destructor
|
|
# "virtual" is useless, if the base class has a virtual destructor then the x_* class too.
|
|
#if($classNode->{HasVirtualDestructor} and $classNode->{HasDestructor}) {
|
|
# $methodCode .= " virtual ~$bridgeClassName() {}\n";
|
|
#}
|
|
# We generate a dtor though, because we might want to add stuff into it
|
|
|
|
if ($currentClassName eq $csharpClassName and $classNode->{HasPublicDestructor}) {
|
|
if ( $generateConstructors ) {
|
|
$methodCode .= "\t\t~$csharpClassName() {\n";
|
|
$methodCode .= "\t\t\tDispose$csharpClassName();\n\t\t}\n";
|
|
|
|
if ( hasVirtualDestructor($classNode, $classNode) == 1 ) {
|
|
$methodCode .= "\t\tpublic new ";
|
|
} else {
|
|
$methodCode .= "\t\tpublic ";
|
|
}
|
|
$methodCode .= "void Dispose() {\n";
|
|
$methodCode .= "\t\t\tDispose$csharpClassName();\n\t\t}\n";
|
|
|
|
$methodCode .= "\t\tprivate void Dispose$csharpClassName() {\n";
|
|
$methodCode .= "\t\t\tProxy$csharpClassName().Dispose$csharpClassName();\n\t\t}\n";
|
|
}
|
|
# die "$className destructor: methodNumber=$methodNumber != case entry=".$classNode->{case}{"~$className()"}."\n"
|
|
# if $methodNumber != $classNode->{case}{"~$className()"};
|
|
$methodNumber++;
|
|
}
|
|
|
|
return ( $methodCode, $interfaceCode, $proxyInterfaceCode, $signalCode );
|
|
}
|
|
|
|
# Return 0 if the class has no virtual dtor, 1 if it has, 2 if it's private
|
|
sub hasVirtualDestructor($$)
|
|
{
|
|
my ( $classNode, $startNode ) = @_;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
return if ( $skippedClasses{$className} || defined interfaceForClass($className) );
|
|
|
|
my $parentHasIt;
|
|
# Look at ancestors, and (recursively) call hasVirtualDestructor for each
|
|
# It's enough to have one parent with a prot/public virtual dtor
|
|
Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
|
|
my $vd = hasVirtualDestructor( $_[0], $_[1] );
|
|
$parentHasIt = $vd unless $parentHasIt > $vd;
|
|
} );
|
|
return $parentHasIt if $parentHasIt; # 1 or 2
|
|
|
|
# Now look in $classNode - including private methods
|
|
my $doPrivate = $main::doPrivate;
|
|
$main::doPrivate = 1;
|
|
my $result;
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
return unless( $m->{NodeType} eq "method" && $m->{ReturnType} eq '~' );
|
|
|
|
if ( $m->{Flags} =~ /[vp]/ && $classNode != $startNode) {
|
|
if ( $m->{Access} =~ /private/ ) {
|
|
$result=2; # private virtual
|
|
} else {
|
|
$result=1; # [protected or public] virtual
|
|
}
|
|
}
|
|
},
|
|
undef
|
|
);
|
|
$main::doPrivate = $doPrivate;
|
|
$result=0 if (!defined $result);
|
|
return $result;
|
|
}
|
|
|
|
=head2 allVirtualMethods
|
|
|
|
Parameters: class node, dict
|
|
|
|
Adds to the dict, for all method nodes that are virtual, in this class and in parent classes :
|
|
{method} the method node, {class} the class node (the one where the virtual is implemented)
|
|
|
|
=cut
|
|
|
|
sub allVirtualMethods($$)
|
|
{
|
|
my ( $classNode, $virtualMethods ) = @_;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
return if ( $skippedClasses{$className} );
|
|
|
|
# Look at ancestors, and (recursively) call allVirtualMethods for each
|
|
# This is done first, so that virtual methods that are reimplemented as 'private'
|
|
# can be removed from the list afterwards (below)
|
|
Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
|
|
allVirtualMethods( @_[0], $virtualMethods );
|
|
}, undef
|
|
);
|
|
|
|
# Now look for virtual methods in $classNode - including private ones
|
|
my $doPrivate = $main::doPrivate;
|
|
$main::doPrivate = 1;
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
# Only interested in methods, and skip destructors
|
|
return unless( $m->{NodeType} eq "method" && $m->{ReturnType} ne '~' );
|
|
|
|
my $signature = methodSignature( $m, $#{$m->{ParamList}} );
|
|
print STDERR $signature . " ($m->{Access})\n" if ($debug);
|
|
|
|
# A method is virtual if marked as such (v=virtual p=pure virtual)
|
|
# or if a parent method with same signature was virtual
|
|
if ( $m->{Flags} =~ /[vp]/ or defined $virtualMethods->{$signature} ) {
|
|
if ( $m->{Access} =~ /private/ ) {
|
|
if ( defined $virtualMethods->{$signature} ) { # remove previously defined
|
|
delete $virtualMethods->{$signature};
|
|
}
|
|
# else, nothing, just ignore private virtual method
|
|
} else {
|
|
$virtualMethods->{$signature}{method} = $m;
|
|
$virtualMethods->{$signature}{class} = $classNode;
|
|
}
|
|
}
|
|
},
|
|
undef
|
|
);
|
|
$main::doPrivate = $doPrivate;
|
|
}
|
|
|
|
# Known typedef? If so, apply it.
|
|
sub applyTypeDef($)
|
|
{
|
|
my $type = shift;
|
|
# Parse 'const' in front of it, and '*' or '&' after it
|
|
my $prefix = $type =~ s/^const\s+// ? 'const ' : '';
|
|
my $suffix = $type =~ s/\s*([\&\*]+)$// ? $1 : '';
|
|
|
|
if (exists $typedeflist{$type}) {
|
|
return $prefix.$typedeflist{$type}.$suffix;
|
|
}
|
|
return $prefix.$type.$suffix;
|
|
}
|
|
|
|
# Register type ($1) into %allTypes if not already there
|
|
sub registerType($$) {
|
|
my $type = shift;
|
|
#print "registerType: $type\n" if ($debug);
|
|
|
|
$type =~ s/\s+const$//; # for 'char* const'
|
|
$type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
|
|
|
|
return if ( $type eq 'void' or $type eq '' or $type eq '~' );
|
|
die if ( $type eq '...' ); # ouch
|
|
|
|
# Let's register the real type, not its known equivalent
|
|
#$type = applyTypeDef($type);
|
|
|
|
# Enum _value_ -> get corresponding type
|
|
if (exists $enumValueToType{$type}) {
|
|
$type = $enumValueToType{$type};
|
|
}
|
|
|
|
# Already in allTypes
|
|
if(exists $allTypes{$type}) {
|
|
return;
|
|
}
|
|
|
|
die if $type eq 'TQTextEdit::UndoRedoInfo::Type';
|
|
die if $type eq '';
|
|
|
|
my $realType = $type;
|
|
|
|
# Look for references (&) and pointers (* or **) - this will not handle *& correctly.
|
|
# We do this parsing here because both the type list and iterproto need it
|
|
if($realType =~ s/&$//) {
|
|
$allTypes{$type}{typeFlags} = 'Smoke::tf_ref';
|
|
}
|
|
elsif($realType ne 'void*' && $realType =~ s/\*$//) {
|
|
$allTypes{$type}{typeFlags} = 'Smoke::tf_ptr';
|
|
}
|
|
else {
|
|
$allTypes{$type}{typeFlags} = 'Smoke::tf_stack';
|
|
}
|
|
|
|
if ( $realType =~ s/^const\s+// ) { # Remove 'const'
|
|
$allTypes{$type}{typeFlags} .= ' | Smoke::tf_const';
|
|
}
|
|
|
|
# Apply typedefs, and store the resulting type.
|
|
# For instance, if $type was TQ_UINT16&, realType will be ushort
|
|
$allTypes{$type}{realType} = applyTypeDef( $realType );
|
|
|
|
# In the first phase we only create entries into allTypes.
|
|
# The values (indexes) are calculated afterwards, once the list is full.
|
|
$allTypes{$type}{index} = -1;
|
|
#print STDERR "Register $type. Realtype: $realType\n" if($debug);
|
|
}
|
|
|
|
# Get type from %allTypes
|
|
# This returns a hash with {index}, {isEnum}, {typeFlags}, {realType}
|
|
# (and {typeId} after the types array is written by writeSmokeDataFile)
|
|
sub findTypeEntry($) {
|
|
my $type = shift;
|
|
my $typeIndex = -1;
|
|
$type =~ s/\s+const$//; # for 'char* const'
|
|
$type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
|
|
|
|
return undef if ( $type =~ '~' or $type eq 'void' or $type eq '' );
|
|
|
|
# Enum _value_ -> get corresponding type
|
|
if (exists $enumValueToType{$type}) {
|
|
$type = $enumValueToType{$type};
|
|
}
|
|
|
|
die "type not known: $type" unless defined $allTypes{$type};
|
|
return $allTypes{ $type };
|
|
}
|
|
|
|
# List of all csharp super-classes for a given class, via single inheritance.
|
|
# Excluding any which are mapped onto interfaces to avoid multiple inheritance.
|
|
sub direct_superclass_list($)
|
|
{
|
|
my $classNode = shift;
|
|
my @super;
|
|
my $has_ancestor = 0;
|
|
my $direct_ancestor = undef;
|
|
my $name;
|
|
|
|
Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
|
|
( $direct_ancestor, $name ) = @_;
|
|
if ($name =~ /TQMemArray|TQSqlFieldInfoList/) {
|
|
# Template classes, give up for now..
|
|
$has_ancestor = 1;
|
|
} elsif (!defined kalyptusDataDict::interfacemap($name)) {
|
|
push @super, $direct_ancestor;
|
|
push @super, direct_superclass_list( $direct_ancestor );
|
|
$has_ancestor = 1;
|
|
}
|
|
}, undef );
|
|
|
|
if (! $has_ancestor and defined $direct_ancestor) {
|
|
push @super, $direct_ancestor;
|
|
push @super, direct_superclass_list( $direct_ancestor );
|
|
}
|
|
|
|
return @super;
|
|
}
|
|
|
|
# List of all super-classes for a given class
|
|
sub superclass_list($)
|
|
{
|
|
my $classNode = shift;
|
|
my @super;
|
|
Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
|
|
push @super, @_[0];
|
|
push @super, superclass_list( @_[0] );
|
|
}, undef );
|
|
return @super;
|
|
}
|
|
|
|
sub is_kindof($$)
|
|
{
|
|
my $classNode = shift;
|
|
my $className = shift;
|
|
|
|
if ($classNode->{astNodeName} eq $className) {
|
|
return 1;
|
|
}
|
|
|
|
my @superclasses = superclass_list($classNode);
|
|
foreach my $ancestor (@superclasses) {
|
|
if ($ancestor->{astNodeName} eq $className) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
# Store the {case} dict in the class Node (method signature -> index in the "case" switch)
|
|
# This also determines which methods should NOT be in the switch, and sets {SkipFromSwitch} for them
|
|
sub prepareCaseDict($) {
|
|
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
$classNode->AddProp("case", {});
|
|
my $methodNumber = 0;
|
|
|
|
# First look at all enums for this class
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
next unless $m->{NodeType} eq 'enum';
|
|
foreach my $val ( @{$m->{ParamList}} ) {
|
|
my $fullEnumName = "$className\::".$val->{ArgName};
|
|
print STDERR "Enum: $fullEnumName -> case $methodNumber\n" if ($debug);
|
|
$classNode->{case}{$fullEnumName} = $methodNumber;
|
|
$enumValueToType{$fullEnumName} = "$className\::$m->{astNodeName}";
|
|
$methodNumber++;
|
|
}
|
|
}, undef );
|
|
|
|
# Check for static vars
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
next unless $m->{NodeType} eq 'var';
|
|
my $name = "$className\::".$m->{astNodeName};
|
|
print STDERR "Var: $name -> case $methodNumber\n" if ($debug);
|
|
$classNode->{case}{$name} = $methodNumber;
|
|
$methodNumber++;
|
|
|
|
}, undef );
|
|
|
|
|
|
# Now look at all methods for this class
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
next unless $m->{NodeType} eq 'method';
|
|
my $name = $m->{astNodeName};
|
|
my $isConstructor = ($name eq $classNode->{astNodeName} );
|
|
if ($isConstructor and ($m->{ReturnType} eq '~')) # destructor
|
|
{
|
|
# Remember whether we'll generate a switch entry for the destructor
|
|
$m->{SkipFromSwitch} = 1 unless ($classNode->{CanBeInstanciated} and $classNode->{HasPublicDestructor});
|
|
next;
|
|
}
|
|
|
|
# Don't generate bindings for protected methods (incl. signals) if
|
|
# we're not deriving from the C++ class. Only take public and public_slots
|
|
my $ok = ( $classNode->{BindingDerives} or $m->{Access} =~ /public/ ) ? 1 : 0;
|
|
|
|
# Don't generate bindings for pure virtuals - we can't call them ;)
|
|
$ok = 0 if ( $ok && $m->{Flags} =~ "p" );
|
|
|
|
# Bugfix for Qt-3.0.4: those methods are NOT implemented (report sent).
|
|
$ok = 0 if ( $ok && $className eq 'TQLineEdit' && ( $name eq 'setPasswordChar' || $name eq 'passwordChar' ) );
|
|
$ok = 0 if ( $ok && $className eq 'TQWidgetItem' && $name eq 'widgetSizeHint' );
|
|
|
|
if ( !$ok )
|
|
{
|
|
#print STDERR "Skipping $className\::$name\n" if ($debug);
|
|
$m->{SkipFromSwitch} = 1;
|
|
next;
|
|
}
|
|
|
|
my @args = @{ $m->{ParamList} };
|
|
my $last = $m->{FirstDefaultParam};
|
|
$last = scalar @args unless defined $last;
|
|
my $iterationCount = scalar(@args) - $last;
|
|
while($iterationCount >= 0) {
|
|
my $sig = methodSignature( $m, $#args );
|
|
$classNode->{case}{$sig} = $methodNumber;
|
|
#print STDERR "prepareCaseDict: registered case number $methodNumber for $sig in $className()\n" if ($debug);
|
|
pop @args;
|
|
$iterationCount--;
|
|
$methodNumber++;
|
|
}
|
|
}, undef );
|
|
|
|
# Add the destructor, at the end
|
|
if ($classNode->{CanBeInstanciated} and $classNode->{HasPublicDestructor}) {
|
|
$classNode->{case}{"~$className()"} = $methodNumber;
|
|
# workaround for ~Sub::Class() being seen as Sub::~Class()
|
|
$classNode->{case}{"~$classNode->{astNodeName}()"} = $methodNumber;
|
|
#print STDERR "prepareCaseDict: registered case number $methodNumber for ~$className()\n" if ($debug);
|
|
}
|
|
}
|
|
|
|
sub writeSmokeDataFile($) {
|
|
my $rootnode = shift;
|
|
|
|
# Make list of classes
|
|
my %allImports; # list of all header files for all classes
|
|
my @classlist;
|
|
push @classlist, ""; # Prepend empty item for "no class"
|
|
my %enumclasslist;
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = $_[0];
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
push @classlist, $className;
|
|
$enumclasslist{$className}++ if keys %{$classNode->{enumerations}};
|
|
$classNode->{ClassIndex} = $#classlist;
|
|
addImportForClass( $classNode, \%allImports, undef );
|
|
} );
|
|
|
|
my %classidx = do { my $i = 0; map { $_ => $i++ } @classlist };
|
|
|
|
my $file = "$outputdir/smokedata.cpp";
|
|
# open OUT, ">$file" or die "Couldn't create $file\n";
|
|
|
|
# foreach my $incl (sort{
|
|
# return 1 if $a=~/qmotif/; # move qmotif* at bottom (they include dirty X11 headers)
|
|
# return -1 if $b=~/qmotif/;
|
|
# return -1 if substr($a,0,1) eq 'q' and substr($b,0,1) ne 'q'; # move Qt headers on top
|
|
# return 1 if substr($a,0,1) ne 'q' and substr($b,0,1) eq 'q';
|
|
# $a cmp $b
|
|
# } keys %allIncludes) {
|
|
# die if $imp eq '';
|
|
# print OUT "import $imp;\n";
|
|
# }
|
|
|
|
# print OUT "\n";
|
|
|
|
print STDERR "Writing ${libname}_cast function\n" if ($debug);
|
|
|
|
# Prepare descendants information for each class
|
|
my %descendants; # classname -> list of descendant nodes
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
# Get _all_ superclasses (up any number of levels)
|
|
# and store that $classNode is a descendant of $s
|
|
my @super = superclass_list($classNode);
|
|
for my $s (@super) {
|
|
my $superClassName = join( "::", kdocAstUtil::heritage($s) );
|
|
Ast::AddPropList( \%descendants, $superClassName, $classNode );
|
|
}
|
|
} );
|
|
|
|
# Iterate over all classes, to write the xtypecast function
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
# @super will contain superclasses, the class itself, and all descendants
|
|
my @super = superclass_list($classNode);
|
|
push @super, $classNode;
|
|
if ( defined $descendants{$className} ) {
|
|
push @super, @{$descendants{$className}};
|
|
}
|
|
my $cur = $classidx{$className};
|
|
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
# print OUT " case $cur:\t//$className\n";
|
|
# print OUT "\tswitch(to) {\n";
|
|
# $cur = -1;
|
|
# my %casevalues;
|
|
# for my $s (@super) {
|
|
# my $superClassName = join( "::", kdocAstUtil::heritage($s) );
|
|
# next if !defined $classidx{$superClassName}; # inherits from unknown class, see below
|
|
# next if $classidx{$superClassName} == $cur; # shouldn't happen in Qt
|
|
# next if $s->kdocAstUtil::inheritsAsVirtual($classNode); # can't cast from a virtual base class
|
|
# $cur = $classidx{$superClassName}; # KDE has MI with diamond shaped cycles (cf. KXMLGUIClient)
|
|
# next if $casevalues{$cur}; # ..so skip any duplicate parents
|
|
# print OUT "\t case $cur: return (void*)($superClassName*)($className*)xptr;\n";
|
|
# $casevalues{$cur} = 1;
|
|
# }
|
|
# print OUT "\t default: return xptr;\n";
|
|
# print OUT "\t}\n";
|
|
} );
|
|
# print OUT " default: return xptr;\n";
|
|
# print OUT " }\n";
|
|
# print OUT "}\n\n";
|
|
|
|
|
|
# Write inheritance array
|
|
# Imagine you have "Class : public super1, super2"
|
|
# The inheritlist array will get 3 new items: super1, super2, 0
|
|
my %inheritfinder; # key = (super1, super2) -> data = (index in @inheritlist). This one allows reuse.
|
|
my %classinherit; # we store that index in %classinherit{className}
|
|
# We don't actually need to store inheritlist in memory, we write it
|
|
# directly to the file. We only need to remember its current size.
|
|
my $inheritlistsize = 1;
|
|
|
|
# print OUT "// Group of class IDs (0 separated) used as super class lists.\n";
|
|
# print OUT "// Classes with super classes have an index into this array.\n";
|
|
# print OUT "static short ${libname}_inheritanceList[] = {\n";
|
|
# print OUT "\t0,\t// 0: (no super class)\n";
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "__", kdocAstUtil::heritage($classNode) );
|
|
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
print STDERR "inheritanceList: looking at $className\n" if ($debug);
|
|
|
|
# Make list of direct ancestors
|
|
my @super;
|
|
Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
|
|
my $superClassName = join( "::", kdocAstUtil::heritage($_[0]) );
|
|
push @super, $superClassName;
|
|
}, undef );
|
|
# Turn that into a list of class indexes
|
|
my $key = '';
|
|
foreach my $superClass( @super ) {
|
|
if (defined $classidx{$superClass}) {
|
|
$key .= ', ' if ( length $key > 0 );
|
|
$key .= $classidx{$superClass};
|
|
}
|
|
}
|
|
if ( $key ne '' ) {
|
|
if ( !defined $inheritfinder{$key} ) {
|
|
print OUT "\t";
|
|
my $index = $inheritlistsize; # Index of first entry (for this group) in inheritlist
|
|
foreach my $superClass( @super ) {
|
|
if (defined $classidx{$superClass}) {
|
|
print OUT "$classidx{$superClass}, ";
|
|
$inheritlistsize++;
|
|
}
|
|
}
|
|
$inheritlistsize++;
|
|
my $comment = join( ", ", @super );
|
|
print OUT "0,\t// $index: $comment\n";
|
|
$inheritfinder{$key} = $index;
|
|
}
|
|
$classinherit{$className} = $inheritfinder{$key};
|
|
} else { # No superclass
|
|
$classinherit{$className} = 0;
|
|
}
|
|
} );
|
|
# print OUT "};\n\n";
|
|
|
|
|
|
# print OUT "// These are the xenum functions for manipulating enum pointers\n";
|
|
for my $className (keys %enumclasslist) {
|
|
my $c = $className;
|
|
$c =~ s/::/__/g;
|
|
# print OUT "void xenum_$c\(Smoke::EnumOperation, Smoke::Index, void*&, long&);\n";
|
|
}
|
|
# print OUT "\n";
|
|
# print OUT "// Those are the xcall functions defined in each x_*.cpp file, for dispatching method calls\n";
|
|
my $firstClass = 1;
|
|
for my $className (@classlist) {
|
|
if ($firstClass) {
|
|
$firstClass = 0;
|
|
next;
|
|
}
|
|
my $c = $className; # make a copy
|
|
$c =~ s/::/__/g;
|
|
# print OUT "void xcall_$c\(Smoke::Index, void*, Smoke::Stack);\n";
|
|
}
|
|
# print OUT "\n";
|
|
|
|
# Write class list afterwards because it needs offsets to the inheritance array.
|
|
# print OUT "// List of all classes\n";
|
|
# print OUT "// Name, index into inheritanceList, method dispatcher, enum dispatcher, class flags\n";
|
|
# print OUT "static Smoke::Class ${libname}_classes[] = {\n";
|
|
my $firstClass = 1;
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "__", kdocAstUtil::heritage($classNode) );
|
|
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
if ($firstClass) {
|
|
$firstClass = 0;
|
|
print OUT "\t{ 0L, 0, 0, 0, 0 }, \t// 0 (no class)\n";
|
|
}
|
|
my $c = $className;
|
|
$c =~ s/::/__/g;
|
|
my $xcallFunc = "xcall_$c";
|
|
my $xenumFunc = "0";
|
|
$xenumFunc = "xenum_$c" if exists $enumclasslist{$className};
|
|
# %classinherit needs Foo__Bar, not Foo::Bar?
|
|
die "problem with $className" unless defined $classinherit{$c};
|
|
|
|
my $xClassFlags = 0;
|
|
$xClassFlags .= "|Smoke::cf_constructor" if $classNode->{CanBeInstanciated}; # correct?
|
|
$xClassFlags .= "|Smoke::cf_deepcopy" if $classNode->{CanBeCopied}; # HasCopyConstructor would be wrong (when it's private)
|
|
$xClassFlags .= "|Smoke::cf_virtual" if hasVirtualDestructor($classNode, $classNode) == 1;
|
|
# $xClassFlags .= "|Smoke::cf_undefined" if ...;
|
|
$xClassFlags =~ s/0\|//; # beautify
|
|
# print OUT "\t{ \"$className\", $classinherit{$c}, $xcallFunc, $xenumFunc, $xClassFlags }, \t//$classidx{$className}\n";
|
|
} );
|
|
# print OUT "};\n\n";
|
|
|
|
|
|
# print OUT "// List of all types needed by the methods (arguments and return values)\n";
|
|
# print OUT "// Name, class ID if arg is a class, and TypeId\n";
|
|
# print OUT "static Smoke::Type ${libname}_types[] = {\n";
|
|
my $typeCount = 0;
|
|
$allTypes{''}{index} = 0; # We need an "item 0"
|
|
for my $type (sort keys %allTypes) {
|
|
$allTypes{$type}{index} = $typeCount; # Register proper index in allTypes
|
|
if ( $typeCount == 0 ) {
|
|
# print OUT "\t{ 0, 0, 0 },\t//0 (no type)\n";
|
|
$typeCount++;
|
|
next;
|
|
}
|
|
my $isEnum = $allTypes{$type}{isEnum};
|
|
my $typeId;
|
|
my $typeFlags = $allTypes{$type}{typeFlags};
|
|
my $realType = $allTypes{$type}{realType};
|
|
die "$type" if !defined $typeFlags;
|
|
# die "$realType" if $realType =~ /\(/;
|
|
# First write the name
|
|
# print OUT "\t{ \"$type\", ";
|
|
# Then write the classId (and find out the typeid at the same time)
|
|
if(exists $classidx{$realType}) { # this one first, we want t_class for TQBlah*
|
|
$typeId = 't_class';
|
|
# print OUT "$classidx{$realType}, ";
|
|
}
|
|
elsif($type =~ /&$/ || $type =~ /\*$/) {
|
|
$typeId = 't_voidp';
|
|
# print OUT "0, "; # no classId
|
|
}
|
|
elsif($isEnum || $allTypes{$realType}{isEnum}) {
|
|
$typeId = 't_enum';
|
|
if($realType =~ /(.*)::/) {
|
|
my $c = $1;
|
|
if($classidx{$c}) {
|
|
# print OUT "$classidx{$c}, ";
|
|
} else {
|
|
# print OUT "0 /* unknown class $c */, ";
|
|
}
|
|
} else {
|
|
# print OUT "0 /* unknown $realType */, "; # no classId
|
|
}
|
|
}
|
|
else {
|
|
$typeId = $typeunion{$realType};
|
|
if (defined $typeId) {
|
|
$typeId =~ s/s_/t_/; # from s_short to t_short for instance
|
|
}
|
|
else {
|
|
# Not a known class - ouch, this happens quite a lot
|
|
# (private classes, typedefs, template-based types, etc)
|
|
if ( $skippedClasses{$realType} ) {
|
|
# print STDERR "$realType has been skipped, using t_voidp for it\n";
|
|
} else {
|
|
unless( $realType =~ /</ ) { # Don't warn for template stuff...
|
|
print STDERR "$realType isn't a known type (type=$type)\n";
|
|
}
|
|
}
|
|
$typeId = 't_voidp'; # Unknown -> map to a void *
|
|
}
|
|
# print OUT "0, "; # no classId
|
|
}
|
|
# Then write the flags
|
|
die "$type" if !defined $typeId;
|
|
# print OUT "Smoke::$typeId | $typeFlags },";
|
|
# print OUT "\t//$typeCount\n";
|
|
$typeCount++;
|
|
# Remember it for coerce_type
|
|
$allTypes{$type}{typeId} = $typeId;
|
|
}
|
|
# print OUT "};\n\n";
|
|
|
|
|
|
my %arglist; # registers the needs for argumentList (groups of type ids)
|
|
my %methods;
|
|
# Look for all methods and all enums, in all classes
|
|
# And fill in methods and arglist. This loop writes nothing to OUT.
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
print STDERR "writeSmokeDataFile: arglist: looking at $className\n" if ($debug);
|
|
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
my $methName = $m->{astNodeName};
|
|
# For destructors, get a proper signature that includes the '~'
|
|
if ( $m->{ReturnType} eq '~' )
|
|
{
|
|
$methName = '~' . $methName ;
|
|
# Let's even store that change, otherwise we have to do it many times
|
|
$m->{astNodeName} = $methName;
|
|
}
|
|
|
|
if( $m->{NodeType} eq "enum" ) {
|
|
|
|
foreach my $enum ( @{$m->{ParamList}} ) {
|
|
my $enumName = $enum->{ArgName};
|
|
$methods{$enumName}++;
|
|
}
|
|
|
|
} elsif ( $m->{NodeType} eq 'var' ) {
|
|
|
|
$methods{$m->{astNodeName}}++;
|
|
|
|
} elsif( $m->{NodeType} eq "method" ) {
|
|
|
|
$methods{$methName}++;
|
|
my @protos;
|
|
makeprotos(\%classidx, $m, \@protos);
|
|
|
|
#print "made @protos from $className $methName $m->{Signature})\n" if ($debug);
|
|
for my $p (@protos) {
|
|
$methods{$p}++;
|
|
my $argcnt = 0;
|
|
$argcnt = length($1) if $p =~ /([\$\#\?]+)/;
|
|
my $sig = methodSignature($m, $argcnt-1);
|
|
# Store in a class hash named "proto", a proto+signature => method association
|
|
$classNode->{proto}{$p}{$sig} = $m;
|
|
#$classNode->{signature}{$sig} = $p;
|
|
# There's probably a way to do this better, but this is the fastest way
|
|
# to get the old code going: store classname into method
|
|
$m->{class} = $className;
|
|
}
|
|
|
|
my $firstDefaultParam = $m->{FirstDefaultParam};
|
|
$firstDefaultParam = scalar(@{ $m->{ParamList} }) unless defined $firstDefaultParam;
|
|
my $argNames = '';
|
|
my $args = '';
|
|
for(my $i = 0; $i < @{ $m->{ParamList} }; $i++) {
|
|
$args .= ', ' if $i;
|
|
$argNames .= ', ' if $i;
|
|
my $argType = $m->{ParamList}[$i]{ArgType};
|
|
my $typeEntry = findTypeEntry( $argType );
|
|
$args .= defined $typeEntry ? $typeEntry->{index} : 0;
|
|
$argNames .= $argType;
|
|
|
|
if($i >= ($firstDefaultParam - 1)) {
|
|
#print "arglist entry: $args\n";
|
|
$arglist{$args} = $argNames;
|
|
}
|
|
|
|
}
|
|
# create an entry for e.g. "arg0,arg1,arg2" where argN is index in allTypes of type for argN
|
|
# The value, $argNames, is temporarily stored, to be written out as comment
|
|
# It gets replaced with the index in the next loop.
|
|
#print "arglist entry : $args\n";
|
|
$arglist{$args} = $argNames;
|
|
}
|
|
}, # end of sub
|
|
undef
|
|
);
|
|
});
|
|
|
|
|
|
$arglist{''} = 0;
|
|
# Print arguments array
|
|
# print OUT "static Smoke::Index ${libname}_argumentList[] = {\n";
|
|
my $argListCount = 0;
|
|
for my $args (sort keys %arglist) {
|
|
my @dunnohowtoavoidthat = split(',',$args);
|
|
my $numTypes = $#dunnohowtoavoidthat;
|
|
if ($args eq '') {
|
|
# print OUT "\t0,\t//0 (void)\n";
|
|
} else {
|
|
# This is a nice trick : args can be written in one go ;)
|
|
# print OUT "\t$args, 0,\t//$argListCount $arglist{$args} \n";
|
|
}
|
|
$arglist{$args} = $argListCount; # Register proper index in argList
|
|
$argListCount += $numTypes + 2; # Move forward by as much as we wrote out
|
|
}
|
|
# print OUT "};\n\n";
|
|
|
|
$methods{''} = 0;
|
|
my @methodlist = sort keys %methods;
|
|
my %methodidx = do { my $i = 0; map { $_ => $i++ } @methodlist };
|
|
|
|
# print OUT "// Raw list of all methods, using munged names\n";
|
|
# print OUT "static const char *${libname}_methodNames[] = {\n";
|
|
my $methodNameCount = $#methodlist;
|
|
for my $m (@methodlist) {
|
|
# print OUT qq( "$m",\t//$methodidx{$m}\n);
|
|
}
|
|
# print OUT "};\n\n";
|
|
|
|
# print OUT "// (classId, name (index in methodNames), argumentList index, number of args, method flags, return type (index in types), xcall() index)\n";
|
|
# print OUT "static Smoke::Method ${libname}_methods[] = {\n";
|
|
my @methods;
|
|
%allMethods = ();
|
|
my $methodCount = 0;
|
|
# Look at all classes and all enums again
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
my $classIndex = $classidx{$className};
|
|
print STDERR "writeSmokeDataFile: methods: looking at $className\n" if ($debug);
|
|
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
if( $m->{NodeType} eq "enum" ) {
|
|
|
|
foreach my $enum ( @{$m->{ParamList}} ) {
|
|
my $enumName = $enum->{ArgName};
|
|
my $fullEnumName = "$className\::$enumName";
|
|
my $sig = "$className\::$enumName\()";
|
|
my $xmethIndex = $methodidx{$enumName};
|
|
die "'Method index' for enum $sig not found" unless defined $xmethIndex;
|
|
my $typeId = findTypeEntry( $fullEnumName )->{index};
|
|
die "enum has no {case} value in $className: $fullEnumName" unless defined $classNode->{case}{$fullEnumName};
|
|
# print OUT "\t{$classIndex, $xmethIndex, 0, 0, Smoke::mf_static, $typeId, $classNode->{case}{$fullEnumName}},\t//$methodCount $fullEnumName (enum)\n";
|
|
$allMethods{$sig} = $methodCount;
|
|
print STDERR "Added entry for " . $sig . " into \$allMethods\n" if ($debug);
|
|
$methods[$methodCount] = {
|
|
c => $classIndex,
|
|
methIndex => $xmethIndex,
|
|
argcnt => '0',
|
|
args => 0,
|
|
retTypeIndex => 0,
|
|
idx => $classNode->{case}{$fullEnumName}
|
|
};
|
|
$methodCount++;
|
|
}
|
|
|
|
} elsif( $m->{NodeType} eq 'var' ) {
|
|
|
|
my $name = $m->{astNodeName};
|
|
my $fullName = "$className\::$name";
|
|
my $sig = "$fullName\()";
|
|
my $xmethIndex = $methodidx{$name};
|
|
die "'Method index' for var $sig not found" unless defined $xmethIndex;
|
|
my $varType = $m->{Type};
|
|
$varType =~ s/static\s//;
|
|
$varType =~ s/const\s+(.*)\s*&/$1/;
|
|
$varType =~ s/\s*$//;
|
|
my $typeId = findTypeEntry( $varType )->{index};
|
|
die "var has no {case} value in $className: $fullName" unless defined $classNode->{case}{$fullName};
|
|
# print OUT "\t{$classIndex, $xmethIndex, 0, 0, Smoke::mf_static, $typeId, $classNode->{case}{$fullName}},\t//$methodCount $fullName (static var)\n";
|
|
$allMethods{$sig} = $methodCount;
|
|
print STDERR "Added entry for " . $sig . " into \$allMethods\n" if ($debug);
|
|
$methods[$methodCount] = {
|
|
c => $classIndex,
|
|
methIndex => $xmethIndex,
|
|
argcnt => '0',
|
|
args => 0,
|
|
retTypeIndex => 0,
|
|
idx => $classNode->{case}{$fullName}
|
|
};
|
|
$methodCount++;
|
|
|
|
|
|
} elsif( $m->{NodeType} eq "method" ) {
|
|
|
|
# We generate a method entry only if the method is in the switch() code
|
|
# BUT: for pure virtuals, they need to have a method entry, even though they
|
|
# do NOT have a switch code.
|
|
return if ( $m->{SkipFromSwitch} && $m->{Flags} !~ "p" );
|
|
|
|
# No switch code for destructors if we didn't derive from the class (e.g. it has private ctors only)
|
|
return if ( $m->{ReturnType} eq '~' && ! ( $classNode->{BindingDerives} and $classNode->{HasPublicDestructor}) );
|
|
|
|
# Is this sorting really important?
|
|
#for my $m (sort {$a->{name} cmp $b->{name}} @{ $self->{$c}{method} }) {
|
|
|
|
my $methName = $m->{astNodeName};
|
|
my $def = $m->{FirstDefaultParam};
|
|
$def = scalar(@{ $m->{ParamList} }) unless defined $def;
|
|
my $last = scalar(@{ $m->{ParamList} }) - 1;
|
|
#print STDERR "writeSmokeDataFile: methods: generating for method $methName, def=$def last=$last\n" if ($debug);
|
|
|
|
while($last >= ($def-1)) {
|
|
last if $last < -1;
|
|
my $args = [ @{ $m->{ParamList} }[0..$last] ];
|
|
my $sig = methodSignature($m, $last);
|
|
#my $methodSig = $classNode->{signature}{$sig}; # Munged signature
|
|
#print STDERR "writeSmokeDataFile: methods: sig=$className\::$sig methodSig=$methodSig\n" if ($debug);
|
|
#my $methodIndex = $methodidx{$methodSig};
|
|
#die "$methodSig" if !defined $methodIndex;
|
|
|
|
my $methodIndex = $methodidx{$methName};
|
|
die "$methName" if !defined $methodIndex;
|
|
my $case = $classNode->{case}{$sig};
|
|
my $typeEntry = findTypeEntry( $m->{ReturnType} );
|
|
my $retTypeIndex = defined $typeEntry ? $typeEntry->{index} : 0;
|
|
|
|
my $i = 0;
|
|
my $t = '';
|
|
for my $arg (@$args) {
|
|
$t .= ', ' if $i++;
|
|
my $typeEntry = findTypeEntry( $arg->{ArgType} );
|
|
$t .= defined $typeEntry ? $typeEntry->{index} : 0;
|
|
}
|
|
my $arglist = $t eq '' ? 0 : $arglist{$t};
|
|
die "arglist for $t not found" unless defined $arglist;
|
|
if ( $m->{Flags} =~ "p" ) {
|
|
# Pure virtuals don't have a {case} number, that's normal
|
|
die if defined $case;
|
|
$case = -1; # This remains -1, not 0 !
|
|
} else {
|
|
;
|
|
# die "$className\::$methName has no case number for sig=$sig" unless defined $case;
|
|
}
|
|
my $argcnt = $last + 1;
|
|
my $methodFlags = '0';
|
|
$methodFlags .= "|Smoke::mf_static" if $m->{Flags} =~ "s";
|
|
$methodFlags .= "|Smoke::mf_const" if $m->{Flags} =~ "c"; # useful?? probably not
|
|
$methodFlags =~ s/0\|//; # beautify
|
|
|
|
# print OUT "\t{$classIndex, $methodIndex, $arglist, $argcnt, $methodFlags, $retTypeIndex, $case},\t//$methodCount $className\::$sig";
|
|
# print OUT " [pure virtual]" if ( $m->{Flags} =~ "p" ); # explain why $case = -1 ;)
|
|
# print OUT "\n";
|
|
|
|
$allMethods{$className . "::" . $sig} = $methodCount;
|
|
$methods[$methodCount] = {
|
|
c => $classIndex,
|
|
methIndex => $methodIndex,
|
|
argcnt => $argcnt,
|
|
args => $arglist,
|
|
retTypeIndex => $retTypeIndex,
|
|
idx => $case
|
|
};
|
|
$methodCount++;
|
|
$last--;
|
|
} # while
|
|
} # if method
|
|
} ); # Method Iter
|
|
} ); # Class Iter
|
|
# print OUT "};\n\n";
|
|
|
|
my @protos;
|
|
Iter::LocalCompounds( $rootnode, sub {
|
|
my $classNode = shift;
|
|
my $className = join( "::", kdocAstUtil::heritage($classNode) );
|
|
|
|
return if $classNode->{NodeType} eq 'namespace';
|
|
|
|
my $classIndex = $classidx{$className};
|
|
print STDERR "writeSmokeDataFile: protos: looking at $className\n" if ($debug);
|
|
|
|
Iter::MembersByType ( $classNode, undef,
|
|
sub { my ($classNode, $m ) = @_;
|
|
|
|
if( $m->{NodeType} eq "enum" ) {
|
|
foreach my $enum ( @{$m->{ParamList}} ) {
|
|
my $enumName = $enum->{ArgName};
|
|
my $sig = "$className\::$enumName\()";
|
|
my $xmeth = $allMethods{$sig};
|
|
die "'Method' for enum $sig not found" unless defined $xmeth;
|
|
my $xmethIndex = $methodidx{$enumName};
|
|
die "'Method index' for enum $enumName not found" unless defined $xmethIndex;
|
|
push @protos, {
|
|
methIndex => $xmethIndex,
|
|
c => $classIndex,
|
|
over => {
|
|
$sig => {
|
|
sig => $sig,
|
|
}
|
|
},
|
|
meth => $xmeth
|
|
};
|
|
}
|
|
|
|
} elsif( $m->{NodeType} eq 'var' ) {
|
|
|
|
my $name = $m->{astNodeName};
|
|
my $fullName = "$className\::$name";
|
|
my $sig = "$fullName\()";
|
|
my $xmeth = $allMethods{$sig};
|
|
die "'Method' for var $sig not found" unless defined $xmeth;
|
|
my $xmethIndex = $methodidx{$name};
|
|
die "'Method index' for var $name not found" unless defined $xmethIndex;
|
|
push @protos, {
|
|
methIndex => $xmethIndex,
|
|
c => $classIndex,
|
|
over => {
|
|
$sig => {
|
|
sig => $sig,
|
|
}
|
|
},
|
|
meth => $xmeth
|
|
};
|
|
|
|
}
|
|
});
|
|
|
|
for my $p (keys %{ $classNode->{proto} }) {
|
|
# For each prototype
|
|
my $scratch = { %{ $classNode->{proto}{$p} } }; # sig->method association
|
|
# first, grab all the superclass voodoo
|
|
for my $supNode (superclass_list($classNode)) {
|
|
my $i = $supNode->{proto}{$p};
|
|
next unless $i;
|
|
for my $k (keys %$i) {
|
|
$scratch->{$k} = $i->{$k} unless exists $scratch->{$k};
|
|
}
|
|
}
|
|
|
|
# Ok, now we have a full list
|
|
#if(scalar keys %$scratch > 1) {
|
|
#print STDERR "Overload: $p (@{[keys %$scratch]})\n" if ($debug);
|
|
#}
|
|
my $xmethIndex = $methodidx{$p};
|
|
my $classIndex = $classidx{$className};
|
|
for my $sig (keys %$scratch) {
|
|
#my $xsig = $scratch->{$sig}{class} . "::" . $sig;
|
|
my $xsig = $className . "::" . $sig;
|
|
$scratch->{$sig}{sig} = $xsig;
|
|
delete $scratch->{$sig}
|
|
if $scratch->{$sig}{Flags} =~ "p" # pure virtual
|
|
or not exists $allMethods{$xsig};
|
|
}
|
|
push @protos, {
|
|
methIndex => $xmethIndex,
|
|
c => $classIndex,
|
|
over => $scratch
|
|
} if scalar keys %$scratch;
|
|
}
|
|
});
|
|
|
|
my @protolist = sort { $a->{c} <=> $b->{c} || $a->{methIndex} <=> $b->{methIndex} } @protos;
|
|
#for my $abc (@protos) {
|
|
#print "$abc->{methIndex}.$abc->{c}\n";
|
|
#}
|
|
|
|
print STDERR "Writing methodmap table\n" if ($debug);
|
|
my @resolve = ();
|
|
# print OUT "// Class ID, munged name ID (index into methodNames), method def (see methods) if >0 or number of overloads if <0\n";
|
|
my $methodMapCount = 1;
|
|
# print OUT "static Smoke::MethodMap ${libname}_methodMaps[] = {\n";
|
|
# print OUT "\t{ 0, 0, 0 },\t//0 (no method)\n";
|
|
for my $cur (@protolist) {
|
|
if(scalar keys %{ $cur->{over} } > 1) {
|
|
# print OUT "\t{$cur->{c}, $cur->{methIndex}, -@{[1+scalar @resolve]}},\t//$methodMapCount $classlist[$cur->{c}]\::$methodlist[$cur->{methIndex}]\n";
|
|
$methodMapCount++;
|
|
for my $k (keys %{ $cur->{over} }) {
|
|
my $p = $cur->{over}{$k};
|
|
my $xsig = $p->{class} ? "$p->{class}\::$k" : $p->{sig};
|
|
push @resolve, { k => $k, p => $p, cur => $cur, id => $allMethods{$xsig} };
|
|
}
|
|
push @resolve, 0;
|
|
} else {
|
|
for my $k (keys %{ $cur->{over} }) {
|
|
my $p = $cur->{over}{$k};
|
|
my $xsig = $p->{class} ? "$p->{class}\::$k" : $p->{sig};
|
|
# print OUT "\t{$cur->{c}, $cur->{methIndex}, $allMethods{$xsig}},\t//$methodMapCount $classlist[$cur->{c}]\::$methodlist[$cur->{methIndex}]\n";
|
|
$methodMapCount++;
|
|
}
|
|
}
|
|
}
|
|
# print OUT "};\n\n";
|
|
|
|
|
|
print STDERR "Writing ambiguousMethodList\n" if ($debug);
|
|
# print OUT "static Smoke::Index ${libname}_ambiguousMethodList[] = {\n";
|
|
# print OUT " 0,\n";
|
|
for my $r (@resolve) {
|
|
unless($r) {
|
|
# print OUT " 0,\n";
|
|
next;
|
|
}
|
|
my $xsig = $r->{p}{class} ? "$r->{p}{class}\::$r->{k}" : $r->{p}{sig};
|
|
die "ambiguousMethodList: no method found for $xsig\n" if !defined $allMethods{$xsig};
|
|
# print OUT " $allMethods{$xsig}, // $xsig\n";
|
|
}
|
|
# print OUT "};\n\n";
|
|
|
|
# print OUT "extern \"C\" { // needed?\n";
|
|
# print OUT " void init_${libname}_Smoke();\n";
|
|
# print OUT "}\n";
|
|
# print OUT "\n";
|
|
# print OUT "Smoke* qt_Smoke = 0L;\n";
|
|
# print OUT "\n";
|
|
# print OUT "// Create the Smoke instance encapsulating all the above.\n";
|
|
# print OUT "void init_${libname}_Smoke() {\n";
|
|
# print OUT " qt_Smoke = new Smoke(\n";
|
|
# print OUT " ${libname}_classes, ".$#classlist.",\n";
|
|
# print OUT " ${libname}_methods, $methodCount,\n";
|
|
# print OUT " ${libname}_methodMaps, $methodMapCount,\n";
|
|
# print OUT " ${libname}_methodNames, $methodNameCount,\n";
|
|
# print OUT " ${libname}_types, $typeCount,\n";
|
|
# print OUT " ${libname}_inheritanceList,\n";
|
|
# print OUT " ${libname}_argumentList,\n";
|
|
# print OUT " ${libname}_ambiguousMethodList,\n";
|
|
# print OUT " ${libname}_cast );\n";
|
|
# print OUT "}\n";
|
|
# close OUT;
|
|
|
|
#print "@{[keys %allMethods ]}\n";
|
|
}
|
|
=head2 printCSharpdocComment
|
|
|
|
Parameters: docnode filehandle
|
|
|
|
Converts a kdoc comment to csharpdoc format.
|
|
@ref's are converted to <see>'s; @p's and @em's are converted
|
|
to inline HTML.
|
|
|
|
=cut
|
|
|
|
sub printCSharpdocComment($$$$)
|
|
{
|
|
my( $docnode, $name, $indent, $signalLink ) = @_;
|
|
|
|
my $node;
|
|
my $returntext = '<remarks>';
|
|
foreach $node ( @{$docnode->{Text}} ) {
|
|
next if $node->{NodeType} ne "DocText" and $node->{NodeType} ne "ListItem"
|
|
and $node->{NodeType} ne "Param";
|
|
my $line = '';
|
|
|
|
if ($node->{NodeType} eq "Param") {
|
|
if ($node->{Name} !~ /argc/) {
|
|
$line = "<param> name=\"" . $node->{Name} . "\" " . $node->{astNodeName} . "</param>";
|
|
}
|
|
} else {
|
|
$line = $node->{astNodeName};
|
|
}
|
|
$line =~ s/argc, ?argv/args/g;
|
|
$line =~ s/int argc, ?char ?\* ?argv(\[\])?/string[] args/g;
|
|
$line =~ s/int argc, ?char ?\*\* ?argv/string[] args/g;
|
|
if ($node->{NodeType} eq "Param") {
|
|
$line =~ s/(const )?QC?StringList(\s*&)?/string[]/g;
|
|
} else {
|
|
$line =~ s/(const )?QC?StringList(\s*&)?/ArrayList/g;
|
|
}
|
|
$line =~ s/NodeList|KTrader::OfferList/ArrayList/g;
|
|
$line =~ s/(const )?TQDate(Time)?(\s*&)?/DateTime/g;
|
|
$line =~ s/(const )?TQTime([^r])/DateTime$1/g;
|
|
$line =~ s/TQString::null/null/g;
|
|
$line =~ s/(const )?QC?String(\s*&)?/string/g;
|
|
$line =~ s/(const )?KCmdLineOptions\s*(\w+)\[\]/string[][] $2/;
|
|
$line =~ s/KCmdLineLastOption//g;
|
|
$line =~ s/virtual //g;
|
|
$line =~ s/~\w+\(\)((\s*{\s*})|;)//g;
|
|
$line =~ s/0L/null/g;
|
|
$line =~ s/(\([^\)]*\))\s*:\s*\w+\([^\)]*\)/$1/g;
|
|
$line =~ s/\(void\)//g;
|
|
$line =~ s/const char/string/g;
|
|
$line =~ s/const (\w+)\&/$1/g;
|
|
$line =~ s/bool/bool/g;
|
|
$line =~ s/SLOT\(\s*([^\)]*)\) ?\)/SLOT("$1)")/g;
|
|
$line =~ s/SIGNAL\(\s*([^\)]*)\) ?\)/SIGNAL("$1)")/g;
|
|
$line =~ s/Q_OBJECT\n//g;
|
|
$line =~ s/public\s*(slots)?:\n/public /g;
|
|
$line =~ s/([^0-9"]\s*)\*(\s*[^0-9"-])/$1$2/g;
|
|
$line =~ s/^(\s*)\*/$1/g;
|
|
$line =~ s/\n \*/\n /g;
|
|
$line =~ s!\@ref\s+([\w]+)::([\w]+)\s*(\([^\)]*\))(\.)?!<see cref=\"$1#$2\"></see>$4!g;
|
|
$line =~ s!\@ref\s+#([\w:]+)(\(\))?!<see cref=\"#$1\"</see>!g;
|
|
$line =~ s!\@ref\s+([\w]+)\s*(\([^\)]*\))!<see cref=\"#$1\"></see>!g;
|
|
$line =~ s!\@ref\s+([\w]+)::([\w]+)!<see cref=\"$1#$2\"></see>!g;
|
|
$line =~ s!\@ref\s+([a-z][\w]+)!<see cref=\"#$1\"></see>!g;
|
|
$line =~ s!\@ref\s+([\w]+)!<see cref=\"$1\"></see>!g;
|
|
while ($line =~ /\@c\s+([\w#\\\.<>]+)/ ) {
|
|
my $code = $1;
|
|
$code =~ s!<!<!g;
|
|
$code =~ s!>!>!g;
|
|
$code =~ s!\\#!#!g;
|
|
$line =~ s!\@c\s+([\w#\\\.<>]+)!<code>$code</code>!;
|
|
}
|
|
$line =~ s!\@em\s+(\w+)!<b>$1</b>!g;
|
|
$line =~ s!\@p\s+([\w\._]*)!<code>$1</code>!g;
|
|
$line =~ s!\\paragraph\s+[\w]+\s([\w]+)!<li><b>$1</b></li>!g;
|
|
$line =~ s!\\b\s+([\w -]+)\\n!<li><b>$1</b></li>!g;
|
|
$line =~ s!\\c\s+([\w\@&\\?;-]+)!<code>$1</code>!g;
|
|
$line =~ s!\\p\s+([\w\@]+)!<pre>$1</pre>!g;
|
|
$line =~ s!\\li\s+([\w\@]+)!<li>$1</li>!g;
|
|
$line =~ s!<b>([\w\t \(\)-]*:?)</b>\\n!<li><b>$1</b></li>!g;
|
|
$line =~ s!static_cast<\s*([\w\.]*)\s*>!($1)!g;
|
|
# if ($name ne "") {
|
|
# $line =~ s/\@link #/\@link $name\#/g;
|
|
# }
|
|
|
|
if ($node->{NodeType} eq "ListItem") {
|
|
$line =~ s/^/\n<li>\n/;
|
|
$line =~ s!$!\n</li>!;
|
|
# $line =~ s/\n/\n$indent\t/g;
|
|
} else {
|
|
# $line =~ s/^/$indent/;
|
|
# $line =~ s/\n/\n$indent/g;
|
|
}
|
|
|
|
# $line =~ s/\n/\n$indent/g;
|
|
$returntext .= $line;
|
|
}
|
|
|
|
$returntext .= "$signalLink</remarks>";
|
|
|
|
if ( defined $docnode->{Returns} ) {
|
|
my $text = $docnode->{Returns};
|
|
$text =~ s/TQString::null/null/g;
|
|
$returntext .= "\t\t<return> $text</return>\n";
|
|
}
|
|
|
|
if ( defined $docnode->{Author} ) {
|
|
$returntext .= "\t\t<author> " . $docnode->{Author} . "</author>\n"
|
|
}
|
|
|
|
if ( defined $docnode->{Version} ) {
|
|
my $versionStr = $docnode->{Version};
|
|
$versionStr =~ s/\$\s*Id:([^\$]*) Exp \$/$1/;
|
|
$returntext .= "\t\t<version> $versionStr</version>\n";
|
|
}
|
|
|
|
if ( defined $docnode->{ClassShort} ) {
|
|
my $shortText = $docnode->{ClassShort};
|
|
$shortText =~ s![\*\n]! !g;
|
|
$returntext .= "\t\t<short> $shortText</short>\n";
|
|
}
|
|
|
|
if ( defined $docnode->{See} ) {
|
|
foreach my $text ( @{$docnode->{See}} ) {
|
|
next if ($text =~ /TQString|^\s*and\s*$|^\s*$|^[^\w]*$/);
|
|
$text =~ s/KIO:://g;
|
|
$text =~ s/KParts:://g;
|
|
while ($text =~ /((::)|(->))(.)/) {
|
|
my $temp = uc($4);
|
|
$text =~ s/$1$4/.$temp/;
|
|
}
|
|
$text =~ s/\(\)//g;
|
|
$text =~ s/^\s*([a-z].*)/$1/g;
|
|
$returntext .= "\t\t<see> $text</see>\n";
|
|
}
|
|
}
|
|
|
|
$returntext =~ s/DOM#([A-Z])/$1/g;
|
|
$returntext =~ s/KIO#([A-Z])/$1/g;
|
|
$returntext =~ s/KParts#([A-Z])/$1/g;
|
|
$returntext =~ s/const\s+(\w+)\s*\&/$1/g;
|
|
$returntext =~ s/TQChar/char/g;
|
|
$returntext =~ s/TQStringList/ArrayList/g;
|
|
$returntext =~ s/([Aa]) ArrayList/$1n ArrayList/g;
|
|
$returntext =~ s/TQString/string/g;
|
|
$returntext =~ s/KCmdLineOptions/string[][]/;
|
|
$returntext =~ s!\\note!<b>Note:<\b>!g;
|
|
$returntext =~ s!\\(code|verbatim)!<pre>!g;
|
|
$returntext =~ s!\\(endcode|endverbatim)!</pre>!g;
|
|
$returntext =~ s!\\addtogroup\s+[\w]+\s+"([^"\@]+)"\s+\@{!<li><b>$1</b></li>!g;
|
|
$returntext =~ s![\\\@]relates\s+([a-z][\w]*)!<see cref=\"$1\"></see>!g;
|
|
$returntext =~ s![\\\@]relates\s+(\w+)::(\w+)!<see cref=\"$1.$2\"></see>!g;
|
|
$returntext =~ s![\\\@]relates\s+(#?\w+)!<see cref=\"$1\"></see>!g;
|
|
$returntext =~ s!\\c\s+([\w\@&\\?";-]+)!<code>$1</code>!g;
|
|
$returntext =~ s!\@p\s+([\w\._]*)!<code>$1</code>!g;
|
|
$returntext =~ s!\@a\s+([:\w]+)!<b>$1</b>!g;
|
|
$returntext =~ s![\@\\]b\s+[:\w]!<b>$1</b>!g;
|
|
$returntext =~ s/};/}/g;
|
|
|
|
while ($returntext =~ /((::)|(->))(.)/) {
|
|
my $temp = uc($4);
|
|
$returntext =~ s/$1$4/.$temp/;
|
|
}
|
|
|
|
$returntext =~ s/\s*$//;
|
|
if ($returntext =~ /^<remarks>\s*<\/remarks>$/) {
|
|
return "";
|
|
} else {
|
|
$returntext =~ s/\n/\n$indent/g;
|
|
$returntext =~ s/^/$indent/;
|
|
return $returntext . "\n";
|
|
}
|
|
}
|
|
|
|
1;
|