aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2009-08-17 17:32:08 -0300
committerHugo Lima <hugo.lima@openbossa.org>2009-08-17 17:32:08 -0300
commit9732e0c744e45a67094fc6ce08bdadb1f9a08d4a (patch)
tree566e389f406515b040317bffa075f4e5021020f7
The genesis...
-rw-r--r--.gitignore4
-rw-r--r--AUTHORS8
-rw-r--r--CMakeLists.txt122
-rw-r--r--COPYING342
-rw-r--r--Doxyfile311
-rw-r--r--FindApiExtractor.cmake.in15
-rw-r--r--abstractmetabuilder.cpp2556
-rw-r--r--abstractmetabuilder.h225
-rw-r--r--abstractmetalang.cpp2175
-rw-r--r--abstractmetalang.h1874
-rw-r--r--apiextractor.cpp307
-rw-r--r--apiextractor.h63
-rw-r--r--apiextractor.pc.in11
-rw-r--r--apiextractorversion.h.in4
-rw-r--r--asttoxml.cpp151
-rw-r--r--asttoxml.h40
-rw-r--r--cmake_uninstall.cmake21
-rw-r--r--doc/Makefile88
-rw-r--r--doc/_static/.gitignore0
-rw-r--r--doc/_static/basic.css417
-rw-r--r--doc/_static/default.css248
-rwxr-xr-xdoc/_static/images/._background_search.jpgbin0 -> 4096 bytes
-rwxr-xr-xdoc/_static/images/._bread_crumb.pngbin0 -> 4096 bytes
-rwxr-xr-xdoc/_static/images/._button_search.jpgbin0 -> 4096 bytes
-rwxr-xr-xdoc/_static/images/._side_background.jpgbin0 -> 25192 bytes
-rwxr-xr-xdoc/_static/images/._top_background.jpgbin0 -> 4096 bytes
-rw-r--r--doc/_static/images/background_search.jpgbin0 -> 2129 bytes
-rw-r--r--doc/_static/images/bg.jpgbin0 -> 5749 bytes
-rw-r--r--doc/_static/images/bread_crumb.pngbin0 -> 743 bytes
-rw-r--r--doc/_static/images/button_search.pngbin0 -> 3259 bytes
-rw-r--r--doc/_static/images/side_background.jpgbin0 -> 13760 bytes
-rw-r--r--doc/_static/images/top_background.jpgbin0 -> 500 bytes
-rw-r--r--doc/_templates/index.html26
-rw-r--r--doc/_templates/layout.html34
-rw-r--r--doc/conf.py195
-rw-r--r--doc/contents.rst8
-rw-r--r--doc/dependency-apiextractor.svg360
-rw-r--r--doc/overview.rst15
-rw-r--r--doc/typesystem.rst810
-rw-r--r--docparser.cpp152
-rw-r--r--docparser.h109
-rw-r--r--doxygenparser.cpp151
-rw-r--r--doxygenparser.h37
-rw-r--r--fileout.cpp218
-rw-r--r--fileout.h58
-rw-r--r--generator.cpp146
-rw-r--r--generator.h358
-rw-r--r--generator.qrc5
-rw-r--r--merge.xsl82
-rw-r--r--parser/ast.cpp33
-rw-r--r--parser/ast.h879
-rw-r--r--parser/binder.cpp852
-rw-r--r--parser/binder.h125
-rw-r--r--parser/class_compiler.cpp66
-rw-r--r--parser/class_compiler.h72
-rw-r--r--parser/codemodel.cpp932
-rw-r--r--parser/codemodel.h838
-rw-r--r--parser/codemodel_finder.cpp98
-rw-r--r--parser/codemodel_finder.h70
-rw-r--r--parser/codemodel_fwd.h80
-rw-r--r--parser/codemodel_pointer.h60
-rw-r--r--parser/compiler_utils.cpp50
-rw-r--r--parser/compiler_utils.h47
-rw-r--r--parser/control.cpp130
-rw-r--r--parser/control.h160
-rw-r--r--parser/declarator_compiler.cpp147
-rw-r--r--parser/declarator_compiler.h96
-rw-r--r--parser/default_visitor.cpp459
-rw-r--r--parser/default_visitor.h118
-rw-r--r--parser/dumptree.cpp125
-rw-r--r--parser/dumptree.h46
-rw-r--r--parser/lexer.cpp1695
-rw-r--r--parser/lexer.h290
-rw-r--r--parser/list.cpp28
-rw-r--r--parser/list.h100
-rw-r--r--parser/name_compiler.cpp134
-rw-r--r--parser/name_compiler.h69
-rw-r--r--parser/parser.cpp4056
-rw-r--r--parser/parser.h198
-rw-r--r--parser/r++.macros28
-rw-r--r--parser/rpp-allocator.h24
-rw-r--r--parser/rpp/builtin-macros.cpp23
-rw-r--r--parser/rpp/pp-cctype.h57
-rw-r--r--parser/rpp/pp-configuration86
-rw-r--r--parser/rpp/pp-engine-bits.h1252
-rw-r--r--parser/rpp/pp-engine.h274
-rw-r--r--parser/rpp/pp-environment.h137
-rw-r--r--parser/rpp/pp-fwd.h39
-rw-r--r--parser/rpp/pp-internal.h117
-rw-r--r--parser/rpp/pp-iterator.h88
-rw-r--r--parser/rpp/pp-macro-expander.h351
-rw-r--r--parser/rpp/pp-macro.h72
-rw-r--r--parser/rpp/pp-main.cpp295
-rw-r--r--parser/rpp/pp-qt-configuration24
-rw-r--r--parser/rpp/pp-scanner.h313
-rw-r--r--parser/rpp/pp-string.h107
-rw-r--r--parser/rpp/pp-symbol.h87
-rw-r--r--parser/rpp/pp.h91
-rw-r--r--parser/rpp/preprocessor.cpp158
-rw-r--r--parser/rpp/preprocessor.h66
-rw-r--r--parser/rxx_allocator.h130
-rw-r--r--parser/smallobject.cpp28
-rw-r--r--parser/smallobject.h47
-rw-r--r--parser/symbol.h122
-rw-r--r--parser/tokens.cpp249
-rw-r--r--parser/tokens.h145
-rw-r--r--parser/type_compiler.cpp129
-rw-r--r--parser/type_compiler.h71
-rw-r--r--parser/visitor.cpp122
-rw-r--r--parser/visitor.h140
-rw-r--r--qtdocparser.cpp156
-rw-r--r--qtdocparser.h38
-rw-r--r--reporthandler.cpp100
-rw-r--r--reporthandler.h154
-rw-r--r--tests/CMakeLists.txt6
-rw-r--r--tests/testabstractmetaclass.cpp86
-rw-r--r--tests/testabstractmetaclass.h47
-rw-r--r--typeparser.cpp261
-rw-r--r--typeparser.h52
-rw-r--r--typesystem.cpp2085
-rw-r--r--typesystem.h1958
121 files changed, 33614 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..4ef169adc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+build
+.kdev4
+
+apiextractor.kdev4
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 000000000..6e802fb53
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,8 @@
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruno Araujo <bruno.araujo@openbossa.org>
+Hugo Parente Lima <hugo.lima@openbossa.org>
+Lauro Moura <lauro.neto@openbossa.org>
+Luciano Wolf <luciano.wolf@openbossa.org>
+Marcelo Lira <marcelo.lira@openbossa.org>
+Renato Araujo Oliveira Filho <renato.filho@openbossa.org>
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..a02f37db7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,122 @@
+project(apiextractor)
+
+cmake_minimum_required(VERSION 2.6)
+
+find_package(Boost COMPONENTS graph REQUIRED)
+find_package(Qt4 4.5.0 REQUIRED)
+find_package(PkgConfig)
+pkg_check_modules(LIBXML2 REQUIRED libxml-2.0>=2.6.32)
+pkg_check_modules(LIBXSLT REQUIRED libxslt>=1.1.19)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -DAPIEXTRACTOR_ENABLE_DUPLICATE_ENUM_VALUES")
+
+set(apiextractor_VERSION 0.1)
+configure_file(apiextractorversion.h.in ${CMAKE_CURRENT_BINARY_DIR}/apiextractorversion.h @ONLY)
+set(QT_USE_QTCORE 1)
+set(QT_USE_QTXML 1)
+include(${QT_USE_FILE})
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+add_definitions(-DRXX_ALLOCATOR_INIT_0)
+
+set(CMAKE_BUILD_TYPE Debug)
+
+set(apiextractor_SRC
+apiextractor.cpp
+abstractmetabuilder.cpp
+abstractmetalang.cpp
+asttoxml.cpp
+docparser.cpp
+doxygenparser.cpp
+qtdocparser.cpp
+fileout.cpp
+generator.cpp
+reporthandler.cpp
+typeparser.cpp
+typesystem.cpp
+parser/ast.cpp
+parser/binder.cpp
+parser/class_compiler.cpp
+parser/codemodel.cpp
+parser/codemodel_finder.cpp
+parser/compiler_utils.cpp
+parser/control.cpp
+parser/declarator_compiler.cpp
+parser/default_visitor.cpp
+parser/dumptree.cpp
+parser/lexer.cpp
+parser/list.cpp
+parser/name_compiler.cpp
+parser/parser.cpp
+parser/smallobject.cpp
+parser/tokens.cpp
+parser/type_compiler.cpp
+parser/visitor.cpp
+parser/rpp/builtin-macros.cpp
+parser/rpp/pp-main.cpp
+parser/rpp/preprocessor.cpp
+)
+
+qt4_add_resources(apiextractor_RCCS_SRC generator.qrc)
+
+set(apiextractor_MOC_HEADERS
+ fileout.h
+ generator.h
+)
+
+qt4_wrap_cpp(apiextractor_MOC_SRC ${apiextractor_MOC_HEADERS})
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/parser
+ ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp
+ ${QT_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
+ ${LIBXSLT_INCLUDE_DIRS}
+ ${LIBXML2_INCLUDE_DIRS}
+ )
+
+add_library(apiextractor SHARED ${apiextractor_SRC} ${apiextractor_MOC_SRC} ${apiextractor_RCCS_SRC})
+target_link_libraries(apiextractor ${Boost_GRAPH_LIBRARY} ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTXMLPATTERNS_LIBRARY} ${QT_QTXML_LIBRARY})
+set_target_properties(apiextractor PROPERTIES SOVERSION ${apiextractor_VERSION})
+
+# create pkg-config file
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/apiextractor.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/apiextractor.pc @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/FindApiExtractor.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindApiExtractor.cmake @ONLY)
+
+# uninstall target
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
+add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
+# "make dist", in fact "make package_source"
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "libapiextractor-${apiextractor_VERSION}")
+set(CPACK_SOURCE_GENERATOR TGZ)
+set(CPACK_SOURCE_IGNORE_FILES "~$" ".svn" "debian/" "build/" ".swp$" "*.kdev4")
+include(CPack)
+
+set(root_HEADERS
+abstractmetalang.h
+generator.h
+apiextractor.h
+reporthandler.h
+typesystem.h
+fileout.h
+docparser.h
+qtdocparser.h
+)
+
+enable_testing()
+add_subdirectory(tests)
+
+install(FILES ${root_HEADERS} DESTINATION include/apiextractor)
+# TODO We do not need to expose these internal headers!
+# install(DIRECTORY parser DESTINATION include/apiextractor
+# FILES_MATCHING PATTERN "*.h"
+# PATTERN ".svn" EXCLUDE
+# )
+install(TARGETS apiextractor LIBRARY DESTINATION lib)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/apiextractor.pc DESTINATION lib/pkgconfig)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindApiExtractor.cmake
+ DESTINATION share/cmake-2.6/Modules)
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..4ccd71466
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,342 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 000000000..ebc397fb9
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,311 @@
+# Doxyfile 1.5.7.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = libgenerator
+PROJECT_NUMBER = 0.1
+OUTPUT_DIRECTORY = /tmp/src/libgenerator/doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = /tmp/src/libgenerator/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+TYPEDEF_HIDES_STRUCT = NO
+SYMBOL_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /tmp/src/libgenerator
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY \
+ *.F90 \
+ *.F \
+ *.VHD \
+ *.VHDL
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 4
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+HTML_DYNAMIC_SECTIONS = NO
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHG_LOCATION =
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NONE
+TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES = qt4.tag=http://doc.trolltech.com/latest
+GENERATE_TAGFILE = libgenerator.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+DOT_FONTNAME = FreeSans
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/FindApiExtractor.cmake.in b/FindApiExtractor.cmake.in
new file mode 100644
index 000000000..addbca36d
--- /dev/null
+++ b/FindApiExtractor.cmake.in
@@ -0,0 +1,15 @@
+# - try to find APIEXTRACTOR
+# APIEXTRACTOR_INCLUDE_DIR - Directories to include to use APIEXTRACTOR
+# APIEXTRACTOR_LIBRARIES - Files to link against to use APIEXTRACTOR
+# APIEXTRACTOR_FOUND - APIEXTRACTOR was found
+
+FIND_PATH(APIEXTRACTOR_INCLUDE_DIR apiextractor.h @CMAKE_INSTALL_PREFIX@/include/apiextractor)
+
+FIND_LIBRARY(APIEXTRACTOR_LIBRARY apiextractor @CMAKE_INSTALL_PREFIX@/lib)
+
+SET(APIEXTRACTOR_FOUND "NO")
+IF(APIEXTRACTOR_LIBRARY AND APIEXTRACTOR_INCLUDE_DIR)
+ SET(APIEXTRACTOR_FOUND "YES")
+ENDIF(APIEXTRACTOR_LIBRARY AND APIEXTRACTOR_INCLUDE_DIR)
+
+
diff --git a/abstractmetabuilder.cpp b/abstractmetabuilder.cpp
new file mode 100644
index 000000000..48fc13c23
--- /dev/null
+++ b/abstractmetabuilder.cpp
@@ -0,0 +1,2556 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "abstractmetabuilder.h"
+#include "reporthandler.h"
+
+#include "parser/ast.h"
+#include "parser/binder.h"
+#include "parser/control.h"
+#include "parser/default_visitor.h"
+#include "parser/dumptree.h"
+#include "parser/lexer.h"
+#include "parser/parser.h"
+#include "parser/tokens.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextCodec>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QTime>
+#include <QtCore/QQueue>
+
+// boost graph library
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/graph_traits.hpp>
+
+#include <cstdio>
+
+static QString stripTemplateArgs(const QString &name)
+{
+ int pos = name.indexOf('<');
+ return pos < 0 ? name : name.left(pos);
+}
+
+AbstractMetaBuilder::AbstractMetaBuilder() : m_currentClass(0)
+{
+}
+
+AbstractMetaBuilder::~AbstractMetaBuilder()
+{
+ qDeleteAll(m_globalFunctions);
+}
+
+void AbstractMetaBuilder::checkFunctionModifications()
+{
+ TypeDatabase *types = TypeDatabase::instance();
+ SingleTypeEntryHash entryHash = types->entries();
+ QList<TypeEntry *> entries = entryHash.values();
+ foreach (TypeEntry *entry, entries) {
+ if (!entry)
+ continue;
+ if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing)
+ continue;
+
+ ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(entry);
+ FunctionModificationList modifications = centry->functionModifications();
+
+ foreach (FunctionModification modification, modifications) {
+ QString signature = modification.signature;
+
+ QString name = signature.trimmed();
+ name = name.mid(0, signature.indexOf("("));
+
+ AbstractMetaClass *clazz = m_metaClasses.findClass(centry->qualifiedCppName());
+ if (!clazz)
+ continue;
+
+ AbstractMetaFunctionList functions = clazz->functions();
+ bool found = false;
+ QStringList possibleSignatures;
+ foreach (AbstractMetaFunction *function, functions) {
+ if (function->minimalSignature() == signature && function->implementingClass() == clazz) {
+ found = true;
+ break;
+ }
+
+ if (function->originalName() == name)
+ possibleSignatures.append(function->minimalSignature() + " in " + function->implementingClass()->name());
+ }
+
+ if (!found) {
+ QString warning
+ = QString("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
+ .arg(signature)
+ .arg(clazz->qualifiedCppName())
+ .arg(possibleSignatures.join(", "));
+
+ ReportHandler::warning(warning);
+ }
+ }
+ }
+}
+
+AbstractMetaClass *AbstractMetaBuilder::argumentToClass(ArgumentModelItem argument)
+{
+ AbstractMetaClass *returned = 0;
+ bool ok = false;
+ AbstractMetaType *type = translateType(argument->type(), &ok);
+ if (ok && type && type->typeEntry() && type->typeEntry()->isComplex()) {
+ const TypeEntry *entry = type->typeEntry();
+ returned = m_metaClasses.findClass(entry->name());
+ }
+ delete type;
+ return returned;
+}
+
+/**
+ * Checks the argument of a hash function and flags the type if it is a complex type
+ */
+void AbstractMetaBuilder::registerHashFunction(FunctionModelItem function_item)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 1) {
+ if (AbstractMetaClass *cls = argumentToClass(arguments.at(0)))
+ cls->setHasHashFunction(true);
+ }
+}
+
+/**
+ * Check if a class has a debug stream operator that can be used as toString
+ */
+
+void AbstractMetaBuilder::registerToStringCapability(FunctionModelItem function_item)
+{
+ // TODO This must set an AbstractMetaFunction, not a FunctionModelItem!
+ #if 0
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 2) {
+ if (arguments.at(0)->type().toString() == "QDebug") {
+ ArgumentModelItem arg = arguments.at(1);
+ if (AbstractMetaClass *cls = argumentToClass(arg)) {
+ if (arg->type().indirections() < 2)
+ cls->setToStringCapability(function_item);
+ }
+ }
+ }
+ #endif
+}
+
+void AbstractMetaBuilder::traverseOperatorFunction(FunctionModelItem item)
+{
+ if (item->accessPolicy() != CodeModel::Public)
+ return;
+
+ ArgumentList arguments = item->arguments();
+ AbstractMetaClass *baseoperandClass;
+ bool firstArgumentIsSelf = true;
+ bool unaryOperator = false;
+
+ baseoperandClass = argumentToClass(arguments.at(0));
+ if (arguments.size() == 1) {
+ unaryOperator = true;
+ } else if (!baseoperandClass) {
+ baseoperandClass = argumentToClass(arguments.at(1));
+ firstArgumentIsSelf = false;
+ }
+
+ if (baseoperandClass) {
+ AbstractMetaClass *oldCurrentClass = m_currentClass;
+ m_currentClass = baseoperandClass;
+ AbstractMetaFunction *metaFunction = traverseFunction(item);
+ if (metaFunction && !metaFunction->isInvalid()) {
+ // Strip away first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = metaFunction->arguments();
+ if (firstArgumentIsSelf || unaryOperator) {
+ arguments.pop_front();
+ metaFunction->setArguments(arguments);
+ } else {
+ // If the operator method is not unary and the first operator is
+ // not of the same type of its owning class we suppose that it
+ // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)).
+ // All operator overloads that operate over a class are already
+ // beign added as member functions of that class by the API Extractor,
+ // in addition to this the reverse operators are marked as static
+ // for identification purposes.
+ *metaFunction += AbstractMetaAttributes::Static;
+ }
+ metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction);
+ metaFunction->setVisibility(AbstractMetaFunction::Public);
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ setupFunctionDefaults(metaFunction, baseoperandClass);
+ baseoperandClass->addFunction(metaFunction);
+ Q_ASSERT(!metaFunction->wasPrivate());
+ } else if (metaFunction) {
+ delete metaFunction;
+ }
+
+ m_currentClass = oldCurrentClass;
+ }
+}
+
+void AbstractMetaBuilder::traverseStreamOperator(FunctionModelItem item)
+{
+ ArgumentList arguments = item->arguments();
+ if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
+ AbstractMetaClass *streamClass = argumentToClass(arguments.at(0));
+ AbstractMetaClass *streamedClass = argumentToClass(arguments.at(1));
+
+ if (streamClass && streamedClass
+ && (streamClass->name() == "QDataStream" || streamClass->name() == "QTextStream")) {
+ AbstractMetaClass *oldCurrentClass = m_currentClass;
+ m_currentClass = streamedClass;
+ AbstractMetaFunction *streamFunction = traverseFunction(item);
+
+ if (streamFunction && !streamFunction->isInvalid()) {
+ QString name = item->name();
+ streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
+ // Strip first argument, since that is the containing object
+ //AbstractMetaArgumentList arguments = streamFunction->arguments();
+ //arguments.pop_front();
+ //streamFunction->setArguments(arguments);
+
+ *streamFunction += AbstractMetaAttributes::Final;
+ *streamFunction += AbstractMetaAttributes::Public;
+ streamFunction->setOriginalAttributes(streamFunction->attributes());
+
+// streamFunction->setType(0);
+
+ AbstractMetaClass *funcClass;
+
+ if (!streamClass->typeEntry()->generateCode()) {
+ AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments());
+ streamFunction->setArguments(reverseArgs);
+ streamFunction->setReverseOperator(true);
+ funcClass = streamedClass;
+ } else {
+ funcClass = streamClass;
+ }
+
+ setupFunctionDefaults(streamFunction, funcClass);
+ funcClass->addFunction(streamFunction);
+ if (funcClass == streamClass)
+ funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include());
+ else
+ funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
+
+ m_currentClass = oldCurrentClass;
+ }
+ }
+ }
+}
+
+void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase *types,
+ NamespaceModelItem scope)
+{
+ foreach (ClassModelItem item, scope->classes()) {
+ QString qualifiedName = item->qualifiedName().join("::");
+ TypeEntry *entry = types->findType(qualifiedName);
+ if (entry) {
+ if (isQObject(qualifiedName) && entry->isComplex())
+ ((ComplexTypeEntry *) entry)->setQObject(true);
+ }
+ }
+
+ foreach (NamespaceModelItem item, scope->namespaceMap().values()) {
+ if (scope != item)
+ fixQObjectForScope(types, item);
+ }
+}
+
+void AbstractMetaBuilder::sortLists()
+{
+ foreach (AbstractMetaClass *cls, m_metaClasses)
+ cls->sortFunctions();
+}
+
+bool AbstractMetaBuilder::build(QIODevice* input)
+{
+ Q_ASSERT(input);
+
+ if (!input->isOpen()) {
+ if (!input->open(QIODevice::ReadOnly))
+ return false;
+ }
+
+ QByteArray contents = input->readAll();
+ input->close();
+
+ Control control;
+ Parser p(&control);
+ pool __pool;
+
+ TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
+
+ CodeModel model;
+ Binder binder(&model, p.location());
+ m_dom = binder.run(ast);
+
+ pushScope(model_dynamic_cast<ScopeModelItem>(m_dom));
+
+ QHash<QString, ClassModelItem> typeMap = m_dom->classMap();
+
+ // fix up QObject's in the type system..
+ TypeDatabase *types = TypeDatabase::instance();
+ fixQObjectForScope(types, model_dynamic_cast<NamespaceModelItem>(m_dom));
+
+ // Start the generation...
+ QList<ClassModelItem > typeValues = typeMap.values();
+ ReportHandler::setProgressReference(typeValues);
+ foreach (ClassModelItem item, typeValues) {
+ ReportHandler::progress("Generating class model for %s", qPrintable(item->name()));
+ AbstractMetaClass *cls = traverseClass(item);
+ if (!cls)
+ continue;
+
+ addAbstractMetaClass(cls);
+ }
+
+ // We need to know all global enums
+ QHash<QString, EnumModelItem> enumMap = m_dom->enumMap();
+ ReportHandler::setProgressReference(enumMap);
+ foreach (EnumModelItem item, enumMap) {
+ ReportHandler::progress("Generating enum model for %s", qPrintable(item->name()));
+ AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>());
+ if (metaEnum) {
+ if (metaEnum->typeEntry()->generateCode())
+ m_globalEnums << metaEnum;
+ }
+ }
+
+ QHash<QString, NamespaceModelItem> namespaceMap = m_dom->namespaceMap();
+ ReportHandler::setProgressReference(namespaceMap);
+ foreach (NamespaceModelItem item, namespaceMap.values()) {
+ ReportHandler::progress("Generating namespace model for %s", qPrintable(item->name()));
+ AbstractMetaClass *metaClass = traverseNamespace(item);
+ if (metaClass)
+ m_metaClasses << metaClass;
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = m_dom->typeAliases();
+ ReportHandler::setProgressReference(typeAliases);
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ ReportHandler::progress("Resolving typedefs...");
+ AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
+ addAbstractMetaClass(cls);
+ }
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ foreach (AbstractMetaClass *cls, m_metaClasses) {
+ ReportHandler::progress("Fixing class inheritance...");
+ if (!cls->isInterface() && !cls->isNamespace())
+ setupInheritance(cls);
+ }
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ foreach (AbstractMetaClass *cls, m_metaClasses) {
+ ReportHandler::progress("Detecting inconsistencies in class model for %s", qPrintable(cls->qualifiedCppName()));
+ cls->fixFunctions();
+
+ if (!cls->typeEntry()) {
+ ReportHandler::warning(QString("class '%1' does not have an entry in the type system")
+ .arg(cls->name()));
+ } else {
+ if (!cls->hasConstructors() && !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace())
+ cls->addDefaultConstructor();
+ }
+
+ if (cls->isAbstract() && !cls->isInterface())
+ cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + "$ConcreteWrapper");
+ }
+
+ QList<TypeEntry *> entries = TypeDatabase::instance()->entries().values();
+ ReportHandler::setProgressReference(entries);
+ foreach (const TypeEntry *entry, entries) {
+ ReportHandler::progress("Detecting inconsistencies in typesystem for %s", qPrintable(entry->name()));
+
+ if (entry->isPrimitive())
+ continue;
+
+ if ((entry->isValue() || entry->isObject())
+ && !entry->isString()
+ && !entry->isChar()
+ && !entry->isContainer()
+ && !entry->isCustom()
+ && !entry->isVariant()
+ && !m_metaClasses.findClass(entry->qualifiedCppName())) {
+ ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
+ .arg(entry->qualifiedCppName()));
+ }
+
+ if (entry->isEnum()) {
+ QString pkg = entry->targetLangPackage();
+ QString name = (pkg.isEmpty() ? QString() : pkg + ".")
+ + ((EnumTypeEntry *) entry)->targetLangQualifier();
+ AbstractMetaClass *cls = m_metaClasses.findClass(name);
+
+ if (cls) {
+ AbstractMetaEnum *e = cls->findEnum(entry->targetLangName());
+ if (!e)
+ ReportHandler::warning(QString("enum '%1' is specified in typesystem, "
+ "but not declared")
+ .arg(entry->qualifiedCppName()));
+ }
+ }
+ }
+
+ {
+ FunctionList hashFunctions = m_dom->findFunctions("qHash");
+ foreach (FunctionModelItem item, hashFunctions)
+ registerHashFunction(item);
+ }
+
+ {
+ FunctionList hashFunctions = m_dom->findFunctions("operator<<");
+ foreach (FunctionModelItem item, hashFunctions)
+ registerToStringCapability(item);
+ }
+
+ {
+ FunctionList binaryOperators = m_dom->findFunctions("operator==")
+ + m_dom->findFunctions("operator!=")
+ + m_dom->findFunctions("operator<=")
+ + m_dom->findFunctions("operator>=")
+ + m_dom->findFunctions("operator<")
+ + m_dom->findFunctions("operator+")
+ + m_dom->findFunctions("operator/")
+ + m_dom->findFunctions("operator*")
+ + m_dom->findFunctions("operator-")
+ + m_dom->findFunctions("operator&")
+ + m_dom->findFunctions("operator|")
+ + m_dom->findFunctions("operator^")
+ + m_dom->findFunctions("operator~")
+ + m_dom->findFunctions("operator>");
+
+ foreach (FunctionModelItem item, binaryOperators)
+ traverseOperatorFunction(item);
+ }
+
+ {
+ FunctionList streamOperators = m_dom->findFunctions("operator<<") + m_dom->findFunctions("operator>>");
+ foreach (FunctionModelItem item, streamOperators)
+ traverseStreamOperator(item);
+ }
+
+ figureOutEnumValues();
+ figureOutDefaultEnumArguments();
+ checkFunctionModifications();
+
+ // sort all classes topologically
+ m_metaClasses = classesTopologicalSorted();
+
+ foreach (AbstractMetaClass *cls, m_metaClasses) {
+// setupEquals(cls);
+// setupComparable(cls);
+ setupClonable(cls);
+
+ // sort all inner classes topologically
+ if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2)
+ continue;
+
+ cls->setInnerClasses(classesTopologicalSorted(cls));
+ }
+
+ dumpLog();
+
+ sortLists();
+
+ m_currentClass = 0;
+
+ foreach (FunctionModelItem func, m_dom->functions()) {
+ if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator"))
+ continue;
+
+ AbstractMetaFunction* metaFunc = traverseFunction(func);
+ if (metaFunc) {
+ metaFunc->setIncludeFile(func->fileName());
+ m_globalFunctions << metaFunc;
+ }
+ }
+ std::puts("");
+ return true;
+}
+
+void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls)
+{
+ if (!cls)
+ return;
+
+ cls->setOriginalAttributes(cls->attributes());
+ if (cls->typeEntry()->isContainer()) {
+ m_templates << cls;
+ } else {
+ m_metaClasses << cls;
+ if (cls->typeEntry()->designatedInterface()) {
+ AbstractMetaClass *interface = cls->extractInterface();
+ m_metaClasses << interface;
+ ReportHandler::debugSparse(QString(" -> interface '%1'").arg(interface->name()));
+ }
+ }
+}
+
+AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem namespaceItem)
+{
+ QString namespaceName = (!m_namespacePrefix.isEmpty() ? m_namespacePrefix + "::" : QString()) + namespaceItem->name();
+ NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespaceName);
+
+ if (TypeDatabase::instance()->isClassRejected(namespaceName)) {
+ m_rejectedClasses.insert(namespaceName, GenerationDisabled);
+ return 0;
+ }
+
+ if (!type) {
+ ReportHandler::warning(QString("namespace '%1' does not have a type entry").arg(namespaceName));
+ return 0;
+ }
+
+ AbstractMetaClass *metaClass = createMetaClass();
+ metaClass->setTypeEntry(type);
+
+ *metaClass += AbstractMetaAttributes::Public;
+
+ m_currentClass = metaClass;
+
+ ReportHandler::debugSparse(QString("namespace '%1.%2'")
+ .arg(metaClass->package())
+ .arg(namespaceItem->name()));
+
+ traverseEnums(model_dynamic_cast<ScopeModelItem>(namespaceItem), metaClass, namespaceItem->enumsDeclarations());
+ traverseFunctions(model_dynamic_cast<ScopeModelItem>(namespaceItem), metaClass);
+// traverseClasses(model_dynamic_cast<ScopeModelItem>(namespace_item));
+
+ pushScope(model_dynamic_cast<ScopeModelItem>(namespaceItem));
+ m_namespacePrefix = currentScope()->qualifiedName().join("::");
+
+ ClassList classes = namespaceItem->classes();
+ foreach (ClassModelItem cls, classes) {
+ AbstractMetaClass *mjc = traverseClass(cls);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = namespaceItem->typeAliases();
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
+ if (cls) {
+ metaClass->addInnerClass(cls);
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+ // Traverse namespaces recursively
+ QList<NamespaceModelItem> innerNamespaces = namespaceItem->namespaceMap().values();
+ foreach (const NamespaceModelItem &ni, innerNamespaces) {
+ AbstractMetaClass *mjc = traverseNamespace(ni);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ m_currentClass = 0;
+
+ popScope();
+ m_namespacePrefix = currentScope()->qualifiedName().join("::");
+
+ if (!type->include().isValid()) {
+ QFileInfo info(namespaceItem->fileName());
+ type->setInclude(Include(Include::IncludePath, info.fileName()));
+ }
+
+ return metaClass;
+}
+
+struct Operator
+{
+ enum Type { Plus, ShiftLeft, None };
+
+ Operator() : type(None) {}
+
+ int calculate(int x)
+ {
+ switch (type) {
+ case Plus: return x + value;
+ case ShiftLeft: return x << value;
+ case None: return x;
+ }
+ return x;
+ }
+
+ Type type;
+ int value;
+};
+
+
+
+Operator findOperator(QString *s)
+{
+ const char *names[] = {
+ "+",
+ "<<"
+ };
+
+ for (int i = 0; i < Operator::None; ++i) {
+ QString name = QLatin1String(names[i]);
+ QString str = *s;
+ int splitPoint = str.indexOf(name);
+ if (splitPoint > 0) {
+ bool ok;
+ QString right = str.mid(splitPoint + name.length());
+ Operator op;
+ op.value = right.toInt(&ok);
+ if (ok) {
+ op.type = Operator::Type(i);
+ *s = str.left(splitPoint).trimmed();
+ return op;
+ }
+ }
+ }
+ return Operator();
+}
+
+int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue,
+ int oldValuevalue,
+ AbstractMetaEnum *metaEnum,
+ AbstractMetaFunction *metaFunction)
+{
+ if (stringValue.isEmpty())
+ return oldValuevalue;
+
+ QStringList stringValues = stringValue.split("|");
+
+ int returnValue = 0;
+
+ bool matched = false;
+
+ for (int i = 0; i < stringValues.size(); ++i) {
+ QString s = stringValues.at(i).trimmed();
+
+ bool ok;
+ int v;
+
+ Operator op = findOperator(&s);
+
+ if (s.length() > 0 && s.at(0) == QLatin1Char('0'))
+ v = s.toUInt(&ok, 0);
+ else
+ v = s.toInt(&ok);
+
+ if (ok) {
+ matched = true;
+
+ } else if (m_enumValues.contains(s)) {
+ v = m_enumValues[s]->value();
+ matched = true;
+
+ } else {
+ AbstractMetaEnumValue *ev = 0;
+
+ if (metaEnum && (ev = metaEnum->values().find(s))) {
+ v = ev->value();
+ matched = true;
+
+ } else if (metaEnum && (ev = metaEnum->enclosingClass()->findEnumValue(s, metaEnum))) {
+ v = ev->value();
+ matched = true;
+
+ } else {
+ if (metaEnum)
+ ReportHandler::warning("unhandled enum value: " + s + " in "
+ + metaEnum->enclosingClass()->name() + "::"
+ + metaEnum->name());
+ else
+ ReportHandler::warning("unhandled enum value: Unknown enum");
+ }
+ }
+
+ if (matched)
+ returnValue |= op.calculate(v);
+ }
+
+ if (!matched) {
+ QString warn = QString("unmatched enum %1").arg(stringValue);
+
+ if (metaFunction) {
+ warn += QString(" when parsing default value of '%1' in class '%2'")
+ .arg(metaFunction->name())
+ .arg(metaFunction->implementingClass()->name());
+ }
+
+ ReportHandler::warning(warn);
+ returnValue = oldValuevalue;
+ }
+
+ return returnValue;
+}
+
+void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass *metaClass,
+ QSet<AbstractMetaClass *> *classes)
+{
+ AbstractMetaClass *base = metaClass->baseClass();
+
+ if (base && !classes->contains(base))
+ figureOutEnumValuesForClass(base, classes);
+
+ if (classes->contains(metaClass))
+ return;
+
+ AbstractMetaEnumList enums = metaClass->enums();
+ foreach (AbstractMetaEnum *e, enums) {
+ if (!e) {
+ ReportHandler::warning("bad enum in class " + metaClass->name());
+ continue;
+ }
+ AbstractMetaEnumValueList lst = e->values();
+ int value = 0;
+ for (int i = 0; i < lst.size(); ++i) {
+ value = figureOutEnumValue(lst.at(i)->stringValue(), value, e);
+ lst.at(i)->setValue(value);
+ value++;
+ }
+
+#ifndef APIEXTRACTOR_ENABLE_DUPLICATE_ENUM_VALUES
+ // Check for duplicate values...
+ EnumTypeEntry *ete = e->typeEntry();
+ if (!ete->forceInteger()) {
+ QHash<int, AbstractMetaEnumValue *> entries;
+ foreach (AbstractMetaEnumValue *v, lst) {
+
+ bool vRejected = ete->isEnumValueRejected(v->name());
+
+ AbstractMetaEnumValue *current = entries.value(v->value());
+ if (current) {
+ bool currentRejected = ete->isEnumValueRejected(current->name());
+ if (!currentRejected && !vRejected) {
+ ReportHandler::warning(
+ QString("duplicate enum values: %1::%2, %3 and %4 are %5, already rejected: (%6)")
+ .arg(metaClass->name())
+ .arg(e->name())
+ .arg(v->name())
+ .arg(entries[v->value()]->name())
+ .arg(v->value())
+ .arg(ete->enumValueRejections().join(", ")));
+ continue;
+ }
+ }
+
+ if (!vRejected)
+ entries[v->value()] = v;
+ }
+
+ // Entries now contain all the original entries, no
+ // rejected ones... Use this to generate the enumValueRedirection table.
+ foreach (AbstractMetaEnumValue *reject, lst) {
+ if (!ete->isEnumValueRejected(reject->name()))
+ continue;
+
+ AbstractMetaEnumValue *used = entries.value(reject->value());
+ if (!used) {
+ ReportHandler::warning(
+ QString::fromLatin1("Rejected enum has no alternative...: %1::%2\n")
+ .arg(metaClass->name())
+ .arg(reject->name()));
+ continue;
+ }
+ ete->addEnumValueRedirection(reject->name(), used->name());
+ }
+
+ }
+#endif
+ }
+
+ *classes += metaClass;
+}
+
+
+void AbstractMetaBuilder::figureOutEnumValues()
+{
+ // Keep a set of classes that we already traversed. We use this to
+ // enforce that we traverse base classes prior to subclasses.
+ QSet<AbstractMetaClass *> classes;
+ foreach (AbstractMetaClass *c, m_metaClasses)
+ figureOutEnumValuesForClass(c, &classes);
+}
+
+void AbstractMetaBuilder::figureOutDefaultEnumArguments()
+{
+ foreach (AbstractMetaClass *metaClass, m_metaClasses) {
+ foreach (AbstractMetaFunction *metaFunction, metaClass->functions()) {
+ foreach (AbstractMetaArgument *arg, metaFunction->arguments()) {
+ QString expr = arg->defaultValueExpression();
+ if (expr.isEmpty())
+ continue;
+
+ if (!metaFunction->replacedDefaultExpression(metaFunction->implementingClass(),
+ arg->argumentIndex() + 1).isEmpty()) {
+ continue;
+ }
+
+ arg->setDefaultValueExpression(expr);
+ }
+ }
+ }
+}
+
+
+AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enumItem, AbstractMetaClass *enclosing, const QSet<QString> &enumsDeclarations)
+{
+ // Skipping private enums.
+ if (enumItem->accessPolicy() == CodeModel::Private)
+ return 0;
+
+ QString qualifiedName = enumItem->qualifiedName().join("::");
+
+ TypeEntry *typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ QString enumName = enumItem->name();
+
+ QString className;
+ if (m_currentClass)
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ if (TypeDatabase::instance()->isEnumRejected(className, enumName)) {
+ m_rejectedEnums.insert(qualifiedName, GenerationDisabled);
+ return 0;
+ }
+
+ if (!typeEntry || !typeEntry->isEnum()) {
+ QString context = m_currentClass ? m_currentClass->name() : QLatin1String("");
+ ReportHandler::warning(QString("enum '%1' does not have a type entry or is not an enum")
+ .arg(qualifiedName));
+ m_rejectedEnums.insert(qualifiedName, NotInTypeSystem);
+ return 0;
+ }
+
+ AbstractMetaEnum *metaEnum = createMetaEnum();
+ if (enumsDeclarations.contains(qualifiedName)
+ || enumsDeclarations.contains(enumName)) {
+ metaEnum->setHasQEnumsDeclaration(true);
+ }
+
+ metaEnum->setTypeEntry((EnumTypeEntry *) typeEntry);
+ switch (enumItem->accessPolicy()) {
+ case CodeModel::Public: *metaEnum += AbstractMetaAttributes::Public; break;
+ case CodeModel::Protected: *metaEnum += AbstractMetaAttributes::Protected; break;
+// case CodeModel::Private: *meta_enum += AbstractMetaAttributes::Private; break;
+ default: break;
+ }
+
+ metaEnum->setIncludeFile(enumItem->fileName());
+
+ ReportHandler::debugMedium(QString(" - traversing enum %1").arg(metaEnum->fullName()));
+
+ foreach (EnumeratorModelItem value, enumItem->enumerators()) {
+
+ AbstractMetaEnumValue *metaEnumValue = createMetaEnumValue();
+ metaEnumValue->setName(value->name());
+ // Deciding the enum value...
+
+ metaEnumValue->setStringValue(value->value());
+ metaEnum->addEnumValue(metaEnumValue);
+
+ ReportHandler::debugFull(" - " + metaEnumValue->name() + " = "
+ + metaEnumValue->value());
+
+ // Add into global register...
+ if (enclosing)
+ m_enumValues[enclosing->name() + "::" + metaEnumValue->name()] = metaEnumValue;
+ else
+ m_enumValues[metaEnumValue->name()] = metaEnumValue;
+ }
+
+ m_enums << metaEnum;
+
+ return metaEnum;
+}
+
+AbstractMetaClass* AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typeAlias)
+{
+ TypeDatabase* types = TypeDatabase::instance();
+ QString className = stripTemplateArgs(typeAlias->name());
+
+ QString fullClassName = className;
+ // we have an inner class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + "::" + fullClassName;
+ }
+
+ // If this is the alias for a primitive type
+ // we store the aliased type on the alias
+ // TypeEntry
+ PrimitiveTypeEntry* ptype = types->findPrimitiveType(className);
+ if (ptype) {
+ QString typeAliasName = typeAlias->type().qualifiedName()[0];
+ ptype->setAliasedTypeEntry(types->findPrimitiveType(typeAliasName));
+ return 0;
+ }
+
+ // If we haven't specified anything for the typedef, then we don't care
+ ComplexTypeEntry* type = types->findComplexType(fullClassName);
+ if (!type)
+ return 0;
+
+ if (type->isObject())
+ static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(stripTemplateArgs(typeAlias->type().qualifiedName().join("::"))));
+
+ AbstractMetaClass *metaClass = createMetaClass();
+ metaClass->setTypeAlias(true);
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(QStringList() << typeAlias->type().qualifiedName().join("::"));
+ *metaClass += AbstractMetaAttributes::Public;
+
+ // Set the default include file name
+ if (!type->include().isValid()) {
+ QFileInfo info(typeAlias->fileName());
+ type->setInclude(Include(Include::IncludePath, info.fileName()));
+ }
+
+ return metaClass;
+}
+
+AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem classItem)
+{
+ QString className = stripTemplateArgs(classItem->name());
+ QString fullClassName = className;
+
+ // we have inner an class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + "::" + fullClassName;
+ }
+
+ ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(fullClassName);
+ RejectReason reason = NoReason;
+
+ if (fullClassName == "QMetaTypeId") {
+ // QtScript: record which types have been declared
+ int lpos = classItem->name().indexOf('<');
+ int rpos = classItem->name().lastIndexOf('>');
+ if ((lpos != -1) && (rpos != -1)) {
+ QString declaredTypename = classItem->name().mid(lpos + 1, rpos - lpos - 1);
+ m_qmetatypeDeclaredTypenames.insert(declaredTypename);
+ }
+ }
+
+ if (TypeDatabase::instance()->isClassRejected(fullClassName)) {
+ reason = GenerationDisabled;
+ } else if (!type) {
+ TypeEntry *te = TypeDatabase::instance()->findType(fullClassName);
+ if (te && !te->isComplex())
+ reason = RedefinedToNotClass;
+ else
+ reason = NotInTypeSystem;
+ } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
+ reason = GenerationDisabled;
+ }
+
+ if (reason != NoReason) {
+ m_rejectedClasses.insert(fullClassName, reason);
+ return 0;
+ }
+
+ if (type->isObject())
+ ((ObjectTypeEntry *)type)->setQObject(isQObject(fullClassName));
+
+ AbstractMetaClass *metaClass = createMetaClass();
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(classItem->baseClasses());
+ *metaClass += AbstractMetaAttributes::Public;
+
+ AbstractMetaClass *oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ if (type->isContainer())
+ ReportHandler::debugSparse(QString("container: '%1'").arg(fullClassName));
+ else
+ ReportHandler::debugSparse(QString("class: '%1'").arg(metaClass->fullName()));
+
+ TemplateParameterList template_parameters = classItem->templateParameters();
+ QList<TypeEntry *> template_args;
+ template_args.clear();
+ for (int i = 0; i < template_parameters.size(); ++i) {
+ const TemplateParameterModelItem &param = template_parameters.at(i);
+ TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name());
+ param_type->setOrdinal(i);
+ template_args.append(param_type);
+ }
+ metaClass->setTemplateArguments(template_args);
+
+ parseQ_Property(metaClass, classItem->propertyDeclarations());
+
+ traverseEnums(model_dynamic_cast<ScopeModelItem>(classItem), metaClass, classItem->enumsDeclarations());
+ traverseFields(model_dynamic_cast<ScopeModelItem>(classItem), metaClass);
+ traverseFunctions(model_dynamic_cast<ScopeModelItem>(classItem), metaClass);
+
+ // Inner classes
+ {
+ QList<ClassModelItem> innerClasses = classItem->classMap().values();
+ foreach (const ClassModelItem &ci, innerClasses) {
+ AbstractMetaClass *cl = traverseClass(ci);
+ if (cl) {
+ cl->setEnclosingClass(metaClass);
+ metaClass->addInnerClass(cl);
+ m_metaClasses << cl;
+ }
+ }
+
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = classItem->typeAliases();
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
+ if (cls) {
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+
+ m_currentClass = oldCurrentClass;
+
+ // Set the default include file name
+ if (!type->include().isValid()) {
+ QFileInfo info(classItem->fileName());
+ type->setInclude(Include(Include::IncludePath, info.fileName()));
+ }
+
+ return metaClass;
+}
+
+AbstractMetaField *AbstractMetaBuilder::traverseField(VariableModelItem field, const AbstractMetaClass *cls)
+{
+ QString fieldName = field->name();
+ QString className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ // Ignore friend decl.
+ if (field->isFriend())
+ return 0;
+
+ if (field->accessPolicy() == CodeModel::Private)
+ return 0;
+
+ if (TypeDatabase::instance()->isFieldRejected(className, fieldName)) {
+ m_rejectedFields.insert(className + "::" + fieldName, GenerationDisabled);
+ return 0;
+ }
+
+
+ AbstractMetaField *metaField = createMetaField();
+ metaField->setName(fieldName);
+ metaField->setEnclosingClass(cls);
+
+ bool ok;
+ TypeInfo fieldType = field->type();
+ AbstractMetaType *metaType = translateType(fieldType, &ok);
+
+ if (!metaType || !ok) {
+ ReportHandler::warning(QString("skipping field '%1::%2' with unmatched type '%3'")
+ .arg(m_currentClass->name())
+ .arg(fieldName)
+ .arg(TypeInfo::resolveType(fieldType, currentScope()->toItem()).qualifiedName().join("::")));
+ delete metaField;
+ return 0;
+ }
+
+ metaField->setType(metaType);
+
+ uint attr = 0;
+ if (field->isStatic())
+ attr |= AbstractMetaAttributes::Static;
+
+ CodeModel::AccessPolicy policy = field->accessPolicy();
+ if (policy == CodeModel::Public)
+ attr |= AbstractMetaAttributes::Public;
+ else if (policy == CodeModel::Protected)
+ attr |= AbstractMetaAttributes::Protected;
+ else
+ attr |= AbstractMetaAttributes::Private;
+ metaField->setAttributes(attr);
+
+ return metaField;
+}
+
+void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMetaClass *metaClass)
+{
+ foreach (VariableModelItem field, scope_item->variables()) {
+ AbstractMetaField *metaField = traverseField(field, metaClass);
+
+ if (metaField) {
+ metaField->setOriginalAttributes(metaField->attributes());
+ metaClass->addField(metaField);
+ }
+ }
+}
+
+void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction *metaFunction, AbstractMetaClass *metaClass)
+{
+ // Set the default value of the declaring class. This may be changed
+ // in fixFunctions later on
+ metaFunction->setDeclaringClass(metaClass);
+
+ // Some of the queries below depend on the implementing class being set
+ // to function properly. Such as function modifications
+ metaFunction->setImplementingClass(metaClass);
+
+ if (metaFunction->name() == "operator_equal")
+ metaClass->setHasEqualsOperator(true);
+
+ if (!metaFunction->isFinalInTargetLang()
+ && metaFunction->isRemovedFrom(metaClass, TypeSystem::TargetLangCode)) {
+ *metaFunction += AbstractMetaAttributes::FinalInCpp;
+ }
+}
+
+void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass *metaClass)
+{
+ foreach (FunctionModelItem function, scopeItem->functions()) {
+ AbstractMetaFunction *metaFunction = traverseFunction(function);
+
+ if (metaFunction) {
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaAttributes::Static;
+
+ if (QPropertySpec *read = metaClass->propertySpecForRead(metaFunction->name())) {
+ if (read->type() == metaFunction->type()->typeEntry()) {
+ *metaFunction += AbstractMetaAttributes::PropertyReader;
+ metaFunction->setPropertySpec(read);
+ }
+ } else if (QPropertySpec *write = metaClass->propertySpecForWrite(metaFunction->name())) {
+ if (write->type() == metaFunction->arguments().at(0)->type()->typeEntry()) {
+ *metaFunction += AbstractMetaAttributes::PropertyWriter;
+ metaFunction->setPropertySpec(write);
+ }
+ } else if (QPropertySpec *reset = metaClass->propertySpecForReset(metaFunction->name())) {
+ *metaFunction += AbstractMetaAttributes::PropertyResetter;
+ metaFunction->setPropertySpec(reset);
+ }
+
+
+ bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
+ bool isInvalidConstructor = metaFunction->isConstructor()
+ && (metaFunction->isPrivate() || metaFunction->isInvalid());
+ if ((isInvalidDestructor || isInvalidConstructor)
+ && !metaClass->hasNonPrivateConstructor()) {
+ *metaClass += AbstractMetaAttributes::Final;
+ } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
+ *metaClass -= AbstractMetaAttributes::Final;
+ metaClass->setHasNonPrivateConstructor(true);
+ }
+
+ // Classes with virtual destructors should always have a shell class
+ // (since we aren't registering the destructors, we need this extra check)
+ if (metaFunction->isDestructor() && !metaFunction->isFinal())
+ metaClass->setForceShellClass(true);
+
+ if (!metaFunction->isDestructor()
+ && !metaFunction->isInvalid()
+ && (!metaFunction->isConstructor() || !metaFunction->isPrivate())) {
+
+ setupFunctionDefaults(metaFunction, metaClass);
+
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) {
+ QString warn = QString("signal '%1' in class '%2' is overloaded.")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
+ }
+
+ if (metaFunction->isSignal() && !metaClass->isQObject()) {
+ QString warn = QString("signal '%1' in non-QObject class '%2'")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
+ }
+
+ metaClass->addFunction(metaFunction);
+ } else if (metaFunction->isDestructor() && metaFunction->isPrivate()) {
+ metaClass->setHasPrivateDestructor(true);
+ }
+ applyFunctionModifications(metaFunction);
+ }
+ }
+}
+
+void AbstractMetaBuilder::applyFunctionModifications(AbstractMetaFunction* func)
+{
+ FunctionModificationList mods = func->modifications(func->implementingClass());
+ AbstractMetaFunction& funcRef = *func;
+ foreach (FunctionModification mod, mods) {
+ if (mod.isRenameModifier()) {
+ func->setOriginalName(func->name());
+ func->setName(mod.renamedTo());
+ } else if (mod.isAccessModifier()) {
+ funcRef -= AbstractMetaAttributes::Public;
+ funcRef -= AbstractMetaAttributes::Protected;
+ funcRef -= AbstractMetaAttributes::Private;
+ funcRef -= AbstractMetaAttributes::Friendly;
+
+ if (mod.isPublic())
+ funcRef += AbstractMetaAttributes::Public;
+ else if (mod.isProtected())
+ funcRef += AbstractMetaAttributes::Protected;
+ else if (mod.isPrivate())
+ funcRef += AbstractMetaAttributes::Private;
+ else if (mod.isFriendly())
+ funcRef += AbstractMetaAttributes::Friendly;
+ }
+
+ if (mod.isFinal())
+ funcRef += AbstractMetaAttributes::FinalInTargetLang;
+ else if (mod.isNonFinal())
+ funcRef -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+}
+
+bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *metaClass)
+{
+ Q_ASSERT(!metaClass->isInterface());
+
+ if (m_setupInheritanceDone.contains(metaClass))
+ return true;
+
+ m_setupInheritanceDone.insert(metaClass);
+
+ QStringList baseClasses = metaClass->baseClassNames();
+
+ TypeDatabase *types = TypeDatabase::instance();
+
+ // we only support our own containers and ONLY if there is only one baseclass
+ if (baseClasses.size() == 1 && baseClasses.first().count('<') == 1) {
+ QStringList scope = metaClass->typeEntry()->qualifiedCppName().split("::");
+ scope.removeLast();
+ for (int i = scope.size(); i >= 0; --i) {
+ QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join("::") + "::" : QString();
+ QString completeName = prefix + baseClasses.first();
+ TypeParser::Info info = TypeParser::parse(completeName);
+ QString baseName = info.qualified_name.join("::");
+
+ AbstractMetaClass *templ = 0;
+ foreach (AbstractMetaClass *c, m_templates) {
+ if (c->typeEntry()->name() == baseName) {
+ templ = c;
+ break;
+ }
+ }
+
+ if (!templ)
+ templ = m_metaClasses.findClass(baseName);
+
+ if (templ) {
+ setupInheritance(templ);
+ inheritTemplate(metaClass, templ, info);
+ return true;
+ }
+ }
+
+ ReportHandler::warning(QString("template baseclass '%1' of '%2' is not known")
+ .arg(baseClasses.first())
+ .arg(metaClass->name()));
+ return false;
+ }
+
+ int primary = -1;
+ int primaries = 0;
+ for (int i = 0; i < baseClasses.size(); ++i) {
+
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ TypeEntry *baseClassEntry = types->findType(baseClasses.at(i));
+ if (!baseClassEntry)
+ ReportHandler::warning(QString("class '%1' inherits from unknown base class '%2'")
+ .arg(metaClass->name()).arg(baseClasses.at(i)));
+
+ // true for primary base class
+ else if (!baseClassEntry->designatedInterface()) {
+ if (primaries > 0) {
+ ReportHandler::warning(QString("class '%1' has multiple primary base classes"
+ " '%2' and '%3'")
+ .arg(metaClass->name())
+ .arg(baseClasses.at(primary))
+ .arg(baseClassEntry->name()));
+ return false;
+ }
+ primaries++;
+ primary = i;
+ }
+ }
+
+ if (primary >= 0) {
+ AbstractMetaClass *baseClass = m_metaClasses.findClass(baseClasses.at(primary));
+ if (!baseClass) {
+ ReportHandler::warning(QString("unknown baseclass for '%1': '%2'")
+ .arg(metaClass->name())
+ .arg(baseClasses.at(primary)));
+ return false;
+ }
+ metaClass->setBaseClass(baseClass);
+ }
+
+ for (int i = 0; i < baseClasses.size(); ++i) {
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ if (i != primary) {
+ AbstractMetaClass *baseClass = m_metaClasses.findClass(baseClasses.at(i));
+ if (!baseClass) {
+ ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(baseClasses.at(i)));
+ return false;
+ }
+
+ setupInheritance(baseClass);
+
+ QString interfaceName = InterfaceTypeEntry::interfaceName(baseClass->name());
+ AbstractMetaClass *iface = m_metaClasses.findClass(interfaceName);
+ if (!iface) {
+ ReportHandler::warning(QString("unknown interface for '%1': '%2'")
+ .arg(metaClass->name())
+ .arg(interfaceName));
+ return false;
+ }
+ metaClass->addInterface(iface);
+
+ AbstractMetaClassList interfaces = iface->interfaces();
+ foreach (AbstractMetaClass *iface, interfaces)
+ metaClass->addInterface(iface);
+ }
+ }
+
+ return true;
+}
+
+void AbstractMetaBuilder::traverseEnums(ScopeModelItem scopeItem, AbstractMetaClass *metaClass, const QStringList &enumsDeclarations)
+{
+ EnumList enums = scopeItem->enums();
+ foreach (EnumModelItem enum_item, enums) {
+ AbstractMetaEnum *meta_enum = traverseEnum(enum_item, metaClass, QSet<QString>::fromList(enumsDeclarations));
+ if (meta_enum) {
+ meta_enum->setOriginalAttributes(meta_enum->attributes());
+ metaClass->addEnum(meta_enum);
+ meta_enum->setEnclosingClass(metaClass);
+ }
+ }
+}
+
+AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem functionItem)
+{
+ QString functionName = functionItem->name();
+ QString className;
+ if (m_currentClass)
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ if (TypeDatabase::instance()->isFunctionRejected(className, functionName)) {
+ m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled);
+ return 0;
+ }
+
+ Q_ASSERT(functionItem->functionType() == CodeModel::Normal
+ || functionItem->functionType() == CodeModel::Signal
+ || functionItem->functionType() == CodeModel::Slot);
+
+ if (functionItem->isFriend())
+ return 0;
+
+
+ QString cast_type;
+
+ AbstractMetaFunction *metaFunction = createMetaFunction();
+ metaFunction->setConstant(functionItem->isConstant());
+
+ ReportHandler::debugMedium(QString(" - %2()").arg(functionName));
+
+ metaFunction->setName(functionName);
+ metaFunction->setOriginalName(functionItem->name());
+
+ if (functionItem->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Abstract;
+
+ if (!metaFunction->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Native;
+
+ if (!functionItem->isVirtual())
+ *metaFunction += AbstractMetaAttributes::Final;
+
+ if (functionItem->isInvokable())
+ *metaFunction += AbstractMetaAttributes::Invokable;
+
+ if (functionItem->isStatic()) {
+ *metaFunction += AbstractMetaAttributes::Static;
+ *metaFunction += AbstractMetaAttributes::Final;
+ }
+
+ // Access rights
+ if (functionItem->accessPolicy() == CodeModel::Public)
+ *metaFunction += AbstractMetaAttributes::Public;
+ else if (functionItem->accessPolicy() == CodeModel::Private)
+ *metaFunction += AbstractMetaAttributes::Private;
+ else
+ *metaFunction += AbstractMetaAttributes::Protected;
+
+
+ QString strippedClassName = className;
+ int cc_pos = strippedClassName.lastIndexOf("::");
+ if (cc_pos > 0)
+ strippedClassName = strippedClassName.mid(cc_pos + 2);
+
+ TypeInfo functionType = functionItem->type();
+ if (functionName.startsWith('~')) {
+ metaFunction->setFunctionType(AbstractMetaFunction::DestructorFunction);
+ metaFunction->setInvalid(true);
+ } else if (stripTemplateArgs(functionName) == strippedClassName) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ metaFunction->setExplicit(functionItem->isExplicit());
+ metaFunction->setName(m_currentClass->name());
+ } else {
+ bool ok;
+ AbstractMetaType *type = 0;
+
+ if (!cast_type.isEmpty()) {
+ TypeInfo info;
+ info.setQualifiedName(QStringList(cast_type));
+ type = translateType(info, &ok);
+ } else {
+ type = translateType(functionType, &ok);
+ }
+
+ if (!ok) {
+ ReportHandler::warning(QString("skipping function '%1::%2', unmatched return type '%3'")
+ .arg(className)
+ .arg(functionItem->name())
+ .arg(functionItem->type().toString()));
+ m_rejectedFunctions[className + "::" + functionName] =
+ UnmatchedReturnType;
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+ metaFunction->setType(type);
+
+ if (functionItem->functionType() == CodeModel::Signal)
+ metaFunction->setFunctionType(AbstractMetaFunction::SignalFunction);
+ else if (functionItem->functionType() == CodeModel::Slot)
+ metaFunction->setFunctionType(AbstractMetaFunction::SlotFunction);
+ }
+
+ ArgumentList arguments = functionItem->arguments();
+ AbstractMetaArgumentList metaArguments;
+
+ int firstDefaultArgument = 0;
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+
+ bool ok;
+ AbstractMetaType *metaType = translateType(arg->type(), &ok);
+ if (!metaType || !ok) {
+ ReportHandler::warning(QString("skipping function '%1::%2', "
+ "unmatched parameter type '%3'")
+ .arg(className)
+ .arg(functionItem->name())
+ .arg(arg->type().toString()));
+ m_rejectedFunctions[className + "::" + functionName] =
+ UnmatchedArgumentType;
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+ AbstractMetaArgument *metaArgument = createMetaArgument();
+ metaArgument->setType(metaType);
+ metaArgument->setName(arg->name());
+ metaArgument->setArgumentIndex(i);
+ metaArguments << metaArgument;
+ }
+
+ metaFunction->setArguments(metaArguments);
+
+ // Find the correct default values
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ AbstractMetaArgument *metaArg = metaArguments.at(i);
+
+ //use relace-default-expression for set default value
+ QString replacedExpression;
+ if (m_currentClass)
+ replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
+
+ if (arg->defaultValue() || !replacedExpression.isEmpty()) {
+ QString expr = arg->defaultValueExpression();
+
+ if (!expr.isEmpty())
+ metaArg->setOriginalDefaultValueExpression(expr);
+
+ if (m_currentClass) {
+ expr = translateDefaultValue(arg, metaArg->type(), metaFunction, m_currentClass, i);
+ metaArg->setDefaultValueExpression(expr);
+ }
+
+ if (expr.isEmpty())
+ firstDefaultArgument = i;
+
+ if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
+ m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction);
+ }
+ }
+
+#if 0
+ // If we where not able to translate the default argument make it
+ // reset all default arguments before this one too.
+ for (int i = 0; i < first_default_argument; ++i)
+ meta_arguments[i]->setDefaultValueExpression("<x>" + QString());
+
+ if (ReportHandler::debugLevel() == ReportHandler::FullDebug)
+ foreach (AbstractMetaArgument *arg, meta_arguments)
+ ReportHandler::debugFull(" - " + arg->toString());
+#endif
+
+ return metaFunction;
+}
+
+
+AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, bool *ok, bool resolveType, bool resolveScope)
+{
+ Q_ASSERT(ok);
+ *ok = true;
+
+ // 1. Test the type info without resolving typedefs in case this is present in the
+ // type system
+ TypeInfo typei;
+ if (resolveType) {
+ bool ok;
+ AbstractMetaType *t = translateType(_typei, &ok, false, resolveScope);
+ if (t && ok)
+ return t;
+ }
+
+ if (!resolveType) {
+ typei = _typei;
+ } else {
+ // Go through all parts of the current scope (including global namespace)
+ // to resolve typedefs. The parser does not properly resolve typedefs in
+ // the global scope when they are referenced from inside a namespace.
+ // This is a work around to fix this bug since fixing it in resolveType
+ // seemed non-trivial
+ int i = m_scopes.size() - 1;
+ while (i >= 0) {
+ typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)->toItem());
+ if (typei.qualifiedName().join("::") != _typei.qualifiedName().join("::"))
+ break;
+ }
+
+ }
+
+ if (typei.isFunctionPointer()) {
+ *ok = false;
+ return 0;
+ }
+
+ TypeParser::Info typeInfo = TypeParser::parse(typei.toString());
+ if (typeInfo.is_busted) {
+ *ok = false;
+ return 0;
+ }
+
+ // 2. Handle pointers specified as arrays with unspecified size
+ bool arrayOfUnspecifiedSize = false;
+ if (typeInfo.arrays.size() > 0) {
+ arrayOfUnspecifiedSize = true;
+ for (int i = 0; i < typeInfo.arrays.size(); ++i)
+ arrayOfUnspecifiedSize = arrayOfUnspecifiedSize && typeInfo.arrays.at(i).isEmpty();
+
+ if (!arrayOfUnspecifiedSize) {
+ TypeInfo newInfo;
+ //newInfo.setArguments(typei.arguments());
+ newInfo.setIndirections(typei.indirections());
+ newInfo.setConstant(typei.isConstant());
+ newInfo.setFunctionPointer(typei.isFunctionPointer());
+ newInfo.setQualifiedName(typei.qualifiedName());
+ newInfo.setReference(typei.isReference());
+ newInfo.setVolatile(typei.isVolatile());
+
+ AbstractMetaType *elementType = translateType(newInfo, ok);
+ if (!(*ok))
+ return 0;
+
+ for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) {
+ QString s = typeInfo.arrays.at(i);
+ bool ok;
+
+ int elems = s.toInt(&ok);
+ if (!ok)
+ return 0;
+
+ AbstractMetaType *arrayType = createMetaType();
+ arrayType->setArrayElementCount(elems);
+ arrayType->setArrayElementType(elementType);
+ arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry()));
+ decideUsagePattern(arrayType);
+
+ elementType = arrayType;
+ }
+
+ return elementType;
+ } else {
+ typeInfo.indirections += typeInfo.arrays.size();
+ }
+ }
+
+ QStringList qualifierList = typeInfo.qualified_name;
+ if (qualifierList.isEmpty()) {
+ ReportHandler::warning(QString("horribly broken type '%1'").arg(_typei.toString()));
+ *ok = false;
+ return 0;
+ }
+
+ QString qualifiedName = qualifierList.join("::");
+ QString name = qualifierList.takeLast();
+
+ // 3. Special case 'void' type
+ if (name == "void" && !typeInfo.indirections)
+ return 0;
+
+ // 4. Special case QFlags (include instantiation in name)
+ if (qualifiedName == "QFlags")
+ qualifiedName = typeInfo.toString();
+
+ // 5. Try to find the type
+ const TypeEntry *type = TypeDatabase::instance()->findType(qualifiedName);
+
+ // 6. No? Try looking it up as a flags type
+ if (!type)
+ type = TypeDatabase::instance()->findFlagsType(qualifiedName);
+
+ // 7. No? Try looking it up as a container type
+ if (!type)
+ type = TypeDatabase::instance()->findContainerType(name);
+
+ // 8. No? Check if the current class is a template and this type is one
+ // of the parameters.
+ if (!type && m_currentClass) {
+ QList<TypeEntry *> template_args = m_currentClass->templateArguments();
+ foreach (TypeEntry *te, template_args) {
+ if (te->name() == qualifiedName)
+ type = te;
+ }
+ }
+
+ // 9. Try finding the type by prefixing it with the current
+ // context and all baseclasses of the current context
+ if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) {
+ QStringList contexts;
+ contexts.append(m_currentClass->qualifiedCppName());
+ contexts.append(currentScope()->qualifiedName().join("::"));
+
+
+ TypeInfo info = typei;
+ bool subclassesDone = false;
+ while (!contexts.isEmpty() && !type) {
+ //type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualified_name);
+
+ bool ok;
+ info.setQualifiedName(QStringList() << contexts.at(0) << qualifiedName);
+ AbstractMetaType *t = translateType(info, &ok, true, false);
+ if (t && ok)
+ return t;
+
+ ClassModelItem item = m_dom->findClass(contexts.at(0));
+ if (item)
+ contexts += item->baseClasses();
+ contexts.pop_front();
+
+ // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
+ // enum types from there may be addressed without any scope resolution in properties.
+ if (!contexts.size() && !subclassesDone) {
+ contexts << "Qt";
+ subclassesDone = true;
+ }
+ }
+
+ }
+
+ if (!type) {
+ *ok = false;
+ return 0;
+ }
+
+ // Used to for diagnostics later...
+ m_usedTypes << type;
+
+ // These are only implicit and should not appear in code...
+ Q_ASSERT(!type->isInterface());
+
+ AbstractMetaType *metaType = createMetaType();
+ metaType->setTypeEntry(type);
+ metaType->setIndirections(typeInfo.indirections);
+ metaType->setReference(typeInfo.is_reference);
+ metaType->setConstant(typeInfo.is_constant);
+ metaType->setOriginalTypeDescription(_typei.toString());
+ decideUsagePattern(metaType);
+
+ if (metaType->typeEntry()->isContainer()) {
+ ContainerTypeEntry::Type container_type = static_cast<const ContainerTypeEntry *>(type)->type();
+
+ if (container_type == ContainerTypeEntry::StringListContainer) {
+ TypeInfo info;
+ info.setQualifiedName(QStringList() << "QString");
+ AbstractMetaType *targType = translateType(info, ok);
+
+ Q_ASSERT(*ok);
+ Q_ASSERT(targType);
+
+ metaType->addInstantiation(targType);
+ metaType->setInstantiationInCpp(false);
+
+ } else {
+ foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) {
+ TypeInfo info;
+ info.setConstant(ta.is_constant);
+ info.setReference(ta.is_reference);
+ info.setIndirections(ta.indirections);
+
+ info.setFunctionPointer(false);
+ info.setQualifiedName(ta.instantiationName().split("::"));
+
+ AbstractMetaType *targType = translateType(info, ok);
+ if (!(*ok)) {
+ delete metaType;
+ return 0;
+ }
+
+ metaType->addInstantiation(targType);
+ }
+ }
+
+ if (container_type == ContainerTypeEntry::ListContainer
+ || container_type == ContainerTypeEntry::VectorContainer
+ || container_type == ContainerTypeEntry::StringListContainer) {
+ Q_ASSERT(metaType->instantiations().size() == 1);
+ }
+ }
+
+ return metaType;
+}
+
+void AbstractMetaBuilder::decideUsagePattern(AbstractMetaType *metaType)
+{
+ const TypeEntry *type = metaType->typeEntry();
+
+ if (type->isPrimitive() && (!metaType->actualIndirections()
+ || (metaType->isConstant() && metaType->isReference() && !metaType->indirections()))) {
+ metaType->setTypeUsagePattern(AbstractMetaType::PrimitivePattern);
+
+ } else if (type->isVoid()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
+
+ } else if (type->isString()
+ && metaType->indirections() == 0
+ && (metaType->isConstant() == metaType->isReference()
+ || metaType->isConstant())) {
+ metaType->setTypeUsagePattern(AbstractMetaType::StringPattern);
+
+ } else if (type->isChar()
+ && !metaType->indirections()
+ && metaType->isConstant() == metaType->isReference()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::CharPattern);
+
+ } else if (type->isJObjectWrapper()
+ && !metaType->indirections()
+ && metaType->isConstant() == metaType->isReference()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::JObjectWrapperPattern);
+
+ } else if (type->isVariant()
+ && !metaType->indirections()
+ && metaType->isConstant() == metaType->isReference()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::VariantPattern);
+
+ } else if (type->isEnum() && !metaType->actualIndirections()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::EnumPattern);
+
+ } else if (type->isObject()
+ && metaType->indirections() == 0
+ && metaType->isReference()) {
+ if (((ComplexTypeEntry *) type)->isQObject())
+ metaType->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
+ else
+ metaType->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
+
+ } else if (type->isObject()
+ && metaType->indirections() == 1) {
+ if (((ComplexTypeEntry *) type)->isQObject())
+ metaType->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
+ else
+ metaType->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
+
+ // const-references to pointers can be passed as pointers
+ if (metaType->isReference() && metaType->isConstant()) {
+ metaType->setReference(false);
+ metaType->setConstant(false);
+ }
+
+ } else if (type->isContainer() && !metaType->indirections()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+
+ } else if (type->isTemplateArgument()) {
+
+ } else if (type->isFlags()
+ && !metaType->indirections()
+ && (metaType->isConstant() == metaType->isReference())) {
+ metaType->setTypeUsagePattern(AbstractMetaType::FlagsPattern);
+
+ } else if (type->isArray()) {
+ metaType->setTypeUsagePattern(AbstractMetaType::ArrayPattern);
+
+ } else if (type->isThread()) {
+ Q_ASSERT(metaType->indirections() == 1);
+ metaType->setTypeUsagePattern(AbstractMetaType::ThreadPattern);
+
+ } else if (type->isValue()
+ && !metaType->indirections()
+ && (metaType->isConstant() == metaType->isReference()
+ || !metaType->isReference())) {
+ metaType->setTypeUsagePattern(AbstractMetaType::ValuePattern);
+
+ } else {
+ metaType->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
+ ReportHandler::debugFull(QString("native pointer pattern for '%1'")
+ .arg(metaType->cppSignature()));
+ }
+}
+
+QString AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
+ AbstractMetaFunction *fnc, AbstractMetaClass *implementingClass,
+ int argumentIndex)
+{
+ QString functionName = fnc->name();
+ QString className = implementingClass->qualifiedCppName();
+
+ QString replacedExpression = fnc->replacedDefaultExpression(implementingClass, argumentIndex + 1);
+ if (fnc->removedDefaultExpression(implementingClass, argumentIndex + 1))
+ return "";
+ else if (!replacedExpression.isEmpty())
+ return replacedExpression;
+
+ QString expr = item->defaultValueExpression();
+ if (type) {
+ if (type->isPrimitive()) {
+ if (type->name() == "boolean") {
+ if (expr != "false" && expr != "true") {
+ bool ok = false;
+ int number = expr.toInt(&ok);
+ if (ok && number)
+ expr = "true";
+ else
+ expr = "false";
+ }
+ } else if (expr == "QVariant::Invalid") {
+ expr = QString::number(QVariant::Invalid);
+ } else {
+ // This can be an enum or flag so I need to delay the
+ // translation untill all namespaces are completly
+ // processed. This is done in figureOutEnumValues()
+ }
+ } else if (type->isFlags() || type->isEnum()) {
+ bool isNumber;
+ expr.toInt(&isNumber);
+ if (!isNumber && expr.indexOf("::") < 0) {
+ // Add the enum/flag scope to default value, making it usable
+ // from other contexts beside its owner class hierarchy
+ QRegExp typeRegEx("[^<]*[<]([^:]*::).*");
+ typeRegEx.indexIn(type->minimalSignature());
+ expr = typeRegEx.cap(1) + expr;
+ }
+ } else if (type->isContainer() && expr.contains('<')) {
+ QRegExp typeRegEx("[^<]*<(.*)>");
+ typeRegEx.indexIn(type->minimalSignature());
+ QRegExp defaultRegEx("([^<]*<).*(>[^>]*)");
+ defaultRegEx.indexIn(expr);
+ expr = defaultRegEx.cap(1) + typeRegEx.cap(1) + defaultRegEx.cap(2);
+ } else {
+ // Here the default value is supposed to be a constructor,
+ // a class field, or a constructor receiving a class field
+ QRegExp defaultRegEx("([^\\(]*\\(|)([^\\)]*)(\\)|)");
+ defaultRegEx.indexIn(expr);
+
+ QString defaultValueCtorName = defaultRegEx.cap(1);
+ if (defaultValueCtorName.endsWith('('))
+ defaultValueCtorName.chop(1);
+
+ // Fix the scope for constructor using the already
+ // resolved argument type as a reference.
+ // The following regular expression extracts any
+ // use of namespaces/scopes from the type string.
+ QRegExp typeRegEx("^(?:const[\\s]+|)([\\w:]*::|)([A-Za-z_]\\w*)\\s*[&\\*]?$");
+ typeRegEx.indexIn(type->minimalSignature());
+
+ QString typeNamespace = typeRegEx.cap(1);
+ QString typeCtorName = typeRegEx.cap(2);
+ if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName)
+ expr.prepend(typeNamespace);
+
+ // Fix scope if the parameter is a field of the current class
+ foreach (const AbstractMetaField* field, implementingClass->fields()) {
+ if (defaultRegEx.cap(2) == field->name()) {
+ expr = defaultRegEx.cap(1) + implementingClass->name() + "::" + defaultRegEx.cap(2) + defaultRegEx.cap(3);
+ break;
+ }
+ }
+ }
+ } else {
+ QString warn = QString("undefined type for default value '%3' of argument in function '%1', class '%2'")
+ .arg(functionName).arg(className).arg(item->defaultValueExpression());
+ ReportHandler::warning(warn);
+ expr = QString();
+ }
+
+ return expr;
+}
+
+bool AbstractMetaBuilder::isQObject(const QString &qualifiedName)
+{
+ if (qualifiedName == "QObject")
+ return true;
+
+ ClassModelItem classItem = m_dom->findClass(qualifiedName);
+
+ if (!classItem) {
+ QStringList names = qualifiedName.split(QLatin1String("::"));
+ NamespaceModelItem ns = model_dynamic_cast<NamespaceModelItem>(m_dom);
+ for (int i = 0; i < names.size() - 1 && ns; ++i)
+ ns = ns->namespaceMap().value(names.at(i));
+ if (ns && names.size() >= 2)
+ classItem = ns->findClass(names.at(names.size() - 1));
+ }
+
+ bool isqobject = classItem && classItem->extendsClass("QObject");
+
+ if (classItem && !isqobject) {
+ QStringList baseClasses = classItem->baseClasses();
+ for (int i = 0; i < baseClasses.count(); ++i) {
+
+ isqobject = isQObject(baseClasses.at(i));
+ if (isqobject)
+ break;
+ }
+ }
+
+ return isqobject;
+}
+
+
+bool AbstractMetaBuilder::isEnum(const QStringList &qualified_name)
+{
+ CodeModelItem item = m_dom->model()->findItem(qualified_name, m_dom->toItem());
+ return item && item->kind() == _EnumModelItem::__node_kind;
+}
+
+AbstractMetaType *AbstractMetaBuilder::inheritTemplateType(const QList<AbstractMetaType *> &templateTypes,
+ AbstractMetaType *metaType, bool *ok)
+{
+ if (ok)
+ *ok = true;
+ if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()))
+ return metaType ? metaType->copy() : 0;
+
+ AbstractMetaType *returned = metaType->copy();
+ returned->setOriginalTemplateType(metaType->copy());
+
+ if (returned->typeEntry()->isTemplateArgument()) {
+ const TemplateArgumentEntry *tae = static_cast<const TemplateArgumentEntry *>(returned->typeEntry());
+
+ // If the template is intantiated with void we special case this as rejecting the functions that use this
+ // parameter from the instantiation.
+ if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == "void") {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ AbstractMetaType *t = returned->copy();
+ t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry());
+ t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0);
+ decideUsagePattern(t);
+
+ delete returned;
+ returned = inheritTemplateType(templateTypes, t, ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+
+ if (returned->hasInstantiations()) {
+ QList<AbstractMetaType *> instantiations = returned->instantiations();
+ for (int i = 0; i < instantiations.count(); ++i) {
+ instantiations[i] = inheritTemplateType(templateTypes, instantiations.at(i), ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+ returned->setInstantiations(instantiations);
+ }
+
+ return returned;
+}
+
+bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass,
+ const AbstractMetaClass *templateClass,
+ const TypeParser::Info &info)
+{
+ QList<TypeParser::Info> targs = info.template_instantiations;
+
+ QList<AbstractMetaType *> templateTypes;
+ foreach (const TypeParser::Info &i, targs) {
+ TypeEntry *t = TypeDatabase::instance()->findType(i.qualified_name.join("::"));
+
+ if (t) {
+ AbstractMetaType *temporaryType = createMetaType();
+ temporaryType->setTypeEntry(t);
+ temporaryType->setConstant(i.is_constant);
+ temporaryType->setReference(i.is_reference);
+ temporaryType->setIndirections(i.indirections);
+ templateTypes << temporaryType;
+ }
+ }
+
+ AbstractMetaFunctionList funcs = subclass->functions();
+ foreach (const AbstractMetaFunction *function, templateClass->functions()) {
+
+ if (function->isModifiedRemoved(TypeSystem::All))
+ continue;
+
+ AbstractMetaFunction *f = function->copy();
+ f->setArguments(AbstractMetaArgumentList());
+
+ bool ok = true;
+ AbstractMetaType *ftype = function->type();
+ f->setType(inheritTemplateType(templateTypes, ftype, &ok));
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ foreach (AbstractMetaArgument *argument, function->arguments()) {
+ AbstractMetaType *atype = argument->type();
+
+ AbstractMetaArgument *arg = argument->copy();
+ arg->setType(inheritTemplateType(templateTypes, atype, &ok));
+ if (!ok)
+ break;
+ f->addArgument(arg);
+ }
+
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ // There is no base class in the target language to inherit from here, so
+ // the template instantiation is the class that implements the function.
+ f->setImplementingClass(subclass);
+
+ // We also set it as the declaring class, since the superclass is
+ // supposed to disappear. This allows us to make certain function modifications
+ // on the inherited functions.
+ f->setDeclaringClass(subclass);
+
+
+ if (f->isConstructor() && subclass->isTypeAlias()) {
+ f->setName(subclass->name());
+ } else if (f->isConstructor()) {
+ delete f;
+ continue;
+ }
+
+ // if the instantiation has a function named the same as an existing
+ // function we have shadowing so we need to skip it.
+ bool found = false;
+ for (int i = 0; i < funcs.size(); ++i) {
+ if (funcs.at(i)->name() == f->name()) {
+ found = true;
+ continue;
+ }
+ }
+ if (found) {
+ delete f;
+ continue;
+ }
+
+ ComplexTypeEntry *te = subclass->typeEntry();
+ FunctionModificationList mods = function->modifications(templateClass);
+ for (int i = 0; i < mods.size(); ++i) {
+ FunctionModification mod = mods.at(i);
+ mod.signature = f->minimalSignature();
+
+ // If we ever need it... Below is the code to do
+ // substitution of the template instantation type inside
+ // injected code..
+#if 0
+ if (mod.modifiers & Modification::CodeInjection) {
+ for (int j = 0; j < template_types.size(); ++j) {
+ CodeSnip &snip = mod.snips.last();
+ QString code = snip.code();
+ code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
+ template_types.at(j)->typeEntry()->qualifiedCppName());
+ snip.codeList.clear();
+ snip.addCode(code);
+ }
+ }
+#endif
+ te->addFunctionModification(mod);
+ }
+
+ subclass->addFunction(f);
+ }
+
+ // Clean up
+ foreach (AbstractMetaType *type, templateTypes)
+ delete type;
+
+ subclass->setTemplateBaseClass(templateClass);
+ subclass->setInterfaces(templateClass->interfaces());
+ subclass->setBaseClass(templateClass->baseClass());
+
+ return true;
+}
+
+void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations)
+{
+ for (int i = 0; i < declarations.size(); ++i) {
+ QString p = declarations.at(i);
+
+ QStringList l = p.split(QLatin1String(" "));
+
+
+ QStringList qualifiedScopeName = currentScope()->qualifiedName();
+ bool ok = false;
+ AbstractMetaType *type = 0;
+ QString scope;
+ for (int j = qualifiedScopeName.size(); j >= 0; --j) {
+ scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join("::") + "::" : QString();
+ TypeInfo info;
+ info.setQualifiedName((scope + l.at(0)).split("::"));
+
+ type = translateType(info, &ok);
+ if (type && ok)
+ break;
+ }
+
+ if (!type || !ok) {
+ ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'")
+ .arg(l.at(0)).arg(metaClass->name()));
+ continue;
+ }
+
+ QString typeName = scope + l.at(0);
+
+ QPropertySpec *spec = new QPropertySpec(type->typeEntry());
+ spec->setName(l.at(1));
+ spec->setIndex(i);
+
+ for (int pos = 2; pos + 1 < l.size(); pos += 2) {
+ if (l.at(pos) == QLatin1String("READ"))
+ spec->setRead(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("WRITE"))
+ spec->setWrite(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("DESIGNABLE"))
+ spec->setDesignable(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("RESET"))
+ spec->setReset(l.at(pos + 1));
+ }
+
+ metaClass->addPropertySpec(spec);
+ delete type;
+ }
+}
+
+#if 0
+static void hide_functions(const AbstractMetaFunctionList &l)
+{
+ foreach (AbstractMetaFunction *f, l) {
+ FunctionModification mod;
+ mod.signature = f->minimalSignature();
+ mod.modifiers = FunctionModification::Private;
+ ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
+ }
+}
+
+static void remove_function(AbstractMetaFunction *f)
+{
+ FunctionModification mod;
+ mod.removal = TypeSystem::All;
+ mod.signature = f->minimalSignature();
+ ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
+}
+
+static AbstractMetaFunctionList filter_functions(const AbstractMetaFunctionList &lst, QSet<QString> *signatures)
+{
+ AbstractMetaFunctionList functions;
+ foreach (AbstractMetaFunction *f, lst) {
+ QString signature = f->minimalSignature();
+ int start = signature.indexOf(QLatin1Char('(')) + 1;
+ int end = signature.lastIndexOf(QLatin1Char(')'));
+ signature = signature.mid(start, end - start);
+ if (signatures->contains(signature)) {
+ remove_function(f);
+ continue;
+ }
+ (*signatures) << signature;
+ functions << f;
+ }
+ return functions;
+}
+
+void AbstractMetaBuilder::setupEquals(AbstractMetaClass */*cls*/)
+{
+// python have operator overloading, so we need all operators declared in C++.
+ AbstractMetaFunctionList equals;
+ AbstractMetaFunctionList nequals;
+
+ QString op_equals = QLatin1String("operator_equal");
+ QString opNequals = QLatin1String("operator_not_equal");
+
+ AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
+ | AbstractMetaClass::NotRemovedFromTargetLang);
+ foreach (AbstractMetaFunction *f, functions) {
+ if (f->name() == op_equals)
+ equals << f;
+ else if (f->name() == opNequals)
+ nequals << f;
+ }
+
+ if (equals.size() || nequals.size()) {
+ if (!cls->hasHashFunction()) {
+ ReportHandler::warning(QString::fromLatin1("Class '%1' has equals operators but no qHash() function")
+ .arg(cls->name()));
+ }
+
+ hide_functions(equals);
+ hide_functions(nequals);
+
+ // We only need == if we have both == and !=, and one == for
+ // each signature type, like QDateTime::==(QDate) and (QTime)
+ // if such a thing exists...
+ QSet<QString> func_signatures;
+ cls->setEqualsFunctions(filter_functions(equals, &func_signatures));
+ cls->setNotEqualsFunctions(filter_functions(nequals, &func_signatures));
+ }
+}
+
+void AbstractMetaBuilder::setupComparable(AbstractMetaClass *cls)
+{
+ AbstractMetaFunctionList greater;
+ AbstractMetaFunctionList greaterEquals;
+ AbstractMetaFunctionList less;
+ AbstractMetaFunctionList lessEquals;
+
+ QString op_greater = QLatin1String("operator_greater");
+ QString opGreaterEq = QLatin1String("operator_greater_or_equal");
+ QString op_less = QLatin1String("operator_less");
+ QString opLessEq = QLatin1String("operator_less_or_equal");
+
+ AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
+ | AbstractMetaClass::NotRemovedFromTargetLang);
+ foreach (AbstractMetaFunction *f, functions) {
+ if (f->name() == op_greater)
+ greater << f;
+ else if (f->name() == opGreaterEq)
+ greaterEquals << f;
+ else if (f->name() == op_less)
+ less << f;
+ else if (f->name() == opLessEq)
+ lessEquals << f;
+ }
+
+ bool hasEquals = cls->equalsFunctions().size() || cls->notEqualsFunctions().size();
+
+ // Conditions for comparable is:
+ // >, ==, < - The basic case
+ // >, == - Less than becomes else case
+ // <, == - Greater than becomes else case
+ // >=, <= - if (<= && >=) -> equal
+ bool mightBeComparable = greater.size() || greaterEquals.size() || less.size() || lessEquals.size()
+ || greaterEquals.size() == 1 || lessEquals.size() == 1;
+
+ if (mightBeComparable) {
+ QSet<QString> signatures;
+
+ // We only hide the original functions if we are able to make a compareTo() method
+ bool wasComparable = false;
+
+ // The three upper cases, prefer the <, == approach
+ if (hasEquals && (greater.size() || less.size())) {
+ cls->setLessThanFunctions(filter_functions(less, &signatures));
+ cls->setGreaterThanFunctions(filter_functions(greater, &signatures));
+ filter_functions(greaterEquals, &signatures);
+ filter_functions(lessEquals, &signatures);
+ wasComparable = true;
+ } else if (hasEquals && (greaterEquals.size() || lessEquals.size())) {
+ cls->setLessThanEqFunctions(filter_functions(lessEquals, &signatures));
+ cls->setGreaterThanEqFunctions(filter_functions(greaterEquals, &signatures));
+ wasComparable = true;
+ } else if (greaterEquals.size() == 1 || lessEquals.size() == 1) {
+ cls->setGreaterThanEqFunctions(greaterEquals);
+ cls->setLessThanEqFunctions(lessEquals);
+ filter_functions(less, &signatures);
+ filter_functions(greater, &signatures);
+ wasComparable = true;
+ }
+
+ if (wasComparable) {
+ hide_functions(greater);
+ hide_functions(greaterEquals);
+ hide_functions(less);
+ hide_functions(lessEquals);
+ }
+ }
+
+}
+#endif
+
+static AbstractMetaFunction *findCopyCtor(AbstractMetaClass *cls)
+{
+ AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible);
+ functions << cls->queryFunctions(AbstractMetaClass::Visible);
+
+ foreach (AbstractMetaFunction *f, functions) {
+ if (f->isConstructor() || f->name() == "operator=") {
+ AbstractMetaArgumentList arguments = f->arguments();
+ if (arguments.size() == 1) {
+ if (cls->typeEntry()->qualifiedCppName() == arguments.at(0)->type()->typeEntry()->qualifiedCppName())
+ return f;
+ }
+ }
+ }
+ return 0;
+}
+
+void AbstractMetaBuilder::setupClonable(AbstractMetaClass *cls)
+{
+ bool result = true;
+
+ // find copy ctor for the current class
+ AbstractMetaFunction *copyCtor = findCopyCtor(cls);
+ if (copyCtor) { // if exists a copy ctor in this class
+ result = copyCtor->isPublic();
+ } else { // else... lets find one in the parent class
+ QQueue<AbstractMetaClass*> baseClasses;
+ if (cls->baseClass())
+ baseClasses.enqueue(cls->baseClass());
+ baseClasses << cls->interfaces();
+
+ while (!baseClasses.isEmpty()) {
+ AbstractMetaClass* currentClass = baseClasses.dequeue();
+ baseClasses << currentClass->interfaces();
+ if (currentClass->baseClass())
+ baseClasses.enqueue(currentClass->baseClass());
+
+ copyCtor = findCopyCtor(currentClass);
+ if (copyCtor) {
+ result = copyCtor->isPublic();
+ break;
+ }
+ }
+ }
+ cls->setHasCloneOperator(result);
+}
+
+static void writeRejectLogFile(const QString &name,
+ const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects)
+{
+ QFile f(name);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ ReportHandler::warning(QString("failed to write log file: '%1'")
+ .arg(f.fileName()));
+ return;
+ }
+
+ QTextStream s(&f);
+
+
+ for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) {
+ s << QString(72, '*') << endl;
+ switch (reason) {
+ case AbstractMetaBuilder::NotInTypeSystem:
+ s << "Not in type system";
+ break;
+ case AbstractMetaBuilder::GenerationDisabled:
+ s << "Generation disabled by type system";
+ break;
+ case AbstractMetaBuilder::RedefinedToNotClass:
+ s << "Type redefined to not be a class";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedReturnType:
+ s << "Unmatched return type";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedArgumentType:
+ s << "Unmatched argument type";
+ break;
+
+ default:
+ s << "unknown reason";
+ break;
+ }
+
+ s << endl;
+
+ for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin();
+ it != rejects.constEnd(); ++it) {
+ if (it.value() != reason)
+ continue;
+ s << " - " << it.key() << endl;
+ }
+
+ s << QString(72, '*') << endl << endl;
+ }
+
+}
+
+
+void AbstractMetaBuilder::dumpLog()
+{
+ writeRejectLogFile("mjb_rejected_classes.log", m_rejectedClasses);
+ writeRejectLogFile("mjb_rejected_enums.log", m_rejectedEnums);
+ writeRejectLogFile("mjb_rejected_functions.log", m_rejectedFunctions);
+ writeRejectLogFile("mjb_rejected_fields.log", m_rejectedFields);
+}
+
+AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const AbstractMetaClass* cppClass) const
+{
+ using namespace boost;
+
+ AbstractMetaClassList result;
+ QList<int> unmappedResult;
+ QSet<QPair<int, int> > deps;
+ QHash<QString, int> map;
+ QHash<int, AbstractMetaClass*> reverseMap;
+
+ AbstractMetaClassList classList;
+ if (cppClass)
+ classList = cppClass->innerClasses();
+ else
+ classList = m_metaClasses;
+
+ int i = 0;
+ foreach (AbstractMetaClass* clazz, classList) {
+ map[clazz->name()] = i;
+ reverseMap[i] = clazz;
+ i++;
+ }
+
+ // TODO choose a better name to these regexs
+ QRegExp regex1("\\(.*\\)");
+ QRegExp regex2("::.*");
+ foreach (AbstractMetaClass* clazz, classList) {
+ if (clazz->isInterface() || !clazz->typeEntry()->generateCode())
+ continue;
+
+ // check base class dep.
+ QString baseClassName(clazz->baseClassName());
+ if (!baseClassName.isNull() && baseClassName != clazz->name() && map.contains(baseClassName)) {
+ if (clazz->baseClass()->enclosingClass() &&
+ clazz->baseClass()->enclosingClass() != clazz->enclosingClass()) {
+ baseClassName = clazz->baseClass()->enclosingClass()->name();
+ }
+ deps << qMakePair(map[clazz->name()], map[baseClassName]);
+ }
+
+ // interfaces...
+ foreach (AbstractMetaClass* interface, clazz->interfaces()) {
+ if (!interface->typeEntry()->generateCode())
+ continue;
+
+ if (interface->isInterface())
+ interface = interface->primaryInterfaceImplementor();
+
+ if (interface->enclosingClass() &&
+ interface->enclosingClass() != clazz->enclosingClass()) {
+ baseClassName = interface->enclosingClass()->name();
+ } else {
+ baseClassName = interface->name();
+ }
+
+ if (!baseClassName.isNull() && baseClassName != clazz->name() && map.contains(baseClassName))
+ deps << qMakePair(map[clazz->name()], map[baseClassName]);
+ }
+
+ foreach (AbstractMetaFunction* func, clazz->functions()) {
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ // check methods with default args
+ QString defaultExpression = arg->originalDefaultValueExpression();
+ if (!defaultExpression.isEmpty()) {
+ defaultExpression.replace(regex1, "");
+ defaultExpression.replace(regex2, "");
+ }
+ if (!defaultExpression.isEmpty() && defaultExpression != clazz->name() && map.contains(defaultExpression))
+ deps << qMakePair(map[clazz->name()], map[defaultExpression]);
+ }
+ }
+ }
+
+ // dot output for debug.
+// typedef QPair<int, int> ABC;
+// qDebug() << "digraph G { ";
+// foreach (ABC p, deps) {
+// TypeEntry* typeEntry = TypeDatabase::instance()->findType(reverseMap[p.second]->name());
+// if (typeEntry && !typeEntry->generateCode())
+// continue;
+// qDebug() << reverseMap[p.first]->name() << " -> " << reverseMap[p.second]->name();
+// }
+// qDebug() << "}";
+
+
+ typedef adjacency_list <vecS, vecS, directedS> Graph;
+ Graph g(deps.begin(), deps.end(), classList.count());
+ topological_sort(g, std::back_inserter(unmappedResult));
+
+ foreach (int i, unmappedResult) {
+ Q_ASSERT(reverseMap.contains(i));
+ if (!reverseMap[i]->isInterface())
+ result << reverseMap[i];
+ }
+
+ return result;
+}
+
+
+AbstractMetaArgumentList AbstractMetaBuilder::reverseList(const AbstractMetaArgumentList& list)
+{
+ AbstractMetaArgumentList ret;
+
+ int index = list.size();
+ foreach (AbstractMetaArgument *arg, list) {
+ arg->setArgumentIndex(index);
+ ret.prepend(arg);
+ index--;
+ }
+
+ return ret;
+}
diff --git a/abstractmetabuilder.h b/abstractmetabuilder.h
new file mode 100644
index 000000000..3cc5f3cee
--- /dev/null
+++ b/abstractmetabuilder.h
@@ -0,0 +1,225 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef ABSTRACTMETABUILDER_H
+#define ABSTRACTMETABUILDER_H
+
+#include "parser/codemodel.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+#include "typeparser.h"
+
+#include <QtCore/QSet>
+
+class AbstractMetaBuilder
+{
+public:
+ enum RejectReason {
+ NotInTypeSystem,
+ GenerationDisabled,
+ RedefinedToNotClass,
+ UnmatchedArgumentType,
+ UnmatchedReturnType,
+ NoReason
+ };
+
+ AbstractMetaBuilder();
+ virtual ~AbstractMetaBuilder();
+
+ AbstractMetaClassList classes() const
+ {
+ return m_metaClasses;
+ }
+ /**
+ * Sorts a list of classes topologically, if an AbstractMetaClass object
+ * is passed the list of classes will be its inner classes, otherwise
+ * the list will be the module global classes.
+ * \return a list of classes sorted topologically
+ */
+ AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass* cppClass = 0) const;
+
+ FileModelItem model() const
+ {
+ return m_dom;
+ }
+
+ void setModel(FileModelItem item)
+ {
+ m_dom = item;
+ }
+
+ ScopeModelItem popScope()
+ {
+ return m_scopes.takeLast();
+ }
+
+ void pushScope(ScopeModelItem item)
+ {
+ m_scopes << item;
+ }
+
+ ScopeModelItem currentScope() const
+ {
+ return m_scopes.last();
+ }
+
+ void dumpLog();
+
+ bool build(QIODevice* input);
+
+ void figureOutEnumValuesForClass(AbstractMetaClass *metaClass, QSet<AbstractMetaClass *> *classes);
+ int figureOutEnumValue(const QString &name, int value, AbstractMetaEnum *meta_enum, AbstractMetaFunction *metaFunction = 0);
+ void figureOutEnumValues();
+ void figureOutDefaultEnumArguments();
+
+ void addAbstractMetaClass(AbstractMetaClass *cls);
+ AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item);
+ AbstractMetaClass *traverseClass(ClassModelItem item);
+ bool setupInheritance(AbstractMetaClass *metaClass);
+ AbstractMetaClass *traverseNamespace(NamespaceModelItem item);
+ AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing, const QSet<QString> &enumsDeclarations);
+ void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent, const QStringList &enumsDeclarations);
+ void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent);
+ void applyFunctionModifications(AbstractMetaFunction* func);
+ void traverseFields(ScopeModelItem item, AbstractMetaClass *parent);
+ void traverseStreamOperator(FunctionModelItem functionItem);
+ void traverseOperatorFunction(FunctionModelItem item);
+ AbstractMetaFunction *traverseFunction(FunctionModelItem function);
+ AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls);
+ void checkFunctionModifications();
+ void registerHashFunction(FunctionModelItem functionItem);
+ void registerToStringCapability(FunctionModelItem functionItem);
+
+ void parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations);
+ void setupEquals(AbstractMetaClass *metaClass);
+ void setupComparable(AbstractMetaClass *metaClass);
+ void setupClonable(AbstractMetaClass *cls);
+ void setupFunctionDefaults(AbstractMetaFunction *metaFunction, AbstractMetaClass *metaClass);
+
+ QString translateDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
+ AbstractMetaFunction *fnc, AbstractMetaClass *,
+ int argumentIndex);
+ AbstractMetaType *translateType(const TypeInfo &type, bool *ok, bool resolveType = true, bool resolveScope = true);
+
+ void decideUsagePattern(AbstractMetaType *type);
+
+ const AbstractMetaFunctionList globalFunctions() const
+ {
+ return m_globalFunctions;
+ }
+
+ const AbstractMetaEnumList globalEnums() const
+ {
+ return m_globalEnums;
+ }
+
+ bool inheritTemplate(AbstractMetaClass *subclass,
+ const AbstractMetaClass *templateClass,
+ const TypeParser::Info &info);
+ AbstractMetaType *inheritTemplateType(const QList<AbstractMetaType *> &templateTypes, AbstractMetaType *metaType, bool *ok = 0);
+
+ bool isQObject(const QString &qualifiedName);
+ bool isEnum(const QStringList &qualifiedName);
+
+ void fixQObjectForScope(TypeDatabase *types,
+ NamespaceModelItem item);
+
+ // QtScript
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const
+ {
+ return m_qmetatypeDeclaredTypenames;
+ }
+
+protected:
+ AbstractMetaClass *argumentToClass(ArgumentModelItem);
+
+ virtual AbstractMetaClass *createMetaClass()
+ {
+ return new AbstractMetaClass();
+ }
+
+ virtual AbstractMetaEnum *createMetaEnum()
+ {
+ return new AbstractMetaEnum();
+ }
+
+ virtual AbstractMetaEnumValue *createMetaEnumValue()
+ {
+ return new AbstractMetaEnumValue();
+ }
+
+ virtual AbstractMetaField *createMetaField()
+ {
+ return new AbstractMetaField();
+ }
+
+ virtual AbstractMetaFunction *createMetaFunction()
+ {
+ return new AbstractMetaFunction();
+ }
+
+ virtual AbstractMetaArgument *createMetaArgument()
+ {
+ return new AbstractMetaArgument();
+ }
+
+ virtual AbstractMetaType *createMetaType()
+ {
+ return new AbstractMetaType();
+ }
+
+ FileModelItem m_dom;
+
+private:
+ void sortLists();
+ AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList& list);
+
+ AbstractMetaClassList m_metaClasses;
+ AbstractMetaClassList m_templates;
+ AbstractMetaFunctionList m_globalFunctions;
+ AbstractMetaEnumList m_globalEnums;
+
+ QSet<const TypeEntry *> m_usedTypes;
+
+ QMap<QString, RejectReason> m_rejectedClasses;
+ QMap<QString, RejectReason> m_rejectedEnums;
+ QMap<QString, RejectReason> m_rejectedFunctions;
+ QMap<QString, RejectReason> m_rejectedFields;
+
+ QList<AbstractMetaEnum *> m_enums;
+
+ QList<QPair<AbstractMetaArgument *, AbstractMetaFunction *> > m_enumDefaultArguments;
+
+ QHash<QString, AbstractMetaEnumValue *> m_enumValues;
+
+ AbstractMetaClass *m_currentClass;
+ QList<ScopeModelItem> m_scopes;
+ QString m_namespacePrefix;
+
+ QSet<AbstractMetaClass *> m_setupInheritanceDone;
+
+ // QtScript
+ QSet<QString> m_qmetatypeDeclaredTypenames;
+};
+
+#endif // ABSTRACTMETBUILDER_H
diff --git a/abstractmetalang.cpp b/abstractmetalang.cpp
new file mode 100644
index 000000000..a789b9eb6
--- /dev/null
+++ b/abstractmetalang.cpp
@@ -0,0 +1,2175 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+
+/*******************************************************************************
+ * AbstractMetaType
+ */
+AbstractMetaType *AbstractMetaType::copy() const
+{
+ AbstractMetaType *cpy = new AbstractMetaType;
+
+ cpy->setTypeUsagePattern(typeUsagePattern());
+ cpy->setConstant(isConstant());
+ cpy->setReference(isReference());
+ cpy->setIndirections(indirections());
+ cpy->setInstantiations(instantiations());
+ cpy->setArrayElementCount(arrayElementCount());
+ cpy->setOriginalTypeDescription(originalTypeDescription());
+ cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0);
+
+ cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : 0);
+
+ cpy->setTypeEntry(typeEntry());
+
+ return cpy;
+}
+
+QString AbstractMetaType::cppSignature() const
+{
+ QString s;
+
+ if (isConstant())
+ s += "const ";
+
+ s += typeEntry()->qualifiedCppName();
+
+ if (hasInstantiationInCpp()) {
+ QList<AbstractMetaType *> types = instantiations();
+ s += "<";
+ for (int i = 0; i < types.count(); ++i) {
+ if (i > 0)
+ s += ", ";
+ s += types.at(i)->cppSignature();
+ }
+ s += " >";
+ }
+
+ if (actualIndirections()) {
+ s += ' ';
+ if (indirections())
+ s += QString(indirections(), '*');
+ if (isReference())
+ s += '&';
+ }
+ return s;
+}
+
+/*******************************************************************************
+ * AbstractMetaArgument
+ */
+AbstractMetaArgument *AbstractMetaArgument::copy() const
+{
+ AbstractMetaArgument *cpy = new AbstractMetaArgument;
+ cpy->setName(AbstractMetaVariable::name());
+ cpy->setDefaultValueExpression(defaultValueExpression());
+ cpy->setOriginalDefaultValueExpression(originalDefaultValueExpression());
+ cpy->setType(type()->copy());
+ cpy->setArgumentIndex(argumentIndex());
+
+ return cpy;
+}
+
+
+QString AbstractMetaArgument::argumentName() const
+{
+ QString n = AbstractMetaVariable::name();
+ if (n.isEmpty())
+ return QString("arg__%2").arg(m_argumentIndex + 1);
+ return n;
+}
+
+
+QString AbstractMetaArgument::indexedName() const
+{
+ QString n = AbstractMetaVariable::name();
+ if (n.isEmpty())
+ return argumentName();
+ return QString("%1%2").arg(n).arg(m_argumentIndex);
+}
+
+QString AbstractMetaArgument::name() const
+{
+ Q_ASSERT_X(0, "AbstractMetaArgument::name()", "use argumentName() or indexedName() instead");
+ return QString();
+}
+
+
+/*******************************************************************************
+ * AbstractMetaFunction
+ */
+AbstractMetaFunction::~AbstractMetaFunction()
+{
+ qDeleteAll(m_arguments);
+ delete m_type;
+}
+
+/*******************************************************************************
+ * Indicates that this function has a modification that removes it
+ */
+bool AbstractMetaFunction::isModifiedRemoved(int types) const
+{
+ FunctionModificationList mods = modifications(implementingClass());
+ foreach (FunctionModification mod, mods) {
+ if (!mod.isRemoveModifier())
+ continue;
+
+ if ((mod.removal & types) == types)
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::needsCallThrough() const
+{
+ if (ownerClass()->isInterface())
+ return false;
+ if (referenceCounts(implementingClass()).size() > 0)
+ return true;
+ if (argumentsHaveNativeId() || !isStatic())
+ return true;
+
+ foreach (const AbstractMetaArgument *arg, arguments()) {
+ if (arg->type()->isArray() || arg->type()->isTargetLangEnum() || arg->type()->isTargetLangFlags())
+ return true;
+ }
+
+ if (type() && (type()->isArray() || type()->isTargetLangEnum() || type()->isTargetLangFlags()))
+ return true;
+
+ for (int i = -1; i <= arguments().size(); ++i) {
+ TypeSystem::Ownership owner = this->ownership(implementingClass(), TypeSystem::TargetLangCode, i);
+ if (owner != TypeSystem::InvalidOwnership)
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::needsSuppressUncheckedWarning() const
+{
+ for (int i = -1; i <= arguments().size(); ++i) {
+ QList<ReferenceCount> referenceCounts = this->referenceCounts(implementingClass(), i);
+ foreach (ReferenceCount referenceCount, referenceCounts) {
+ if (referenceCount.action != ReferenceCount::Set)
+ return true;
+ }
+ }
+ return false;
+}
+
+QString AbstractMetaFunction::marshalledName() const
+{
+ QString returned = "__qt_" + name();
+ AbstractMetaArgumentList arguments = this->arguments();
+ foreach (const AbstractMetaArgument *arg, arguments) {
+ returned += "_";
+ if (arg->type()->isNativePointer())
+ returned += "nativepointer";
+ else if (arg->type()->isIntegerEnum() || arg->type()->isIntegerFlags())
+ returned += "int";
+ else
+ returned += arg->type()->name().replace("[]", "_3").replace(".", "_");
+ }
+ return returned;
+}
+
+bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const
+{
+ uint result = compareTo(&other);
+ return result & NameLessThan;
+}
+
+
+/*!
+ Returns a mask of CompareResult describing how this function is
+ compares to another function
+*/
+uint AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const
+{
+ uint result = 0;
+
+ // Enclosing class...
+ if (ownerClass() == other->ownerClass())
+ result |= EqualImplementor;
+
+ // Attributes
+ if (attributes() == other->attributes())
+ result |= EqualAttributes;
+
+ // Compare types
+ AbstractMetaType *t = type();
+ AbstractMetaType *ot = other->type();
+ if ((!t && !ot) || ((t && ot && t->name() == ot->name())))
+ result |= EqualReturnType;
+
+ // Compare names
+ int cmp = originalName().compare(other->originalName());
+
+ if (cmp < 0)
+ result |= NameLessThan;
+ else if (!cmp)
+ result |= EqualName;
+
+ // compare name after modification...
+ cmp = modifiedName().compare(other->modifiedName());
+ if (!cmp)
+ result |= EqualModifiedName;
+
+ // Compare arguments...
+ AbstractMetaArgumentList minArguments;
+ AbstractMetaArgumentList maxArguments;
+ if (arguments().size() < other->arguments().size()) {
+ minArguments = arguments();
+ maxArguments = other->arguments();
+ } else {
+ minArguments = other->arguments();
+ maxArguments = arguments();
+ }
+
+ int minCount = minArguments.size();
+ int maxCount = maxArguments.size();
+ bool same = true;
+ for (int i = 0; i < maxCount; ++i) {
+ if (i < minCount) {
+ const AbstractMetaArgument *min_arg = minArguments.at(i);
+ const AbstractMetaArgument *max_arg = maxArguments.at(i);
+ if (min_arg->type()->name() != max_arg->type()->name()
+ && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) {
+ same = false;
+ break;
+ }
+ } else {
+ if (maxArguments.at(i)->defaultValueExpression().isEmpty()) {
+ same = false;
+ break;
+ }
+ }
+ }
+
+ if (same)
+ result |= minCount == maxCount ? EqualArguments : EqualDefaultValueOverload;
+
+ return result;
+}
+
+AbstractMetaFunction *AbstractMetaFunction::copy() const
+{
+ AbstractMetaFunction *cpy = new AbstractMetaFunction;
+ cpy->setName(name());
+ cpy->setOriginalName(originalName());
+ cpy->setOwnerClass(ownerClass());
+ cpy->setImplementingClass(implementingClass());
+ cpy->setInterfaceClass(interfaceClass());
+ cpy->setFunctionType(functionType());
+ cpy->setAttributes(attributes());
+ cpy->setDeclaringClass(declaringClass());
+ if (type())
+ cpy->setType(type()->copy());
+ cpy->setConstant(isConstant());
+ cpy->setOriginalAttributes(originalAttributes());
+
+ foreach (AbstractMetaArgument *arg, arguments())
+ cpy->addArgument(arg->copy());
+
+ Q_ASSERT((!type() && !cpy->type())
+ || (type()->instantiations() == cpy->type()->instantiations()));
+
+ return cpy;
+}
+
+QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const
+{
+ AbstractMetaArgumentList arguments = this->arguments();
+ if (arguments.size() == resolvedArguments.size()) {
+ return (QStringList() << QMetaObject::normalizedSignature((name() + "(" + resolvedArguments.join(",") + ")").toUtf8().constData()));
+ } else {
+ QStringList returned;
+
+ AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
+ QStringList minimalTypeSignature = argument->type()->minimalSignature().split("::");
+ for (int i = 0; i < minimalTypeSignature.size(); ++i) {
+ returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
+ << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join("::"));
+ }
+
+ return returned;
+ }
+}
+
+QString AbstractMetaFunction::signature() const
+{
+ QString s(m_originalName);
+
+ s += "(";
+
+ for (int i = 0; i < m_arguments.count(); ++i) {
+ if (i > 0)
+ s += ", ";
+ AbstractMetaArgument *a = m_arguments.at(i);
+ s += a->type()->cppSignature();
+
+ // We need to have the argument names in the qdoc files
+ s += " ";
+ s += a->argumentName();
+ }
+ s += ")";
+
+ if (isConstant())
+ s += " const";
+
+ return s;
+}
+
+int AbstractMetaFunction::actualMinimumArgumentCount() const
+{
+ AbstractMetaArgumentList arguments = this->arguments();
+
+ int count = 0;
+ for (int i = 0; i < arguments.size(); ++i && ++count) {
+ if (argumentRemoved(i + 1))
+ --count;
+ else if (!arguments.at(i)->defaultValueExpression().isEmpty())
+ break;
+ }
+
+ return count;
+}
+
+// Returns reference counts for argument at idx, or all arguments if idx == -2
+QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const
+{
+ QList<ReferenceCount> returned;
+
+ FunctionModificationList mods = this->modifications(cls);
+ foreach (FunctionModification mod, mods) {
+ QList<ArgumentModification> argumentMods = mod.argument_mods;
+ foreach (ArgumentModification argumentMod, argumentMods) {
+ if (argumentMod.index != idx && idx != -2)
+ continue;
+ returned += argumentMod.referenceCounts;
+ }
+ }
+
+ return returned;
+}
+
+
+ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const
+{
+ FunctionModificationList mods = this->modifications(cls);
+ foreach (FunctionModification mod, mods) {
+ QList<ArgumentModification> argumentMods = mod.argument_mods;
+ foreach (ArgumentModification argumentMod, argumentMods) {
+ if (argumentMod.index != idx)
+ continue;
+ return argumentMod.owner;
+ }
+ }
+ return ArgumentOwner();
+}
+
+
+QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const
+{
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key
+ && !argumentModification.replacedDefaultExpression.isEmpty()) {
+ return argumentModification.replacedDefaultExpression;
+ }
+ }
+ }
+
+ return QString();
+}
+
+bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const
+{
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key
+ && argumentModification.removedDefaultExpression) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::resetObjectAfterUse(int argumentIdx) const
+{
+ const AbstractMetaClass *cls = declaringClass();
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == argumentIdx && argumentModification.resetAfterUse)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QString AbstractMetaFunction::nullPointerDefaultValue(const AbstractMetaClass *mainClass, int argumentIdx) const
+{
+ Q_ASSERT(nullPointersDisabled(mainClass, argumentIdx));
+
+ const AbstractMetaClass *cls = mainClass;
+ if (!cls)
+ cls = implementingClass();
+
+ do {
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == argumentIdx
+ && argumentModification.noNullPointers) {
+ return argumentModification.nullPointerDefaultValue;
+ }
+ }
+ }
+ cls = cls->baseClass();
+ } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class
+
+ return QString();
+
+}
+
+bool AbstractMetaFunction::nullPointersDisabled(const AbstractMetaClass *mainClass, int argumentIdx) const
+{
+ const AbstractMetaClass *cls = mainClass;
+ if (!cls)
+ cls = implementingClass();
+
+ do {
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == argumentIdx
+ && argumentModification.noNullPointers) {
+ return true;
+ }
+ }
+ }
+
+ cls = cls->baseClass();
+ } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class
+
+ return false;
+}
+
+QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index != key)
+ continue;
+
+ foreach (CodeSnip snip, argumentModification.conversion_rules) {
+ if (snip.language == language && !snip.code().isEmpty())
+ return snip.code();
+ }
+ }
+ }
+
+ return QString();
+}
+
+QString AbstractMetaFunction::argumentReplaced(int key) const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key && !argumentModification.replace_value.isEmpty())
+ return argumentModification.replace_value;
+ }
+ }
+
+ return "";
+}
+
+// FIXME If we remove a arg. in the method at the base class, it will not reflect here.
+bool AbstractMetaFunction::argumentRemoved(int key) const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key) {
+ if (argumentModification.removed)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::isVirtualSlot() const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ if (modification.isVirtualSlot())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::disabledGarbageCollection(const AbstractMetaClass *cls, int key) const
+{
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index != key)
+ continue;
+
+ foreach (TypeSystem::Ownership ownership, argumentModification.ownerships.values()) {
+ if (ownership == TypeSystem::CppOwnership)
+ return true;
+ }
+
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::isDeprecated() const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ if (modification.isDeprecated())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isThread() const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ if (modification.isThread())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::allowThread() const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ if (modification.allowThread())
+ return true;
+ }
+ return false;
+}
+
+
+TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
+{
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key)
+ return argumentModification.ownerships.value(language, TypeSystem::InvalidOwnership);
+ }
+ }
+
+ return TypeSystem::InvalidOwnership;
+}
+
+bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const
+{
+ return isRemovedFrom(cls, TypeSystem::All);
+}
+
+bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const
+{
+ FunctionModificationList modifications = this->modifications(cls);
+ foreach (FunctionModification modification, modifications) {
+ if ((modification.removal & language) == language)
+ return true;
+ }
+
+ return false;
+
+}
+
+QString AbstractMetaFunction::typeReplaced(int key) const
+{
+ FunctionModificationList modifications = this->modifications(declaringClass());
+ foreach (FunctionModification modification, modifications) {
+ QList<ArgumentModification> argumentModifications = modification.argument_mods;
+ foreach (ArgumentModification argumentModification, argumentModifications) {
+ if (argumentModification.index == key
+ && !argumentModification.modified_type.isEmpty()) {
+ return argumentModification.modified_type;
+ }
+ }
+ }
+
+ return QString();
+}
+
+QString AbstractMetaFunction::minimalSignature() const
+{
+ if (!m_cachedMinimalSignature.isEmpty())
+ return m_cachedMinimalSignature;
+
+ QString minimalSignature = originalName() + "(";
+ AbstractMetaArgumentList arguments = this->arguments();
+
+ for (int i = 0; i < arguments.count(); ++i) {
+ AbstractMetaType *t = arguments.at(i)->type();
+
+ if (i > 0)
+ minimalSignature += ",";
+
+ minimalSignature += t->minimalSignature();
+ }
+ minimalSignature += ")";
+ if (isConstant())
+ minimalSignature += "const";
+
+ minimalSignature = QMetaObject::normalizedSignature(minimalSignature.toLocal8Bit().constData());
+ m_cachedMinimalSignature = minimalSignature;
+
+ return minimalSignature;
+}
+
+FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const
+{
+ // FIXME Global functions do not support modifications
+ if (!implementor)
+ return FunctionModificationList();
+ return implementor->typeEntry()->functionModifications(minimalSignature());
+}
+
+bool AbstractMetaFunction::hasModifications(const AbstractMetaClass *implementor) const
+{
+ return !modifications(implementor).isEmpty();
+}
+
+bool AbstractMetaFunction::hasInjectedCode() const
+{
+ foreach (const FunctionModification mod, modifications(ownerClass())) {
+ if (mod.isCodeInjection())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::hasSignatureModifications() const
+{
+ foreach (const FunctionModification mod, modifications(ownerClass())) {
+ foreach (const ArgumentModification argmod, mod.argument_mods) {
+ // since zero represents the return type and we're
+ // interested only in checking the function arguments,
+ // it will be ignored.
+ if (argmod.index > 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isConversionOperator(QString funcName)
+{
+ QRegExp opRegEx("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$");
+ return opRegEx.indexIn(funcName) > -1;
+}
+
+bool AbstractMetaFunction::isOperatorOverload(QString funcName)
+{
+ if (isConversionOperator(funcName))
+ return true;
+
+ QRegExp opRegEx("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?"
+ "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~"
+ "|\\[\\]|\\s+delete\\[?\\]?"
+ "|\\s+new\\[?\\]?)$");
+ return opRegEx.indexIn(funcName) > -1;
+}
+
+bool AbstractMetaFunction::isArithmeticOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == "operator+" || name == "operator+="
+ || name == "operator-" || name == "operator-="
+ || name == "operator*" || name == "operator*="
+ || name == "operator/" || name == "operator/="
+ || name == "operator%" || name == "operator%="
+ || name == "operator++" || name == "operator--";
+}
+
+bool AbstractMetaFunction::isBitwiseOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == "operator<<" || name == "operator<<="
+ || name == "operator>>" || name == "operator>>="
+ || name == "operator&" || name == "operator&="
+ || name == "operator|" || name == "operator|="
+ || name == "operator^" || name == "operator^="
+ || name == "operator~";
+}
+
+bool AbstractMetaFunction::isComparisonOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == "operator<" || name == "operator<="
+ || name == "operator>" || name == "operator>="
+ || name == "operator==" || name == "operator!=";
+}
+
+bool AbstractMetaFunction::isLogicalOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == "operator!"
+ || name == "operator&&"
+ || name == "operator||";
+}
+
+bool AbstractMetaFunction::isSubscriptOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ return originalName() == "operator[]";
+}
+
+bool AbstractMetaFunction::isAssignmentOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ return originalName() == "operator=";
+}
+
+bool AbstractMetaFunction::isOtherOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ return !isArithmeticOperator()
+ && !isBitwiseOperator()
+ && !isComparisonOperator()
+ && !isLogicalOperator()
+ && !isConversionOperator()
+ && !isSubscriptOperator()
+ && !isAssignmentOperator();
+}
+
+int AbstractMetaFunction::arityOfOperator() const
+{
+ if (!isOperatorOverload())
+ return -1;
+
+ int arity = m_arguments.size();
+
+ // Operator overloads that are class members
+ // implicitly includes the instance and have
+ // one parameter less than their arity,
+ // so we increment it.
+ if (ownerClass() && arity < 2)
+ arity++;
+
+ return arity;
+}
+
+bool AbstractMetaFunction::isInplaceOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == "operator+=" || name == "operator&="
+ || name == "operator-=" || name == "operator|="
+ || name == "operator*=" || name == "operator^="
+ || name == "operator/=" || name == "operator<<="
+ || name == "operator%=" || name == "operator>>=";
+}
+
+bool AbstractMetaFunction::isVirtual() const
+{
+ return !isFinal() && !isSignal() && !isStatic() && !isFinalInCpp();
+}
+
+bool AbstractMetaFunction::isCopyConstructor() const
+{
+ if (!ownerClass() || !isConstructor() || arguments().count() != 1)
+ return false;
+
+ const AbstractMetaType* type = arguments().first()->type();
+ return type->typeEntry() == ownerClass()->typeEntry() &&
+ type->isConstant() && type->isReference();
+}
+
+QString AbstractMetaFunction::modifiedName() const
+{
+ if (m_cachedModifiedName.isEmpty()) {
+ FunctionModificationList mods = modifications(implementingClass());
+ foreach (FunctionModification mod, mods) {
+ if (mod.isRenameModifier()) {
+ m_cachedModifiedName = mod.renamedToName;
+ break;
+ }
+ }
+ if (m_cachedModifiedName.isEmpty())
+ m_cachedModifiedName = name();
+ }
+ return m_cachedModifiedName;
+}
+
+QString AbstractMetaFunction::targetLangSignature(bool minimal) const
+{
+ QString s;
+
+ // Attributes...
+ if (!minimal) {
+ // Return type
+ if (type())
+ s += type()->name() + " ";
+ else
+ s += "void ";
+ }
+
+ s += modifiedName();
+ s += "(";
+
+ int j = 0;
+ for (int i = 0; i < m_arguments.size(); ++i) {
+ if (argumentRemoved(i + 1))
+ continue;
+ if (j) {
+ s += ",";
+ if (!minimal)
+ s += QLatin1Char(' ');
+ }
+ s += m_arguments.at(i)->type()->name();
+
+ if (!minimal) {
+ s += " ";
+ s += m_arguments.at(i)->argumentName();
+ }
+ ++j;
+ }
+
+ s += ")";
+
+ return s;
+}
+
+
+bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
+{
+ return a->signature() < b->signature();
+}
+
+/*******************************************************************************
+ * AbstractMetaClass
+ */
+AbstractMetaClass::~AbstractMetaClass()
+{
+ qDeleteAll(m_functions);
+ qDeleteAll(m_fields);
+}
+
+/*******************************************************************************
+ * Returns true if this class is a subclass of the given class
+ */
+bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const
+{
+ Q_ASSERT(cls);
+
+ const AbstractMetaClass *clazz = this;
+ while (clazz) {
+ if (clazz == cls)
+ return true;
+
+ clazz = clazz->baseClass();
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ * Constructs an interface based on the functions and enums in this
+ * class and returns it...
+ */
+AbstractMetaClass *AbstractMetaClass::extractInterface()
+{
+ Q_ASSERT(typeEntry()->designatedInterface());
+
+ if (!m_extractedInterface) {
+ AbstractMetaClass *iface = new AbstractMetaClass;
+ iface->setAttributes(attributes());
+ iface->setBaseClass(0);
+ iface->setPrimaryInterfaceImplementor(this);
+
+ iface->setTypeEntry(typeEntry()->designatedInterface());
+
+ foreach (AbstractMetaFunction *function, functions()) {
+ if (!function->isConstructor())
+ iface->addFunction(function->copy());
+ }
+
+// iface->setEnums(enums());
+// setEnums(AbstractMetaEnumList());
+
+ foreach (const AbstractMetaField *field, fields()) {
+ if (field->isPublic()) {
+ AbstractMetaField *new_field = field->copy();
+ new_field->setEnclosingClass(iface);
+ iface->addField(new_field);
+ }
+ }
+
+ m_extractedInterface = iface;
+ addInterface(iface);
+ }
+
+ return m_extractedInterface;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions with a given name
+ */
+AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const
+{
+ AbstractMetaFunctionList returned;
+ AbstractMetaFunctionList functions = this->functions();
+ foreach (AbstractMetaFunction *function, functions) {
+ if (function->name() == name)
+ returned.append(function);
+ }
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns all reference count modifications for any function in the class
+ */
+QList<ReferenceCount> AbstractMetaClass::referenceCounts() const
+{
+ QList<ReferenceCount> returned;
+
+ AbstractMetaFunctionList functions = this->functions();
+ foreach (AbstractMetaFunction *function, functions)
+ returned += function->referenceCounts(this);
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions retrieved during parsing which should
+ * be added to the API.
+ */
+AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const
+{
+ int default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang;
+
+ // Interfaces don't implement functions
+ default_flags |= isInterface() ? 0 : ClassImplements;
+
+ // Only public functions in final classes
+ // default_flags |= isFinal() ? WasPublic : 0;
+ int public_flags = isFinal() ? WasPublic : 0;
+
+ // Constructors
+ AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags);
+
+ // Final functions
+ returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
+
+ // Virtual functions
+ returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
+
+ // Static functions
+ returned += queryFunctions(StaticFunctions | default_flags | public_flags);
+
+ // Empty, private functions, since they aren't caught by the other ones
+ returned += queryFunctions(Empty | Invisible);
+
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::virtualFunctions() const
+{
+ AbstractMetaFunctionList list = functionsInShellClass();
+
+ AbstractMetaFunctionList returned;
+ foreach (AbstractMetaFunction *f, list) {
+ if (!f->isFinalInCpp() || f->isVirtualSlot())
+ returned += f;
+ }
+
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::nonVirtualShellFunctions() const
+{
+ AbstractMetaFunctionList list = functionsInShellClass();
+ AbstractMetaFunctionList returned;
+ foreach (AbstractMetaFunction *f, list) {
+ if (f->isFinalInCpp() && !f->isVirtualSlot())
+ returned += f;
+ }
+
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::implicitConversions() const
+{
+ AbstractMetaFunctionList list = queryFunctions(Constructors);
+ AbstractMetaFunctionList returned;
+ foreach (AbstractMetaFunction *f, list) {
+ if (f->arguments().size() == 1 && !f->isExplicit() && !f->isCopyConstructor() && hasCloneOperator())
+ returned += f;
+ }
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::operatorOverloads(uint query) const
+{
+ AbstractMetaFunctionList list = queryFunctions(OperatorOverloads);
+ AbstractMetaFunctionList returned;
+ foreach (AbstractMetaFunction *f, list) {
+ if (((query & ArithmeticOp) && f->isArithmeticOperator())
+ || ((query & BitwiseOp) && f->isBitwiseOperator())
+ || ((query & ComparisonOp) && f->isComparisonOperator())
+ || ((query & LogicalOp) && f->isLogicalOperator())
+ || ((query & SubscriptionOp) && f->isSubscriptOperator())
+ || ((query & AssignmentOp) && f->isAssignmentOperator())
+ || ((query & ConversionOp) && f->isConversionOperator())
+ || ((query & OtherOp) && f->isOtherOperator()))
+ returned += f;
+ }
+
+ return returned;
+}
+
+bool AbstractMetaClass::hasOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isOperatorOverload())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasArithmeticOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isArithmeticOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasBitwiseOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isBitwiseOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasComparisonOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isComparisonOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasLogicalOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isLogicalOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasSubscriptOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isSubscriptOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasAssignmentOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isAssignmentOperator())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasConversionOperatorOverload() const
+{
+ foreach (const AbstractMetaFunction *f, m_functions) {
+ if (f->isConversionOperator())
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ * Returns a list of all functions that should be declared and implemented in
+ * the shell class which is generated as a wrapper on top of the actual C++ class
+ */
+AbstractMetaFunctionList AbstractMetaClass::functionsInShellClass() const
+{
+ // Only functions and only protected and public functions
+ int default_flags = NormalFunctions | Visible | WasVisible | NotRemovedFromShell;
+
+ // All virtual functions
+ AbstractMetaFunctionList returned = queryFunctions(VirtualFunctions | default_flags);
+
+ // All functions explicitly set to be implemented by the shell class
+ // (mainly superclass functions that are hidden by other declarations)
+ returned += queryFunctions(ForcedShellFunctions | default_flags);
+
+ // All functions explicitly set to be virtual slots
+ returned += queryFunctions(VirtualSlots | default_flags);
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns a list of all functions that require a public override function to
+ * be generated in the shell class. This includes all functions that were originally
+ * protected in the superclass.
+ */
+AbstractMetaFunctionList AbstractMetaClass::publicOverrideFunctions() const
+{
+ return queryFunctions(NormalFunctions | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang)
+ + queryFunctions(Signals | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang);
+}
+
+AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const
+{
+ return queryFunctions(NormalFunctions | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell) +
+ queryFunctions(Signals | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell);
+}
+
+void AbstractMetaClass::sortFunctions()
+{
+ qSort(m_functions.begin(), m_functions.end(), function_sorter);
+}
+
+void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
+{
+ m_functions = functions;
+
+ // Functions must be sorted by name before next loop
+ sortFunctions();
+
+ QString currentName;
+ bool hasVirtuals = false;
+ AbstractMetaFunctionList finalFunctions;
+ foreach (AbstractMetaFunction *f, m_functions) {
+ f->setOwnerClass(this);
+
+ m_hasVirtualSlots |= f->isVirtualSlot();
+ m_hasVirtuals |= !f->isFinal() || f->isVirtualSlot();
+ m_isPolymorphic |= m_hasVirtuals;
+ m_hasNonpublic |= !f->isPublic();
+
+ // If we have non-virtual overloads of a virtual function, we have to implement
+ // all the overloads in the shell class to override the hiding rule
+ if (currentName == f->name()) {
+ hasVirtuals = hasVirtuals || !f->isFinal();
+ if (f->isFinal())
+ finalFunctions += f;
+ } else {
+ if (hasVirtuals && finalFunctions.size() > 0) {
+ foreach (AbstractMetaFunction *final_function, finalFunctions) {
+ *final_function += AbstractMetaAttributes::ForceShellImplementation;
+
+ QString warn = QString("hiding of function '%1' in class '%2'")
+ .arg(final_function->name()).arg(name());
+ ReportHandler::warning(warn);
+ }
+ }
+
+ hasVirtuals = !f->isFinal();
+ finalFunctions.clear();
+ if (f->isFinal())
+ finalFunctions += f;
+ currentName = f->name();
+ }
+ }
+}
+
+bool AbstractMetaClass::hasFieldAccessors() const
+{
+ foreach (const AbstractMetaField *field, fields()) {
+ if (field->getter() || field->setter())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaClass::hasDefaultToStringFunction() const
+{
+ foreach (AbstractMetaFunction *f, queryFunctionsByName("toString")) {
+ if (!f->actualMinimumArgumentCount())
+ return true;
+ }
+ return false;
+}
+
+void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
+{
+ function->setOwnerClass(this);
+
+ if (!function->isDestructor())
+ m_functions << function;
+
+ m_hasVirtualSlots |= function->isVirtualSlot();
+ m_hasVirtuals |= !function->isFinal() || function->isVirtualSlot();
+ m_isPolymorphic |= m_hasVirtuals;
+ m_hasNonpublic |= !function->isPublic();
+}
+
+bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
+{
+ if (!other->isSignal())
+ return false;
+
+ foreach (const AbstractMetaFunction *f, functions()) {
+ if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName)
+ return other->modifiedName() == f->modifiedName();
+ }
+
+ return false;
+}
+
+
+QString AbstractMetaClass::name() const
+{
+ return m_typeEntry->targetLangName();
+// return QString(m_typeEntry->targetLangName()).replace("::", "_");
+}
+
+void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass)
+{
+ m_baseClass = baseClass;
+ if (baseClass)
+ m_isPolymorphic |= baseClass->isPolymorphic();
+}
+
+bool AbstractMetaClass::hasFunction(const QString &str) const
+{
+ foreach (const AbstractMetaFunction *f, functions())
+ if (f->name() == str)
+ return true;
+ return false;
+}
+
+/* Returns true if this class has one or more functions that are
+ protected. If a class has protected members we need to generate a
+ shell class with public accessors to the protected functions, so
+ they can be called from the native functions.
+*/
+bool AbstractMetaClass::hasProtectedFunctions() const
+{
+ foreach (AbstractMetaFunction *func, m_functions) {
+ if (func->isProtected())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::generateShellClass() const
+{
+ return m_forceShellClass ||
+ (!isFinal()
+ && (hasVirtualFunctions()
+ || hasProtectedFunctions()
+ || hasFieldAccessors()));
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i)
+ if (name == m_propertySpecs.at(i)->read())
+ return m_propertySpecs.at(i);
+ return 0;
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i)
+ if (name == m_propertySpecs.at(i)->write())
+ return m_propertySpecs.at(i);
+ return 0;
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i) {
+ if (name == m_propertySpecs.at(i)->reset())
+ return m_propertySpecs.at(i);
+ }
+ return 0;
+}
+
+
+
+static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
+{
+ foreach (const AbstractMetaFunction *f, l) {
+ if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar)
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaField::AbstractMetaField() : m_getter(0), m_setter(0), m_class(0)
+{
+}
+
+AbstractMetaField::~AbstractMetaField()
+{
+ delete m_setter;
+ delete m_getter;
+}
+ushort painters; // refcount
+AbstractMetaField *AbstractMetaField::copy() const
+{
+ AbstractMetaField *returned = new AbstractMetaField;
+ returned->setEnclosingClass(0);
+ returned->setAttributes(attributes());
+ returned->setName(name());
+ returned->setType(type()->copy());
+ returned->setOriginalAttributes(originalAttributes());
+
+ return returned;
+}
+
+static QString upCaseFirst(const QString &str)
+{
+ Q_ASSERT(!str.isEmpty());
+ QString s = str;
+ s[0] = s.at(0).toUpper();
+ return s;
+}
+
+static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name, uint type)
+{
+ AbstractMetaFunction *f = new AbstractMetaFunction;
+
+
+
+ f->setName(name);
+ f->setOriginalName(name);
+ f->setOwnerClass(g->enclosingClass());
+ f->setImplementingClass(g->enclosingClass());
+ f->setDeclaringClass(g->enclosingClass());
+
+ uint attr = AbstractMetaAttributes::Native
+ | AbstractMetaAttributes::Final
+ | type;
+ if (g->isStatic())
+ attr |= AbstractMetaAttributes::Static;
+ if (g->isPublic())
+ attr |= AbstractMetaAttributes::Public;
+ else if (g->isProtected())
+ attr |= AbstractMetaAttributes::Protected;
+ else
+ attr |= AbstractMetaAttributes::Private;
+ f->setAttributes(attr);
+ f->setOriginalAttributes(attr);
+
+ FieldModificationList mods = g->modifications();
+ foreach (FieldModification mod, mods) {
+ if (mod.isRenameModifier())
+ f->setName(mod.renamedTo());
+ if (mod.isAccessModifier()) {
+ if (mod.isPrivate())
+ f->setVisibility(AbstractMetaAttributes::Private);
+ else if (mod.isProtected())
+ f->setVisibility(AbstractMetaAttributes::Protected);
+ else if (mod.isPublic())
+ f->setVisibility(AbstractMetaAttributes::Public);
+ else if (mod.isFriendly())
+ f->setVisibility(AbstractMetaAttributes::Friendly);
+ }
+ }
+ return f;
+}
+
+FieldModificationList AbstractMetaField::modifications() const
+{
+ FieldModificationList mods = enclosingClass()->typeEntry()->fieldModifications();
+ FieldModificationList returned;
+
+ foreach (FieldModification mod, mods) {
+ if (mod.name == name())
+ returned += mod;
+ }
+
+ return returned;
+}
+
+const AbstractMetaFunction *AbstractMetaField::setter() const
+{
+ if (!m_setter) {
+ m_setter = createXetter(this,
+ "set" + upCaseFirst(name()),
+ AbstractMetaAttributes::SetterFunction);
+ AbstractMetaArgumentList arguments;
+ AbstractMetaArgument *argument = new AbstractMetaArgument;
+ argument->setType(type()->copy());
+ argument->setName(name());
+ arguments.append(argument);
+ m_setter->setArguments(arguments);
+ }
+ return m_setter;
+}
+
+const AbstractMetaFunction *AbstractMetaField::getter() const
+{
+ if (!m_getter) {
+ m_getter = createXetter(this,
+ name(),
+ AbstractMetaAttributes::GetterFunction);
+ m_getter->setType(type());
+ }
+
+ return m_getter;
+}
+
+
+bool AbstractMetaClass::hasConstructors() const
+{
+ return queryFunctions(Constructors).size();
+}
+
+void AbstractMetaClass::addDefaultConstructor()
+{
+ AbstractMetaFunction *f = new AbstractMetaFunction;
+ f->setName(name());
+ f->setOwnerClass(this);
+ f->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ f->setArguments(AbstractMetaArgumentList());
+ f->setDeclaringClass(this);
+
+ uint attr = AbstractMetaAttributes::Native;
+ attr |= AbstractMetaAttributes::Public;
+ f->setAttributes(attr);
+ f->setImplementingClass(this);
+ f->setOriginalAttributes(f->attributes());
+
+ addFunction(f);
+}
+
+bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
+{
+ return functions_contains(m_functions, f);
+}
+
+/* Goes through the list of functions and returns a list of all
+ functions matching all of the criteria in \a query.
+ */
+
+AbstractMetaFunctionList AbstractMetaClass::queryFunctions(uint query) const
+{
+ AbstractMetaFunctionList functions;
+
+ foreach (AbstractMetaFunction *f, m_functions) {
+
+ if ((query & VirtualSlots) && !f->isVirtualSlot())
+ continue;
+
+ if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode))
+ continue;
+
+ if ((query & NotRemovedFromTargetLang) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode))
+ continue;
+
+ if ((query & NotRemovedFromShell) && f->isRemovedFrom(f->implementingClass(), TypeSystem::ShellCode))
+ continue;
+
+ if ((query & NotRemovedFromShell) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::ShellCode))
+ continue;
+
+ if ((query & Visible) && f->isPrivate())
+ continue;
+
+ if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
+ continue;
+
+ if ((query & Invisible) && !f->isPrivate())
+ continue;
+
+ if ((query & Empty) && !f->isEmptyFunction())
+ continue;
+
+ if ((query & WasPublic) && !f->wasPublic())
+ continue;
+
+ if ((query & WasVisible) && f->wasPrivate())
+ continue;
+
+ if ((query & WasProtected) && !f->wasProtected())
+ continue;
+
+ if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
+ continue;
+
+ if ((query & Inconsistent) && (f->isFinalInTargetLang() || !f->isFinalInCpp() || f->isStatic()))
+ continue;
+
+ if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
+ continue;
+
+ if ((query & FinalInCppFunctions) && !f->isFinalInCpp())
+ continue;
+
+ if ((query & VirtualInCppFunctions) && f->isFinalInCpp())
+ continue;
+
+ if ((query & Signals) && (!f->isSignal()))
+ continue;
+
+ if ((query & ForcedShellFunctions) &&
+ (!f->isForcedShellImplementation() || !f->isFinal())) {
+ continue;
+ }
+
+ if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
+ continue;
+
+ if (!(query & Constructors) && f->isConstructor())
+ continue;
+
+ // Destructors are never included in the functions of a class currently
+ /*
+ if ((query & Destructors) && (!f->isDestructor()
+ || f->ownerClass() != f->implementingClass())
+ || f->isDestructor() && (query & Destructors) == 0) {
+ continue;
+ }*/
+
+ if ((query & VirtualFunctions) && (f->isFinal() || f->isSignal() || f->isStatic()))
+ continue;
+
+ if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
+ continue;
+
+ if ((query & NonStaticFunctions) && (f->isStatic()))
+ continue;
+
+ if ((query & NonEmptyFunctions) && (f->isEmptyFunction()))
+ continue;
+
+ if ((query & NormalFunctions) && (f->isSignal()))
+ continue;
+
+ if ((query & AbstractFunctions) && !f->isAbstract())
+ continue;
+
+ if ((query & OperatorOverloads) && !f->isOperatorOverload())
+ continue;
+
+ functions << f;
+ }
+
+// qDebug() << "queried" << m_typeEntry->qualifiedCppName() << "got" << functions.size() << "out of" << m_functions.size();
+
+ return functions;
+}
+
+
+bool AbstractMetaClass::hasInconsistentFunctions() const
+{
+ return cppInconsistentFunctions().size() > 0;
+}
+
+bool AbstractMetaClass::hasSignals() const
+{
+ return cppSignalFunctions().size() > 0;
+}
+
+
+/**
+ * Adds the specified interface to this class by adding all the
+ * functions in the interface to this class.
+ */
+void AbstractMetaClass::addInterface(AbstractMetaClass *interface)
+{
+ Q_ASSERT(!m_interfaces.contains(interface));
+ m_interfaces << interface;
+
+ m_isPolymorphic |= interface->isPolymorphic();
+
+ if (m_extractedInterface && m_extractedInterface != interface)
+ m_extractedInterface->addInterface(interface);
+
+#if 0
+ foreach (AbstractMetaFunction *function, interface->functions())
+ if (!hasFunction(function) && !function->isConstructor()) {
+ AbstractMetaFunction *cpy = function->copy();
+ cpy->setImplementingClass(this);
+
+ // Setup that this function is an interface class.
+ cpy->setInterfaceClass(interface);
+ *cpy += AbstractMetaAttributes::InterfaceFunction;
+
+ // Copy the modifications in interface into the implementing classes.
+ FunctionModificationList mods = function->modifications(interface);
+ foreach (const FunctionModification &mod, mods)
+ m_typeEntry->addFunctionModification(mod);
+
+ // It should be mostly safe to assume that when we implement an interface
+ // we don't "pass on" pure virtual functions to our sublcasses...
+// *cpy -= AbstractMetaAttributes::Abstract;
+
+ addFunction(cpy);
+ }
+#endif
+
+}
+
+
+void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces)
+{
+ m_interfaces = interfaces;
+ foreach (const AbstractMetaClass* interface, interfaces) {
+ if (interface)
+ m_isPolymorphic |= interface->isPolymorphic();
+ }
+}
+
+
+AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
+{
+ foreach (AbstractMetaEnum *e, m_enums) {
+ if (e->name() == enumName)
+ return e;
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnum(enumName);
+
+ return 0;
+}
+
+
+
+
+/*! Recursivly searches for the enum value named \a enumValueName in
+ this class and its superclasses and interfaces. Values belonging to
+ \a meta_enum are excluded from the search.
+*/
+AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName, AbstractMetaEnum *meta_enum)
+{
+ foreach (AbstractMetaEnum *e, m_enums) {
+ if (e == meta_enum)
+ continue;
+ foreach (AbstractMetaEnumValue *v, e->values()) {
+ if (v->name() == enumValueName)
+ return v;
+ }
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnumValue(enumValueName, meta_enum);
+
+ if (baseClass())
+ return baseClass()->findEnumValue(enumValueName, meta_enum);
+
+ return 0;
+}
+
+
+/*!
+ * Searches through all of this class' enums for a value matching the
+ * name \a enumValueName. The name is excluding the class/namespace
+ * prefix. The function recursivly searches interfaces and baseclasses
+ * of this class.
+ */
+AbstractMetaEnum *AbstractMetaClass::findEnumForValue(const QString &enumValueName)
+{
+ foreach (AbstractMetaEnum *e, m_enums) {
+ foreach (AbstractMetaEnumValue *v, e->values()) {
+ if (v->name() == enumValueName)
+ return e;
+ }
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnumForValue(enumValueName);
+
+ if (baseClass())
+ return baseClass()->findEnumForValue(enumValueName);
+
+ return 0;
+}
+
+
+static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type)
+{
+ if (!type)
+ return;
+
+ Q_ASSERT(metaClass);
+ const TypeEntry *entry = (type ? type->typeEntry() : 0);
+ if (entry && entry->isComplex()) {
+ const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry);
+ ComplexTypeEntry *class_entry = metaClass->typeEntry();
+ if (class_entry && centry->include().isValid())
+ class_entry->addExtraInclude(centry->include());
+ }
+
+ if (type->hasInstantiations()) {
+ QList<AbstractMetaType *> instantiations = type->instantiations();
+ foreach (AbstractMetaType *instantiation, instantiations)
+ addExtraIncludeForType(metaClass, instantiation);
+ }
+}
+
+static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, const AbstractMetaFunction *meta_function)
+{
+ Q_ASSERT(metaClass);
+ Q_ASSERT(meta_function);
+ addExtraIncludeForType(metaClass, meta_function->type());
+
+ AbstractMetaArgumentList arguments = meta_function->arguments();
+ foreach (AbstractMetaArgument *argument, arguments)
+ addExtraIncludeForType(metaClass, argument->type());
+}
+
+void AbstractMetaClass::fixFunctions()
+{
+ if (m_functionsFixed)
+ return;
+ else
+ m_functionsFixed = true;
+
+ AbstractMetaClass *superClass = baseClass();
+ AbstractMetaFunctionList funcs = functions();
+
+// printf("fix functions for %s\n", qPrintable(name()));
+
+ if (superClass)
+ superClass->fixFunctions();
+ int iface_idx = 0;
+ while (superClass || iface_idx < interfaces().size()) {
+// printf(" - base: %s\n", qPrintable(super_class->name()));
+
+ // Since we always traverse the complete hierarchy we are only
+ // interrested in what each super class implements, not what
+ // we may have propagated from their base classes again.
+ AbstractMetaFunctionList superFuncs;
+ if (superClass) {
+ // Super classes can never be final
+ if (superClass->isFinalInTargetLang()) {
+ ReportHandler::warning("Final class '" + superClass->name() + "' set to non-final, as it is extended by other classes");
+ *superClass -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+ superFuncs = superClass->queryFunctions(AbstractMetaClass::ClassImplements);
+ AbstractMetaFunctionList virtuals = superClass->queryFunctions(AbstractMetaClass::VirtualInCppFunctions);
+ superFuncs += virtuals;
+ } else {
+ superFuncs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions);
+ AbstractMetaFunctionList virtuals = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::VirtualInCppFunctions);
+ superFuncs += virtuals;
+ }
+
+ QSet<AbstractMetaFunction *> funcsToAdd;
+ for (int sfi = 0; sfi < superFuncs.size(); ++sfi) {
+ AbstractMetaFunction *sf = superFuncs.at(sfi);
+
+ if (sf->isRemovedFromAllLanguages(sf->implementingClass()))
+ continue;
+
+ // we generally don't care about private functions, but we have to get the ones that are
+ // virtual in case they override abstract functions.
+ bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
+ for (int fi = 0; fi < funcs.size(); ++fi) {
+ AbstractMetaFunction *f = funcs.at(fi);
+ if (f->isRemovedFromAllLanguages(f->implementingClass()))
+ continue;
+
+ uint cmp = f->compareTo(sf);
+
+ if (cmp & AbstractMetaFunction::EqualModifiedName) {
+// printf(" - %s::%s similar to %s::%s %x vs %x\n",
+// qPrintable(sf->implementingClass()->typeEntry()->qualifiedCppName()),
+// qPrintable(sf->name()),
+// qPrintable(f->implementingClass()->typeEntry()->qualifiedCppName()),
+// qPrintable(f->name()),
+// sf->attributes(),
+// f->attributes());
+
+ add = false;
+ if (cmp & AbstractMetaFunction::EqualArguments) {
+
+// if (!(cmp & AbstractMetaFunction::EqualReturnType)) {
+// ReportHandler::warning(QString("%1::%2 and %3::%4 differ in retur type")
+// .arg(sf->implementingClass()->name())
+// .arg(sf->name())
+// .arg(f->implementingClass()->name())
+// .arg(f->name()));
+// }
+
+ // Same function, propegate virtual...
+ if (!(cmp & AbstractMetaFunction::EqualAttributes)) {
+ if (!f->isEmptyFunction()) {
+ if (!sf->isFinalInCpp() && f->isFinalInCpp()) {
+ *f -= AbstractMetaAttributes::FinalInCpp;
+ // printf(" --- inherit virtual\n");
+ }
+ if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) {
+ *f -= AbstractMetaAttributes::FinalInTargetLang;
+ // printf(" --- inherit virtual\n");
+ }
+#if 0
+ if (!f->isFinalInTargetLang() && f->isPrivate()) {
+ f->setFunctionType(AbstractMetaFunction::EmptyFunction);
+ f->setVisibility(AbstractMetaAttributes::Protected);
+ *f += AbstractMetaAttributes::FinalInTargetLang;
+ ReportHandler::warning(QString("private virtual function '%1' in '%2'")
+ .arg(f->signature())
+ .arg(f->implementingClass()->name()));
+ }
+#endif
+ }
+ }
+
+ if (f->visibility() != sf->visibility()) {
+ QString warn = QString("visibility of function '%1' modified in class '%2'")
+ .arg(f->name()).arg(name());
+ ReportHandler::warning(warn);
+#if 0
+ // If new visibility is private, we can't
+ // do anything. If it isn't, then we
+ // prefer the parent class's visibility
+ // setting for the function.
+ if (!f->isPrivate() && !sf->isPrivate())
+ f->setVisibility(sf->visibility());
+#endif
+ // Private overrides of abstract functions have to go into the class or
+ // the subclasses will not compile as non-abstract classes.
+ // But they don't need to be implemented, since they can never be called.
+ if (f->isPrivate() && sf->isAbstract()) {
+ f->setFunctionType(AbstractMetaFunction::EmptyFunction);
+// f->setVisibility(sf->visibility());
+ *f += AbstractMetaAttributes::FinalInTargetLang;
+ *f += AbstractMetaAttributes::FinalInCpp;
+ }
+ }
+
+ // Set the class which first declares this function, afawk
+ f->setDeclaringClass(sf->declaringClass());
+
+ if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) {
+ // Shadowed funcion, need to make base class
+ // function non-virtual
+ if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) {
+
+ // Check whether the superclass method has been redefined to non-final
+
+ bool hasNonFinalModifier = false;
+ bool isBaseImplPrivate = false;
+ FunctionModificationList mods = sf->modifications(sf->implementingClass());
+ foreach (FunctionModification mod, mods) {
+ if (mod.isNonFinal()) {
+ hasNonFinalModifier = true;
+ break;
+ } else if (mod.isPrivate()) {
+ isBaseImplPrivate = true;
+ break;
+ }
+ }
+
+ if (!hasNonFinalModifier && !isBaseImplPrivate) {
+ ReportHandler::warning(QString::fromLatin1("Shadowing: %1::%2 and %3::%4")
+ .arg(sf->implementingClass()->name())
+ .arg(sf->signature())
+ .arg(f->implementingClass()->name())
+ .arg(f->signature()));
+ }
+ }
+ }
+
+ }
+
+ if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
+ AbstractMetaArgumentList arguments;
+ if (f->arguments().size() < sf->arguments().size())
+ arguments = sf->arguments();
+ else
+ arguments = f->arguments();
+ //TODO: fix this
+ //for (int i=0; i<arguments.size(); ++i)
+ // arguments[i]->setDefaultValueExpression("<#>" + QString());
+ }
+
+
+ // Otherwise we have function shadowing and we can
+ // skip the thing...
+ } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) {
+ // In the case of function shadowing where the function name has been altered to
+ // avoid conflict, we don't copy in the original.
+ add = false;
+ }
+ }
+
+ if (add)
+ funcsToAdd << sf;
+ }
+
+ foreach (AbstractMetaFunction *f, funcsToAdd)
+ funcs << f->copy();
+
+ if (superClass)
+ superClass = superClass->baseClass();
+ else
+ iface_idx++;
+ }
+
+ bool hasPrivateConstructors = false;
+ bool hasPublicConstructors = false;
+ foreach (AbstractMetaFunction *func, funcs) {
+ FunctionModificationList mods = func->modifications(this);
+ foreach (const FunctionModification &mod, mods) {
+ if (mod.isRenameModifier()) {
+// qDebug() << name() << func->originalName() << func << " from "
+// << func->implementingClass()->name() << "renamed to" << mod.renamedTo();
+ func->setName(mod.renamedTo());
+ }
+ }
+
+ // Make sure class is abstract if one of the functions is
+ if (func->isAbstract()) {
+ (*this) += AbstractMetaAttributes::Abstract;
+ (*this) -= AbstractMetaAttributes::Final;
+ }
+
+ if (func->isConstructor()) {
+ if (func->isPrivate())
+ hasPrivateConstructors = true;
+ else
+ hasPublicConstructors = true;
+ }
+
+
+
+ // Make sure that we include files for all classes that are in use
+
+ if (!func->isRemovedFrom(this, TypeSystem::ShellCode))
+ addExtraIncludesForFunction(this, func);
+ }
+
+ if (hasPrivateConstructors && !hasPublicConstructors) {
+ (*this) += AbstractMetaAttributes::Abstract;
+ (*this) -= AbstractMetaAttributes::Final;
+ }
+
+ foreach (AbstractMetaFunction *f1, funcs) {
+ foreach (AbstractMetaFunction *f2, funcs) {
+ if (f1 != f2) {
+ uint cmp = f1->compareTo(f2);
+ if ((cmp & AbstractMetaFunction::EqualName)
+ && !f1->isFinalInCpp()
+ && f2->isFinalInCpp()) {
+ *f2 += AbstractMetaAttributes::FinalOverload;
+// qDebug() << f2 << f2->implementingClass()->name() << "::" << f2->name() << f2->arguments().size() << " vs " << f1 << f1->implementingClass()->name() << "::" << f1->name() << f1->arguments().size();
+// qDebug() << " " << f2;
+// AbstractMetaArgumentList f2Args = f2->arguments();
+// foreach (AbstractMetaArgument *a, f2Args)
+// qDebug() << " " << a->type()->name() << a->name();
+// qDebug() << " " << f1;
+// AbstractMetaArgumentList f1Args = f1->arguments();
+// foreach (AbstractMetaArgument *a, f1Args)
+// qDebug() << " " << a->type()->name() << a->name();
+
+ }
+ }
+ }
+ }
+
+ setFunctions(funcs);
+}
+
+
+QString AbstractMetaType::minimalSignature() const
+{
+ QString minimalSignature;
+ if (isConstant())
+ minimalSignature += "const ";
+ minimalSignature += typeEntry()->qualifiedCppName();
+ if (hasInstantiations()) {
+ QList<AbstractMetaType *> instantiations = this->instantiations();
+ minimalSignature += "< ";
+ for (int i = 0; i < instantiations.size(); ++i) {
+ if (i > 0)
+ minimalSignature += ",";
+ minimalSignature += instantiations.at(i)->minimalSignature();
+ }
+ minimalSignature += " >";
+ }
+
+ if (isReference())
+ minimalSignature += "&";
+ for (int j = 0; j < indirections(); ++j)
+ minimalSignature += "*";
+
+ return minimalSignature;
+}
+
+bool AbstractMetaType::hasNativeId() const
+{
+ return (isQObject() || isValue() || isObject()) && typeEntry()->isNativeIdBased();
+}
+
+
+/*******************************************************************************
+ * Other stuff...
+ */
+
+
+AbstractMetaEnum *AbstractMetaClassList::findEnum(const EnumTypeEntry *entry) const
+{
+ Q_ASSERT(entry->isEnum());
+
+ QString qualifiedName = entry->qualifiedCppName();
+ int pos = qualifiedName.lastIndexOf("::");
+
+ QString enumName;
+ QString className;
+
+ if (pos > 0) {
+ enumName = qualifiedName.mid(pos + 2);
+ className = qualifiedName.mid(0, pos);
+ } else {
+ enumName = qualifiedName;
+ className = TypeDatabase::globalNamespaceClassName(entry);
+ }
+
+ AbstractMetaClass *metaClass = findClass(className);
+ if (!metaClass) {
+ ReportHandler::warning(QString("AbstractMeta::findEnum(), unknown class '%1' in '%2'")
+ .arg(className).arg(entry->qualifiedCppName()));
+ return 0;
+ }
+
+ return metaClass->findEnum(enumName);
+}
+
+AbstractMetaEnumValue *AbstractMetaEnumValueList::find(const QString &name) const
+{
+ for (int i = 0; i < size(); ++i) {
+ if (name == at(i)->name())
+ return at(i);
+ }
+ return 0;
+}
+
+AbstractMetaEnumValue *AbstractMetaClassList::findEnumValue(const QString &name) const
+{
+ QStringList lst = name.split(QLatin1String("::"));
+
+ Q_ASSERT_X(lst.size() == 2, "AbstractMetaClassList::findEnumValue()", "Expected qualified enum");
+
+
+ QString prefixName = lst.at(0);
+ QString enumName = lst.at(1);
+
+ AbstractMetaClass *cl = findClass(prefixName);
+ if (cl)
+ return cl->findEnumValue(enumName, 0);
+
+ ReportHandler::warning(QString("no matching enum '%1'").arg(name));
+ return 0;
+}
+
+/*!
+ * Searches the list after a class that mathces \a name; either as
+ * C++, Target language base name or complete Target language package.class name.
+ */
+
+AbstractMetaClass *AbstractMetaClassList::findClass(const QString &name) const
+{
+ if (name.isEmpty())
+ return 0;
+
+ foreach (AbstractMetaClass *c, *this) {
+ if (c->qualifiedCppName() == name)
+ return c;
+ }
+
+ foreach (AbstractMetaClass *c, *this) {
+ if (c->fullName() == name)
+ return c;
+ }
+
+ foreach (AbstractMetaClass *c, *this) {
+ if (c->name() == name)
+ return c;
+ }
+
+ return 0;
+}
diff --git a/abstractmetalang.h b/abstractmetalang.h
new file mode 100644
index 000000000..a7b0be1c0
--- /dev/null
+++ b/abstractmetalang.h
@@ -0,0 +1,1874 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef ABSTRACTMETALANG_H
+#define ABSTRACTMETALANG_H
+
+#include "typesystem.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+
+
+class AbstractMeta;
+class AbstractMetaClass;
+class AbstractMetaField;
+class AbstractMetaFunction;
+class AbstractMetaType;
+class AbstractMetaVariable;
+class AbstractMetaArgument;
+class AbstractMetaEnumValue;
+class AbstractMetaEnum;
+class QPropertySpec;
+
+class Documentation
+{
+public:
+ enum Format {
+ Native,
+ Target
+ };
+
+ Documentation()
+ : m_format(Documentation::Native) {}
+
+ Documentation(const QString& value, Format fmt = Documentation::Native)
+ : m_data(value), m_format(fmt) {}
+
+ QString value() const
+ {
+ return m_data;
+ }
+
+ void setValue(const QString& value, Format fmt = Documentation::Native)
+ {
+ m_data = value; m_format = fmt;
+ }
+
+ Documentation::Format format() const
+ {
+ return m_format;
+ }
+
+private:
+ QString m_data;
+ Format m_format;
+
+};
+
+typedef QList<AbstractMetaField *> AbstractMetaFieldList;
+typedef QList<AbstractMetaArgument *> AbstractMetaArgumentList;
+typedef QList<AbstractMetaFunction *> AbstractMetaFunctionList;
+class AbstractMetaClassList : public QList<AbstractMetaClass *>
+{
+public:
+ AbstractMetaClass *findClass(const QString &name) const;
+ AbstractMetaEnumValue *findEnumValue(const QString &string) const;
+ AbstractMetaEnum *findEnum(const EnumTypeEntry *entry) const;
+
+};
+
+
+
+class AbstractMetaAttributes
+{
+public:
+ AbstractMetaAttributes() : m_attributes(0) {};
+
+ enum Attribute {
+ None = 0x00000000,
+
+ Private = 0x00000001,
+ Protected = 0x00000002,
+ Public = 0x00000004,
+ Friendly = 0x00000008,
+ Visibility = 0x0000000f,
+
+ Native = 0x00000010,
+ Abstract = 0x00000020,
+ Static = 0x00000040,
+
+ FinalInTargetLang = 0x00000080,
+ FinalInCpp = 0x00000100,
+ ForceShellImplementation = 0x00000200,
+
+ GetterFunction = 0x00000400,
+ SetterFunction = 0x00000800,
+
+ FinalOverload = 0x00001000,
+ InterfaceFunction = 0x00002000,
+
+ PropertyReader = 0x00004000,
+ PropertyWriter = 0x00008000,
+ PropertyResetter = 0x00010000,
+
+ Fake = 0x00020000,
+
+ Invokable = 0x00040000,
+
+ Final = FinalInTargetLang | FinalInCpp
+ };
+
+ uint attributes() const
+ {
+ return m_attributes;
+ }
+
+ void setAttributes(uint attributes)
+ {
+ m_attributes = attributes;
+ }
+
+ uint originalAttributes() const
+ {
+ return m_originalAttributes;
+ }
+
+ void setOriginalAttributes(uint attributes)
+ {
+ m_originalAttributes = attributes;
+ }
+
+ uint visibility() const
+ {
+ return m_attributes & Visibility;
+ }
+
+ void setVisibility(uint visi)
+ {
+ m_attributes = (m_attributes & ~Visibility) | visi;
+ }
+
+ void operator+=(Attribute attribute)
+ {
+ m_attributes |= attribute;
+ }
+
+ void operator-=(Attribute attribute)
+ {
+ m_attributes &= ~attribute;
+ }
+
+ bool isNative() const
+ {
+ return m_attributes & Native;
+ }
+
+ bool isFinal() const
+ {
+ return (m_attributes & Final) == Final;
+ }
+
+ bool isFinalInTargetLang() const
+ {
+ return m_attributes & FinalInTargetLang;
+ }
+
+ bool isFinalInCpp() const
+ {
+ return m_attributes & FinalInCpp;
+ }
+
+ bool isAbstract() const
+ {
+ return m_attributes & Abstract;
+ }
+
+ bool isStatic() const
+ {
+ return m_attributes & Static;
+ }
+
+ bool isForcedShellImplementation() const
+ {
+ return m_attributes & ForceShellImplementation;
+ }
+
+ bool isInterfaceFunction() const
+ {
+ return m_attributes & InterfaceFunction;
+ }
+
+ bool isFinalOverload() const
+ {
+ return m_attributes & FinalOverload;
+ }
+
+ bool isInvokable() const
+ {
+ return m_attributes & Invokable;
+ }
+
+ bool isPropertyReader() const
+ {
+ return m_attributes & PropertyReader;
+ }
+
+ bool isPropertyWriter() const
+ {
+ return m_attributes & PropertyWriter;
+ }
+
+ bool isPropertyResetter() const
+ {
+ return m_attributes & PropertyResetter;
+ }
+
+ bool isPrivate() const
+ {
+ return m_attributes & Private;
+ }
+
+ bool isProtected() const
+ {
+ return m_attributes & Protected;
+ }
+
+ bool isPublic() const
+ {
+ return m_attributes & Public;
+ }
+
+ bool isFriendly() const
+ {
+ return m_attributes & Friendly;
+ }
+
+ bool wasPrivate() const
+ {
+ return m_originalAttributes & Private;
+ }
+
+ bool wasProtected() const
+ {
+ return m_originalAttributes & Protected;
+ }
+
+ bool wasPublic() const
+ {
+ return m_originalAttributes & Public;
+ }
+
+ bool wasFriendly() const
+ {
+ return m_originalAttributes & Friendly;
+ }
+
+ // valid only for global components
+ // (e.g.: functions, enums, flags)
+ QString includeFile() const
+ {
+ return m_includeFile;
+ }
+
+ void setIncludeFile(const QString& file)
+ {
+ m_includeFile = file;
+ }
+
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ uint m_attributes;
+ uint m_originalAttributes;
+ QString m_includeFile;
+ Documentation m_doc;
+};
+
+
+class AbstractMetaType
+{
+public:
+ enum TypeUsagePattern {
+ InvalidPattern,
+ PrimitivePattern,
+ FlagsPattern,
+ EnumPattern,
+ ValuePattern,
+ StringPattern,
+ CharPattern,
+ ObjectPattern,
+ QObjectPattern,
+ NativePointerPattern,
+ ContainerPattern,
+ VariantPattern,
+ JObjectWrapperPattern,
+ ArrayPattern,
+ ThreadPattern
+ };
+
+ AbstractMetaType() :
+ m_typeEntry(0),
+ m_arrayElementCount(0),
+ m_arrayElementType(0),
+ m_originalTemplateType(0),
+ m_pattern(InvalidPattern),
+ m_constant(false),
+ m_reference(false),
+ m_cppInstantiation(true),
+ m_indirections(0),
+ m_reserved(0)
+ {}
+
+ QString package() const
+ {
+ return m_typeEntry->targetLangPackage();
+ }
+ QString name() const
+ {
+ return m_typeEntry->targetLangName();
+ }
+ QString fullName() const
+ {
+ return m_typeEntry->qualifiedTargetLangName();
+ }
+
+ void setTypeUsagePattern(TypeUsagePattern pattern)
+ {
+ m_pattern = pattern;
+ }
+ TypeUsagePattern typeUsagePattern() const
+ {
+ return m_pattern;
+ }
+
+ // true when use pattern is container
+ bool hasInstantiations() const
+ {
+ return !m_instantiations.isEmpty();
+ }
+ void addInstantiation(AbstractMetaType *inst)
+ {
+ m_instantiations << inst;
+ }
+ void setInstantiations(const QList<AbstractMetaType *> &insts)
+ {
+ m_instantiations = insts;
+ }
+ QList<AbstractMetaType *> instantiations() const
+ {
+ return m_instantiations;
+ }
+ void setInstantiationInCpp(bool incpp)
+ {
+ m_cppInstantiation = incpp;
+ }
+ bool hasInstantiationInCpp() const
+ {
+ return hasInstantiations() && m_cppInstantiation;
+ }
+
+ QString minimalSignature() const;
+
+ // true when the type is a QtJambiObject subclass
+ bool hasNativeId() const;
+
+ // returns true if the typs is used as a non complex primitive, no & or *'s
+ bool isPrimitive() const
+ {
+ return m_pattern == PrimitivePattern;
+ }
+
+ // returns true if the type is used as an enum
+ bool isEnum() const
+ {
+ return m_pattern == EnumPattern;
+ }
+
+ // returns true if the type is used as a QObject *
+ bool isQObject() const
+ {
+ return m_pattern == QObjectPattern;
+ }
+
+ // returns true if the type is used as an object, e.g. Xxx *
+ bool isObject() const
+ {
+ return m_pattern == ObjectPattern;
+ }
+
+ // returns true if the type is used as an array, e.g. Xxx[42]
+ bool isArray() const
+ {
+ return m_pattern == ArrayPattern;
+ }
+
+ // returns true if the type is used as a value type (X or const X &)
+ bool isValue() const
+ {
+ return m_pattern == ValuePattern;
+ }
+
+ // returns true for more complex types...
+ bool isNativePointer() const
+ {
+ return m_pattern == NativePointerPattern;
+ }
+
+ // returns true if the type was originally a QString or const QString & or equivalent for QLatin1String
+ bool isTargetLangString() const
+ {
+ return m_pattern == StringPattern;
+ }
+
+ // returns true if the type was originally a QChar or const QChar &
+ bool isTargetLangChar() const
+ {
+ return m_pattern == CharPattern;
+ }
+
+ // return true if the type was originally a QVariant or const QVariant &
+ bool isVariant() const
+ {
+ return m_pattern == VariantPattern;
+ }
+
+ // return true if the type was originally a JObjectWrapper or const JObjectWrapper &
+ bool isJObjectWrapper() const
+ {
+ return m_pattern == JObjectWrapperPattern;
+ }
+
+ // returns true if the type was used as a container
+ bool isContainer() const
+ {
+ return m_pattern == ContainerPattern;
+ }
+
+ // returns true if the type was used as a flag
+ bool isFlags() const
+ {
+ return m_pattern == FlagsPattern;
+ }
+
+ // returns true if the type was used as a thread
+ bool isThread() const
+ {
+ return m_pattern == ThreadPattern;
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+ void setConstant(bool constant)
+ {
+ m_constant = constant;
+ }
+
+ bool isReference() const
+ {
+ return m_reference;
+ }
+ void setReference(bool ref)
+ {
+ m_reference = ref;
+ }
+
+ /**
+ * Says if the type is to be implemented using target language
+ * equivalent of C++ enums, i.e. not plain ints.
+ * /return true if the type is to be implemented using target
+ * language enums
+ */
+ bool isTargetLangEnum() const
+ {
+ return isEnum() && !((EnumTypeEntry *) typeEntry())->forceInteger();
+ }
+ bool isIntegerEnum() const
+ {
+ return isEnum() && !isTargetLangEnum();
+ }
+
+ /**
+ * Says if the type is to be implemented using target language
+ * equivalent of Qt's QFlags, i.e. not plain ints.
+ * /return true if the type is to be implemented using target
+ * language QFlags
+ */
+ bool isTargetLangFlags() const
+ {
+ return isFlags() && !((FlagsTypeEntry *) typeEntry())->forceInteger();
+ }
+ bool isIntegerFlags() const
+ {
+ return isFlags() && !isTargetLangFlags();
+ }
+
+ int actualIndirections() const
+ {
+ return m_indirections + (isReference() ? 1 : 0);
+ }
+ int indirections() const
+ {
+ return m_indirections;
+ }
+ void setIndirections(int indirections)
+ {
+ m_indirections = indirections;
+ }
+
+ void setArrayElementCount(int n)
+ {
+ m_arrayElementCount = n;
+ }
+ int arrayElementCount() const
+ {
+ return m_arrayElementCount;
+ }
+
+ AbstractMetaType *arrayElementType() const
+ {
+ return m_arrayElementType;
+ }
+ void setArrayElementType(AbstractMetaType *t)
+ {
+ m_arrayElementType = t;
+ }
+
+ QString cppSignature() const;
+
+ AbstractMetaType *copy() const;
+
+ const TypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+ void setTypeEntry(const TypeEntry *type)
+ {
+ m_typeEntry = type;
+ }
+
+ void setOriginalTypeDescription(const QString &otd)
+ {
+ m_originalTypeDescription = otd;
+ }
+ QString originalTypeDescription() const
+ {
+ return m_originalTypeDescription;
+ }
+
+ void setOriginalTemplateType(const AbstractMetaType *type)
+ {
+ m_originalTemplateType = type;
+ }
+ const AbstractMetaType *originalTemplateType() const
+ {
+ return m_originalTemplateType;
+ }
+
+private:
+ const TypeEntry *m_typeEntry;
+ QList <AbstractMetaType *> m_instantiations;
+ QString m_package;
+ QString m_originalTypeDescription;
+
+ int m_arrayElementCount;
+ AbstractMetaType *m_arrayElementType;
+ const AbstractMetaType *m_originalTemplateType;
+
+ TypeUsagePattern m_pattern;
+ uint m_constant : 1;
+ uint m_reference : 1;
+ uint m_cppInstantiation : 1;
+ int m_indirections : 4;
+ uint m_reserved : 25; // unused
+};
+
+class AbstractMetaVariable
+{
+public:
+ AbstractMetaVariable() : m_type(0) {}
+
+ AbstractMetaType *type() const
+ {
+ return m_type;
+ }
+ void setType(AbstractMetaType *type)
+ {
+ m_type = type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ QString m_name;
+ AbstractMetaType *m_type;
+
+ Documentation m_doc;
+};
+
+
+
+class AbstractMetaArgument : public AbstractMetaVariable
+{
+public:
+ AbstractMetaArgument() : m_argumentIndex(0) {};
+
+ QString defaultValueExpression() const
+ {
+ return m_expression;
+ }
+ void setDefaultValueExpression(const QString &expr)
+ {
+ m_expression = expr;
+ }
+
+ QString originalDefaultValueExpression() const
+ {
+ return m_originalExpression;
+ }
+ void setOriginalDefaultValueExpression(const QString &expr)
+ {
+ m_originalExpression = expr;
+ }
+
+ QString toString() const
+ {
+ return type()->name() + " " + AbstractMetaVariable::name() +
+ (m_expression.isEmpty() ? "" : " = " + m_expression);
+ }
+
+ int argumentIndex() const
+ {
+ return m_argumentIndex;
+ }
+ void setArgumentIndex(int argIndex)
+ {
+ m_argumentIndex = argIndex;
+ }
+
+ QString argumentName() const;
+ QString indexedName() const;
+
+ AbstractMetaArgument *copy() const;
+
+private:
+ // Just to force people to call argumentName() And indexedName();
+ QString name() const;
+
+ QString m_expression;
+ QString m_originalExpression;
+ int m_argumentIndex;
+};
+
+
+class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttributes
+{
+public:
+ AbstractMetaField();
+ ~AbstractMetaField();
+
+ const AbstractMetaClass *enclosingClass() const
+ {
+ return m_class;
+ }
+ void setEnclosingClass(const AbstractMetaClass *cls)
+ {
+ m_class = cls;
+ }
+
+ const AbstractMetaFunction *getter() const;
+ const AbstractMetaFunction *setter() const;
+
+ FieldModificationList modifications() const;
+
+ using AbstractMetaVariable::setDocumentation;
+ using AbstractMetaVariable::documentation;
+
+ AbstractMetaField *copy() const;
+
+private:
+ mutable AbstractMetaFunction *m_getter;
+ mutable AbstractMetaFunction *m_setter;
+ const AbstractMetaClass *m_class;
+};
+
+
+class AbstractMetaFunction : public AbstractMetaAttributes
+{
+public:
+ enum FunctionType {
+ ConstructorFunction,
+ DestructorFunction,
+ NormalFunction,
+ SignalFunction,
+ EmptyFunction,
+ SlotFunction,
+ GlobalScopeFunction
+ };
+
+ enum CompareResult {
+ EqualName = 0x00000001,
+ EqualArguments = 0x00000002,
+ EqualAttributes = 0x00000004,
+ EqualImplementor = 0x00000008,
+ EqualReturnType = 0x00000010,
+ EqualDefaultValueOverload = 0x00000020,
+ EqualModifiedName = 0x00000040,
+
+ NameLessThan = 0x00001000,
+
+ PrettySimilar = EqualName | EqualArguments,
+ Equal = 0x0000001f,
+ NotEqual = 0x00001000
+ };
+
+ AbstractMetaFunction()
+ : m_functionType(NormalFunction),
+ m_type(0),
+ m_class(0),
+ m_implementingClass(0),
+ m_declaringClass(0),
+ m_interfaceClass(0),
+ m_propertySpec(0),
+ m_constant(false),
+ m_invalid(false),
+ m_reverse(false),
+ m_explicit(false)
+ {
+ }
+
+ ~AbstractMetaFunction();
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ QString originalName() const
+ {
+ return m_originalName.isEmpty() ? name() : m_originalName;
+ }
+
+ void setOriginalName(const QString &name)
+ {
+ m_originalName = name;
+ }
+
+ void setReverseOperator(bool reverse)
+ {
+ m_reverse = reverse;
+ }
+
+ bool isReverseOperator() const
+ {
+ return m_reverse;
+ }
+
+ void setExplicit(bool isExplicit)
+ {
+ m_explicit = isExplicit;
+ }
+ /**
+ * Says if the function (a constructor) was declared as explicit in C++.
+ * \return true if the function was declared as explicit in C++
+ */
+ bool isExplicit() const
+ {
+ return m_explicit;
+ }
+
+ static bool isConversionOperator(QString funcName);
+ bool isConversionOperator() const
+ {
+ return isConversionOperator(originalName());
+ }
+
+ static bool isOperatorOverload(QString funcName);
+ bool isOperatorOverload() const
+ {
+ return isOperatorOverload(originalName());
+ }
+
+ bool isArithmeticOperator() const;
+ bool isBitwiseOperator() const;
+ bool isComparisonOperator() const;
+ bool isLogicalOperator() const;
+ bool isSubscriptOperator() const;
+ bool isAssignmentOperator() const;
+ bool isOtherOperator() const;
+
+ /**
+ * Informs the arity of the operator or -1 if the function is not
+ * an operator overload.
+ * /return the arity of the operator or -1
+ */
+ int arityOfOperator() const;
+ bool isUnaryOperator() const { return arityOfOperator() == 1; }
+ bool isBinaryOperator() const { return arityOfOperator() == 2; }
+ bool isInplaceOperator() const;
+
+ // TODO: ths function *should* know if it is virtual
+ // instead of asking to your implementing class.
+ bool isVirtual() const;
+ bool isCopyConstructor() const;
+ bool isThread() const;
+ bool allowThread() const;
+ QString modifiedName() const;
+
+ QString minimalSignature() const;
+ QStringList possibleIntrospectionCompatibleSignatures() const;
+
+ QString marshalledName() const;
+
+ // true if one or more of the arguments are of QtJambiObject subclasses
+ bool argumentsHaveNativeId() const
+ {
+ foreach (const AbstractMetaArgument *arg, m_arguments) {
+ if (arg->type()->hasNativeId())
+ return true;
+ }
+
+ return false;
+ }
+
+ bool isModifiedRemoved(int types = TypeSystem::All) const;
+
+ AbstractMetaType *type() const
+ {
+ return m_type;
+ }
+ void setType(AbstractMetaType *type)
+ {
+ m_type = type;
+ }
+
+ // The class that has this function as a member.
+ const AbstractMetaClass *ownerClass() const
+ {
+ return m_class;
+ }
+ void setOwnerClass(const AbstractMetaClass *cls)
+ {
+ m_class = cls;
+ }
+
+ // The first class in a hierarchy that declares the function
+ const AbstractMetaClass *declaringClass() const
+ {
+ return m_declaringClass;
+ }
+ void setDeclaringClass(const AbstractMetaClass *cls)
+ {
+ m_declaringClass = cls;
+ }
+
+ // The class that actually implements this function
+ const AbstractMetaClass *implementingClass() const
+ {
+ return m_implementingClass;
+ }
+ void setImplementingClass(const AbstractMetaClass *cls)
+ {
+ m_implementingClass = cls;
+ }
+
+ bool needsCallThrough() const;
+
+ AbstractMetaArgumentList arguments() const
+ {
+ return m_arguments;
+ }
+ void setArguments(const AbstractMetaArgumentList &arguments)
+ {
+ m_arguments = arguments;
+ }
+ void addArgument(AbstractMetaArgument *argument)
+ {
+ m_arguments << argument;
+ }
+ int actualMinimumArgumentCount() const;
+
+ void setInvalid(bool on)
+ {
+ m_invalid = on;
+ }
+ bool isInvalid() const
+ {
+ return m_invalid;
+ }
+ bool isDeprecated() const;
+ bool isDestructor() const
+ {
+ return functionType() == DestructorFunction;
+ }
+ bool isConstructor() const
+ {
+ return functionType() == ConstructorFunction;
+ }
+ bool isNormal() const
+ {
+ return functionType() == NormalFunction || isSlot() || isInGlobalScope();
+ }
+ bool isInGlobalScope() const
+ {
+ return functionType() == GlobalScopeFunction;
+ }
+ bool isSignal() const
+ {
+ return functionType() == SignalFunction;
+ }
+ bool isSlot() const
+ {
+ return functionType() == SlotFunction;
+ }
+ bool isEmptyFunction() const
+ {
+ return functionType() == EmptyFunction;
+ }
+ FunctionType functionType() const
+ {
+ return m_functionType;
+ }
+ void setFunctionType(FunctionType type)
+ {
+ m_functionType = type;
+ }
+
+ QStringList introspectionCompatibleSignatures(const QStringList &resolvedArguments = QStringList()) const;
+ QString signature() const;
+ QString targetLangSignature(bool minimal = false) const;
+ bool shouldReturnThisObject() const
+ {
+ return QLatin1String("this") == argumentReplaced(0);
+ }
+ bool shouldIgnoreReturnValue() const
+ {
+ return QLatin1String("void") == argumentReplaced(0);
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+ void setConstant(bool constant)
+ {
+ m_constant = constant;
+ }
+
+ QString toString() const
+ {
+ return m_name;
+ }
+
+ uint compareTo(const AbstractMetaFunction *other) const;
+
+ bool operator <(const AbstractMetaFunction &a) const;
+
+ AbstractMetaFunction *copy() const;
+
+ QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
+ bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
+ QString conversionRule(TypeSystem::Language language, int idx) const;
+ QList<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const;
+ ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const;
+
+ bool nullPointersDisabled(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
+ QString nullPointerDefaultValue(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
+
+ bool resetObjectAfterUse(int argument_idx) const;
+
+ // Returns whether garbage collection is disabled for the argument in any context
+ bool disabledGarbageCollection(const AbstractMetaClass *cls, int key) const;
+
+ // Returns the ownership rules for the given argument in the given context
+ TypeSystem::Ownership ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int idx) const;
+
+ bool isVirtualSlot() const;
+
+ QString typeReplaced(int argument_index) const;
+ bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
+ bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
+ bool argumentRemoved(int) const;
+
+ QString argumentReplaced(int key) const;
+ bool needsSuppressUncheckedWarning() const;
+
+ bool hasModifications(const AbstractMetaClass *implementor) const;
+ /**
+ * Verifies if any modification to the function is an inject code.
+ * \return true if there is inject code modifications to the function.
+ */
+ bool hasInjectedCode() const;
+ /**
+ * Verifies if any modification to the function alters/removes its
+ * arguments types or default values.
+ * \return true if there is some modification to function signature
+ */
+ bool hasSignatureModifications() const;
+ FunctionModificationList modifications(const AbstractMetaClass *implementor) const;
+
+ // If this function stems from an interface, this returns the
+ // interface that declares it.
+ const AbstractMetaClass *interfaceClass() const
+ {
+ return m_interfaceClass;
+ }
+
+ void setInterfaceClass(const AbstractMetaClass *cl)
+ {
+ m_interfaceClass = cl;
+ }
+
+ void setPropertySpec(QPropertySpec *spec)
+ {
+ m_propertySpec = spec;
+ }
+
+ QPropertySpec *propertySpec() const
+ {
+ return m_propertySpec;
+ }
+
+private:
+ QString m_name;
+ QString m_originalName;
+ mutable QString m_cachedMinimalSignature;
+ mutable QString m_cachedModifiedName;
+
+ FunctionType m_functionType;
+ AbstractMetaType *m_type;
+ const AbstractMetaClass *m_class;
+ const AbstractMetaClass *m_implementingClass;
+ const AbstractMetaClass *m_declaringClass;
+ const AbstractMetaClass *m_interfaceClass;
+ QPropertySpec *m_propertySpec;
+ AbstractMetaArgumentList m_arguments;
+ uint m_constant : 1;
+ uint m_invalid : 1;
+ uint m_reverse : 1;
+ uint m_explicit : 1;
+};
+
+
+class AbstractMetaEnumValue
+{
+public:
+ AbstractMetaEnumValue()
+ : m_valueSet(false), m_value(0)
+ {
+ }
+
+ int value() const
+ {
+ return m_value;
+ }
+
+ void setValue(int value)
+ {
+ m_valueSet = true;
+ m_value = value;
+ }
+
+ QString stringValue() const
+ {
+ return m_stringValue;
+ }
+
+ void setStringValue(const QString &v)
+ {
+ m_stringValue = v;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ bool isValueSet() const
+ {
+ return m_valueSet;
+ }
+
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ QString m_name;
+ QString m_stringValue;
+
+ bool m_valueSet;
+ int m_value;
+
+ Documentation m_doc;
+};
+
+
+class AbstractMetaEnumValueList : public QList<AbstractMetaEnumValue *>
+{
+public:
+ AbstractMetaEnumValue *find(const QString &name) const;
+};
+
+class AbstractMetaEnum : public AbstractMetaAttributes
+{
+public:
+ AbstractMetaEnum() : m_typeEntry(0), m_class(0), m_hasQenumsDeclaration(false) {}
+
+ AbstractMetaEnumValueList values() const
+ {
+ return m_enumValues;
+ }
+
+ void addEnumValue(AbstractMetaEnumValue *enumValue)
+ {
+ m_enumValues << enumValue;
+ }
+
+ QString name() const
+ {
+ return m_typeEntry->targetLangName();
+ }
+
+ QString qualifier() const
+ {
+ return m_typeEntry->targetLangQualifier();
+ }
+
+ QString package() const
+ {
+ return m_typeEntry->targetLangPackage();
+ }
+
+ QString fullName() const
+ {
+ return package() + "." + qualifier() + "." + name();
+ }
+
+ // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class?
+ void setHasQEnumsDeclaration(bool on)
+ {
+ m_hasQenumsDeclaration = on;
+ }
+
+ bool hasQEnumsDeclaration() const
+ {
+ return m_hasQenumsDeclaration;
+ }
+
+ EnumTypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+
+ void setTypeEntry(EnumTypeEntry *entry)
+ {
+ m_typeEntry = entry;
+ }
+
+ AbstractMetaClass *enclosingClass() const
+ {
+ return m_class;
+ }
+
+ void setEnclosingClass(AbstractMetaClass *c)
+ {
+ m_class = c;
+ }
+
+private:
+ AbstractMetaEnumValueList m_enumValues;
+ EnumTypeEntry *m_typeEntry;
+ AbstractMetaClass *m_class;
+
+ uint m_hasQenumsDeclaration : 1;
+ uint m_reserved : 31;
+};
+
+typedef QList<AbstractMetaEnum *> AbstractMetaEnumList;
+
+class AbstractMetaClass : public AbstractMetaAttributes
+{
+public:
+ enum FunctionQueryOption {
+ Constructors = 0x0000001, // Only constructors
+ //Destructors = 0x0000002, // Only destructors. Not included in class.
+ VirtualFunctions = 0x0000004, // Only virtual functions (virtual in both TargetLang and C++)
+ FinalInTargetLangFunctions = 0x0000008, // Only functions that are non-virtual in TargetLang
+ FinalInCppFunctions = 0x0000010, // Only functions that are non-virtual in C++
+ ClassImplements = 0x0000020, // Only functions implemented by the current class
+ Inconsistent = 0x0000040, // Only inconsistent functions (inconsistent virtualness in TargetLang/C++)
+ StaticFunctions = 0x0000080, // Only static functions
+ Signals = 0x0000100, // Only signals
+ NormalFunctions = 0x0000200, // Only functions that aren't signals
+ Visible = 0x0000400, // Only public and protected functions
+ ForcedShellFunctions = 0x0000800, // Only functions that are overridden to be implemented in the shell class
+ WasPublic = 0x0001000, // Only functions that were originally public
+ WasProtected = 0x0002000, // Only functions that were originally protected
+ NonStaticFunctions = 0x0004000, // No static functions
+ Empty = 0x0008000, // Empty overrides of abstract functions
+ Invisible = 0x0010000, // Only private functions
+ VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++
+ NonEmptyFunctions = 0x0040000, // Only functions with target language API implementations
+ VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang
+ AbstractFunctions = 0x0100000, // Only abstract functions
+ WasVisible = 0x0200000, // Only functions that were public or protected in the original code
+ NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang
+ NotRemovedFromShell = 0x0800000, // Only functions that have not been removed from the shell class
+ VirtualSlots = 0x1000000, // Only functions that are set as virtual slots in the type system
+ OperatorOverloads = 0x2000000 // Only functions that are operator overloads
+ };
+
+ enum OperatorQueryOption {
+ ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, ++, --, unary+, unary-
+ BitwiseOp = 0x02, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^=
+ ComparisonOp = 0x04, // Comparison: <, <=, >, >=, !=, ==
+ LogicalOp = 0x08, // Logical: !, &&, ||
+ ConversionOp = 0x10, // Conversion: operator [const] TYPE()
+ SubscriptionOp = 0x20, // Subscription: []
+ AssignmentOp = 0x40, // Assignment: =
+ OtherOp = 0x80, // The remaining operators: call(), etc
+ AllOperators = ArithmeticOp | BitwiseOp | ComparisonOp
+ | LogicalOp | ConversionOp | SubscriptionOp
+ | AssignmentOp | OtherOp
+ };
+
+ AbstractMetaClass()
+ : m_namespace(false),
+ m_qobject(false),
+ m_hasVirtuals(false),
+ m_isPolymorphic(false),
+ m_hasNonpublic(false),
+ m_hasVirtualSlots(false),
+ m_hasNonPrivateConstructor(false),
+ m_functionsFixed(false),
+ m_hasPrivateDestructor(false),
+ m_forceShellClass(false),
+ m_hasHashFunction(false),
+ m_hasEqualsOperator(false),
+ m_hasCloneOperator(false),
+ m_isTypeAlias(false),
+ m_enclosingClass(0),
+ m_baseClass(0),
+ m_templateBaseClass(0),
+ m_extractedInterface(0),
+ m_primaryInterfaceImplementor(0),
+ m_typeEntry(0)//,
+ //m_qDebugStreamFunction(0)
+ {}
+
+ virtual ~AbstractMetaClass();
+
+ AbstractMetaClass *extractInterface();
+ void fixFunctions();
+
+ AbstractMetaFunctionList functions() const
+ {
+ return m_functions;
+ }
+
+ void setFunctions(const AbstractMetaFunctionList &functions);
+ void addFunction(AbstractMetaFunction *function);
+ bool hasFunction(const AbstractMetaFunction *f) const;
+ bool hasFunction(const QString &str) const;
+ bool hasSignal(const AbstractMetaFunction *f) const;
+
+ bool hasConstructors() const;
+
+ void addDefaultConstructor();
+
+ bool hasNonPrivateConstructor() const
+ {
+ return m_hasNonPrivateConstructor;
+ }
+
+ void setHasNonPrivateConstructor(bool value)
+ {
+ m_hasNonPrivateConstructor = value;
+ }
+
+ bool hasPrivateDestructor() const
+ {
+ return m_hasPrivateDestructor;
+ }
+
+ void setHasPrivateDestructor(bool value)
+ {
+ m_hasPrivateDestructor = value;
+ }
+
+ AbstractMetaFunctionList queryFunctionsByName(const QString &name) const;
+ AbstractMetaFunctionList queryFunctions(uint query) const;
+ inline AbstractMetaFunctionList allVirtualFunctions() const;
+ inline AbstractMetaFunctionList allFinalFunctions() const;
+ AbstractMetaFunctionList functionsInTargetLang() const;
+ AbstractMetaFunctionList functionsInShellClass() const;
+ inline AbstractMetaFunctionList cppInconsistentFunctions() const;
+ inline AbstractMetaFunctionList cppSignalFunctions() const;
+ AbstractMetaFunctionList publicOverrideFunctions() const;
+ AbstractMetaFunctionList virtualOverrideFunctions() const;
+ AbstractMetaFunctionList virtualFunctions() const;
+ AbstractMetaFunctionList nonVirtualShellFunctions() const;
+ AbstractMetaFunctionList implicitConversions() const;
+
+ /**
+ * Retrives all class' operator overloads that meet
+ * query crieteria defined with the OperatorQueryOption
+ * enum.
+ * /param query composition of OperatorQueryOption enum values
+ * /return list of operator overload methods that meet the
+ * query criteria
+ */
+ AbstractMetaFunctionList operatorOverloads(uint query = AllOperators) const;
+
+ bool hasOperatorOverload() const;
+ bool hasArithmeticOperatorOverload() const;
+ bool hasBitwiseOperatorOverload() const;
+ bool hasComparisonOperatorOverload() const;
+ bool hasLogicalOperatorOverload() const;
+ bool hasSubscriptOperatorOverload() const;
+ bool hasAssignmentOperatorOverload() const;
+ bool hasConversionOperatorOverload() const;
+
+ AbstractMetaFieldList fields() const
+ {
+ return m_fields;
+ }
+
+ void setFields(const AbstractMetaFieldList &fields)
+ {
+ m_fields = fields;
+ }
+
+ void addField(AbstractMetaField *field)
+ {
+ m_fields << field;
+ }
+
+ AbstractMetaEnumList enums() const
+ {
+ return m_enums;
+ }
+ void setEnums(const AbstractMetaEnumList &enums)
+ {
+ m_enums = enums;
+ }
+
+ void addEnum(AbstractMetaEnum *e)
+ {
+ m_enums << e;
+ }
+
+ AbstractMetaEnum *findEnum(const QString &enumName);
+ AbstractMetaEnum *findEnumForValue(const QString &enumName);
+ AbstractMetaEnumValue *findEnumValue(const QString &enumName, AbstractMetaEnum *meta_enum);
+
+ AbstractMetaClassList interfaces() const
+ {
+ return m_interfaces;
+ }
+ void addInterface(AbstractMetaClass *interface);
+ void setInterfaces(const AbstractMetaClassList &interface);
+
+ QString fullName() const
+ {
+ return package() + "." + name();
+ }
+
+ QString name() const;
+
+ QString baseClassName() const
+ {
+ return m_baseClass ? m_baseClass->name() : QString();
+ }
+
+ AbstractMetaClass *baseClass() const
+ {
+ return m_baseClass;
+ }
+
+ void setBaseClass(AbstractMetaClass *base_class);
+
+ const AbstractMetaClass *enclosingClass() const
+ {
+ return m_enclosingClass;
+ }
+
+ void setEnclosingClass(AbstractMetaClass *cl)
+ {
+ m_enclosingClass = cl;
+ }
+
+ const AbstractMetaClassList& innerClasses() const
+ {
+ return m_innerClasses;
+ }
+
+ void addInnerClass(AbstractMetaClass* cl)
+ {
+ m_innerClasses << cl;
+ }
+
+ void setInnerClasses(AbstractMetaClassList innerClasses)
+ {
+ m_innerClasses = innerClasses;
+ }
+
+ QString package() const
+ {
+ return m_typeEntry->targetLangPackage();
+ }
+
+ bool isInterface() const
+ {
+ return m_typeEntry->isInterface();
+ }
+
+ bool isNamespace() const
+ {
+ return m_typeEntry->isNamespace();
+ }
+
+ bool isQObject() const
+ {
+ return m_typeEntry->isQObject();
+ }
+
+ bool isQtNamespace() const
+ {
+ return isNamespace() && name() == "Qt";
+ }
+
+ QString qualifiedCppName() const
+ {
+ return m_typeEntry->qualifiedCppName();
+ }
+
+ bool hasInconsistentFunctions() const;
+ bool hasSignals() const;
+ bool inheritsFrom(const AbstractMetaClass *other) const;
+
+ void setForceShellClass(bool on)
+ {
+ m_forceShellClass = on;
+ }
+
+ bool generateShellClass() const;
+
+ bool hasVirtualSlots() const
+ {
+ return m_hasVirtualSlots;
+ }
+
+ /**
+ * Says if a class has any virtual functions of its own.
+ * \return true if the class implements any virtual methods
+ */
+ bool hasVirtualFunctions() const
+ {
+ return !isFinal() && m_hasVirtuals;
+ }
+ /**
+ * Says if the class that declares or inherits a virtual function.
+ * \return true if the class implements or inherits any virtual methods
+ */
+ bool isPolymorphic() const
+ {
+ return m_isPolymorphic;
+ }
+ bool hasProtectedFunctions() const;
+
+ QList<TypeEntry *> templateArguments() const
+ {
+ return m_templateArgs;
+ }
+
+ void setTemplateArguments(const QList<TypeEntry *> &args)
+ {
+ m_templateArgs = args;
+ }
+
+ bool hasFieldAccessors() const;
+
+ // only valid during metabuilder's run
+ QStringList baseClassNames() const
+ {
+ return m_baseClassNames;
+ }
+
+ void setBaseClassNames(const QStringList &names)
+ {
+ m_baseClassNames = names;
+ }
+
+ AbstractMetaClass *primaryInterfaceImplementor() const
+ {
+ return m_primaryInterfaceImplementor;
+ }
+
+ void setPrimaryInterfaceImplementor(AbstractMetaClass *cl)
+ {
+ m_primaryInterfaceImplementor = cl;
+ }
+
+ const ComplexTypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+
+ ComplexTypeEntry *typeEntry()
+ {
+ return m_typeEntry;
+ }
+
+ void setTypeEntry(ComplexTypeEntry *type)
+ {
+ m_typeEntry = type;
+ }
+
+ void setHasHashFunction(bool on)
+ {
+ m_hasHashFunction = on;
+ }
+
+ bool hasHashFunction() const
+ {
+ return m_hasHashFunction;
+ }
+#if 0
+ void setToStringCapability(FunctionModelItem fun)
+ {
+ m_qDebugStreamFunction = fun;
+ }
+
+ FunctionModelItem hasToStringCapability() const
+ {
+ return m_qDebugStreamFunction;
+ }
+#endif
+ virtual bool hasDefaultToStringFunction() const;
+
+ void setHasEqualsOperator(bool on)
+ {
+ m_hasEqualsOperator = on;
+ }
+
+ bool hasEqualsOperator() const
+ {
+ return m_hasEqualsOperator;
+ }
+
+ void setHasCloneOperator(bool on)
+ {
+ m_hasCloneOperator = on;
+ }
+
+ bool hasCloneOperator() const
+ {
+ return m_hasCloneOperator;
+ }
+
+ void addPropertySpec(QPropertySpec *spec)
+ {
+ m_propertySpecs << spec;
+ }
+
+ QList<QPropertySpec *> propertySpecs() const
+ {
+ return m_propertySpecs;
+ }
+
+ QPropertySpec *propertySpecForRead(const QString &name) const;
+ QPropertySpec *propertySpecForWrite(const QString &name) const;
+ QPropertySpec *propertySpecForReset(const QString &name) const;
+
+ QList<ReferenceCount> referenceCounts() const;
+
+ void setEqualsFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_equalsFunctions = lst;
+ }
+
+ AbstractMetaFunctionList equalsFunctions() const
+ {
+ return m_equalsFunctions;
+ }
+
+ void setNotEqualsFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_nequalsFunctions = lst;
+ }
+
+ AbstractMetaFunctionList notEqualsFunctions() const
+ {
+ return m_nequalsFunctions;
+ }
+
+ void setLessThanFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_lessThanFunctions = lst;
+ }
+
+ AbstractMetaFunctionList lessThanFunctions() const
+ {
+ return m_lessThanFunctions;
+ }
+
+ void setGreaterThanFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_greaterThanFunctions = lst;
+ }
+
+ AbstractMetaFunctionList greaterThanFunctions() const
+ {
+ return m_greaterThanFunctions;
+ }
+
+ void setLessThanEqFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_lessThanEqFunctions = lst;
+ }
+
+ AbstractMetaFunctionList lessThanEqFunctions() const
+ {
+ return m_lessThanEqFunctions;
+ }
+
+ void setGreaterThanEqFunctions(const AbstractMetaFunctionList &lst)
+ {
+ m_greaterThanEqFunctions = lst;
+ }
+
+ AbstractMetaFunctionList greaterThanEqFunctions() const
+ {
+ return m_greaterThanEqFunctions;
+ }
+
+ void sortFunctions();
+
+ const AbstractMetaClass *templateBaseClass() const
+ {
+ return m_templateBaseClass;
+ }
+
+ void setTemplateBaseClass(const AbstractMetaClass *cls)
+ {
+ m_templateBaseClass = cls;
+ }
+
+ void setTypeAlias(bool typeAlias)
+ {
+ m_isTypeAlias = typeAlias;
+ }
+
+ bool isTypeAlias() const
+ {
+ return m_isTypeAlias;
+ }
+
+private:
+ uint m_namespace : 1;
+ uint m_qobject : 1;
+ uint m_hasVirtuals : 1;
+ uint m_isPolymorphic : 1;
+ uint m_hasNonpublic : 1;
+ uint m_hasVirtualSlots : 1;
+ uint m_hasNonPrivateConstructor : 1;
+ uint m_functionsFixed : 1;
+ uint m_hasPrivateDestructor : 1;
+ uint m_forceShellClass : 1;
+ uint m_hasHashFunction : 1;
+ uint m_hasEqualsOperator : 1;
+ uint m_hasCloneOperator : 1;
+ uint m_isTypeAlias : 1;
+ uint m_reserved : 18;
+
+ const AbstractMetaClass *m_enclosingClass;
+ AbstractMetaClass *m_baseClass;
+ const AbstractMetaClass *m_templateBaseClass;
+ AbstractMetaFunctionList m_functions;
+ AbstractMetaFieldList m_fields;
+ AbstractMetaEnumList m_enums;
+ AbstractMetaClassList m_interfaces;
+ AbstractMetaClass *m_extractedInterface;
+ AbstractMetaClass *m_primaryInterfaceImplementor;
+ QList<QPropertySpec *> m_propertySpecs;
+ AbstractMetaFunctionList m_equalsFunctions;
+ AbstractMetaFunctionList m_nequalsFunctions;
+ AbstractMetaClassList m_innerClasses;
+
+ AbstractMetaFunctionList m_lessThanFunctions;
+ AbstractMetaFunctionList m_greaterThanFunctions;
+ AbstractMetaFunctionList m_lessThanEqFunctions;
+ AbstractMetaFunctionList m_greaterThanEqFunctions;
+
+ QStringList m_baseClassNames;
+ QList<TypeEntry *> m_templateArgs;
+ ComplexTypeEntry *m_typeEntry;
+// FunctionModelItem m_qDebugStreamFunction;
+};
+
+class QPropertySpec
+{
+public:
+ QPropertySpec(const TypeEntry *type)
+ : m_type(type),
+ m_index(-1)
+ {}
+
+ const TypeEntry *type() const
+ {
+ return m_type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ QString read() const
+ {
+ return m_read;
+ }
+
+ void setRead(const QString &read)
+ {
+ m_read = read;
+ }
+
+ QString write() const
+ {
+ return m_write;
+ }
+
+ void setWrite(const QString &write)
+ {
+ m_write = write;
+ }
+
+ QString designable() const
+ {
+ return m_designable;
+ }
+
+ void setDesignable(const QString &designable)
+ {
+ m_designable = designable;
+ }
+
+ QString reset() const
+ {
+ return m_reset;
+ }
+
+ void setReset(const QString &reset)
+ {
+ m_reset = reset;
+ }
+
+ int index() const
+ {
+ return m_index;
+ }
+
+ void setIndex(int index)
+ {
+ m_index = index;
+ }
+
+private:
+ QString m_name;
+ QString m_read;
+ QString m_write;
+ QString m_designable;
+ QString m_reset;
+ const TypeEntry *m_type;
+ int m_index;
+};
+
+inline AbstractMetaFunctionList AbstractMetaClass::allVirtualFunctions() const
+{
+ return queryFunctions(VirtualFunctions | NotRemovedFromTargetLang);
+}
+
+inline AbstractMetaFunctionList AbstractMetaClass::allFinalFunctions() const
+{
+ return queryFunctions(FinalInTargetLangFunctions
+ | FinalInCppFunctions
+ | NotRemovedFromTargetLang);
+}
+
+inline AbstractMetaFunctionList AbstractMetaClass::cppInconsistentFunctions() const
+{
+ return queryFunctions(Inconsistent
+ | NormalFunctions
+ | Visible
+ | NotRemovedFromTargetLang);
+}
+
+inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
+{
+ return queryFunctions(Signals
+ | Visible
+ | NotRemovedFromTargetLang);
+}
+
+#endif // ABSTRACTMETALANG_H
diff --git a/apiextractor.cpp b/apiextractor.cpp
new file mode 100644
index 000000000..d2ef9ee23
--- /dev/null
+++ b/apiextractor.cpp
@@ -0,0 +1,307 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "apiextractor.h"
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <iostream>
+
+#include "reporthandler.h"
+#include "typesystem.h"
+#include "fileout.h"
+#include "parser/rpp/pp.h"
+#include "abstractmetabuilder.h"
+#include "generator.h"
+#include "apiextractorversion.h"
+
+static bool preprocess(const QString& sourceFile,
+ const QString& targetFile,
+ const QString& commandLineIncludes);
+
+ApiExtractor::ApiExtractor(int argc, char** argv) : m_versionHandler(0)
+{
+ m_programName = argv[0];
+ // store args in m_args map
+ int argNum = 0;
+ for (int i = 1; i < argc; ++i) {
+ QString arg(argv[i]);
+ arg = arg.trimmed();
+ if (arg.startsWith("--")) {
+ int split = arg.indexOf("=");
+ if (split > 0)
+ m_args[arg.mid(2).left(split-2)] = arg.mid(split + 1).trimmed();
+ else
+ m_args[arg.mid(2)] = QString();
+ } else if (arg.startsWith("-")) {
+ m_args[arg.mid(1)] = QString();
+ } else {
+ argNum++;
+ m_args[QString("arg-%1").arg(argNum)] = arg;
+ }
+ }
+
+ // Environment TYPESYSTEMPATH
+ QString envTypesystemPaths = getenv("TYPESYSTEMPATH");
+ TypeDatabase::instance()->addTypesystemPath(envTypesystemPaths);
+ ReportHandler::setContext("ApiExtractor");
+}
+
+ApiExtractor::~ApiExtractor()
+{
+ qDeleteAll(m_generators);
+}
+
+void ApiExtractor::addGenerator(Generator* generator)
+{
+ m_generators << generator;
+}
+
+bool ApiExtractor::parseGeneralArgs()
+{
+ // set debug level
+ if (m_args.contains("silent")) {
+ ReportHandler::setSilent(true);
+ } else if (m_args.contains("debug-level")) {
+ QString level = m_args.value("debug-level");
+ if (level == "sparse")
+ ReportHandler::setDebugLevel(ReportHandler::SparseDebug);
+ else if (level == "medium")
+ ReportHandler::setDebugLevel(ReportHandler::MediumDebug);
+ else if (level == "full")
+ ReportHandler::setDebugLevel(ReportHandler::FullDebug);
+ }
+
+ if (m_args.contains("no-suppress-warnings")) {
+ TypeDatabase *db = TypeDatabase::instance();
+ db->setSuppressWarnings(false);
+ }
+
+ if (m_args.contains("dummy"))
+ FileOut::dummy = true;
+
+ if (m_args.contains("diff"))
+ FileOut::diff = true;
+
+ if (m_args.count() == 1)
+ return false;
+
+ if (m_args.contains("typesystem-paths"))
+ TypeDatabase::instance()->addTypesystemPath(m_args.value("typesystem-paths"));
+
+ m_globalHeaderFileName = m_args.value("arg-1");
+ m_typeSystemFileName = m_args.value("arg-2");
+ if (m_args.contains("arg-3"))
+ return false;
+
+ if (m_globalHeaderFileName.isEmpty() || m_typeSystemFileName.isEmpty())
+ return false;
+ return true;
+}
+
+int ApiExtractor::exec()
+{
+ if (m_args.contains("version")) {
+ if (m_versionHandler)
+ m_versionHandler("ApiExtractor v" APIEXTRACTOR_VERSION);
+ else
+ std::cout << m_programName << " using ApiExtractor v" APIEXTRACTOR_VERSION << std::endl;
+ return 0;
+ } else if (!parseGeneralArgs()) {
+ printUsage();
+ return 1;
+ }
+
+ QLatin1String ppFileName(".preprocessed.tmp");
+
+ if (!TypeDatabase::instance()->parseFile(m_typeSystemFileName))
+ std::cerr << "Cannot parse file: " << qPrintable(m_typeSystemFileName);
+
+ if (!preprocess(m_globalHeaderFileName, ppFileName, m_args.value("include-paths"))) {
+ std::cerr << "Preprocessor failed on file: " << qPrintable(m_globalHeaderFileName);
+ return 1;
+ }
+
+ QString licenseComment;
+ if (m_args.contains("license-file") && !m_args.value("license-file").isEmpty()) {
+ QString license_filename = m_args.value("license-file");
+ if (QFile::exists(license_filename)) {
+ QFile license_file(license_filename);
+ if (license_file.open(QIODevice::ReadOnly))
+ licenseComment = license_file.readAll();
+ } else {
+ std::cerr << "Couldn't find the file containing the license heading: ";
+ std::cerr << qPrintable(license_filename);
+ return 1;
+ }
+ }
+
+ AbstractMetaBuilder builder;
+ QFile ppFile(ppFileName);
+ builder.build(&ppFile);
+
+ QString outputDirectory = m_args.contains("output-directory") ? m_args["output-directory"] : "out";
+ bool docOnly = m_args.contains("documentation-only");
+ foreach (Generator* g, m_generators) {
+ bool docGen = g->type() == Generator::DocumentationType;
+ bool missingDocInfo = m_args["library-source-dir"].isEmpty()
+ || m_args["documentation-data-dir"].isEmpty();
+ if ((!docGen && docOnly) || (docGen && missingDocInfo)) {
+ std::cout << "Skipping " << g->name() << std::endl;
+ continue;
+ }
+ g->setOutputDirectory(outputDirectory);
+ g->setLicenseComment(licenseComment);
+ g->setBuilder(&builder);
+ std::cout << "Running " << g->name() << std::endl;
+ if (g->prepareGeneration(m_args))
+ g->generate();
+ }
+
+ std::cout << "Done, " << ReportHandler::warningCount();
+ std::cout << " warnings (" << ReportHandler::suppressedCount() << " known issues)";
+ std::cout << std::endl;
+ return 0;
+}
+
+static void printOptions(QTextStream& s, const QMap<QString, QString>& options) {
+ QMap<QString, QString>::const_iterator it = options.constBegin();
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ for (; it != options.constEnd(); ++it) {
+ s << " --";
+ s.setFieldWidth(38);
+ s << it.key() << it.value();
+ s.setFieldWidth(0);
+ s << endl;
+ }
+}
+
+void ApiExtractor::printUsage()
+{
+ #if defined(Q_OS_WIN32)
+ #define PATHSPLITTER ";"
+ #else
+ #define PATHSPLITTER ":"
+ #endif
+ QTextStream s(stdout);
+ s << "Usage:\n "
+ << m_programName << " [options] header-file typesystem-file\n\n"
+ "General options:\n";
+ QMap<QString, QString> generalOptions;
+ generalOptions.insert("debug-level=[sparse|medium|full]", "Set the debug level");
+ generalOptions.insert("silent", "Avoid printing any message");
+ generalOptions.insert("help", "Display this help and exit");
+ generalOptions.insert("no-suppress-warnings", "Show all warnings");
+ generalOptions.insert("output-directory=[dir]", "The directory where the generated files will be written");
+ generalOptions.insert("include-paths=<path>[" PATHSPLITTER "<path>" PATHSPLITTER "...]", "Include paths used by the C++ parser");
+ generalOptions.insert("typesystem-paths=<path>[" PATHSPLITTER "<path>" PATHSPLITTER "...]", "Paths used when searching for typesystems");
+ generalOptions.insert("documentation-only", "Do not generates any code, just the documentation");
+ generalOptions.insert("license-file=[licensefile]", "File used for copyright headers of generated files");
+ generalOptions.insert("version", "Output version information and exit");
+ printOptions(s, generalOptions);
+
+ foreach (Generator* generator, m_generators) {
+ QMap<QString, QString> options = generator->options();
+ if (!options.isEmpty()) {
+ s << endl << generator->name() << " options:\n";
+ printOptions(s, generator->options());
+ }
+ }
+}
+
+
+static bool preprocess(const QString& sourceFile,
+ const QString& targetFile,
+ const QString& commandLineIncludes)
+{
+ rpp::pp_environment env;
+ rpp::pp preprocess(env);
+
+ rpp::pp_null_output_iterator null_out;
+
+ const char *ppconfig = ":/trolltech/generator/pp-qt-configuration";
+
+ QFile file(ppconfig);
+ if (!file.open(QFile::ReadOnly)) {
+ std::cerr << "Preprocessor configuration file not found " << ppconfig << std::endl;
+ return false;
+ }
+
+ QByteArray ba = file.readAll();
+ file.close();
+ preprocess.operator()(ba.constData(), ba.constData() + ba.size(), null_out);
+
+ QStringList includes;
+
+#if defined(Q_OS_WIN32)
+ char *pathSplitter = const_cast<char *>(";");
+#else
+ char *pathSplitter = const_cast<char *>(":");
+#endif
+
+ // Environment INCLUDE
+ QString includePath = getenv("INCLUDE");
+ if (!includePath.isEmpty())
+ includes += includePath.split(pathSplitter);
+
+ // Includes from the command line
+ if (!commandLineIncludes.isEmpty())
+ includes += commandLineIncludes.split(pathSplitter);
+
+ includes << QLatin1String(".");
+ includes << QLatin1String("/usr/include");
+
+ foreach (QString include, includes)
+ preprocess.push_include_path(QDir::convertSeparators(include).toStdString());
+
+ QString currentDir = QDir::current().absolutePath();
+ QFileInfo sourceInfo(sourceFile);
+ if (!sourceInfo.exists()) {
+ std::cerr << "File not found " << qPrintable(sourceFile) << std::endl;
+ return false;
+ }
+ QDir::setCurrent(sourceInfo.absolutePath());
+
+ std::string result;
+ result.reserve(20 * 1024); // 20K
+
+ result += "# 1 \"builtins\"\n";
+ result += "# 1 \"";
+ result += sourceFile.toStdString();
+ result += "\"\n";
+
+ preprocess.file(sourceInfo.fileName().toStdString(),
+ rpp::pp_output_iterator<std::string> (result));
+
+ QDir::setCurrent(currentDir);
+
+ QFile f(targetFile);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ std::cerr << "Failed to write preprocessed file: " << qPrintable(targetFile) << std::endl;
+ return false;
+ }
+
+ f.write(result.c_str(), result.length());
+
+ return true;
+}
+
diff --git a/apiextractor.h b/apiextractor.h
new file mode 100644
index 000000000..301e8cdd3
--- /dev/null
+++ b/apiextractor.h
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef APIEXTRACTOR_H
+#define APIEXTRACTOR_H
+
+#include <QLinkedList>
+#include <QMap>
+#include <QString>
+
+class Generator;
+
+class ApiExtractor
+{
+public:
+ ApiExtractor(int argc, char** argv);
+ ~ApiExtractor();
+
+ void addGenerator(Generator* generator);
+ void setVersionHandler(void (*versionHandler)(const char*))
+ {
+ m_versionHandler = versionHandler;
+ }
+
+ int exec();
+
+private:
+ QLinkedList<Generator*> m_generators;
+ QMap<QString, QString> m_args;
+ QString m_typeSystemFileName;
+ QString m_globalHeaderFileName;
+ const char* m_programName;
+ void (*m_versionHandler)(const char*);
+
+ bool parseGeneralArgs();
+ void printUsage();
+
+ // disable copy
+ ApiExtractor(const ApiExtractor&);
+ ApiExtractor& operator=(const ApiExtractor&);
+};
+
+#endif // APIEXTRACTOR_H
diff --git a/apiextractor.pc.in b/apiextractor.pc.in
new file mode 100644
index 000000000..07896a1a0
--- /dev/null
+++ b/apiextractor.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@/bin
+libdir=@CMAKE_INSTALL_PREFIX@/lib
+includedir=@CMAKE_INSTALL_PREFIX@/include
+
+Name: apiextractor
+Description: Qt4 Binding Generator library
+Requires: QtCore
+Version: @apiextractor_VERSION@
+Libs: -L${libdir} -lapiextractor
+Cflags: -I${includedir}/apiextractor
diff --git a/apiextractorversion.h.in b/apiextractorversion.h.in
new file mode 100644
index 000000000..45ce51e83
--- /dev/null
+++ b/apiextractorversion.h.in
@@ -0,0 +1,4 @@
+#ifndef APIEXTRACTORVERSION_H
+#define APIEXTRACTORVERSION_H
+#define APIEXTRACTOR_VERSION "@apiextractor_VERSION@"
+#endif
diff --git a/asttoxml.cpp b/asttoxml.cpp
new file mode 100644
index 000000000..e884835c0
--- /dev/null
+++ b/asttoxml.cpp
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "asttoxml.h"
+#include "parser/control.h"
+#include "parser/parser.h"
+#include "parser/binder.h"
+
+
+#include <QtCore/QXmlStreamWriter>
+#include <QtCore/QTextStream>
+#include <QtCore/QTextCodec>
+#include <QtCore/QFile>
+
+void astToXML(QString name)
+{
+ QFile file(name);
+
+ if (!file.open(QFile::ReadOnly))
+ return;
+
+ QTextStream stream(&file);
+ stream.setCodec(QTextCodec::codecForName("UTF-8"));
+ QByteArray contents = stream.readAll().toUtf8();
+ file.close();
+
+ Control control;
+ Parser p(&control);
+ pool __pool;
+
+ TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
+
+ CodeModel model;
+ Binder binder(&model, p.location());
+ FileModelItem dom = binder.run(ast);
+
+ QFile outputFile;
+ if (!outputFile.open(stdout, QIODevice::WriteOnly))
+ return;
+
+ QXmlStreamWriter s(&outputFile);
+ s.setAutoFormatting(true);
+
+ s.writeStartElement("code");
+
+ QHash<QString, NamespaceModelItem> namespaceMap = dom->namespaceMap();
+ foreach (NamespaceModelItem item, namespaceMap.values())
+ writeOutNamespace(s, item);
+
+ QHash<QString, ClassModelItem> typeMap = dom->classMap();
+ foreach (ClassModelItem item, typeMap.values())
+ writeOutClass(s, item);
+
+ s.writeEndElement();
+}
+
+
+void writeOutNamespace(QXmlStreamWriter &s, NamespaceModelItem &item)
+{
+ s.writeStartElement("namespace");
+ s.writeAttribute("name", item->name());
+
+ QHash<QString, NamespaceModelItem> namespaceMap = item->namespaceMap();
+ foreach (NamespaceModelItem item, namespaceMap.values())
+ writeOutNamespace(s, item);
+
+ QHash<QString, ClassModelItem> typeMap = item->classMap();
+ foreach (ClassModelItem item, typeMap.values())
+ writeOutClass(s, item);
+
+ QHash<QString, EnumModelItem> enumMap = item->enumMap();
+ foreach (EnumModelItem item, enumMap.values())
+ writeOutEnum(s, item);
+
+ s.writeEndElement();
+}
+
+void writeOutEnum(QXmlStreamWriter &s, EnumModelItem &item)
+{
+ QString qualifiedName = item->qualifiedName().join("::");
+ s.writeStartElement("enum");
+ s.writeAttribute("name", qualifiedName);
+
+ EnumeratorList enumList = item->enumerators();
+ for (int i = 0; i < enumList.size() ; i++) {
+ s.writeStartElement("enumerator");
+ if (!enumList[i]->value().isEmpty())
+ s.writeAttribute("value", enumList[i]->value());
+ s.writeCharacters(enumList[i]->name());
+
+ s.writeEndElement();
+ }
+ s.writeEndElement();
+}
+
+void writeOutFunction(QXmlStreamWriter &s, FunctionModelItem &item)
+{
+ QString qualifiedName = item->qualifiedName().join("::");
+ s.writeStartElement("function");
+ s.writeAttribute("name", qualifiedName);
+
+ ArgumentList arguments = item->arguments();
+ for (int i = 0; i < arguments.size() ; i++) {
+ s.writeStartElement("argument");
+ s.writeAttribute("type", arguments[i]->type().qualifiedName().join("::"));
+ s.writeEndElement();
+ }
+ s.writeEndElement();
+}
+
+void writeOutClass(QXmlStreamWriter &s, ClassModelItem &item)
+{
+ QString qualifiedName = item->qualifiedName().join("::");
+ s.writeStartElement("class");
+ s.writeAttribute("name", qualifiedName);
+
+ QHash<QString, EnumModelItem> enumMap = item->enumMap();
+ foreach (EnumModelItem item, enumMap.values())
+ writeOutEnum(s, item);
+
+ QHash<QString, FunctionModelItem> functionMap = item->functionMap();
+ foreach (FunctionModelItem item, functionMap.values())
+ writeOutFunction(s, item);
+
+ QHash<QString, ClassModelItem> typeMap = item->classMap();
+ foreach (ClassModelItem item, typeMap.values())
+ writeOutClass(s, item);
+
+ s.writeEndElement();
+}
+
diff --git a/asttoxml.h b/asttoxml.h
new file mode 100644
index 000000000..43c7cc238
--- /dev/null
+++ b/asttoxml.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef ASTTOXML
+#define ASTTOXML
+
+#include "parser/codemodel.h"
+
+#include <QtCore/QString>
+#include <QtCore/QXmlStreamWriter>
+
+void astToXML(const QString name);
+void writeOutNamespace(QXmlStreamWriter &s, NamespaceModelItem &item);
+void writeOutEnum(QXmlStreamWriter &s, EnumModelItem &item);
+void writeOutFunction(QXmlStreamWriter &s, FunctionModelItem &item);
+void writeOutClass(QXmlStreamWriter &s, ClassModelItem &item);
+
+
+#endif // ASTTOXML
diff --git a/cmake_uninstall.cmake b/cmake_uninstall.cmake
new file mode 100644
index 000000000..df95fb9d8
--- /dev/null
+++ b/cmake_uninstall.cmake
@@ -0,0 +1,21 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..0f70dfc08
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,88 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf _build/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
+ @echo
+ @echo "Build finished. The HTML pages are in _build/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in _build/dirhtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in _build/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in _build/qthelp, like this:"
+ @echo "# qcollectiongenerator _build/qthelp/APIExtractor.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile _build/qthelp/APIExtractor.qhc"
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in _build/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
+ @echo
+ @echo "The overview file is in _build/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in _build/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in _build/doctest/output.txt."
diff --git a/doc/_static/.gitignore b/doc/_static/.gitignore
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/doc/_static/.gitignore
diff --git a/doc/_static/basic.css b/doc/_static/basic.css
new file mode 100644
index 000000000..2509c227f
--- /dev/null
+++ b/doc/_static/basic.css
@@ -0,0 +1,417 @@
+/**
+ * Sphinx stylesheet -- basic theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.clearer {
+ clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 0px;
+ list-style: none;
+}
+
+div.related li {
+ float: left;
+ display: inline;
+ padding-right:17px;
+ padding-left:10px;
+ background-image:url(images/bread_crumb.png);
+ background-position:right;
+ background-repeat:no-repeat;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+ padding: 0 0 0 0px;
+ background-image:none;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+img {
+ border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ text-align: left;
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ text-align: left;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+ padding: 2px 8px 2px 8px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dt:target, .highlight {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.refcount {
+ color: #060;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
diff --git a/doc/_static/default.css b/doc/_static/default.css
new file mode 100644
index 000000000..721ceb71b
--- /dev/null
+++ b/doc/_static/default.css
@@ -0,0 +1,248 @@
+/**
+ * Sphinx stylesheet -- default theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #000000;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+div.document {
+ background-image:url(images/side_background.jpg);
+ background-repeat:repeat-y;
+ background-color:#ffd800;
+}
+
+div.body {
+ position:relative;
+ background-color:#fff;
+ color: #000000;
+ padding: 0 20px 30px 20px;
+}
+
+div.footer {
+ color: #ffffff;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #ffffff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-image:url(images/top_background.jpg);
+ background-repeat:repeat-x;
+ background-color: #d7aa00;
+ line-height:33px;
+ height:33px;
+ color: #000000;
+}
+
+div.related a {
+ color: #000000;
+}
+
+div.related img {
+ padding-top:3px;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+ font-family: Arial, Verdana, sans-serif;
+ color: #000000;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: #000000;
+}
+
+div.sphinxsidebar h4 {
+ font-family: Arial, Verdana, sans-serif;
+ color: #000000;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ color: #ffffff;
+}
+
+div#searchbox p.searchtip {
+ color:#000000;
+ font-size:90%;
+ padding-top:50px;
+}
+
+div#searchbox {
+ background-image:url(images/background_search.jpg);
+ background-repeat:no-repeat;
+ background-position:center;
+ border:none;
+}
+
+div.sphinxsidebar a {
+ color: #009491;
+}
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+a {
+ color: #009491;
+ text-decoration: underline;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: left;
+ line-height: 130%;
+}
+
+div.body h1 {
+ font-family: Arial, Verdana, sans-serif;
+ background-color: #f2f2f2;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: Arial, Verdana, Helvetica, sans-serif;
+ font-size:12px;
+ font-weight:normal;
+ border-left-width: 1px;
+ border-right-width: 1px;
+ border-top-width: 1px;
+ border-bottom-width: 2px;
+ border-style: solid;
+ border-left-color: #b1b1b1;
+ border-right-color: #b1b1b1;
+ border-top-color: #b1b1b1;
+ border-bottom-color: #009491;
+ background-color: #e0e0e0;
+ padding-left:5px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 120%; }
+div.body h3 { font-size: 115%; }
+div.body h4 { font-size: 110%; }
+div.body h5 { font-size: 105%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: left;
+ line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.topic {
+ background-color: #eee;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+input[type=text]{
+ background-color: #009491;
+ font: 11px verdana, arial, helvetica, sans-serif;
+ color:#FFFFFF;
+ width: 150px;
+ height: 18px;
+ border: 1px solid #009491;
+ margin-left:13px;
+ margin-top:15px;
+ margin-bottom:4px;
+ border:none;
+}
+
+pre {
+ padding: 5px;
+ background-color: #eeffcc;
+ color: #333333;
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
diff --git a/doc/_static/images/._background_search.jpg b/doc/_static/images/._background_search.jpg
new file mode 100755
index 000000000..d5c689c31
--- /dev/null
+++ b/doc/_static/images/._background_search.jpg
Binary files differ
diff --git a/doc/_static/images/._bread_crumb.png b/doc/_static/images/._bread_crumb.png
new file mode 100755
index 000000000..46b8591c6
--- /dev/null
+++ b/doc/_static/images/._bread_crumb.png
Binary files differ
diff --git a/doc/_static/images/._button_search.jpg b/doc/_static/images/._button_search.jpg
new file mode 100755
index 000000000..d5c689c31
--- /dev/null
+++ b/doc/_static/images/._button_search.jpg
Binary files differ
diff --git a/doc/_static/images/._side_background.jpg b/doc/_static/images/._side_background.jpg
new file mode 100755
index 000000000..a79b91c97
--- /dev/null
+++ b/doc/_static/images/._side_background.jpg
Binary files differ
diff --git a/doc/_static/images/._top_background.jpg b/doc/_static/images/._top_background.jpg
new file mode 100755
index 000000000..d5c689c31
--- /dev/null
+++ b/doc/_static/images/._top_background.jpg
Binary files differ
diff --git a/doc/_static/images/background_search.jpg b/doc/_static/images/background_search.jpg
new file mode 100644
index 000000000..c0481c561
--- /dev/null
+++ b/doc/_static/images/background_search.jpg
Binary files differ
diff --git a/doc/_static/images/bg.jpg b/doc/_static/images/bg.jpg
new file mode 100644
index 000000000..2ceb19583
--- /dev/null
+++ b/doc/_static/images/bg.jpg
Binary files differ
diff --git a/doc/_static/images/bread_crumb.png b/doc/_static/images/bread_crumb.png
new file mode 100644
index 000000000..f7ebd20e4
--- /dev/null
+++ b/doc/_static/images/bread_crumb.png
Binary files differ
diff --git a/doc/_static/images/button_search.png b/doc/_static/images/button_search.png
new file mode 100644
index 000000000..0160b81ab
--- /dev/null
+++ b/doc/_static/images/button_search.png
Binary files differ
diff --git a/doc/_static/images/side_background.jpg b/doc/_static/images/side_background.jpg
new file mode 100644
index 000000000..6e6667542
--- /dev/null
+++ b/doc/_static/images/side_background.jpg
Binary files differ
diff --git a/doc/_static/images/top_background.jpg b/doc/_static/images/top_background.jpg
new file mode 100644
index 000000000..aafe1f72e
--- /dev/null
+++ b/doc/_static/images/top_background.jpg
Binary files differ
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
new file mode 100644
index 000000000..00a829ccc
--- /dev/null
+++ b/doc/_templates/index.html
@@ -0,0 +1,26 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+{% block body %}
+ <h1>API Extractor {{ version }}</h1>
+
+ <p>API Extractor is a tool that eases the development of bindings of Qt-based libraries for high
+ level languages by automating most of the process.
+
+ <p>API Extractor is based on the
+ <a href="http://labs.trolltech.com/page/Projects/QtScript/Generator">QtScriptGenerator</a> project.</p>
+
+ <h2>Documentation</h2>
+ <table class="contentstable" align="center" style="margin-left: 30px"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("overview") }}">Overview</a><br/>
+ <span class="linkdescr">how API Extractor works</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("typesystem") }}">Typesystem reference</a><br/>
+ <span class="linkdescr">reference for all typesystem tags</span></p>
+ </td>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
+ <span class="linkdescr">for a complete overview</span></p>
+ </td></tr>
+ </table>
+
+{% endblock %}
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
new file mode 100644
index 000000000..12fed4d0f
--- /dev/null
+++ b/doc/_templates/layout.html
@@ -0,0 +1,34 @@
+{% extends "!layout.html" %}
+{% block rootrellink %}
+ <!--<li><img src="{{ pathto('_static/py.png', 1) }}" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>-->
+ <li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
+{% endblock %}
+{% set reldelim1 = '' %}
+{% block extrahead %}
+ <!--<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/py.png', 1) }}" />-->
+{{ super() }}
+{% endblock %}
+
+{% block sidebarsearch %}
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <div style="width:195px;">
+ <div style="float:left;">
+ <input type="text" name="q" size="18" />
+ </div>
+ <div style="float:right; padding-top:14px; ">
+ <input type="image" src="{{ pathto('_static/images/button_search.png', 1) }}"/>
+ </div>
+ </div>
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+{% endblock %}
+
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 000000000..77a4122cd
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+#
+# ApiExtractor documentation build configuration file, created by
+# sphinx-quickstart on Wed Apr 22 15:04:20 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage']
+
+rst_epilog = """
+.. |project| replace:: API Extractor
+"""
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+#master_doc = 'contents'
+
+# General information about the project.
+project = u'API Extractor'
+copyright = u'2009, Nokia Corporation'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.2'
+# The full version, including alpha/beta/rc tags.
+release = '0.2'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {
+#}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = { '' : ''}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = { 'index' : 'index.html'}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'apiextractor.tex', u'API Extractor Documentation',
+ u'Nokia Corporation', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/doc/contents.rst b/doc/contents.rst
new file mode 100644
index 000000000..88362d38d
--- /dev/null
+++ b/doc/contents.rst
@@ -0,0 +1,8 @@
+Table of contents
+*****************
+.. toctree::
+ :numbered:
+ :maxdepth: 3
+
+ overview.rst
+ typesystem.rst
diff --git a/doc/dependency-apiextractor.svg b/doc/dependency-apiextractor.svg
new file mode 100644
index 000000000..6bec8b5a8
--- /dev/null
+++ b/doc/dependency-apiextractor.svg
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="750"
+ height="230"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="dependency-apiextractor.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/tmp/dependency-pyside.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3270"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible">
+ <path
+ id="path3679"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.6315754"
+ inkscape:cx="375"
+ inkscape:cy="115"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1278"
+ inkscape:window-height="949"
+ inkscape:window-x="1330"
+ inkscape:window-y="25">
+ <sodipodi:guide
+ orientation="1,0"
+ position="384.28571,590"
+ id="guide2601" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="678.57143,491.42857"
+ id="guide2603" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="78.571429,257.14286"
+ id="guide2605" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="93.571429,280.71429"
+ id="guide7565" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="148.57143,216.42857"
+ id="guide7567" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-250.44576,-308.53365)" />
+ <g
+ id="g2664"
+ transform="translate(-162.03535,-115.53321)">
+ <path
+ inkscape:connector-type="polyline"
+ id="path2869"
+ d="M 439.27375,270.21407 L 594.99083,193.03351"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <g
+ transform="translate(166.24286,-190.07976)"
+ id="g2606">
+ <rect
+ style="fill:#e3e2db;stroke:#000000;stroke-opacity:1"
+ id="rect7541"
+ width="211.42857"
+ height="124.28571"
+ x="6.6142678"
+ y="308.16089"
+ ry="17.142857" />
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="339.74512"
+ id="text7543"><tspan
+ sodipodi:role="line"
+ id="tspan7545"
+ x="76.614265"
+ y="339.74512">Boost</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="372.67505"
+ id="text7547"><tspan
+ sodipodi:role="line"
+ id="tspan7549"
+ x="76.614265"
+ y="372.67505">Qt Software</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="408.38055"
+ id="text7551"><tspan
+ sodipodi:role="line"
+ id="tspan7553"
+ x="76.614265"
+ y="408.38055">INdT/Nokia</tspan></text>
+ <rect
+ style="fill:#aaeeff;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7555"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="321.55374"
+ ry="6.4285707" />
+ <rect
+ style="fill:#b3ff80;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7561"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="355.4823"
+ ry="6.4285707" />
+ <rect
+ style="fill:#e9ddaf;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7563"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="390.4823"
+ ry="6.4285707" />
+ </g>
+ <path
+ inkscape:connector-type="polyline"
+ id="path2604"
+ d="M 782.79015,270.0418 L 627.07307,192.86124"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <g
+ transform="translate(234.84929,-73.143707)"
+ id="g5193">
+ <rect
+ ry="9.2689295"
+ style="fill:#b3ff80;fill-rule:evenodd;stroke:#2a7800;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2417"
+ width="274.18781"
+ height="73.282379"
+ x="78.571426"
+ y="342.86383"
+ rx="8.3239012" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="359.67014"
+ id="text2419"><tspan
+ sodipodi:role="line"
+ id="tspan2421"
+ x="88.822823"
+ y="359.67014">Qt 4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="375.33484"
+ id="text2423"><tspan
+ sodipodi:role="line"
+ id="tspan2425"
+ x="88.822823"
+ y="375.33484">4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="390.87479"
+ id="text2427"><tspan
+ sodipodi:role="line"
+ id="tspan2429"
+ x="88.822823"
+ y="390.87479">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="400.84058"
+ id="text2431"><tspan
+ sodipodi:role="line"
+ id="tspan2433"
+ x="88.822823"
+ y="400.84058">GNU General Public License v3 /</tspan><tspan
+ id="tspan2472"
+ sodipodi:role="line"
+ x="88.822823"
+ y="411.1687">GNU Lesser General Public Licence v2.1</tspan></text>
+ </g>
+ <g
+ transform="translate(101.41581,-378.37135)"
+ id="g5120">
+ <rect
+ rx="10.404889"
+ ry="13.104635"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2441"
+ width="274.54263"
+ height="73.281754"
+ x="384.28571"
+ y="496.43558" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="513.59869"
+ id="text2443"><tspan
+ sodipodi:role="line"
+ id="tspan2445"
+ x="389.17969"
+ y="513.59869">libapiextractor</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="529.26337"
+ id="text2447"><tspan
+ sodipodi:role="line"
+ id="tspan2449"
+ x="389.17969"
+ y="529.26337">0.2</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="544.80334"
+ id="text2451"><tspan
+ sodipodi:role="line"
+ x="389.17969"
+ y="544.80334"
+ id="tspan2453">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="560.12628"
+ id="text2455"><tspan
+ sodipodi:role="line"
+ id="tspan2457"
+ x="389.17969"
+ y="560.12628">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ transform="translate(242.40213,-378.858)"
+ id="g5182">
+ <rect
+ ry="11.287985"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2563"
+ width="274.54263"
+ height="73.281754"
+ x="384.28571"
+ y="648.57843"
+ rx="10.404877" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="665.74158"
+ id="text2565"><tspan
+ sodipodi:role="line"
+ id="tspan2567"
+ x="389.17969"
+ y="665.74158">boost::graph</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="681.40625"
+ id="text2569"><tspan
+ sodipodi:role="line"
+ id="tspan2571"
+ x="389.17969"
+ y="681.40625">1.38.0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="696.94623"
+ id="text2573"><tspan
+ sodipodi:role="line"
+ x="389.17969"
+ y="696.94623"
+ id="tspan2575">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="712.26917"
+ id="text2577"><tspan
+ sodipodi:role="line"
+ id="tspan2579"
+ x="389.17969"
+ y="712.26917">Boost Software License 1.0</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644
index 000000000..471e2439b
--- /dev/null
+++ b/doc/overview.rst
@@ -0,0 +1,15 @@
+.. _gen-overview:
+
+**********************
+API Extractor Overview
+**********************
+
+The **API Extractor** library is used by the binding generator to parse headers
+of a given library and merge this data with information provided by
+typesystem (XML) files, resulting in a representation of how the API should be
+exported to the chosen target language. The generation of source code for the
+bindings is performed by specific generators using the API Extractor library.
+
+The API Extractor is based on QtScriptGenerator_ codebase.
+
+.. _QtScriptGenerator: http://labs.trolltech.com/page/Projects/QtScript/Generator
diff --git a/doc/typesystem.rst b/doc/typesystem.rst
new file mode 100644
index 000000000..19c46aeb1
--- /dev/null
+++ b/doc/typesystem.rst
@@ -0,0 +1,810 @@
+The API Extractor Type System
+*****************************
+
+The typesystem is used by a binding generator to map a C++ library API onto
+a higher level language.
+
+The typesystem specification is a handwritten XML document listing the types
+that will be available in the generated target language API; types that are not
+declared in the specification will be ignored along with everything depending on
+them. In addition, it is possible to manipulate and modify types and functions.
+It is even possible to use the typesystem specification to inject arbitrary
+code into the source files, such as an extra member function.
+
+The typesystem specification is passed as an argument to the generator.
+
+Below there is a complete reference guide to the various nodes of the typesystem.
+For usage examples, take a look at the typesystem files used to generate the Qt
+Python bindings. These files can be found in the data directory of the PySide
+package.
+
+.. _specifying-types:
+
+Specifying Types
+----------------
+
+typesystem
+^^^^^^^^^^
+
+ This is the root node containing all the type system information. It can
+ have a number of attributes, described below.
+
+ .. code-block:: xml
+
+ <typesystem package="..." default-superclass="...">
+ </typesystem>
+
+ The **package** attribute is a string describing the package to be used,
+ e.g. "QtCore".
+ The *optional* **default-superclass** attribute is the canonical C++ base class
+ name of all objects, e.g., "object".
+
+load-typesystem
+^^^^^^^^^^^^^^^
+
+ The load-typesystem node specifies which type systems to load when mapping
+ multiple libraries to another language or basing one library on another, and
+ it is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <load-typesystem name="..." generate="yes | no" />
+ </typesystem>
+
+ The **name** attribute is the filename of the typesystem to load, the
+ **generate** attribute specifies whether code should be generated or not. The
+ later must be specified when basing one library on another, making the generator
+ able to understand inheritance hierarchies, primitive mapping, parameter types
+ in functions, etc.
+
+ Most libraries will be based on both the QtCore and QtGui modules, in which
+ case code generation for these libraries will be disabled.
+
+
+rejection
+^^^^^^^^^
+
+ The rejection node rejects the given class, or the specified function or
+ field, and it is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <rejection class="..."
+ function-name="..."
+ field-name="..." />
+ </typesystem>
+
+ The **class** attribute is the C++ class name of the class to reject. Use the
+ *optional* **function-name** or **field-name** attributes to reject a particular
+ function or field. Note that the **field-name** and **function-name** cannot
+ be specified at the same time. To remove all occurrences of a given field or
+ function, set the class attribute to \*. You can use an empty class field
+ to denote a global function.
+
+
+primitive-type
+^^^^^^^^^^^^^^
+
+ The primitive-type node describes how a primitive type is mapped from C++ to
+ the target language, and is a child of the typesystem node. Note that most
+ primitives are already specified in the QtCore typesystem.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <primitive-type name="..."
+ target-name="..."
+ preferred-conversion="yes | no" />
+ </typesystem>
+
+ The **name** attribute is the name of the primitive in C++, the optimal
+ **target-name** attribute is the name of the primitive type in the target
+ language. If the later two attributes are not specified their default value
+ will be the same as the **name** attribute.
+
+ If the *optional* **preferred-conversion** attribute is set to *no*, it
+ indicates that this version of the primitive type is not the preferred C++
+ equivalent of the target language type. For example, in Python both "qint64"
+ and "long long" become "long" but we should prefer the "qint64" version. For
+ this reason we mark "long long" with preferred-conversion="no".
+
+namespace-type
+^^^^^^^^^^^^^^
+
+ The namespace-type node maps the given C++ namespace to the target language,
+ and it is a child of the typesystem node. Note that within namespaces, the
+ generator only supports enums (i.e., no functions or classes).
+
+ .. code-block:: xml
+
+ <typesystem>
+ <namespace-type name="..."
+ package="..." />
+ </typesystem>
+
+ The **name** attribute is the name of the namespace, e.g., "Qt". The **package**
+ attribute can be used to override the package of the type system.
+
+enum-type
+^^^^^^^^^
+
+ The enum-type node maps the given enum from C++ to the target language,
+ and it is a child of the typesystem node. Use the reject-enum-value to
+ reject values.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <enum-type name="..."
+ flags="yes | no"
+ lower-bound="..."
+ upper-bound="..."
+ force-integer="yes | no"
+ extensible="yes | no" />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ name of the enum
+ (e.g.,"Qt::FillRule"). If the *optional* **flags** attribute is set to *yes*
+ (the default is *no*), the generator will expect an existing QFlags<T> for the
+ given enum type. The **lower-bound** and **upper-bound** attributes are used
+ to specify runtime bounds checking for the enum value. The value must be a
+ compilable target language statement, such as "QGradient.Spread.PadSpread"
+ (taking again Python as an example). If the **force-integer** attribute is
+ set to *yes* (the default is *no*), the generated target language code will
+ use the target language integers instead of enums. And finally, the
+ **extensible** attribute specifies whether the given enum can be extended
+ with user values (the default is *no*).
+
+
+value-type
+^^^^^^^^^^
+
+ The value-type node indicates that the given C++ type is mapped onto the target
+ language as a value type. This means that it is an object passed by value on C++,
+ i.e. it is stored in the function call stack. It is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <value-type name="..."
+ copyable="yes | no"
+ hash-function="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name, such as
+ "QMatrix" or "QPainterPath::Element". The **copyable** attribute is used to
+ force or not specify if this type is copyable. The *optional* **hash-function**
+ attribute informs the function name of a hash function for the type.
+
+
+object-type
+^^^^^^^^^^^
+
+ The object-type node indicates that the given C++ type is mapped onto the target
+ language as an object type. This means that it is an object passed by pointer on
+ C++ and it is stored on the heap. It is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <object-type name="..."
+ copyable="yes | no"
+ hash-function="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name. If there is no
+ C++ base class, the default-superclass attribute can be used to specify a
+ superclass for the given type, in the generated target language API. The
+ **copyable** and **hash-function** attributes are the same as described for
+ :ref:`value-type`.
+
+
+interface-type
+^^^^^^^^^^^^^^
+
+ The interface-type node indicates that the given class is replaced by an
+ interface pattern when mapping from C++ to the target language. Using the
+ interface-type node implicitly makes the given type an object type.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <interface-type name="..."
+ package ="..."
+ default-superclass ="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name. The *optional*
+ **package** attribute can be used to override the package of the type system.
+ If there is no C++ base class, the *optional* **default-superclass** attribute
+ can be used to specify a superclass in the generated target language API, for
+ the given class.
+
+suppress-warning
+^^^^^^^^^^^^^^^^
+
+ The generator will generate several warnings which may be irrelevant to the
+ user. The suppress-warning node suppresses the specified warning, and it is
+ a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <suppress-warning text="..." />
+ </typesystem>
+
+ The **text* attribute is the warning text to suppress, and may contain the *
+ wildcard (use "" to escape regular expression matching if the warning contain
+ a regular "*").
+
+
+template
+^^^^^^^^
+
+ The template node registers a template that can be used to avoid duplicate
+ code when extending the generated code, and it is a child of the typesystem
+ node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <template name="my_template">
+ // the code
+ </template>
+ </typesystem>
+
+ Use the insert-template node to insert the template code (identified by the
+ template's **name** attribute) into the generated code base.
+
+
+
+.. _value-type-requirements:
+
+Value Type Requirements
+------------------------
+
+custom-constructor
+^^^^^^^^^^^^^^^^^^
+
+ In some target languages, such as Python, value types are required to have a
+ copy constructor. If a C++ class without a copy constructor is mapped onto
+ the target language as a value type, it is possible to provide a custom
+ constructor using the custom-constructor node which is a child of the
+ value-type node.
+
+ .. code-block:: xml
+
+ <value-type>
+ <custom-constructor
+ name="..."
+ param-name="...">
+ // code for custom constructor
+ </custom-constructor>
+ </value-type>
+
+ The custom constructor's signature becomes:
+
+ T \*name(T \*param-name);
+
+ If not specified the **name** of the constructor becomes
+ <lowercase type name>_create() and the **param-name** becomes copy.
+
+ **name** and **param-name** attributes are *optional*.
+
+custom-destructor
+^^^^^^^^^^^^^^^^^
+
+ When a custom constructor is provided using the custom-constructor node, it is
+ most likely required to clean up the allocated memory. For that reason, it is
+ also possible to provide a custom destructor using the custom-destructor node
+ which is a child of the value-type node.
+
+ .. code-block:: xml
+
+ <value-type>
+ <custom-destructor
+ name="..."
+ param-name="...">
+ // code for custom destructor
+ </custom-destructor>
+ </value-type>
+
+ The custom destructor must have the following signature:
+
+ T \*name(T \*param-name);
+
+ If not specified the **name** of the destructor becomes
+ <lowercase type name>_delete() and the **param-name** becomes copy.
+
+ **name** and **param-name** attributes are *optional*.
+
+insert-template
+^^^^^^^^^^^^^^^
+
+ Documented in the :ref:`using-code-templates`
+
+
+
+.. _manipulating-object-and-value-types:
+
+Manipulating Object and Value Types
+-----------------------------------
+
+inject-code
+^^^^^^^^^^^
+ The inject-code node inserts the given code into the generated code for the
+ given type or function, and it is a child of the object-type, value-type and
+ modify-function nodes.
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target | target-declaration"
+ position="beginning | end">
+ // the code
+ </inject-code>
+ </value-type>
+
+ The **class** attribute specifies which module of the generated code that
+ will be affected by the code injection. The **class** attribute accepts the
+ following values:
+
+ * native: The c++ code
+ * target: The binding code
+ * target-declaration: The code will be injected into the generated header
+ file containing the c++ wrapper class definition.
+
+ If the **position** attribute is set to *beginning* (the default), the code
+ is inserted at the beginning of the function. If it is set to *end*, the code
+ is inserted at the end of the function.
+
+modify-field
+^^^^^^^^^^^^
+
+ The modify-field node allows you to alter the access privileges for a given
+ C++ field when mapping it onto the target language, and it is a child of an
+ object-type or a value-type node.
+
+ .. code-block:: xml
+
+ <object-type>
+ <modify-field name="..."
+ write="true | false"
+ read="true | false" />
+ </object-type>
+
+ The **name** attribute is the name of the field, the *optional* **write**
+ and **read** attributes specify the field's access privileges in the target
+ language API (both are set to true by default).
+
+modify-function
+^^^^^^^^^^^^^^^
+
+ The modify-function node allows you to modify a given C++ function when mapping
+ it onto the target language, and it is a child of an object-type or a value-type
+ node. Use the modify-argument node to specify which argument the modification
+ affects.
+
+ .. code-block:: xml
+
+ <object-type>
+ <modify-function signature="..."
+ remove="all | c++"
+ access="public | private | protected"
+ rename="..." >
+ </object-type>
+
+ The **signature** attribute is a normalized C++ signature, excluding return
+ values but including potential const declarations.
+
+ The **remove**, **access** and **rename** attributes are *optional* attributes
+ for added convenience; they serve the same purpose as the tags remove, access
+ and rename.
+
+
+include
+^^^^^^^
+
+ Documented in the :ref:`manipulating-namespace-and-interface-types`
+
+
+extra-includes
+^^^^^^^^^^^^^^
+
+ Documented in the :ref:`manipulating-namespace-and-interface-types`
+
+
+insert-template
+^^^^^^^^^^^^^^^
+
+ Documented in the :ref:`using-code-templates`
+
+
+.. _manipulating-namespace-and-interface-types:
+
+Manipulating Namespace and Interface Types
+------------------------------------------
+
+extra-includes
+^^^^^^^^^^^^^^
+
+ The extra-includes node contains declarations of additional include files,
+ and it can be a child of the interface-type, namespace-type, value-type and
+ object-type nodes.
+
+ The generator automatically tries to read the global header for each type but
+ sometimes it is required to include extra files in the generated C++ code to
+ make sure that the code compiles. These files must be listed using include
+ nodes witin the extra-include node:
+
+ .. code-block:: xml
+
+ <value-type>
+ <extra-includes>
+ <include file-name="..." location="global | local"/>
+ </extra-includes>
+ </value-type>
+
+ The **file-name** attribute is the file to include, such as "QStringList".
+ The **location** attribute is where the file is located: *global* means that
+ the file is located in $INCLUDEPATH and will be included using #include <...>,
+ *local* means that the file is in a local directory and will be included
+ using #include "...".
+
+
+include
+^^^^^^^
+
+ The include node specifies the name and location of a file that must be
+ included, and it is a child of the interface-type, namespace-type, value-type,
+ object-type or extra-includes nodes
+
+ The generator automatically tries to read the global header for each type. Use
+ the include node to override this behavior, providing an alternative file. The
+ include node can also be used to specify extra include files.
+
+ .. code-block:: xml
+
+ <value-type>
+ <include file-name="..."
+ location="global | local"/>
+ </value-type>
+ The **file-name** attribute is the file to include, such as "QStringList".
+ The **location** attribute is where the file is located: *global* means that
+ the file is located in $INCLUDEPATH and will be included using #include <...>,
+ *local* means that the file is in a local directory and will be included
+ using #include "...".
+
+
+.. _manipulating-enum-types:
+
+Manipulating Enum Types
+-----------------------
+
+reject-enum-value
+^^^^^^^^^^^^^^^^^
+
+ The reject-enum-value node rejects the enum value specified by the **name**
+ attribute, and it is a child of the enum-type node.
+
+ .. code-block:: xml
+
+ <enum-type>
+ <reject-enum-value name="..."/>
+ </enum-type>
+
+ This node is used when a C++ enum implementation has several identical numeric
+ values, some of which are typically obsolete.
+
+ **WARNING:** If the enum has some duplicated value don't forget to remove one
+ of them.
+
+
+.. _modifying-functions:
+
+Modifying Functions
+-------------------
+
+modify-argument
+^^^^^^^^^^^^^^^
+
+ The modify-argument node specifies which of the given function's arguments the
+ modification affects, and is a child of the modify-function node. Use the
+ remove-argument, replace-default-expression, remove-default-expression,
+ replace-type, reference-count and define-ownership nodes to specify the details
+ of the modification.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <modify-argument index="return | this | 1 ..." >
+ // modifications
+ </modify-argument>
+ </modify-function>
+
+ Set the **index** attribute to "1" for the first argument, "2" for the second
+ one and so on. Alternatively, set it to "return" or "this" if you want to
+ modify the function's return value or the object the function is called upon,
+ respectively.
+
+
+remove
+^^^^^^
+
+ The remove node removes the given method from the generated target language
+ API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <remove class="all" />
+ </modify-function>
+
+
+access
+^^^^^^
+
+ The access node changes the access privileges of the given function in the
+ generated target language API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <access modifier="public | protected | private"/>
+ </modify-function>
+
+
+rename
+^^^^^^
+
+ The rename node changes the name of the given function in the generated target
+ language API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <rename to="..." />
+ </modify-function>
+
+ The **to** attribute is the new name of the function.
+
+
+inject-code
+^^^^^^^^^^^
+
+ Documented in the :ref:`manipulating-object-and-value-types`
+
+
+argument-map
+^^^^^^^^^^^^
+
+ The argument-map node maps a C++ argument name to the argument name used in
+ the generated target language API, and is a child of the inject-code node
+ when the later is a child of a modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <inject-code>
+ <argument-map index="numeric value"
+ meta-name="string value">
+ </inject-code>
+ </modify-function>
+
+ The **index** attribute is an index, starting at 1, indicating the argument
+ position to which this argument mapping applies. The **meta-name** attribute
+ is the name used within the code injection to adress the argument at the
+ given position.
+
+
+.. _modifying-arguments:
+
+Modifying Arguments
+-------------------
+
+remove-argument
+^^^^^^^^^^^^^^^
+
+ The remove-argument node removes the given argument from the function's
+ signature, and it is a child of the modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <remove-argument />
+ </modify-argument>
+
+ Typically, when removing an argument, some conversion rules must be specified,
+ e.g., when converting from the target language to C++. This can be done using
+ the :ref:`conversion-rule` node.
+
+
+remove-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The remove-default-expression node disables the use of the default expression
+ for the given argument, and it is a child of the modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument...>
+ <remove-default-expression />
+ </modify-argument>
+
+replace-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The replace-default-expression node replaces the specified argument with the
+ expression specified by the **with** attribute, and it is a child of the
+ modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <replace-default-expression with="..." />
+ </modify-argument>
+
+
+replace-type
+^^^^^^^^^^^^
+
+ The replace-type node replaces the type of the given argument to the one
+ specified by the **modified-type** attribute, and it is a child of the
+ modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <replace-type modified-type="..." />
+ </modify-argument>
+
+ If the new type is a class, the **modified-type** attribute must be set to
+ the fully qualified name (including name of the package as well as the class
+ name).
+
+ Typically when changing the type of an argument some conversion rules must be
+ specified. This can be done using the :ref:`conversion-rule` node.
+
+
+define-ownership
+^^^^^^^^^^^^^^^^
+
+ The define-ownership tag indicates that the function changes the ownership
+ rules of the argument object. The **class** attribute specifies the class of
+ function where to inject the ownership altering code. The **owner** attribute
+ specifies the new ownership of the object. It accepts the following values:
+
+ * target: the target language will assume full ownership of the object.
+ The native resources will be deleted when the target language
+ object is finalized.
+ * c++: The native code assumes full ownership of the object. The target
+ language object will not be garbage collected.
+ * default: The object will get default ownership, depending on how it
+ was created.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <define-ownership class="target | shell"
+ owner="target | c++ | default" />
+ </modify-argument>
+
+
+insert-template
+^^^^^^^^^^^^^^^
+
+ Documented in the :ref:`using-code-templates`
+
+
+replace-value
+^^^^^^^^^^^^^
+
+ The **replace-value** attribute lets you replace the return statement of a
+ function with a fixed string. This attribute can only be used for the
+ argument at **index** 0, which is always the function's return value.
+
+ .. code-block:: xml
+
+ <modify-argument index="0" replace-value="this"/>
+
+
+parent
+^^^^^^
+
+ The **parent** attribute lets you define argument parent which will
+ take ownership of argument and will destroy the C++ child object when the
+ parent is destroyed.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <parent index="this" action="add | remove" />
+ </modify-argument>
+
+ In the **index** argument you must specify the parent argument. The action
+ *add* creates a parent link between objects, while *remove* will undo the
+ parentage relationship.
+
+
+.. _using-code-templates:
+
+Using Code Templates
+--------------------
+
+insert-template
+^^^^^^^^^^^^^^^
+
+ The insert-template node includes the code template identified by the name
+ attribute, and it can be a child of the inject-code, conversion-rule, template,
+ custom-constructor and custom-destructor nodes.
+
+ .. code-block:: xml
+
+ <inject-code class="target" position="beginning">
+ <insert-template name="my_template" />
+ </inject-code>
+
+ Use the replace node to modify the template code.
+
+
+replace
+^^^^^^^
+
+ The replace node allows you to modify template code before inserting it into
+ the generated code, and it can be a child of the insert-template node.
+
+ .. code-block:: xml
+
+ <insert-template name="my_template">
+ <replace from="..." to="..." />
+ </insert-template>
+
+ This node will replace the attribute **from** with the value pointed by
+ **to**.
+
+
+Manipulating Documentation
+--------------------------
+
+inject-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+ The inject-documentation node inserts the documentation into the generated
+ documentation. This node is a child of the object-type, value-type and
+ modify-function nodes.
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-documentation mode="append | prepend | replace" format="native | target" >
+ // the documentation
+ </inject-code>
+ </value-type>
+
+ The **mode** attribute default value is *replace*.
+
+ The **format** attribute specifies when the documentation injection will
+ occur and it accepts the following values:
+
+ * native: Before XML<->Backend transformation occur, so the injected code *must* be a valid XML.
+ * target: Before XML<->Backend transformation occur, so the injected code *must* be a valid backend format.
+
+ At the moment the only supported backend is Sphinx.
+
+modify-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+ The modify-documentation node allows you to change the auto-generated
+ documentation. API Extractor transforms XML's from qdoc3 (the Qt documentation
+ tool) into .rst files to be processed later using Sphinx. So you can modify
+ the XML before the transformation occur.
+
+ .. code-block:: xml
+
+ <modify-documentation xpath="...">
+ <!-- new documentation -->
+ </modify-documentation>
+
+ The **xpath** attribute is the XPath to the node that you want to modify.
diff --git a/docparser.cpp b/docparser.cpp
new file mode 100644
index 000000000..ddff5ffe9
--- /dev/null
+++ b/docparser.cpp
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include "docparser.h"
+#include <QtCore/QDebug>
+#include <QtXmlPatterns/QXmlQuery>
+#include <QBuffer>
+
+#include <cstdlib>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+
+DocParser::DocParser()
+{
+ xmlSubstituteEntitiesDefault(1);
+}
+
+DocParser::~DocParser()
+{
+}
+
+QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query,
+ const DocModificationList& mods) const
+{
+ QString doc = execXQuery(xquery, query);
+ return applyDocModifications(mods, doc);
+}
+
+QString DocParser::execXQuery(QXmlQuery& xquery, const QString& query) const
+{
+ QString escapedQuery(query);
+ // XQuery can't have invalid XML characters
+ escapedQuery.replace("&", "&amp;").replace("<", "&lt;");
+ xquery.setQuery(escapedQuery);
+ if (!xquery.isValid()) {
+ qWarning() << "Bad XQuery: " << escapedQuery;
+ return QString();
+ }
+
+ QString result;
+ xquery.evaluateTo(&result);
+ return result;
+}
+
+namespace
+{
+
+struct XslResources
+{
+ xmlDocPtr xmlDoc;
+ xsltStylesheetPtr xslt;
+ xmlDocPtr xslResult;
+
+ XslResources() : xmlDoc(0), xslt(0), xslResult(0) {}
+
+ ~XslResources()
+ {
+ if (xslt)
+ xsltFreeStylesheet(xslt);
+
+ if (xslResult)
+ xmlFreeDoc(xslResult);
+
+ if (xmlDoc)
+ xmlFreeDoc(xmlDoc);
+
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+ }
+};
+
+} // namespace
+
+QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) const
+{
+ if (mods.isEmpty())
+ return xml;
+
+ QString xsl = QLatin1String("<xsl:transform version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ "<xsl:template match=\"/\">\n"
+ " <xsl:apply-templates />\n"
+ "</xsl:template>\n"
+ "<xsl:template match=\"*\">\n"
+ "<xsl:copy>\n"
+ " <xsl:copy-of select=\"@*\"/>\n"
+ " <xsl:apply-templates/>\n"
+ "</xsl:copy>\n"
+ "</xsl:template>\n"
+ );
+ foreach (DocModification mod, mods) {
+ if (mod.mode() == DocModification::XPathReplace) {
+ xsl += QLatin1String("<xsl:template match=\"")
+ + mod.xpath().replace("\"", "&quot;") + QLatin1String("\">")
+ + mod.code() + QLatin1String("</xsl:template>\n");
+ }
+ }
+ xsl += QLatin1String("</xsl:transform>");
+
+ XslResources res;
+ // Read XML data
+ QByteArray xmlData = xml.toUtf8();
+ res.xmlDoc = xmlParseMemory(xmlData.constData(), xmlData.size());
+ if (!res.xmlDoc)
+ return xml;
+
+ // Read XSL data as a XML file
+ QByteArray xslData = xsl.toUtf8();
+ // xsltFreeStylesheet will delete this pointer
+ xmlDocPtr xslDoc = xmlParseMemory(xslData.constData(), xslData.size());
+ if (!xslDoc)
+ return xml;
+
+ // Parse XSL data
+ res.xslt = xsltParseStylesheetDoc(xslDoc);
+ if (!res.xslt)
+ return xml;
+
+ // Apply XSL
+ res.xslResult = xsltApplyStylesheet(res.xslt, res.xmlDoc, 0);
+ xmlChar* buffer = 0;
+ int bufferSize;
+ QString result;
+ if (!xsltSaveResultToString(&buffer, &bufferSize, res.xslResult, res.xslt)) {
+ result = QByteArray(reinterpret_cast<char*>(buffer), bufferSize);
+ std::free(buffer);
+ } else {
+ result = xml;
+ }
+
+ Q_ASSERT(result != xml);
+ return result;
+}
+
diff --git a/docparser.h b/docparser.h
new file mode 100644
index 000000000..ecc3204e9
--- /dev/null
+++ b/docparser.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef DOCPARSER_H
+#define DOCPARSER_H
+
+#include <QString>
+#include <QDir>
+// #include <QtCore/QMap>
+
+#include "abstractmetalang.h"
+
+class QDomDocument;
+class QDomNode;
+class QXmlQuery;
+
+class DocParser
+{
+public:
+ DocParser();
+ virtual ~DocParser();
+ virtual void fillDocumentation(AbstractMetaClass* metaClass) = 0;
+
+ /**
+ * Process and retrieves documentation concerning the entire
+ * module or library.
+ * /return object containing module/library documentation information
+ */
+ virtual Documentation retrieveModuleDocumentation() = 0;
+
+ void setDocumentationDataDirectory(const QString& dir)
+ {
+ m_docDataDir = dir;
+ }
+
+ /**
+ * Informs the location of the XML data generated by the tool
+ * (e.g.: DoxyGen, qdoc) used to extract the library's documentation
+ * comment.
+ * /return the path for the directory containing the XML data created
+ * from the library's documentation beign parsed.
+ */
+ QString documentationDataDirectory() const
+ {
+ return m_docDataDir;
+ }
+
+ void setLibrarySourceDirectory(const QString& dir)
+ {
+ m_libSourceDir = dir;
+ }
+ /**
+ * Informs the location of the library being parsed. The library
+ * source code is parsed for the documentation comments.
+ * /return the path for the directory containing the source code of
+ * the library beign parsed.
+ */
+ QString librarySourceDirectory() const
+ {
+ return m_libSourceDir;
+ }
+
+ void setPackageName(const QString& packageName)
+ {
+ m_packageName = packageName;
+ }
+ /**
+ * Retrieves the name of the package (or module or library) being parsed.
+ * /return the name of the package (module/library) being parsed
+ */
+ QString packageName() const
+ {
+ return m_packageName;
+ }
+
+protected:
+ QString getDocumentation(QXmlQuery& xquery, const QString& query,
+ const DocModificationList& mods) const;
+
+private:
+ QString m_packageName;
+ QString m_docDataDir;
+ QString m_libSourceDir;
+
+ QString execXQuery(QXmlQuery& xquery, const QString& query) const;
+ QString applyDocModifications(const DocModificationList& mods, const QString& xml) const;
+};
+
+#endif // DOCPARSER_H
+
diff --git a/doxygenparser.cpp b/doxygenparser.cpp
new file mode 100644
index 000000000..ccf14a916
--- /dev/null
+++ b/doxygenparser.cpp
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "doxygenparser.h"
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+
+#include <QtXmlPatterns/QXmlQuery>
+
+namespace
+{
+
+QString getSectionKindAttr(const AbstractMetaFunction* func)
+{
+ if (func->isSignal()) {
+ return QLatin1String("signal");
+ } else {
+ QString kind = func->isPublic() ? QLatin1String("public") : QLatin1String("protected");
+ if (func->isStatic())
+ kind += QLatin1String("-static");
+ else if (func->isSlot())
+ kind += QLatin1String("-slot");
+ return kind;
+ }
+}
+
+}
+
+void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ QString doxyFileSuffix;
+ if (metaClass->enclosingClass()) {
+ doxyFileSuffix += metaClass->enclosingClass()->name();
+ doxyFileSuffix += "_1_1"; // FIXME: Check why _1_1!!
+ }
+ doxyFileSuffix += metaClass->name();
+ doxyFileSuffix += ".xml";
+
+ const char* prefixes[] = { "class", "struct", "namespace" };
+ const int numPrefixes = sizeof(prefixes);
+
+ QString doxyFilePath;
+ for (int i = 0; i < numPrefixes; ++i) {
+ doxyFilePath = documentationDataDirectory() + "./" + prefixes[i] + doxyFileSuffix;
+ if (QFile::exists(doxyFilePath))
+ break;
+ doxyFilePath.clear();
+ }
+
+ if (doxyFilePath.isEmpty()) {
+ ReportHandler::warning("Can't find doxygen file for class "
+ + metaClass->name() + ", tried: "
+ + documentationDataDirectory() + "/{struct|class|namespace}"
+ + doxyFileSuffix);
+ return;
+ }
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(doxyFilePath));
+
+ // Get class documentation
+ QString classDoc = getDocumentation(xquery, "/doxygen/compounddef/detaileddescription",
+ metaClass->typeEntry()->docModifications());
+ if (classDoc.isEmpty()) {
+ ReportHandler::warning("Can't find documentation for class \""
+ + metaClass->name() + "\".");
+ }
+ metaClass->setDocumentation(classDoc);
+
+ //Functions Documentation
+ AbstractMetaFunctionList funcs = metaClass->functionsInTargetLang();
+ foreach (AbstractMetaFunction *func, funcs) {
+ if (!func || func->isPrivate())
+ continue;
+
+ QString query = "/doxygen/compounddef/sectiondef";
+ // properties
+ if (func->isPropertyReader() || func->isPropertyWriter()
+ || func->isPropertyResetter()) {
+ query += "[@kind=\"property\"]/memberdef/name[text()=\""
+ + func->propertySpec()->name() + "\"]";
+ } else { // normal methods
+ QString kind = getSectionKindAttr(func);
+ query += "[@kind=\"" + kind + "-func\"]/memberdef/name[text()=\""
+ + func->originalName() + "\"]";
+
+ if (func->arguments().isEmpty()) {
+ QString args = func->isConstant() ? "() const " : "()";
+ query += "/../argsstring[text()=\"" + args + "\"]";
+ } else {
+ int i = 1;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ QString type;
+ if (!arg->type()->isPrimitive()) {
+ query += "/../param[" + QString::number(i) + "]/type/ref[text()=\""
+ + arg->type()->name() + "\"]/../..";
+ } else {
+ query += "/../param[" + QString::number(i) + "]/type[text()=\""
+ + arg->type()->name() + "\"]/..";
+ }
+ ++i;
+ }
+ }
+ }
+ query += "/../detaileddescription";
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ func->setDocumentation(doc);
+ }
+
+ //Fields
+ AbstractMetaFieldList fields = metaClass->fields();
+ foreach (AbstractMetaField *field, fields) {
+ if (field->isPrivate())
+ return;
+
+ QString query = "/doxygen/compounddef/sectiondef/memberdef/name[text()=\""
+ + field->name() + "\"]/../detaileddescription";
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ field->setDocumentation(doc);
+ }
+
+ //Enums
+ AbstractMetaEnumList enums = metaClass->enums();
+ foreach (AbstractMetaEnum *meta_enum, enums) {
+ QString query = "/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\"" + meta_enum->name() + "\"]/../detaileddescription";
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ meta_enum->setDocumentation(doc);
+ }
+}
diff --git a/doxygenparser.h b/doxygenparser.h
new file mode 100644
index 000000000..16d53bdcd
--- /dev/null
+++ b/doxygenparser.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef DOXYGENPARSER_H
+#define DOXYGENPARSER_H
+
+#include "docparser.h"
+
+class DoxygenParser : public DocParser
+{
+public:
+ DoxygenParser() {}
+ virtual void fillDocumentation(AbstractMetaClass *metaClass);
+ virtual Documentation retrieveModuleDocumentation() { return Documentation(); }
+};
+
+#endif // DOXYGENPARSER_H
diff --git a/fileout.cpp b/fileout.cpp
new file mode 100644
index 000000000..ac5206bd6
--- /dev/null
+++ b/fileout.cpp
@@ -0,0 +1,218 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "fileout.h"
+#include "reporthandler.h"
+
+#include <QtCore/QTextCodec>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+
+#include <cstdio>
+
+bool FileOut::dummy = false;
+bool FileOut::diff = false;
+
+#ifdef Q_OS_LINUX
+const char* colorDelete = "\033[31m";
+const char* colorAdd = "\033[32m";
+const char* colorInfo = "\033[36m";
+const char* colorReset = "\033[0m";
+#else
+const char* colorDelete = "";
+const char* colorAdd = "";
+const char* colorInfo = "";
+const char* colorReset = "";
+#endif
+
+FileOut::FileOut(QString n):
+ name(n),
+ stream(&tmp),
+ isDone(false)
+{}
+
+static int* lcsLength(QList<QByteArray> a, QList<QByteArray> b)
+{
+ const int height = a.size() + 1;
+ const int width = b.size() + 1;
+
+ int *res = new int[width * height];
+
+ for (int row = 0; row < height; row++)
+ res[width * row] = 0;
+
+ for (int col = 0; col < width; col++)
+ res[col] = 0;
+
+ for (int row = 1; row < height; row++) {
+ for (int col = 1; col < width; col++) {
+ if (a[row-1] == b[col-1])
+ res[width * row + col] = res[width * (row-1) + col-1] + 1;
+ else
+ res[width * row + col] = qMax(res[width * row + col-1],
+ res[width * (row-1) + col]);
+ }
+ }
+ return res;
+}
+
+enum Type {
+ Add,
+ Delete,
+ Unchanged
+};
+
+struct Unit
+{
+ Unit(Type type, int pos) :
+ type(type),
+ start(pos),
+ end(pos) {}
+
+ Type type;
+ int start;
+ int end;
+
+ void print(QList<QByteArray> a, QList<QByteArray> b)
+ {
+ if (type == Unchanged) {
+ if ((end - start) > 9) {
+ for (int i = start; i <= start + 2; i++)
+ std::printf(" %s\n", a[i].data());
+ std::printf("%s=\n= %d more lines\n=%s\n", colorInfo, end - start - 6, colorReset);
+ for (int i = end - 2; i <= end; i++)
+ std::printf(" %s\n", a[i].data());
+ } else {
+ for (int i = start; i <= end; i++)
+ std::printf(" %s\n", a[i].data());
+ }
+ } else if (type == Add) {
+ std::printf("%s", colorAdd);
+ for (int i = start; i <= end; i++)
+ std::printf("+ %s\n", b[i].data());
+ std::printf("%s", colorReset);
+ } else if (type == Delete) {
+ std::printf("%s", colorDelete);
+ for (int i = start; i <= end; i++)
+ std::printf("- %s\n", a[i].data());
+ std::printf("%s", colorReset);
+ }
+ }
+};
+
+static QList<Unit*> *unitAppend(QList<Unit*> *res, Type type, int pos)
+{
+ if (!res) {
+ res = new QList<Unit*>;
+ res->append(new Unit(type, pos));
+ return res;
+ }
+
+ Unit *last = res->last();
+ if (last->type == type)
+ last->end = pos;
+ else
+ res->append(new Unit(type, pos));
+
+ return res;
+}
+
+static QList<Unit*> *diffHelper(int *lcs, QList<QByteArray> a, QList<QByteArray> b, int row, int col)
+{
+ if (row > 0 && col > 0 && (a[row-1] == b[col-1])) {
+ return unitAppend(diffHelper(lcs, a, b, row - 1, col - 1), Unchanged, row - 1);
+ } else {
+ int width = b.size() + 1;
+ if ((col > 0)
+ && (row == 0 || lcs[width * row + col-1] >= lcs[width *(row-1) + col])) {
+ return unitAppend(diffHelper(lcs, a, b, row, col - 1), Add, col - 1);
+ } else if ((row > 0)
+ && (col == 0 || lcs[width * row + col-1] < lcs[width *(row-1) + col])) {
+ return unitAppend(diffHelper(lcs, a, b, row - 1, col), Delete, row - 1);
+ }
+ }
+ delete lcs;
+ return 0;
+}
+
+static void diff(QList<QByteArray> a, QList<QByteArray> b)
+{
+ QList<Unit*> *res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
+ for (int i = 0; i < res->size(); i++) {
+ Unit *unit = res->at(i);
+ unit->print(a, b);
+ delete(unit);
+ }
+ delete(res);
+}
+
+
+bool FileOut::done()
+{
+ Q_ASSERT(!isDone);
+ isDone = true;
+ bool fileEqual = false;
+ QFile fileRead(name);
+ QFileInfo info(fileRead);
+ stream.flush();
+ QByteArray original;
+ if (info.exists() && (diff || (info.size() == tmp.size()))) {
+ if (!fileRead.open(QIODevice::ReadOnly)) {
+ ReportHandler::warning(QString("failed to open file '%1' for reading")
+ .arg(fileRead.fileName()));
+ return false;
+ }
+
+ original = fileRead.readAll();
+ fileRead.close();
+ fileEqual = (original == tmp);
+ }
+
+ if (!fileEqual) {
+ if (!FileOut::dummy) {
+ QDir dir(info.absolutePath());
+ if (!dir.mkpath(dir.absolutePath())) {
+ ReportHandler::warning(QString("unable to create directory '%1'")
+ .arg(dir.absolutePath()));
+ return false;
+ }
+
+ QFile fileWrite(name);
+ if (!fileWrite.open(QIODevice::WriteOnly)) {
+ ReportHandler::warning(QString("failed to open file '%1' for writing")
+ .arg(fileWrite.fileName()));
+ return false;
+ }
+ QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
+ stream.setDevice(&fileWrite);
+ stream << tmp;
+ }
+ if (diff) {
+ std::printf("%sFile: %s%s\n", colorInfo, qPrintable(name), colorReset);
+ ::diff(original.split('\n'), tmp.split('\n'));
+ std::printf("\n");
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/fileout.h b/fileout.h
new file mode 100644
index 000000000..7570bbc45
--- /dev/null
+++ b/fileout.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef FILEOUT_H
+#define FILEOUT_H
+
+#include <QtCore/QObject>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+
+class FileOut : public QObject
+{
+ Q_OBJECT
+
+private:
+ QByteArray tmp;
+ QString name;
+
+public:
+ FileOut(QString name);
+ ~FileOut()
+ {
+ if (!isDone)
+ done();
+ }
+
+ bool done();
+
+ QTextStream stream;
+
+ static bool dummy;
+ static bool diff;
+
+private:
+ bool isDone;
+};
+
+#endif // FILEOUT_H
diff --git a/generator.cpp b/generator.cpp
new file mode 100644
index 000000000..46de409c9
--- /dev/null
+++ b/generator.cpp
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "generator.h"
+#include "reporthandler.h"
+#include "fileout.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QDebug>
+#include "abstractmetabuilder.h"
+
+Generator::Generator() : m_numGenerated(0), m_numGeneratedWritten(0)
+{}
+
+Generator::~Generator()
+{
+}
+
+void Generator::setBuilder(AbstractMetaBuilder* builder)
+{
+ m_globalEnums = builder->globalEnums();
+ m_globalFunctions = builder->globalFunctions();
+ m_classes = builder->classes();
+ m_primitiveTypes = TypeDatabase::instance()->primitiveTypes();
+ m_containerTypes = TypeDatabase::instance()->containerTypes();
+ foreach (const AbstractMetaClass* cppClass, m_classes) {
+ if (m_packageName.isEmpty()
+ && cppClass->typeEntry()->generateCode()
+ && !cppClass->package().isEmpty()) {
+ m_packageName = cppClass->package();
+ break;
+ }
+ }
+ // does anyone use this?
+ m_qmetatypeDeclaredTypenames = builder->qtMetaTypeDeclaredTypeNames();
+}
+
+void Generator::generate()
+{
+ if (m_classes.isEmpty()) {
+ ReportHandler::warning(QString("%1: no classes, skipping")
+ .arg(metaObject()->className()));
+ return;
+ }
+
+ foreach (AbstractMetaClass *cls, m_classes) {
+ if (!shouldGenerate(cls))
+ continue;
+
+ QString fileName = fileNameForClass(cls);
+ if (fileName.isNull())
+ continue;
+ ReportHandler::debugSparse(QString("generating: %1").arg(fileName));
+
+ FileOut fileOut(outputDirectory() + '/' + subDirectoryForClass(cls) + '/' + fileName);
+ generateClass(fileOut.stream, cls);
+
+ if (fileOut.done())
+ ++m_numGeneratedWritten;
+ ++m_numGenerated;
+ }
+ finishGeneration();
+}
+
+bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
+{
+ return metaClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang;
+}
+
+void Generator::verifyDirectoryFor(const QFile &file)
+{
+ QDir dir = QFileInfo(file).dir();
+ if (!dir.exists()) {
+ if (!dir.mkpath(dir.absolutePath()))
+ ReportHandler::warning(QString("unable to create directory '%1'")
+ .arg(dir.absolutePath()));
+ }
+}
+
+bool Generator::hasDefaultConstructor(const AbstractMetaType *type)
+{
+ QString full_name = type->typeEntry()->qualifiedTargetLangName();
+ QString class_name = type->typeEntry()->targetLangName();
+
+ foreach (const AbstractMetaClass *cls, m_classes) {
+ if (cls->typeEntry()->qualifiedTargetLangName() == full_name) {
+ AbstractMetaFunctionList functions = cls->functions();
+ foreach (const AbstractMetaFunction *function, functions) {
+ if (function->arguments().isEmpty() && function->name() == class_name)
+ return true;
+ }
+ return false;
+ }
+ }
+ return false;
+}
+
+void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func)
+{
+ const AbstractMetaClass *cpp_class = func->ownerClass();
+ code.replace("%TYPE", cpp_class->name());
+
+ foreach (AbstractMetaArgument *arg, func->arguments())
+ code.replace("%" + QString::number(arg->argumentIndex() + 1), arg->argumentName());
+
+ //template values
+ code.replace("%RETURN_TYPE", translateType(func->type(), cpp_class));
+ code.replace("%FUNCTION_NAME", func->originalName());
+
+ if (code.contains("%ARGUMENT_NAMES")) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
+ code.replace("%ARGUMENT_NAMES", str);
+ }
+
+ if (code.contains("%ARGUMENTS")) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeFunctionArguments(aux_stream, func, Generator::SkipDefaultValues | Generator::SkipRemovedArguments);
+ code.replace("%ARGUMENTS", str);
+ }
+}
+
diff --git a/generator.h b/generator.h
new file mode 100644
index 000000000..0be9e6c73
--- /dev/null
+++ b/generator.h
@@ -0,0 +1,358 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <QtCore/QObject>
+#include <QtCore/QDir>
+#include "abstractmetalang.h"
+
+class AbstractMetaBuilder;
+class QFile;
+
+/**
+ * Base class for all generators. The default implementations does nothing,
+ * you must subclass this to create your own generators.
+ */
+class Generator : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString outputDirectory READ outputDirectory WRITE setOutputDirectory);
+
+public:
+ enum GeneratorType {
+ CodeType,
+ DocumentationType
+ };
+ /// Optiosn used around the generator code
+ enum Option {
+ NoOption = 0x00000000,
+ BoxedPrimitive = 0x00000001,
+ ExcludeConst = 0x00000002,
+ ExcludeReference = 0x00000004,
+ UseNativeIds = 0x00000008,
+
+ EnumAsInts = 0x00000010,
+ SkipName = 0x00000020,
+ NoCasts = 0x00000040,
+ SkipReturnType = 0x00000080,
+ OriginalName = 0x00000100,
+ ShowStatic = 0x00000200,
+ UnderscoreSpaces = 0x00000400,
+ ForceEnumCast = 0x00000800,
+ ArrayAsPointer = 0x00001000,
+ VirtualCall = 0x00002000,
+ SkipTemplateParameters = 0x00004000,
+ SkipAttributes = 0x00008000,
+ OriginalTypeDescription = 0x00010000,
+ SkipRemovedArguments = 0x00020000,
+ IncludeDefaultExpression = 0x00040000,
+ NoReturnStatement = 0x00080000,
+ NoBlockedSlot = 0x00100000,
+
+ SuperCall = 0x00200000,
+
+ GlobalRefJObject = 0x00100000,
+
+ SkipDefaultValues = 0x00400000,
+
+ WriteSelf = 0x00800000,
+ ExcludeMethodConst = 0x01000000,
+
+ ForceValueType = ExcludeReference | ExcludeConst
+ };
+
+ Generator();
+ virtual ~Generator();
+
+ void setBuilder(AbstractMetaBuilder* builder);
+ /**
+ * Returns the generator name.
+ */
+ virtual const char* name() const
+ {
+ return "<Unnamed>";
+ }
+
+ virtual QMap<QString, QString> options() const
+ {
+ return QMap<QString, QString>();
+ }
+
+ /**
+ * The Generator identifies itself through this method,
+ * as a CodeType generator or a DocumentationType generator.
+ * If not reimplemented this method the Generator will be
+ * of CodeType.
+ * /return a GeneratorType value identifying the kind of
+ * generator this is
+ */
+ virtual GeneratorType type() const
+ {
+ return CodeType;
+ }
+
+ /// Returns the classes used to generate the binding code.
+ AbstractMetaClassList classes() const
+ {
+ return m_classes;
+ }
+
+ AbstractMetaFunctionList globalFunctions() const
+ {
+ return m_globalFunctions;
+ }
+
+ AbstractMetaEnumList globalEnums() const
+ {
+ return m_globalEnums;
+ }
+
+ QList<const PrimitiveTypeEntry*> primitiveTypes() const
+ {
+ return m_primitiveTypes;
+ }
+
+ QList<const ContainerTypeEntry*> containerTypes() const
+ {
+ return m_containerTypes;
+ }
+
+ /// Returns the output directory
+ QString outputDirectory() const
+ {
+ return m_outDir;
+ }
+
+ /// Set the output directory
+ void setOutputDirectory(const QString &outDir)
+ {
+ m_outDir = outDir;
+ }
+
+ virtual bool prepareGeneration(const QMap<QString, QString>& args) = 0;
+ /**
+ * Start the code generation, be sure to call setClasses before callign this method.
+ * For each class it creates a QTextStream, call the write method with the current
+ * class and the associated text stream, then write the text stream contents if needed.
+ * \see #write
+ */
+ void generate();
+
+ /// Returns the number of generated items
+ int numGenerated()
+ {
+ return m_numGenerated;
+ }
+
+ /// Returns the number of generated items written
+ int numGeneratedAndWritten()
+ {
+ return m_numGeneratedWritten;
+ }
+
+ /// Returns true if the generator should generate any code for the AbstractMetaClass
+ virtual bool shouldGenerate(const AbstractMetaClass *) const;
+
+ /// Returns the subdirectory used to write the binding code of an AbstractMetaClass.
+ virtual QString subDirectoryForClass(const AbstractMetaClass* clazz) const = 0;
+
+ /**
+ * Translate metatypes to binding source format.
+ * \param metatype a pointer to metatype
+ * \param context the current meta class
+ * \param option some extra options
+ * \return the metatype translated to binding source format
+ */
+ virtual QString translateType(const AbstractMetaType *metatype,
+ const AbstractMetaClass *context,
+ int option = NoOption) const = 0;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param metafunction the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ virtual void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ uint options = 0) const = 0;
+
+ virtual void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ uint options = 0) const = 0;
+
+ void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
+
+ bool hasDefaultConstructor(const AbstractMetaType *type);
+
+ // QtScript
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const
+ {
+ return m_qmetatypeDeclaredTypenames;
+ }
+
+ /**
+ * Returns the license comment to be prepended to each source file generated.
+ */
+ QString licenseComment()
+ {
+ return m_licenseComment;
+ }
+
+ /**
+ * Sets the license comment to be prepended to each source file generated.
+ */
+ void setLicenseComment(const QString &licenseComment)
+ {
+ m_licenseComment = licenseComment;
+ }
+
+ /**
+ * Returns the package name.
+ */
+ QString packageName()
+ {
+ return m_packageName;
+ }
+
+ /**
+ * Sets the package name.
+ */
+ void setPackageName(const QString &packageName)
+ {
+ m_packageName = packageName;
+ }
+
+ /**
+ * Retrieves the name of the currently processed module. While package name
+ * is a complete package idetification, e.g. 'PySide.QtCore', a module name
+ * represents the last part of the package, e.g. 'QtCore'.
+ * If the target language separates the modules with characters other than
+ * dots ('.') the generator subclass must overload this method.
+ * /return a string representing the last part of a package name
+ */
+ virtual QString moduleName()
+ {
+ return QString(m_packageName).remove(0, m_packageName.lastIndexOf('.') + 1);
+ }
+
+protected:
+ QString m_packageName;
+
+ /**
+ * Returns the file name used to write the binding code of an AbstractMetaClass.
+ * /param metaClass the AbstractMetaClass for which the file name must be
+ * returned
+ * /return the file name used to write the binding code for the class
+ */
+ virtual QString fileNameForClass(const AbstractMetaClass* metaClass) const = 0;
+
+ /**
+ * Returns the subdirectory path for a given package
+ * (aka module, aka library) name.
+ * If the target language separates the package modules with characters other
+ * than dots ('.') the generator subclass must overload this method.
+ * /param packageName complete package name for which to return the subdirectory path
+ * or nothing the use the name of the currently processed package
+ * /return a string representing the subdirectory path for the given package
+ */
+ virtual QString subDirectoryForPackage(QString packageName = QString()) const
+ {
+ if (packageName.isEmpty())
+ packageName = m_packageName;
+ return QString(packageName).replace(".", QDir::separator());
+ }
+
+ /**
+ * Write the bindding code for an AbstractMetaClass.
+ * This is called by the default implementation of generate method.
+ * \param s text stream to write the generated output
+ * \param metaClass the class that should be generated
+ */
+ virtual void generateClass(QTextStream& s, const AbstractMetaClass* metaClass) = 0;
+ virtual void finishGeneration() = 0;
+
+ void verifyDirectoryFor(const QFile &file);
+
+ int m_numGenerated;
+ int m_numGeneratedWritten;
+
+private:
+ AbstractMetaClassList m_classes;
+ AbstractMetaFunctionList m_globalFunctions;
+ AbstractMetaEnumList m_globalEnums;
+ QString m_outDir;
+
+ QList<const PrimitiveTypeEntry*> m_primitiveTypes;
+ QList<const ContainerTypeEntry*> m_containerTypes;
+
+ // QtScript
+ QSet<QString> m_qmetatypeDeclaredTypenames;
+
+ // License comment
+ QString m_licenseComment;
+};
+
+/**
+* Utility class to store the identation level, use it in a QTextStream.
+*/
+class Indentor
+{
+public:
+ Indentor():
+ indent(0) {}
+ int indent;
+};
+
+/**
+* Class that use the RAII idiom to set and unset the identation level.
+*/
+class Indentation
+{
+public:
+ Indentation(Indentor &indentor) : indentor(indentor)
+ {
+ indentor.indent++;
+ }
+ ~Indentation()
+ {
+ indentor.indent--;
+ }
+
+private:
+ Indentor &indentor;
+};
+
+inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor)
+{
+ for (int i = 0; i < indentor.indent; ++i)
+ s << " ";
+ return s;
+}
+
+#endif // GENERATOR_H
+
diff --git a/generator.qrc b/generator.qrc
new file mode 100644
index 000000000..2d82b37cb
--- /dev/null
+++ b/generator.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/trolltech/generator/">
+<file alias="pp-qt-configuration">parser/rpp/pp-qt-configuration</file>
+</qresource>
+</RCC>
diff --git a/merge.xsl b/merge.xsl
new file mode 100644
index 000000000..d0b7eafa5
--- /dev/null
+++ b/merge.xsl
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:param name="lang" />
+ <xsl:param name="source" />
+
+ <xsl:template match="processing-instruction()" />
+
+ <xsl:template match="/typesystem">
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:for-each select="document($source)/typesystem/@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[not(self::object-type | self::value-type | self::interface-type | self::namespace-type)]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:apply-templates select="node()" />
+
+ </xsl:copy>
+ </xsl:template>
+
+
+
+ <xsl:template match="/typesystem/*[self::object-type | self::value-type | self::interface-type | self::namespace-type]">
+ <xsl:variable name="name" select="name()" />
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:apply-templates select="node()" />
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[name() = $name][@name = current()/@name]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Plain identity transform. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/parser/ast.cpp b/parser/ast.cpp
new file mode 100644
index 000000000..ff5b7dfc8
--- /dev/null
+++ b/parser/ast.cpp
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "ast.h"
+#include "lexer.h"
+
+QString AST::toString(TokenStream *stream) const
+{
+ const Token &tk = stream->token((int) start_token);
+ const Token &end_tk = stream->token((int) end_token);
+ return QString::fromLatin1(tk.text + tk.position, end_tk.position - tk.position);
+}
diff --git a/parser/ast.h b/parser/ast.h
new file mode 100644
index 000000000..aa98ee4db
--- /dev/null
+++ b/parser/ast.h
@@ -0,0 +1,879 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef AST_H
+#define AST_H
+
+#include "smallobject.h"
+#include "list.h"
+
+class QString;
+
+#define DECLARE_AST_NODE(k) \
+ enum { __node_kind = Kind_##k };
+
+class TokenStream;
+
+struct AccessSpecifierAST;
+struct AsmDefinitionAST;
+struct BaseClauseAST;
+struct BaseSpecifierAST;
+struct BinaryExpressionAST;
+struct CastExpressionAST;
+struct ClassMemberAccessAST;
+struct ClassSpecifierAST;
+struct CompoundStatementAST;
+struct ConditionAST;
+struct ConditionalExpressionAST;
+struct CppCastExpressionAST;
+struct CtorInitializerAST;
+struct DeclarationAST;
+struct DeclarationStatementAST;
+struct DeclaratorAST;
+struct DeleteExpressionAST;
+struct DoStatementAST;
+struct ElaboratedTypeSpecifierAST;
+struct EnumSpecifierAST;
+struct EnumeratorAST;
+struct ExceptionSpecificationAST;
+struct ExpressionAST;
+struct ExpressionOrDeclarationStatementAST;
+struct ExpressionStatementAST;
+struct ForStatementAST;
+struct FunctionCallAST;
+struct FunctionDefinitionAST;
+struct IfStatementAST;
+struct IncrDecrExpressionAST;
+struct InitDeclaratorAST;
+struct InitializerAST;
+struct InitializerClauseAST;
+struct LabeledStatementAST;
+struct LinkageBodyAST;
+struct LinkageSpecificationAST;
+struct MemInitializerAST;
+struct NameAST;
+struct NamespaceAST;
+struct NamespaceAliasDefinitionAST;
+struct NewDeclaratorAST;
+struct NewExpressionAST;
+struct NewInitializerAST;
+struct NewTypeIdAST;
+struct OperatorAST;
+struct OperatorFunctionIdAST;
+struct ParameterDeclarationAST;
+struct ParameterDeclarationClauseAST;
+struct PostfixExpressionAST;
+struct PrimaryExpressionAST;
+struct PtrOperatorAST;
+struct PtrToMemberAST;
+struct ReturnStatementAST;
+struct SimpleDeclarationAST;
+struct SimpleTypeSpecifierAST;
+struct SizeofExpressionAST;
+struct StatementAST;
+struct StringLiteralAST;
+struct SubscriptExpressionAST;
+struct SwitchStatementAST;
+struct TemplateArgumentAST;
+struct TemplateDeclarationAST;
+struct TemplateParameterAST;
+struct ThrowExpressionAST;
+struct TranslationUnitAST;
+struct TryBlockStatementAST;
+struct TypeIdAST;
+struct TypeIdentificationAST;
+struct TypeParameterAST;
+struct TypeSpecifierAST;
+struct TypedefAST;
+struct UnaryExpressionAST;
+struct UnqualifiedNameAST;
+struct UsingAST;
+struct UsingDirectiveAST;
+struct WhileStatementAST;
+struct WinDeclSpecAST;
+struct QPropertyAST;
+struct QEnumsAST;
+
+struct AST
+{
+ enum NODE_KIND {
+ Kind_UNKNOWN = 0,
+
+ Kind_AccessSpecifier,
+ Kind_AsmDefinition,
+ Kind_BaseClause,
+ Kind_BaseSpecifier,
+ Kind_BinaryExpression,
+ Kind_CastExpression,
+ Kind_ClassMemberAccess,
+ Kind_ClassSpecifier,
+ Kind_CompoundStatement,
+ Kind_Condition,
+ Kind_ConditionalExpression,
+ Kind_CppCastExpression,
+ Kind_CtorInitializer,
+ Kind_DeclarationStatement,
+ Kind_Declarator,
+ Kind_DeleteExpression,
+ Kind_DoStatement,
+ Kind_ElaboratedTypeSpecifier,
+ Kind_EnumSpecifier,
+ Kind_Enumerator,
+ Kind_ExceptionSpecification,
+ Kind_ExpressionOrDeclarationStatement,
+ Kind_ExpressionStatement,
+ Kind_ForStatement,
+ Kind_FunctionCall,
+ Kind_FunctionDefinition,
+ Kind_IfStatement,
+ Kind_IncrDecrExpression,
+ Kind_InitDeclarator,
+ Kind_Initializer,
+ Kind_InitializerClause,
+ Kind_LabeledStatement,
+ Kind_LinkageBody,
+ Kind_LinkageSpecification,
+ Kind_MemInitializer,
+ Kind_Name,
+ Kind_Namespace,
+ Kind_NamespaceAliasDefinition,
+ Kind_NewDeclarator,
+ Kind_NewExpression,
+ Kind_NewInitializer,
+ Kind_NewTypeId,
+ Kind_Operator,
+ Kind_OperatorFunctionId,
+ Kind_ParameterDeclaration,
+ Kind_ParameterDeclarationClause,
+ Kind_PostfixExpression,
+ Kind_PrimaryExpression,
+ Kind_PtrOperator,
+ Kind_PtrToMember,
+ Kind_ReturnStatement,
+ Kind_SimpleDeclaration,
+ Kind_SimpleTypeSpecifier,
+ Kind_SizeofExpression,
+ Kind_StringLiteral,
+ Kind_SubscriptExpression,
+ Kind_SwitchStatement,
+ Kind_TemplateArgument,
+ Kind_TemplateDeclaration,
+ Kind_TemplateParameter,
+ Kind_ThrowExpression,
+ Kind_TranslationUnit,
+ Kind_TryBlockStatement,
+ Kind_TypeId,
+ Kind_TypeIdentification,
+ Kind_TypeParameter,
+ Kind_Typedef,
+ Kind_UnaryExpression,
+ Kind_UnqualifiedName,
+ Kind_Using,
+ Kind_UsingDirective,
+ Kind_WhileStatement,
+ Kind_WinDeclSpec,
+ Kind_QPropertyAST,
+ Kind_ForwardDeclarationSpecifier,
+ Kind_QEnumsAST,
+
+ NODE_KIND_COUNT
+ };
+
+ QString toString(TokenStream *stream) const;
+
+ int kind;
+
+ std::size_t start_token;
+ std::size_t end_token;
+};
+
+struct TypeSpecifierAST: public AST
+{
+ const ListNode<std::size_t> *cv;
+};
+
+struct StatementAST: public AST
+{
+};
+
+struct ExpressionAST: public AST
+{
+};
+
+struct DeclarationAST: public AST
+{
+};
+
+struct AccessSpecifierAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(AccessSpecifier)
+
+ const ListNode<std::size_t> *specs;
+};
+
+struct AsmDefinitionAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(AsmDefinition)
+
+ const ListNode<std::size_t> *cv;
+};
+
+struct BaseClauseAST: public AST
+{ // ### kill me
+ DECLARE_AST_NODE(BaseClause)
+
+ const ListNode<BaseSpecifierAST*> *base_specifiers;
+};
+
+struct BaseSpecifierAST: public AST
+{
+ DECLARE_AST_NODE(BaseSpecifier)
+
+ std::size_t virt;
+ std::size_t access_specifier;
+ NameAST *name;
+};
+
+struct BinaryExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(BinaryExpression)
+
+ std::size_t op;
+ ExpressionAST *left_expression;
+ ExpressionAST *right_expression;
+};
+
+struct CastExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(CastExpression)
+
+ TypeIdAST *type_id;
+ ExpressionAST *expression;
+};
+
+struct ClassMemberAccessAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(ClassMemberAccess)
+
+ std::size_t op;
+ NameAST *name;
+};
+
+struct ClassSpecifierAST: public TypeSpecifierAST
+{
+ DECLARE_AST_NODE(ClassSpecifier)
+
+ WinDeclSpecAST *win_decl_specifiers;
+ std::size_t class_key;
+ NameAST *name;
+ BaseClauseAST *base_clause;
+ const ListNode<DeclarationAST*> *member_specs;
+};
+
+struct ForwardDeclarationSpecifierAST: public TypeSpecifierAST
+{
+ DECLARE_AST_NODE(ForwardDeclarationSpecifier)
+
+ std::size_t class_key;
+ NameAST *name;
+ BaseClauseAST *base_clause;
+};
+
+struct CompoundStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(CompoundStatement)
+
+ const ListNode<StatementAST*> *statements;
+};
+
+struct ConditionAST: public AST
+{
+ DECLARE_AST_NODE(Condition)
+
+ TypeSpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ ExpressionAST *expression;
+};
+
+struct ConditionalExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(ConditionalExpression)
+
+ ExpressionAST *condition;
+ ExpressionAST *left_expression;
+ ExpressionAST *right_expression;
+};
+
+struct CppCastExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(CppCastExpression)
+
+ std::size_t op;
+ TypeIdAST *type_id;
+ ExpressionAST *expression;
+ const ListNode<ExpressionAST*> *sub_expressions;
+};
+
+struct CtorInitializerAST: public AST
+{
+ DECLARE_AST_NODE(CtorInitializer)
+
+ std::size_t colon;
+ const ListNode<MemInitializerAST*> *member_initializers;
+};
+
+struct DeclarationStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(DeclarationStatement)
+
+ DeclarationAST *declaration;
+};
+
+struct DeclaratorAST: public AST
+{
+ DECLARE_AST_NODE(Declarator)
+
+ const ListNode<PtrOperatorAST*> *ptr_ops;
+ DeclaratorAST *sub_declarator;
+ NameAST *id;
+ ExpressionAST *bit_expression;
+ const ListNode<ExpressionAST*> *array_dimensions;
+ ParameterDeclarationClauseAST *parameter_declaration_clause;
+ const ListNode<std::size_t> *fun_cv;
+ ExceptionSpecificationAST *exception_spec;
+};
+
+struct DeleteExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(DeleteExpression)
+
+ std::size_t scope_token;
+ std::size_t delete_token;
+ std::size_t lbracket_token;
+ std::size_t rbracket_token;
+ ExpressionAST *expression;
+};
+
+struct DoStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(DoStatement)
+
+ StatementAST *statement;
+ ExpressionAST *expression;
+};
+
+struct ElaboratedTypeSpecifierAST: public TypeSpecifierAST
+{
+ DECLARE_AST_NODE(ElaboratedTypeSpecifier)
+
+ std::size_t type;
+ NameAST *name;
+};
+
+struct EnumSpecifierAST: public TypeSpecifierAST
+{
+ DECLARE_AST_NODE(EnumSpecifier)
+
+ NameAST *name;
+ const ListNode<EnumeratorAST*> *enumerators;
+};
+
+struct EnumeratorAST: public AST
+{
+ DECLARE_AST_NODE(Enumerator)
+
+ std::size_t id;
+ ExpressionAST *expression;
+};
+
+struct ExceptionSpecificationAST: public AST
+{
+ DECLARE_AST_NODE(ExceptionSpecification)
+
+ std::size_t ellipsis;
+ const ListNode<TypeIdAST*> *type_ids;
+};
+
+struct ExpressionOrDeclarationStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(ExpressionOrDeclarationStatement)
+
+ StatementAST *expression;
+ StatementAST *declaration;
+};
+
+struct ExpressionStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(ExpressionStatement)
+
+ ExpressionAST *expression;
+};
+
+struct FunctionCallAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(FunctionCall)
+
+ ExpressionAST *arguments;
+};
+
+struct FunctionDefinitionAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(FunctionDefinition)
+
+ const ListNode<std::size_t> *storage_specifiers;
+ const ListNode<std::size_t> *function_specifiers;
+ TypeSpecifierAST *type_specifier;
+ InitDeclaratorAST *init_declarator;
+ StatementAST *function_body;
+ WinDeclSpecAST *win_decl_specifiers;
+};
+
+struct ForStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(ForStatement)
+
+ StatementAST *init_statement;
+ ConditionAST *condition;
+ ExpressionAST *expression;
+ StatementAST *statement;
+};
+
+struct IfStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(IfStatement)
+
+ ConditionAST *condition;
+ StatementAST *statement;
+ StatementAST *else_statement;
+};
+
+struct IncrDecrExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(IncrDecrExpression)
+
+ std::size_t op;
+};
+
+struct InitDeclaratorAST: public AST
+{
+ DECLARE_AST_NODE(InitDeclarator)
+
+ DeclaratorAST *declarator;
+ InitializerAST *initializer;
+};
+
+struct InitializerAST: public AST
+{
+ DECLARE_AST_NODE(Initializer)
+
+ InitializerClauseAST *initializer_clause;
+ ExpressionAST *expression;
+};
+
+struct InitializerClauseAST: public AST
+{
+ DECLARE_AST_NODE(InitializerClause)
+
+ ExpressionAST *expression;
+};
+
+struct LabeledStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(LabeledStatement)
+};
+
+struct LinkageBodyAST: public AST
+{
+ DECLARE_AST_NODE(LinkageBody)
+
+ const ListNode<DeclarationAST*> *declarations;
+};
+
+struct LinkageSpecificationAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(LinkageSpecification)
+
+ std::size_t extern_type;
+ LinkageBodyAST *linkage_body;
+ DeclarationAST *declaration;
+};
+
+struct MemInitializerAST: public AST
+{
+ DECLARE_AST_NODE(MemInitializer)
+
+ NameAST *initializer_id;
+ ExpressionAST *expression;
+};
+
+struct NameAST: public AST
+{
+ DECLARE_AST_NODE(Name)
+
+ bool global;
+ const ListNode<UnqualifiedNameAST*> *qualified_names;
+ UnqualifiedNameAST *unqualified_name;
+};
+
+struct NamespaceAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(Namespace)
+
+ std::size_t namespace_name;
+ LinkageBodyAST *linkage_body;
+};
+
+struct NamespaceAliasDefinitionAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(NamespaceAliasDefinition)
+
+ std::size_t namespace_name;
+ NameAST *alias_name;
+};
+
+struct NewDeclaratorAST: public AST
+{
+ DECLARE_AST_NODE(NewDeclarator)
+
+ PtrOperatorAST *ptr_op;
+ NewDeclaratorAST *sub_declarator;
+ const ListNode<ExpressionAST*> *expressions;
+};
+
+struct NewExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(NewExpression)
+
+ std::size_t scope_token;
+ std::size_t new_token;
+ ExpressionAST *expression;
+ TypeIdAST *type_id;
+ NewTypeIdAST *new_type_id;
+ NewInitializerAST *new_initializer;
+};
+
+struct NewInitializerAST: public AST
+{
+ DECLARE_AST_NODE(NewInitializer)
+
+ ExpressionAST *expression;
+};
+
+struct NewTypeIdAST: public AST
+{
+ DECLARE_AST_NODE(NewTypeId)
+
+ TypeSpecifierAST *type_specifier;
+ NewInitializerAST *new_initializer;
+ NewDeclaratorAST *new_declarator;
+};
+
+struct OperatorAST: public AST
+{
+ DECLARE_AST_NODE(Operator)
+
+ std::size_t op;
+ std::size_t open;
+ std::size_t close;
+};
+
+struct OperatorFunctionIdAST: public AST
+{
+ DECLARE_AST_NODE(OperatorFunctionId)
+
+ OperatorAST *op;
+ TypeSpecifierAST *type_specifier;
+ const ListNode<PtrOperatorAST*> *ptr_ops;
+};
+
+struct ParameterDeclarationAST: public AST
+{
+ DECLARE_AST_NODE(ParameterDeclaration)
+
+ TypeSpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ ExpressionAST *expression;
+};
+
+struct ParameterDeclarationClauseAST: public AST
+{
+ DECLARE_AST_NODE(ParameterDeclarationClause)
+
+ const ListNode<ParameterDeclarationAST*> *parameter_declarations;
+ std::size_t ellipsis;
+};
+
+struct PostfixExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(PostfixExpression)
+
+ TypeSpecifierAST *type_specifier;
+ ExpressionAST *expression;
+ const ListNode<ExpressionAST*> *sub_expressions;
+};
+
+struct PrimaryExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(PrimaryExpression)
+
+ StringLiteralAST *literal;
+ std::size_t token;
+ StatementAST *expression_statement;
+ ExpressionAST *sub_expression;
+ NameAST *name;
+};
+
+struct PtrOperatorAST: public AST
+{
+ DECLARE_AST_NODE(PtrOperator)
+
+ const ListNode<std::size_t> *cv;
+ std::size_t op;
+ PtrToMemberAST *mem_ptr;
+};
+
+struct PtrToMemberAST: public AST
+{
+ DECLARE_AST_NODE(PtrToMember)
+};
+
+struct ReturnStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(ReturnStatement)
+
+ ExpressionAST *expression;
+};
+
+struct SimpleDeclarationAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(SimpleDeclaration)
+
+ const ListNode<std::size_t> *storage_specifiers;
+ const ListNode<std::size_t> *function_specifiers;
+ TypeSpecifierAST *type_specifier;
+ const ListNode<InitDeclaratorAST*> *init_declarators;
+ WinDeclSpecAST *win_decl_specifiers;
+};
+
+struct SimpleTypeSpecifierAST: public TypeSpecifierAST
+{
+ DECLARE_AST_NODE(SimpleTypeSpecifier)
+
+ const ListNode<std::size_t> *integrals;
+ std::size_t type_of;
+ TypeIdAST *type_id;
+ ExpressionAST *expression;
+ NameAST *name;
+};
+
+struct SizeofExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(SizeofExpression)
+
+ std::size_t sizeof_token;
+ TypeIdAST *type_id;
+ ExpressionAST *expression;
+};
+
+struct StringLiteralAST: public AST
+{
+ DECLARE_AST_NODE(StringLiteral)
+
+ const ListNode<std::size_t> *literals;
+};
+
+struct SubscriptExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(SubscriptExpression)
+
+ ExpressionAST *subscript;
+};
+
+struct SwitchStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(SwitchStatement)
+
+ ConditionAST *condition;
+ StatementAST *statement;
+};
+
+struct TemplateArgumentAST: public AST
+{
+ DECLARE_AST_NODE(TemplateArgument)
+
+ TypeIdAST *type_id;
+ ExpressionAST *expression;
+};
+
+struct TemplateDeclarationAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(TemplateDeclaration)
+
+ std::size_t exported;
+ const ListNode<TemplateParameterAST*> *template_parameters;
+ DeclarationAST* declaration;
+};
+
+struct TemplateParameterAST: public AST
+{
+ DECLARE_AST_NODE(TemplateParameter)
+
+ TypeParameterAST *type_parameter;
+ ParameterDeclarationAST *parameter_declaration;
+};
+
+struct ThrowExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(ThrowExpression)
+
+ std::size_t throw_token;
+ ExpressionAST *expression;
+};
+
+struct TranslationUnitAST: public AST
+{
+ DECLARE_AST_NODE(TranslationUnit)
+
+ const ListNode<DeclarationAST*> *declarations;
+};
+
+struct TryBlockStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(TryBlockStatement)
+};
+
+struct TypeIdAST: public AST
+{
+ DECLARE_AST_NODE(TypeId)
+
+ TypeSpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+};
+
+struct TypeIdentificationAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(TypeIdentification)
+
+ std::size_t typename_token;
+ NameAST *name;
+ ExpressionAST *expression;
+};
+
+struct TypeParameterAST: public AST
+{
+ DECLARE_AST_NODE(TypeParameter)
+
+ std::size_t type;
+ NameAST *name;
+ TypeIdAST *type_id;
+ const ListNode<TemplateParameterAST*> *template_parameters;
+ NameAST *template_name;
+};
+
+struct TypedefAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(Typedef)
+
+ TypeSpecifierAST *type_specifier;
+ const ListNode<InitDeclaratorAST*> *init_declarators;
+};
+
+struct UnaryExpressionAST: public ExpressionAST
+{
+ DECLARE_AST_NODE(UnaryExpression)
+
+ std::size_t op;
+ ExpressionAST *expression;
+};
+
+struct UnqualifiedNameAST: public AST
+{
+ DECLARE_AST_NODE(UnqualifiedName)
+
+ std::size_t tilde;
+ std::size_t id;
+ OperatorFunctionIdAST *operator_id;
+ const ListNode<TemplateArgumentAST*> *template_arguments;
+};
+
+struct UsingAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(Using)
+
+ std::size_t type_name;
+ NameAST *name;
+};
+
+struct UsingDirectiveAST: public DeclarationAST
+{
+ DECLARE_AST_NODE(UsingDirective)
+
+ NameAST *name;
+};
+
+struct WhileStatementAST: public StatementAST
+{
+ DECLARE_AST_NODE(WhileStatement)
+
+ ConditionAST *condition;
+ StatementAST *statement;
+};
+
+struct WinDeclSpecAST: public AST
+{
+ DECLARE_AST_NODE(WinDeclSpec)
+
+ std::size_t specifier;
+ std::size_t modifier;
+};
+
+struct QPropertyAST : public DeclarationAST
+{
+ DECLARE_AST_NODE(QPropertyAST)
+};
+
+struct QEnumsAST : public DeclarationAST
+{
+ DECLARE_AST_NODE(QEnumsAST)
+};
+
+template <class _Tp>
+_Tp *CreateNode(pool *memory_pool)
+{
+ _Tp *node = reinterpret_cast<_Tp*>(memory_pool->allocate(sizeof(_Tp)));
+ node->kind = _Tp::__node_kind;
+ return node;
+}
+
+template <class _Tp>
+_Tp ast_cast(AST *item)
+{
+ if (item && static_cast<_Tp>(0)->__node_kind == item->kind)
+ return static_cast<_Tp>(item);
+
+ return 0;
+}
+
+#endif // AST_H
diff --git a/parser/binder.cpp b/parser/binder.cpp
new file mode 100644
index 000000000..8b6c4c024
--- /dev/null
+++ b/parser/binder.cpp
@@ -0,0 +1,852 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "binder.h"
+#include "lexer.h"
+#include "control.h"
+#include "symbol.h"
+#include "codemodel_finder.h"
+#include "class_compiler.h"
+#include "compiler_utils.h"
+#include "tokens.h"
+#include "dumptree.h"
+
+#include <iostream>
+#include <QDebug>
+
+Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control)
+ : _M_model(__model),
+ _M_location(__location),
+ _M_token_stream(&_M_location.token_stream),
+ _M_control(__control),
+ _M_current_function_type(CodeModel::Normal),
+ type_cc(this),
+ name_cc(this),
+ decl_cc(this)
+{
+ _M_qualified_types["char"] = QString();
+ _M_qualified_types["double"] = QString();
+ _M_qualified_types["float"] = QString();
+ _M_qualified_types["int"] = QString();
+ _M_qualified_types["long"] = QString();
+ _M_qualified_types["short"] = QString();
+ _M_qualified_types["void"] = QString();
+}
+
+Binder::~Binder()
+{
+}
+
+FileModelItem Binder::run(AST *node)
+{
+ FileModelItem old = _M_current_file;
+ _M_current_access = CodeModel::Public;
+
+ _M_current_file = model()->create<FileModelItem>();
+ updateItemPosition(_M_current_file->toItem(), node);
+ visit(node);
+ FileModelItem result = _M_current_file;
+
+ _M_current_file = old; // restore
+
+ return result;
+}
+
+ScopeModelItem Binder::currentScope()
+{
+ if (_M_current_class)
+ return model_static_cast<ScopeModelItem>(_M_current_class);
+ else if (_M_current_namespace)
+ return model_static_cast<ScopeModelItem>(_M_current_namespace);
+
+ return model_static_cast<ScopeModelItem>(_M_current_file);
+}
+
+TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters)
+{
+ TemplateParameterList old = _M_current_template_parameters;
+ _M_current_template_parameters = templateParameters;
+ return old;
+}
+
+CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType)
+{
+ CodeModel::FunctionType old = _M_current_function_type;
+ _M_current_function_type = functionType;
+ return old;
+}
+
+CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy)
+{
+ CodeModel::AccessPolicy old = _M_current_access;
+ _M_current_access = accessPolicy;
+ return old;
+}
+
+NamespaceModelItem Binder::changeCurrentNamespace(NamespaceModelItem item)
+{
+ NamespaceModelItem old = _M_current_namespace;
+ _M_current_namespace = item;
+ return old;
+}
+
+ClassModelItem Binder::changeCurrentClass(ClassModelItem item)
+{
+ ClassModelItem old = _M_current_class;
+ _M_current_class = item;
+ return old;
+}
+
+FunctionDefinitionModelItem Binder::changeCurrentFunction(FunctionDefinitionModelItem item)
+{
+ FunctionDefinitionModelItem old = _M_current_function;
+ _M_current_function = item;
+ return old;
+}
+
+int Binder::decode_token(std::size_t index) const
+{
+ return _M_token_stream->kind(index);
+}
+
+CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const
+{
+ switch (decode_token(index)) {
+ case Token_class:
+ return CodeModel::Private;
+
+ case Token_struct:
+ case Token_union:
+ return CodeModel::Public;
+
+ default:
+ return CodeModel::Public;
+ }
+}
+
+CodeModel::ClassType Binder::decode_class_type(std::size_t index) const
+{
+ switch (decode_token(index)) {
+ case Token_class:
+ return CodeModel::Class;
+ case Token_struct:
+ return CodeModel::Struct;
+ case Token_union:
+ return CodeModel::Union;
+ default:
+ std::cerr << "** WARNING unrecognized class type" << std::endl;
+ }
+ return CodeModel::Class;
+}
+
+const NameSymbol *Binder::decode_symbol(std::size_t index) const
+{
+ return _M_token_stream->symbol(index);
+}
+
+void Binder::visitAccessSpecifier(AccessSpecifierAST *node)
+{
+ const ListNode<std::size_t> *it = node->specs;
+ if (!it)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do {
+ switch (decode_token(it->element)) {
+ default:
+ break;
+
+ case Token_public:
+ changeCurrentAccess(CodeModel::Public);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_protected:
+ changeCurrentAccess(CodeModel::Protected);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_private:
+ changeCurrentAccess(CodeModel::Private);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_signals:
+ changeCurrentAccess(CodeModel::Protected);
+ changeCurrentFunctionType(CodeModel::Signal);
+ break;
+ case Token_slots:
+ changeCurrentFunctionType(CodeModel::Slot);
+ break;
+ }
+ it = it->next;
+ } while (it != end);
+}
+
+void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node)
+{
+ visit(node->type_specifier);
+
+ if (const ListNode<InitDeclaratorAST*> *it = node->init_declarators) {
+ it = it->toFront();
+ const ListNode<InitDeclaratorAST*> *end = it;
+ do {
+ InitDeclaratorAST *init_declarator = it->element;
+ declare_symbol(node, init_declarator);
+ it = it->next;
+ } while (it != end);
+ }
+}
+
+void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator)
+{
+ DeclaratorAST *declarator = init_declarator->declarator;
+
+ while (declarator && declarator->sub_declarator)
+ declarator = declarator->sub_declarator;
+
+ NameAST *id = declarator->id;
+ if (!declarator->id) {
+ std::cerr << "** WARNING expected a declarator id" << std::endl;
+ return;
+ }
+
+ CodeModelFinder finder(model(), this);
+ ScopeModelItem symbolScope = finder.resolveScope(id, currentScope());
+ if (!symbolScope) {
+ name_cc.run(id);
+ std::cerr << "** WARNING scope not found for symbol:"
+ << qPrintable(name_cc.name()) << std::endl;
+ return;
+ }
+
+ decl_cc.run(declarator);
+
+ if (decl_cc.isFunction()) {
+ name_cc.run(id->unqualified_name);
+
+ FunctionModelItem fun = model()->create<FunctionModelItem>();
+ updateItemPosition(fun->toItem(), node);
+ fun->setAccessPolicy(_M_current_access);
+ fun->setFunctionType(_M_current_function_type);
+ fun->setName(name_cc.name());
+ fun->setAbstract(init_declarator->initializer != 0);
+ fun->setConstant(declarator->fun_cv != 0);
+ fun->setTemplateParameters(_M_current_template_parameters);
+ applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(fun));
+ applyFunctionSpecifiers(node->function_specifiers, fun);
+
+ // build the type
+ TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+ declarator,
+ this);
+
+ fun->setType(qualifyType(typeInfo, symbolScope->qualifiedName()));
+
+
+ fun->setVariadics(decl_cc.isVariadics());
+
+ // ... and the signature
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) {
+ ArgumentModelItem arg = model()->create<ArgumentModelItem>();
+ arg->setType(qualifyType(p.type, _M_context));
+ arg->setName(p.name);
+ arg->setDefaultValue(p.defaultValue);
+ if (p.defaultValue)
+ arg->setDefaultValueExpression(p.defaultValueExpression);
+ fun->addArgument(arg);
+ }
+
+ fun->setScope(symbolScope->qualifiedName());
+ symbolScope->addFunction(fun);
+ } else {
+ VariableModelItem var = model()->create<VariableModelItem>();
+ updateItemPosition(var->toItem(), node);
+ var->setTemplateParameters(_M_current_template_parameters);
+ var->setAccessPolicy(_M_current_access);
+ name_cc.run(id->unqualified_name);
+ var->setName(name_cc.name());
+ TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+ declarator,
+ this);
+ if (declarator != init_declarator->declarator
+ && init_declarator->declarator->parameter_declaration_clause) {
+ typeInfo.setFunctionPointer(true);
+ decl_cc.run(init_declarator->declarator);
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ typeInfo.addArgument(p.type);
+ }
+
+ var->setType(qualifyType(typeInfo, _M_context));
+ applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(var));
+
+ var->setScope(symbolScope->qualifiedName());
+ symbolScope->addVariable(var);
+ }
+}
+
+void Binder::visitFunctionDefinition(FunctionDefinitionAST *node)
+{
+ Q_ASSERT(node->init_declarator);
+
+ ScopeModelItem scope = currentScope();
+
+ InitDeclaratorAST *init_declarator = node->init_declarator;
+ DeclaratorAST *declarator = init_declarator->declarator;
+
+ // in the case of "void (func)()" or "void ((func))()" we need to
+ // skip to the inner most. This is in line with how the declarator
+ // node is generated in 'parser.cpp'
+ while (declarator && declarator->sub_declarator)
+ declarator = declarator->sub_declarator;
+ Q_ASSERT(declarator->id);
+
+ CodeModelFinder finder(model(), this);
+
+ ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope);
+ if (!functionScope) {
+ name_cc.run(declarator->id);
+ std::cerr << "** WARNING scope not found for function definition:"
+ << qPrintable(name_cc.name()) << std::endl
+ << "\tdefinition *ignored*"
+ << std::endl;
+ return;
+ }
+
+ decl_cc.run(declarator);
+
+ Q_ASSERT(!decl_cc.id().isEmpty());
+
+ FunctionDefinitionModelItem
+ old = changeCurrentFunction(_M_model->create<FunctionDefinitionModelItem>());
+ _M_current_function->setScope(functionScope->qualifiedName());
+ updateItemPosition(_M_current_function->toItem(), node);
+
+ Q_ASSERT(declarator->id->unqualified_name);
+ name_cc.run(declarator->id->unqualified_name);
+ QString unqualified_name = name_cc.name();
+
+ _M_current_function->setName(unqualified_name);
+ TypeInfo tmp_type = CompilerUtils::typeDescription(node->type_specifier,
+ declarator, this);
+
+ _M_current_function->setType(qualifyType(tmp_type, _M_context));
+ _M_current_function->setAccessPolicy(_M_current_access);
+ _M_current_function->setFunctionType(_M_current_function_type);
+ _M_current_function->setConstant(declarator->fun_cv);
+ _M_current_function->setTemplateParameters(_M_current_template_parameters);
+
+ applyStorageSpecifiers(node->storage_specifiers,
+ model_static_cast<MemberModelItem>(_M_current_function));
+ applyFunctionSpecifiers(node->function_specifiers,
+ model_static_cast<FunctionModelItem>(_M_current_function));
+
+ _M_current_function->setVariadics(decl_cc.isVariadics());
+
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) {
+ ArgumentModelItem arg = model()->create<ArgumentModelItem>();
+ arg->setType(qualifyType(p.type, functionScope->qualifiedName()));
+ arg->setName(p.name);
+ arg->setDefaultValue(p.defaultValue);
+ if (p.defaultValue)
+ arg->setDefaultValueExpression(p.defaultValueExpression);
+ _M_current_function->addArgument(arg);
+ }
+
+ functionScope->addFunctionDefinition(_M_current_function);
+
+ FunctionModelItem prototype = model_static_cast<FunctionModelItem>(_M_current_function);
+ FunctionModelItem declared = functionScope->declaredFunction(prototype);
+
+ // try to find a function declaration for this definition..
+ if (!declared) {
+ functionScope->addFunction(prototype);
+ } else {
+ applyFunctionSpecifiers(node->function_specifiers, declared);
+
+ // fix the function type and the access policy
+ _M_current_function->setAccessPolicy(declared->accessPolicy());
+ _M_current_function->setFunctionType(declared->functionType());
+ }
+
+ changeCurrentFunction(old);
+}
+
+void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node)
+{
+ const ListNode<TemplateParameterAST*> *it = node->template_parameters;
+ if (!it) {
+ // QtScript: we want to visit the declaration still, so that
+ // e.g. QMetaTypeId<Foo> is added to the code model
+ visit(node->declaration);
+ return;
+ }
+
+ TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList());
+
+ it = it->toFront();
+ const ListNode<TemplateParameterAST*> *end = it;
+
+ TemplateParameterList templateParameters;
+ do {
+ TemplateParameterAST *parameter = it->element;
+ TypeParameterAST *type_parameter = parameter->type_parameter;
+
+ NameAST *name;
+ if (!type_parameter) {
+ // A hacky hack to work around missing support for parameter declarations in
+ // templates. We just need the to get the name of the variable, since we
+ // aren't actually compiling these anyway. We are still not supporting much
+ // more, but we are refusing to fail for a few more declarations
+ if (!parameter->parameter_declaration ||
+ !parameter->parameter_declaration->declarator ||
+ !parameter->parameter_declaration->declarator->id) {
+
+ /*std::cerr << "** WARNING template declaration not supported ``";
+ Token const &tk = _M_token_stream->token ((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+ std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+ << std::endl << std::endl;*/
+
+ changeTemplateParameters(savedTemplateParameters);
+ return;
+
+ }
+
+ name = parameter->parameter_declaration->declarator->id;
+ } else {
+ int tk = decode_token(type_parameter->type);
+ if (tk != Token_typename && tk != Token_class) {
+ /*std::cerr << "** WARNING template declaration not supported ``";
+ Token const &tk = _M_token_stream->token ((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+ std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+ << std::endl << std::endl;*/
+
+ changeTemplateParameters(savedTemplateParameters);
+ return;
+ }
+ assert(tk == Token_typename || tk == Token_class);
+
+ name = type_parameter->name;
+ }
+
+ TemplateParameterModelItem p = model()->create<TemplateParameterModelItem>();
+ name_cc.run(name);
+ p->setName(name_cc.name());
+
+ _M_current_template_parameters.append(p);
+ it = it->next;
+ } while (it != end);
+
+ visit(node->declaration);
+
+ changeTemplateParameters(savedTemplateParameters);
+}
+
+void Binder::visitTypedef(TypedefAST *node)
+{
+ const ListNode<InitDeclaratorAST*> *it = node->init_declarators;
+ if (!it)
+ return;
+
+ it = it->toFront();
+ const ListNode<InitDeclaratorAST*> *end = it;
+
+ do {
+ InitDeclaratorAST *init_declarator = it->element;
+ it = it->next;
+
+ Q_ASSERT(init_declarator->declarator);
+
+ // the name
+ decl_cc.run(init_declarator->declarator);
+ QString alias_name = decl_cc.id();
+
+ if (alias_name.isEmpty()) {
+ std::cerr << "** WARNING anonymous typedef not supported! ``";
+ Token const &tk = _M_token_stream->token((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token((int) node->end_token);
+
+ std::cerr << std::string(&tk.text[tk.position], end_tk.position - tk.position) << "''"
+ << std::endl << std::endl;
+ continue;
+ }
+
+ // build the type
+ TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+ init_declarator->declarator,
+ this);
+ DeclaratorAST *decl = init_declarator->declarator;
+ while (decl && decl->sub_declarator)
+ decl = decl->sub_declarator;
+
+ if (decl != init_declarator->declarator
+ && init_declarator->declarator->parameter_declaration_clause) {
+ typeInfo.setFunctionPointer(true);
+ decl_cc.run(init_declarator->declarator);
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ typeInfo.addArgument(p.type);
+ }
+
+ ScopeModelItem scope = currentScope();
+ DeclaratorAST *declarator = init_declarator->declarator;
+ CodeModelFinder finder(model(), this);
+ ScopeModelItem typedefScope = finder.resolveScope(declarator->id, scope);
+
+ TypeAliasModelItem typeAlias = model()->create<TypeAliasModelItem> ();
+ updateItemPosition(typeAlias->toItem(), node);
+ typeAlias->setName(alias_name);
+ typeAlias->setType(qualifyType(typeInfo, currentScope()->qualifiedName()));
+ typeAlias->setScope(typedefScope->qualifiedName());
+ _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString();
+ currentScope()->addTypeAlias(typeAlias);
+ } while (it != end);
+}
+
+void Binder::visitNamespace(NamespaceAST *node)
+{
+ bool anonymous = (node->namespace_name == 0);
+
+ ScopeModelItem scope = currentScope();
+
+ NamespaceModelItem old;
+ if (!anonymous) {
+ QString name = decode_symbol(node->namespace_name)->as_string();
+
+ QStringList qualified_name = scope->qualifiedName();
+ qualified_name += name;
+ NamespaceModelItem ns =
+ model_safe_cast<NamespaceModelItem>(_M_model->findItem(qualified_name,
+ _M_current_file->toItem()));
+ if (!ns) {
+ ns = _M_model->create<NamespaceModelItem>();
+ updateItemPosition(ns->toItem(), node);
+ ns->setName(name);
+ ns->setScope(scope->qualifiedName());
+ }
+ old = changeCurrentNamespace(ns);
+
+ _M_context.append(name);
+ }
+
+ DefaultVisitor::visitNamespace(node);
+
+ if (!anonymous) {
+ Q_ASSERT(scope->kind() == _CodeModelItem::Kind_Namespace
+ || scope->kind() == _CodeModelItem::Kind_File);
+
+ _M_context.removeLast();
+
+ if (NamespaceModelItem ns = model_static_cast<NamespaceModelItem>(scope))
+ ns->addNamespace(_M_current_namespace);
+
+ changeCurrentNamespace(old);
+ }
+}
+
+void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *node)
+{
+ name_cc.run(node->name);
+ if (name_cc.name().isEmpty())
+ return;
+
+ ScopeModelItem scope = currentScope();
+ _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".")] = QString();
+}
+
+void Binder::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ ClassCompiler class_cc(this);
+ class_cc.run(node);
+
+ if (class_cc.name().isEmpty()) {
+ // anonymous not supported
+ return;
+ }
+
+ Q_ASSERT(node->name && node->name->unqualified_name);
+
+ ScopeModelItem scope = currentScope();
+
+ ClassModelItem old = changeCurrentClass(_M_model->create<ClassModelItem>());
+ updateItemPosition(_M_current_class->toItem(), node);
+ _M_current_class->setName(class_cc.name());
+
+ QStringList baseClasses = class_cc.baseClasses();
+ TypeInfo info;
+ for (int i = 0; i < baseClasses.size(); ++i) {
+ info.setQualifiedName(baseClasses.at(i).split("::"));
+ baseClasses[i] = qualifyType(info, scope->qualifiedName()).qualifiedName().join("::");
+ }
+
+ _M_current_class->setBaseClasses(baseClasses);
+ _M_current_class->setClassType(decode_class_type(node->class_key));
+ _M_current_class->setTemplateParameters(_M_current_template_parameters);
+
+ if (!_M_current_template_parameters.isEmpty()) {
+ QString name = _M_current_class->name();
+ name += "<";
+ for (int i = 0; i < _M_current_template_parameters.size(); ++i) {
+ if (i > 0)
+ name += ",";
+
+ name += _M_current_template_parameters.at(i)->name();
+ }
+
+ name += ">";
+ _M_current_class->setName(name);
+ }
+
+ CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key));
+ CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal);
+
+ _M_current_class->setScope(scope->qualifiedName());
+ _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString();
+
+ scope->addClass(_M_current_class);
+
+ name_cc.run(node->name->unqualified_name);
+ _M_context.append(name_cc.name());
+ visitNodes(this, node->member_specs);
+ _M_context.removeLast();
+
+ changeCurrentClass(old);
+ changeCurrentAccess(oldAccessPolicy);
+ changeCurrentFunctionType(oldFunctionType);
+}
+
+void Binder::visitLinkageSpecification(LinkageSpecificationAST *node)
+{
+ DefaultVisitor::visitLinkageSpecification(node);
+}
+
+void Binder::visitUsing(UsingAST *node)
+{
+ DefaultVisitor::visitUsing(node);
+}
+
+void Binder::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+ CodeModelFinder finder(model(), this);
+ ScopeModelItem scope = currentScope();
+ ScopeModelItem enumScope = finder.resolveScope(node->name, scope);
+
+ name_cc.run(node->name);
+ QString name = name_cc.name();
+
+ if (name.isEmpty()) {
+ // anonymous enum
+ QString key = _M_context.join("::");
+ int current = ++_M_anonymous_enums[key];
+ name += QLatin1String("enum_");
+ name += QString::number(current);
+ }
+
+ _M_current_enum = model()->create<EnumModelItem>();
+ _M_current_enum->setAccessPolicy(_M_current_access);
+ updateItemPosition(_M_current_enum->toItem(), node);
+ _M_current_enum->setName(name);
+ _M_current_enum->setScope(enumScope->qualifiedName());
+
+ _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString();
+
+ enumScope->addEnum(_M_current_enum);
+
+ DefaultVisitor::visitEnumSpecifier(node);
+
+ _M_current_enum = 0;
+}
+
+static QString strip_preprocessor_lines(const QString &name)
+{
+ QStringList lst = name.split("\n");
+ QString s;
+ for (int i = 0; i < lst.size(); ++i) {
+ if (!lst.at(i).startsWith('#'))
+ s += lst.at(i);
+ }
+ return s.trimmed();
+}
+
+void Binder::visitEnumerator(EnumeratorAST *node)
+{
+ Q_ASSERT(_M_current_enum);
+ EnumeratorModelItem e = model()->create<EnumeratorModelItem>();
+ updateItemPosition(e->toItem(), node);
+ e->setName(decode_symbol(node->id)->as_string());
+
+ if (ExpressionAST *expr = node->expression) {
+ const Token &start_token = _M_token_stream->token((int) expr->start_token);
+ const Token &end_token = _M_token_stream->token((int) expr->end_token);
+
+ e->setValue(strip_preprocessor_lines(QString::fromUtf8(&start_token.text[start_token.position],
+ (int)(end_token.position - start_token.position)).trimmed()).remove(' '));
+ }
+
+ _M_current_enum->addEnumerator(e);
+}
+
+void Binder::visitUsingDirective(UsingDirectiveAST *node)
+{
+ DefaultVisitor::visitUsingDirective(node);
+}
+
+void Binder::visitQEnums(QEnumsAST *node)
+{
+ const Token &start = _M_token_stream->token((int) node->start_token);
+ const Token &end = _M_token_stream->token((int) node->end_token);
+ QStringList enum_list = QString::fromLatin1(start.text + start.position,
+ end.position - start.position).split(' ');
+
+ ScopeModelItem scope = currentScope();
+ for (int i = 0; i < enum_list.size(); ++i)
+ scope->addEnumsDeclaration(enum_list.at(i));
+}
+
+void Binder::visitQProperty(QPropertyAST *node)
+{
+ const Token &start = _M_token_stream->token((int) node->start_token);
+ const Token &end = _M_token_stream->token((int) node->end_token);
+ QString property = QString::fromLatin1(start.text + start.position,
+ end.position - start.position);
+ _M_current_class->addPropertyDeclaration(property);
+}
+
+void Binder::applyStorageSpecifiers(const ListNode<std::size_t> *it, MemberModelItem item)
+{
+ if (!it)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do {
+ switch (decode_token(it->element)) {
+ default:
+ break;
+
+ case Token_friend:
+ item->setFriend(true);
+ break;
+ case Token_auto:
+ item->setAuto(true);
+ break;
+ case Token_register:
+ item->setRegister(true);
+ break;
+ case Token_static:
+ item->setStatic(true);
+ break;
+ case Token_extern:
+ item->setExtern(true);
+ break;
+ case Token_mutable:
+ item->setMutable(true);
+ break;
+ }
+ it = it->next;
+ } while (it != end);
+}
+
+void Binder::applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item)
+{
+ if (!it)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do {
+ switch (decode_token(it->element)) {
+ default:
+ break;
+
+ case Token_inline:
+ item->setInline(true);
+ break;
+
+ case Token_virtual:
+ item->setVirtual(true);
+ break;
+
+ case Token_explicit:
+ item->setExplicit(true);
+ break;
+
+ case Token_Q_INVOKABLE:
+ item->setInvokable(true);
+ break;
+ }
+ it = it->next;
+ } while (it != end);
+}
+
+TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const
+{
+ // ### Potentially improve to use string list in the name table to
+ if (!context.size()) {
+ // ### We can assume that this means global namespace for now...
+ return type;
+ } else if (_M_qualified_types.contains(type.qualifiedName().join("."))) {
+ return type;
+ } else {
+ QStringList expanded = context;
+ expanded << type.qualifiedName();
+ if (_M_qualified_types.contains(expanded.join("."))) {
+ TypeInfo modified_type = type;
+ modified_type.setQualifiedName(expanded);
+ return modified_type;
+ } else {
+ CodeModelItem scope = model()->findItem(context, _M_current_file->toItem());
+
+ if (ClassModelItem klass = model_dynamic_cast<ClassModelItem> (scope)) {
+ foreach (QString base, klass->baseClasses()) {
+ QStringList ctx = context;
+ ctx.removeLast();
+ ctx.append(base);
+
+ TypeInfo qualified = qualifyType(type, ctx);
+ if (qualified != type)
+ return qualified;
+ }
+ }
+
+ QStringList copy = context;
+ copy.removeLast();
+ return qualifyType(type, copy);
+ }
+ }
+}
+
+void Binder::updateItemPosition(CodeModelItem item, AST *node)
+{
+ QString filename;
+ int line, column;
+
+ assert(node);
+ _M_location.positionAt(_M_token_stream->position(node->start_token), &line, &column, &filename);
+ item->setFileName(filename);
+}
diff --git a/parser/binder.h b/parser/binder.h
new file mode 100644
index 000000000..b4d4da667
--- /dev/null
+++ b/parser/binder.h
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef BINDER_H
+#define BINDER_H
+
+#include "default_visitor.h"
+#include "codemodel.h"
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "declarator_compiler.h"
+
+class TokenStream;
+class LocationManager;
+class Control;
+struct NameSymbol;
+
+class Binder: protected DefaultVisitor
+{
+public:
+ Binder(CodeModel *__model, LocationManager &__location, Control *__control = 0);
+ virtual ~Binder();
+
+ inline TokenStream *tokenStream() const
+ {
+ return _M_token_stream;
+ }
+
+ inline CodeModel *model() const
+ {
+ return _M_model;
+ }
+
+ ScopeModelItem currentScope();
+
+ FileModelItem run(AST *node);
+
+// utils
+ TypeInfo qualifyType(const TypeInfo &type, const QStringList &context) const;
+
+protected:
+ virtual void visitAccessSpecifier(AccessSpecifierAST *);
+ virtual void visitClassSpecifier(ClassSpecifierAST *);
+ virtual void visitEnumSpecifier(EnumSpecifierAST *);
+ virtual void visitEnumerator(EnumeratorAST *);
+ virtual void visitFunctionDefinition(FunctionDefinitionAST *);
+ virtual void visitLinkageSpecification(LinkageSpecificationAST *);
+ virtual void visitNamespace(NamespaceAST *);
+ virtual void visitSimpleDeclaration(SimpleDeclarationAST *);
+ virtual void visitTemplateDeclaration(TemplateDeclarationAST *);
+ virtual void visitTypedef(TypedefAST *);
+ virtual void visitUsing(UsingAST *);
+ virtual void visitUsingDirective(UsingDirectiveAST *);
+ virtual void visitQProperty(QPropertyAST *);
+ virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *);
+ virtual void visitQEnums(QEnumsAST *);
+
+private:
+
+ int decode_token(std::size_t index) const;
+ const NameSymbol *decode_symbol(std::size_t index) const;
+ CodeModel::AccessPolicy decode_access_policy(std::size_t index) const;
+ CodeModel::ClassType decode_class_type(std::size_t index) const;
+
+ CodeModel::FunctionType changeCurrentFunctionType(CodeModel::FunctionType functionType);
+ CodeModel::AccessPolicy changeCurrentAccess(CodeModel::AccessPolicy accessPolicy);
+ NamespaceModelItem changeCurrentNamespace(NamespaceModelItem item);
+ ClassModelItem changeCurrentClass(ClassModelItem item);
+ FunctionDefinitionModelItem changeCurrentFunction(FunctionDefinitionModelItem item);
+ TemplateParameterList changeTemplateParameters(TemplateParameterList templateParameters);
+
+ void declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator);
+
+ void applyStorageSpecifiers(const ListNode<std::size_t> *storage_specifiers, MemberModelItem item);
+ void applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item);
+
+ void updateItemPosition(CodeModelItem item, AST *node);
+
+private:
+ CodeModel *_M_model;
+ LocationManager &_M_location;
+ TokenStream *_M_token_stream;
+ Control *_M_control;
+
+ CodeModel::FunctionType _M_current_function_type;
+ CodeModel::AccessPolicy _M_current_access;
+ FileModelItem _M_current_file;
+ NamespaceModelItem _M_current_namespace;
+ ClassModelItem _M_current_class;
+ FunctionDefinitionModelItem _M_current_function;
+ EnumModelItem _M_current_enum;
+ QStringList _M_context;
+ TemplateParameterList _M_current_template_parameters; // ### check me
+ QHash<QString, QString> _M_qualified_types;
+ QHash<QString, int> _M_anonymous_enums;
+
+protected:
+ TypeCompiler type_cc;
+ NameCompiler name_cc;
+ DeclaratorCompiler decl_cc;
+};
+
+#endif // BINDER_H
diff --git a/parser/class_compiler.cpp b/parser/class_compiler.cpp
new file mode 100644
index 000000000..e04ffe109
--- /dev/null
+++ b/parser/class_compiler.cpp
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "class_compiler.h"
+#include "lexer.h"
+#include "binder.h"
+
+ClassCompiler::ClassCompiler(Binder *binder)
+ : _M_binder(binder),
+ _M_token_stream(binder->tokenStream()),
+ name_cc(_M_binder),
+ type_cc(_M_binder)
+{
+}
+
+ClassCompiler::~ClassCompiler()
+{
+}
+
+void ClassCompiler::run(ClassSpecifierAST *node)
+{
+ name_cc.run(node->name);
+ _M_name = name_cc.name();
+ _M_base_classes.clear();
+
+ visit(node);
+}
+
+void ClassCompiler::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ visit(node->base_clause);
+}
+
+void ClassCompiler::visitBaseSpecifier(BaseSpecifierAST *node)
+{
+ name_cc.run(node->name);
+ QString name = name_cc.name();
+
+ if (!name.isEmpty())
+ _M_base_classes.append(name);
+}
+
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/class_compiler.h b/parser/class_compiler.h
new file mode 100644
index 000000000..69fccf757
--- /dev/null
+++ b/parser/class_compiler.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef CLASS_COMPILER_H
+#define CLASS_COMPILER_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QStringList>
+
+#include <default_visitor.h>
+#include <name_compiler.h>
+#include <type_compiler.h>
+
+class TokenStream;
+class Binder;
+
+class ClassCompiler: protected DefaultVisitor
+{
+public:
+ ClassCompiler(Binder *binder);
+ virtual ~ClassCompiler();
+
+ inline QString name() const
+ {
+ return _M_name;
+ }
+
+ inline QStringList baseClasses() const
+ {
+ return _M_base_classes;
+ }
+
+ void run(ClassSpecifierAST *node);
+
+protected:
+ virtual void visitClassSpecifier(ClassSpecifierAST *node);
+ virtual void visitBaseSpecifier(BaseSpecifierAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QString _M_name;
+ QStringList _M_base_classes;
+ NameCompiler name_cc;
+ TypeCompiler type_cc;
+};
+
+#endif // CLASS_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/codemodel.cpp b/parser/codemodel.cpp
new file mode 100644
index 000000000..ecc8e3036
--- /dev/null
+++ b/parser/codemodel.cpp
@@ -0,0 +1,932 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "codemodel.h"
+
+// ---------------------------------------------------------------------------
+CodeModel::CodeModel()
+ : _M_creation_id(0)
+{
+ _M_globalNamespace = create<NamespaceModelItem>();
+}
+
+CodeModel::~CodeModel()
+{
+}
+
+void CodeModel::wipeout()
+{
+ _M_globalNamespace = create<NamespaceModelItem>();
+ _M_files.clear();
+}
+
+FileList CodeModel::files() const
+{
+ return _M_files.values();
+}
+
+NamespaceModelItem CodeModel::globalNamespace() const
+{
+ return _M_globalNamespace;
+}
+
+void CodeModel::addFile(FileModelItem item)
+{
+ _M_creation_id = 0; // reset the creation id
+ _M_files.insert(item->name(), item);
+}
+
+void CodeModel::removeFile(FileModelItem item)
+{
+ QHash<QString, FileModelItem>::Iterator it = _M_files.find(item->name());
+
+ if (it != _M_files.end() && it.value() == item)
+ _M_files.erase(it);
+}
+
+FileModelItem CodeModel::findFile(const QString &name) const
+{
+ return _M_files.value(name);
+}
+
+QHash<QString, FileModelItem> CodeModel::fileMap() const
+{
+ return _M_files;
+}
+
+CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, CodeModelItem scope) const
+{
+ for (int i = 0; i < qualifiedName.size(); ++i) {
+ // ### Extend to look for members etc too.
+ const QString &name = qualifiedName.at(i);
+
+ if (NamespaceModelItem ns = model_dynamic_cast<NamespaceModelItem>(scope)) {
+ if (NamespaceModelItem tmp_ns = ns->findNamespace(name)) {
+ scope = tmp_ns;
+ continue;
+ }
+ }
+
+ if (ScopeModelItem ss = model_dynamic_cast<ScopeModelItem>(scope)) {
+ if (ClassModelItem cs = ss->findClass(name)) {
+ scope = cs;
+ } else if (EnumModelItem es = ss->findEnum(name)) {
+ if (i == qualifiedName.size() - 1)
+ return es->toItem();
+ } else if (TypeAliasModelItem tp = ss->findTypeAlias(name)) {
+ if (i == qualifiedName.size() - 1)
+ return tp->toItem();
+ } else {
+ // If we don't find the name in the scope chain we
+ // need to return an empty item to indicate failure...
+ return CodeModelItem();
+ }
+ }
+ }
+
+ return scope;
+}
+
+
+// ---------------------------------------------------------------------------
+TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs)
+{
+ TypeInfo __result = __lhs;
+
+ __result.setConstant(__result.isConstant() || __rhs.isConstant());
+ __result.setVolatile(__result.isVolatile() || __rhs.isVolatile());
+ __result.setReference(__result.isReference() || __rhs.isReference());
+ __result.setIndirections(__result.indirections() + __rhs.indirections());
+ __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements());
+
+ return __result;
+}
+
+TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope)
+{
+ CodeModel *__model = __scope->model();
+ Q_ASSERT(__model != 0);
+
+ CodeModelItem __item = __model->findItem(__type.qualifiedName(), __scope);
+
+ // Copy the type and replace with the proper qualified name. This
+ // only makes sence to do if we're actually getting a resolved
+ // type with a namespace. We only get this if the returned type
+ // has more than 2 entries in the qualified name... This test
+ // could be improved by returning if the type was found or not.
+ TypeInfo otherType(__type);
+ if (__item && __item->qualifiedName().size() > 1) {
+ otherType.setQualifiedName(__item->qualifiedName());
+ }
+
+ if (TypeAliasModelItem __alias = model_dynamic_cast<TypeAliasModelItem> (__item))
+ return resolveType(TypeInfo::combine(__alias->type(), otherType), __scope);
+
+ return otherType;
+}
+
+QString TypeInfo::toString() const
+{
+ QString tmp;
+
+ tmp += m_qualifiedName.join("::");
+ if (isConstant())
+ tmp += QLatin1String(" const");
+
+ if (isVolatile())
+ tmp += QLatin1String(" volatile");
+
+ if (indirections())
+ tmp += QString(indirections(), QLatin1Char('*'));
+
+ if (isReference())
+ tmp += QLatin1Char('&');
+
+ if (isFunctionPointer()) {
+ tmp += QLatin1String(" (*)(");
+ for (int i = 0; i < m_arguments.count(); ++i) {
+ if (i != 0)
+ tmp += QLatin1String(", ");
+
+ tmp += m_arguments.at(i).toString();
+ }
+ tmp += QLatin1String(")");
+ }
+
+ foreach(QString elt, arrayElements()) {
+ tmp += QLatin1String("[");
+ tmp += elt;
+ tmp += QLatin1String("]");
+ }
+
+ return tmp;
+}
+
+bool TypeInfo::operator==(const TypeInfo &other)
+{
+ if (arrayElements().count() != other.arrayElements().count())
+ return false;
+
+#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break
+ for (int i = 0; i < arrayElements().count(); ++i) {
+ QString elt1 = arrayElements().at(i).trimmed();
+ QString elt2 = other.arrayElements().at(i).trimmed();
+
+ if (elt1 != elt2)
+ return false;
+ }
+#endif
+
+ return flags == other.flags
+ && m_qualifiedName == other.m_qualifiedName
+ && (!m_functionPointer || m_arguments == other.m_arguments);
+}
+
+// ---------------------------------------------------------------------------
+_CodeModelItem::_CodeModelItem(CodeModel *model, int kind)
+ : _M_model(model),
+ _M_kind(kind),
+ _M_startLine(0),
+ _M_startColumn(0),
+ _M_endLine(0),
+ _M_endColumn(0),
+ _M_creation_id(0)
+{
+}
+
+_CodeModelItem::~_CodeModelItem()
+{
+}
+
+CodeModelItem _CodeModelItem::toItem() const
+{
+ return CodeModelItem(const_cast<_CodeModelItem*>(this));
+}
+
+int _CodeModelItem::kind() const
+{
+ return _M_kind;
+}
+
+void _CodeModelItem::setKind(int kind)
+{
+ _M_kind = kind;
+}
+
+QStringList _CodeModelItem::qualifiedName() const
+{
+ QStringList q = scope();
+
+ if (!name().isEmpty())
+ q += name();
+
+ return q;
+}
+
+QString _CodeModelItem::name() const
+{
+ return _M_name;
+}
+
+void _CodeModelItem::setName(const QString &name)
+{
+ _M_name = name;
+}
+
+QStringList _CodeModelItem::scope() const
+{
+ return _M_scope;
+}
+
+void _CodeModelItem::setScope(const QStringList &scope)
+{
+ _M_scope = scope;
+}
+
+QString _CodeModelItem::fileName() const
+{
+ return _M_fileName;
+}
+
+void _CodeModelItem::setFileName(const QString &fileName)
+{
+ _M_fileName = fileName;
+}
+
+FileModelItem _CodeModelItem::file() const
+{
+ return model()->findFile(fileName());
+}
+
+void _CodeModelItem::getStartPosition(int *line, int *column)
+{
+ *line = _M_startLine;
+ *column = _M_startColumn;
+}
+
+void _CodeModelItem::setStartPosition(int line, int column)
+{
+ _M_startLine = line;
+ _M_startColumn = column;
+}
+
+void _CodeModelItem::getEndPosition(int *line, int *column)
+{
+ *line = _M_endLine;
+ *column = _M_endColumn;
+}
+
+void _CodeModelItem::setEndPosition(int line, int column)
+{
+ _M_endLine = line;
+ _M_endColumn = column;
+}
+
+// ---------------------------------------------------------------------------
+QStringList _ClassModelItem::baseClasses() const
+{
+ return _M_baseClasses;
+}
+
+void _ClassModelItem::setBaseClasses(const QStringList &baseClasses)
+{
+ _M_baseClasses = baseClasses;
+}
+
+TemplateParameterList _ClassModelItem::templateParameters() const
+{
+ return _M_templateParameters;
+}
+
+void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
+{
+ _M_templateParameters = templateParameters;
+}
+
+void _ClassModelItem::addBaseClass(const QString &baseClass)
+{
+ _M_baseClasses.append(baseClass);
+}
+
+void _ClassModelItem::removeBaseClass(const QString &baseClass)
+{
+ _M_baseClasses.removeAt(_M_baseClasses.indexOf(baseClass));
+}
+
+bool _ClassModelItem::extendsClass(const QString &name) const
+{
+ return _M_baseClasses.contains(name);
+}
+
+void _ClassModelItem::setClassType(CodeModel::ClassType type)
+{
+ _M_classType = type;
+}
+
+CodeModel::ClassType _ClassModelItem::classType() const
+{
+ return _M_classType;
+}
+
+void _ClassModelItem::addPropertyDeclaration(const QString &propertyDeclaration)
+{
+ _M_propertyDeclarations << propertyDeclaration;
+}
+
+
+// ---------------------------------------------------------------------------
+FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item)
+{
+ FunctionList function_list = findFunctions(item->name());
+
+ foreach(FunctionModelItem fun, function_list) {
+ if (fun->isSimilar(item))
+ return fun;
+ }
+
+ return FunctionModelItem();
+}
+
+ClassList _ScopeModelItem::classes() const
+{
+ return _M_classes.values();
+}
+
+TypeAliasList _ScopeModelItem::typeAliases() const
+{
+ return _M_typeAliases.values();
+}
+
+VariableList _ScopeModelItem::variables() const
+{
+ return _M_variables.values();
+}
+
+FunctionList _ScopeModelItem::functions() const
+{
+ return _M_functions.values();
+}
+
+void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration)
+{
+ _M_enumsDeclarations << enumsDeclaration;
+}
+
+FunctionDefinitionList _ScopeModelItem::functionDefinitions() const
+{
+ return _M_functionDefinitions.values();
+}
+
+EnumList _ScopeModelItem::enums() const
+{
+ return _M_enums.values();
+}
+
+void _ScopeModelItem::addClass(ClassModelItem item)
+{
+ QString name = item->name();
+ int idx = name.indexOf("<");
+ if (idx > 0)
+ _M_classes.insert(name.left(idx), item);
+ _M_classes.insert(name, item);
+}
+
+void _ScopeModelItem::addFunction(FunctionModelItem item)
+{
+ _M_functions.insert(item->name(), item);
+}
+
+void _ScopeModelItem::addFunctionDefinition(FunctionDefinitionModelItem item)
+{
+ _M_functionDefinitions.insert(item->name(), item);
+}
+
+void _ScopeModelItem::addVariable(VariableModelItem item)
+{
+ _M_variables.insert(item->name(), item);
+}
+
+void _ScopeModelItem::addTypeAlias(TypeAliasModelItem item)
+{
+ _M_typeAliases.insert(item->name(), item);
+}
+
+void _ScopeModelItem::addEnum(EnumModelItem item)
+{
+ _M_enums.insert(item->name(), item);
+}
+
+void _ScopeModelItem::removeClass(ClassModelItem item)
+{
+ QHash<QString, ClassModelItem>::Iterator it = _M_classes.find(item->name());
+
+ if (it != _M_classes.end() && it.value() == item)
+ _M_classes.erase(it);
+}
+
+void _ScopeModelItem::removeFunction(FunctionModelItem item)
+{
+ QMultiHash<QString, FunctionModelItem>::Iterator it = _M_functions.find(item->name());
+
+ while (it != _M_functions.end() && it.key() == item->name()
+ && it.value() != item) {
+ ++it;
+ }
+
+ if (it != _M_functions.end() && it.value() == item) {
+ _M_functions.erase(it);
+ }
+}
+
+void _ScopeModelItem::removeFunctionDefinition(FunctionDefinitionModelItem item)
+{
+ QMultiHash<QString, FunctionDefinitionModelItem>::Iterator it = _M_functionDefinitions.find(item->name());
+
+ while (it != _M_functionDefinitions.end() && it.key() == item->name()
+ && it.value() != item) {
+ ++it;
+ }
+
+ if (it != _M_functionDefinitions.end() && it.value() == item) {
+ _M_functionDefinitions.erase(it);
+ }
+}
+
+void _ScopeModelItem::removeVariable(VariableModelItem item)
+{
+ QHash<QString, VariableModelItem>::Iterator it = _M_variables.find(item->name());
+
+ if (it != _M_variables.end() && it.value() == item)
+ _M_variables.erase(it);
+}
+
+void _ScopeModelItem::removeTypeAlias(TypeAliasModelItem item)
+{
+ QHash<QString, TypeAliasModelItem>::Iterator it = _M_typeAliases.find(item->name());
+
+ if (it != _M_typeAliases.end() && it.value() == item)
+ _M_typeAliases.erase(it);
+}
+
+void _ScopeModelItem::removeEnum(EnumModelItem item)
+{
+ QHash<QString, EnumModelItem>::Iterator it = _M_enums.find(item->name());
+
+ if (it != _M_enums.end() && it.value() == item)
+ _M_enums.erase(it);
+}
+
+ClassModelItem _ScopeModelItem::findClass(const QString &name) const
+{
+ return _M_classes.value(name);
+}
+
+VariableModelItem _ScopeModelItem::findVariable(const QString &name) const
+{
+ return _M_variables.value(name);
+}
+
+TypeAliasModelItem _ScopeModelItem::findTypeAlias(const QString &name) const
+{
+ return _M_typeAliases.value(name);
+}
+
+EnumModelItem _ScopeModelItem::findEnum(const QString &name) const
+{
+ return _M_enums.value(name);
+}
+
+FunctionList _ScopeModelItem::findFunctions(const QString &name) const
+{
+ return _M_functions.values(name);
+}
+
+FunctionDefinitionList _ScopeModelItem::findFunctionDefinitions(const QString &name) const
+{
+ return _M_functionDefinitions.values(name);
+}
+
+// ---------------------------------------------------------------------------
+NamespaceList _NamespaceModelItem::namespaces() const
+{
+ return _M_namespaces.values();
+}
+void _NamespaceModelItem::addNamespace(NamespaceModelItem item)
+{
+ _M_namespaces.insert(item->name(), item);
+}
+void _NamespaceModelItem::removeNamespace(NamespaceModelItem item)
+{
+ QHash<QString, NamespaceModelItem>::Iterator it = _M_namespaces.find(item->name());
+
+ if (it != _M_namespaces.end() && it.value() == item)
+ _M_namespaces.erase(it);
+}
+
+NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const
+{
+ return _M_namespaces.value(name);
+}
+
+// ---------------------------------------------------------------------------
+TypeInfo _ArgumentModelItem::type() const
+{
+ return _M_type;
+}
+
+void _ArgumentModelItem::setType(const TypeInfo &type)
+{
+ _M_type = type;
+}
+
+bool _ArgumentModelItem::defaultValue() const
+{
+ return _M_defaultValue;
+}
+
+void _ArgumentModelItem::setDefaultValue(bool defaultValue)
+{
+ _M_defaultValue = defaultValue;
+}
+
+// ---------------------------------------------------------------------------
+bool _FunctionModelItem::isSimilar(FunctionModelItem other) const
+{
+ if (name() != other->name())
+ return false;
+
+ if (isConstant() != other->isConstant())
+ return false;
+
+ if (isVariadics() != other->isVariadics())
+ return false;
+
+ if (arguments().count() != other->arguments().count())
+ return false;
+
+ // ### check the template parameters
+
+ for (int i = 0; i < arguments().count(); ++i) {
+ ArgumentModelItem arg1 = arguments().at(i);
+ ArgumentModelItem arg2 = other->arguments().at(i);
+
+ if (arg1->type() != arg2->type())
+ return false;
+ }
+
+ return true;
+}
+
+ArgumentList _FunctionModelItem::arguments() const
+{
+ return _M_arguments;
+}
+
+void _FunctionModelItem::addArgument(ArgumentModelItem item)
+{
+ _M_arguments.append(item);
+}
+
+void _FunctionModelItem::removeArgument(ArgumentModelItem item)
+{
+ _M_arguments.removeAt(_M_arguments.indexOf(item));
+}
+
+CodeModel::FunctionType _FunctionModelItem::functionType() const
+{
+ return _M_functionType;
+}
+
+void _FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType)
+{
+ _M_functionType = functionType;
+}
+
+bool _FunctionModelItem::isVariadics() const
+{
+ return _M_isVariadics;
+}
+
+void _FunctionModelItem::setVariadics(bool isVariadics)
+{
+ _M_isVariadics = isVariadics;
+}
+
+bool _FunctionModelItem::isVirtual() const
+{
+ return _M_isVirtual;
+}
+
+void _FunctionModelItem::setVirtual(bool isVirtual)
+{
+ _M_isVirtual = isVirtual;
+}
+
+bool _FunctionModelItem::isInline() const
+{
+ return _M_isInline;
+}
+
+void _FunctionModelItem::setInline(bool isInline)
+{
+ _M_isInline = isInline;
+}
+
+bool _FunctionModelItem::isExplicit() const
+{
+ return _M_isExplicit;
+}
+
+void _FunctionModelItem::setExplicit(bool isExplicit)
+{
+ _M_isExplicit = isExplicit;
+}
+
+bool _FunctionModelItem::isAbstract() const
+{
+ return _M_isAbstract;
+}
+
+void _FunctionModelItem::setAbstract(bool isAbstract)
+{
+ _M_isAbstract = isAbstract;
+}
+
+// Qt
+bool _FunctionModelItem::isInvokable() const
+{
+ return _M_isInvokable;
+}
+
+void _FunctionModelItem::setInvokable(bool isInvokable)
+{
+ _M_isInvokable = isInvokable;
+}
+
+// ---------------------------------------------------------------------------
+TypeInfo _TypeAliasModelItem::type() const
+{
+ return _M_type;
+}
+
+void _TypeAliasModelItem::setType(const TypeInfo &type)
+{
+ _M_type = type;
+}
+
+// ---------------------------------------------------------------------------
+CodeModel::AccessPolicy _EnumModelItem::accessPolicy() const
+{
+ return _M_accessPolicy;
+}
+
+void _EnumModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ _M_accessPolicy = accessPolicy;
+}
+
+EnumeratorList _EnumModelItem::enumerators() const
+{
+ return _M_enumerators;
+}
+
+void _EnumModelItem::addEnumerator(EnumeratorModelItem item)
+{
+ _M_enumerators.append(item);
+}
+
+void _EnumModelItem::removeEnumerator(EnumeratorModelItem item)
+{
+ _M_enumerators.removeAt(_M_enumerators.indexOf(item));
+}
+
+// ---------------------------------------------------------------------------
+QString _EnumeratorModelItem::value() const
+{
+ return _M_value;
+}
+
+void _EnumeratorModelItem::setValue(const QString &value)
+{
+ _M_value = value;
+}
+
+// ---------------------------------------------------------------------------
+TypeInfo _TemplateParameterModelItem::type() const
+{
+ return _M_type;
+}
+
+void _TemplateParameterModelItem::setType(const TypeInfo &type)
+{
+ _M_type = type;
+}
+
+bool _TemplateParameterModelItem::defaultValue() const
+{
+ return _M_defaultValue;
+}
+
+void _TemplateParameterModelItem::setDefaultValue(bool defaultValue)
+{
+ _M_defaultValue = defaultValue;
+}
+
+// ---------------------------------------------------------------------------
+ScopeModelItem _ScopeModelItem::create(CodeModel *model)
+{
+ ScopeModelItem item(new _ScopeModelItem(model));
+ return item;
+}
+
+ClassModelItem _ClassModelItem::create(CodeModel *model)
+{
+ ClassModelItem item(new _ClassModelItem(model));
+ return item;
+}
+
+NamespaceModelItem _NamespaceModelItem::create(CodeModel *model)
+{
+ NamespaceModelItem item(new _NamespaceModelItem(model));
+ return item;
+}
+
+FileModelItem _FileModelItem::create(CodeModel *model)
+{
+ FileModelItem item(new _FileModelItem(model));
+ return item;
+}
+
+ArgumentModelItem _ArgumentModelItem::create(CodeModel *model)
+{
+ ArgumentModelItem item(new _ArgumentModelItem(model));
+ return item;
+}
+
+FunctionModelItem _FunctionModelItem::create(CodeModel *model)
+{
+ FunctionModelItem item(new _FunctionModelItem(model));
+ return item;
+}
+
+FunctionDefinitionModelItem _FunctionDefinitionModelItem::create(CodeModel *model)
+{
+ FunctionDefinitionModelItem item(new _FunctionDefinitionModelItem(model));
+ return item;
+}
+
+VariableModelItem _VariableModelItem::create(CodeModel *model)
+{
+ VariableModelItem item(new _VariableModelItem(model));
+ return item;
+}
+
+TypeAliasModelItem _TypeAliasModelItem::create(CodeModel *model)
+{
+ TypeAliasModelItem item(new _TypeAliasModelItem(model));
+ return item;
+}
+
+EnumModelItem _EnumModelItem::create(CodeModel *model)
+{
+ EnumModelItem item(new _EnumModelItem(model));
+ return item;
+}
+
+EnumeratorModelItem _EnumeratorModelItem::create(CodeModel *model)
+{
+ EnumeratorModelItem item(new _EnumeratorModelItem(model));
+ return item;
+}
+
+TemplateParameterModelItem _TemplateParameterModelItem::create(CodeModel *model)
+{
+ TemplateParameterModelItem item(new _TemplateParameterModelItem(model));
+ return item;
+}
+
+// ---------------------------------------------------------------------------
+TypeInfo _MemberModelItem::type() const
+{
+ return _M_type;
+}
+
+void _MemberModelItem::setType(const TypeInfo &type)
+{
+ _M_type = type;
+}
+
+CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const
+{
+ return _M_accessPolicy;
+}
+
+void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ _M_accessPolicy = accessPolicy;
+}
+
+bool _MemberModelItem::isStatic() const
+{
+ return _M_isStatic;
+}
+
+void _MemberModelItem::setStatic(bool isStatic)
+{
+ _M_isStatic = isStatic;
+}
+
+bool _MemberModelItem::isConstant() const
+{
+ return _M_isConstant;
+}
+
+void _MemberModelItem::setConstant(bool isConstant)
+{
+ _M_isConstant = isConstant;
+}
+
+bool _MemberModelItem::isVolatile() const
+{
+ return _M_isVolatile;
+}
+
+void _MemberModelItem::setVolatile(bool isVolatile)
+{
+ _M_isVolatile = isVolatile;
+}
+
+bool _MemberModelItem::isAuto() const
+{
+ return _M_isAuto;
+}
+
+void _MemberModelItem::setAuto(bool isAuto)
+{
+ _M_isAuto = isAuto;
+}
+
+bool _MemberModelItem::isFriend() const
+{
+ return _M_isFriend;
+}
+
+void _MemberModelItem::setFriend(bool isFriend)
+{
+ _M_isFriend = isFriend;
+}
+
+bool _MemberModelItem::isRegister() const
+{
+ return _M_isRegister;
+}
+
+void _MemberModelItem::setRegister(bool isRegister)
+{
+ _M_isRegister = isRegister;
+}
+
+bool _MemberModelItem::isExtern() const
+{
+ return _M_isExtern;
+}
+
+void _MemberModelItem::setExtern(bool isExtern)
+{
+ _M_isExtern = isExtern;
+}
+
+bool _MemberModelItem::isMutable() const
+{
+ return _M_isMutable;
+}
+
+void _MemberModelItem::setMutable(bool isMutable)
+{
+ _M_isMutable = isMutable;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/codemodel.h b/parser/codemodel.h
new file mode 100644
index 000000000..3ea94480f
--- /dev/null
+++ b/parser/codemodel.h
@@ -0,0 +1,838 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef CODEMODEL_H
+#define CODEMODEL_H
+
+#include "codemodel_fwd.h"
+#include "codemodel_pointer.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+#define DECLARE_MODEL_NODE(k) \
+ enum { __node_kind = Kind_##k }; \
+ typedef CodeModelPointer<k##ModelItem> Pointer;
+
+template <class _Target, class _Source>
+_Target model_static_cast(_Source item)
+{
+ typedef typename _Target::Type * _Target_pointer;
+
+ _Target ptr(static_cast<_Target_pointer>(item.data()));
+ return ptr;
+}
+
+class CodeModel
+{
+public:
+ enum AccessPolicy {
+ Public,
+ Protected,
+ Private
+ };
+
+ enum FunctionType {
+ Normal,
+ Signal,
+ Slot
+ };
+
+ enum ClassType {
+ Class,
+ Struct,
+ Union
+ };
+
+public:
+ CodeModel();
+ virtual ~CodeModel();
+
+ template <class _Target> _Target create()
+ {
+ typedef typename _Target::Type _Target_type;
+
+ _Target result = _Target_type::create(this);
+ result->setCreationId(_M_creation_id++);
+ return result;
+ }
+
+ FileList files() const;
+ NamespaceModelItem globalNamespace() const;
+
+ void addFile(FileModelItem item);
+ void removeFile(FileModelItem item);
+ FileModelItem findFile(const QString &name) const;
+ QHash<QString, FileModelItem> fileMap() const;
+
+ CodeModelItem findItem(const QStringList &qualifiedName, CodeModelItem scope) const;
+
+ void wipeout();
+
+private:
+ QHash<QString, FileModelItem> _M_files;
+ NamespaceModelItem _M_globalNamespace;
+ std::size_t _M_creation_id;
+
+private:
+ CodeModel(const CodeModel &other);
+ void operator = (const CodeModel &other);
+};
+
+class TypeInfo
+{
+public:
+ TypeInfo(const TypeInfo &other)
+ : flags(other.flags),
+ m_qualifiedName(other.m_qualifiedName),
+ m_arrayElements(other.m_arrayElements),
+ m_arguments(other.m_arguments)
+ {}
+
+ TypeInfo():
+ flags(0) {}
+
+ QStringList qualifiedName() const
+ {
+ return m_qualifiedName;
+ }
+
+ void setQualifiedName(const QStringList &qualified_name)
+ {
+ m_qualifiedName = qualified_name;
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+
+ void setConstant(bool is)
+ {
+ m_constant = is;
+ }
+
+ bool isVolatile() const
+ {
+ return m_volatile;
+ }
+
+ void setVolatile(bool is)
+ {
+ m_volatile = is;
+ }
+
+ bool isReference() const
+ {
+ return m_reference;
+ }
+
+ void setReference(bool is)
+ {
+ m_reference = is;
+ }
+
+ int indirections() const
+ {
+ return m_indirections;
+ }
+
+ void setIndirections(int indirections)
+ {
+ m_indirections = indirections;
+ }
+
+ bool isFunctionPointer() const
+ {
+ return m_functionPointer;
+ }
+ void setFunctionPointer(bool is)
+ {
+ m_functionPointer = is;
+ }
+
+ QStringList arrayElements() const
+ {
+ return m_arrayElements;
+ }
+ void setArrayElements(const QStringList &arrayElements)
+ {
+ m_arrayElements = arrayElements;
+ }
+
+ QList<TypeInfo> arguments() const
+ {
+ return m_arguments;
+ }
+
+ void setArguments(const QList<TypeInfo> &arguments);
+
+ void addArgument(const TypeInfo &arg)
+ {
+ m_arguments.append(arg);
+ }
+
+ bool operator==(const TypeInfo &other);
+
+ bool operator!=(const TypeInfo &other)
+ {
+ return !(*this == other);
+ }
+
+ // ### arrays and templates??
+
+ QString toString() const;
+
+ static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs);
+ static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope);
+
+private:
+ union {
+ uint flags;
+
+ struct {
+ uint m_constant: 1;
+ uint m_volatile: 1;
+ uint m_reference: 1;
+ uint m_functionPointer: 1;
+ uint m_indirections: 6;
+ uint m_padding: 22;
+ };
+ };
+
+ QStringList m_qualifiedName;
+ QStringList m_arrayElements;
+ QList<TypeInfo> m_arguments;
+};
+
+class _CodeModelItem: public QSharedData
+{
+public:
+ enum Kind {
+ /* These are bit-flags resembling inheritance */
+ Kind_Scope = 0x1,
+ Kind_Namespace = 0x2 | Kind_Scope,
+ Kind_Member = 0x4,
+ Kind_Function = 0x8 | Kind_Member,
+ KindMask = 0xf,
+
+ /* These are for classes that are not inherited from */
+ FirstKind = 0x8,
+ Kind_Argument = 1 << FirstKind,
+ Kind_Class = 2 << FirstKind | Kind_Scope,
+ Kind_Enum = 3 << FirstKind,
+ Kind_Enumerator = 4 << FirstKind,
+ Kind_File = 5 << FirstKind | Kind_Namespace,
+ Kind_FunctionDefinition = 6 << FirstKind | Kind_Function,
+ Kind_TemplateParameter = 7 << FirstKind,
+ Kind_TypeAlias = 8 << FirstKind,
+ Kind_Variable = 9 << FirstKind | Kind_Member
+ };
+
+public:
+ virtual ~_CodeModelItem();
+
+ int kind() const;
+
+ QStringList qualifiedName() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QStringList scope() const;
+ void setScope(const QStringList &scope);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ FileModelItem file() const;
+
+ void getStartPosition(int *line, int *column);
+ void setStartPosition(int line, int column);
+
+ void getEndPosition(int *line, int *column);
+ void setEndPosition(int line, int column);
+
+ inline std::size_t creationId() const
+ {
+ return _M_creation_id;
+ }
+
+ inline void setCreationId(std::size_t creation_id)
+ {
+ _M_creation_id = creation_id;
+ }
+
+ inline CodeModel *model() const
+ {
+ return _M_model;
+ }
+
+ CodeModelItem toItem() const;
+
+protected:
+ _CodeModelItem(CodeModel *model, int kind);
+ void setKind(int kind);
+
+private:
+ CodeModel *_M_model;
+ int _M_kind;
+ int _M_startLine;
+ int _M_startColumn;
+ int _M_endLine;
+ int _M_endColumn;
+ std::size_t _M_creation_id;
+ QString _M_name;
+ QString _M_fileName;
+ QStringList _M_scope;
+
+private:
+ _CodeModelItem(const _CodeModelItem &other);
+ void operator = (const _CodeModelItem &other);
+};
+
+class _ScopeModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Scope)
+
+ static ScopeModelItem create(CodeModel *model);
+
+public:
+ ClassList classes() const;
+ EnumList enums() const;
+ FunctionDefinitionList functionDefinitions() const;
+ FunctionList functions() const;
+ TypeAliasList typeAliases() const;
+ VariableList variables() const;
+
+ void addClass(ClassModelItem item);
+ void addEnum(EnumModelItem item);
+ void addFunction(FunctionModelItem item);
+ void addFunctionDefinition(FunctionDefinitionModelItem item);
+ void addTypeAlias(TypeAliasModelItem item);
+ void addVariable(VariableModelItem item);
+
+ void removeClass(ClassModelItem item);
+ void removeEnum(EnumModelItem item);
+ void removeFunction(FunctionModelItem item);
+ void removeFunctionDefinition(FunctionDefinitionModelItem item);
+ void removeTypeAlias(TypeAliasModelItem item);
+ void removeVariable(VariableModelItem item);
+
+ ClassModelItem findClass(const QString &name) const;
+ EnumModelItem findEnum(const QString &name) const;
+ FunctionDefinitionList findFunctionDefinitions(const QString &name) const;
+ FunctionList findFunctions(const QString &name) const;
+ TypeAliasModelItem findTypeAlias(const QString &name) const;
+ VariableModelItem findVariable(const QString &name) const;
+
+ void addEnumsDeclaration(const QString &enumsDeclaration);
+ QStringList enumsDeclarations() const
+ {
+ return _M_enumsDeclarations;
+ }
+
+ inline QHash<QString, ClassModelItem> classMap() const
+ {
+ return _M_classes;
+ }
+ inline QHash<QString, EnumModelItem> enumMap() const
+ {
+ return _M_enums;
+ }
+ inline QHash<QString, TypeAliasModelItem> typeAliasMap() const
+ {
+ return _M_typeAliases;
+ }
+ inline QHash<QString, VariableModelItem> variableMap() const
+ {
+ return _M_variables;
+ }
+ inline QMultiHash<QString, FunctionDefinitionModelItem> functionDefinitionMap() const
+ {
+ return _M_functionDefinitions;
+ }
+ inline QMultiHash<QString, FunctionModelItem> functionMap() const
+ {
+ return _M_functions;
+ }
+
+ FunctionModelItem declaredFunction(FunctionModelItem item);
+
+protected:
+ _ScopeModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+
+private:
+ QHash<QString, ClassModelItem> _M_classes;
+ QHash<QString, EnumModelItem> _M_enums;
+ QHash<QString, TypeAliasModelItem> _M_typeAliases;
+ QHash<QString, VariableModelItem> _M_variables;
+ QMultiHash<QString, FunctionDefinitionModelItem> _M_functionDefinitions;
+ QMultiHash<QString, FunctionModelItem> _M_functions;
+
+private:
+ _ScopeModelItem(const _ScopeModelItem &other);
+ void operator = (const _ScopeModelItem &other);
+
+ QStringList _M_enumsDeclarations;
+};
+
+class _ClassModelItem: public _ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Class)
+
+ static ClassModelItem create(CodeModel *model);
+
+public:
+ QStringList baseClasses() const;
+
+ void setBaseClasses(const QStringList &baseClasses);
+ void addBaseClass(const QString &baseClass);
+ void removeBaseClass(const QString &baseClass);
+
+ TemplateParameterList templateParameters() const;
+ void setTemplateParameters(const TemplateParameterList &templateParameters);
+
+ bool extendsClass(const QString &name) const;
+
+ void setClassType(CodeModel::ClassType type);
+ CodeModel::ClassType classType() const;
+
+ void addPropertyDeclaration(const QString &propertyDeclaration);
+ QStringList propertyDeclarations() const
+ {
+ return _M_propertyDeclarations;
+ }
+
+protected:
+ _ClassModelItem(CodeModel *model, int kind = __node_kind)
+ : _ScopeModelItem(model, kind), _M_classType(CodeModel::Class) {}
+
+private:
+ QStringList _M_baseClasses;
+ TemplateParameterList _M_templateParameters;
+ CodeModel::ClassType _M_classType;
+
+ QStringList _M_propertyDeclarations;
+
+private:
+ _ClassModelItem(const _ClassModelItem &other);
+ void operator = (const _ClassModelItem &other);
+};
+
+class _NamespaceModelItem: public _ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Namespace)
+
+ static NamespaceModelItem create(CodeModel *model);
+
+public:
+ NamespaceList namespaces() const;
+
+ void addNamespace(NamespaceModelItem item);
+ void removeNamespace(NamespaceModelItem item);
+
+ NamespaceModelItem findNamespace(const QString &name) const;
+
+ inline QHash<QString, NamespaceModelItem> namespaceMap() const
+ {
+ return _M_namespaces;
+ };
+
+protected:
+ _NamespaceModelItem(CodeModel *model, int kind = __node_kind)
+ : _ScopeModelItem(model, kind) {}
+
+private:
+ QHash<QString, NamespaceModelItem> _M_namespaces;
+
+private:
+ _NamespaceModelItem(const _NamespaceModelItem &other);
+ void operator = (const _NamespaceModelItem &other);
+};
+
+class _FileModelItem: public _NamespaceModelItem
+{
+public:
+ DECLARE_MODEL_NODE(File)
+
+ static FileModelItem create(CodeModel *model);
+
+protected:
+ _FileModelItem(CodeModel *model, int kind = __node_kind)
+ : _NamespaceModelItem(model, kind) {}
+
+private:
+ _FileModelItem(const _FileModelItem &other);
+ void operator = (const _FileModelItem &other);
+};
+
+class _ArgumentModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Argument)
+
+ static ArgumentModelItem create(CodeModel *model);
+
+public:
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+ QString defaultValueExpression() const
+ {
+ return _M_defaultValueExpression;
+ }
+
+ void setDefaultValueExpression(const QString &expr)
+ {
+ _M_defaultValueExpression = expr;
+ }
+
+protected:
+ _ArgumentModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), _M_defaultValue(false) {}
+
+private:
+ TypeInfo _M_type;
+ QString _M_defaultValueExpression;
+ bool _M_defaultValue;
+
+private:
+ _ArgumentModelItem(const _ArgumentModelItem &other);
+ void operator = (const _ArgumentModelItem &other);
+};
+
+class _MemberModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Member)
+
+ bool isConstant() const;
+ void setConstant(bool isConstant);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isAuto() const;
+ void setAuto(bool isAuto);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ TemplateParameterList templateParameters() const
+ {
+ return _M_templateParameters;
+ }
+
+ void setTemplateParameters(const TemplateParameterList &templateParameters)
+ {
+ _M_templateParameters = templateParameters;
+ }
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+protected:
+ _MemberModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind),
+ _M_accessPolicy(CodeModel::Public),
+ _M_flags(0) {}
+
+private:
+ TemplateParameterList _M_templateParameters;
+ TypeInfo _M_type;
+ CodeModel::AccessPolicy _M_accessPolicy;
+ union {
+ struct {
+ uint _M_isConstant: 1;
+ uint _M_isVolatile: 1;
+ uint _M_isStatic: 1;
+ uint _M_isAuto: 1;
+ uint _M_isFriend: 1;
+ uint _M_isRegister: 1;
+ uint _M_isExtern: 1;
+ uint _M_isMutable: 1;
+ };
+ uint _M_flags;
+ };
+
+};
+
+class _FunctionModelItem: public _MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Function)
+
+ static FunctionModelItem create(CodeModel *model);
+
+public:
+ ArgumentList arguments() const;
+
+ void addArgument(ArgumentModelItem item);
+ void removeArgument(ArgumentModelItem item);
+
+ CodeModel::FunctionType functionType() const;
+ void setFunctionType(CodeModel::FunctionType functionType);
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool isInvokable() const; // Qt
+ void setInvokable(bool isInvokable); // Qt
+
+ bool isAbstract() const;
+ void setAbstract(bool isAbstract);
+
+ bool isVariadics() const;
+ void setVariadics(bool isVariadics);
+
+ bool isSimilar(FunctionModelItem other) const;
+
+protected:
+ _FunctionModelItem(CodeModel *model, int kind = __node_kind)
+ : _MemberModelItem(model, kind),
+ _M_functionType(CodeModel::Normal),
+ _M_flags(0) {}
+
+private:
+ ArgumentList _M_arguments;
+ CodeModel::FunctionType _M_functionType;
+ union {
+ struct {
+ uint _M_isVirtual: 1;
+ uint _M_isInline: 1;
+ uint _M_isAbstract: 1;
+ uint _M_isExplicit: 1;
+ uint _M_isVariadics: 1;
+ uint _M_isInvokable : 1; // Qt
+ };
+ uint _M_flags;
+ };
+
+private:
+ _FunctionModelItem(const _FunctionModelItem &other);
+ void operator = (const _FunctionModelItem &other);
+};
+
+class _FunctionDefinitionModelItem: public _FunctionModelItem
+{
+public:
+ DECLARE_MODEL_NODE(FunctionDefinition)
+
+ static FunctionDefinitionModelItem create(CodeModel *model);
+
+protected:
+ _FunctionDefinitionModelItem(CodeModel *model, int kind = __node_kind)
+ : _FunctionModelItem(model, kind) {}
+
+private:
+ _FunctionDefinitionModelItem(const _FunctionDefinitionModelItem &other);
+ void operator = (const _FunctionDefinitionModelItem &other);
+};
+
+class _VariableModelItem: public _MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Variable)
+
+ static VariableModelItem create(CodeModel *model);
+
+protected:
+ _VariableModelItem(CodeModel *model, int kind = __node_kind)
+ : _MemberModelItem(model, kind) {}
+
+private:
+ _VariableModelItem(const _VariableModelItem &other);
+ void operator = (const _VariableModelItem &other);
+};
+
+class _TypeAliasModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TypeAlias)
+
+ static TypeAliasModelItem create(CodeModel *model);
+
+public:
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+protected:
+ _TypeAliasModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+
+private:
+ TypeInfo _M_type;
+
+private:
+ _TypeAliasModelItem(const _TypeAliasModelItem &other);
+ void operator = (const _TypeAliasModelItem &other);
+};
+
+class _EnumModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enum)
+
+ static EnumModelItem create(CodeModel *model);
+
+public:
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ EnumeratorList enumerators() const;
+ void addEnumerator(EnumeratorModelItem item);
+ void removeEnumerator(EnumeratorModelItem item);
+
+protected:
+ _EnumModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind),
+ _M_accessPolicy(CodeModel::Public) {}
+
+private:
+ CodeModel::AccessPolicy _M_accessPolicy;
+ EnumeratorList _M_enumerators;
+
+private:
+ _EnumModelItem(const _EnumModelItem &other);
+ void operator = (const _EnumModelItem &other);
+};
+
+class _EnumeratorModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enumerator)
+
+ static EnumeratorModelItem create(CodeModel *model);
+
+public:
+ QString value() const;
+ void setValue(const QString &value);
+
+protected:
+ _EnumeratorModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+
+private:
+ QString _M_value;
+
+private:
+ _EnumeratorModelItem(const _EnumeratorModelItem &other);
+ void operator = (const _EnumeratorModelItem &other);
+};
+
+class _TemplateParameterModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TemplateParameter)
+
+ static TemplateParameterModelItem create(CodeModel *model);
+
+public:
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+protected:
+ _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), _M_defaultValue(false) {}
+
+private:
+ TypeInfo _M_type;
+ bool _M_defaultValue;
+
+private:
+ _TemplateParameterModelItem(const _TemplateParameterModelItem &other);
+ void operator = (const _TemplateParameterModelItem &other);
+};
+
+template <class _Target, class _Source>
+_Target model_safe_cast(_Source item)
+{
+ typedef typename _Target::Type * _Target_pointer;
+ typedef typename _Source::Type * _Source_pointer;
+
+ _Source_pointer source = item.data();
+ if (source && source->kind() == _Target_pointer(0)->__node_kind) {
+ _Target ptr(static_cast<_Target_pointer>(source));
+ return ptr;
+ }
+
+ return _Target();
+}
+
+template <typename _Target, typename _Source>
+_Target model_dynamic_cast(_Source item)
+{
+ typedef typename _Target::Type * _Target_pointer;
+ typedef typename _Source::Type * _Source_pointer;
+
+ _Source_pointer source = item.data();
+ if (source && (source->kind() == _Target_pointer(0)->__node_kind
+ || (int(_Target_pointer(0)->__node_kind) <= int(_CodeModelItem::KindMask)
+ && ((source->kind() & _Target_pointer(0)->__node_kind)
+ == _Target_pointer(0)->__node_kind)))) {
+ _Target ptr(static_cast<_Target_pointer>(source));
+ return ptr;
+ }
+
+ return _Target();
+}
+#endif // CODEMODEL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/codemodel_finder.cpp b/parser/codemodel_finder.cpp
new file mode 100644
index 000000000..866ea1cbd
--- /dev/null
+++ b/parser/codemodel_finder.cpp
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "codemodel_finder.h"
+#include "codemodel.h"
+#include "binder.h"
+
+CodeModelFinder::CodeModelFinder(CodeModel *model, Binder *binder)
+ : _M_model(model),
+ _M_binder(binder),
+ _M_token_stream(binder->tokenStream()),
+ name_cc(_M_binder),
+ _M_resolve_policy(ResolveItem)
+{
+}
+
+CodeModelFinder::~CodeModelFinder()
+{
+}
+
+ScopeModelItem CodeModelFinder::resolveScope(NameAST *name, ScopeModelItem scope)
+{
+ Q_ASSERT(scope);
+
+ ResolvePolicy saved_resolve_policy = _M_resolve_policy;
+ _M_resolve_policy = ResolveScope;
+
+ ScopeModelItem old = changeCurrentScope(scope);
+
+ visit(name);
+ ScopeModelItem result = _M_current_scope;
+
+ changeCurrentScope(old); // restore
+
+ _M_resolve_policy = saved_resolve_policy;
+
+ return result;
+}
+
+ScopeModelItem CodeModelFinder::changeCurrentScope(ScopeModelItem scope)
+{
+ ScopeModelItem old = _M_current_scope;
+ _M_current_scope = scope;
+ return old;
+}
+
+void CodeModelFinder::visitName(NameAST *node)
+{
+ visitNodes(this, node->qualified_names);
+
+ if (_M_resolve_policy == ResolveItem)
+ visit(node->unqualified_name);
+}
+
+void CodeModelFinder::visitUnqualifiedName(UnqualifiedNameAST *node)
+{
+ if (!_M_current_scope) {
+ // nothing to do
+ return;
+ }
+
+ name_cc.run(node);
+ QString id = name_cc.name();
+
+ if (ClassModelItem klass = _M_current_scope->findClass(id)) {
+ _M_current_scope = klass;
+ } else if (NamespaceModelItem parentNamespace = model_safe_cast<NamespaceModelItem>(_M_current_scope)) {
+ NamespaceModelItem ns = parentNamespace->findNamespace(id);
+ _M_current_scope = model_static_cast<ScopeModelItem>(ns);
+ } else if (FileModelItem file = model_safe_cast<FileModelItem>(_M_current_scope)) {
+ NamespaceModelItem ns = file->findNamespace(id);
+ _M_current_scope = model_static_cast<ScopeModelItem>(ns);
+ }
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/codemodel_finder.h b/parser/codemodel_finder.h
new file mode 100644
index 000000000..ac1b5b0eb
--- /dev/null
+++ b/parser/codemodel_finder.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef CODEMODEL_FINDER_H
+#define CODEMODEL_FINDER_H
+
+#include <default_visitor.h>
+#include <codemodel_fwd.h>
+#include <name_compiler.h>
+
+class TokenStream;
+class Binder;
+
+class CodeModelFinder: protected DefaultVisitor
+{
+ enum ResolvePolicy {
+ ResolveScope,
+ ResolveItem
+ };
+
+public:
+ CodeModelFinder(CodeModel *model, Binder *binder);
+ virtual ~CodeModelFinder();
+
+ ScopeModelItem resolveScope(NameAST *name, ScopeModelItem scope);
+
+ inline CodeModel *model() const
+ {
+ return _M_model;
+ }
+
+protected:
+ virtual void visitName(NameAST *node);
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *node);
+
+ ScopeModelItem changeCurrentScope(ScopeModelItem scope);
+
+private:
+ CodeModel *_M_model;
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ NameCompiler name_cc;
+
+ ScopeModelItem _M_current_scope;
+ ResolvePolicy _M_resolve_policy;
+};
+
+#endif // CODEMODEL_FINDER_H
diff --git a/parser/codemodel_fwd.h b/parser/codemodel_fwd.h
new file mode 100644
index 000000000..96405909c
--- /dev/null
+++ b/parser/codemodel_fwd.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef CODEMODEL_FWD_H
+#define CODEMODEL_FWD_H
+
+#include "codemodel_pointer.h"
+#include <QtCore/QList>
+
+// forward declarations
+class CodeModel;
+class _ArgumentModelItem;
+class _ClassModelItem;
+class _CodeModelItem;
+class _EnumModelItem;
+class _EnumeratorModelItem;
+class _FileModelItem;
+class _FunctionDefinitionModelItem;
+class _FunctionModelItem;
+class _NamespaceModelItem;
+class _ScopeModelItem;
+class _TemplateParameterModelItem;
+class _TypeAliasModelItem;
+class _VariableModelItem;
+class _MemberModelItem;
+class TypeInfo;
+
+typedef CodeModelPointer<_ArgumentModelItem> ArgumentModelItem;
+typedef CodeModelPointer<_ClassModelItem> ClassModelItem;
+typedef CodeModelPointer<_CodeModelItem> CodeModelItem;
+typedef CodeModelPointer<_EnumModelItem> EnumModelItem;
+typedef CodeModelPointer<_EnumeratorModelItem> EnumeratorModelItem;
+typedef CodeModelPointer<_FileModelItem> FileModelItem;
+typedef CodeModelPointer<_FunctionDefinitionModelItem> FunctionDefinitionModelItem;
+typedef CodeModelPointer<_FunctionModelItem> FunctionModelItem;
+typedef CodeModelPointer<_NamespaceModelItem> NamespaceModelItem;
+typedef CodeModelPointer<_ScopeModelItem> ScopeModelItem;
+typedef CodeModelPointer<_TemplateParameterModelItem> TemplateParameterModelItem;
+typedef CodeModelPointer<_TypeAliasModelItem> TypeAliasModelItem;
+typedef CodeModelPointer<_VariableModelItem> VariableModelItem;
+typedef CodeModelPointer<_MemberModelItem> MemberModelItem;
+
+typedef QList<ArgumentModelItem> ArgumentList;
+typedef QList<ClassModelItem> ClassList;
+typedef QList<CodeModelItem> ItemList;
+typedef QList<EnumModelItem> EnumList;
+typedef QList<EnumeratorModelItem> EnumeratorList;
+typedef QList<FileModelItem> FileList;
+typedef QList<FunctionDefinitionModelItem> FunctionDefinitionList;
+typedef QList<FunctionModelItem> FunctionList;
+typedef QList<NamespaceModelItem> NamespaceList;
+typedef QList<ScopeModelItem> ScopeList;
+typedef QList<TemplateParameterModelItem> TemplateParameterList;
+typedef QList<TypeAliasModelItem> TypeAliasList;
+typedef QList<VariableModelItem> VariableList;
+typedef QList<MemberModelItem> MemberList;
+
+#endif // CODEMODEL_FWD_H
diff --git a/parser/codemodel_pointer.h b/parser/codemodel_pointer.h
new file mode 100644
index 000000000..2c728f3c5
--- /dev/null
+++ b/parser/codemodel_pointer.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2006 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef CODEMODEL_POINTER_H
+#define CODEMODEL_POINTER_H
+
+#include <QtCore/QSharedData>
+#include <QAtomicPointer>
+
+template <class T> class CodeModelPointer : public QAtomicPointer<T>
+{
+public:
+ typedef T Type;
+
+ inline CodeModelPointer(T *value = 0) : QAtomicPointer<T>(value) {}
+
+ inline CodeModelPointer &operator=(T *o)
+ {
+ QAtomicPointer<T>::operator=(o);
+ return *this;
+ }
+
+ inline T *data()
+ {
+ return (T *) *this;
+ }
+
+ inline const T *data() const
+ {
+ return (const T *) *this;
+ }
+
+ inline const T *constData() const
+ {
+ return (const T *) *this;
+ }
+};
+
+#endif // CODEMODEL_POINTER_H
diff --git a/parser/compiler_utils.cpp b/parser/compiler_utils.cpp
new file mode 100644
index 000000000..49624149a
--- /dev/null
+++ b/parser/compiler_utils.cpp
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "compiler_utils.h"
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "declarator_compiler.h"
+#include "ast.h"
+#include "binder.h"
+
+TypeInfo CompilerUtils::typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder)
+{
+ TypeCompiler type_cc(binder);
+ DeclaratorCompiler decl_cc(binder);
+
+ type_cc.run(type_specifier);
+ decl_cc.run(declarator);
+
+ TypeInfo typeInfo;
+ typeInfo.setQualifiedName(type_cc.qualifiedName());
+ typeInfo.setConstant(type_cc.isConstant());
+ typeInfo.setVolatile(type_cc.isVolatile());
+ typeInfo.setReference(decl_cc.isReference());
+ typeInfo.setIndirections(decl_cc.indirection());
+ typeInfo.setArrayElements(decl_cc.arrayElements());
+
+ return typeInfo;
+}
diff --git a/parser/compiler_utils.h b/parser/compiler_utils.h
new file mode 100644
index 000000000..fdd96f15b
--- /dev/null
+++ b/parser/compiler_utils.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef COMPILER_UTILS_H
+#define COMPILER_UTILS_H
+
+#include <utility>
+
+#include "codemodel.h"
+
+class QString;
+class QStringList;
+struct TypeSpecifierAST;
+struct DeclaratorAST;
+class TokenStream;
+class Binder;
+
+namespace CompilerUtils
+{
+
+TypeInfo typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder);
+
+} // namespace CompilerUtils
+
+#endif // COMPILER_UTILS_H
diff --git a/parser/control.cpp b/parser/control.cpp
new file mode 100644
index 000000000..9615debba
--- /dev/null
+++ b/parser/control.cpp
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "control.h"
+#include "lexer.h"
+
+Control::Control()
+ : current_context(0),
+ _M_skipFunctionBody(false),
+ _M_lexer(0),
+ _M_parser(0)
+{
+ pushContext();
+
+ declareTypedef(findOrInsertName("__builtin_va_list",
+ strlen("__builtin_va_list")), 0);
+}
+
+Control::~Control()
+{
+ popContext();
+
+ Q_ASSERT(current_context == 0);
+}
+
+Lexer *Control::changeLexer(Lexer *lexer)
+{
+ Lexer *old = _M_lexer;
+ _M_lexer = lexer;
+ return old;
+}
+
+Parser *Control::changeParser(Parser *parser)
+{
+ Parser *old = _M_parser;
+ _M_parser = parser;
+ return old;
+}
+
+Type *Control::lookupType(const NameSymbol *name) const
+{
+ Q_ASSERT(current_context != 0);
+
+ return current_context->resolve(name);
+}
+
+void Control::declare(const NameSymbol *name, Type *type)
+{
+ //printf("*** Declare:");
+ //printSymbol(name);
+ //putchar('\n');
+ Q_ASSERT(current_context != 0);
+
+ current_context->bind(name, type);
+}
+
+void Control::pushContext()
+{
+ // printf("+Context\n");
+ Context *new_context = new Context;
+ new_context->parent = current_context;
+ current_context = new_context;
+}
+
+void Control::popContext()
+{
+ // printf("-Context\n");
+ Q_ASSERT(current_context != 0);
+
+ Context *old_context = current_context;
+ current_context = current_context->parent;
+
+ delete old_context;
+}
+
+void Control::declareTypedef(const NameSymbol *name, Declarator *d)
+{
+ // printf("declared typedef:");
+ // printSymbol(name);
+ // printf("\n");
+ stl_typedef_table.insert(name, d);
+}
+
+bool Control::isTypedef(const NameSymbol *name) const
+{
+ // printf("is typedef:");
+ // printSymbol(name);
+ // printf("= %d\n", (stl_typedef_table.find(name) != stl_typedef_table.end()));
+
+ return stl_typedef_table.contains(name);
+}
+
+QList<Control::ErrorMessage> Control::errorMessages() const
+{
+ return _M_error_messages;
+}
+
+void Control::clearErrorMessages()
+{
+ _M_error_messages.clear();
+}
+
+void Control::reportError(const ErrorMessage &errmsg)
+{
+ _M_error_messages.append(errmsg);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/control.h b/parser/control.h
new file mode 100644
index 000000000..533db912c
--- /dev/null
+++ b/parser/control.h
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include "symbol.h"
+#include "smallobject.h"
+
+#include <QtCore/QHash>
+
+struct Declarator;
+struct Type;
+class Lexer;
+class Parser;
+
+struct Context {
+ Context *parent;
+
+ inline void bind(const NameSymbol *name, Type *type) {
+ symbol_table.insert(name, type);
+ }
+
+ inline Type *resolve(const NameSymbol *name) const {
+ if (Type *type = symbol_table.value(name))
+ return type;
+ else if (parent)
+ return parent->resolve(name);
+
+ return 0;
+ }
+
+ typedef QHash<const NameSymbol*, Type*> symbol_table_t;
+
+ symbol_table_t symbol_table;
+};
+
+class Control
+{
+public:
+ class ErrorMessage
+ {
+ public:
+ ErrorMessage():
+ _M_line(0),
+ _M_column(0) {}
+
+ inline int line() const {
+ return _M_line;
+ }
+ inline void setLine(int line) {
+ _M_line = line;
+ }
+
+ inline int column() const {
+ return _M_column;
+ }
+ inline void setColumn(int column) {
+ _M_column = column;
+ }
+
+ inline QString fileName() const {
+ return _M_fileName;
+ }
+ inline void setFileName(const QString &fileName) {
+ _M_fileName = fileName;
+ }
+
+ inline QString message() const {
+ return _M_message;
+ }
+ inline void setMessage(const QString &message) {
+ _M_message = message;
+ }
+
+ private:
+ int _M_line;
+ int _M_column;
+ QString _M_fileName;
+ QString _M_message;
+ };
+
+ Control();
+ ~Control();
+
+ inline bool skipFunctionBody() const {
+ return _M_skipFunctionBody;
+ }
+ inline void setSkipFunctionBody(bool skip) {
+ _M_skipFunctionBody = skip;
+ }
+
+ Lexer *changeLexer(Lexer *lexer);
+ Parser *changeParser(Parser *parser);
+
+ Lexer *currentLexer() const {
+ return _M_lexer;
+ }
+ Parser *currentParser() const {
+ return _M_parser;
+ }
+
+ Context *current_context;
+
+ inline Context *currentContext() const {
+ return current_context;
+ }
+
+ void pushContext();
+ void popContext();
+
+ Type *lookupType(const NameSymbol *name) const;
+ void declare(const NameSymbol *name, Type *type);
+
+ inline const NameSymbol *findOrInsertName(const char *data, size_t count) {
+ return name_table.findOrInsert(data, count);
+ }
+
+ void declareTypedef(const NameSymbol *name, Declarator *d);
+ bool isTypedef(const NameSymbol *name) const;
+
+ void reportError(const ErrorMessage &errmsg);
+ QList<ErrorMessage> errorMessages() const;
+ void clearErrorMessages();
+
+private:
+ NameTable name_table;
+ QHash<const NameSymbol*, Declarator*> stl_typedef_table;
+ bool _M_skipFunctionBody;
+ Lexer *_M_lexer;
+ Parser *_M_parser;
+
+ QList<ErrorMessage> _M_error_messages;
+};
+
+#endif // CONTROL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/declarator_compiler.cpp b/parser/declarator_compiler.cpp
new file mode 100644
index 000000000..255bfcddb
--- /dev/null
+++ b/parser/declarator_compiler.cpp
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "declarator_compiler.h"
+#include "name_compiler.h"
+#include "type_compiler.h"
+#include "compiler_utils.h"
+#include "lexer.h"
+#include "binder.h"
+#include "tokens.h"
+
+#include <qdebug.h>
+
+DeclaratorCompiler::DeclaratorCompiler(Binder *binder)
+ : _M_binder(binder), _M_token_stream(binder->tokenStream())
+{
+}
+
+void DeclaratorCompiler::run(DeclaratorAST *node)
+{
+ _M_id.clear();
+ _M_parameters.clear();
+ _M_array.clear();
+ _M_function = false;
+ _M_reference = false;
+ _M_variadics = false;
+ _M_indirection = 0;
+
+ if (node) {
+ NameCompiler name_cc(_M_binder);
+
+ DeclaratorAST *decl = node;
+ while (decl && decl->sub_declarator)
+ decl = decl->sub_declarator;
+
+ Q_ASSERT(decl != 0);
+
+ name_cc.run(decl->id);
+ _M_id = name_cc.name();
+ _M_function = (node->parameter_declaration_clause != 0);
+ if (node->parameter_declaration_clause && node->parameter_declaration_clause->ellipsis)
+ _M_variadics = true;
+
+ visitNodes(this, node->ptr_ops);
+ visit(node->parameter_declaration_clause);
+
+ if (const ListNode<ExpressionAST*> *it = node->array_dimensions) {
+ it->toFront();
+ const ListNode<ExpressionAST*> *end = it;
+
+ do {
+ QString elt;
+ if (ExpressionAST *expr = it->element) {
+ const Token &start_token = _M_token_stream->token((int) expr->start_token);
+ const Token &end_token = _M_token_stream->token((int) expr->end_token);
+
+ elt += QString::fromUtf8(&start_token.text[start_token.position],
+ (int)(end_token.position - start_token.position)).trimmed();
+ }
+
+ _M_array.append(elt);
+
+ it = it->next;
+ } while (it != end);
+ }
+ }
+}
+
+void DeclaratorCompiler::visitPtrOperator(PtrOperatorAST *node)
+{
+ std::size_t op = _M_token_stream->kind(node->op);
+
+ switch (op) {
+ case '&':
+ _M_reference = true;
+ break;
+ case '*':
+ ++_M_indirection;
+ break;
+
+ default:
+ break;
+ }
+
+ if (node->mem_ptr) {
+#if defined(__GNUC__)
+#warning "ptr to mem -- not implemented"
+#endif
+ }
+}
+
+void DeclaratorCompiler::visitParameterDeclaration(ParameterDeclarationAST *node)
+{
+ Parameter p;
+
+ TypeCompiler type_cc(_M_binder);
+ DeclaratorCompiler decl_cc(_M_binder);
+
+ decl_cc.run(node->declarator);
+
+ p.name = decl_cc.id();
+ p.type = CompilerUtils::typeDescription(node->type_specifier, node->declarator, _M_binder);
+ if (node->expression != 0) {
+ const Token &start = _M_token_stream->token((int) node->expression->start_token);
+ const Token &end = _M_token_stream->token((int) node->expression->end_token);
+ int length = (int)(end.position - start.position);
+
+ p.defaultValueExpression = QString();
+ QString source = QString::fromUtf8(&start.text[start.position], length).trimmed();
+ QStringList list = source.split("\n");
+
+
+ for (int i = 0; i < list.size(); ++i) {
+ if (!list.at(i).startsWith("#"))
+ p.defaultValueExpression += list.at(i).trimmed();
+ }
+
+ p.defaultValue = p.defaultValueExpression.size() > 0;
+
+ }
+
+ _M_parameters.append(p);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/declarator_compiler.h b/parser/declarator_compiler.h
new file mode 100644
index 000000000..70a65b058
--- /dev/null
+++ b/parser/declarator_compiler.h
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef DECLARATOR_COMPILER_H
+#define DECLARATOR_COMPILER_H
+
+#include "default_visitor.h"
+#include "codemodel.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+class TokenStream;
+class Binder;
+
+class DeclaratorCompiler: protected DefaultVisitor
+{
+public:
+ struct Parameter {
+ TypeInfo type;
+ QString name;
+ QString defaultValueExpression;
+ bool defaultValue;
+
+ Parameter(): defaultValue(false) {}
+ };
+
+public:
+ DeclaratorCompiler(Binder *binder);
+
+ void run(DeclaratorAST *node);
+
+ inline QString id() const {
+ return _M_id;
+ }
+ inline QStringList arrayElements() const {
+ return _M_array;
+ }
+ inline bool isFunction() const {
+ return _M_function;
+ }
+ inline bool isVariadics() const {
+ return _M_variadics;
+ }
+ inline bool isReference() const {
+ return _M_reference;
+ }
+ inline int indirection() const {
+ return _M_indirection;
+ }
+ inline QList<Parameter> parameters() const {
+ return _M_parameters;
+ }
+
+protected:
+ virtual void visitPtrOperator(PtrOperatorAST *node);
+ virtual void visitParameterDeclaration(ParameterDeclarationAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+
+ bool _M_function;
+ bool _M_reference;
+ bool _M_variadics;
+ int _M_indirection;
+ QString _M_id;
+ QStringList _M_array;
+ QList<Parameter> _M_parameters;
+};
+
+#endif // DECLARATOR_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/default_visitor.cpp b/parser/default_visitor.cpp
new file mode 100644
index 000000000..07ab968cc
--- /dev/null
+++ b/parser/default_visitor.cpp
@@ -0,0 +1,459 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "default_visitor.h"
+
+void DefaultVisitor::visitAccessSpecifier(AccessSpecifierAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitAsmDefinition(AsmDefinitionAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitBaseClause(BaseClauseAST *node)
+{
+ visitNodes(this, node->base_specifiers);
+}
+
+void DefaultVisitor::visitBaseSpecifier(BaseSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void DefaultVisitor::visitBinaryExpression(BinaryExpressionAST *node)
+{
+ visit(node->left_expression);
+ visit(node->right_expression);
+}
+
+void DefaultVisitor::visitCastExpression(CastExpressionAST *node)
+{
+ visit(node->type_id);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitClassMemberAccess(ClassMemberAccessAST *node)
+{
+ visit(node->name);
+}
+
+void DefaultVisitor::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ visit(node->win_decl_specifiers);
+ visit(node->name);
+ visit(node->base_clause);
+ visitNodes(this, node->member_specs);
+}
+
+void DefaultVisitor::visitCompoundStatement(CompoundStatementAST *node)
+{
+ visitNodes(this, node->statements);
+}
+
+void DefaultVisitor::visitCondition(ConditionAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->declarator);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitConditionalExpression(ConditionalExpressionAST *node)
+{
+ visit(node->condition);
+ visit(node->left_expression);
+ visit(node->right_expression);
+}
+
+void DefaultVisitor::visitCppCastExpression(CppCastExpressionAST *node)
+{
+ visit(node->type_id);
+ visit(node->expression);
+ visitNodes(this, node->sub_expressions);
+}
+
+void DefaultVisitor::visitCtorInitializer(CtorInitializerAST *node)
+{
+ visitNodes(this, node->member_initializers);
+}
+
+void DefaultVisitor::visitDeclarationStatement(DeclarationStatementAST *node)
+{
+ visit(node->declaration);
+}
+
+void DefaultVisitor::visitDeclarator(DeclaratorAST *node)
+{
+ visit(node->sub_declarator);
+ visitNodes(this, node->ptr_ops);
+ visit(node->id);
+ visit(node->bit_expression);
+ visitNodes(this, node->array_dimensions);
+ visit(node->parameter_declaration_clause);
+ visit(node->exception_spec);
+}
+
+void DefaultVisitor::visitDeleteExpression(DeleteExpressionAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitDoStatement(DoStatementAST *node)
+{
+ visit(node->statement);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void DefaultVisitor::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+ visit(node->name);
+ visitNodes(this, node->enumerators);
+}
+
+void DefaultVisitor::visitEnumerator(EnumeratorAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitExceptionSpecification(ExceptionSpecificationAST *node)
+{
+ visitNodes(this, node->type_ids);
+}
+
+void DefaultVisitor::visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *node)
+{
+ visit(node->expression);
+ visit(node->declaration);
+}
+
+void DefaultVisitor::visitExpressionStatement(ExpressionStatementAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitForStatement(ForStatementAST *node)
+{
+ visit(node->init_statement);
+ visit(node->condition);
+ visit(node->expression);
+ visit(node->statement);
+}
+
+void DefaultVisitor::visitFunctionCall(FunctionCallAST *node)
+{
+ visit(node->arguments);
+}
+
+void DefaultVisitor::visitFunctionDefinition(FunctionDefinitionAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->init_declarator);
+ visit(node->function_body);
+ visit(node->win_decl_specifiers);
+}
+
+void DefaultVisitor::visitIfStatement(IfStatementAST *node)
+{
+ visit(node->condition);
+ visit(node->statement);
+ visit(node->else_statement);
+}
+
+void DefaultVisitor::visitIncrDecrExpression(IncrDecrExpressionAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitInitDeclarator(InitDeclaratorAST *node)
+{
+ visit(node->declarator);
+ visit(node->initializer);
+}
+
+void DefaultVisitor::visitInitializer(InitializerAST *node)
+{
+ visit(node->initializer_clause);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitInitializerClause(InitializerClauseAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitLabeledStatement(LabeledStatementAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitLinkageBody(LinkageBodyAST *node)
+{
+ visitNodes(this, node->declarations);
+}
+
+void DefaultVisitor::visitLinkageSpecification(LinkageSpecificationAST *node)
+{
+ visit(node->linkage_body);
+ visit(node->declaration);
+}
+
+void DefaultVisitor::visitMemInitializer(MemInitializerAST *node)
+{
+ visit(node->initializer_id);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitName(NameAST *node)
+{
+ visitNodes(this, node->qualified_names);
+ visit(node->unqualified_name);
+}
+
+void DefaultVisitor::visitNamespace(NamespaceAST *node)
+{
+ visit(node->linkage_body);
+}
+
+void DefaultVisitor::visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *node)
+{
+ visit(node->alias_name);
+}
+
+void DefaultVisitor::visitNewDeclarator(NewDeclaratorAST *node)
+{
+ visit(node->ptr_op);
+ visit(node->sub_declarator);
+ visitNodes(this, node->expressions);
+}
+
+void DefaultVisitor::visitNewExpression(NewExpressionAST *node)
+{
+ visit(node->expression);
+ visit(node->type_id);
+ visit(node->new_type_id);
+ visit(node->new_initializer);
+}
+
+void DefaultVisitor::visitNewInitializer(NewInitializerAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitNewTypeId(NewTypeIdAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->new_initializer);
+ visit(node->new_declarator);
+}
+
+void DefaultVisitor::visitOperator(OperatorAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitOperatorFunctionId(OperatorFunctionIdAST *node)
+{
+ visit(node->op);
+ visit(node->type_specifier);
+ visitNodes(this, node->ptr_ops);
+}
+
+void DefaultVisitor::visitParameterDeclaration(ParameterDeclarationAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->declarator);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitParameterDeclarationClause(ParameterDeclarationClauseAST *node)
+{
+ visitNodes(this, node->parameter_declarations);
+}
+
+void DefaultVisitor::visitPostfixExpression(PostfixExpressionAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->expression);
+ visitNodes(this, node->sub_expressions);
+}
+
+void DefaultVisitor::visitPrimaryExpression(PrimaryExpressionAST *node)
+{
+ visit(node->literal);
+ visit(node->expression_statement);
+ visit(node->sub_expression);
+ visit(node->name);
+}
+
+void DefaultVisitor::visitPtrOperator(PtrOperatorAST *node)
+{
+ visit(node->mem_ptr);
+}
+
+void DefaultVisitor::visitPtrToMember(PtrToMemberAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitReturnStatement(ReturnStatementAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitSimpleDeclaration(SimpleDeclarationAST *node)
+{
+ visit(node->type_specifier);
+ visitNodes(this, node->init_declarators);
+ visit(node->win_decl_specifiers);
+}
+
+void DefaultVisitor::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node)
+{
+ visit(node->name);
+ visit(node->type_id);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitSizeofExpression(SizeofExpressionAST *node)
+{
+ visit(node->type_id);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitStringLiteral(StringLiteralAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitSubscriptExpression(SubscriptExpressionAST *node)
+{
+ visit(node->subscript);
+}
+
+void DefaultVisitor::visitSwitchStatement(SwitchStatementAST *node)
+{
+ visit(node->condition);
+ visit(node->statement);
+}
+
+void DefaultVisitor::visitTemplateArgument(TemplateArgumentAST *node)
+{
+ visit(node->type_id);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitTemplateDeclaration(TemplateDeclarationAST *node)
+{
+ visitNodes(this, node->template_parameters);
+ visit(node->declaration);
+}
+
+void DefaultVisitor::visitTemplateParameter(TemplateParameterAST *node)
+{
+ visit(node->type_parameter);
+ visit(node->parameter_declaration);
+}
+
+void DefaultVisitor::visitThrowExpression(ThrowExpressionAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitTranslationUnit(TranslationUnitAST *node)
+{
+ visitNodes(this, node->declarations);
+}
+
+void DefaultVisitor::visitTryBlockStatement(TryBlockStatementAST *)
+{
+ // nothing to do
+}
+
+void DefaultVisitor::visitTypeId(TypeIdAST *node)
+{
+ visit(node->type_specifier);
+ visit(node->declarator);
+}
+
+void DefaultVisitor::visitTypeIdentification(TypeIdentificationAST *node)
+{
+ visit(node->name);
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitTypeParameter(TypeParameterAST *node)
+{
+ visit(node->name);
+ visit(node->type_id);
+ visitNodes(this, node->template_parameters);
+ visit(node->template_name);
+}
+
+void DefaultVisitor::visitTypedef(TypedefAST *node)
+{
+ visit(node->type_specifier);
+ visitNodes(this, node->init_declarators);
+}
+
+void DefaultVisitor::visitUnaryExpression(UnaryExpressionAST *node)
+{
+ visit(node->expression);
+}
+
+void DefaultVisitor::visitUnqualifiedName(UnqualifiedNameAST *node)
+{
+ visit(node->operator_id);
+ visitNodes(this, node->template_arguments);
+}
+
+void DefaultVisitor::visitUsing(UsingAST *node)
+{
+ visit(node->name);
+}
+
+void DefaultVisitor::visitUsingDirective(UsingDirectiveAST *node)
+{
+ visit(node->name);
+}
+
+void DefaultVisitor::visitWhileStatement(WhileStatementAST *node)
+{
+ visit(node->condition);
+ visit(node->statement);
+}
+
+void DefaultVisitor::visitWinDeclSpec(WinDeclSpecAST *)
+{
+ // nothing to do
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/default_visitor.h b/parser/default_visitor.h
new file mode 100644
index 000000000..ec1caf3bc
--- /dev/null
+++ b/parser/default_visitor.h
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef DEFAULT_VISITOR_H
+#define DEFAULT_VISITOR_H
+
+#include "visitor.h"
+
+class DefaultVisitor: public Visitor
+{
+public:
+ DefaultVisitor() {}
+
+protected:
+ virtual void visitAccessSpecifier(AccessSpecifierAST *);
+ virtual void visitAsmDefinition(AsmDefinitionAST *);
+ virtual void visitBaseClause(BaseClauseAST *);
+ virtual void visitBaseSpecifier(BaseSpecifierAST *);
+ virtual void visitBinaryExpression(BinaryExpressionAST *);
+ virtual void visitCastExpression(CastExpressionAST *);
+ virtual void visitClassMemberAccess(ClassMemberAccessAST *);
+ virtual void visitClassSpecifier(ClassSpecifierAST *);
+ virtual void visitCompoundStatement(CompoundStatementAST *);
+ virtual void visitCondition(ConditionAST *);
+ virtual void visitConditionalExpression(ConditionalExpressionAST *);
+ virtual void visitCppCastExpression(CppCastExpressionAST *);
+ virtual void visitCtorInitializer(CtorInitializerAST *);
+ virtual void visitDeclarationStatement(DeclarationStatementAST *);
+ virtual void visitDeclarator(DeclaratorAST *);
+ virtual void visitDeleteExpression(DeleteExpressionAST *);
+ virtual void visitDoStatement(DoStatementAST *);
+ virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *);
+ virtual void visitEnumSpecifier(EnumSpecifierAST *);
+ virtual void visitEnumerator(EnumeratorAST *);
+ virtual void visitExceptionSpecification(ExceptionSpecificationAST *);
+ virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *);
+ virtual void visitExpressionStatement(ExpressionStatementAST *);
+ virtual void visitForStatement(ForStatementAST *);
+ virtual void visitFunctionCall(FunctionCallAST *);
+ virtual void visitFunctionDefinition(FunctionDefinitionAST *);
+ virtual void visitIfStatement(IfStatementAST *);
+ virtual void visitIncrDecrExpression(IncrDecrExpressionAST *);
+ virtual void visitInitDeclarator(InitDeclaratorAST *);
+ virtual void visitInitializer(InitializerAST *);
+ virtual void visitInitializerClause(InitializerClauseAST *);
+ virtual void visitLabeledStatement(LabeledStatementAST *);
+ virtual void visitLinkageBody(LinkageBodyAST *);
+ virtual void visitLinkageSpecification(LinkageSpecificationAST *);
+ virtual void visitMemInitializer(MemInitializerAST *);
+ virtual void visitName(NameAST *);
+ virtual void visitNamespace(NamespaceAST *);
+ virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *);
+ virtual void visitNewDeclarator(NewDeclaratorAST *);
+ virtual void visitNewExpression(NewExpressionAST *);
+ virtual void visitNewInitializer(NewInitializerAST *);
+ virtual void visitNewTypeId(NewTypeIdAST *);
+ virtual void visitOperator(OperatorAST *);
+ virtual void visitOperatorFunctionId(OperatorFunctionIdAST *);
+ virtual void visitParameterDeclaration(ParameterDeclarationAST *);
+ virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *);
+ virtual void visitPostfixExpression(PostfixExpressionAST *);
+ virtual void visitPrimaryExpression(PrimaryExpressionAST *);
+ virtual void visitPtrOperator(PtrOperatorAST *);
+ virtual void visitPtrToMember(PtrToMemberAST *);
+ virtual void visitReturnStatement(ReturnStatementAST *);
+ virtual void visitSimpleDeclaration(SimpleDeclarationAST *);
+ virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *);
+ virtual void visitSizeofExpression(SizeofExpressionAST *);
+ virtual void visitStringLiteral(StringLiteralAST *);
+ virtual void visitSubscriptExpression(SubscriptExpressionAST *);
+ virtual void visitSwitchStatement(SwitchStatementAST *);
+ virtual void visitTemplateArgument(TemplateArgumentAST *);
+ virtual void visitTemplateDeclaration(TemplateDeclarationAST *);
+ virtual void visitTemplateParameter(TemplateParameterAST *);
+ virtual void visitThrowExpression(ThrowExpressionAST *);
+ virtual void visitTranslationUnit(TranslationUnitAST *);
+ virtual void visitTryBlockStatement(TryBlockStatementAST *);
+ virtual void visitTypeId(TypeIdAST *);
+ virtual void visitTypeIdentification(TypeIdentificationAST *);
+ virtual void visitTypeParameter(TypeParameterAST *);
+ virtual void visitTypedef(TypedefAST *);
+ virtual void visitUnaryExpression(UnaryExpressionAST *);
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *);
+ virtual void visitUsing(UsingAST *);
+ virtual void visitUsingDirective(UsingDirectiveAST *);
+ virtual void visitWhileStatement(WhileStatementAST *);
+ virtual void visitWinDeclSpec(WinDeclSpecAST *);
+
+private:
+ typedef void (Visitor::*visitor_fun_ptr)(AST *);
+ static visitor_fun_ptr _S_table[];
+};
+
+#endif // VISITOR_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/dumptree.cpp b/parser/dumptree.cpp
new file mode 100644
index 000000000..1514b0f64
--- /dev/null
+++ b/parser/dumptree.cpp
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "dumptree.h"
+
+#include <QtCore/QString>
+#include <QtCore/qdebug.h>
+
+static char const * const names[] = {
+ 0,
+ "AccessSpecifier",
+ "AsmDefinition",
+ "BaseClause",
+ "BaseSpecifier",
+ "BinaryExpression",
+ "CastExpression",
+ "ClassMemberAccess",
+ "ClassSpecifier",
+ "CompoundStatement",
+ "Condition",
+ "ConditionalExpression",
+ "CppCastExpression",
+ "CtorInitializer",
+ "DeclarationStatement",
+ "Declarator",
+ "DeleteExpression",
+ "DoStatement",
+ "ElaboratedTypeSpecifier",
+ "EnumSpecifier",
+ "Enumerator",
+ "ExceptionSpecification",
+ "ExpressionOrDeclarationStatement",
+ "ExpressionStatement",
+ "ForStatement",
+ "FunctionCall",
+ "FunctionDefinition",
+ "IfStatement",
+ "IncrDecrExpression",
+ "InitDeclarator",
+ "Initializer",
+ "InitializerClause",
+ "LabeledStatement",
+ "LinkageBody",
+ "LinkageSpecification",
+ "MemInitializer",
+ "Name",
+ "Namespace",
+ "NamespaceAliasDefinition",
+ "NewDeclarator",
+ "NewExpression",
+ "NewInitializer",
+ "NewTypeId",
+ "Operator",
+ "OperatorFunctionId",
+ "ParameterDeclaration",
+ "ParameterDeclarationClause",
+ "PostfixExpression",
+ "PrimaryExpression",
+ "PtrOperator",
+ "PtrToMember",
+ "ReturnStatement",
+ "SimpleDeclaration",
+ "SimpleTypeSpecifier",
+ "SizeofExpression",
+ "StringLiteral",
+ "SubscriptExpression",
+ "SwitchStatement",
+ "TemplateArgument",
+ "TemplateDeclaration",
+ "TemplateParameter",
+ "ThrowExpression",
+ "TranslationUnit",
+ "TryBlockStatement",
+ "TypeId",
+ "TypeIdentification",
+ "TypeParameter",
+ "Typedef",
+ "UnaryExpression",
+ "UnqualifiedName",
+ "Using",
+ "UsingDirective",
+ "WhileStatement",
+ "WinDeclSpec"
+};
+
+DumpTree::DumpTree()
+{
+}
+
+void DumpTree::visit(AST *node)
+{
+ static int indent = 0;
+
+ if (node)
+ qDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind]
+ << '[' << node->start_token << ", " << node->end_token << ']';
+
+ ++indent;
+ DefaultVisitor::visit(node);
+ --indent;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/dumptree.h b/parser/dumptree.h
new file mode 100644
index 000000000..cfc55e2e6
--- /dev/null
+++ b/parser/dumptree.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef DUMPTREE_H
+#define DUMPTREE_H
+
+#include "default_visitor.h"
+
+class DumpTree: protected DefaultVisitor
+{
+public:
+ DumpTree();
+
+ void dump(AST *node) {
+ visit(node);
+ }
+
+protected:
+ virtual void visit(AST *node);
+};
+
+#endif // DUMPTREE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/lexer.cpp b/parser/lexer.cpp
new file mode 100644
index 000000000..2abb540d0
--- /dev/null
+++ b/parser/lexer.cpp
@@ -0,0 +1,1695 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "lexer.h"
+#include "tokens.h"
+#include "control.h"
+
+#include <cctype>
+#include <iostream>
+
+scan_fun_ptr Lexer::s_scan_keyword_table[] = {
+ &Lexer::scanKeyword0, &Lexer::scanKeyword0,
+ &Lexer::scanKeyword2, &Lexer::scanKeyword3,
+ &Lexer::scanKeyword4, &Lexer::scanKeyword5,
+ &Lexer::scanKeyword6, &Lexer::scanKeyword7,
+ &Lexer::scanKeyword8, &Lexer::scanKeyword9,
+ &Lexer::scanKeyword10, &Lexer::scanKeyword11,
+ &Lexer::scanKeyword12, &Lexer::scanKeyword13,
+ &Lexer::scanKeyword14, &Lexer::scanKeyword0,
+ &Lexer::scanKeyword16
+};
+
+void LocationManager::extract_line(int offset, int *line, QString *filename) const
+{
+ *line = 0;
+ if (token_stream.size() < 1)
+ return;
+
+ const unsigned char *begin_buffer = reinterpret_cast<const unsigned char *>(token_stream[0].text);
+ const unsigned char *cursor = begin_buffer + offset;
+
+ ++cursor; // skip '#'
+ if (std::isspace(*cursor) && std::isdigit(*(cursor + 1))) {
+ ++cursor;
+ char buffer[1024], *cp = buffer;
+ do {
+ *cp++ = *cursor++;
+ } while (std::isdigit(*cursor));
+ *cp = '\0';
+ int l = strtol(buffer, 0, 0);
+
+ Q_ASSERT(std::isspace(*cursor));
+ ++cursor;
+
+ Q_ASSERT(*cursor == '"');
+ ++cursor;
+
+ cp = buffer;
+ while (*cursor && *cursor != '"') {
+ *cp++ = *cursor++;
+ }
+ *cp = '\0';
+ Q_ASSERT(*cursor == '"');
+ ++cursor;
+
+ *filename = buffer;
+ *line = l;
+ // printf("filename: %s line: %d\n", buffer, line);
+ }
+}
+
+void LocationManager::positionAt(std::size_t offset, int *line, int *column,
+ QString *filename) const
+{
+ int ppline, ppcolumn;
+ line_table.positionAt(offset, &ppline, &ppcolumn);
+
+ int base_line;
+ extract_line((int) line_table[ppline-1], &base_line, filename);
+
+ int line2, column2;
+ location_table.positionAt((int) line_table[ppline-1], &line2, &column2);
+
+ location_table.positionAt(offset, line, column);
+ *line = base_line + *line - line2 - 1;
+}
+
+scan_fun_ptr Lexer::s_scan_table[256];
+bool Lexer::s_initialized = false;
+
+void Lexer::tokenize(const char *contents, std::size_t size)
+{
+ if (!s_initialized)
+ initialize_scan_table();
+
+ token_stream.resize(1024);
+ token_stream[0].kind = Token_EOF;
+ token_stream[0].text = contents;
+
+ index = 1;
+
+ cursor = (const unsigned char *) contents;
+ begin_buffer = (const unsigned char *) contents;
+ end_buffer = cursor + size;
+
+ location_table.resize(1024);
+ location_table[0] = 0;
+ location_table.current_line = 1;
+
+ line_table.resize(1024);
+ line_table[0] = 0;
+ line_table.current_line = 1;
+
+ do {
+ if (index == token_stream.size())
+ token_stream.resize(token_stream.size() * 2);
+
+ Token *current_token = &token_stream[(int) index];
+ current_token->text = reinterpret_cast<const char*>(begin_buffer);
+ current_token->position = cursor - begin_buffer;
+ (this->*s_scan_table[*cursor])();
+ current_token->size = cursor - begin_buffer - current_token->position;
+ } while (cursor < end_buffer);
+
+ if (index == token_stream.size())
+ token_stream.resize(token_stream.size() * 2);
+
+ Q_ASSERT(index < token_stream.size());
+ token_stream[(int) index].position = cursor - begin_buffer;
+ token_stream[(int) index].kind = Token_EOF;
+}
+
+void Lexer::reportError(const QString& msg)
+{
+ int line, column;
+ QString fileName;
+
+ std::size_t tok = token_stream.cursor();
+ _M_location.positionAt(token_stream.position(tok),
+ &line, &column, &fileName);
+
+ Control::ErrorMessage errmsg;
+ errmsg.setLine(line + 1);
+ errmsg.setColumn(column);
+ errmsg.setFileName(fileName);
+ errmsg.setMessage(QLatin1String("** LEXER ERROR ") + msg);
+ control->reportError(errmsg);
+}
+
+void Lexer::initialize_scan_table()
+{
+ s_initialized = true;
+
+ for (int i = 0; i < 256; ++i) {
+ if (isspace(i))
+ s_scan_table[i] = &Lexer::scan_white_spaces;
+ else if (isalpha(i) || i == '_')
+ s_scan_table[i] = &Lexer::scan_identifier_or_keyword;
+ else if (isdigit(i))
+ s_scan_table[i] = &Lexer::scan_int_constant;
+ else
+ s_scan_table[i] = &Lexer::scan_invalid_input;
+ }
+
+ s_scan_table[int('L')] = &Lexer::scan_identifier_or_literal;
+ s_scan_table[int('\n')] = &Lexer::scan_newline;
+ s_scan_table[int('#')] = &Lexer::scan_preprocessor;
+
+ s_scan_table[int('\'')] = &Lexer::scan_char_constant;
+ s_scan_table[int('"')] = &Lexer::scan_string_constant;
+
+ s_scan_table[int('.')] = &Lexer::scan_int_constant;
+
+ s_scan_table[int('!')] = &Lexer::scan_not;
+ s_scan_table[int('%')] = &Lexer::scan_remainder;
+ s_scan_table[int('&')] = &Lexer::scan_and;
+ s_scan_table[int('(')] = &Lexer::scan_left_paren;
+ s_scan_table[int(')')] = &Lexer::scan_right_paren;
+ s_scan_table[int('*')] = &Lexer::scan_star;
+ s_scan_table[int('+')] = &Lexer::scan_plus;
+ s_scan_table[int(',')] = &Lexer::scan_comma;
+ s_scan_table[int('-')] = &Lexer::scan_minus;
+ s_scan_table[int('/')] = &Lexer::scan_divide;
+ s_scan_table[int(':')] = &Lexer::scan_colon;
+ s_scan_table[int(';')] = &Lexer::scan_semicolon;
+ s_scan_table[int('<')] = &Lexer::scan_less;
+ s_scan_table[int('=')] = &Lexer::scan_equal;
+ s_scan_table[int('>')] = &Lexer::scan_greater;
+ s_scan_table[int('?')] = &Lexer::scan_question;
+ s_scan_table[int('[')] = &Lexer::scan_left_bracket;
+ s_scan_table[int(']')] = &Lexer::scan_right_bracket;
+ s_scan_table[int('^')] = &Lexer::scan_xor;
+ s_scan_table[int('{')] = &Lexer::scan_left_brace;
+ s_scan_table[int('|')] = &Lexer::scan_or;
+ s_scan_table[int('}')] = &Lexer::scan_right_brace;
+ s_scan_table[int('~')] = &Lexer::scan_tilde;
+
+ s_scan_table[0] = &Lexer::scan_EOF;
+}
+
+void Lexer::scan_preprocessor()
+{
+ if (line_table.current_line == line_table.size())
+ line_table.resize(line_table.current_line * 2);
+
+ line_table[(int) line_table.current_line++] = (cursor - begin_buffer);
+
+ while (*cursor && *cursor != '\n')
+ ++cursor;
+
+ if (*cursor != '\n')
+ reportError("expected newline");
+}
+
+void Lexer::scan_char_constant()
+{
+ const unsigned char *begin = cursor;
+
+ ++cursor;
+ while (*cursor && *cursor != '\'') {
+ if (*cursor == '\n')
+ reportError("did not expect newline");
+
+ if (*cursor == '\\')
+ ++cursor;
+ ++cursor;
+ }
+
+ if (*cursor != '\'')
+ reportError("expected \'");
+
+ ++cursor;
+
+ token_stream[(int) index].extra.symbol =
+ control->findOrInsertName((const char*) begin, cursor - begin);
+
+ token_stream[(int) index++].kind = Token_char_literal;
+}
+
+void Lexer::scan_string_constant()
+{
+ const unsigned char *begin = cursor;
+
+ ++cursor;
+ while (*cursor && *cursor != '"') {
+ if (*cursor == '\n')
+ reportError("did not expect newline");
+
+ if (*cursor == '\\')
+ ++cursor;
+ ++cursor;
+ }
+
+ if (*cursor != '"')
+ reportError("expected \"");
+
+ ++cursor;
+
+ token_stream[(int) index].extra.symbol =
+ control->findOrInsertName((const char*) begin, cursor - begin);
+
+ token_stream[(int) index++].kind = Token_string_literal;
+}
+
+void Lexer::scan_newline()
+{
+ if (location_table.current_line == location_table.size())
+ location_table.resize(location_table.current_line * 2);
+
+ location_table[(int) location_table.current_line++] = (cursor - begin_buffer);
+ ++cursor;
+}
+
+void Lexer::scan_white_spaces()
+{
+ while (isspace(*cursor)) {
+ if (*cursor == '\n')
+ scan_newline();
+ else
+ ++cursor;
+ }
+}
+
+void Lexer::scan_identifier_or_literal()
+{
+ switch (*(cursor + 1)) {
+ case '\'':
+ ++cursor;
+ scan_char_constant();
+ break;
+
+ case '\"':
+ ++cursor;
+ scan_string_constant();
+ break;
+
+ default:
+ scan_identifier_or_keyword();
+ break;
+ }
+}
+
+void Lexer::scan_identifier_or_keyword()
+{
+ const unsigned char *skip = cursor;
+ while (isalnum(*skip) || *skip == '_')
+ ++skip;
+
+ int n = skip - cursor;
+ Token *current_token = &token_stream[(int) index];
+ (this->*s_scan_keyword_table[n < 17 ? n : 0])();
+
+ if (current_token->kind == Token_identifier) {
+ current_token->extra.symbol =
+ control->findOrInsertName((const char*) cursor, n);
+ }
+
+ cursor = skip;
+}
+
+void Lexer::scan_int_constant()
+{
+ if (*cursor == '.' && !std::isdigit(*(cursor + 1))) {
+ scan_dot();
+ return;
+ }
+
+ const unsigned char *begin = cursor;
+
+ while (isalnum(*cursor) || *cursor == '.')
+ ++cursor;
+
+ token_stream[(int) index].extra.symbol =
+ control->findOrInsertName((const char*) begin, cursor - begin);
+
+ token_stream[(int) index++].kind = Token_number_literal;
+}
+
+void Lexer::scan_not()
+{
+ /*
+ '!' ::= not
+ '!=' ::= not_equal
+ */
+
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_not_eq;
+ } else {
+ token_stream[(int) index++].kind = '!';
+ }
+}
+
+void Lexer::scan_remainder()
+{
+ /*
+ '%' ::= remainder
+ '%=' ::= remainder_equal
+ */
+
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = '%';
+ }
+}
+
+void Lexer::scan_and()
+{
+ /*
+ '&&' ::= and_and
+ '&' ::= and
+ '&=' ::= and_equal
+ */
+
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else if (*cursor == '&') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_and;
+ } else {
+ token_stream[(int) index++].kind = '&';
+ }
+}
+
+void Lexer::scan_left_paren()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '(';
+}
+
+void Lexer::scan_right_paren()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = ')';
+}
+
+void Lexer::scan_star()
+{
+ /*
+ '*' ::= star
+ '*=' ::= star_equal
+ */
+
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = '*';
+ }
+}
+
+void Lexer::scan_plus()
+{
+ /*
+ '+' ::= plus
+ '++' ::= incr
+ '+=' ::= plus_equal
+ */
+
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else if (*cursor == '+') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_incr;
+ } else {
+ token_stream[(int) index++].kind = '+';
+ }
+}
+
+void Lexer::scan_comma()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = ',';
+}
+
+void Lexer::scan_minus()
+{
+ /*
+ '-' ::= minus
+ '--' ::= decr
+ '-=' ::= minus_equal
+ '->' ::= left_arrow
+ */
+
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else if (*cursor == '-') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_decr;
+ } else if (*cursor == '>') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_arrow;
+ if (*cursor == '*') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_ptrmem;
+ }
+ } else {
+ token_stream[(int) index++].kind = '-';
+ }
+}
+
+void Lexer::scan_dot()
+{
+ /*
+ '.' ::= dot
+ '...' ::= ellipsis
+ */
+
+ ++cursor;
+ if (*cursor == '.' && *(cursor + 1) == '.') {
+ cursor += 2;
+ token_stream[(int) index++].kind = Token_ellipsis;
+ } else if (*cursor == '.' && *(cursor + 1) == '*') {
+ cursor += 2;
+ token_stream[(int) index++].kind = Token_ptrmem;
+ } else
+ token_stream[(int) index++].kind = '.';
+}
+
+void Lexer::scan_divide()
+{
+ /*
+ '/' ::= divide
+ '/=' ::= divide_equal
+ */
+
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = '/';
+ }
+}
+
+void Lexer::scan_colon()
+{
+ ++cursor;
+ if (*cursor == ':') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_scope;
+ } else {
+ token_stream[(int) index++].kind = ':';
+ }
+}
+
+void Lexer::scan_semicolon()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = ';';
+}
+
+void Lexer::scan_less()
+{
+ /*
+ '<' ::= less
+ '<<' ::= left_shift
+ '<<=' ::= left_shift_equal
+ '<=' ::= less_equal
+ */
+
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_leq;
+ } else if (*cursor == '<') {
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = Token_shift;
+ }
+ } else {
+ token_stream[(int) index++].kind = '<';
+ }
+}
+
+void Lexer::scan_equal()
+{
+ /*
+ '=' ::= equal
+ '==' ::= equal_equal
+ */
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_eq;
+ } else {
+ token_stream[(int) index++].kind = '=';
+ }
+}
+
+void Lexer::scan_greater()
+{
+ /*
+ '>' ::= greater
+ '>=' ::= greater_equal
+ '>>' ::= right_shift
+ '>>=' ::= right_shift_equal
+ */
+
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_geq;
+ } else if (*cursor == '>') {
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = Token_shift;
+ }
+ } else {
+ token_stream[(int) index++].kind = '>';
+ }
+}
+
+void Lexer::scan_question()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '?';
+}
+
+void Lexer::scan_left_bracket()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '[';
+}
+
+void Lexer::scan_right_bracket()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = ']';
+}
+
+void Lexer::scan_xor()
+{
+ /*
+ '^' ::= xor
+ '^=' ::= xor_equal
+ */
+ ++cursor;
+
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else {
+ token_stream[(int) index++].kind = '^';
+ }
+}
+
+void Lexer::scan_left_brace()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '{';
+}
+
+void Lexer::scan_or()
+{
+ /*
+ '|' ::= or
+ '|=' ::= or_equal
+ '||' ::= or_or
+ */
+ ++cursor;
+ if (*cursor == '=') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_assign;
+ } else if (*cursor == '|') {
+ ++cursor;
+ token_stream[(int) index++].kind = Token_or;
+ } else {
+ token_stream[(int) index++].kind = '|';
+ }
+}
+
+void Lexer::scan_right_brace()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '}';
+}
+
+void Lexer::scan_tilde()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = '~';
+}
+
+void Lexer::scan_EOF()
+{
+ ++cursor;
+ token_stream[(int) index++].kind = Token_EOF;
+}
+
+void Lexer::scan_invalid_input()
+{
+ QString errmsg("invalid input: %1");
+ errmsg.arg(int(*cursor));
+ reportError(errmsg);
+ ++cursor;
+}
+
+void LocationTable::positionAt(std::size_t offset, int max_line,
+ int *line, int *column) const
+{
+ if (!(line && column && max_line != 0))
+ return;
+
+ int first = 0;
+ int len = max_line;
+ int half;
+ int middle;
+
+ while (len > 0) {
+ half = len >> 1;
+ middle = first;
+
+ middle += half;
+
+ if (lines[middle] < offset) {
+ first = middle;
+ ++first;
+ len = len - half - 1;
+ } else
+ len = half;
+ }
+
+ *line = std::max(first, 1);
+ *column = (int)(offset - lines[*line - 1] - 1);
+
+ if (*column < 0) {
+ *column = 0;
+ }
+}
+
+void Lexer::scanKeyword0()
+{
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword2()
+{
+ switch (*cursor) {
+ case 'i':
+ if (*(cursor + 1) == 'f') {
+ token_stream[(int) index++].kind = Token_if;
+ return;
+ }
+ break;
+
+ case 'd':
+ if (*(cursor + 1) == 'o') {
+ token_stream[(int) index++].kind = Token_do;
+ return;
+ }
+ break;
+
+ case 'o':
+ if (*(cursor + 1) == 'r') {
+ token_stream[(int) index++].kind = Token_or;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword3()
+{
+ switch (*cursor) {
+ case 'a':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 'd') {
+ token_stream[(int) index++].kind = Token_and;
+ return;
+ }
+ if (*(cursor + 1) == 's' &&
+ *(cursor + 2) == 'm') {
+ token_stream[(int) index++].kind = Token_asm;
+ return;
+ }
+ break;
+
+ case 'f':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'r') {
+ token_stream[(int) index++].kind = Token_for;
+ return;
+ }
+ break;
+
+ case 'i':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 't') {
+ token_stream[(int) index++].kind = Token_int;
+ return;
+ }
+ break;
+
+ case 'n':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'w') {
+ token_stream[(int) index++].kind = Token_new;
+ return;
+ }
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 't') {
+ token_stream[(int) index++].kind = Token_not;
+ return;
+ }
+ break;
+
+ case 't':
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == 'y') {
+ token_stream[(int) index++].kind = Token_try;
+ return;
+ }
+ break;
+
+ case 'x':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'r') {
+ token_stream[(int) index++].kind = Token_xor;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword4()
+{
+ switch (*cursor) {
+ case 'a':
+ if (*(cursor + 1) == 'u' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'o') {
+ token_stream[(int) index++].kind = Token_auto;
+ return;
+ }
+ break;
+
+ case 'c':
+ if (*(cursor + 1) == 'a' &&
+ *(cursor + 2) == 's' &&
+ *(cursor + 3) == 'e') {
+ token_stream[(int) index++].kind = Token_case;
+ return;
+ }
+ if (*(cursor + 1) == 'h' &&
+ *(cursor + 2) == 'a' &&
+ *(cursor + 3) == 'r') {
+ token_stream[(int) index++].kind = Token_char;
+ return;
+ }
+ break;
+
+ case 'b':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'o' &&
+ *(cursor + 3) == 'l') {
+ token_stream[(int) index++].kind = Token_bool;
+ return;
+ }
+ break;
+
+ case 'e':
+ if (*(cursor + 1) == 'l' &&
+ *(cursor + 2) == 's' &&
+ *(cursor + 3) == 'e') {
+ token_stream[(int) index++].kind = Token_else;
+ return;
+ }
+ if (*(cursor + 1) == 'm' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 't') {
+ token_stream[(int) index++].kind = Token_emit;
+ return;
+ }
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 'u' &&
+ *(cursor + 3) == 'm') {
+ token_stream[(int) index++].kind = Token_enum;
+ return;
+ }
+ break;
+
+ case 'g':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'o') {
+ token_stream[(int) index++].kind = Token_goto;
+ return;
+ }
+ break;
+
+ case 'l':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'n' &&
+ *(cursor + 3) == 'g') {
+ token_stream[(int) index++].kind = Token_long;
+ return;
+ }
+ break;
+
+ case 't':
+ if (*(cursor + 1) == 'h' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 's') {
+ token_stream[(int) index++].kind = Token_this;
+ return;
+ }
+ break;
+
+ case 'v':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'd') {
+ token_stream[(int) index++].kind = Token_void;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword5()
+{
+ switch (*cursor) {
+ case 'c':
+ if (*(cursor + 1) == 'a' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'c' &&
+ *(cursor + 4) == 'h') {
+ token_stream[(int) index++].kind = Token_catch;
+ return;
+ }
+ if (*(cursor + 1) == 'l' &&
+ *(cursor + 2) == 'a' &&
+ *(cursor + 3) == 's' &&
+ *(cursor + 4) == 's') {
+ token_stream[(int) index++].kind = Token_class;
+ return;
+ }
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'm' &&
+ *(cursor + 3) == 'p' &&
+ *(cursor + 4) == 'l') {
+ token_stream[(int) index++].kind = Token_compl;
+ return;
+ }
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'n' &&
+ *(cursor + 3) == 's' &&
+ *(cursor + 4) == 't') {
+ token_stream[(int) index++].kind = Token_const;
+ return;
+ }
+ break;
+
+ case 'b':
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'o' &&
+ *(cursor + 4) == 'r') {
+ token_stream[(int) index++].kind = Token_bitor;
+ return;
+ }
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == 'e' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 'k') {
+ token_stream[(int) index++].kind = Token_break;
+ return;
+ }
+ break;
+
+ case 'f':
+ if (*(cursor + 1) == 'l' &&
+ *(cursor + 2) == 'o' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 't') {
+ token_stream[(int) index++].kind = Token_float;
+ return;
+ }
+ break;
+
+ case 'o':
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == '_' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'q') {
+ token_stream[(int) index++].kind = Token_or_eq;
+ return;
+ }
+ break;
+
+ case 's':
+ if (*(cursor + 1) == 'h' &&
+ *(cursor + 2) == 'o' &&
+ *(cursor + 3) == 'r' &&
+ *(cursor + 4) == 't') {
+ token_stream[(int) index++].kind = Token_short;
+ return;
+ }
+ if (*(cursor + 1) == 'l' &&
+ *(cursor + 2) == 'o' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 's') {
+ token_stream[(int) index++].kind = Token_slots;
+ return;
+ }
+ break;
+
+ case 'u':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'o' &&
+ *(cursor + 4) == 'n') {
+ token_stream[(int) index++].kind = Token_union;
+ return;
+ }
+ if (*(cursor + 1) == 's' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'n' &&
+ *(cursor + 4) == 'g') {
+ token_stream[(int) index++].kind = Token_using;
+ return;
+ }
+ break;
+
+ case 't':
+ if (*(cursor + 1) == 'h' &&
+ *(cursor + 2) == 'r' &&
+ *(cursor + 3) == 'o' &&
+ *(cursor + 4) == 'w') {
+ token_stream[(int) index++].kind = Token_throw;
+ return;
+ }
+ break;
+
+ case 'w':
+ if (*(cursor + 1) == 'h' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'l' &&
+ *(cursor + 4) == 'e') {
+ token_stream[(int) index++].kind = Token_while;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword6()
+{
+ switch (*cursor) {
+ case 'a':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 'd' &&
+ *(cursor + 3) == '_' &&
+ *(cursor + 4) == 'e' &&
+ *(cursor + 5) == 'q') {
+ token_stream[(int) index++].kind = Token_and_eq;
+ return;
+ }
+ break;
+
+ case 'b':
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 'n' &&
+ *(cursor + 5) == 'd') {
+ token_stream[(int) index++].kind = Token_bitand;
+ return;
+ }
+ break;
+
+ case 'e':
+ if (*(cursor + 1) == 'x' &&
+ *(cursor + 2) == 'p' &&
+ *(cursor + 3) == 'o' &&
+ *(cursor + 4) == 'r' &&
+ *(cursor + 5) == 't') {
+ token_stream[(int) index++].kind = Token_export;
+ return;
+ }
+ if (*(cursor + 1) == 'x' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'r' &&
+ *(cursor + 5) == 'n') {
+ token_stream[(int) index++].kind = Token_extern;
+ return;
+ }
+ break;
+
+ case 'd':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'l' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 't' &&
+ *(cursor + 5) == 'e') {
+ token_stream[(int) index++].kind = Token_delete;
+ return;
+ }
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'u' &&
+ *(cursor + 3) == 'b' &&
+ *(cursor + 4) == 'l' &&
+ *(cursor + 5) == 'e') {
+ token_stream[(int) index++].kind = Token_double;
+ return;
+ }
+ break;
+
+ case 'f':
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'n' &&
+ *(cursor + 5) == 'd') {
+ token_stream[(int) index++].kind = Token_friend;
+ return;
+ }
+ break;
+
+ case 'i':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 'l' &&
+ *(cursor + 3) == 'i' &&
+ *(cursor + 4) == 'n' &&
+ *(cursor + 5) == 'e') {
+ token_stream[(int) index++].kind = Token_inline;
+ return;
+ }
+ break;
+
+ case 'K':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'D' &&
+ *(cursor + 3) == 'C' &&
+ *(cursor + 4) == 'O' &&
+ *(cursor + 5) == 'P') {
+ token_stream[(int) index++].kind = Token_K_DCOP;
+ return;
+ }
+ break;
+
+ case 'n':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == '_' &&
+ *(cursor + 4) == 'e' &&
+ *(cursor + 5) == 'q') {
+ token_stream[(int) index++].kind = Token_not_eq;
+ return;
+ }
+ break;
+
+ case 'p':
+ if (*(cursor + 1) == 'u' &&
+ *(cursor + 2) == 'b' &&
+ *(cursor + 3) == 'l' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'c') {
+ token_stream[(int) index++].kind = Token_public;
+ return;
+ }
+ break;
+
+ case 's':
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 'g' &&
+ *(cursor + 3) == 'n' &&
+ *(cursor + 4) == 'e' &&
+ *(cursor + 5) == 'd') {
+ token_stream[(int) index++].kind = Token_signed;
+ return;
+ }
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 'z' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'o' &&
+ *(cursor + 5) == 'f') {
+ token_stream[(int) index++].kind = Token_sizeof;
+ return;
+ }
+ if (*(cursor + 1) == 't' &&
+ *(cursor + 2) == 'a' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'c') {
+ token_stream[(int) index++].kind = Token_static;
+ return;
+ }
+ if (*(cursor + 1) == 't' &&
+ *(cursor + 2) == 'r' &&
+ *(cursor + 3) == 'u' &&
+ *(cursor + 4) == 'c' &&
+ *(cursor + 5) == 't') {
+ token_stream[(int) index++].kind = Token_struct;
+ return;
+ }
+ if (*(cursor + 1) == 'w' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'c' &&
+ *(cursor + 5) == 'h') {
+ token_stream[(int) index++].kind = Token_switch;
+ return;
+ }
+ break;
+
+ case 'r':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'u' &&
+ *(cursor + 4) == 'r' &&
+ *(cursor + 5) == 'n') {
+ token_stream[(int) index++].kind = Token_return;
+ return;
+ }
+ break;
+
+ case 't':
+ if (*(cursor + 1) == 'y' &&
+ *(cursor + 2) == 'p' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'd') {
+ token_stream[(int) index++].kind = Token_typeid;
+ return;
+ }
+ break;
+
+ case 'x':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'r' &&
+ *(cursor + 3) == '_' &&
+ *(cursor + 4) == 'e' &&
+ *(cursor + 5) == 'q') {
+ token_stream[(int) index++].kind = Token_xor_eq;
+ return;
+ }
+ break;
+
+ case 'k':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'd' &&
+ *(cursor + 3) == 'c' &&
+ *(cursor + 4) == 'o' &&
+ *(cursor + 5) == 'p') {
+ token_stream[(int) index++].kind = Token_k_dcop;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword7()
+{
+ switch (*cursor) {
+ case 'd':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'f' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 'u' &&
+ *(cursor + 5) == 'l' &&
+ *(cursor + 6) == 't') {
+ token_stream[(int) index++].kind = Token_default;
+ return;
+ }
+ break;
+
+ case 'm':
+ if (*(cursor + 1) == 'u' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 'b' &&
+ *(cursor + 5) == 'l' &&
+ *(cursor + 6) == 'e') {
+ token_stream[(int) index++].kind = Token_mutable;
+ return;
+ }
+ break;
+
+ case 'p':
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'v' &&
+ *(cursor + 4) == 'a' &&
+ *(cursor + 5) == 't' &&
+ *(cursor + 6) == 'e') {
+ token_stream[(int) index++].kind = Token_private;
+ return;
+ }
+ break;
+ case 's':
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 'g' &&
+ *(cursor + 3) == 'n' &&
+ *(cursor + 4) == 'a' &&
+ *(cursor + 5) == 'l' &&
+ *(cursor + 6) == 's') {
+ token_stream[(int) index++].kind = Token_signals;
+ return;
+ }
+ break;
+ case 't':
+ if (*(cursor + 1) == 'y' &&
+ *(cursor + 2) == 'p' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'd' &&
+ *(cursor + 5) == 'e' &&
+ *(cursor + 6) == 'f') {
+ token_stream[(int) index++].kind = Token_typedef;
+ return;
+ }
+ break;
+
+ case 'v':
+ if (*(cursor + 1) == 'i' &&
+ *(cursor + 2) == 'r' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'u' &&
+ *(cursor + 5) == 'a' &&
+ *(cursor + 6) == 'l') {
+ token_stream[(int) index++].kind = Token_virtual;
+ return;
+ }
+ break;
+
+ case 'Q':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'E' &&
+ *(cursor + 3) == 'N' &&
+ *(cursor + 4) == 'U' &&
+ *(cursor + 5) == 'M' &&
+ *(cursor + 6) == 'S') {
+ token_stream[(int) index++].kind = Token_Q_ENUMS;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword8()
+{
+ switch (*cursor) {
+ case '_':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 't' &&
+ *(cursor + 3) == 'y' &&
+ *(cursor + 4) == 'p' &&
+ *(cursor + 5) == 'e' &&
+ *(cursor + 6) == 'o' &&
+ *(cursor + 7) == 'f') {
+ token_stream[(int) index++].kind = Token___typeof;
+ return;
+ }
+ break;
+
+ case 'c':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'n' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'n' &&
+ *(cursor + 6) == 'u' &&
+ *(cursor + 7) == 'e') {
+ token_stream[(int) index++].kind = Token_continue;
+ return;
+ }
+ break;
+
+ case 'e':
+ if (*(cursor + 1) == 'x' &&
+ *(cursor + 2) == 'p' &&
+ *(cursor + 3) == 'l' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'c' &&
+ *(cursor + 6) == 'i' &&
+ *(cursor + 7) == 't') {
+ token_stream[(int) index++].kind = Token_explicit;
+ return;
+ }
+ break;
+
+ case 'o':
+ if (*(cursor + 1) == 'p' &&
+ *(cursor + 2) == 'e' &&
+ *(cursor + 3) == 'r' &&
+ *(cursor + 4) == 'a' &&
+ *(cursor + 5) == 't' &&
+ *(cursor + 6) == 'o' &&
+ *(cursor + 7) == 'r') {
+ token_stream[(int) index++].kind = Token_operator;
+ return;
+ }
+ break;
+
+ case 'Q':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'O' &&
+ *(cursor + 3) == 'B' &&
+ *(cursor + 4) == 'J' &&
+ *(cursor + 5) == 'E' &&
+ *(cursor + 6) == 'C' &&
+ *(cursor + 7) == 'T') {
+ token_stream[(int) index++].kind = Token_Q_OBJECT;
+ return;
+ }
+ break;
+
+ case 'r':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'g' &&
+ *(cursor + 3) == 'i' &&
+ *(cursor + 4) == 's' &&
+ *(cursor + 5) == 't' &&
+ *(cursor + 6) == 'e' &&
+ *(cursor + 7) == 'r') {
+ token_stream[(int) index++].kind = Token_register;
+ return;
+ }
+ break;
+
+ case 'u':
+ if (*(cursor + 1) == 'n' &&
+ *(cursor + 2) == 's' &&
+ *(cursor + 3) == 'i' &&
+ *(cursor + 4) == 'g' &&
+ *(cursor + 5) == 'n' &&
+ *(cursor + 6) == 'e' &&
+ *(cursor + 7) == 'd') {
+ token_stream[(int) index++].kind = Token_unsigned;
+ return;
+ }
+ break;
+
+ case 't':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'm' &&
+ *(cursor + 3) == 'p' &&
+ *(cursor + 4) == 'l' &&
+ *(cursor + 5) == 'a' &&
+ *(cursor + 6) == 't' &&
+ *(cursor + 7) == 'e') {
+ token_stream[(int) index++].kind = Token_template;
+ return;
+ }
+ if (*(cursor + 1) == 'y' &&
+ *(cursor + 2) == 'p' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 'n' &&
+ *(cursor + 5) == 'a' &&
+ *(cursor + 6) == 'm' &&
+ *(cursor + 7) == 'e') {
+ token_stream[(int) index++].kind = Token_typename;
+ return;
+ }
+ break;
+
+ case 'v':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'l' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 't' &&
+ *(cursor + 5) == 'i' &&
+ *(cursor + 6) == 'l' &&
+ *(cursor + 7) == 'e') {
+ token_stream[(int) index++].kind = Token_volatile;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword9()
+{
+ switch (*cursor) {
+ case 'p':
+ if (*(cursor + 1) == 'r' &&
+ *(cursor + 2) == 'o' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'e' &&
+ *(cursor + 5) == 'c' &&
+ *(cursor + 6) == 't' &&
+ *(cursor + 7) == 'e' &&
+ *(cursor + 8) == 'd') {
+ token_stream[(int) index++].kind = Token_protected;
+ return;
+ }
+ break;
+
+ case 'n':
+ if (*(cursor + 1) == 'a' &&
+ *(cursor + 2) == 'm' &&
+ *(cursor + 3) == 'e' &&
+ *(cursor + 4) == 's' &&
+ *(cursor + 5) == 'p' &&
+ *(cursor + 6) == 'a' &&
+ *(cursor + 7) == 'c' &&
+ *(cursor + 8) == 'e') {
+ token_stream[(int) index++].kind = Token_namespace;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword10()
+{
+ switch (*cursor) {
+ case 'c':
+ if (*(cursor + 1) == 'o' &&
+ *(cursor + 2) == 'n' &&
+ *(cursor + 3) == 's' &&
+ *(cursor + 4) == 't' &&
+ *(cursor + 5) == '_' &&
+ *(cursor + 6) == 'c' &&
+ *(cursor + 7) == 'a' &&
+ *(cursor + 8) == 's' &&
+ *(cursor + 9) == 't') {
+ token_stream[(int) index++].kind = Token_const_cast;
+ return;
+ }
+ break;
+
+ case 'Q':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'P' &&
+ *(cursor + 3) == 'R' &&
+ *(cursor + 4) == 'O' &&
+ *(cursor + 5) == 'P' &&
+ *(cursor + 6) == 'E' &&
+ *(cursor + 7) == 'R' &&
+ *(cursor + 8) == 'T' &&
+ *(cursor + 9) == 'Y') {
+ token_stream[(int) index++].kind = Token_Q_PROPERTY;
+ return;
+ }
+
+ break;
+ }
+
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword11()
+{
+ switch (*cursor) {
+ case 'Q':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'I' &&
+ *(cursor + 3) == 'N' &&
+ *(cursor + 4) == 'V' &&
+ *(cursor + 5) == 'O' &&
+ *(cursor + 6) == 'K' &&
+ *(cursor + 7) == 'A' &&
+ *(cursor + 8) == 'B' &&
+ *(cursor + 9) == 'L' &&
+ *(cursor + 10) == 'E') {
+ token_stream[(int) index++].kind = Token_Q_INVOKABLE;
+ return;
+ }
+ break;
+
+ case 's':
+ if (*(cursor + 1) == 't' &&
+ *(cursor + 2) == 'a' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 'i' &&
+ *(cursor + 5) == 'c' &&
+ *(cursor + 6) == '_' &&
+ *(cursor + 7) == 'c' &&
+ *(cursor + 8) == 'a' &&
+ *(cursor + 9) == 's' &&
+ *(cursor + 10) == 't') {
+ token_stream[(int) index++].kind = Token_static_cast;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword12()
+{
+ switch (*cursor) {
+ case 'd':
+ if (*(cursor + 1) == 'y' &&
+ *(cursor + 2) == 'n' &&
+ *(cursor + 3) == 'a' &&
+ *(cursor + 4) == 'm' &&
+ *(cursor + 5) == 'i' &&
+ *(cursor + 6) == 'c' &&
+ *(cursor + 7) == '_' &&
+ *(cursor + 8) == 'c' &&
+ *(cursor + 9) == 'a' &&
+ *(cursor + 10) == 's' &&
+ *(cursor + 11) == 't') {
+ token_stream[(int) index++].kind = Token_dynamic_cast;
+ return;
+ }
+ break;
+
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword13()
+{
+ switch (*cursor) {
+ case '_':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'a' &&
+ *(cursor + 3) == 't' &&
+ *(cursor + 4) == 't' &&
+ *(cursor + 5) == 'r' &&
+ *(cursor + 6) == 'i' &&
+ *(cursor + 7) == 'b' &&
+ *(cursor + 8) == 'u' &&
+ *(cursor + 9) == 't' &&
+ *(cursor + 10) == 'e' &&
+ *(cursor + 11) == '_' &&
+ *(cursor + 12) == '_') {
+ token_stream[(int) index++].kind = Token___attribute__;
+ return;
+ }
+ break;
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword14()
+{
+ switch (*cursor) {
+ case 'k':
+ if (*(cursor + 1) == '_' &&
+ *(cursor + 2) == 'd' &&
+ *(cursor + 3) == 'c' &&
+ *(cursor + 4) == 'o' &&
+ *(cursor + 5) == 'p' &&
+ *(cursor + 6) == '_' &&
+ *(cursor + 7) == 's' &&
+ *(cursor + 8) == 'i' &&
+ *(cursor + 9) == 'g' &&
+ *(cursor + 10) == 'n' &&
+ *(cursor + 11) == 'a' &&
+ *(cursor + 12) == 'l' &&
+ *(cursor + 13) == 's') {
+ token_stream[(int) index++].kind = Token_k_dcop_signals;
+ return;
+ }
+ break;
+ }
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+void Lexer::scanKeyword16()
+{
+ switch (*cursor) {
+ case 'r':
+ if (*(cursor + 1) == 'e' &&
+ *(cursor + 2) == 'i' &&
+ *(cursor + 3) == 'n' &&
+ *(cursor + 4) == 't' &&
+ *(cursor + 5) == 'e' &&
+ *(cursor + 6) == 'r' &&
+ *(cursor + 7) == 'p' &&
+ *(cursor + 8) == 'r' &&
+ *(cursor + 9) == 'e' &&
+ *(cursor + 10) == 't' &&
+ *(cursor + 11) == '_' &&
+ *(cursor + 12) == 'c' &&
+ *(cursor + 13) == 'a' &&
+ *(cursor + 14) == 's' &&
+ *(cursor + 15) == 't') {
+ token_stream[(int) index++].kind = Token_reinterpret_cast;
+ return;
+ }
+ break;
+ }
+
+ token_stream[(int) index++].kind = Token_identifier;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/lexer.h b/parser/lexer.h
new file mode 100644
index 000000000..874805325
--- /dev/null
+++ b/parser/lexer.h
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "symbol.h"
+
+#include <QtCore/QString>
+#include <cstdlib>
+#include <cassert>
+
+struct NameSymbol;
+class Lexer;
+class Control;
+
+typedef void (Lexer::*scan_fun_ptr)();
+
+class Token
+{
+public:
+ int kind;
+ std::size_t position;
+ std::size_t size;
+ char const *text;
+
+ union {
+ const NameSymbol *symbol;
+ std::size_t right_brace;
+ } extra;
+};
+
+class LocationTable
+{
+private:
+ LocationTable(const LocationTable &source);
+ void operator = (const LocationTable &source);
+
+public:
+ inline LocationTable(std::size_t size = 1024)
+ : lines(0),
+ line_count(0),
+ current_line(0) {
+ resize(size);
+ }
+
+ inline ~LocationTable() {
+ free(lines);
+ }
+
+ inline std::size_t size() const {
+ return line_count;
+ }
+
+ void resize(std::size_t size) {
+ Q_ASSERT(size > 0);
+ lines = (std::size_t*) ::realloc(lines, sizeof(std::size_t) * size);
+ line_count = size;
+ }
+
+ void positionAt(std::size_t offset, int *line, int *column) const {
+ positionAt(offset, (int) current_line, line, column);
+ }
+
+ void positionAt(std::size_t offset, int max_line, int *line, int *column) const;
+
+ inline std::size_t &operator[](int index) {
+ return lines[index];
+ }
+
+private:
+ std::size_t *lines;
+ std::size_t line_count;
+ std::size_t current_line;
+
+ friend class Lexer;
+};
+
+class TokenStream
+{
+private:
+ TokenStream(const TokenStream &);
+ void operator = (const TokenStream &);
+
+public:
+ inline TokenStream(std::size_t size = 1024)
+ : tokens(0),
+ index(0),
+ token_count(0) {
+ resize(size);
+ }
+
+ inline ~TokenStream() {
+ ::free(tokens);
+ }
+
+ inline std::size_t size() const {
+ return token_count;
+ }
+
+ inline std::size_t cursor() const {
+ return index;
+ }
+
+ inline void rewind(int i) {
+ index = i;
+ }
+
+ void resize(std::size_t size) {
+ Q_ASSERT(size > 0);
+ tokens = (Token*) ::realloc(tokens, sizeof(Token) * size);
+ token_count = size;
+ }
+
+ inline std::size_t nextToken() {
+ return index++;
+ }
+
+ inline int lookAhead(std::size_t i = 0) const {
+ return tokens[index + i].kind;
+ }
+
+ inline int kind(std::size_t i) const {
+ return tokens[i].kind;
+ }
+
+ inline std::size_t position(std::size_t i) const {
+ return tokens[i].position;
+ }
+
+ inline const NameSymbol *symbol(std::size_t i) const {
+ return tokens[i].extra.symbol;
+ }
+
+ inline std::size_t matchingBrace(std::size_t i) const {
+ return tokens[i].extra.right_brace;
+ }
+
+ inline Token &operator[](int index) {
+ return tokens[index];
+ }
+
+ inline const Token &token(int index) const {
+ return tokens[index];
+ }
+
+private:
+ Token *tokens;
+ std::size_t index;
+ std::size_t token_count;
+
+private:
+ friend class Lexer;
+};
+
+class LocationManager
+{
+ LocationManager(LocationManager const &__other);
+ void operator = (LocationManager const &__other);
+
+public:
+ LocationManager(TokenStream &__token_stream,
+ LocationTable &__location_table,
+ LocationTable &__line_table):
+ token_stream(__token_stream),
+ location_table(__location_table),
+ line_table(__line_table) {}
+
+ void positionAt(std::size_t offset, int *line, int *column,
+ QString *filename) const;
+
+ void extract_line(int offset, int *line, QString *filename) const;
+
+ TokenStream &token_stream;
+ LocationTable &location_table;
+ LocationTable &line_table;
+};
+
+class Lexer
+{
+public:
+ Lexer(LocationManager &__location, Control *__control):
+ _M_location(__location),
+ token_stream(_M_location.token_stream),
+ location_table(_M_location.location_table),
+ line_table(_M_location.line_table),
+ control(__control) {}
+
+ void tokenize(const char *contents, std::size_t size);
+
+ LocationManager &_M_location;
+ TokenStream &token_stream;
+ LocationTable &location_table;
+ LocationTable &line_table;
+
+private:
+ void reportError(const QString& msg);
+
+ void initialize_scan_table();
+ void scan_newline();
+ void scan_white_spaces();
+ void scan_identifier_or_keyword();
+ void scan_identifier_or_literal();
+ void scan_int_constant();
+ void scan_char_constant();
+ void scan_string_constant();
+ void scan_invalid_input();
+ void scan_preprocessor();
+
+ // keywords
+ void scanKeyword0();
+ void scanKeyword2();
+ void scanKeyword3();
+ void scanKeyword4();
+ void scanKeyword5();
+ void scanKeyword6();
+ void scanKeyword7();
+ void scanKeyword8();
+ void scanKeyword9();
+ void scanKeyword10();
+ void scanKeyword11();
+ void scanKeyword12();
+ void scanKeyword13();
+ void scanKeyword14();
+ void scanKeyword16();
+
+ // operators
+ void scan_not();
+ void scan_remainder();
+ void scan_and();
+ void scan_left_paren();
+ void scan_right_paren();
+ void scan_star();
+ void scan_plus();
+ void scan_comma();
+ void scan_minus();
+ void scan_dot();
+ void scan_divide();
+ void scan_colon();
+ void scan_semicolon();
+ void scan_less();
+ void scan_equal();
+ void scan_greater();
+ void scan_question();
+ void scan_left_bracket();
+ void scan_right_bracket();
+ void scan_xor();
+ void scan_left_brace();
+ void scan_or();
+ void scan_right_brace();
+ void scan_tilde();
+ void scan_EOF();
+
+private:
+ Control *control;
+ const unsigned char *cursor;
+ const unsigned char *begin_buffer;
+ const unsigned char *end_buffer;
+ std::size_t index;
+
+ static scan_fun_ptr s_scan_table[];
+ static scan_fun_ptr s_scan_keyword_table[];
+ static bool s_initialized;
+};
+
+#endif // LEXER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/list.cpp b/parser/list.cpp
new file mode 100644
index 000000000..7482b7392
--- /dev/null
+++ b/parser/list.cpp
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "list.h"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/list.h b/parser/list.h
new file mode 100644
index 000000000..64aef452f
--- /dev/null
+++ b/parser/list.h
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef FASTLIST_H
+#define FASTLIST_H
+
+#include "smallobject.h"
+
+template <typename Tp>
+struct ListNode {
+ Tp element;
+ int index;
+ mutable const ListNode<Tp> *next;
+
+ static ListNode *create(const Tp &element, pool *p) {
+ ListNode<Tp> *node = new(p->allocate(sizeof(ListNode))) ListNode();
+ node->element = element;
+ node->index = 0;
+ node->next = node;
+
+ return node;
+ }
+
+ static ListNode *create(const ListNode *n1, const Tp &element, pool *p) {
+ ListNode<Tp> *n2 = ListNode::create(element, p);
+
+ n2->index = n1->index + 1;
+ n2->next = n1->next;
+ n1->next = n2;
+
+ return n2;
+ }
+
+ inline ListNode<Tp>() { }
+
+ inline const ListNode<Tp> *at(int index) const {
+ const ListNode<Tp> *node = this;
+ while (index != node->index)
+ node = node->next;
+
+ return node;
+ }
+
+ inline bool hasNext() const {
+ return index < next->index;
+ }
+
+ inline int count() const {
+ return 1 + toBack()->index;
+ }
+
+ inline const ListNode<Tp> *toFront() const {
+ return toBack()->next;
+ }
+
+ inline const ListNode<Tp> *toBack() const {
+ const ListNode<Tp> *node = this;
+ while (node->hasNext())
+ node = node->next;
+
+ return node;
+ }
+};
+
+template <class Tp>
+inline const ListNode<Tp> *snoc(const ListNode<Tp> *list,
+ const Tp &element, pool *p)
+{
+ if (!list)
+ return ListNode<Tp>::create(element, p);
+
+ return ListNode<Tp>::create(list->toBack(), element, p);
+}
+
+#endif // FASTLIST_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/name_compiler.cpp b/parser/name_compiler.cpp
new file mode 100644
index 000000000..4dbd516d6
--- /dev/null
+++ b/parser/name_compiler.cpp
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "name_compiler.h"
+#include "type_compiler.h"
+#include "declarator_compiler.h"
+#include "lexer.h"
+#include "symbol.h"
+#include "binder.h"
+
+#include <QtCore/qdebug.h>
+
+NameCompiler::NameCompiler(Binder *binder)
+ : _M_binder(binder), _M_token_stream(binder->tokenStream())
+{
+}
+
+QString NameCompiler::decode_operator(std::size_t index) const
+{
+ const Token &tk = _M_token_stream->token((int) index);
+ return QString::fromUtf8(&tk.text[tk.position], (int) tk.size);
+}
+
+QString NameCompiler::internal_run(AST *node)
+{
+ _M_name.clear();
+ visit(node);
+ return name();
+}
+
+void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node)
+{
+ QString tmp_name;
+
+ if (node->tilde)
+ tmp_name += QLatin1String("~");
+
+ if (node->id)
+ tmp_name += _M_token_stream->symbol(node->id)->as_string();
+
+ if (OperatorFunctionIdAST *op_id = node->operator_id) {
+#if defined(__GNUC__)
+#warning "NameCompiler::visitUnqualifiedName() -- implement me"
+#endif
+
+ if (op_id->op && op_id->op->op) {
+ tmp_name += QLatin1String("operator");
+ tmp_name += decode_operator(op_id->op->op);
+ if (op_id->op->close)
+ tmp_name += decode_operator(op_id->op->close);
+ } else if (op_id->type_specifier) {
+#if defined(__GNUC__)
+#warning "don't use an hardcoded string as cast' name"
+#endif
+ Token const &tk = _M_token_stream->token((int) op_id->start_token);
+ Token const &end_tk = _M_token_stream->token((int) op_id->end_token);
+ tmp_name += QString::fromLatin1(&tk.text[tk.position],
+ (int)(end_tk.position - tk.position)).trimmed();
+ }
+ }
+
+ _M_name += tmp_name;
+ if (node->template_arguments) {
+ // ### cleanup
+ _M_name.last() += QLatin1String("<");
+ visitNodes(this, node->template_arguments);
+ _M_name.last().truncate(_M_name.last().count() - 1); // remove the last ','
+ _M_name.last() += QLatin1String(">");
+ }
+
+}
+
+void NameCompiler::visitTemplateArgument(TemplateArgumentAST *node)
+{
+ if (node->type_id && node->type_id->type_specifier) {
+ TypeCompiler type_cc(_M_binder);
+ type_cc.run(node->type_id->type_specifier);
+
+ DeclaratorCompiler decl_cc(_M_binder);
+ decl_cc.run(node->type_id->declarator);
+
+ if (type_cc.isConstant())
+ _M_name.last() += "const ";
+
+ QStringList q = type_cc.qualifiedName();
+
+ if (q.count() == 1) {
+#if defined (RXX_RESOLVE_TYPEDEF) // ### it'll break :(
+ TypeInfo tp;
+ tp.setQualifiedName(q);
+ tp = TypeInfo::resolveType(tp, _M_binder->currentScope()->toItem());
+ q = tp.qualifiedName();
+#endif
+
+ if (CodeModelItem item = _M_binder->model()->findItem(q, _M_binder->currentScope()->toItem())) {
+ if (item->name() == q.last())
+ q = item->qualifiedName();
+ }
+ }
+
+ _M_name.last() += q.join("::");
+
+ if (decl_cc.isReference())
+ _M_name.last() += "&";
+ if (decl_cc.indirection())
+ _M_name.last() += QString(decl_cc.indirection(), '*');
+
+ _M_name.last() += QLatin1String(",");
+ }
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/name_compiler.h b/parser/name_compiler.h
new file mode 100644
index 000000000..66cabaccf
--- /dev/null
+++ b/parser/name_compiler.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef NAME_COMPILER_H
+#define NAME_COMPILER_H
+
+#include "default_visitor.h"
+#include <QtCore/QStringList>
+
+class TokenStream;
+class Binder;
+
+class NameCompiler: protected DefaultVisitor
+{
+public:
+ NameCompiler(Binder *binder);
+
+ void run(NameAST *node) {
+ internal_run(node);
+ }
+ void run(UnqualifiedNameAST *node) {
+ internal_run(node);
+ }
+
+ QString name() const {
+ return _M_name.join("::");
+ }
+ QStringList qualifiedName() const {
+ return _M_name;
+ }
+
+protected:
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *node);
+ virtual void visitTemplateArgument(TemplateArgumentAST *node);
+
+ QString internal_run(AST *node);
+ QString decode_operator(std::size_t index) const;
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QStringList _M_name;
+};
+
+#endif // NAME_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/parser.cpp b/parser/parser.cpp
new file mode 100644
index 000000000..d65d5f3e4
--- /dev/null
+++ b/parser/parser.cpp
@@ -0,0 +1,4056 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+
+// c++ support
+#include "parser.h"
+#include "tokens.h"
+#include "lexer.h"
+#include "control.h"
+
+#include <cstdlib>
+
+#define ADVANCE(tk, descr) \
+ { \
+ if (token_stream.lookAhead() != tk) { \
+ tokenRequiredError(tk); \
+ return false; \
+ } \
+ token_stream.nextToken(); \
+ }
+
+#define ADVANCE_NR(tk, descr) \
+ do { \
+ if (token_stream.lookAhead() != tk) { \
+ tokenRequiredError(tk); \
+ } \
+ else \
+ token_stream.nextToken(); \
+ } while (0)
+
+#define CHECK(tk) \
+ do { \
+ if (token_stream.lookAhead() != tk) { \
+ return false; \
+ } \
+ token_stream.nextToken(); \
+ } while (0)
+
+#define UPDATE_POS(_node, start, end) \
+ do { \
+ (_node)->start_token = start; \
+ (_node)->end_token = end; \
+ } while (0)
+
+Parser::Parser(Control *c)
+ : _M_location(token_stream, location_table, line_table),
+ control(c),
+ lexer(_M_location, control)
+{
+ _M_block_errors = false;
+}
+
+Parser::~Parser()
+{
+}
+
+void Parser::advance()
+{
+ token_stream.nextToken();
+}
+
+TranslationUnitAST *Parser::parse(const char *contents,
+ std::size_t size, pool *p)
+{
+ _M_block_errors = false;
+ _M_pool = p;
+ lexer.tokenize(contents, size);
+ token_stream.nextToken(); // skip the first token
+
+ Lexer *oldLexer = control->changeLexer(&lexer);
+ Parser *oldParser = control->changeParser(this);
+
+ TranslationUnitAST *ast = 0;
+ parseTranslationUnit(ast);
+
+ control->changeLexer(oldLexer);
+ control->changeParser(oldParser);
+
+ return ast;
+}
+
+bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node)
+{
+ if (token_stream.lookAhead() != Token_identifier)
+ return false;
+
+ std::size_t start = token_stream.cursor();
+
+ const NameSymbol *name_symbol = token_stream.symbol(token_stream.cursor());
+ QString name = name_symbol->as_string();
+ if (name != QLatin1String("__declspec"))
+ return false;
+ std::size_t specifier = token_stream.cursor();
+
+ token_stream.nextToken();
+ if (token_stream.lookAhead() != '(')
+ return false;
+
+ token_stream.nextToken();
+ if (token_stream.lookAhead() != Token_identifier)
+ return false;
+ std::size_t modifier = token_stream.cursor();
+
+ token_stream.nextToken();
+ if (token_stream.lookAhead() != ')')
+ return false;
+
+ token_stream.nextToken();
+
+ node = CreateNode<WinDeclSpecAST>(_M_pool);
+ node->specifier = specifier;
+ node->modifier = modifier;
+
+ UPDATE_POS(node, start, token_stream.cursor());
+
+ return true;
+}
+
+void Parser::tokenRequiredError(int token)
+{
+ QString err;
+
+ err += "expected token ";
+ err += "``";
+ err += token_name(token);
+ err += "'' found ``";
+ err += token_name(token_stream.lookAhead());
+ err += "''";
+
+ reportError(err);
+}
+
+void Parser::syntaxError()
+{
+ QString err;
+
+ err += "unexpected token ";
+ err += "``";
+ err += token_name(token_stream.lookAhead());
+ err += "''";
+
+ reportError(err);
+}
+
+void Parser::reportError(const QString& msg)
+{
+ if (!_M_block_errors) {
+ int line, column;
+ QString fileName;
+
+ std::size_t tok = token_stream.cursor();
+ location().positionAt(token_stream.position(tok),
+ &line, &column, &fileName);
+
+ Control::ErrorMessage errmsg;
+ errmsg.setLine(line + 1);
+ errmsg.setColumn(column);
+ errmsg.setFileName(fileName);
+ errmsg.setMessage(QLatin1String("** PARSER ERROR ") + msg);
+ control->reportError(errmsg);
+ }
+}
+
+bool Parser::skipUntil(int token)
+{
+ while (token_stream.lookAhead()) {
+ if (token_stream.lookAhead() == token)
+ return true;
+
+ token_stream.nextToken();
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilDeclaration()
+{
+ while (token_stream.lookAhead()) {
+
+ switch (token_stream.lookAhead()) {
+ case ';':
+ case '~':
+ case Token_scope:
+ case Token_identifier:
+ case Token_operator:
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ case Token_extern:
+ case Token_namespace:
+ case Token_using:
+ case Token_typedef:
+ case Token_asm:
+ case Token_template:
+ case Token_export:
+
+ case Token_const: // cv
+ case Token_volatile: // cv
+
+ case Token_public:
+ case Token_protected:
+ case Token_private:
+ case Token_signals: // Qt
+ case Token_slots: // Qt
+ return true;
+
+ default:
+ token_stream.nextToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilStatement()
+{
+ while (token_stream.lookAhead()) {
+ switch (token_stream.lookAhead()) {
+ case ';':
+ case '{':
+ case '}':
+ case Token_const:
+ case Token_volatile:
+ case Token_identifier:
+ case Token_case:
+ case Token_default:
+ case Token_if:
+ case Token_switch:
+ case Token_while:
+ case Token_do:
+ case Token_for:
+ case Token_break:
+ case Token_continue:
+ case Token_return:
+ case Token_goto:
+ case Token_try:
+ case Token_catch:
+ case Token_throw:
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ case Token_class:
+ case Token_struct:
+ case Token_union:
+ case Token_enum:
+ case Token_scope:
+ case Token_template:
+ case Token_using:
+ return true;
+
+ default:
+ token_stream.nextToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skip(int l, int r)
+{
+ int count = 0;
+ while (token_stream.lookAhead()) {
+ int tk = token_stream.lookAhead();
+
+ if (tk == l)
+ ++count;
+ else if (tk == r)
+ --count;
+ else if (l != '{' && (tk == '{' || tk == '}' || tk == ';'))
+ return false;
+
+ if (!count)
+ return true;
+
+ token_stream.nextToken();
+ }
+
+ return false;
+}
+
+bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
+{
+ std::size_t start = token_stream.cursor();
+
+ WinDeclSpecAST *winDeclSpec = 0;
+ parseWinDeclSpec(winDeclSpec);
+
+ NameAST *ast = CreateNode<NameAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_scope) {
+ ast->global = true;
+ token_stream.nextToken();
+ }
+
+ std::size_t idx = token_stream.cursor();
+
+ while (true) {
+ UnqualifiedNameAST *n = 0;
+ if (!parseUnqualifiedName(n))
+ return false;
+
+ if (token_stream.lookAhead() == Token_scope) {
+ token_stream.nextToken();
+
+ ast->qualified_names
+ = snoc(ast->qualified_names, n, _M_pool);
+
+ if (token_stream.lookAhead() == Token_template) {
+ /// skip optional template #### @todo CHECK
+ token_stream.nextToken();
+ }
+ } else {
+ Q_ASSERT(n);
+ if (!acceptTemplateId) {
+ token_stream.rewind((int) n->start_token);
+ parseUnqualifiedName(n, false);
+ }
+
+ ast->unqualified_name = n;
+ break;
+ }
+ }
+
+ if (idx == token_stream.cursor())
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+ TranslationUnitAST *ast = CreateNode<TranslationUnitAST>(_M_pool);
+
+ while (token_stream.lookAhead()) {
+ std::size_t startDecl = token_stream.cursor();
+
+ DeclarationAST *declaration = 0;
+ if (parseDeclaration(declaration)) {
+ ast->declarations =
+ snoc(ast->declarations, declaration, _M_pool);
+ } else {
+ // error recovery
+ if (startDecl == token_stream.cursor()) {
+ // skip at least one token
+ token_stream.nextToken();
+ }
+
+ skipUntilDeclaration();
+ }
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDeclaration(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ switch (token_stream.lookAhead()) {
+ case ';':
+ token_stream.nextToken();
+ return true;
+
+ case Token_extern:
+ return parseLinkageSpecification(node);
+
+ case Token_namespace:
+ return parseNamespace(node);
+
+ case Token_using:
+ return parseUsing(node);
+
+ case Token_typedef:
+ return parseTypedef(node);
+
+ case Token_asm:
+ return parseAsmDefinition(node);
+
+ case Token_Q_ENUMS:
+ return parseQ_ENUMS(node);
+
+ case Token_template:
+ case Token_export:
+ return parseTemplateDeclaration(node);
+
+ default: {
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ const ListNode<std::size_t> *storageSpec = 0;
+ parseStorageClassSpecifier(storageSpec);
+
+ parseCvQualify(cv);
+
+ TypeSpecifierAST *spec = 0;
+ if (parseEnumSpecifier(spec)
+ || parseClassSpecifier(spec)
+ || parseForwardDeclarationSpecifier(spec)) {
+ parseCvQualify(cv);
+
+ spec->cv = cv;
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ parseInitDeclaratorList(declarators);
+ ADVANCE(';', ";");
+
+ SimpleDeclarationAST *ast =
+ CreateNode<SimpleDeclarationAST>(_M_pool);
+
+ ast->storage_specifiers = storageSpec;
+ ast->type_specifier = spec;
+ ast->init_declarators = declarators;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+ } // end switch
+
+ token_stream.rewind((int) start);
+ return parseDeclarationInternal(node);
+}
+
+bool Parser::parseLinkageSpecification(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_extern);
+
+ LinkageSpecificationAST *ast = CreateNode<LinkageSpecificationAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_string_literal) {
+ ast->extern_type = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ if (token_stream.lookAhead() == '{')
+ parseLinkageBody(ast->linkage_body);
+ else if (!parseDeclaration(ast->declaration))
+ reportError(("Declaration syntax error"));
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseLinkageBody(LinkageBodyAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK('{');
+
+ LinkageBodyAST *ast = CreateNode<LinkageBodyAST>(_M_pool);
+
+ while (token_stream.lookAhead()) {
+ int tk = token_stream.lookAhead();
+
+ if (tk == '}')
+ break;
+
+ std::size_t startDecl = token_stream.cursor();
+
+ DeclarationAST *declaration = 0;
+ if (parseDeclaration(declaration)) {
+ ast->declarations = snoc(ast->declarations, declaration, _M_pool);
+ } else {
+ // error recovery
+ if (startDecl == token_stream.cursor()) {
+ // skip at least one token
+ token_stream.nextToken();
+ }
+
+ skipUntilDeclaration();
+ }
+ }
+
+ if (token_stream.lookAhead() != '}')
+ reportError(("} expected"));
+ else
+ token_stream.nextToken();
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNamespace(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_namespace);
+
+ std::size_t namespace_name = 0;
+ if (token_stream.lookAhead() == Token_identifier) {
+ namespace_name = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ if (token_stream.lookAhead() == '=') {
+ // namespace alias
+ token_stream.nextToken();
+
+ NameAST *name = 0;
+ if (parseName(name)) {
+ ADVANCE(';', ";");
+
+ NamespaceAliasDefinitionAST *ast
+ = CreateNode<NamespaceAliasDefinitionAST>(_M_pool);
+ ast->namespace_name = namespace_name;
+ ast->alias_name = name;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ return true;
+ } else {
+ reportError(("namespace expected"));
+ return false;
+ }
+ } else if (token_stream.lookAhead() != '{') {
+ reportError(("{ expected"));
+ return false;
+ }
+
+ NamespaceAST *ast = CreateNode<NamespaceAST>(_M_pool);
+ ast->namespace_name = namespace_name;
+ parseLinkageBody(ast->linkage_body);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseUsing(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_using);
+
+ if (token_stream.lookAhead() == Token_namespace)
+ return parseUsingDirective(node);
+
+ UsingAST *ast = CreateNode<UsingAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_typename) {
+ ast->type_name = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ if (!parseName(ast->name))
+ return false;
+
+ ADVANCE(';', ";");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseUsingDirective(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_namespace);
+
+ NameAST *name = 0;
+ if (!parseName(name)) {
+ reportError(("Namespace name expected"));
+ return false;
+ }
+
+ ADVANCE(';', ";");
+
+ UsingDirectiveAST *ast = CreateNode<UsingDirectiveAST>(_M_pool);
+ ast->name = name;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseOperatorFunctionId(OperatorFunctionIdAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_operator);
+
+ OperatorFunctionIdAST *ast = CreateNode<OperatorFunctionIdAST>(_M_pool);
+
+ if (!parseOperator(ast->op)) {
+ ast->op = 0;
+
+ // parse cast operator
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ if (!parseSimpleTypeSpecifier(ast->type_specifier)) {
+ syntaxError();
+ return false;
+ }
+
+ parseCvQualify(cv);
+ ast->type_specifier->cv = cv;
+
+ PtrOperatorAST *ptr_op = 0;
+ while (parsePtrOperator(ptr_op))
+ ast->ptr_ops = snoc(ast->ptr_ops, ptr_op, _M_pool);
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ return true;
+}
+
+bool Parser::parseTemplateArgumentList(const ListNode<TemplateArgumentAST*> *&node,
+ bool reportError)
+{
+ TemplateArgumentAST *templArg = 0;
+ if (!parseTemplateArgument(templArg))
+ return false;
+
+ node = snoc(node, templArg, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseTemplateArgument(templArg)) {
+ if (reportError) {
+ syntaxError();
+ break;
+ }
+
+ node = 0;
+ return false;
+ }
+
+ node = snoc(node, templArg, _M_pool);
+ }
+
+ return true;
+}
+
+bool Parser::parseTypedef(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_typedef);
+
+ TypeSpecifierAST *spec = 0;
+ if (!parseTypeSpecifierOrClassSpec(spec)) {
+ reportError(("Need a type specifier to declare"));
+ return false;
+ }
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ if (!parseInitDeclaratorList(declarators)) {
+ //reportError(("Need an identifier to declare"));
+ //return false;
+ }
+
+ ADVANCE(';', ";");
+
+ TypedefAST *ast = CreateNode<TypedefAST>(_M_pool);
+ ast->type_specifier = spec;
+ ast->init_declarators = declarators;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAsmDefinition(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ADVANCE(Token_asm, "asm");
+
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+#if defined(__GNUC__)
+#warning "implement me"
+#endif
+ skip('(', ')');
+ token_stream.nextToken();
+ ADVANCE(';', ";");
+
+ AsmDefinitionAST *ast = CreateNode<AsmDefinitionAST>(_M_pool);
+ ast->cv = cv;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ std::size_t exported = 0;
+ if (token_stream.lookAhead() == Token_export) {
+ exported = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ CHECK(Token_template);
+
+ const ListNode<TemplateParameterAST*> *params = 0;
+ if (token_stream.lookAhead() == '<') {
+ token_stream.nextToken();
+ parseTemplateParameterList(params);
+
+ ADVANCE('>', ">");
+ }
+
+ DeclarationAST *declaration = 0;
+ if (!parseDeclaration(declaration))
+ reportError(("expected a declaration"));
+
+ TemplateDeclarationAST *ast = CreateNode<TemplateDeclarationAST>(_M_pool);
+ ast->exported = exported;
+ ast->template_parameters = params;
+ ast->declaration = declaration;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseOperator(OperatorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ OperatorAST *ast = CreateNode<OperatorAST>(_M_pool);
+
+ switch (token_stream.lookAhead()) {
+ case Token_new:
+ case Token_delete: {
+ ast->op = token_stream.cursor();
+ token_stream.nextToken();
+
+ if (token_stream.lookAhead() == '['
+ && token_stream.lookAhead(1) == ']') {
+ ast->open = token_stream.cursor();
+ token_stream.nextToken();
+
+ ast->close = token_stream.cursor();
+ token_stream.nextToken();
+ }
+ }
+ break;
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '^':
+ case '&':
+ case '|':
+ case '~':
+ case '!':
+ case '=':
+ case '<':
+ case '>':
+ case ',':
+ case Token_assign:
+ case Token_shift:
+ case Token_eq:
+ case Token_not_eq:
+ case Token_leq:
+ case Token_geq:
+ case Token_and:
+ case Token_or:
+ case Token_incr:
+ case Token_decr:
+ case Token_ptrmem:
+ case Token_arrow:
+ ast->op = token_stream.cursor();
+ token_stream.nextToken();
+ break;
+
+ default:
+ if (token_stream.lookAhead() == '('
+ && token_stream.lookAhead(1) == ')') {
+ ast->op = ast->open = token_stream.cursor();
+ token_stream.nextToken();
+ ast->close = token_stream.cursor();
+ token_stream.nextToken();
+ } else if (token_stream.lookAhead() == '['
+ && token_stream.lookAhead(1) == ']') {
+ ast->op = ast->open = token_stream.cursor();
+ token_stream.nextToken();
+ ast->close = token_stream.cursor();
+ token_stream.nextToken();
+ } else {
+ return false;
+ }
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseCvQualify(const ListNode<std::size_t> *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int tk;
+ while (0 != (tk = token_stream.lookAhead())
+ && (tk == Token_const || tk == Token_volatile)) {
+ node = snoc(node, token_stream.cursor(), _M_pool);
+ token_stream.nextToken();
+ }
+
+ return start != token_stream.cursor();
+}
+
+bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node,
+ bool onlyIntegral)
+{
+ std::size_t start = token_stream.cursor();
+ bool isIntegral = false;
+ bool done = false;
+
+ const ListNode<std::size_t> *integrals = 0;
+
+ while (!done) {
+ switch (token_stream.lookAhead()) {
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ integrals = snoc(integrals, token_stream.cursor(), _M_pool);
+ isIntegral = true;
+ token_stream.nextToken();
+ break;
+
+ default:
+ done = true;
+ }
+ }
+
+ SimpleTypeSpecifierAST *ast = CreateNode<SimpleTypeSpecifierAST>(_M_pool);
+ if (isIntegral) {
+ ast->integrals = integrals;
+ } else if (token_stream.lookAhead() == Token___typeof) {
+ ast->type_of = token_stream.cursor();
+ token_stream.nextToken();
+
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ std::size_t saved = token_stream.cursor();
+ parseTypeId(ast->type_id);
+ if (token_stream.lookAhead() != ')') {
+ ast->type_id = 0;
+ token_stream.rewind((int) saved);
+ parseUnaryExpression(ast->expression);
+ }
+ ADVANCE(')', ")");
+ } else {
+ parseUnaryExpression(ast->expression);
+ }
+ } else if (onlyIntegral) {
+ token_stream.rewind((int) start);
+ return false;
+ } else {
+ if (!parseName(ast->name, true)) {
+ ast->name = 0;
+ token_stream.rewind((int) start);
+ return false;
+ }
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parsePtrOperator(PtrOperatorAST *&node)
+{
+ int tk = token_stream.lookAhead();
+
+ if (tk != '&' && tk != '*'
+ && tk != Token_scope && tk != Token_identifier) {
+ return false;
+ }
+
+ std::size_t start = token_stream.cursor();
+
+ PtrOperatorAST *ast = CreateNode<PtrOperatorAST>(_M_pool);
+
+ switch (token_stream.lookAhead()) {
+ case '&':
+ case '*':
+ ast->op = token_stream.cursor();
+ token_stream.nextToken();
+ break;
+
+ case Token_scope:
+ case Token_identifier: {
+ if (!parsePtrToMember(ast->mem_ptr)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ }
+ break;
+
+ default:
+ Q_ASSERT(0);
+ break;
+ }
+
+ parseCvQualify(ast->cv);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTemplateArgument(TemplateArgumentAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ TypeIdAST *typeId = 0;
+ ExpressionAST *expr = 0;
+
+ if (!parseTypeId(typeId) || (token_stream.lookAhead() != ','
+ && token_stream.lookAhead() != '>')) {
+ token_stream.rewind((int) start);
+
+ if (!parseLogicalOrExpression(expr, true))
+ return false;
+ }
+
+ TemplateArgumentAST *ast = CreateNode<TemplateArgumentAST>(_M_pool);
+ ast->type_id = typeId;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ TypeSpecifierAST *ast = 0;
+ if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ parseCvQualify(cv);
+ ast->cv = cv;
+
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDeclarator(DeclaratorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool);
+
+ //fprintf(stderr, "[%s-%s] ast->ptr_ops: %p\n", __FILE__, __FUNCTION__, ast->ptr_ops);
+
+ DeclaratorAST *decl = 0;
+ NameAST *declId = 0;
+
+ PtrOperatorAST *ptrOp = 0;
+ while (parsePtrOperator(ptrOp))
+ ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool);
+
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ if (!parseDeclarator(decl))
+ return false;
+
+ ast->sub_declarator = decl;
+
+ CHECK(')');
+ } else {
+ if (token_stream.lookAhead() == ':') {
+ // unnamed bitfield
+ } else if (parseName(declId, true)) {
+ ast->id = declId;
+ } else {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ if (token_stream.lookAhead() == ':') {
+ token_stream.nextToken();
+
+ if (!parseConstantExpression(ast->bit_expression))
+ reportError(("Constant expression expected"));
+
+ goto update_pos;
+ }
+ }
+
+ {
+ bool isVector = true;
+
+ while (token_stream.lookAhead() == '[') {
+ token_stream.nextToken();
+
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+
+ ADVANCE(']', "]");
+
+ ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool);
+ isVector = true;
+ }
+
+ bool skipParen = false;
+ if (token_stream.lookAhead() == Token_identifier
+ && token_stream.lookAhead(1) == '('
+ && token_stream.lookAhead(2) == '(') {
+ token_stream.nextToken();
+ token_stream.nextToken();
+ skipParen = true;
+ }
+
+ int tok = token_stream.lookAhead();
+ if (ast->sub_declarator
+ && !(isVector || tok == '(' || tok == ','
+ || tok == ';' || tok == '=')) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ std::size_t index = token_stream.cursor();
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ ParameterDeclarationClauseAST *params = 0;
+ if (!parseParameterDeclarationClause(params)) {
+ token_stream.rewind((int) index);
+ goto update_pos;
+ }
+
+ ast->parameter_declaration_clause = params;
+
+ if (token_stream.lookAhead() != ')') {
+ token_stream.rewind((int) index);
+ goto update_pos;
+ }
+
+ token_stream.nextToken(); // skip ')'
+
+ parseCvQualify(ast->fun_cv);
+ parseExceptionSpecification(ast->exception_spec);
+
+ if (token_stream.lookAhead() == Token___attribute__)
+ parse_Attribute__();
+ }
+
+ if (skipParen) {
+ if (token_stream.lookAhead() != ')')
+ reportError(("')' expected"));
+ else
+ token_stream.nextToken();
+ }
+ }
+
+update_pos:
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool);
+ DeclaratorAST *decl = 0;
+
+ PtrOperatorAST *ptrOp = 0;
+ while (parsePtrOperator(ptrOp))
+ ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool);
+
+ int index = (int) token_stream.cursor();
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ if (!parseAbstractDeclarator(decl)) {
+ token_stream.rewind((int) index);
+ goto label1;
+ }
+
+ ast->sub_declarator = decl;
+
+ if (token_stream.lookAhead() != ')') {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ token_stream.nextToken();
+ } else if (token_stream.lookAhead() == ':') {
+ token_stream.nextToken();
+ if (!parseConstantExpression(ast->bit_expression)) {
+ ast->bit_expression = 0;
+ reportError(("Constant expression expected"));
+ }
+ goto update_pos;
+ }
+
+label1: {
+ bool isVector = true;
+
+ while (token_stream.lookAhead() == '[') {
+ token_stream.nextToken();
+
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+
+ ADVANCE(']', "]");
+
+ ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool);
+ isVector = true;
+ }
+
+ int tok = token_stream.lookAhead();
+ if (ast->sub_declarator
+ && !(isVector || tok == '(' || tok == ','
+ || tok == ';' || tok == '=')) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ int index = (int) token_stream.cursor();
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ ParameterDeclarationClauseAST *params = 0;
+ if (!parseParameterDeclarationClause(params)) {
+ token_stream.rewind((int) index);
+ goto update_pos;
+ }
+
+ ast->parameter_declaration_clause = params;
+
+ if (token_stream.lookAhead() != ')') {
+ token_stream.rewind((int) index);
+ goto update_pos;
+ }
+
+ token_stream.nextToken(); // skip ')'
+
+ parseCvQualify(ast->fun_cv);
+ parseExceptionSpecification(ast->exception_spec);
+ }
+ }
+
+update_pos:
+ if (token_stream.cursor() == start)
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_enum);
+
+ NameAST *name = 0;
+ parseName(name);
+
+ if (token_stream.lookAhead() != '{') {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ token_stream.nextToken();
+
+ EnumSpecifierAST *ast = CreateNode<EnumSpecifierAST>(_M_pool);
+ ast->name = name;
+
+ EnumeratorAST *enumerator = 0;
+ if (parseEnumerator(enumerator)) {
+ ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseEnumerator(enumerator)) {
+ //reportError(("Enumerator expected"));
+ break;
+ }
+
+ ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool);
+ }
+ }
+
+ ADVANCE_NR('}', "}");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTemplateParameterList(const ListNode<TemplateParameterAST*> *&node)
+{
+ TemplateParameterAST *param = 0;
+ if (!parseTemplateParameter(param))
+ return false;
+
+ node = snoc(node, param, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseTemplateParameter(param)) {
+ syntaxError();
+ break;
+ } else {
+ node = snoc(node, param, _M_pool);
+ }
+ }
+
+ return true;
+}
+
+bool Parser::parseTemplateParameter(TemplateParameterAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+ TemplateParameterAST *ast = CreateNode<TemplateParameterAST>(_M_pool);
+
+ int tk = token_stream.lookAhead();
+
+ if ((tk == Token_class || tk == Token_typename || tk == Token_template)
+ && parseTypeParameter(ast->type_parameter)) {
+ // nothing to do
+ } else if (!parseParameterDeclaration(ast->parameter_declaration))
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTypeParameter(TypeParameterAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ TypeParameterAST *ast = CreateNode<TypeParameterAST>(_M_pool);
+ ast->type = start;
+
+ switch (token_stream.lookAhead()) {
+ case Token_class:
+ case Token_typename: {
+ token_stream.nextToken(); // skip class
+
+ // parse optional name
+ if (parseName(ast->name, true)) {
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+
+ if (!parseTypeId(ast->type_id)) {
+ //syntaxError();
+ token_stream.rewind((int) start);
+ return false;
+ }
+ } else if (token_stream.lookAhead() != ','
+ && token_stream.lookAhead() != '>') {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ }
+ }
+ break;
+
+ case Token_template: {
+ token_stream.nextToken(); // skip template
+ ADVANCE('<', "<");
+
+ if (!parseTemplateParameterList(ast->template_parameters))
+ return false;
+
+ ADVANCE('>', ">");
+
+ if (token_stream.lookAhead() == Token_class)
+ token_stream.nextToken();
+
+ // parse optional name
+ if (parseName(ast->name, true)) {
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+
+ if (!parseTypeId(ast->type_id)) {
+ syntaxError();
+ return false;
+ }
+ }
+ }
+
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+
+ parseName(ast->template_name, true);
+ }
+ }
+ break;
+
+ default:
+ return false;
+
+ } // end switch
+
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ return true;
+}
+
+bool Parser::parseStorageClassSpecifier(const ListNode<std::size_t> *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int tk;
+ while (0 != (tk = token_stream.lookAhead())
+ && (tk == Token_friend || tk == Token_auto
+ || tk == Token_register || tk == Token_static
+ || tk == Token_extern || tk == Token_mutable)) {
+ node = snoc(node, token_stream.cursor(), _M_pool);
+ token_stream.nextToken();
+ }
+
+ return start != token_stream.cursor();
+}
+
+bool Parser::parseFunctionSpecifier(const ListNode<std::size_t> *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int tk;
+ while (0 != (tk = token_stream.lookAhead())
+ && (tk == Token_inline || tk == Token_virtual
+ || tk == Token_explicit || tk == Token_Q_INVOKABLE)) {
+ node = snoc(node, token_stream.cursor(), _M_pool);
+ token_stream.nextToken();
+ }
+
+ return start != token_stream.cursor();
+}
+
+bool Parser::parseTypeId(TypeIdAST *&node)
+{
+ /// @todo implement the AST for typeId
+ std::size_t start = token_stream.cursor();
+
+ TypeSpecifierAST *spec = 0;
+ if (!parseTypeSpecifier(spec)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ DeclaratorAST *decl = 0;
+ parseAbstractDeclarator(decl);
+
+ TypeIdAST *ast = CreateNode<TypeIdAST>(_M_pool);
+ ast->type_specifier = spec;
+ ast->declarator = decl;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node)
+{
+ InitDeclaratorAST *decl = 0;
+ if (!parseInitDeclarator(decl))
+ return false;
+
+ node = snoc(node, decl, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseInitDeclarator(decl)) {
+ syntaxError();
+ break;
+ }
+ node = snoc(node, decl, _M_pool);
+ }
+
+ return true;
+}
+
+bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ParameterDeclarationClauseAST *ast
+ = CreateNode<ParameterDeclarationClauseAST>(_M_pool);
+
+ if (!parseParameterDeclarationList(ast->parameter_declarations)) {
+ if (token_stream.lookAhead() == ')')
+ goto good;
+
+ if (token_stream.lookAhead() == Token_ellipsis
+ && token_stream.lookAhead(1) == ')') {
+ ast->ellipsis = token_stream.cursor();
+ goto good;
+ }
+
+ return false;
+ }
+
+good:
+
+ if (token_stream.lookAhead() == Token_ellipsis) {
+ ast->ellipsis = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ /// @todo add ellipsis
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseParameterDeclarationList(const ListNode<ParameterDeclarationAST*> *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ParameterDeclarationAST *param = 0;
+ if (!parseParameterDeclaration(param)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ node = snoc(node, param, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (token_stream.lookAhead() == Token_ellipsis)
+ break;
+
+ if (!parseParameterDeclaration(param)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ node = snoc(node, param, _M_pool);
+ }
+
+ return true;
+}
+
+bool Parser::parseParameterDeclaration(ParameterDeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ const ListNode<std::size_t> *storage = 0;
+ parseStorageClassSpecifier(storage);
+
+ // parse decl spec
+ TypeSpecifierAST *spec = 0;
+ if (!parseTypeSpecifier(spec)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ int index = (int) token_stream.cursor();
+
+ DeclaratorAST *decl = 0;
+ if (!parseDeclarator(decl)) {
+ token_stream.rewind((int) index);
+
+ // try with abstract declarator
+ parseAbstractDeclarator(decl);
+ }
+
+ ExpressionAST *expr = 0;
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+ if (!parseLogicalOrExpression(expr, true))
+ reportError(("Expression expected"));
+ }
+
+ ParameterDeclarationAST *ast = CreateNode<ParameterDeclarationAST>(_M_pool);
+ ast->type_specifier = spec;
+ ast->declarator = decl;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parse_Attribute__()
+{
+ token_stream.nextToken();
+
+ ADVANCE('(', "(");
+
+ ExpressionAST *expr = 0;
+ parseExpression(expr);
+
+ if (token_stream.lookAhead() != ')') {
+ reportError(("')' expected"));
+ return false;
+ } else {
+ token_stream.nextToken();
+ }
+ return true;
+}
+
+QString Parser::tokenText(AST *ast) const
+{
+ if (!ast)
+ return QString();
+
+ int start_token = ast->start_token;
+ int end_token = ast->end_token;
+
+ Token const &tk = token_stream.token(start_token);
+ Token const &end_tk = token_stream.token(end_token);
+
+ return QString::fromLatin1(&tk.text[tk.position],
+ (int)(end_tk.position - tk.position)).trimmed();
+}
+
+bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int kind = token_stream.lookAhead();
+ if (kind != Token_class && kind != Token_struct && kind != Token_union)
+ return false;
+
+ std::size_t class_key = token_stream.cursor();
+ token_stream.nextToken();
+
+ NameAST *name = 0;
+ if (!parseName(name, false)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ BaseClauseAST *bases = 0;
+ if (token_stream.lookAhead() == ':') {
+ if (!parseBaseClause(bases)) {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ }
+
+ if (token_stream.lookAhead() != ';') {
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ ForwardDeclarationSpecifierAST *ast = CreateNode<ForwardDeclarationSpecifierAST>(_M_pool);
+ ast->class_key = class_key;
+ ast->name = name;
+ ast->base_clause = bases;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseClassSpecifier(TypeSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int kind = token_stream.lookAhead();
+ if (kind != Token_class && kind != Token_struct && kind != Token_union)
+ return false;
+
+ std::size_t class_key = token_stream.cursor();
+ token_stream.nextToken();
+
+ WinDeclSpecAST *winDeclSpec = 0;
+ parseWinDeclSpec(winDeclSpec);
+
+ if (token_stream.lookAhead() == Token___attribute__)
+ parse_Attribute__();
+
+ while (token_stream.lookAhead() == Token_identifier
+ && token_stream.lookAhead(1) == Token_identifier)
+ token_stream.nextToken();
+
+ NameAST *name = 0;
+ parseName(name, true);
+
+ BaseClauseAST *bases = 0;
+
+ if (token_stream.lookAhead() == ':') {
+ if (!parseBaseClause(bases))
+ skipUntil('{');
+ }
+
+ if (token_stream.lookAhead() != '{') {
+
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ ADVANCE('{', "{");
+
+ ClassSpecifierAST *ast = CreateNode<ClassSpecifierAST>(_M_pool);
+ ast->win_decl_specifiers = winDeclSpec;
+ ast->class_key = class_key;
+ ast->name = name;
+ ast->base_clause = bases;
+
+ while (token_stream.lookAhead()) {
+ if (token_stream.lookAhead() == '}')
+ break;
+
+ std::size_t startDecl = token_stream.cursor();
+
+ DeclarationAST *memSpec = 0;
+ if (!parseMemberSpecification(memSpec)) {
+ if (startDecl == token_stream.cursor())
+ token_stream.nextToken(); // skip at least one token
+ skipUntilDeclaration();
+ } else
+ ast->member_specs = snoc(ast->member_specs, memSpec, _M_pool);
+ }
+
+ ADVANCE_NR('}', "}");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAccessSpecifier(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ const ListNode<std::size_t> *specs = 0;
+
+ bool done = false;
+ while (!done) {
+ switch (token_stream.lookAhead()) {
+ case Token_signals:
+ case Token_slots:
+ case Token_k_dcop:
+ case Token_k_dcop_signals:
+ case Token_public:
+ case Token_protected:
+ case Token_private:
+ specs = snoc(specs, token_stream.cursor(), _M_pool);
+ token_stream.nextToken();
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+
+ if (!specs)
+ return false;
+
+ ADVANCE(':', ":");
+
+ AccessSpecifierAST *ast = CreateNode<AccessSpecifierAST>(_M_pool);
+ ast->specs = specs;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseMemberSpecification(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (token_stream.lookAhead() == ';') {
+ token_stream.nextToken();
+ return true;
+ } else if (token_stream.lookAhead() == Token_Q_OBJECT
+ || token_stream.lookAhead() == Token_K_DCOP) {
+ token_stream.nextToken();
+ return true;
+ } else if (parseTypedef(node)) {
+ return true;
+ } else if (parseUsing(node)) {
+ return true;
+ } else if (parseTemplateDeclaration(node)) {
+ return true;
+ } else if (parseAccessSpecifier(node)) {
+ return true;
+ } else if (parseQ_PROPERTY(node)) {
+ return true;
+ } else if (parseQ_ENUMS(node)) {
+ return true;
+ }
+
+ token_stream.rewind((int) start);
+
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ const ListNode<std::size_t> *storageSpec = 0;
+ parseStorageClassSpecifier(storageSpec);
+
+ parseCvQualify(cv);
+
+ TypeSpecifierAST *spec = 0;
+ if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) {
+ parseCvQualify(cv);
+ spec->cv = cv;
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ parseInitDeclaratorList(declarators);
+ ADVANCE(';', ";");
+
+ SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
+ ast->type_specifier = spec;
+ ast->init_declarators = declarators;
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+
+ token_stream.rewind((int) start);
+ return parseDeclarationInternal(node);
+}
+
+bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(':');
+
+ CtorInitializerAST *ast = CreateNode<CtorInitializerAST>(_M_pool);
+ ast->colon = start;
+
+ if (!parseMemInitializerList(ast->member_initializers))
+ reportError(("Member initializers expected"));
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int tk = token_stream.lookAhead();
+ if (tk == Token_class
+ || tk == Token_struct
+ || tk == Token_union
+ || tk == Token_enum
+ || tk == Token_typename) {
+ std::size_t type = token_stream.cursor();
+ token_stream.nextToken();
+
+ NameAST *name = 0;
+ if (parseName(name, true)) {
+ ElaboratedTypeSpecifierAST *ast
+ = CreateNode<ElaboratedTypeSpecifierAST>(_M_pool);
+
+ ast->type = type;
+ ast->name = name;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+
+ token_stream.rewind((int) start);
+ return false;
+}
+
+bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_throw);
+ ADVANCE('(', "(");
+
+ ExceptionSpecificationAST *ast = CreateNode<ExceptionSpecificationAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_ellipsis) {
+ ast->ellipsis = token_stream.cursor();
+ token_stream.nextToken();
+ } else {
+ parseTypeIdList(ast->type_ids);
+ }
+
+ ADVANCE(')', ")");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseEnumerator(EnumeratorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_identifier);
+ std::size_t id = token_stream.cursor() - 1;
+
+ EnumeratorAST *ast = CreateNode<EnumeratorAST>(_M_pool);
+ ast->id = id;
+
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+
+ if (!parseConstantExpression(ast->expression))
+ reportError(("Constant expression expected"));
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseInitDeclarator(InitDeclaratorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ DeclaratorAST *decl = 0;
+ if (!parseDeclarator(decl))
+ return false;
+
+ if (token_stream.lookAhead(0) == Token_asm) {
+ token_stream.nextToken();
+ skip('(', ')');
+ token_stream.nextToken();
+ }
+
+ InitializerAST *init = 0;
+ parseInitializer(init);
+
+ InitDeclaratorAST *ast = CreateNode<InitDeclaratorAST>(_M_pool);
+ ast->declarator = decl;
+ ast->initializer = init;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseBaseClause(BaseClauseAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(':');
+
+ BaseSpecifierAST *baseSpec = 0;
+ if (!parseBaseSpecifier(baseSpec))
+ return false;
+
+ BaseClauseAST *ast = CreateNode<BaseClauseAST>(_M_pool);
+ ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseBaseSpecifier(baseSpec)) {
+ reportError(("Base class specifier expected"));
+ break;
+ }
+ ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool);
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseInitializer(InitializerAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ int tk = token_stream.lookAhead();
+ if (tk != '=' && tk != '(')
+ return false;
+
+ InitializerAST *ast = CreateNode<InitializerAST>(_M_pool);
+
+ if (tk == '=') {
+ token_stream.nextToken();
+
+ if (!parseInitializerClause(ast->initializer_clause))
+ reportError(("Initializer clause expected"));
+
+ } else if (tk == '(') {
+ token_stream.nextToken();
+ parseCommaExpression(ast->expression);
+ CHECK(')');
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseMemInitializerList(const ListNode<MemInitializerAST*> *&node)
+{
+ MemInitializerAST *init = 0;
+
+ if (!parseMemInitializer(init))
+ return false;
+
+ node = snoc(node, init, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+
+ if (!parseMemInitializer(init))
+ break;
+
+ node = snoc(node, init, _M_pool);
+ }
+
+ return true;
+}
+
+bool Parser::parseMemInitializer(MemInitializerAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ NameAST *initId = 0;
+ if (!parseName(initId, true)) {
+ reportError(("Identifier expected"));
+ return false;
+ }
+
+ ADVANCE('(', "(");
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+ ADVANCE(')', ")");
+
+ MemInitializerAST *ast = CreateNode<MemInitializerAST>(_M_pool);
+ ast->initializer_id = initId;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTypeIdList(const ListNode<TypeIdAST*> *&node)
+{
+ TypeIdAST *typeId = 0;
+ if (!parseTypeId(typeId))
+ return false;
+
+ node = snoc(node, typeId, _M_pool);
+
+ while (token_stream.lookAhead() == ',') {
+ token_stream.nextToken();
+ if (parseTypeId(typeId)) {
+ node = snoc(node, typeId, _M_pool);
+ } else {
+ reportError(("Type id expected"));
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ BaseSpecifierAST *ast = CreateNode<BaseSpecifierAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_virtual) {
+ ast->virt = token_stream.cursor();
+ token_stream.nextToken();
+
+ int tk = token_stream.lookAhead();
+ if (tk == Token_public || tk == Token_protected
+ || tk == Token_private) {
+ ast->access_specifier = token_stream.cursor();
+ token_stream.nextToken();
+ }
+ } else {
+ int tk = token_stream.lookAhead();
+ if (tk == Token_public || tk == Token_protected
+ || tk == Token_private) {
+ ast->access_specifier = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ if (token_stream.lookAhead() == Token_virtual) {
+ ast->virt = token_stream.cursor();
+ token_stream.nextToken();
+ }
+ }
+
+ if (!parseName(ast->name, true))
+ reportError(("Class name expected"));
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseInitializerClause(InitializerClauseAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ InitializerClauseAST *ast = CreateNode<InitializerClauseAST>(_M_pool);
+
+ if (token_stream.lookAhead() == '{') {
+#if defined(__GNUC__)
+#warning "implement me"
+#endif
+ if (skip('{', '}'))
+ token_stream.nextToken();
+ else
+ reportError(("} missing"));
+ } else {
+ if (!parseAssignmentExpression(ast->expression))
+ reportError(("Expression expected"));
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parsePtrToMember(PtrToMemberAST *&node)
+{
+#if defined(__GNUC__)
+#warning "implemente me (AST)"
+#endif
+
+ std::size_t start = token_stream.cursor();
+
+ std::size_t global_scope = 0;
+ if (token_stream.lookAhead() == Token_scope) {
+ global_scope = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ UnqualifiedNameAST *name = 0;
+ while (token_stream.lookAhead() == Token_identifier) {
+ if (!parseUnqualifiedName(name))
+ break;
+
+ if (token_stream.lookAhead() == Token_scope
+ && token_stream.lookAhead(1) == '*') {
+ token_stream.nextToken();
+ token_stream.nextToken();
+
+ PtrToMemberAST *ast = CreateNode<PtrToMemberAST>(_M_pool);
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+
+ if (token_stream.lookAhead() == Token_scope)
+ token_stream.nextToken();
+ }
+
+ token_stream.rewind((int) start);
+ return false;
+}
+
+bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node,
+ bool parseTemplateId)
+{
+ std::size_t start = token_stream.cursor();
+
+ std::size_t tilde = 0;
+ std::size_t id = 0;
+ OperatorFunctionIdAST *operator_id = 0;
+
+ if (token_stream.lookAhead() == Token_identifier) {
+ id = token_stream.cursor();
+ token_stream.nextToken();
+ } else if (token_stream.lookAhead() == '~'
+ && token_stream.lookAhead(1) == Token_identifier) {
+ tilde = token_stream.cursor();
+ token_stream.nextToken(); // skip ~
+
+ id = token_stream.cursor();
+ token_stream.nextToken(); // skip classname
+ } else if (token_stream.lookAhead() == Token_operator) {
+ if (!parseOperatorFunctionId(operator_id))
+ return false;
+ } else {
+ return false;
+ }
+
+ UnqualifiedNameAST *ast = CreateNode<UnqualifiedNameAST>(_M_pool);
+ ast->tilde = tilde;
+ ast->id = id;
+ ast->operator_id = operator_id;
+
+ if (parseTemplateId && !tilde) {
+ std::size_t index = token_stream.cursor();
+
+ if (token_stream.lookAhead() == '<') {
+ token_stream.nextToken();
+
+ // optional template arguments
+ parseTemplateArgumentList(ast->template_arguments);
+
+ if (token_stream.lookAhead() == '>') {
+ token_stream.nextToken();
+ } else {
+ ast->template_arguments = 0;
+ token_stream.rewind((int) index);
+ }
+ }
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseStringLiteral(StringLiteralAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (token_stream.lookAhead() != Token_string_literal)
+ return false;
+
+ StringLiteralAST *ast = CreateNode<StringLiteralAST>(_M_pool);
+
+ while (token_stream.lookAhead() == Token_string_literal) {
+ ast->literals = snoc(ast->literals, token_stream.cursor(), _M_pool);
+ token_stream.nextToken();
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseExpressionStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+
+ ADVANCE(';', ";");
+
+ ExpressionStatementAST *ast = CreateNode<ExpressionStatementAST>(_M_pool);
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ switch (token_stream.lookAhead()) {
+ case Token_while:
+ return parseWhileStatement(node);
+
+ case Token_do:
+ return parseDoStatement(node);
+
+ case Token_for:
+ return parseForStatement(node);
+
+ case Token_if:
+ return parseIfStatement(node);
+
+ case Token_switch:
+ return parseSwitchStatement(node);
+
+ case Token_try:
+ return parseTryBlockStatement(node);
+
+ case Token_case:
+ case Token_default:
+ return parseLabeledStatement(node);
+
+ case Token_break:
+ case Token_continue:
+#if defined(__GNUC__)
+#warning "implement me"
+#endif
+ token_stream.nextToken();
+ ADVANCE(';', ";");
+ return true;
+
+ case Token_goto:
+#if defined(__GNUC__)
+#warning "implement me"
+#endif
+ token_stream.nextToken();
+ ADVANCE(Token_identifier, "identifier");
+ ADVANCE(';', ";");
+ return true;
+
+ case Token_return: {
+ token_stream.nextToken();
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+
+ ADVANCE(';', ";");
+
+ ReturnStatementAST *ast = CreateNode<ReturnStatementAST>(_M_pool);
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case '{':
+ return parseCompoundStatement(node);
+
+ case Token_identifier:
+ if (parseLabeledStatement(node))
+ return true;
+ break;
+ }
+
+ return parseExpressionOrDeclarationStatement(node);
+}
+
+bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
+{
+ bool blocked = block_errors(true);
+
+ std::size_t start = token_stream.cursor();
+
+ StatementAST *decl_ast = 0;
+ bool maybe_amb = parseDeclarationStatement(decl_ast);
+ maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';';
+
+ std::size_t end = token_stream.cursor();
+
+ token_stream.rewind((int) start);
+ StatementAST *expr_ast = 0;
+ maybe_amb &= parseExpressionStatement(expr_ast);
+ maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';';
+
+ if (maybe_amb) {
+ Q_ASSERT(decl_ast && expr_ast);
+ ExpressionOrDeclarationStatementAST *ast =
+ CreateNode<ExpressionOrDeclarationStatementAST>(_M_pool);
+ ast->declaration = decl_ast;
+ ast->expression = expr_ast;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ } else {
+ token_stream.rewind((int) std::max(end, token_stream.cursor()));
+
+ node = decl_ast;
+ if (!node)
+ node = expr_ast;
+ }
+
+ block_errors(blocked);
+
+ if (!node)
+ syntaxError();
+
+ return node != 0;
+}
+
+bool Parser::parseCondition(ConditionAST *&node, bool initRequired)
+{
+ std::size_t start = token_stream.cursor();
+
+ ConditionAST *ast = CreateNode<ConditionAST>(_M_pool);
+ TypeSpecifierAST *spec = 0;
+
+ if (parseTypeSpecifier(spec)) {
+ ast->type_specifier = spec;
+
+ std::size_t declarator_start = token_stream.cursor();
+
+ DeclaratorAST *decl = 0;
+ if (!parseDeclarator(decl)) {
+ token_stream.rewind((int) declarator_start);
+ if (!initRequired && !parseAbstractDeclarator(decl))
+ decl = 0;
+ }
+
+ if (decl && (!initRequired || token_stream.lookAhead() == '=')) {
+ ast->declarator = decl;
+
+ if (token_stream.lookAhead() == '=') {
+ token_stream.nextToken();
+
+ parseExpression(ast->expression);
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+
+ token_stream.rewind((int) start);
+
+ if (!parseCommaExpression(ast->expression))
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseWhileStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ADVANCE(Token_while, "while");
+ ADVANCE('(' , "(");
+
+ ConditionAST *cond = 0;
+ if (!parseCondition(cond)) {
+ reportError(("condition expected"));
+ return false;
+ }
+ ADVANCE(')', ")");
+
+ StatementAST *body = 0;
+ if (!parseStatement(body)) {
+ reportError(("statement expected"));
+ return false;
+ }
+
+ WhileStatementAST *ast = CreateNode<WhileStatementAST>(_M_pool);
+ ast->condition = cond;
+ ast->statement = body;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDoStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ADVANCE(Token_do, "do");
+
+ StatementAST *body = 0;
+ if (!parseStatement(body)) {
+ reportError(("statement expected"));
+ //return false;
+ }
+
+ ADVANCE_NR(Token_while, "while");
+ ADVANCE_NR('(' , "(");
+
+ ExpressionAST *expr = 0;
+ if (!parseCommaExpression(expr)) {
+ reportError(("expression expected"));
+ //return false;
+ }
+
+ ADVANCE_NR(')', ")");
+ ADVANCE_NR(';', ";");
+
+ DoStatementAST *ast = CreateNode<DoStatementAST>(_M_pool);
+ ast->statement = body;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseForStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ADVANCE(Token_for, "for");
+ ADVANCE('(', "(");
+
+ StatementAST *init = 0;
+ if (!parseForInitStatement(init)) {
+ reportError(("for initialization expected"));
+ return false;
+ }
+
+ ConditionAST *cond = 0;
+ parseCondition(cond);
+ ADVANCE(';', ";");
+
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+ ADVANCE(')', ")");
+
+ StatementAST *body = 0;
+ if (!parseStatement(body))
+ return false;
+
+ ForStatementAST *ast = CreateNode<ForStatementAST>(_M_pool);
+ ast->init_statement = init;
+ ast->condition = cond;
+ ast->expression = expr;
+ ast->statement = body;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseForInitStatement(StatementAST *&node)
+{
+ if (parseDeclarationStatement(node))
+ return true;
+
+ return parseExpressionStatement(node);
+}
+
+bool Parser::parseCompoundStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK('{');
+
+ CompoundStatementAST *ast = CreateNode<CompoundStatementAST>(_M_pool);
+
+ while (token_stream.lookAhead()) {
+ if (token_stream.lookAhead() == '}')
+ break;
+
+ std::size_t startStmt = token_stream.cursor();
+
+ StatementAST *stmt = 0;
+ if (!parseStatement(stmt)) {
+ if (startStmt == token_stream.cursor())
+ token_stream.nextToken();
+
+ skipUntilStatement();
+ } else {
+ ast->statements = snoc(ast->statements, stmt, _M_pool);
+ }
+ }
+
+ ADVANCE_NR('}', "}");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseIfStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ ADVANCE(Token_if, "if");
+
+ ADVANCE('(' , "(");
+
+ IfStatementAST *ast = CreateNode<IfStatementAST>(_M_pool);
+
+ ConditionAST *cond = 0;
+ if (!parseCondition(cond)) {
+ reportError(("condition expected"));
+ return false;
+ }
+ ADVANCE(')', ")");
+
+ StatementAST *stmt = 0;
+ if (!parseStatement(stmt)) {
+ reportError(("statement expected"));
+ return false;
+ }
+
+ ast->condition = cond;
+ ast->statement = stmt;
+
+ if (token_stream.lookAhead() == Token_else) {
+ token_stream.nextToken();
+
+ if (!parseStatement(ast->else_statement)) {
+ reportError(("statement expected"));
+ return false;
+ }
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseSwitchStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+ ADVANCE(Token_switch, "switch");
+
+ ADVANCE('(' , "(");
+
+ ConditionAST *cond = 0;
+ if (!parseCondition(cond)) {
+ reportError(("condition expected"));
+ return false;
+ }
+ ADVANCE(')', ")");
+
+ StatementAST *stmt = 0;
+ if (!parseCompoundStatement(stmt)) {
+ syntaxError();
+ return false;
+ }
+
+ SwitchStatementAST *ast = CreateNode<SwitchStatementAST>(_M_pool);
+ ast->condition = cond;
+ ast->statement = stmt;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseLabeledStatement(StatementAST *&node)
+{
+ switch (token_stream.lookAhead()) {
+ case Token_identifier:
+ case Token_default:
+ if (token_stream.lookAhead(1) == ':') {
+ token_stream.nextToken();
+ token_stream.nextToken();
+
+ StatementAST *stmt = 0;
+ if (parseStatement(stmt)) {
+ node = stmt;
+ return true;
+ }
+ }
+ break;
+
+ case Token_case: {
+ token_stream.nextToken();
+ ExpressionAST *expr = 0;
+ if (!parseConstantExpression(expr)) {
+ reportError(("expression expected"));
+ } else if (token_stream.lookAhead() == Token_ellipsis) {
+ token_stream.nextToken();
+
+ ExpressionAST *expr2 = 0;
+ if (!parseConstantExpression(expr2))
+ reportError(("expression expected"));
+ }
+ ADVANCE(':', ":");
+
+ StatementAST *stmt = 0;
+ if (parseStatement(stmt)) {
+ node = stmt;
+ return true;
+ }
+ }
+ break;
+
+ }
+
+ return false;
+}
+
+bool Parser::parseBlockDeclaration(DeclarationAST *&node)
+{
+ switch (token_stream.lookAhead()) {
+ case Token_typedef:
+ return parseTypedef(node);
+ case Token_using:
+ return parseUsing(node);
+ case Token_asm:
+ return parseAsmDefinition(node);
+ case Token_namespace:
+ return parseNamespaceAliasDefinition(node);
+ }
+
+ std::size_t start = token_stream.cursor();
+
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ const ListNode<std::size_t> *storageSpec = 0;
+ parseStorageClassSpecifier(storageSpec);
+
+ parseCvQualify(cv);
+
+ TypeSpecifierAST *spec = 0;
+ if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?!
+ token_stream.rewind((int) start);
+ return false;
+ }
+
+ parseCvQualify(cv);
+ spec->cv = cv;
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ parseInitDeclaratorList(declarators);
+
+ if (token_stream.lookAhead() != ';') {
+ token_stream.rewind((int) start);
+ return false;
+ }
+ token_stream.nextToken();
+
+ SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
+ ast->type_specifier = spec;
+ ast->init_declarators = declarators;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_namespace);
+
+ NamespaceAliasDefinitionAST *ast
+ = CreateNode<NamespaceAliasDefinitionAST>(_M_pool);
+
+ ADVANCE(Token_identifier, "identifier");
+ ast->namespace_name = token_stream.cursor() - 1;
+
+ ADVANCE('=', "=");
+
+ if (!parseName(ast->alias_name))
+ reportError(("Namespace name expected"));
+
+ ADVANCE(';', ";");
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDeclarationStatement(StatementAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ DeclarationAST *decl = 0;
+ if (!parseBlockDeclaration(decl))
+ return false;
+
+ DeclarationStatementAST *ast = CreateNode<DeclarationStatementAST>(_M_pool);
+ ast->declaration = decl;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDeclarationInternal(DeclarationAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ // that is for the case '__declspec(dllexport) int ...' or
+ // '__declspec(dllexport) inline int ...', etc.
+ WinDeclSpecAST *winDeclSpec = 0;
+ parseWinDeclSpec(winDeclSpec);
+
+ const ListNode<std::size_t> *funSpec = 0;
+ bool hasFunSpec = parseFunctionSpecifier(funSpec);
+
+ const ListNode<std::size_t> *cv = 0;
+ parseCvQualify(cv);
+
+ const ListNode<std::size_t> *storageSpec = 0;
+ bool hasStorageSpec = parseStorageClassSpecifier(storageSpec);
+
+ if (hasStorageSpec && !hasFunSpec)
+ hasFunSpec = parseFunctionSpecifier(funSpec);
+
+ // that is for the case 'friend __declspec(dllexport) ....'
+ parseWinDeclSpec(winDeclSpec);
+
+ if (!cv)
+ parseCvQualify(cv);
+
+ int index = (int) token_stream.cursor();
+ NameAST *name = 0;
+ if (parseName(name, true) && token_stream.lookAhead() == '(') {
+ // no type specifier, maybe a constructor or a cast operator??
+
+ token_stream.rewind((int) index);
+
+ InitDeclaratorAST *declarator = 0;
+ if (parseInitDeclarator(declarator)) {
+ switch (token_stream.lookAhead()) {
+ case ';': {
+ token_stream.nextToken();
+
+ SimpleDeclarationAST *ast
+ = CreateNode<SimpleDeclarationAST>(_M_pool);
+
+ ast->storage_specifiers = storageSpec;
+ ast->function_specifiers = funSpec;
+ ast->init_declarators = snoc(ast->init_declarators,
+ declarator, _M_pool);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case ':': {
+ CtorInitializerAST *ctorInit = 0;
+ StatementAST *funBody = 0;
+
+ if (parseCtorInitializer(ctorInit)
+ && parseFunctionBody(funBody)) {
+ FunctionDefinitionAST *ast
+ = CreateNode<FunctionDefinitionAST>(_M_pool);
+
+ ast->storage_specifiers = storageSpec;
+ ast->function_specifiers = funSpec;
+ ast->init_declarator = declarator;
+ ast->function_body = funBody;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+ break;
+
+ case '{': {
+ StatementAST *funBody = 0;
+ if (parseFunctionBody(funBody)) {
+ FunctionDefinitionAST *ast
+ = CreateNode<FunctionDefinitionAST>(_M_pool);
+
+ ast->storage_specifiers = storageSpec;
+ ast->function_specifiers = funSpec;
+ ast->init_declarator = declarator;
+ ast->function_body = funBody;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+ break;
+
+ case '(':
+ case '[':
+ // ops!! it seems a declarator
+ goto start_decl;
+ break;
+ }
+
+ }
+ }
+
+start_decl:
+ token_stream.rewind((int) index);
+
+ if (token_stream.lookAhead() == Token_const
+ && token_stream.lookAhead(1) == Token_identifier
+ && token_stream.lookAhead(2) == '=') {
+ // constant definition
+ token_stream.nextToken(); // skip const
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ if (!parseInitDeclaratorList(declarators)) {
+ syntaxError();
+ return false;
+ }
+
+ ADVANCE(';', ";");
+
+#if defined(__GNUC__)
+#warning "mark the ast as constant"
+#endif
+ SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
+ ast->init_declarators = declarators;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+
+ TypeSpecifierAST *spec = 0;
+ if (parseTypeSpecifier(spec)) {
+ Q_ASSERT(spec);
+
+ if (!hasFunSpec)
+ parseFunctionSpecifier(funSpec); // e.g. "void inline"
+
+ spec->cv = cv;
+
+ const ListNode<InitDeclaratorAST*> *declarators = 0;
+ InitDeclaratorAST *decl = 0;
+ int startDeclarator = (int) token_stream.cursor();
+ bool maybeFunctionDefinition = false;
+
+ if (token_stream.lookAhead() != ';') {
+ if (parseInitDeclarator(decl) && token_stream.lookAhead() == '{') {
+ // function definition
+ maybeFunctionDefinition = true;
+ } else {
+ token_stream.rewind((int) startDeclarator);
+ if (!parseInitDeclaratorList(declarators)) {
+ syntaxError();
+ return false;
+ }
+ }
+ }
+
+ switch (token_stream.lookAhead()) {
+ case ';': {
+ token_stream.nextToken();
+ SimpleDeclarationAST *ast
+ = CreateNode<SimpleDeclarationAST>(_M_pool);
+
+ ast->storage_specifiers = storageSpec;
+ ast->function_specifiers = funSpec;
+ ast->type_specifier = spec;
+ ast->win_decl_specifiers = winDeclSpec;
+ ast->init_declarators = declarators;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case '{': {
+ if (!maybeFunctionDefinition) {
+ syntaxError();
+ return false;
+ }
+
+ StatementAST *funBody = 0;
+ if (parseFunctionBody(funBody)) {
+ FunctionDefinitionAST *ast
+ = CreateNode<FunctionDefinitionAST>(_M_pool);
+
+ ast->win_decl_specifiers = winDeclSpec;
+ ast->storage_specifiers = storageSpec;
+ ast->function_specifiers = funSpec;
+ ast->type_specifier = spec;
+ ast->init_declarator = decl;
+ ast->function_body = funBody;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+ break;
+ } // end switch
+ }
+
+ syntaxError();
+ return false;
+}
+
+bool Parser::skipFunctionBody(StatementAST *&)
+{
+#if defined(__GNUC__)
+#warning "Parser::skipFunctionBody() -- implement me"
+#endif
+ Q_ASSERT(0); // ### not implemented
+ return 0;
+}
+
+bool Parser::parseFunctionBody(StatementAST *&node)
+{
+ if (control->skipFunctionBody())
+ return skipFunctionBody(node);
+
+ return parseCompoundStatement(node);
+}
+
+bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node)
+{
+ if (parseClassSpecifier(node))
+ return true;
+ else if (parseEnumSpecifier(node))
+ return true;
+ else if (parseTypeSpecifier(node))
+ return true;
+
+ return false;
+}
+
+bool Parser::parseTryBlockStatement(StatementAST *&node)
+{
+#if defined(__GNUC__)
+#warning "implement me"
+#endif
+ CHECK(Token_try);
+
+ StatementAST *stmt = 0;
+ if (!parseCompoundStatement(stmt)) {
+ syntaxError();
+ return false;
+ }
+
+ if (token_stream.lookAhead() != Token_catch) {
+ reportError(("catch expected"));
+ return false;
+ }
+
+ while (token_stream.lookAhead() == Token_catch) {
+ token_stream.nextToken();
+ ADVANCE('(', "(");
+ ConditionAST *cond = 0;
+ if (token_stream.lookAhead() == Token_ellipsis) {
+ token_stream.nextToken();
+ } else if (!parseCondition(cond, false)) {
+ reportError(("condition expected"));
+ return false;
+ }
+ ADVANCE(')', ")");
+
+ StatementAST *body = 0;
+ if (!parseCompoundStatement(body)) {
+ syntaxError();
+ return false;
+ }
+ }
+
+ node = stmt;
+ return true;
+}
+
+bool Parser::parsePrimaryExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ PrimaryExpressionAST *ast = CreateNode<PrimaryExpressionAST>(_M_pool);
+
+ switch (token_stream.lookAhead()) {
+ case Token_string_literal:
+ parseStringLiteral(ast->literal);
+ break;
+
+ case Token_number_literal:
+ case Token_char_literal:
+ case Token_true:
+ case Token_false:
+ case Token_this:
+ ast->token = token_stream.cursor();
+ token_stream.nextToken();
+ break;
+
+ case '(':
+ token_stream.nextToken();
+
+ if (token_stream.lookAhead() == '{') {
+ if (!parseCompoundStatement(ast->expression_statement))
+ return false;
+ } else {
+ if (!parseExpression(ast->sub_expression))
+ return false;
+ }
+
+ CHECK(')');
+ break;
+
+ default:
+ if (!parseName(ast->name))
+ return false;
+
+ break;
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+
+/*
+ postfix-expression-internal:
+ [ expression ]
+ ( expression-list [opt] )
+ (.|->) template [opt] id-expression
+ (.|->) pseudo-destructor-name
+ ++
+ --
+*/
+bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ switch (token_stream.lookAhead()) {
+ case '[': {
+ token_stream.nextToken();
+ ExpressionAST *expr = 0;
+ parseExpression(expr);
+ CHECK(']');
+
+ SubscriptExpressionAST *ast
+ = CreateNode<SubscriptExpressionAST>(_M_pool);
+
+ ast->subscript = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case '(': {
+ token_stream.nextToken();
+ ExpressionAST *expr = 0;
+ parseExpression(expr);
+ CHECK(')');
+
+ FunctionCallAST *ast = CreateNode<FunctionCallAST>(_M_pool);
+ ast->arguments = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case '.':
+ case Token_arrow: {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ std::size_t templ = 0;
+ if (token_stream.lookAhead() == Token_template) {
+ templ = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ int saved = int(token_stream.cursor());
+ NameAST *name = 0;
+
+ if (parseName(name, true) && name->unqualified_name
+ && name->unqualified_name->template_arguments
+ && token_stream.lookAhead() == '(') {
+ // a template method call
+ // ### reverse the logic
+ } else {
+ token_stream.rewind(saved);
+ name = 0;
+
+ if (!parseName(name, templ != 0))
+ return false;
+ }
+
+ ClassMemberAccessAST *ast = CreateNode<ClassMemberAccessAST>(_M_pool);
+ ast->op = op;
+ ast->name = name;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case Token_incr:
+ case Token_decr: {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ IncrDecrExpressionAST *ast = CreateNode<IncrDecrExpressionAST>(_M_pool);
+ ast->op = op;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*
+ postfix-expression:
+ simple-type-specifier ( expression-list [opt] )
+ primary-expression postfix-expression-internal*
+*/
+bool Parser::parsePostfixExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ switch (token_stream.lookAhead()) {
+ case Token_dynamic_cast:
+ case Token_static_cast:
+ case Token_reinterpret_cast:
+ case Token_const_cast: {
+ std::size_t castOp = token_stream.cursor();
+ token_stream.nextToken();
+
+ CHECK('<');
+ TypeIdAST *typeId = 0;
+ parseTypeId(typeId);
+ CHECK('>');
+
+ CHECK('(');
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+ CHECK(')');
+
+ CppCastExpressionAST *ast = CreateNode<CppCastExpressionAST>(_M_pool);
+ ast->op = castOp;
+ ast->type_id = typeId;
+ ast->expression = expr;
+
+ ExpressionAST *e = 0;
+ while (parsePostfixExpressionInternal(e))
+ ast->sub_expressions = snoc(ast->sub_expressions, e, _M_pool);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case Token_typename: {
+ std::size_t token = token_stream.cursor();
+ token_stream.nextToken();
+
+ NameAST* name = 0;
+ if (!parseName(name, true))
+ return false;
+
+ CHECK('(');
+ ExpressionAST *expr = 0;
+ parseCommaExpression(expr);
+ CHECK(')');
+
+ TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool);
+ ast->typename_token = token;
+ ast->name = name;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case Token_typeid: {
+ token_stream.nextToken();
+
+ CHECK('(');
+ TypeIdAST *typeId = 0;
+ parseTypeId(typeId);
+ CHECK(')');
+
+ TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool);
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ default:
+ break;
+ }
+
+ std::size_t saved_pos = token_stream.cursor();
+
+ TypeSpecifierAST *typeSpec = 0;
+ ExpressionAST *expr = 0;
+
+ // let's try to parse a type
+ NameAST *name = 0;
+ if (parseName(name, true)) {
+ Q_ASSERT(name->unqualified_name);
+
+ bool has_template_args = name->unqualified_name->template_arguments != 0;
+
+ if (has_template_args && token_stream.lookAhead() == '(') {
+ ExpressionAST *cast_expr = 0;
+ if (parseCastExpression(cast_expr)
+ && cast_expr->kind == AST::Kind_CastExpression) {
+ token_stream.rewind((int) saved_pos);
+ parsePrimaryExpression(expr);
+ goto L_no_rewind;
+ }
+ }
+ }
+
+ token_stream.rewind((int) saved_pos);
+
+L_no_rewind:
+ if (!expr && parseSimpleTypeSpecifier(typeSpec)
+ && token_stream.lookAhead() == '(') {
+ token_stream.nextToken(); // skip '('
+ parseCommaExpression(expr);
+ CHECK(')');
+ } else if (expr) {
+ typeSpec = 0;
+ } else {
+ typeSpec = 0;
+ token_stream.rewind((int) start);
+
+ if (!parsePrimaryExpression(expr))
+ return false;
+ }
+
+ const ListNode<ExpressionAST*> *sub_expressions = 0;
+ ExpressionAST *sub_expression = 0;
+
+ while (parsePostfixExpressionInternal(sub_expression))
+ sub_expressions = snoc(sub_expressions, sub_expression, _M_pool);
+
+ if (sub_expressions || !expr || (typeSpec && expr)) {
+ PostfixExpressionAST *ast = CreateNode<PostfixExpressionAST>(_M_pool);
+ ast->type_specifier = typeSpec;
+ ast->expression = expr;
+ ast->sub_expressions = sub_expressions;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ } else
+ node = expr;
+
+ return true;
+}
+
+bool Parser::parseUnaryExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ switch (token_stream.lookAhead()) {
+ case Token_incr:
+ case Token_decr:
+ case '*':
+ case '&':
+ case '+':
+ case '-':
+ case '!':
+ case '~': {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *expr = 0;
+ if (!parseCastExpression(expr))
+ return false;
+
+ UnaryExpressionAST *ast = CreateNode<UnaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->expression = expr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+ return true;
+
+ case Token_sizeof: {
+ std::size_t sizeof_token = token_stream.cursor();
+ token_stream.nextToken();
+
+ SizeofExpressionAST *ast = CreateNode<SizeofExpressionAST>(_M_pool);
+ ast->sizeof_token = sizeof_token;
+
+ std::size_t index = token_stream.cursor();
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+ if (parseTypeId(ast->type_id) && token_stream.lookAhead() == ')') {
+ token_stream.nextToken(); // skip )
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ return true;
+ }
+
+ ast->type_id = 0;
+ token_stream.rewind((int) index);
+ }
+
+ if (!parseUnaryExpression(ast->expression))
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ int token = token_stream.lookAhead();
+
+ if (token == Token_new
+ || (token == Token_scope && token_stream.lookAhead(1) == Token_new))
+ return parseNewExpression(node);
+
+ if (token == Token_delete
+ || (token == Token_scope && token_stream.lookAhead(1) == Token_delete))
+ return parseDeleteExpression(node);
+
+ return parsePostfixExpression(node);
+}
+
+bool Parser::parseNewExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ NewExpressionAST *ast = CreateNode<NewExpressionAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_scope
+ && token_stream.lookAhead(1) == Token_new) {
+ ast->scope_token = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ CHECK(Token_new);
+ ast->new_token = token_stream.cursor() - 1;
+
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+ parseCommaExpression(ast->expression);
+ CHECK(')');
+ }
+
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+ parseTypeId(ast->type_id);
+ CHECK(')');
+ } else {
+ parseNewTypeId(ast->new_type_id);
+ }
+
+ parseNewInitializer(ast->new_initializer);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNewTypeId(NewTypeIdAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ TypeSpecifierAST *typeSpec = 0;
+ if (!parseTypeSpecifier(typeSpec))
+ return false;
+
+ NewTypeIdAST *ast = CreateNode<NewTypeIdAST>(_M_pool);
+ ast->type_specifier = typeSpec;
+
+ parseNewDeclarator(ast->new_declarator);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ NewDeclaratorAST *ast = CreateNode<NewDeclaratorAST>(_M_pool);
+
+ PtrOperatorAST *ptrOp = 0;
+ if (parsePtrOperator(ptrOp)) {
+ ast->ptr_op = ptrOp;
+ parseNewDeclarator(ast->sub_declarator);
+ }
+
+ while (token_stream.lookAhead() == '[') {
+ token_stream.nextToken();
+ ExpressionAST *expr = 0;
+ parseExpression(expr);
+ ast->expressions = snoc(ast->expressions, expr, _M_pool);
+ ADVANCE(']', "]");
+ }
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNewInitializer(NewInitializerAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK('(');
+
+ NewInitializerAST *ast = CreateNode<NewInitializerAST>(_M_pool);
+
+ parseCommaExpression(ast->expression);
+
+ CHECK(')');
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDeleteExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ DeleteExpressionAST *ast = CreateNode<DeleteExpressionAST>(_M_pool);
+
+ if (token_stream.lookAhead() == Token_scope
+ && token_stream.lookAhead(1) == Token_delete) {
+ ast->scope_token = token_stream.cursor();
+ token_stream.nextToken();
+ }
+
+ CHECK(Token_delete);
+ ast->delete_token = token_stream.cursor() - 1;
+
+ if (token_stream.lookAhead() == '[') {
+ ast->lbracket_token = token_stream.cursor();
+ token_stream.nextToken();
+ CHECK(']');
+ ast->rbracket_token = token_stream.cursor() - 1;
+ }
+
+ if (!parseCastExpression(ast->expression))
+ return false;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseCastExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (token_stream.lookAhead() == '(') {
+ token_stream.nextToken();
+
+ CastExpressionAST *ast = CreateNode<CastExpressionAST>(_M_pool);
+
+ if (parseTypeId(ast->type_id)) {
+ if (token_stream.lookAhead() == ')') {
+ token_stream.nextToken();
+
+ if (parseCastExpression(ast->expression)) {
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+ }
+ }
+ }
+ }
+
+ token_stream.rewind((int) start);
+ return parseUnaryExpression(node);
+}
+
+bool Parser::parsePmExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseCastExpression(node) || !node) // ### fixme
+ return false;
+
+ while (token_stream.lookAhead() == Token_ptrmem) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseCastExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parsePmExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == '*'
+ || token_stream.lookAhead() == '/'
+ || token_stream.lookAhead() == '%') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parsePmExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+
+bool Parser::parseAdditiveExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseMultiplicativeExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == '+' || token_stream.lookAhead() == '-') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseMultiplicativeExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseShiftExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseAdditiveExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == Token_shift) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseAdditiveExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseShiftExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == '<'
+ || (token_stream.lookAhead() == '>' && !templArgs)
+ || token_stream.lookAhead() == Token_leq
+ || token_stream.lookAhead() == Token_geq) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseShiftExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseRelationalExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == Token_eq
+ || token_stream.lookAhead() == Token_not_eq) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseRelationalExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseEqualityExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == '&') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseEqualityExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseAndExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == '^') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseAndExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseExclusiveOrExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == '|') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseExclusiveOrExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseInclusiveOrExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == Token_and) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseInclusiveOrExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseLogicalAndExpression(node, templArgs))
+ return false;
+
+ while (token_stream.lookAhead() == Token_or) {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseLogicalAndExpression(rightExpr, templArgs))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseConditionalExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseLogicalOrExpression(node))
+ return false;
+
+ if (token_stream.lookAhead() == '?') {
+ token_stream.nextToken();
+
+ ExpressionAST *leftExpr = 0;
+ if (!parseExpression(leftExpr))
+ return false;
+
+ CHECK(':');
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseAssignmentExpression(rightExpr))
+ return false;
+
+ ConditionalExpressionAST *ast
+ = CreateNode<ConditionalExpressionAST>(_M_pool);
+
+ ast->condition = node;
+ ast->left_expression = leftExpr;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseAssignmentExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (token_stream.lookAhead() == Token_throw && !parseThrowExpression(node))
+ return false;
+ else if (!parseConditionalExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == Token_assign
+ || token_stream.lookAhead() == '=') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseConditionalExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseConstantExpression(ExpressionAST *&node)
+{
+ return parseConditionalExpression(node);
+}
+
+bool Parser::parseExpression(ExpressionAST *&node)
+{
+ return parseCommaExpression(node);
+}
+
+bool Parser::parseCommaExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ if (!parseAssignmentExpression(node))
+ return false;
+
+ while (token_stream.lookAhead() == ',') {
+ std::size_t op = token_stream.cursor();
+ token_stream.nextToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (!parseAssignmentExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
+ ast->op = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseThrowExpression(ExpressionAST *&node)
+{
+ std::size_t start = token_stream.cursor();
+
+ CHECK(Token_throw);
+
+ ThrowExpressionAST *ast = CreateNode<ThrowExpressionAST>(_M_pool);
+ ast->throw_token = token_stream.cursor() - 1;
+
+ parseAssignmentExpression(ast->expression);
+
+ UPDATE_POS(ast, start, token_stream.cursor());
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseQ_ENUMS(DeclarationAST *&node)
+{
+ if (token_stream.lookAhead() != Token_Q_ENUMS)
+ return false;
+
+ if (token_stream.lookAhead(1) != '(')
+ return false;
+
+ token_stream.nextToken();
+ token_stream.nextToken();
+
+ int firstToken = token_stream.cursor();
+ while (token_stream.lookAhead() != ')')
+ token_stream.nextToken();
+
+ QEnumsAST *ast = CreateNode<QEnumsAST>(_M_pool);
+ UPDATE_POS(ast, firstToken, token_stream.cursor());
+ node = ast;
+
+ token_stream.nextToken();
+
+ return true;
+}
+
+bool Parser::parseQ_PROPERTY(DeclarationAST *&node)
+{
+ if (token_stream.lookAhead() != Token_Q_PROPERTY)
+ return false;
+
+ if (token_stream.lookAhead(1) != '(')
+ return false;
+
+ token_stream.nextToken();
+ token_stream.nextToken();
+
+ int firstToken = token_stream.cursor();
+ while (token_stream.lookAhead() != ')')
+ token_stream.nextToken();
+
+ QPropertyAST *ast = CreateNode<QPropertyAST>(_M_pool);
+ UPDATE_POS(ast, firstToken, token_stream.cursor());
+ node = ast;
+
+// const Token &t1 = token_stream[firstToken];
+// const Token &t2 = token_stream[token_stream.cursor()];
+// printf("property: %s\n",
+// qPrintable(QString::fromLatin1(t1.text + t1.position, t2.position - t1.position)));
+
+ token_stream.nextToken();
+
+ return true;
+}
+
+bool Parser::block_errors(bool block)
+{
+ bool current = _M_block_errors;
+ _M_block_errors = block;
+ return current;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/parser.h b/parser/parser.h
new file mode 100644
index 000000000..4b0c76c85
--- /dev/null
+++ b/parser/parser.h
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include "ast.h"
+#include "lexer.h"
+
+#include <QtCore/QString>
+
+class FileSymbol;
+class Control;
+
+class Parser
+{
+public:
+ Parser(Control *control);
+ ~Parser();
+
+ LocationManager &location() { return _M_location; }
+
+ TranslationUnitAST *parse(const char *contents, std::size_t size, pool *p);
+
+private:
+ void reportError(const QString& msg);
+ void syntaxError();
+ void tokenRequiredError(int expected);
+
+public:
+ bool skipFunctionBody(StatementAST *&node);
+
+public:
+ bool parse_Attribute__();
+ bool parseAbstractDeclarator(DeclaratorAST *&node);
+ bool parseAccessSpecifier(DeclarationAST *&node);
+ bool parseAdditiveExpression(ExpressionAST *&node);
+ bool parseAndExpression(ExpressionAST *&node, bool templArgs = false);
+ bool parseAsmDefinition(DeclarationAST *&node);
+ bool parseAssignmentExpression(ExpressionAST *&node);
+ bool parseBaseClause(BaseClauseAST *&node);
+ bool parseBaseSpecifier(BaseSpecifierAST *&node);
+ bool parseBlockDeclaration(DeclarationAST *&node);
+ bool parseCastExpression(ExpressionAST *&node);
+ bool parseClassSpecifier(TypeSpecifierAST *&node);
+ bool parseForwardDeclarationSpecifier(TypeSpecifierAST *&node);
+ bool parseCommaExpression(ExpressionAST *&node);
+ bool parseCompoundStatement(StatementAST *&node);
+ bool parseCondition(ConditionAST *&node, bool initRequired = true);
+ bool parseConditionalExpression(ExpressionAST *&node);
+ bool parseConstantExpression(ExpressionAST *&node);
+ bool parseCtorInitializer(CtorInitializerAST *&node);
+ bool parseCvQualify(const ListNode<std::size_t> *&node);
+ bool parseDeclaration(DeclarationAST *&node);
+ bool parseDeclarationInternal(DeclarationAST *&node);
+ bool parseDeclarationStatement(StatementAST *&node);
+ bool parseDeclarator(DeclaratorAST *&node);
+ bool parseDeleteExpression(ExpressionAST *&node);
+ bool parseDoStatement(StatementAST *&node);
+ bool parseElaboratedTypeSpecifier(TypeSpecifierAST *&node);
+ bool parseEnumSpecifier(TypeSpecifierAST *&node);
+ bool parseEnumerator(EnumeratorAST *&node);
+ bool parseEqualityExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseExceptionSpecification(ExceptionSpecificationAST *&node);
+ bool parseExclusiveOrExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseExpression(ExpressionAST *&node);
+ bool parseExpressionOrDeclarationStatement(StatementAST *&node);
+ bool parseExpressionStatement(StatementAST *&node);
+ bool parseForInitStatement(StatementAST *&node);
+ bool parseForStatement(StatementAST *&node);
+ bool parseFunctionBody(StatementAST *&node);
+ bool parseFunctionSpecifier(const ListNode<std::size_t> *&node);
+ bool parseIfStatement(StatementAST *&node);
+ bool parseInclusiveOrExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseInitDeclarator(InitDeclaratorAST *&node);
+ bool parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node);
+ bool parseInitializer(InitializerAST *&node);
+ bool parseInitializerClause(InitializerClauseAST *&node);
+ bool parseLabeledStatement(StatementAST *&node);
+ bool parseLinkageBody(LinkageBodyAST *&node);
+ bool parseLinkageSpecification(DeclarationAST *&node);
+ bool parseLogicalAndExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseLogicalOrExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseMemInitializer(MemInitializerAST *&node);
+ bool parseMemInitializerList(const ListNode<MemInitializerAST*> *&node);
+ bool parseMemberSpecification(DeclarationAST *&node);
+ bool parseMultiplicativeExpression(ExpressionAST *&node);
+ bool parseName(NameAST *&node, bool acceptTemplateId = false);
+ bool parseNamespace(DeclarationAST *&node);
+ bool parseNamespaceAliasDefinition(DeclarationAST *&node);
+ bool parseNewDeclarator(NewDeclaratorAST *&node);
+ bool parseNewExpression(ExpressionAST *&node);
+ bool parseNewInitializer(NewInitializerAST *&node);
+ bool parseNewTypeId(NewTypeIdAST *&node);
+ bool parseOperator(OperatorAST *&node);
+ bool parseOperatorFunctionId(OperatorFunctionIdAST *&node);
+ bool parseParameterDeclaration(ParameterDeclarationAST *&node);
+ bool parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node);
+ bool parseParameterDeclarationList(const ListNode<ParameterDeclarationAST*> *&node);
+ bool parsePmExpression(ExpressionAST *&node);
+ bool parsePostfixExpression(ExpressionAST *&node);
+ bool parsePostfixExpressionInternal(ExpressionAST *&node);
+ bool parsePrimaryExpression(ExpressionAST *&node);
+ bool parsePtrOperator(PtrOperatorAST *&node);
+ bool parsePtrToMember(PtrToMemberAST *&node);
+ bool parseRelationalExpression(ExpressionAST *&node,
+ bool templArgs = false);
+ bool parseShiftExpression(ExpressionAST *&node);
+ bool parseSimpleTypeSpecifier(TypeSpecifierAST *&node,
+ bool onlyIntegral = false);
+ bool parseStatement(StatementAST *&node);
+ bool parseStorageClassSpecifier(const ListNode<std::size_t> *&node);
+ bool parseStringLiteral(StringLiteralAST *&node);
+ bool parseSwitchStatement(StatementAST *&node);
+ bool parseTemplateArgument(TemplateArgumentAST *&node);
+ bool parseTemplateArgumentList(const ListNode<TemplateArgumentAST*> *&node,
+ bool reportError = true);
+ bool parseTemplateDeclaration(DeclarationAST *&node);
+ bool parseTemplateParameter(TemplateParameterAST *&node);
+ bool parseTemplateParameterList(const ListNode<TemplateParameterAST*> *&node);
+ bool parseThrowExpression(ExpressionAST *&node);
+ bool parseTranslationUnit(TranslationUnitAST *&node);
+ bool parseTryBlockStatement(StatementAST *&node);
+ bool parseTypeId(TypeIdAST *&node);
+ bool parseTypeIdList(const ListNode<TypeIdAST*> *&node);
+ bool parseTypeParameter(TypeParameterAST *&node);
+ bool parseTypeSpecifier(TypeSpecifierAST *&node);
+ bool parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node);
+ bool parseTypedef(DeclarationAST *&node);
+ bool parseUnaryExpression(ExpressionAST *&node);
+ bool parseUnqualifiedName(UnqualifiedNameAST *&node,
+ bool parseTemplateId = true);
+ bool parseUsing(DeclarationAST *&node);
+ bool parseUsingDirective(DeclarationAST *&node);
+ bool parseWhileStatement(StatementAST *&node);
+ bool parseWinDeclSpec(WinDeclSpecAST *&node);
+
+ bool parseQ_PROPERTY(DeclarationAST *&node);
+ bool parseQ_ENUMS(DeclarationAST *&node);
+
+ bool skipUntil(int token);
+ bool skipUntilDeclaration();
+ bool skipUntilStatement();
+ bool skip(int l, int r);
+
+ void advance();
+
+ // private:
+ TokenStream token_stream;
+ LocationTable location_table;
+ LocationTable line_table;
+
+ bool block_errors(bool block);
+
+private:
+ QString tokenText(AST *) const;
+
+ LocationManager _M_location;
+ Control *control;
+ Lexer lexer;
+ pool *_M_pool;
+ bool _M_block_errors;
+
+private:
+ Parser(const Parser& source);
+ void operator = (const Parser& source);
+};
+
+#endif
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/r++.macros b/parser/r++.macros
new file mode 100644
index 000000000..455276c84
--- /dev/null
+++ b/parser/r++.macros
@@ -0,0 +1,28 @@
+
+#define __attribute__(a...)
+#define __typeof__ __typeof
+
+#define __extension
+#define __extension__
+
+#define __restrict
+#define __restrict__
+
+#define __volatile volatile
+#define __volatile__ volatile
+
+#define __inline inline
+#define __inline__ inline
+
+#define __const const
+#define __const__ const
+
+#define __asm asm
+#define __asm__ asm
+
+#define __GNUC__ 3
+//#define __GNUC_MINOR__ 4
+
+#define __ROBC__ 0
+#define __ROBC_MINOR__ 1
+
diff --git a/parser/rpp-allocator.h b/parser/rpp-allocator.h
new file mode 100644
index 000000000..313895f00
--- /dev/null
+++ b/parser/rpp-allocator.h
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "parser/rxx_allocator.h"
diff --git a/parser/rpp/builtin-macros.cpp b/parser/rpp/builtin-macros.cpp
new file mode 100644
index 000000000..1b0fc06af
--- /dev/null
+++ b/parser/rpp/builtin-macros.cpp
@@ -0,0 +1,23 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
diff --git a/parser/rpp/pp-cctype.h b/parser/rpp/pp-cctype.h
new file mode 100644
index 000000000..5b0bf477c
--- /dev/null
+++ b/parser/rpp/pp-cctype.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_CCTYPE_H
+#define PP_CCTYPE_H
+
+#include <cctype>
+
+namespace rpp
+{
+
+inline bool pp_isalpha(int __ch)
+{
+ return std::isalpha((unsigned char) __ch) != 0;
+}
+
+inline bool pp_isalnum(int __ch)
+{
+ return std::isalnum((unsigned char) __ch) != 0;
+}
+
+inline bool pp_isdigit(int __ch)
+{
+ return std::isdigit((unsigned char) __ch) != 0;
+}
+
+inline bool pp_isspace(int __ch)
+{
+ return std::isspace((unsigned char) __ch) != 0;
+}
+
+} // namespace rpp
+
+#endif // PP_CCTYPE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-configuration b/parser/rpp/pp-configuration
new file mode 100644
index 000000000..15586dd88
--- /dev/null
+++ b/parser/rpp/pp-configuration
@@ -0,0 +1,86 @@
+#define __DBL_MIN_EXP__ (-1021)
+#define __FLT_MIN__ 1.17549435e-38F
+#define __CHAR_BIT__ 8
+#define __WCHAR_MAX__ 2147483647
+#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+#define __FLT_EVAL_METHOD__ 2
+#define __DBL_MIN_10_EXP__ (-307)
+#define __FINITE_MATH_ONLY__ 0
+#define __GNUC_PATCHLEVEL__ 2
+#define __SHRT_MAX__ 32767
+#define __LDBL_MAX__ 1.18973149535723176502e+4932L
+#define __UINTMAX_TYPE__ long long unsigned int
+#define __linux 1
+#define __unix 1
+#define __LDBL_MAX_EXP__ 16384
+#define __linux__ 1
+#define __SCHAR_MAX__ 127
+#define __USER_LABEL_PREFIX__
+#define __STDC_HOSTED__ 1
+#define __LDBL_HAS_INFINITY__ 1
+#define __DBL_DIG__ 15
+#define __FLT_EPSILON__ 1.19209290e-7F
+#define __GXX_WEAK__ 1
+#define __LDBL_MIN__ 3.36210314311209350626e-4932L
+#define __unix__ 1
+#define __DECIMAL_DIG__ 21
+#define __gnu_linux__ 1
+#define __LDBL_HAS_QUIET_NAN__ 1
+#define __GNUC__ 4
+#define __DBL_MAX__ 1.7976931348623157e+308
+#define __DBL_HAS_INFINITY__ 1
+#define __cplusplus 1
+#define __DEPRECATED 1
+#define __DBL_MAX_EXP__ 1024
+#define __GNUG__ 4
+#define __LONG_LONG_MAX__ 9223372036854775807LL
+#define __GXX_ABI_VERSION 1002
+#define __FLT_MIN_EXP__ (-125)
+#define __DBL_MIN__ 2.2250738585072014e-308
+#define __FLT_MIN_10_EXP__ (-37)
+#define __DBL_HAS_QUIET_NAN__ 1
+#define __REGISTER_PREFIX__
+#define __NO_INLINE__ 1
+#define __i386 1
+#define __FLT_MANT_DIG__ 24
+#define __VERSION__ "4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)"
+#define i386 1
+#define __i486__ 1
+#define unix 1
+#define __i386__ 1
+#define __SIZE_TYPE__ unsigned int
+#define __ELF__ 1
+#define __FLT_RADIX__ 2
+#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
+#define __FLT_HAS_QUIET_NAN__ 1
+#define __FLT_MAX_10_EXP__ 38
+#define __LONG_MAX__ 2147483647L
+#define __FLT_HAS_INFINITY__ 1
+#define linux 1
+#define __EXCEPTIONS 1
+#define __LDBL_MANT_DIG__ 64
+#define __WCHAR_TYPE__ int
+#define __FLT_DIG__ 6
+#define __INT_MAX__ 2147483647
+#define __i486 1
+#define __FLT_MAX_EXP__ 128
+#define __DBL_MANT_DIG__ 53
+#define __WINT_TYPE__ unsigned int
+#define __LDBL_MIN_EXP__ (-16381)
+#define __LDBL_MAX_10_EXP__ 4932
+#define __DBL_EPSILON__ 2.2204460492503131e-16
+#define __tune_i486__ 1
+#define __INTMAX_MAX__ 9223372036854775807LL
+#define __FLT_DENORM_MIN__ 1.40129846e-45F
+#define __FLT_MAX__ 3.40282347e+38F
+#define __INTMAX_TYPE__ long long int
+#define __GNUC_MINOR__ 0
+#define __DBL_MAX_10_EXP__ 308
+#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
+#define __PTRDIFF_TYPE__ int
+#define __LDBL_MIN_10_EXP__ (-4931)
+#define __LDBL_DIG__ 18
+#define _GNU_SOURCE 1
+
+
+#define __STDC__
diff --git a/parser/rpp/pp-engine-bits.h b/parser/rpp/pp-engine-bits.h
new file mode 100644
index 000000000..7594ab796
--- /dev/null
+++ b/parser/rpp/pp-engine-bits.h
@@ -0,0 +1,1252 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_ENGINE_BITS_H
+#define PP_ENGINE_BITS_H
+
+#include "pp.h"
+#include <sys/stat.h>
+#include <cstdio>
+#include <iostream>
+
+namespace rpp
+{
+
+inline std::string pp::fix_file_path(std::string const &filename) const
+{
+#if defined (PP_OS_WIN)
+ std::string s = filename;
+ for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
+ if (*it == '/')
+ *it = '\\';
+ }
+ return s;
+#else
+ return filename;
+#endif
+}
+
+inline bool pp::is_absolute(std::string const &filename) const
+{
+#if defined(PP_OS_WIN)
+ return filename.length() >= 3
+ && filename.at(1) == ':'
+ && (filename.at(2) == '\\' || filename.at(2) == '/');
+#else
+ return filename.length() >= 1
+ && filename.at(0) == '/';
+#endif
+}
+
+template <typename _OutputIterator>
+void pp::file(std::string const &filename, _OutputIterator __result)
+{
+ FILE *fp = std::fopen(filename.c_str(), "rb");
+ if (fp != 0) {
+ std::string was = env.current_file;
+ env.current_file = filename;
+ file(fp, __result);
+ env.current_file = was;
+ }
+ //else
+ //std::cerr << "** WARNING file ``" << filename << " not found!" << std::endl;
+}
+
+template <typename _OutputIterator>
+void pp::file(FILE *fp, _OutputIterator __result)
+{
+ assert(fp != 0);
+
+#if defined (HAVE_MMAP)
+ struct stat st;
+ fstat(FILENO(fp), &st);
+ std::size_t size = st.st_size;
+ char *buffer = 0;
+ buffer = (char *) ::mmap(0, size, PROT_READ, MAP_SHARED, FILENO(fp), 0);
+ fclose(fp);
+ if (!buffer || buffer == (char*) - 1)
+ return;
+ this->operator()(buffer, buffer + size, __result);
+ ::munmap(buffer, size);
+#else
+ std::string buffer;
+ while (!feof(fp)) {
+ char tmp[1024];
+ int read = (int) fread(tmp, sizeof(char), 1023, fp);
+ tmp[read] = '\0';
+ buffer += tmp;
+ }
+ fclose(fp);
+ this->operator()(buffer.c_str(), buffer.c_str() + buffer.size(), __result);
+#endif
+}
+
+template <typename _InputIterator>
+bool pp::find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot)
+{
+ int was = env.current_line;
+
+ while (__first != __last) {
+ if (pp_isspace(*__first)) {
+ if (*__first == '\n')
+ ++env.current_line;
+
+ ++__first;
+ } else if (_PP_internal::comment_p(__first, __last)) {
+ __first = skip_comment_or_divop(__first, __last);
+ env.current_line += skip_comment_or_divop.lines;
+ } else if (*__first == '#') {
+ __first = skip_blanks(++__first, __last);
+ env.current_line += skip_blanks.lines;
+
+ if (__first != __last && *__first == 'i') {
+ _InputIterator __begin = __first;
+ __first = skip_identifier(__begin, __last);
+ env.current_line += skip_identifier.lines;
+
+ std::string __directive(__begin, __first);
+
+ if (__directive == "ifndef") {
+ __first = skip_blanks(__first, __last);
+ env.current_line += skip_blanks.lines;
+
+ __begin = __first;
+ __first = skip_identifier(__first, __last);
+ env.current_line += skip_identifier.lines;
+
+ if (__begin != __first && __first != __last) {
+ __prot->assign(__begin, __first);
+ return true;
+ }
+ }
+ }
+ break;
+ } else
+ break;
+ }
+
+ env.current_line = was;
+ return false;
+}
+
+inline pp::PP_DIRECTIVE_TYPE pp::find_directive(char const *__directive, std::size_t __size) const
+{
+ switch (__size) {
+ case 2:
+ if (__directive[0] == 'i'
+ && __directive[1] == 'f')
+ return PP_IF;
+ break;
+
+ case 4:
+ if (__directive[0] == 'e' && !strcmp(__directive, "elif"))
+ return PP_ELIF;
+ else if (__directive[0] == 'e' && !strcmp(__directive, "else"))
+ return PP_ELSE;
+ break;
+
+ case 5:
+ if (__directive[0] == 'i' && !strcmp(__directive, "ifdef"))
+ return PP_IFDEF;
+ else if (__directive[0] == 'u' && !strcmp(__directive, "undef"))
+ return PP_UNDEF;
+ else if (__directive[0] == 'e') {
+ if (!strcmp(__directive, "endif"))
+ return PP_ENDIF;
+ else if (!strcmp(__directive, "error"))
+ return PP_ERROR;
+ }
+ break;
+
+ case 6:
+ if (__directive[0] == 'i' && !strcmp(__directive, "ifndef"))
+ return PP_IFNDEF;
+ else if (__directive[0] == 'd' && !strcmp(__directive, "define"))
+ return PP_DEFINE;
+ else if (__directive[0] == 'p' && !strcmp(__directive, "pragma"))
+ return PP_PRAGMA;
+ break;
+
+ case 7:
+ if (__directive[0] == 'i' && !strcmp(__directive, "include"))
+ return PP_INCLUDE;
+ else if (!strcmp(__directive, "warning"))
+ return PP_WARNING;
+ break;
+
+ case 12:
+ if (__directive[0] == 'i' && !strcmp(__directive, "include_next"))
+ return PP_INCLUDE_NEXT;
+ break;
+
+ default:
+ break;
+ }
+ std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl;
+ return PP_UNKNOWN_DIRECTIVE;
+}
+
+inline bool pp::file_isdir(std::string const &__filename) const
+{
+ struct stat __st;
+#if defined(PP_OS_WIN)
+ if (stat(__filename.c_str(), &__st) == 0)
+ return (__st.st_mode & _S_IFDIR) == _S_IFDIR;
+ else
+ return false;
+#else
+ if (lstat(__filename.c_str(), &__st) == 0)
+ return (__st.st_mode & S_IFDIR) == S_IFDIR;
+ else
+ return false;
+#endif
+}
+
+inline bool pp::file_exists(std::string const &__filename) const
+{
+ struct stat __st;
+#if defined(PP_OS_WIN)
+ return stat(__filename.c_str(), &__st) == 0;
+#else
+ return lstat(__filename.c_str(), &__st) == 0;
+#endif
+}
+
+inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath,
+ INCLUDE_POLICY __include_policy, bool __skip_current_path) const
+{
+ assert(__filepath != 0);
+ assert(! __input_filename.empty());
+
+ __filepath->assign(__input_filename);
+
+ if (is_absolute(*__filepath))
+ return std::fopen(__filepath->c_str(), "r");
+
+ if (! env.current_file.empty())
+ _PP_internal::extract_file_path(env.current_file, __filepath);
+
+ if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) {
+ std::string __tmp(*__filepath);
+ __tmp += __input_filename;
+
+ if (file_exists(__tmp) && !file_isdir(__tmp)) {
+ __filepath->append(__input_filename);
+ return std::fopen(__filepath->c_str(), "r");
+ }
+ }
+
+ std::vector<std::string>::const_iterator it = include_paths.begin();
+
+ if (__skip_current_path) {
+ it = std::find(include_paths.begin(), include_paths.end(), *__filepath);
+
+ if (it != include_paths.end())
+ ++it;
+
+ else
+ it = include_paths.begin();
+ }
+
+ for (; it != include_paths.end(); ++it) {
+ if (__skip_current_path && it == include_paths.begin())
+ continue;
+
+ __filepath->assign(*it);
+ __filepath->append(__input_filename);
+
+ if (file_exists(*__filepath) && !file_isdir(*__filepath))
+ return std::fopen(__filepath->c_str(), "r");
+
+#ifdef Q_OS_MAC
+ // try in Framework path on Mac, if there is a path in front
+ // ### what about escaped slashes?
+ size_t slashPos = __input_filename.find('/');
+ if (slashPos != std::string::npos) {
+ __filepath->assign(*it);
+ __filepath->append(__input_filename.substr(0, slashPos));
+ __filepath->append(".framework/Headers/");
+ __filepath->append(__input_filename.substr(slashPos + 1, std::string::npos));
+ std::cerr << *__filepath << "\n";
+
+ if (file_exists(*__filepath) && !file_isdir(*__filepath))
+ return fopen(__filepath->c_str(), "r");
+ }
+#endif // Q_OS_MAC
+ }
+
+ return 0;
+}
+
+template <typename _InputIterator, typename _OutputIterator>
+_InputIterator pp::handle_directive(char const *__directive, std::size_t __size,
+ _InputIterator __first, _InputIterator __last, _OutputIterator __result)
+{
+ __first = skip_blanks(__first, __last);
+
+ PP_DIRECTIVE_TYPE d = find_directive(__directive, __size);
+ switch (d) {
+ case PP_DEFINE:
+ if (! skipping())
+ return handle_define(__first, __last);
+ break;
+
+ case PP_INCLUDE:
+ case PP_INCLUDE_NEXT:
+ if (! skipping())
+ return handle_include(d == PP_INCLUDE_NEXT, __first, __last, __result);
+ break;
+
+ case PP_UNDEF:
+ if (! skipping())
+ return handle_undef(__first, __last);
+ break;
+
+ case PP_ELIF:
+ return handle_elif(__first, __last);
+
+ case PP_ELSE:
+ return handle_else(__first, __last);
+
+ case PP_ENDIF:
+ return handle_endif(__first, __last);
+
+ case PP_IF:
+ return handle_if(__first, __last);
+
+ case PP_IFDEF:
+ return handle_ifdef(false, __first, __last);
+
+ case PP_IFNDEF:
+ return handle_ifdef(true, __first, __last);
+
+ default:
+ break;
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator, typename _OutputIterator>
+_InputIterator pp::handle_include(bool __skip_current_path, _InputIterator __first, _InputIterator __last,
+ _OutputIterator __result)
+{
+ if (pp_isalpha(*__first) || *__first == '_') {
+ pp_macro_expander expand_include(env);
+ std::string name;
+ name.reserve(255);
+ expand_include(__first, __last, std::back_inserter(name));
+ std::string::iterator it = skip_blanks(name.begin(), name.end());
+ assert(it != name.end() && (*it == '<' || *it == '"'));
+ handle_include(__skip_current_path, it, name.end(), __result);
+ return __first;
+ }
+
+ assert(*__first == '<' || *__first == '"');
+ int quote = (*__first == '"') ? '"' : '>';
+ ++__first;
+
+ _InputIterator end_name = __first;
+ for (; end_name != __last; ++end_name) {
+ assert(*end_name != '\n');
+
+ if (*end_name == quote)
+ break;
+ }
+
+ std::string filename(__first, end_name);
+
+#ifdef PP_OS_WIN
+ std::replace(filename.begin(), filename.end(), '/', '\\');
+#endif
+
+ std::string filepath;
+ FILE *fp = find_include_file(filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path);
+
+#if defined (PP_HOOK_ON_FILE_INCLUDED)
+ PP_HOOK_ON_FILE_INCLUDED(env.current_file, fp ? filepath : filename, fp);
+#endif
+
+ if (fp != 0) {
+ std::string old_file = env.current_file;
+ env.current_file = filepath;
+ int __saved_lines = env.current_line;
+
+ env.current_line = 1;
+ //output_line (env.current_file, 1, __result);
+
+ file(fp, __result);
+
+ // restore the file name and the line position
+ env.current_file = old_file;
+ env.current_line = __saved_lines;
+
+ // sync the buffer
+ _PP_internal::output_line(env.current_file, env.current_line, __result);
+ }
+#ifndef RPP_JAMBI
+// else
+// std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl;
+#endif
+
+ return __first;
+}
+
+template <typename _InputIterator, typename _OutputIterator>
+void pp::operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
+{
+#ifndef PP_NO_SMART_HEADER_PROTECTION
+ std::string __prot;
+ __prot.reserve(255);
+ pp_fast_string __tmp(__prot.c_str(), __prot.size());
+
+ if (find_header_protection(__first, __last, &__prot)
+ && env.resolve(&__tmp) != 0) {
+ // std::cerr << "** DEBUG found header protection:" << __prot << std::endl;
+ return;
+ }
+#endif
+
+ env.current_line = 1;
+ char __buffer[512];
+
+ while (true) {
+ __first = skip_blanks(__first, __last);
+ env.current_line += skip_blanks.lines;
+
+ if (__first == __last)
+ break;
+ else if (*__first == '#') {
+ assert(*__first == '#');
+ __first = skip_blanks(++__first, __last);
+ env.current_line += skip_blanks.lines;
+
+ _InputIterator end_id = skip_identifier(__first, __last);
+ env.current_line += skip_identifier.lines;
+ std::size_t __size = end_id - __first;
+
+ assert(__size < 512);
+ char *__cp = __buffer;
+ std::copy(__first, end_id, __cp);
+ __cp[__size] = '\0';
+
+ end_id = skip_blanks(end_id, __last);
+ __first = skip(end_id, __last);
+
+ int was = env.current_line;
+ (void) handle_directive(__buffer, __size, end_id, __first, __result);
+
+ if (env.current_line != was) {
+ env.current_line = was;
+ _PP_internal::output_line(env.current_file, env.current_line, __result);
+ }
+ } else if (*__first == '\n') {
+ // ### compress the line
+ *__result++ = *__first++;
+ ++env.current_line;
+ } else if (skipping())
+ __first = skip(__first, __last);
+ else {
+ _PP_internal::output_line(env.current_file, env.current_line, __result);
+ __first = expand(__first, __last, __result);
+ env.current_line += expand.lines;
+
+ if (expand.generated_lines)
+ _PP_internal::output_line(env.current_file, env.current_line, __result);
+ }
+ }
+}
+
+inline pp::pp(pp_environment &__env):
+ env(__env), expand(env)
+{
+ iflevel = 0;
+ _M_skipping[iflevel] = 0;
+ _M_true_test[iflevel] = 0;
+}
+
+inline std::back_insert_iterator<std::vector<std::string> > pp::include_paths_inserter()
+{
+ return std::back_inserter(include_paths);
+}
+
+inline std::vector<std::string>::iterator pp::include_paths_begin()
+{
+ return include_paths.begin();
+}
+
+inline std::vector<std::string>::iterator pp::include_paths_end()
+{
+ return include_paths.end();
+}
+
+inline std::vector<std::string>::const_iterator pp::include_paths_begin() const
+{
+ return include_paths.begin();
+}
+
+inline std::vector<std::string>::const_iterator pp::include_paths_end() const
+{
+ return include_paths.end();
+}
+
+inline void pp::push_include_path(std::string const &__path)
+{
+ if (__path.empty() || __path [__path.size() - 1] != PATH_SEPARATOR) {
+ std::string __tmp(__path);
+ __tmp += PATH_SEPARATOR;
+ include_paths.push_back(__tmp);
+ }
+
+ else
+ include_paths.push_back(__path);
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_define(_InputIterator __first, _InputIterator __last)
+{
+ pp_macro macro;
+#if defined (PP_WITH_MACRO_POSITION)
+ macro.file = pp_symbol::get(env.current_file);
+#endif
+ std::string definition;
+
+ __first = skip_blanks(__first, __last);
+ _InputIterator end_macro_name = skip_identifier(__first, __last);
+ pp_fast_string const *macro_name = pp_symbol::get(__first, end_macro_name);
+ __first = end_macro_name;
+
+ if (__first != __last && *__first == '(') {
+ macro.function_like = true;
+ macro.formals.reserve(5);
+
+ __first = skip_blanks(++__first, __last); // skip '('
+ _InputIterator arg_end = skip_identifier(__first, __last);
+ if (__first != arg_end)
+ macro.formals.push_back(pp_symbol::get(__first, arg_end));
+
+ __first = skip_blanks(arg_end, __last);
+
+ if (*__first == '.') {
+ macro.variadics = true;
+ while (*__first == '.')
+ ++__first;
+ }
+
+ while (__first != __last && *__first == ',') {
+ __first = skip_blanks(++__first, __last);
+
+ arg_end = skip_identifier(__first, __last);
+ if (__first != arg_end)
+ macro.formals.push_back(pp_symbol::get(__first, arg_end));
+
+ __first = skip_blanks(arg_end, __last);
+
+ if (*__first == '.') {
+ macro.variadics = true;
+ while (*__first == '.')
+ ++__first;
+ }
+ }
+
+ assert(*__first == ')');
+ ++__first;
+ }
+
+ __first = skip_blanks(__first, __last);
+
+ while (__first != __last && *__first != '\n') {
+ if (*__first == '/') {
+ __first = skip_comment_or_divop(__first, __last);
+ env.current_line += skip_comment_or_divop.lines;
+ }
+
+ if (*__first == '\\') {
+ _InputIterator __begin = __first;
+ __begin = skip_blanks(++__begin, __last);
+
+ if (__begin != __last && *__begin == '\n') {
+ ++macro.lines;
+ __first = skip_blanks(++__begin, __last);
+ definition += ' ';
+ continue;
+ }
+ }
+
+ definition += *__first++;
+ }
+
+ macro.definition = pp_symbol::get(definition);
+ env.bind(macro_name, macro);
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::skip(_InputIterator __first, _InputIterator __last)
+{
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+
+ while (__first != __last && *__first != '\n') {
+ if (*__first == '/') {
+ __first = skip_comment_or_divop(__first, __last);
+ env.current_line += skip_comment_or_divop.lines;
+ } else if (*__first == '"') {
+ __first = skip_string_literal(__first, __last);
+ env.current_line += skip_string_literal.lines;
+ } else if (*__first == '\'') {
+ __first = skip_char_literal(__first, __last);
+ env.current_line += skip_char_literal.lines;
+ } else if (*__first == '\\') {
+ __first = skip_blanks(++__first, __last);
+ env.current_line += skip_blanks.lines;
+
+ if (__first != __last && *__first == '\n') {
+ ++__first;
+ ++env.current_line;
+ }
+ } else
+ ++__first;
+ }
+
+ return __first;
+}
+
+inline bool pp::test_if_level()
+{
+ bool result = !_M_skipping[iflevel++];
+ _M_skipping[iflevel] = _M_skipping[iflevel - 1];
+ _M_true_test[iflevel] = false;
+ return result;
+}
+
+inline int pp::skipping() const
+{
+ return _M_skipping[iflevel];
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ bool expect_paren = false;
+ int token;
+ __first = next_token(__first, __last, &token);
+
+ switch (token) {
+ case TOKEN_NUMBER:
+ result->set_long(token_value);
+ break;
+
+ case TOKEN_UNUMBER:
+ result->set_ulong(token_uvalue);
+ break;
+
+ case TOKEN_DEFINED:
+ __first = next_token(__first, __last, &token);
+
+ if (token == '(') {
+ expect_paren = true;
+ __first = next_token(__first, __last, &token);
+ }
+
+ if (token != TOKEN_IDENTIFIER) {
+ std::cerr << "** WARNING expected ``identifier'' found:" << char(token) << std::endl;
+ result->set_long(0);
+ break;
+ }
+
+ result->set_long(env.resolve(token_text->c_str(), token_text->size()) != 0);
+
+ next_token(__first, __last, &token); // skip '('
+
+ if (expect_paren) {
+ _InputIterator next = next_token(__first, __last, &token);
+ if (token != ')')
+ std::cerr << "** WARNING expected ``)''" << std::endl;
+ else
+ __first = next;
+ }
+ break;
+
+ case TOKEN_IDENTIFIER:
+ result->set_long(0);
+ break;
+
+ case '-':
+ __first = eval_primary(__first, __last, result);
+ result->set_long(- result->l);
+ return __first;
+
+ case '+':
+ __first = eval_primary(__first, __last, result);
+ return __first;
+
+ case '!':
+ __first = eval_primary(__first, __last, result);
+ result->set_long(result->is_zero());
+ return __first;
+
+ case '(':
+ __first = eval_constant_expression(__first, __last, result);
+ next_token(__first, __last, &token);
+
+ if (token != ')')
+ std::cerr << "** WARNING expected ``)'' = " << token << std::endl;
+ else
+ __first = next_token(__first, __last, &token);
+ break;
+
+ default:
+ result->set_long(0);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_primary(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '*' || token == '/' || token == '%') {
+ Value value;
+ __first = eval_primary(next, __last, &value);
+
+ if (token == '*')
+ result->op_mult(value);
+ else if (token == '/') {
+ if (value.is_zero()) {
+ std::cerr << "** WARNING division by zero" << std::endl;
+ result->set_long(0);
+ } else
+ result->op_div(value);
+ } else {
+ if (value.is_zero()) {
+ std::cerr << "** WARNING division by zero" << std::endl;
+ result->set_long(0);
+ } else
+ result->op_mod(value);
+ }
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_multiplicative(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '+' || token == '-') {
+ Value value;
+ __first = eval_multiplicative(next, __last, &value);
+
+ if (token == '+')
+ result->op_add(value);
+ else
+ result->op_sub(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_additive(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) {
+ Value value;
+ __first = eval_additive(next, __last, &value);
+
+ if (token == TOKEN_LT_LT)
+ result->op_lhs(value);
+ else
+ result->op_rhs(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_shift(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '<'
+ || token == '>'
+ || token == TOKEN_LT_EQ
+ || token == TOKEN_GT_EQ) {
+ Value value;
+ __first = eval_shift(next, __last, &value);
+
+ switch (token) {
+ default:
+ assert(0);
+ break;
+
+ case '<':
+ result->op_lt(value);
+ break;
+
+ case '>':
+ result->op_gt(value);
+ break;
+
+ case TOKEN_LT_EQ:
+ result->op_le(value);
+ break;
+
+ case TOKEN_GT_EQ:
+ result->op_ge(value);
+ break;
+ }
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_relational(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) {
+ Value value;
+ __first = eval_relational(next, __last, &value);
+
+ if (token == TOKEN_EQ_EQ)
+ result->op_eq(value);
+ else
+ result->op_ne(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_equality(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '&') {
+ Value value;
+ __first = eval_equality(next, __last, &value);
+ result->op_bit_and(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_and(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '^') {
+ Value value;
+ __first = eval_and(next, __last, &value);
+ result->op_bit_xor(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_xor(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == '|') {
+ Value value;
+ __first = eval_xor(next, __last, &value);
+ result->op_bit_or(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_or(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == TOKEN_AND_AND) {
+ Value value;
+ __first = eval_or(next, __last, &value);
+ result->op_and(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_logical_and(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ while (token == TOKEN_OR_OR) {
+ Value value;
+ __first = eval_logical_and(next, __last, &value);
+ result->op_or(value);
+ next = next_token(__first, __last, &token);
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ __first = eval_logical_or(__first, __last, result);
+
+ int token;
+ _InputIterator next = next_token(__first, __last, &token);
+
+ if (token == '?') {
+ Value left_value;
+ __first = eval_constant_expression(next, __last, &left_value);
+ __first = skip_blanks(__first, __last);
+
+ __first = next_token(__first, __last, &token);
+ if (token == ':') {
+ Value right_value;
+ __first = eval_constant_expression(__first, __last, &right_value);
+
+ *result = !result->is_zero() ? left_value : right_value;
+ } else {
+ std::cerr << "** WARNING expected ``:'' = " << int (token) << std::endl;
+ *result = left_value;
+ }
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::eval_expression(_InputIterator __first, _InputIterator __last, Value *result)
+{
+ return __first = eval_constant_expression(skip_blanks(__first, __last), __last, result);
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_if(_InputIterator __first, _InputIterator __last)
+{
+ if (test_if_level()) {
+ pp_macro_expander expand_condition(env);
+ std::string condition;
+ condition.reserve(255);
+ expand_condition(skip_blanks(__first, __last), __last, std::back_inserter(condition));
+
+ Value result;
+ result.set_long(0);
+ eval_expression(condition.c_str(), condition.c_str() + condition.size(), &result);
+
+ _M_true_test[iflevel] = !result.is_zero();
+ _M_skipping[iflevel] = result.is_zero();
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_else(_InputIterator __first, _InputIterator /*__last*/)
+{
+ if (iflevel == 0 && !skipping()) {
+ std::cerr << "** WARNING #else without #if" << std::endl;
+ } else if (iflevel > 0 && _M_skipping[iflevel - 1]) {
+ _M_skipping[iflevel] = true;
+ } else {
+ _M_skipping[iflevel] = _M_true_test[iflevel];
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_elif(_InputIterator __first, _InputIterator __last)
+{
+ assert(iflevel > 0);
+
+ if (iflevel == 0 && !skipping()) {
+ std::cerr << "** WARNING #else without #if" << std::endl;
+ } else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) {
+ Value result;
+ __first = eval_expression(__first, __last, &result);
+ _M_true_test[iflevel] = !result.is_zero();
+ _M_skipping[iflevel] = result.is_zero();
+ } else {
+ _M_skipping[iflevel] = true;
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_endif(_InputIterator __first, _InputIterator /*__last*/)
+{
+ if (iflevel == 0 && !skipping()) {
+ std::cerr << "** WARNING #endif without #if" << std::endl;
+ } else {
+ _M_skipping[iflevel] = 0;
+ _M_true_test[iflevel] = 0;
+
+ --iflevel;
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last)
+{
+ if (test_if_level()) {
+ _InputIterator end_macro_name = skip_identifier(__first, __last);
+
+ std::size_t __size;
+#if defined(__SUNPRO_CC)
+ std::distance(__first, end_macro_name, __size);
+#else
+ __size = std::distance(__first, end_macro_name);
+#endif
+ assert(__size < 256);
+
+ char __buffer [256];
+ std::copy(__first, end_macro_name, __buffer);
+
+ bool value = env.resolve(__buffer, __size) != 0;
+
+ __first = end_macro_name;
+
+ if (check_undefined)
+ value = !value;
+
+ _M_true_test[iflevel] = value;
+ _M_skipping[iflevel] = !value;
+ }
+
+ return __first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last)
+{
+ __first = skip_blanks(__first, __last);
+ _InputIterator end_macro_name = skip_identifier(__first, __last);
+ assert(end_macro_name != __first);
+
+ std::size_t __size;
+#if defined(__SUNPRO_CC)
+ std::distance(__first, end_macro_name, __size);
+#else
+ __size = std::distance(__first, end_macro_name);
+#endif
+
+ assert(__size < 256);
+
+ char __buffer [256];
+ std::copy(__first, end_macro_name, __buffer);
+
+ pp_fast_string const __tmp(__buffer, __size);
+ env.unbind(&__tmp);
+
+ __first = end_macro_name;
+
+ return __first;
+}
+
+template <typename _InputIterator>
+char pp::peek_char(_InputIterator __first, _InputIterator __last)
+{
+ if (__first == __last)
+ return 0;
+
+ return *++__first;
+}
+
+template <typename _InputIterator>
+_InputIterator pp::next_token(_InputIterator __first, _InputIterator __last, int *kind)
+{
+ __first = skip_blanks(__first, __last);
+
+ if (__first == __last) {
+ *kind = 0;
+ return __first;
+ }
+
+ char ch = *__first;
+ char ch2 = peek_char(__first, __last);
+
+ switch (ch) {
+ case '/':
+ if (ch2 == '/' || ch2 == '*') {
+ __first = skip_comment_or_divop(__first, __last);
+ return next_token(__first, __last, kind);
+ }
+ ++__first;
+ *kind = '/';
+ break;
+
+ case '<':
+ ++__first;
+ if (ch2 == '<') {
+ ++__first;
+ *kind = TOKEN_LT_LT;
+ } else if (ch2 == '=') {
+ ++__first;
+ *kind = TOKEN_LT_EQ;
+ } else
+ *kind = '<';
+
+ return __first;
+
+ case '>':
+ ++__first;
+ if (ch2 == '>') {
+ ++__first;
+ *kind = TOKEN_GT_GT;
+ } else if (ch2 == '=') {
+ ++__first;
+ *kind = TOKEN_GT_EQ;
+ } else
+ *kind = '>';
+
+ return __first;
+
+ case '!':
+ ++__first;
+ if (ch2 == '=') {
+ ++__first;
+ *kind = TOKEN_NOT_EQ;
+ } else
+ *kind = '!';
+
+ return __first;
+
+ case '=':
+ ++__first;
+ if (ch2 == '=') {
+ ++__first;
+ *kind = TOKEN_EQ_EQ;
+ } else
+ *kind = '=';
+
+ return __first;
+
+ case '|':
+ ++__first;
+ if (ch2 == '|') {
+ ++__first;
+ *kind = TOKEN_OR_OR;
+ } else
+ *kind = '|';
+
+ return __first;
+
+ case '&':
+ ++__first;
+ if (ch2 == '&') {
+ ++__first;
+ *kind = TOKEN_AND_AND;
+ } else
+ *kind = '&';
+
+ return __first;
+
+ default:
+ if (pp_isalpha(ch) || ch == '_') {
+ _InputIterator end = skip_identifier(__first, __last);
+ _M_current_text.assign(__first, end);
+
+ token_text = &_M_current_text;
+ __first = end;
+
+ if (*token_text == "defined")
+ *kind = TOKEN_DEFINED;
+ else
+ *kind = TOKEN_IDENTIFIER;
+ } else if (pp_isdigit(ch)) {
+ _InputIterator end = skip_number(__first, __last);
+ std::string __str(__first, __last);
+ char ch = __str [__str.size() - 1];
+ if (ch == 'u' || ch == 'U') {
+ token_uvalue = strtoul(__str.c_str(), 0, 0);
+ *kind = TOKEN_UNUMBER;
+ } else {
+ token_value = strtol(__str.c_str(), 0, 0);
+ *kind = TOKEN_NUMBER;
+ }
+ __first = end;
+ } else
+ *kind = *__first++;
+ }
+
+ return __first;
+}
+
+} // namespace rpp
+
+#endif // PP_ENGINE_BITS_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-engine.h b/parser/rpp/pp-engine.h
new file mode 100644
index 000000000..79e74c1aa
--- /dev/null
+++ b/parser/rpp/pp-engine.h
@@ -0,0 +1,274 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_ENGINE_H
+#define PP_ENGINE_H
+
+namespace rpp
+{
+
+struct Value {
+ enum Kind {
+ Kind_Long,
+ Kind_ULong,
+ };
+
+ Kind kind;
+
+ union {
+ long l;
+ unsigned long ul;
+ };
+
+ inline bool is_ulong() const {
+ return kind == Kind_ULong;
+ }
+
+ inline void set_ulong(unsigned long v) {
+ ul = v;
+ kind = Kind_ULong;
+ }
+
+ inline void set_long(long v) {
+ l = v;
+ kind = Kind_Long;
+ }
+
+ inline bool is_zero() const {
+ return l == 0;
+ }
+
+#define PP_DEFINE_BIN_OP(name, op) \
+ inline Value &name (const Value &other) \
+ { \
+ if (is_ulong () || other.is_ulong ()) \
+ set_ulong (ul op other.ul); \
+ else \
+ set_long (l op other.l); \
+ return *this; \
+ }
+
+ PP_DEFINE_BIN_OP(op_add, +)
+ PP_DEFINE_BIN_OP(op_sub, -)
+ PP_DEFINE_BIN_OP(op_mult, *)
+ PP_DEFINE_BIN_OP(op_div, /)
+ PP_DEFINE_BIN_OP(op_mod, %)
+ PP_DEFINE_BIN_OP(op_lhs, <<)
+ PP_DEFINE_BIN_OP(op_rhs, >>)
+ PP_DEFINE_BIN_OP(op_lt, <)
+ PP_DEFINE_BIN_OP(op_gt, >)
+ PP_DEFINE_BIN_OP(op_le, <=)
+ PP_DEFINE_BIN_OP(op_ge, >=)
+ PP_DEFINE_BIN_OP(op_eq, ==)
+ PP_DEFINE_BIN_OP(op_ne, !=)
+ PP_DEFINE_BIN_OP(op_bit_and, &)
+ PP_DEFINE_BIN_OP(op_bit_or, |)
+ PP_DEFINE_BIN_OP(op_bit_xor, ^)
+ PP_DEFINE_BIN_OP(op_and, &&)
+ PP_DEFINE_BIN_OP(op_or, ||)
+
+#undef PP_DEFINE_BIN_OP
+};
+
+class pp
+{
+ pp_environment &env;
+ pp_macro_expander expand;
+ pp_skip_identifier skip_identifier;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_number skip_number;
+ std::vector<std::string> include_paths;
+ std::string _M_current_text;
+
+ enum { MAX_LEVEL = 512 };
+ int _M_skipping[MAX_LEVEL];
+ int _M_true_test[MAX_LEVEL];
+ int iflevel;
+
+ union {
+ long token_value;
+ unsigned long token_uvalue;
+ std::string *token_text;
+ };
+
+ enum INCLUDE_POLICY {
+ INCLUDE_GLOBAL,
+ INCLUDE_LOCAL
+ };
+
+ enum TOKEN_TYPE {
+ TOKEN_NUMBER = 1000,
+ TOKEN_UNUMBER,
+ TOKEN_IDENTIFIER,
+ TOKEN_DEFINED,
+ TOKEN_LT_LT,
+ TOKEN_LT_EQ,
+ TOKEN_GT_GT,
+ TOKEN_GT_EQ,
+ TOKEN_EQ_EQ,
+ TOKEN_NOT_EQ,
+ TOKEN_OR_OR,
+ TOKEN_AND_AND,
+ };
+
+ enum PP_DIRECTIVE_TYPE {
+ PP_UNKNOWN_DIRECTIVE,
+ PP_DEFINE,
+ PP_INCLUDE,
+ PP_INCLUDE_NEXT,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_UNDEF,
+ PP_PRAGMA,
+ PP_ERROR,
+ PP_WARNING
+ };
+
+public:
+ pp(pp_environment &__env);
+
+ inline std::back_insert_iterator<std::vector<std::string> > include_paths_inserter();
+
+ inline void push_include_path(std::string const &__path);
+
+ inline std::vector<std::string>::iterator include_paths_begin();
+ inline std::vector<std::string>::iterator include_paths_end();
+
+ inline std::vector<std::string>::const_iterator include_paths_begin() const;
+ inline std::vector<std::string>::const_iterator include_paths_end() const;
+
+ template <typename _InputIterator>
+ inline _InputIterator eval_expression(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _OutputIterator>
+ void file(std::string const &filename, _OutputIterator __result);
+
+ template <typename _OutputIterator>
+ void file(FILE *fp, _OutputIterator __result);
+
+ template <typename _InputIterator, typename _OutputIterator>
+ void operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result);
+
+private:
+ inline bool file_isdir(std::string const &__filename) const;
+ inline bool file_exists(std::string const &__filename) const;
+ FILE *find_include_file(std::string const &__filename, std::string *__filepath,
+ INCLUDE_POLICY __include_policy, bool __skip_current_path = false) const;
+
+ inline int skipping() const;
+ bool test_if_level();
+
+ inline std::string fix_file_path(std::string const &filename) const;
+ inline bool is_absolute(std::string const &filename) const;
+
+ PP_DIRECTIVE_TYPE find_directive(char const *__directive, std::size_t __size) const;
+
+ template <typename _InputIterator>
+ bool find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot);
+
+ template <typename _InputIterator>
+ _InputIterator skip(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator eval_primary(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_additive(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_shift(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_relational(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_equality(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_and(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_xor(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_or(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator>
+ _InputIterator eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result);
+
+ template <typename _InputIterator, typename _OutputIterator>
+ _InputIterator handle_directive(char const *__directive, std::size_t __size,
+ _InputIterator __first, _InputIterator __last, _OutputIterator __result);
+
+ template <typename _InputIterator, typename _OutputIterator>
+ _InputIterator handle_include(bool skip_current_path, _InputIterator __first, _InputIterator __last,
+ _OutputIterator __result);
+
+ template <typename _InputIterator>
+ _InputIterator handle_define(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_if(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_else(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_elif(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_endif(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator handle_undef(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ inline char peek_char(_InputIterator __first, _InputIterator __last);
+
+ template <typename _InputIterator>
+ _InputIterator next_token(_InputIterator __first, _InputIterator __last, int *kind);
+};
+
+} // namespace rpp
+
+#endif // PP_ENGINE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-environment.h b/parser/rpp/pp-environment.h
new file mode 100644
index 000000000..6003c0820
--- /dev/null
+++ b/parser/rpp/pp-environment.h
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_ENVIRONMENT_H
+#define PP_ENVIRONMENT_H
+
+#include <vector>
+#include <cstring>
+
+namespace rpp
+{
+
+class pp_environment
+{
+public:
+ typedef std::vector<pp_macro*>::const_iterator const_iterator;
+
+public:
+ pp_environment():
+ current_line(0),
+ _M_hash_size(4093) {
+ _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*));
+ }
+
+ ~pp_environment() {
+ for (std::size_t i = 0; i < _M_macros.size(); ++i)
+ delete _M_macros [i];
+
+ delete [] _M_base;
+ }
+
+ const_iterator first_macro() const {
+ return _M_macros.begin();
+ }
+ const_iterator last_macro() const {
+ return _M_macros.end();
+ }
+
+ inline void bind(pp_fast_string const *__name, pp_macro const &__macro) {
+ std::size_t h = hash_code(*__name) % _M_hash_size;
+ pp_macro *m = new pp_macro(__macro);
+ m->name = __name;
+ m->next = _M_base [h];
+ m->hash_code = h;
+ _M_base [h] = m;
+
+ _M_macros.push_back(m);
+
+ if (_M_macros.size() == _M_hash_size)
+ rehash();
+ }
+
+ inline void unbind(pp_fast_string const *__name) {
+ if (pp_macro *m = resolve(__name))
+ m->hidden = true;
+ }
+
+ inline void unbind(char const *__s, std::size_t __size) {
+ pp_fast_string __tmp(__s, __size);
+ unbind(&__tmp);
+ }
+
+ inline pp_macro *resolve(pp_fast_string const *__name) const {
+ std::size_t h = hash_code(*__name) % _M_hash_size;
+ pp_macro *it = _M_base [h];
+
+ while (it && it->name && it->hash_code == h && (*it->name != *__name || it->hidden))
+ it = it->next;
+
+ return it;
+ }
+
+ inline pp_macro *resolve(char const *__data, std::size_t __size) const {
+ pp_fast_string const __tmp(__data, __size);
+ return resolve(&__tmp);
+ }
+
+ std::string current_file;
+ int current_line;
+
+private:
+ inline std::size_t hash_code(pp_fast_string const &s) const {
+ std::size_t hash_value = 0;
+
+ for (std::size_t i = 0; i < s.size(); ++i)
+ hash_value = (hash_value << 5) - hash_value + s.at(i);
+
+ return hash_value;
+ }
+
+ void rehash() {
+ delete[] _M_base;
+
+ _M_hash_size <<= 1;
+
+ _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*));
+ for (std::size_t index = 0; index < _M_macros.size(); ++index) {
+ pp_macro *elt = _M_macros [index];
+ std::size_t h = hash_code(*elt->name) % _M_hash_size;
+ elt->next = _M_base [h];
+ elt->hash_code = h;
+ _M_base [h] = elt;
+ }
+ }
+
+private:
+ std::vector<pp_macro*> _M_macros;
+ pp_macro **_M_base;
+ std::size_t _M_hash_size;
+};
+
+} // namespace rpp
+
+#endif // PP_ENVIRONMENT_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-fwd.h b/parser/rpp/pp-fwd.h
new file mode 100644
index 000000000..5b1c792f8
--- /dev/null
+++ b/parser/rpp/pp-fwd.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_FWD_H
+#define PP_FWD_H
+
+namespace rpp
+{
+
+template <typename _CharT> class pp_string;
+
+typedef pp_string<char> pp_fast_string;
+
+} // namespace rpp
+
+#endif // PP_FWD_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-internal.h b/parser/rpp/pp-internal.h
new file mode 100644
index 000000000..7e708101d
--- /dev/null
+++ b/parser/rpp/pp-internal.h
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_INTERNAL_H
+#define PP_INTERNAL_H
+
+#include <algorithm>
+#include <string>
+#include "pp.h"
+
+namespace rpp
+{
+
+namespace _PP_internal
+{
+
+inline void extract_file_path(const std::string &__filename, std::string *__filepath)
+{
+ std::size_t __index = __filename.rfind(PATH_SEPARATOR);
+
+ if (__index == std::string::npos)
+ *__filepath = "/";
+
+ else
+ __filepath->assign(__filename, 0, __index + 1);
+}
+
+template <typename _OutputIterator>
+void output_line(const std::string &__filename, int __line, _OutputIterator __result)
+{
+ std::string __msg;
+
+ __msg += "# ";
+
+ char __line_descr[16];
+ pp_snprintf(__line_descr, 16, "%d", __line);
+ __msg += __line_descr;
+
+ __msg += " \"";
+
+ if (__filename.empty())
+ __msg += "<internal>";
+ else
+ __msg += __filename;
+
+ __msg += "\"\n";
+ std::copy(__msg.begin(), __msg.end(), __result);
+}
+
+template <typename _InputIterator>
+inline bool comment_p(_InputIterator __first, _InputIterator __last) /*const*/
+{
+ if (__first == __last)
+ return false;
+
+ if (*__first != '/')
+ return false;
+
+ if (++__first == __last)
+ return false;
+
+ return (*__first == '/' || *__first == '*');
+}
+
+struct _Compare_string: public std::binary_function<bool, pp_fast_string const *, pp_fast_string const *> {
+ inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const {
+ return *__lhs < *__rhs;
+ }
+};
+
+struct _Equal_to_string: public std::binary_function<bool, pp_fast_string const *, pp_fast_string const *> {
+ inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const {
+ return *__lhs == *__rhs;
+ }
+};
+
+struct _Hash_string: public std::unary_function<std::size_t, pp_fast_string const *> {
+ inline std::size_t operator()(pp_fast_string const *__s) const {
+ char const *__ptr = __s->begin();
+ std::size_t __size = __s->size();
+ std::size_t __h = 0;
+
+ for (std::size_t i = 0; i < __size; ++i)
+ __h = (__h << 5) - __h + __ptr [i];
+
+ return __h;
+ }
+};
+
+} // _PP_internal
+
+} // namespace rpp
+
+#endif // PP_INTERNAL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-iterator.h b/parser/rpp/pp-iterator.h
new file mode 100644
index 000000000..fe846bd26
--- /dev/null
+++ b/parser/rpp/pp-iterator.h
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_ITERATOR_H
+#define PP_ITERATOR_H
+
+#include <iterator>
+
+namespace rpp
+{
+
+class pp_null_output_iterator
+ : public std::iterator<std::output_iterator_tag, void, void, void, void>
+{
+public:
+ pp_null_output_iterator() {}
+
+ template <typename _Tp>
+ pp_null_output_iterator &operator=(_Tp const &) {
+ return *this;
+ }
+
+ inline pp_null_output_iterator &operator *() {
+ return *this;
+ }
+ inline pp_null_output_iterator &operator ++ () {
+ return *this;
+ }
+ inline pp_null_output_iterator operator ++ (int) {
+ return *this;
+ }
+};
+
+template <typename _Container>
+class pp_output_iterator
+ : public std::iterator<std::output_iterator_tag, void, void, void, void>
+{
+ std::string &_M_result;
+
+public:
+ explicit pp_output_iterator(std::string &__result):
+ _M_result(__result) {}
+
+ inline pp_output_iterator &operator=(typename _Container::const_reference __v) {
+ if (_M_result.capacity() == _M_result.size())
+ _M_result.reserve(_M_result.capacity() << 2);
+
+ _M_result.push_back(__v);
+ return *this;
+ }
+
+ inline pp_output_iterator &operator *() {
+ return *this;
+ }
+ inline pp_output_iterator &operator ++ () {
+ return *this;
+ }
+ inline pp_output_iterator operator ++ (int) {
+ return *this;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_ITERATOR_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-macro-expander.h b/parser/rpp/pp-macro-expander.h
new file mode 100644
index 000000000..fd875d980
--- /dev/null
+++ b/parser/rpp/pp-macro-expander.h
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_MACRO_EXPANDER_H
+#define PP_MACRO_EXPANDER_H
+
+namespace rpp
+{
+
+struct pp_frame {
+ pp_macro *expanding_macro;
+ std::vector<std::string> *actuals;
+
+ pp_frame(pp_macro *__expanding_macro, std::vector<std::string> *__actuals):
+ expanding_macro(__expanding_macro), actuals(__actuals) {}
+};
+
+class pp_macro_expander
+{
+ pp_environment &env;
+ pp_frame *frame;
+
+ pp_skip_number skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_argument skip_argument;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_whitespaces skip_whitespaces;
+
+ std::string const *resolve_formal(pp_fast_string const *__name) {
+ assert(__name != 0);
+
+ if (! frame)
+ return 0;
+
+ assert(frame->expanding_macro != 0);
+
+ std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals;
+ for (std::size_t index = 0; index < formals.size(); ++index) {
+ pp_fast_string const *formal = formals[index];
+
+ if (*formal != *__name)
+ continue;
+
+ else if (frame->actuals && index < frame->actuals->size())
+ return &(*frame->actuals)[index];
+
+ else
+ assert(0); // internal error?
+ }
+
+ return 0;
+ }
+
+public: // attributes
+ int lines;
+ int generated_lines;
+
+public:
+ pp_macro_expander(pp_environment &__env, pp_frame *__frame = 0):
+ env(__env), frame(__frame), lines(0), generated_lines(0) {}
+
+ template <typename _InputIterator, typename _OutputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
+ generated_lines = 0;
+ __first = skip_blanks(__first, __last);
+ lines = skip_blanks.lines;
+
+ while (__first != __last) {
+ if (*__first == '\n') {
+ *__result++ = *__first;
+ ++lines;
+
+ __first = skip_blanks(++__first, __last);
+ lines += skip_blanks.lines;
+
+ if (__first != __last && *__first == '#')
+ break;
+ } else if (*__first == '#') {
+ __first = skip_blanks(++__first, __last);
+ lines += skip_blanks.lines;
+
+ _InputIterator end_id = skip_identifier(__first, __last);
+
+ // ### rewrite: not safe
+ char name_buffer[512], *cp = name_buffer;
+ std::copy(__first, end_id, cp);
+ std::size_t name_size = end_id - __first;
+ name_buffer[name_size] = '\0';
+
+ pp_fast_string fast_name(name_buffer, name_size);
+
+ if (std::string const *actual = resolve_formal(&fast_name)) {
+ *__result++ = '\"';
+
+ for (std::string::const_iterator it = skip_whitespaces(actual->begin(), actual->end());
+ it != actual->end(); ++it) {
+ if (*it == '"') {
+ *__result++ = '\\';
+ *__result++ = *it;
+ }
+
+ else if (*it == '\n') {
+ *__result++ = '"';
+ *__result++ = '\n';
+ *__result++ = '"';
+ }
+
+ else
+ *__result++ = *it;
+ }
+
+ *__result++ = '\"';
+ __first = end_id;
+ } else
+ *__result++ = '#'; // ### warning message?
+ } else if (*__first == '\"') {
+ _InputIterator next_pos = skip_string_literal(__first, __last);
+ lines += skip_string_literal.lines;
+ std::copy(__first, next_pos, __result);
+ __first = next_pos;
+ } else if (*__first == '\'') {
+ _InputIterator next_pos = skip_char_literal(__first, __last);
+ lines += skip_char_literal.lines;
+ std::copy(__first, next_pos, __result);
+ __first = next_pos;
+ } else if (_PP_internal::comment_p(__first, __last)) {
+ __first = skip_comment_or_divop(__first, __last);
+ int n = skip_comment_or_divop.lines;
+ lines += n;
+
+ while (n-- > 0)
+ *__result++ = '\n';
+ } else if (pp_isspace(*__first)) {
+ for (; __first != __last; ++__first) {
+ if (*__first == '\n' || !pp_isspace(*__first))
+ break;
+ }
+
+ *__result = ' ';
+ } else if (pp_isdigit(*__first)) {
+ _InputIterator next_pos = skip_number(__first, __last);
+ lines += skip_number.lines;
+ std::copy(__first, next_pos, __result);
+ __first = next_pos;
+ } else if (pp_isalpha(*__first) || *__first == '_') {
+ _InputIterator name_begin = __first;
+ _InputIterator name_end = skip_identifier(__first, __last);
+ __first = name_end; // advance
+
+ // search for the paste token
+ _InputIterator next = skip_blanks(__first, __last);
+ if (next != __last && *next == '#') {
+ ++next;
+ if (next != __last && *next == '#')
+ __first = skip_blanks(++next, __last);
+ }
+
+ // ### rewrite: not safe
+
+ std::ptrdiff_t name_size;
+#if defined(__SUNPRO_CC)
+ std::distance(name_begin, name_end, name_size);
+#else
+ name_size = std::distance(name_begin, name_end);
+#endif
+ assert(name_size >= 0 && name_size < 512);
+
+ char name_buffer[512], *cp = name_buffer;
+ std::size_t __size = name_end - name_begin;
+ std::copy(name_begin, name_end, cp);
+ name_buffer[__size] = '\0';
+
+ pp_fast_string fast_name(name_buffer, name_size);
+
+ if (std::string const *actual = resolve_formal(&fast_name)) {
+ std::copy(actual->begin(), actual->end(), __result);
+ continue;
+ }
+
+ static bool hide_next = false; // ### remove me
+
+ pp_macro *macro = env.resolve(name_buffer, name_size);
+ if (! macro || macro->hidden || hide_next) {
+ hide_next = ! strcmp(name_buffer, "defined");
+
+ if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') {
+ if (! strcmp(name_buffer, "__LINE__")) {
+ char buf [16];
+ char *end = buf + pp_snprintf(buf, 16, "%d", env.current_line + lines);
+
+ std::copy(&buf [0], end, __result);
+ continue;
+ }
+
+ else if (! strcmp(name_buffer, "__FILE__")) {
+ __result++ = '"';
+ std::copy(env.current_file.begin(), env.current_file.end(), __result); // ### quote
+ __result++ = '"';
+ continue;
+ }
+ }
+
+ std::copy(name_begin, name_end, __result);
+ continue;
+ }
+
+ if (! macro->function_like) {
+ pp_macro *m = 0;
+
+ if (macro->definition) {
+ macro->hidden = true;
+
+ std::string __tmp;
+ __tmp.reserve(256);
+
+ pp_macro_expander expand_macro(env);
+ expand_macro(macro->definition->begin(), macro->definition->end(), std::back_inserter(__tmp));
+ generated_lines += expand_macro.lines;
+
+ if (! __tmp.empty()) {
+ std::string::iterator __begin_id = skip_whitespaces(__tmp.begin(), __tmp.end());
+ std::string::iterator __end_id = skip_identifier(__begin_id, __tmp.end());
+
+ if (__end_id == __tmp.end()) {
+ std::string __id;
+ __id.assign(__begin_id, __end_id);
+
+ std::size_t x;
+#if defined(__SUNPRO_CC)
+ std::distance(__begin_id, __end_id, x);
+#else
+ x = std::distance(__begin_id, __end_id);
+#endif
+ m = env.resolve(__id.c_str(), x);
+ }
+
+ if (! m)
+ std::copy(__tmp.begin(), __tmp.end(), __result);
+ }
+
+ macro->hidden = false;
+ }
+
+ if (! m)
+ continue;
+
+ macro = m;
+ }
+
+ // function like macro
+ _InputIterator arg_it = skip_whitespaces(__first, __last);
+
+ if (arg_it == __last || *arg_it != '(') {
+ std::copy(name_begin, name_end, __result);
+ lines += skip_whitespaces.lines;
+ __first = arg_it;
+ continue;
+ }
+
+ std::vector<std::string> actuals;
+ actuals.reserve(5);
+ ++arg_it; // skip '('
+
+ pp_macro_expander expand_actual(env, frame);
+
+ _InputIterator arg_end = skip_argument_variadics(actuals, macro, arg_it, __last);
+ if (arg_it != arg_end) {
+ std::string actual(arg_it, arg_end);
+ actuals.resize(actuals.size() + 1);
+ actuals.back().reserve(255);
+ expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back()));
+ arg_it = arg_end;
+ }
+
+ while (arg_it != __last && *arg_end == ',') {
+ ++arg_it; // skip ','
+
+ arg_end = skip_argument_variadics(actuals, macro, arg_it, __last);
+ std::string actual(arg_it, arg_end);
+ actuals.resize(actuals.size() + 1);
+ actuals.back().reserve(255);
+ expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back()));
+ arg_it = arg_end;
+ }
+
+ assert(arg_it != __last && *arg_it == ')');
+
+ ++arg_it; // skip ')'
+ __first = arg_it;
+
+#if 0 // ### enable me
+ assert((macro->variadics && macro->formals.size() >= actuals.size())
+ || macro->formals.size() == actuals.size());
+#endif
+
+ pp_frame frame(macro, &actuals);
+ pp_macro_expander expand_macro(env, &frame);
+ macro->hidden = true;
+ expand_macro(macro->definition->begin(), macro->definition->end(), __result);
+ macro->hidden = false;
+ generated_lines += expand_macro.lines;
+ } else
+ *__result++ = *__first++;
+ }
+
+ return __first;
+ }
+
+ template <typename _InputIterator>
+ _InputIterator skip_argument_variadics(std::vector<std::string> const &__actuals, pp_macro *__macro,
+ _InputIterator __first, _InputIterator __last) {
+ _InputIterator arg_end = skip_argument(__first, __last);
+
+ while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ','
+ && (__actuals.size() + 1) == __macro->formals.size()) {
+ arg_end = skip_argument(++arg_end, __last);
+ }
+
+ return arg_end;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_MACRO_EXPANDER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-macro.h b/parser/rpp/pp-macro.h
new file mode 100644
index 000000000..e633834b1
--- /dev/null
+++ b/parser/rpp/pp-macro.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_MACRO_H
+#define PP_MACRO_H
+
+#include <vector>
+#include "pp-fwd.h"
+
+namespace rpp
+{
+
+struct pp_macro {
+#if defined (PP_WITH_MACRO_POSITION)
+ pp_fast_string const *file;
+#endif
+ pp_fast_string const *name;
+ pp_fast_string const *definition;
+ std::vector<pp_fast_string const *> formals;
+
+ union {
+ int unsigned state;
+
+ struct {
+ int unsigned hidden: 1;
+ int unsigned function_like: 1;
+ int unsigned variadics: 1;
+ };
+ };
+
+ int lines;
+ pp_macro *next;
+ std::size_t hash_code;
+
+ inline pp_macro():
+#if defined (PP_WITH_MACRO_POSITION)
+ file(0),
+#endif
+ name(0),
+ definition(0),
+ state(0),
+ lines(0),
+ next(0),
+ hash_code(0) {}
+};
+
+} // namespace rpp
+
+#endif // PP_MACRO_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-main.cpp b/parser/rpp/pp-main.cpp
new file mode 100644
index 000000000..4c37e754f
--- /dev/null
+++ b/parser/rpp/pp-main.cpp
@@ -0,0 +1,295 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <fstream>
+#include "pp.h"
+
+using namespace rpp;
+
+#ifndef GCC_MACHINE
+# define GCC_MACHINE "i386-redhat-linux"
+#endif
+
+#ifndef GCC_VERSION
+# define GCC_VERSION "4.1.1"
+#endif
+
+void usage()
+{
+ std::cerr << "usage: rpp file.cpp" << std::endl;
+ ::exit(EXIT_FAILURE);
+}
+
+void dump_macros(pp_environment &env, pp &, std::ostream &__out)
+{
+ for (pp_environment::const_iterator it = env.first_macro(); it != env.last_macro(); ++it) {
+ pp_macro const *m = *it;
+
+ if (m->hidden)
+ continue;
+
+ std::string id(m->name->begin(), m->name->end());
+ __out << "#define " << id;
+
+ if (m->function_like) {
+ __out << "(";
+
+ for (std::size_t i = 0; i < m->formals.size(); ++i) {
+ if (i != 0)
+ __out << ", ";
+
+ pp_fast_string const *f = m->formals [i];
+ std::string name(f->begin(), f->end());
+ __out << name;
+ }
+
+ if (m->variadics)
+ __out << "...";
+
+ __out << ")";
+ }
+
+ __out << "\t";
+ if (m->definition) {
+ std::string def(m->definition->begin(), m->definition->end());
+ __out << def;
+ }
+
+ __out << std::endl;
+ }
+}
+#if 0
+int main(int, char *argv [])
+{
+ char const *input_file = 0;
+ char const *output_file = 0;
+ char const *include_pch_file = 0;
+ bool opt_help = false;
+ bool opt_dump_macros = false;
+ bool opt_pch = false;
+
+ pp_environment env;
+ pp preprocess(env);
+
+ std::string result;
+ result.reserve(20 * 1024); // 20K
+
+ pp_output_iterator<std::string> out(result);
+ pp_null_output_iterator null_out;
+
+ preprocess.push_include_path("/usr/include");
+ preprocess.push_include_path("/usr/lib/gcc/" GCC_MACHINE "/" GCC_VERSION "/include");
+
+ preprocess.push_include_path("/usr/include/c++/" GCC_VERSION);
+ preprocess.push_include_path("/usr/include/c++/" GCC_VERSION "/" GCC_MACHINE);
+
+ std::string extra_args;
+
+ while (const char *arg = *++argv) {
+ if (arg [0] != '-')
+ input_file = arg;
+
+ else if (! strcmp(arg, "-help"))
+ opt_help = true;
+
+ else if (! strcmp(arg, "-dM"))
+ opt_dump_macros = true;
+
+ else if (! strcmp(arg, "-pch"))
+ opt_pch = true;
+
+ else if (! strcmp(arg, "-msse")) {
+ pp_macro __macro;
+ __macro.name = pp_symbol::get("__SSE__", 7);
+ env.bind(__macro.name, __macro);
+
+ __macro.name = pp_symbol::get("__MMX__", 7);
+ env.bind(__macro.name, __macro);
+ }
+
+ else if (! strcmp(arg, "-include")) {
+ if (argv [1])
+ include_pch_file = *++argv;
+ }
+
+ else if (! strncmp(arg, "-o", 2)) {
+ arg += 2;
+
+ if (! arg [0] && argv [1])
+ arg = *++argv;
+
+ if (arg)
+ output_file = arg;
+ }
+
+ else if (! strncmp(arg, "-conf", 8)) {
+ if (argv [1])
+ preprocess.file(*++argv, null_out);
+ }
+
+ else if (! strncmp(arg, "-I", 2)) {
+ arg += 2;
+
+ if (! arg [0] && argv [1])
+ arg = *++argv;
+
+ if (arg)
+ preprocess.push_include_path(arg);
+ }
+
+ else if (! strncmp(arg, "-U", 2)) {
+ arg += 2;
+
+ if (! arg [0] && argv [1])
+ arg = *++argv;
+
+ if (arg) {
+ env.unbind(arg, strlen(arg));
+ }
+ }
+
+ else if (! strncmp(arg, "-D", 2)) {
+ arg += 2;
+
+ if (! arg [0] && argv [1])
+ arg = *++argv;
+
+ if (arg) {
+ pp_macro __macro;
+
+ char const *end = arg;
+ char const *eq = 0;
+
+ for (; *end; ++end) {
+ if (*end == '=')
+ eq = end;
+ }
+
+ if (eq != 0) {
+ __macro.name = pp_symbol::get(arg, eq - arg);
+ __macro.definition = pp_symbol::get(eq + 1, end - (eq + 1));
+ }
+
+ else {
+ __macro.name = pp_symbol::get(arg, end - arg);
+ __macro.definition = 0;
+ }
+
+ env.bind(__macro.name, __macro);
+ }
+ } else {
+ extra_args += " ";
+ extra_args += arg;
+ }
+ }
+
+ if (! input_file || opt_help) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ std::string __ifile(input_file);
+ bool is_c_file = false;
+ if (__ifile.size() > 2 && __ifile [__ifile.size() - 1] == 'c' && __ifile [__ifile.size() - 2] == '.') {
+ is_c_file = true;
+ env.unbind("__cplusplus", 11);
+
+ pp_macro __macro;
+ __macro.name = pp_symbol::get("__null");
+ __macro.definition = pp_symbol::get("((void*) 0)");
+ env.bind(__macro.name, __macro);
+
+ // turn off the pch
+ include_pch_file = 0;
+ } else if (include_pch_file) {
+ std::string __pch(include_pch_file);
+ __pch += ".gch/c++.conf";
+
+ //std::cerr << "*** pch file " << __pch << std::endl;
+ preprocess.file(__pch, null_out);
+ }
+
+ if (opt_dump_macros) {
+ preprocess.file(input_file, null_out);
+ dump_macros(env, preprocess, std::cout);
+ return EXIT_SUCCESS;
+ }
+
+ preprocess.file(input_file, out);
+
+ if (opt_pch) {
+ if (! output_file) {
+ std::cerr << "*** WARNING expected a file name" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::string __conf_file(output_file);
+ __conf_file += ".conf";
+
+ std::ofstream __out;
+ __out.open(__conf_file.c_str());
+ dump_macros(env, preprocess, __out);
+ __out.close();
+
+ std::string __pp_file(output_file);
+ __pp_file += ".i";
+
+ __out.open(__pp_file.c_str());
+ __out.write(result.c_str(), result.size());
+ __out.close();
+ return EXIT_SUCCESS;
+ }
+
+ std::ostream *__out = &std::cout;
+ std::ofstream __ofile;
+
+ if (output_file) {
+ std::string __output_file_name(output_file);
+ __ofile.open(output_file);
+ __out = &__ofile;
+ }
+
+ if (include_pch_file) {
+ std::string __pch(include_pch_file);
+ __pch += ".gch/c++.i";
+
+ std::ifstream __in(__pch.c_str());
+
+ char buffer [1024];
+ while (__in.read(buffer, 1024))
+ __out->write(buffer, 1024);
+
+ __in.close();
+ }
+
+ __out->write(result.c_str(), result.size());
+
+ if (output_file)
+ __ofile.close();
+
+ return EXIT_SUCCESS;
+}
+#endif
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/rpp/pp-qt-configuration b/parser/rpp/pp-qt-configuration
new file mode 100644
index 000000000..206c3d643
--- /dev/null
+++ b/parser/rpp/pp-qt-configuration
@@ -0,0 +1,24 @@
+#define __cplusplus 1
+
+#define __STDC__
+
+// Qt
+#define QOBJECTDEFS_H
+
+// not yet supported
+#define Q_SLOTS slots
+#define Q_SIGNALS signals
+#define Q_FLAGS(a)
+#define Q_PRIVATE_SLOT(a, b)
+#define Q_DECLARE_INTERFACE(a,b)
+#define Q_INTERFACES(a)
+#define Q_GADGET
+#define Q_OVERRIDE(a)
+#define Q_OS_OS2
+#define Q_NO_USING_KEYWORD
+#define QT_NO_QOBJECT_CHECK
+#define QT_NO_MEMBER_TEMPLATES
+// There are symbols in Qt that exist in Debug but
+// not in release
+#define QT_NO_DEBUG
+
diff --git a/parser/rpp/pp-scanner.h b/parser/rpp/pp-scanner.h
new file mode 100644
index 000000000..e97b15843
--- /dev/null
+++ b/parser/rpp/pp-scanner.h
@@ -0,0 +1,313 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_SCANNER_H
+#define PP_SCANNER_H
+
+#include "pp-cctype.h"
+#include <cassert>
+
+namespace rpp
+{
+
+struct pp_skip_blanks {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ if (*__first == '\\') {
+ _InputIterator __begin = __first;
+ ++__begin;
+
+ if (__begin != __last && *__begin == '\n')
+ ++__first;
+ else
+ break;
+ } else if (*__first == '\n' || !pp_isspace(*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_whitespaces {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ if (! pp_isspace(*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_comment_or_divop {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ enum {
+ MAYBE_BEGIN,
+ BEGIN,
+ MAYBE_END,
+ END,
+ IN_COMMENT,
+ IN_CXX_COMMENT
+ } state(MAYBE_BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ switch (state) {
+ default:
+ assert(0);
+ break;
+
+ case MAYBE_BEGIN:
+ if (*__first != '/')
+ return __first;
+
+ state = BEGIN;
+ break;
+
+ case BEGIN:
+ if (*__first == '*')
+ state = IN_COMMENT;
+ else if (*__first == '/')
+ state = IN_CXX_COMMENT;
+ else
+ return __first;
+ break;
+
+ case IN_COMMENT:
+ if (*__first == '*')
+ state = MAYBE_END;
+ break;
+
+ case IN_CXX_COMMENT:
+ if (*__first == '\n')
+ return __first;
+ break;
+
+ case MAYBE_END:
+ if (*__first == '/')
+ state = END;
+ else if (*__first != '*')
+ state = IN_COMMENT;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_identifier {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ if (! pp_isalnum(*__first) && *__first != '_')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_number {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ if (! pp_isalnum(*__first) && *__first != '.')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_string_literal {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state(BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ switch (state) {
+ default:
+ assert(0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\"')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ assert(*__first != '\n');
+
+ if (*__first == '\"')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_char_literal {
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state(BEGIN);
+
+ lines = 0;
+
+ for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) {
+ switch (state) {
+ default:
+ assert(0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\'')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ assert(*__first != '\n');
+
+ if (*__first == '\'')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_argument {
+ pp_skip_identifier skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ int lines;
+
+ template <typename _InputIterator>
+ _InputIterator operator()(_InputIterator __first, _InputIterator __last) {
+ int depth = 0;
+ lines = 0;
+
+ while (__first != __last) {
+ if (!depth && (*__first == ')' || *__first == ','))
+ break;
+ else if (*__first == '(')
+ ++depth, ++__first;
+ else if (*__first == ')')
+ --depth, ++__first;
+ else if (*__first == '\"') {
+ __first = skip_string_literal(__first, __last);
+ lines += skip_string_literal.lines;
+ } else if (*__first == '\'') {
+ __first = skip_char_literal(__first, __last);
+ lines += skip_char_literal.lines;
+ } else if (*__first == '/') {
+ __first = skip_comment_or_divop(__first, __last);
+ lines += skip_comment_or_divop.lines;
+ } else if (pp_isalpha(*__first) || *__first == '_') {
+ __first = skip_identifier(__first, __last);
+ lines += skip_identifier.lines;
+ } else if (pp_isdigit(*__first)) {
+ __first = skip_number(__first, __last);
+ lines += skip_number.lines;
+ } else if (*__first == '\n') {
+ ++__first;
+ ++lines;
+ } else
+ ++__first;
+ }
+
+ return __first;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_SCANNER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-string.h b/parser/rpp/pp-string.h
new file mode 100644
index 000000000..31bca4f7b
--- /dev/null
+++ b/parser/rpp/pp-string.h
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_STRING_H
+#define PP_STRING_H
+
+namespace rpp
+{
+
+template <typename _CharT>
+class pp_string
+{
+ typedef std::char_traits<_CharT> traits_type;
+ typedef std::size_t size_type;
+
+ _CharT const *_M_begin;
+ std::size_t _M_size;
+
+public:
+ inline pp_string():
+ _M_begin(0), _M_size(0) {}
+
+ explicit pp_string(std::string const &__s):
+ _M_begin(__s.c_str()), _M_size(__s.size()) {}
+
+ inline pp_string(_CharT const *__begin, std::size_t __size):
+ _M_begin(__begin), _M_size(__size) {}
+
+ inline _CharT const *begin() const {
+ return _M_begin;
+ }
+ inline _CharT const *end() const {
+ return _M_begin + _M_size;
+ }
+
+ inline _CharT at(std::size_t index) const {
+ return _M_begin [index];
+ }
+
+ inline std::size_t size() const {
+ return _M_size;
+ }
+
+ inline int compare(pp_string const &__other) const {
+ size_type const __size = this->size();
+ size_type const __osize = __other.size();
+ size_type const __len = std::min(__size, __osize);
+
+ int __r = traits_type::compare(_M_begin, __other._M_begin, __len);
+ if (!__r)
+ __r = (int)(__size - __osize);
+
+ return __r;
+ }
+
+ inline bool operator == (pp_string const &__other) const {
+ return compare(__other) == 0;
+ }
+
+ inline bool operator != (pp_string const &__other) const {
+ return compare(__other) != 0;
+ }
+
+ inline bool operator < (pp_string const &__other) const {
+ return compare(__other) < 0;
+ }
+
+ inline bool operator == (char const *s) const {
+ std::size_t n = strlen(s);
+
+ if (n != _M_size)
+ return false;
+
+ return ! strncmp(_M_begin, s, n);
+ }
+
+ inline bool operator != (char const *s) const {
+ return ! operator == (s);
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_STRING_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp-symbol.h b/parser/rpp/pp-symbol.h
new file mode 100644
index 000000000..eef668379
--- /dev/null
+++ b/parser/rpp/pp-symbol.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_SYMBOL_H
+#define PP_SYMBOL_H
+
+#include <cassert>
+#include <iterator>
+#include "pp-fwd.h"
+#include "parser/rxx_allocator.h"
+
+namespace rpp
+{
+
+class pp_symbol
+{
+ static rxx_allocator<char> &allocator_instance() {
+ static rxx_allocator<char>__allocator;
+ return __allocator;
+ }
+
+public:
+ static int &N() {
+ static int __N;
+ return __N;
+ }
+
+ static pp_fast_string const *get(char const *__data, std::size_t __size) {
+ ++N();
+ char *data = allocator_instance().allocate(__size + 1);
+ memcpy(data, __data, __size);
+ data[__size] = '\0';
+
+ char *where = allocator_instance().allocate(sizeof(pp_fast_string));
+ return new(where) pp_fast_string(data, __size);
+ }
+
+ template <typename _InputIterator>
+ static pp_fast_string const *get(_InputIterator __first, _InputIterator __last) {
+ ++N();
+ std::ptrdiff_t __size;
+#if defined(__SUNPRO_CC)
+ std::distance(__first, __last, __size);
+#else
+ __size = std::distance(__first, __last);
+#endif
+ assert(__size >= 0 && __size < 512);
+
+ char *data = allocator_instance().allocate(__size + 1);
+ std::copy(__first, __last, data);
+ data[__size] = '\0';
+
+ char *where = allocator_instance().allocate(sizeof(pp_fast_string));
+ return new(where) pp_fast_string(data, __size);
+ }
+
+ static pp_fast_string const *get(std::string const &__s) {
+ return get(__s.c_str(), __s.size());
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_SYMBOL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/pp.h b/parser/rpp/pp.h
new file mode 100644
index 000000000..3ff38c0d1
--- /dev/null
+++ b/parser/rpp/pp.h
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PP_H
+#define PP_H
+
+#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \
+ || defined(_WIN32) || defined(WIN32) || defined(__WIN32__)
+# define PP_OS_WIN
+#endif
+
+#include <set>
+#include <map>
+#include <vector>
+#include <string>
+#include <iterator>
+#include <iostream>
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+
+#include <fcntl.h>
+
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if (_MSC_VER >= 1400)
+# define FILENO _fileno
+#else
+# define FILENO fileno
+#endif
+
+#if defined (PP_OS_WIN)
+# define PATH_SEPARATOR '\\'
+#else
+# define PATH_SEPARATOR '/'
+#endif
+
+#if defined (RPP_JAMBI)
+# include "parser/rxx_allocator.h"
+#else
+# include "parser/rpp-allocator.h"
+#endif
+
+#if defined (_MSC_VER)
+# define pp_snprintf _snprintf
+#else
+# define pp_snprintf snprintf
+#endif
+
+#include "pp-fwd.h"
+#include "pp-cctype.h"
+#include "pp-string.h"
+#include "pp-symbol.h"
+#include "pp-internal.h"
+#include "pp-iterator.h"
+#include "pp-macro.h"
+#include "pp-environment.h"
+#include "pp-scanner.h"
+#include "pp-macro-expander.h"
+#include "pp-engine.h"
+#include "pp-engine-bits.h"
+
+#endif // PP_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/rpp/preprocessor.cpp b/parser/rpp/preprocessor.cpp
new file mode 100644
index 000000000..be6a85186
--- /dev/null
+++ b/parser/rpp/preprocessor.cpp
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Harald Fernengel <harry@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "preprocessor.h"
+
+#include <string>
+
+// register callback for include hooks
+static void includeFileHook(const std::string &, const std::string &, FILE *);
+
+#define PP_HOOK_ON_FILE_INCLUDED(A, B, C) includeFileHook(A, B, C)
+#include "pp.h"
+
+using namespace rpp;
+
+#include <QtCore/QtCore>
+
+class PreprocessorPrivate
+{
+public:
+ QByteArray result;
+ pp_environment env;
+ QStringList includePaths;
+
+ void initPP(pp &proc) {
+ foreach(QString path, includePaths)
+ proc.push_include_path(path.toStdString());
+ }
+};
+
+QHash<QString, QStringList> includedFiles;
+
+void includeFileHook(const std::string &fileName, const std::string &filePath, FILE *)
+{
+ includedFiles[QString::fromStdString(fileName)].append(QString::fromStdString(filePath));
+}
+
+Preprocessor::Preprocessor()
+{
+ d = new PreprocessorPrivate;
+ includedFiles.clear();
+}
+
+Preprocessor::~Preprocessor()
+{
+ delete d;
+}
+
+void Preprocessor::processFile(const QString &fileName)
+{
+ pp proc(d->env);
+ d->initPP(proc);
+
+ d->result.reserve(d->result.size() + 20 * 1024);
+
+ d->result += "# 1 \"" + fileName.toLatin1() + "\"\n"; // ### REMOVE ME
+ proc.file(fileName.toLocal8Bit().constData(), std::back_inserter(d->result));
+}
+
+void Preprocessor::processString(const QByteArray &str)
+{
+ pp proc(d->env);
+ d->initPP(proc);
+
+ proc(str.begin(), str.end(), std::back_inserter(d->result));
+}
+
+QByteArray Preprocessor::result() const
+{
+ return d->result;
+}
+
+void Preprocessor::addIncludePaths(const QStringList &includePaths)
+{
+ d->includePaths += includePaths;
+}
+
+QStringList Preprocessor::macroNames() const
+{
+ QStringList macros;
+
+ pp_environment::const_iterator it = d->env.first_macro();
+ while (it != d->env.last_macro()) {
+ const pp_macro *m = *it;
+ macros += QString::fromLatin1(m->name->begin(), m->name->size());
+ ++it;
+ }
+
+ return macros;
+}
+
+QList<Preprocessor::MacroItem> Preprocessor::macros() const
+{
+ QList<MacroItem> items;
+
+ pp_environment::const_iterator it = d->env.first_macro();
+ while (it != d->env.last_macro()) {
+ const pp_macro *m = *it;
+ MacroItem item;
+ item.name = QString::fromLatin1(m->name->begin(), m->name->size());
+ item.definition = QString::fromLatin1(m->definition->begin(),
+ m->definition->size());
+ for (size_t i = 0; i < m->formals.size(); ++i) {
+ item.parameters += QString::fromLatin1(m->formals[i]->begin(),
+ m->formals[i]->size());
+ }
+ item.isFunctionLike = m->function_like;
+
+#ifdef PP_WITH_MACRO_POSITION
+ item.fileName = QString::fromLatin1(m->file->begin(), m->file->size());
+#endif
+ items += item;
+
+ ++it;
+ }
+
+ return items;
+}
+
+/*
+int main()
+{
+ Preprocessor pp;
+
+ QStringList paths;
+ paths << "/usr/include";
+ pp.addIncludePaths(paths);
+
+ pp.processFile("pp-configuration");
+ pp.processFile("/usr/include/stdio.h");
+
+ qDebug() << pp.result();
+
+ return 0;
+}
+*/
+
diff --git a/parser/rpp/preprocessor.h b/parser/rpp/preprocessor.h
new file mode 100644
index 000000000..c363ea7c8
--- /dev/null
+++ b/parser/rpp/preprocessor.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright 2005 Harald Fernengel <harry@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PREPROCESSOR_H
+#define PREPROCESSOR_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+class QByteArray;
+class PreprocessorPrivate;
+
+class Preprocessor
+{
+public:
+ Preprocessor();
+ ~Preprocessor();
+
+ void processFile(const QString &fileName);
+ void processString(const QByteArray &str);
+
+ void addIncludePaths(const QStringList &includePaths);
+
+ QByteArray result() const;
+
+ QStringList macroNames() const;
+
+ struct MacroItem {
+ QString name;
+ QStringList parameters;
+ QString definition;
+ bool isFunctionLike;
+#ifdef PP_WITH_MACRO_POSITION
+ QString fileName;
+#endif
+ };
+ QList<MacroItem> macros() const;
+
+private:
+ Q_DISABLE_COPY(Preprocessor)
+ PreprocessorPrivate *d;
+};
+
+#endif
diff --git a/parser/rxx_allocator.h b/parser/rxx_allocator.h
new file mode 100644
index 000000000..e4a387554
--- /dev/null
+++ b/parser/rxx_allocator.h
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef RXX_ALLOCATOR_H
+#define RXX_ALLOCATOR_H
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+
+template <class _Tp> class rxx_allocator
+{
+public:
+ typedef _Tp value_type;
+ typedef _Tp* pointer;
+ typedef const _Tp* const_pointer;
+ typedef _Tp& reference;
+ typedef const _Tp& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ static const size_type max_block_count = size_type(-1);
+ static const size_type _S_block_size = 1 << 16; // 64K
+
+ rxx_allocator()
+ {
+ _M_block_index = max_block_count;
+ _M_current_index = 0;
+ _M_storage = 0;
+ _M_current_block = 0;
+ }
+
+ ~rxx_allocator()
+ {
+ for (size_type index = 0; index < _M_block_index + 1; ++index)
+ delete[] _M_storage[index];
+
+ ::free(_M_storage);
+ }
+
+ pointer address(reference __val) { return &__val; }
+ const_pointer address(const_reference __val) const { return &__val; }
+
+ pointer allocate(size_type __n, const void* = 0)
+ {
+ const size_type bytes = __n * sizeof(_Tp);
+
+ if (_M_current_block == 0
+ || _S_block_size < _M_current_index + bytes) {
+ ++_M_block_index;
+
+ _M_storage = reinterpret_cast<char**>
+ (::realloc(_M_storage, sizeof(char*) * (1 + _M_block_index)));
+
+ _M_current_block = _M_storage[_M_block_index] = reinterpret_cast<char*>
+ (new char[_S_block_size]);
+
+#if defined(RXX_ALLOCATOR_INIT_0) // ### make it a policy
+ ::memset(_M_current_block, 0, _S_block_size);
+#endif
+ _M_current_index = 0;
+ }
+
+ pointer p = reinterpret_cast<pointer>
+ (_M_current_block + _M_current_index);
+
+ _M_current_index += bytes;
+
+ return p;
+ }
+
+ void deallocate(pointer __p, size_type __n) {}
+
+ size_type max_size() const
+ {
+ return size_type(-1) / sizeof(_Tp);
+ }
+
+ void contruct(pointer __p, const_reference __val)
+ {
+ new(__p) _Tp(__val);
+ }
+ void destruct(pointer __p)
+ {
+ __p->~_Tp();
+ }
+
+private:
+ template <class _Tp1>
+ struct rebind
+ {
+ typedef rxx_allocator<_Tp1> other;
+ };
+
+ template <class _Tp1> rxx_allocator(const rxx_allocator<_Tp1> &__o) {}
+
+private:
+ size_type _M_block_index;
+ size_type _M_current_index;
+ char *_M_current_block;
+ char **_M_storage;
+};
+
+#endif // RXX_ALLOCATOR_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/smallobject.cpp b/parser/smallobject.cpp
new file mode 100644
index 000000000..e96d417c6
--- /dev/null
+++ b/parser/smallobject.cpp
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "smallobject.h"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/smallobject.h b/parser/smallobject.h
new file mode 100644
index 000000000..52cdc232f
--- /dev/null
+++ b/parser/smallobject.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef SMALLOBJECT_H
+#define SMALLOBJECT_H
+
+#include "rxx_allocator.h"
+#include <cstring>
+
+class pool
+{
+ rxx_allocator<char> __alloc;
+
+public:
+ inline void *allocate(std::size_t __size);
+};
+
+inline void *pool::allocate(std::size_t __size)
+{
+ return __alloc.allocate(__size);
+}
+
+#endif
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/symbol.h b/parser/symbol.h
new file mode 100644
index 000000000..8e393cddb
--- /dev/null
+++ b/parser/symbol.h
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef SYMBOL_H
+#define SYMBOL_H
+
+#include <QtCore/QString>
+#include <cstring>
+
+#include <QtCore/QHash>
+#include <QtCore/QPair>
+
+struct NameSymbol
+{
+ const char *data;
+ std::size_t count;
+
+ inline QString as_string() const
+ {
+ return QString::fromUtf8(data, (int) count);
+ }
+
+ inline bool operator == (const NameSymbol &other) const
+ {
+ return count == other.count
+ && !std::strncmp(data, other.data, count);
+ }
+
+protected:
+ inline NameSymbol() {}
+ inline NameSymbol(const char *d, std::size_t c)
+ : data(d), count(c) {}
+
+private:
+ void operator = (const NameSymbol &);
+
+ friend class NameTable;
+};
+
+inline uint qHash(const NameSymbol &r)
+{
+ uint hash_value = 0;
+
+ for (std::size_t i = 0; i < r.count; ++i)
+ hash_value = (hash_value << 5) - hash_value + r.data[i];
+
+ return hash_value;
+}
+
+inline uint qHash(const QPair<const char*, std::size_t> &r)
+{
+ uint hash_value = 0;
+
+ for (std::size_t i = 0; i < r.second; ++i)
+ hash_value = (hash_value << 5) - hash_value + r.first[i];
+
+ return hash_value;
+}
+
+class NameTable
+{
+public:
+ typedef QPair<const char *, std::size_t> KeyType;
+ typedef QHash<KeyType, NameSymbol*> ContainerType;
+
+public:
+ NameTable() {}
+
+ ~NameTable()
+ {
+ qDeleteAll(_M_storage);
+ }
+
+ inline const NameSymbol *findOrInsert(const char *str, std::size_t len)
+ {
+ KeyType key(str, len);
+
+ NameSymbol *name = _M_storage.value(key);
+ if (!name) {
+ name = new NameSymbol(str, len);
+ _M_storage.insert(key, name);
+ }
+
+ return name;
+ }
+
+ inline std::size_t count() const { return _M_storage.size(); }
+
+private:
+ ContainerType _M_storage;
+
+private:
+ NameTable(const NameTable &other);
+ void operator=(const NameTable &other);
+};
+
+#endif // SYMBOL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/tokens.cpp b/parser/tokens.cpp
new file mode 100644
index 000000000..2e054d894
--- /dev/null
+++ b/parser/tokens.cpp
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include <QtCore/qglobal.h>
+
+#include "tokens.h"
+
+static char const * const _S_token_names[] = {
+ "K_DCOP",
+ "Q_OBJECT",
+ "Q_PROPERTY",
+ "__attribute__",
+ "__typeof",
+ "and",
+ "and_eq",
+ "arrow",
+ "asm",
+ "assign",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "char_literal",
+ "class",
+ "comment",
+ "compl",
+ "concat",
+ "const",
+ "const_cast",
+ "continue",
+ "decr",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "ellipsis",
+ "else",
+ "emit",
+ "enum",
+ "eq",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "geq",
+ "goto",
+ "identifier",
+ "if",
+ "incr",
+ "inline",
+ "int",
+ "k_dcop",
+ "k_dcop_signals",
+ "leq",
+ "long",
+ "mutable",
+ "namespace",
+ "new",
+ "not",
+ "not_eq",
+ "number_literal",
+ "operator",
+ "or",
+ "or_eq",
+ "preproc",
+ "private",
+ "protected",
+ "ptrmem",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "return",
+ "scope",
+ "shift",
+ "short",
+ "signals",
+ "signed",
+ "sizeof",
+ "slots",
+ "static",
+ "static_cast",
+ "string_literal",
+ "struct",
+ "switch",
+ "template",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "whitespaces",
+ "xor",
+ "xor_eq",
+ "Q_ENUMS"
+};
+
+static char _S_printable[][2] = {
+ { char(32), '\0' },
+ { char(33), '\0' },
+ { char(34), '\0' },
+ { char(35), '\0' },
+ { char(36), '\0' },
+ { char(37), '\0' },
+ { char(38), '\0' },
+ { char(39), '\0' },
+ { char(40), '\0' },
+ { char(41), '\0' },
+ { char(42), '\0' },
+ { char(43), '\0' },
+ { char(44), '\0' },
+ { char(45), '\0' },
+ { char(46), '\0' },
+ { char(47), '\0' },
+ { char(48), '\0' },
+ { char(49), '\0' },
+ { char(50), '\0' },
+ { char(51), '\0' },
+ { char(52), '\0' },
+ { char(53), '\0' },
+ { char(54), '\0' },
+ { char(55), '\0' },
+ { char(56), '\0' },
+ { char(57), '\0' },
+ { char(58), '\0' },
+ { char(59), '\0' },
+ { char(60), '\0' },
+ { char(61), '\0' },
+ { char(62), '\0' },
+ { char(63), '\0' },
+ { char(64), '\0' },
+ { char(65), '\0' },
+ { char(66), '\0' },
+ { char(67), '\0' },
+ { char(68), '\0' },
+ { char(69), '\0' },
+ { char(70), '\0' },
+ { char(71), '\0' },
+ { char(72), '\0' },
+ { char(73), '\0' },
+ { char(74), '\0' },
+ { char(75), '\0' },
+ { char(76), '\0' },
+ { char(77), '\0' },
+ { char(78), '\0' },
+ { char(79), '\0' },
+ { char(80), '\0' },
+ { char(81), '\0' },
+ { char(82), '\0' },
+ { char(83), '\0' },
+ { char(84), '\0' },
+ { char(85), '\0' },
+ { char(86), '\0' },
+ { char(87), '\0' },
+ { char(88), '\0' },
+ { char(89), '\0' },
+ { char(90), '\0' },
+ { char(91), '\0' },
+ { char(92), '\0' },
+ { char(93), '\0' },
+ { char(94), '\0' },
+ { char(95), '\0' },
+ { char(96), '\0' },
+ { char(97), '\0' },
+ { char(98), '\0' },
+ { char(99), '\0' },
+ { char(100), '\0' },
+ { char(101), '\0' },
+ { char(102), '\0' },
+ { char(103), '\0' },
+ { char(104), '\0' },
+ { char(105), '\0' },
+ { char(106), '\0' },
+ { char(107), '\0' },
+ { char(108), '\0' },
+ { char(109), '\0' },
+ { char(110), '\0' },
+ { char(111), '\0' },
+ { char(112), '\0' },
+ { char(113), '\0' },
+ { char(114), '\0' },
+ { char(115), '\0' },
+ { char(116), '\0' },
+ { char(117), '\0' },
+ { char(118), '\0' },
+ { char(119), '\0' },
+ { char(120), '\0' },
+ { char(121), '\0' },
+ { char(122), '\0' },
+ { char(123), '\0' },
+ { char(124), '\0' },
+ { char(125), '\0' },
+ { char(126), '\0' },
+ { char(127), '\0' },
+};
+
+char const *token_name(int token)
+{
+ if (token == 0)
+ return "eof";
+ else if (token >= 32 && token <= 127)
+ return _S_printable[token - 32];
+ else if (token >= 1000)
+ return _S_token_names[token - 1000];
+
+ Q_ASSERT(0);
+ return 0;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/tokens.h b/parser/tokens.h
new file mode 100644
index 000000000..257ff0992
--- /dev/null
+++ b/parser/tokens.h
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef TOKENS_H
+#define TOKENS_H
+
+enum TOKEN_KIND {
+ Token_EOF = 0,
+
+ Token_K_DCOP = 1000,
+ Token_Q_OBJECT,
+ Token_Q_PROPERTY,
+ Token___attribute__,
+ Token___typeof,
+ Token_and,
+ Token_and_eq,
+ Token_arrow,
+ Token_asm,
+ Token_assign,
+ Token_auto,
+ Token_bitand,
+ Token_bitor,
+ Token_bool,
+ Token_break,
+ Token_case,
+ Token_catch,
+ Token_char,
+ Token_char_literal,
+ Token_class,
+ Token_comment,
+ Token_compl,
+ Token_concat,
+ Token_const,
+ Token_const_cast,
+ Token_continue,
+ Token_decr,
+ Token_default,
+ Token_delete,
+ Token_do,
+ Token_double,
+ Token_dynamic_cast,
+ Token_ellipsis,
+ Token_else,
+ Token_emit,
+ Token_enum,
+ Token_eq,
+ Token_explicit,
+ Token_export,
+ Token_extern,
+ Token_false,
+ Token_float,
+ Token_for,
+ Token_friend,
+ Token_geq,
+ Token_goto,
+ Token_identifier,
+ Token_if,
+ Token_incr,
+ Token_inline,
+ Token_int,
+ Token_k_dcop,
+ Token_k_dcop_signals,
+ Token_leq,
+ Token_long,
+ Token_mutable,
+ Token_namespace,
+ Token_new,
+ Token_not,
+ Token_not_eq,
+ Token_number_literal,
+ Token_operator,
+ Token_or,
+ Token_or_eq,
+ Token_preproc,
+ Token_private,
+ Token_protected,
+ Token_ptrmem,
+ Token_public,
+ Token_register,
+ Token_reinterpret_cast,
+ Token_return,
+ Token_scope,
+ Token_shift,
+ Token_short,
+ Token_signals,
+ Token_signed,
+ Token_sizeof,
+ Token_slots,
+ Token_static,
+ Token_static_cast,
+ Token_string_literal,
+ Token_struct,
+ Token_switch,
+ Token_template,
+ Token_this,
+ Token_throw,
+ Token_true,
+ Token_try,
+ Token_typedef,
+ Token_typeid,
+ Token_typename,
+ Token_union,
+ Token_unsigned,
+ Token_using,
+ Token_virtual,
+ Token_void,
+ Token_volatile,
+ Token_wchar_t,
+ Token_while,
+ Token_whitespaces,
+ Token_xor,
+ Token_xor_eq,
+ Token_Q_ENUMS,
+ Token_Q_INVOKABLE,
+
+ TOKEN_KIND_COUNT
+};
+
+char const *token_name(int token);
+
+#endif
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/type_compiler.cpp b/parser/type_compiler.cpp
new file mode 100644
index 000000000..4bcdb277a
--- /dev/null
+++ b/parser/type_compiler.cpp
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "lexer.h"
+#include "symbol.h"
+#include "tokens.h"
+#include "binder.h"
+
+#include <QtCore/QString>
+
+TypeCompiler::TypeCompiler(Binder *binder)
+ : _M_binder(binder), _M_token_stream(binder->tokenStream())
+{
+}
+
+void TypeCompiler::run(TypeSpecifierAST *node)
+{
+ _M_type.clear();
+ _M_cv.clear();
+
+ visit(node);
+
+ if (node && node->cv) {
+ const ListNode<std::size_t> *it = node->cv->toFront();
+ const ListNode<std::size_t> *end = it;
+ do {
+ int kind = _M_token_stream->kind(it->element);
+ if (!_M_cv.contains(kind))
+ _M_cv.append(kind);
+
+ it = it->next;
+ } while (it != end);
+ }
+}
+
+void TypeCompiler::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node)
+{
+ if (const ListNode<std::size_t> *it = node->integrals) {
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+ QString current_item;
+ do {
+ std::size_t token = it->element;
+ current_item += token_name(_M_token_stream->kind(token));
+ current_item += " ";
+ it = it->next;
+ } while (it != end);
+ _M_type += current_item.trimmed();
+ } else if (node->type_of) {
+ // ### implement me
+ _M_type += QLatin1String("typeof<...>");
+ }
+
+ visit(node->name);
+}
+
+void TypeCompiler::visitName(NameAST *node)
+{
+ NameCompiler name_cc(_M_binder);
+ name_cc.run(node);
+ _M_type = name_cc.qualifiedName();
+}
+
+QStringList TypeCompiler::cvString() const
+{
+ QStringList lst;
+
+ foreach (int q, cv()) {
+ if (q == Token_const)
+ lst.append(QLatin1String("const"));
+ else if (q == Token_volatile)
+ lst.append(QLatin1String("volatile"));
+ }
+
+ return lst;
+}
+
+bool TypeCompiler::isConstant() const
+{
+ return _M_cv.contains(Token_const);
+}
+
+bool TypeCompiler::isVolatile() const
+{
+ return _M_cv.contains(Token_volatile);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/type_compiler.h b/parser/type_compiler.h
new file mode 100644
index 000000000..985cc8e2e
--- /dev/null
+++ b/parser/type_compiler.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef TYPE_COMPILER_H
+#define TYPE_COMPILER_H
+
+#include "default_visitor.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+
+class TokenStream;
+class Binder;
+
+class TypeCompiler: protected DefaultVisitor
+{
+public:
+ TypeCompiler(Binder *binder);
+
+ inline QStringList qualifiedName() const { return _M_type; }
+ inline QList<int> cv() const { return _M_cv; }
+
+ bool isConstant() const;
+ bool isVolatile() const;
+
+ QStringList cvString() const;
+
+ void run(TypeSpecifierAST *node);
+
+protected:
+ virtual void visitClassSpecifier(ClassSpecifierAST *node);
+ virtual void visitEnumSpecifier(EnumSpecifierAST *node);
+ virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node);
+ virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node);
+
+ virtual void visitName(NameAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QStringList _M_type;
+ QList<int> _M_cv;
+};
+
+#endif // TYPE_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/parser/visitor.cpp b/parser/visitor.cpp
new file mode 100644
index 000000000..742981414
--- /dev/null
+++ b/parser/visitor.cpp
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#include "visitor.h"
+
+Visitor::visitor_fun_ptr Visitor::_S_table[AST::NODE_KIND_COUNT] = {
+ 0,
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitAccessSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitAsmDefinition),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBaseClause),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBaseSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBinaryExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCastExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitClassMemberAccess),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitClassSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCompoundStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCondition),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitConditionalExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCppCastExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCtorInitializer),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeclarationStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeclarator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeleteExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDoStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitElaboratedTypeSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitEnumSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitEnumerator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExceptionSpecification),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExpressionOrDeclarationStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExpressionStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitForStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitFunctionCall),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitFunctionDefinition),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitIfStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitIncrDecrExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitDeclarator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitializer),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitializerClause),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLabeledStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLinkageBody),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLinkageSpecification),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitMemInitializer),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitName),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNamespace),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNamespaceAliasDefinition),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewDeclarator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewInitializer),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewTypeId),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitOperator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitOperatorFunctionId),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitParameterDeclaration),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitParameterDeclarationClause),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPostfixExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPrimaryExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPtrOperator),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPtrToMember),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitReturnStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSimpleDeclaration),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSimpleTypeSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSizeofExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitStringLiteral),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSubscriptExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSwitchStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateArgument),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateDeclaration),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateParameter),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitThrowExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTranslationUnit),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTryBlockStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeId),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeIdentification),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeParameter),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypedef),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUnaryExpression),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUnqualifiedName),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsing),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsingDirective),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWhileStatement),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWinDeclSpec),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitQProperty),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitForwardDeclarationSpecifier),
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitQEnums)
+};
+
+Visitor::Visitor()
+{
+}
+
+Visitor::~Visitor()
+{
+}
+
+void Visitor::visit(AST *node)
+{
+ if (node)
+ (this->*_S_table[node->kind])(node);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/parser/visitor.h b/parser/visitor.h
new file mode 100644
index 000000000..74edcca83
--- /dev/null
+++ b/parser/visitor.h
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+#ifndef VISITOR_H
+#define VISITOR_H
+
+#include "ast.h"
+
+class Visitor
+{
+public:
+ Visitor();
+ virtual ~Visitor();
+
+ virtual void visit(AST *node);
+
+protected:
+ virtual void visitAccessSpecifier(AccessSpecifierAST *) {}
+ virtual void visitAsmDefinition(AsmDefinitionAST *) {}
+ virtual void visitBaseClause(BaseClauseAST *) {}
+ virtual void visitBaseSpecifier(BaseSpecifierAST *) {}
+ virtual void visitBinaryExpression(BinaryExpressionAST *) {}
+ virtual void visitCastExpression(CastExpressionAST *) {}
+ virtual void visitClassMemberAccess(ClassMemberAccessAST *) {}
+ virtual void visitClassSpecifier(ClassSpecifierAST *) {}
+ virtual void visitCompoundStatement(CompoundStatementAST *) {}
+ virtual void visitCondition(ConditionAST *) {}
+ virtual void visitConditionalExpression(ConditionalExpressionAST *) {}
+ virtual void visitCppCastExpression(CppCastExpressionAST *) {}
+ virtual void visitCtorInitializer(CtorInitializerAST *) {}
+ virtual void visitDeclarationStatement(DeclarationStatementAST *) {}
+ virtual void visitDeclarator(DeclaratorAST *) {}
+ virtual void visitDeleteExpression(DeleteExpressionAST *) {}
+ virtual void visitDoStatement(DoStatementAST *) {}
+ virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *) {}
+ virtual void visitEnumSpecifier(EnumSpecifierAST *) {}
+ virtual void visitEnumerator(EnumeratorAST *) {}
+ virtual void visitExceptionSpecification(ExceptionSpecificationAST *) {}
+ virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *) {}
+ virtual void visitExpressionStatement(ExpressionStatementAST *) {}
+ virtual void visitForStatement(ForStatementAST *) {}
+ virtual void visitFunctionCall(FunctionCallAST *) {}
+ virtual void visitFunctionDefinition(FunctionDefinitionAST *) {}
+ virtual void visitIfStatement(IfStatementAST *) {}
+ virtual void visitIncrDecrExpression(IncrDecrExpressionAST *) {}
+ virtual void visitInitDeclarator(InitDeclaratorAST *) {}
+ virtual void visitInitializer(InitializerAST *) {}
+ virtual void visitInitializerClause(InitializerClauseAST *) {}
+ virtual void visitLabeledStatement(LabeledStatementAST *) {}
+ virtual void visitLinkageBody(LinkageBodyAST *) {}
+ virtual void visitLinkageSpecification(LinkageSpecificationAST *) {}
+ virtual void visitMemInitializer(MemInitializerAST *) {}
+ virtual void visitName(NameAST *) {}
+ virtual void visitNamespace(NamespaceAST *) {}
+ virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *) {}
+ virtual void visitNewDeclarator(NewDeclaratorAST *) {}
+ virtual void visitNewExpression(NewExpressionAST *) {}
+ virtual void visitNewInitializer(NewInitializerAST *) {}
+ virtual void visitNewTypeId(NewTypeIdAST *) {}
+ virtual void visitOperator(OperatorAST *) {}
+ virtual void visitOperatorFunctionId(OperatorFunctionIdAST *) {}
+ virtual void visitParameterDeclaration(ParameterDeclarationAST *) {}
+ virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *) {}
+ virtual void visitPostfixExpression(PostfixExpressionAST *) {}
+ virtual void visitPrimaryExpression(PrimaryExpressionAST *) {}
+ virtual void visitPtrOperator(PtrOperatorAST *) {}
+ virtual void visitPtrToMember(PtrToMemberAST *) {}
+ virtual void visitReturnStatement(ReturnStatementAST *) {}
+ virtual void visitSimpleDeclaration(SimpleDeclarationAST *) {}
+ virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *) {}
+ virtual void visitSizeofExpression(SizeofExpressionAST *) {}
+ virtual void visitStringLiteral(StringLiteralAST *) {}
+ virtual void visitSubscriptExpression(SubscriptExpressionAST *) {}
+ virtual void visitSwitchStatement(SwitchStatementAST *) {}
+ virtual void visitTemplateArgument(TemplateArgumentAST *) {}
+ virtual void visitTemplateDeclaration(TemplateDeclarationAST *) {}
+ virtual void visitTemplateParameter(TemplateParameterAST *) {}
+ virtual void visitThrowExpression(ThrowExpressionAST *) {}
+ virtual void visitTranslationUnit(TranslationUnitAST *) {}
+ virtual void visitTryBlockStatement(TryBlockStatementAST *) {}
+ virtual void visitTypeId(TypeIdAST *) {}
+ virtual void visitTypeIdentification(TypeIdentificationAST *) {}
+ virtual void visitTypeParameter(TypeParameterAST *) {}
+ virtual void visitTypedef(TypedefAST *) {}
+ virtual void visitUnaryExpression(UnaryExpressionAST *) {}
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *) {}
+ virtual void visitUsing(UsingAST *) {}
+ virtual void visitUsingDirective(UsingDirectiveAST *) {}
+ virtual void visitWhileStatement(WhileStatementAST *) {}
+ virtual void visitWinDeclSpec(WinDeclSpecAST *) {}
+ virtual void visitQProperty(QPropertyAST *) {}
+ virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *) {}
+ virtual void visitQEnums(QEnumsAST *) {}
+
+private:
+ typedef void (Visitor::*visitor_fun_ptr)(AST *);
+ static visitor_fun_ptr _S_table[];
+};
+
+template <class _Tp>
+void visitNodes(Visitor *v, const ListNode<_Tp> *nodes)
+{
+ if (!nodes)
+ return;
+
+ const ListNode<_Tp>
+ *it = nodes->toFront(),
+ *end = it;
+
+ do {
+ v->visit(it->element);
+ it = it->next;
+ } while (it != end);
+}
+
+#endif // VISITOR_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/qtdocparser.cpp b/qtdocparser.cpp
new file mode 100644
index 000000000..0651d5fd5
--- /dev/null
+++ b/qtdocparser.cpp
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "qtdocparser.h"
+#include "reporthandler.h"
+#include <QtXmlPatterns/QXmlQuery>
+#include <QUrl>
+
+Documentation QtDocParser::retrieveModuleDocumentation()
+{
+ // TODO: This method of acquiring the module name supposes that the target language uses
+ // dots as module separators in package names. Improve this.
+ QString moduleName = QString(packageName()).remove(0, packageName().lastIndexOf('.') + 1);
+ QString sourceFile = documentationDataDirectory() + '/' + moduleName.toLower() + ".xml";
+
+ if (!QFile::exists(sourceFile)) {
+ ReportHandler::warning("Can't find qdoc3 file for module "
+ + packageName() + ", tried: "
+ + sourceFile);
+ return Documentation();
+ }
+
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(sourceFile));
+
+ // Module documentation
+ QString query = "/WebXML/document/page[@name=\"" + moduleName + "\"]/description";
+ return Documentation(getDocumentation(xquery, query, DocModificationList()));
+}
+
+void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ QString sourceFile = documentationDataDirectory() + '/' + metaClass->name().toLower() + ".xml";
+ if (metaClass->enclosingClass())
+ sourceFile.replace("::", "-");
+
+ if (!QFile::exists(sourceFile)) {
+ ReportHandler::warning("Can't find qdoc3 file for class "
+ + metaClass->name() + ", tried: "
+ + sourceFile);
+ return;
+ }
+
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(sourceFile));
+
+ QString className = metaClass->name();
+ QString nameType = metaClass->enclosingClass() ? "fullname" : "name";
+
+ // Class/Namespace documentation
+ QString type = metaClass->isNamespace() ? QLatin1String("namespace") : QLatin1String("class");
+ QString query = "/WebXML/document/" + type + "[@" + nameType + "=\"" + className + "\"]/description";
+
+ DocModificationList signedModifs, classModifs;
+ foreach (DocModification docModif, metaClass->typeEntry()->docModifications()) {
+ if (docModif.signature().isEmpty())
+ classModifs.append(docModif);
+ else
+ signedModifs.append(docModif);
+ }
+
+ Documentation doc(getDocumentation(xquery, query, classModifs));
+ metaClass->setDocumentation(doc);
+
+
+ //Functions Documentation
+ AbstractMetaFunctionList funcs = metaClass->functionsInTargetLang();
+ foreach (AbstractMetaFunction *func, funcs) {
+ if (!func || func->isPrivate())
+ continue;
+
+ QString query = "/WebXML/document/" + type + "[@" + nameType + "=\"" + className + "\"]";
+ // properties
+ if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) {
+ query += "/property[@name=\"" + func->propertySpec()->name() + "\"]";
+ } else { // normal methods
+ QString isConst = func->isConstant() ? "true" : "false";
+ query += "/function[@name=\"" + func->originalName()
+ + "\" and count(parameter)="
+ + QString::number(func->arguments().count())
+ + " and @const=\"" + isConst + "\"]";
+
+ int i = 1;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ QString type = arg->type()->name();
+ /* XXX Hack to get arguments working inside namespaces types */
+ type = type.split("::").last();
+
+ if (arg->type()->isConstant())
+ type.prepend("const ");
+
+ if (arg->type()->isReference()) {
+ type += " &";
+ } if (arg->type()->indirections()) {
+ type += ' ';
+ for (int j = 0, max = arg->type()->indirections(); j < max; ++j)
+ type += '*';
+ }
+ query += "/parameter[" + QString::number(i) + "][@left=\"" + type + "\"]/..";
+ ++i;
+ }
+ }
+ query += "/description";
+ DocModificationList funcModifs;
+ foreach (DocModification funcModif, signedModifs) {
+ if (funcModif.signature() == func->minimalSignature())
+ funcModifs.append(funcModif);
+ }
+ doc.setValue(getDocumentation(xquery, query, funcModifs));
+ func->setDocumentation(doc);
+ }
+#if 0
+ // Fields
+ AbstractMetaFieldList fields = metaClass->fields();
+ foreach (AbstractMetaField *field, fields) {
+ if (field->isPrivate())
+ return;
+
+ QString query = "/doxygen/compounddef/sectiondef/memberdef/name[text()=\"" + field->name() + "\"]/..";
+ Documentation doc = getDocumentation(DocModificationList(), xquery, query);
+ field->setDocumentation(doc);
+ }
+#endif
+ // Enums
+ AbstractMetaEnumList enums = metaClass->enums();
+ foreach (AbstractMetaEnum *meta_enum, enums) {
+ QString query = "/WebXML/document/" + type + "[@" + nameType + "=\""
+ + className + "\"]/enum[@name=\""
+ + meta_enum->name() + "\"]/description";
+ doc.setValue(getDocumentation(xquery, query, DocModificationList()));
+ meta_enum->setDocumentation(doc);
+ }
+}
diff --git a/qtdocparser.h b/qtdocparser.h
new file mode 100644
index 000000000..e4b7089d7
--- /dev/null
+++ b/qtdocparser.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef QTDOCPARSER_H
+#define QTDOCPARSER_H
+
+#include "docparser.h"
+
+class QtDocParser : public DocParser
+{
+public:
+ QtDocParser() {}
+ virtual void fillDocumentation(AbstractMetaClass* metaClass);
+ virtual Documentation retrieveModuleDocumentation();
+};
+
+#endif // QTDOCPARSER_H
+
diff --git a/reporthandler.cpp b/reporthandler.cpp
new file mode 100644
index 000000000..c03100815
--- /dev/null
+++ b/reporthandler.cpp
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "reporthandler.h"
+#include "typesystem.h"
+#include <cstring>
+
+#ifndef NOCOLOR
+#define COLOR_END "\033[0m"
+#define COLOR_WHITE "\033[1;37m"
+#define COLOR_YELLOW "\033[1;33m"
+#define COLOR_GREEN "\033[0;32m"
+#else
+#define COLOR_END ""
+#define COLOR_WHITE ""
+#define COLOR_YELLOW ""
+#define COLOR_GREEN ""
+#endif
+
+
+bool ReportHandler::m_silent = false;
+int ReportHandler::m_warningCount = 0;
+int ReportHandler::m_suppressedCount = 0;
+QString ReportHandler::m_context;
+ReportHandler::DebugLevel ReportHandler::m_debugLevel = NoDebug;
+QSet<QString> ReportHandler::m_reportedWarnings;
+char ReportHandler::m_progressBuffer[1024] = {0};
+ProgressAnimation ReportHandler::m_anim;
+
+
+void ReportHandler::warning(const QString &text)
+{
+ if (m_silent)
+ return;
+
+// Context is useless!
+// QString warningText = QString("\r" COLOR_YELLOW "WARNING(%1)" COLOR_END " :: %2").arg(m_context).arg(text);
+ QString warningText = QString("\033[1K\r" COLOR_YELLOW "WARNING" COLOR_END " :: %2").arg(text);
+
+ TypeDatabase *db = TypeDatabase::instance();
+ if (db && db->isSuppressedWarning(text)) {
+ ++m_suppressedCount;
+ } else if (!m_reportedWarnings.contains(text)) {
+ puts(qPrintable(warningText));
+ printProgress();
+ ++m_warningCount;
+
+ m_reportedWarnings.insert(text);
+ }
+}
+
+void ReportHandler::progress(const QString& str, ...)
+{
+ if (m_silent)
+ return;
+ QString msg = QString("\033[1K\r" COLOR_WHITE "%1 (%2/%3) " COLOR_END).arg(m_anim.toString()).arg(m_anim.current()).arg(m_anim.max()) + str;
+ va_list argp;
+ va_start(argp, str);
+ vsnprintf(m_progressBuffer, sizeof(m_progressBuffer), msg.toLocal8Bit().constData(), argp);
+ va_end(argp);
+ printProgress();
+}
+
+void ReportHandler::printProgress()
+{
+ printf(m_progressBuffer);
+ fflush(stdout);
+}
+
+
+void ReportHandler::debug(DebugLevel level, const QString &text)
+{
+ if (m_debugLevel == NoDebug)
+ return;
+
+ if (level <= m_debugLevel) {
+ printf("\r" COLOR_GREEN "DEBUG" COLOR_END " :: %-70s\n", qPrintable(text));
+ printProgress();
+ }
+}
diff --git a/reporthandler.h b/reporthandler.h
new file mode 100644
index 000000000..e13d3562f
--- /dev/null
+++ b/reporthandler.h
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef REPORTHANDLER_H
+#define REPORTHANDLER_H
+
+#include <QtCore/QString>
+#include <QtCore/QSet>
+#include <cstring>
+
+class ProgressAnimation
+{
+public:
+ ProgressAnimation()
+ {
+ anim_data = "|/-\\";
+ anim_frame = anim_data;
+ std::strcpy(anim_string, "[ ]");
+ m_current = m_max = 0;
+ }
+ const char* toString()
+ {
+ step();
+ return anim_string;
+ }
+ template<typename T>
+ void setCollection(T collection)
+ {
+ m_current = 1;
+ m_max = collection.count();
+ }
+
+ int current() const
+ {
+ return m_current;
+ }
+ int max() const
+ {
+ return m_max;
+ }
+
+private:
+ const char* anim_data;
+ char anim_string[4];
+ const char* anim_frame;
+ int m_max;
+ int m_current;
+
+ void step()
+ {
+ if (!*(++anim_frame))
+ anim_frame = anim_data;
+ anim_string[1] = *anim_frame;
+ m_current++;
+ }
+};
+
+class ReportHandler
+{
+public:
+ enum DebugLevel { NoDebug, SparseDebug, MediumDebug, FullDebug };
+
+ static void setContext(const QString &context)
+ {
+ m_context = context;
+ }
+
+ static DebugLevel debugLevel()
+ {
+ return m_debugLevel;
+ }
+ static void setDebugLevel(DebugLevel level)
+ {
+ m_debugLevel = level;
+ }
+
+ static int warningCount()
+ {
+ return m_warningCount;
+ }
+
+ static int suppressedCount()
+ {
+ return m_suppressedCount;
+ }
+
+ static void warning(const QString &str);
+
+ template <typename T>
+ static void setProgressReference(T collection)
+ {
+ m_anim.setCollection(collection);
+ }
+
+ static void progress(const QString &str, ...);
+
+ static void debugSparse(const QString &str)
+ {
+ debug(SparseDebug, str);
+ }
+ static void debugMedium(const QString &str)
+ {
+ debug(MediumDebug, str);
+ }
+ static void debugFull(const QString &str)
+ {
+ debug(FullDebug, str);
+ }
+ static void debug(DebugLevel level, const QString &str);
+
+ static bool isSilent()
+ {
+ return m_silent;
+ }
+ static void setSilent(bool silent)
+ {
+ m_silent = silent;
+ }
+
+private:
+ static bool m_silent;
+ static int m_warningCount;
+ static int m_suppressedCount;
+ static DebugLevel m_debugLevel;
+ static QString m_context;
+ static QSet<QString> m_reportedWarnings;
+
+ static ProgressAnimation m_anim;
+ static char m_progressBuffer[1024];
+
+ static void printProgress();
+};
+
+#endif // REPORTHANDLER_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 000000000..8517a28a9
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+qt4_automoc(testabstractmetaclass.cpp)
+add_executable(testabstractmetaclass testabstractmetaclass.cpp)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${apiextractor_SOURCE_DIR})
+target_link_libraries(testabstractmetaclass ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} apiextractor)
+add_test("AbstractMetaClass" testabstractmetaclass)
diff --git a/tests/testabstractmetaclass.cpp b/tests/testabstractmetaclass.cpp
new file mode 100644
index 000000000..d7eb77ca2
--- /dev/null
+++ b/tests/testabstractmetaclass.cpp
@@ -0,0 +1,86 @@
+/*
+* This file is part of the API Extractor project.
+*
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+*
+* Contact: PySide team <contact@pyside.org>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#include "testabstractmetaclass.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include <QBuffer>
+
+
+TestAbstractMetaClass::TestAbstractMetaClass() : m_builder(0)
+{
+}
+
+void TestAbstractMetaClass::init()
+{
+ m_builder = new AbstractMetaBuilder;
+}
+
+void TestAbstractMetaClass::cleanup()
+{
+ delete m_builder;
+ m_builder = 0;
+}
+
+void TestAbstractMetaClass::processCode (const char* cppCode, const char* xmlCode )
+{
+ QBuffer buffer;
+ // parse typesystem
+ buffer.setData(xmlCode);
+ TypeDatabase::instance()->parseFile(&buffer);
+ buffer.close();
+ // parse C++ code
+ buffer.setData(cppCode);
+ m_builder->build(&buffer);
+}
+
+void TestAbstractMetaClass::testClassName()
+{
+ const char* cppCode ="class ClassName {};";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"ClassName\"/></typesystem>";
+ processCode(cppCode, xmlCode);
+ AbstractMetaClassList classes = m_builder->classes();
+ QCOMPARE(classes.count(), 1);
+ QCOMPARE(classes[0]->name(), QString("ClassName"));
+}
+
+void TestAbstractMetaClass::testClassNameUnderNamespace()
+{
+ const char* cppCode ="namespace Namespace { class ClassName {}; }";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\"> \
+ <namespace-type name=\"Namespace\"/> \
+ <value-type name=\"Namespace::ClassName\"/> \
+ </typesystem>";
+ processCode(cppCode, xmlCode);
+ AbstractMetaClassList classes = m_builder->classes();
+ QCOMPARE(classes.count(), 2); // 1 namespace + 1 class
+ QCOMPARE(classes[0]->name(), QString("ClassName"));
+ QCOMPARE(classes[0]->qualifiedCppName(), QString("Namespace::ClassName"));
+ QCOMPARE(classes[1]->name(), QString("Namespace"));
+}
+
+
+QTEST_APPLESS_MAIN(TestAbstractMetaClass)
+
+#include "testabstractmetaclass.moc"
diff --git a/tests/testabstractmetaclass.h b/tests/testabstractmetaclass.h
new file mode 100644
index 000000000..a15061bbe
--- /dev/null
+++ b/tests/testabstractmetaclass.h
@@ -0,0 +1,47 @@
+/*
+* This file is part of the API Extractor project.
+*
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+*
+* Contact: PySide team <contact@pyside.org>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestAbstractMetaClass : public QObject
+{
+ Q_OBJECT
+public:
+ TestAbstractMetaClass();
+private slots:
+ void init();
+ void cleanup();
+ void testClassName();
+ void testClassNameUnderNamespace();
+private:
+ AbstractMetaBuilder* m_builder;
+
+ void processCode(const char* cppCode, const char* xmlCode);
+};
+
+#endif // TESTABSTRACTMETACLASS_H
diff --git a/typeparser.cpp b/typeparser.cpp
new file mode 100644
index 000000000..7c82a282f
--- /dev/null
+++ b/typeparser.cpp
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "typeparser.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+
+class Scanner
+{
+public:
+ enum Token {
+ StarToken,
+ AmpersandToken,
+ LessThanToken,
+ ColonToken,
+ CommaToken,
+ OpenParenToken,
+ CloseParenToken,
+ SquareBegin,
+ SquareEnd,
+ GreaterThanToken,
+
+ ConstToken,
+ Identifier,
+ NoToken
+ };
+
+ Scanner(const QString &s)
+ : m_pos(0), m_length(s.length()), m_chars(s.constData())
+ {
+ }
+
+ Token nextToken();
+ QString identifier() const;
+
+private:
+ int m_pos;
+ int m_length;
+ int m_tokenStart;
+ const QChar *m_chars;
+};
+
+QString Scanner::identifier() const
+{
+ return QString(m_chars + m_tokenStart, m_pos - m_tokenStart);
+}
+
+Scanner::Token Scanner::nextToken()
+{
+ Token tok = NoToken;
+
+ // remove whitespace
+ while (m_pos < m_length && m_chars[m_pos] == ' ')
+ ++m_pos;
+
+ m_tokenStart = m_pos;
+
+ while (m_pos < m_length) {
+
+ const QChar &c = m_chars[m_pos];
+
+ if (tok == NoToken) {
+ switch (c.toLatin1()) {
+ case '*': tok = StarToken; break;
+ case '&': tok = AmpersandToken; break;
+ case '<': tok = LessThanToken; break;
+ case '>': tok = GreaterThanToken; break;
+ case ',': tok = CommaToken; break;
+ case '(': tok = OpenParenToken; break;
+ case ')': tok = CloseParenToken; break;
+ case '[': tok = SquareBegin; break;
+ case ']' : tok = SquareEnd; break;
+ case ':':
+ tok = ColonToken;
+ Q_ASSERT(m_pos + 1 < m_length);
+ ++m_pos;
+ break;
+ default:
+ if (c.isLetterOrNumber() || c == '_')
+ tok = Identifier;
+ else
+ qFatal("Unrecognized character in lexer: %c", c.toLatin1());
+ break;
+ }
+ }
+
+ if (tok <= GreaterThanToken) {
+ ++m_pos;
+ break;
+ }
+
+ if (tok == Identifier) {
+ if (c.isLetterOrNumber() || c == '_')
+ ++m_pos;
+ else
+ break;
+ }
+ }
+
+ if (tok == Identifier && m_pos - m_tokenStart == 5) {
+ if (m_chars[m_tokenStart] == 'c'
+ && m_chars[m_tokenStart + 1] == 'o'
+ && m_chars[m_tokenStart + 2] == 'n'
+ && m_chars[m_tokenStart + 3] == 's'
+ && m_chars[m_tokenStart + 4] == 't')
+ tok = ConstToken;
+ }
+
+ return tok;
+
+}
+
+TypeParser::Info TypeParser::parse(const QString &str)
+{
+ Scanner scanner(str);
+
+ Info info;
+ QStack<Info *> stack;
+ stack.push(&info);
+
+ bool colon_prefix = false;
+ bool in_array = false;
+ QString array;
+
+ Scanner::Token tok = scanner.nextToken();
+ while (tok != Scanner::NoToken) {
+
+// switch (tok) {
+// case Scanner::StarToken: printf(" - *\n"); break;
+// case Scanner::AmpersandToken: printf(" - &\n"); break;
+// case Scanner::LessThanToken: printf(" - <\n"); break;
+// case Scanner::GreaterThanToken: printf(" - >\n"); break;
+// case Scanner::ColonToken: printf(" - ::\n"); break;
+// case Scanner::CommaToken: printf(" - ,\n"); break;
+// case Scanner::ConstToken: printf(" - const\n"); break;
+// case Scanner::SquareBegin: printf(" - [\n"); break;
+// case Scanner::SquareEnd: printf(" - ]\n"); break;
+// case Scanner::Identifier: printf(" - '%s'\n", qPrintable(scanner.identifier())); break;
+// default:
+// break;
+// }
+
+ switch (tok) {
+
+ case Scanner::StarToken:
+ ++stack.top()->indirections;
+ break;
+
+ case Scanner::AmpersandToken:
+ stack.top()->is_reference = true;
+ break;
+
+ case Scanner::LessThanToken:
+ stack.top()->template_instantiations << Info();
+ stack.push(&stack.top()->template_instantiations.last());
+ break;
+
+ case Scanner::CommaToken:
+ stack.pop();
+ stack.top()->template_instantiations << Info();
+ stack.push(&stack.top()->template_instantiations.last());
+ break;
+
+ case Scanner::GreaterThanToken:
+ stack.pop();
+ break;
+
+ case Scanner::ColonToken:
+ colon_prefix = true;
+ break;
+
+ case Scanner::ConstToken:
+ stack.top()->is_constant = true;
+ break;
+
+ case Scanner::OpenParenToken: // function pointers not supported
+ case Scanner::CloseParenToken: {
+ Info i;
+ i.is_busted = true;
+ return i;
+ }
+
+
+ case Scanner::Identifier:
+ if (in_array) {
+ array = scanner.identifier();
+ } else if (colon_prefix || stack.top()->qualified_name.isEmpty()) {
+ stack.top()->qualified_name << scanner.identifier();
+ colon_prefix = false;
+ } else {
+ stack.top()->qualified_name.last().append(" " + scanner.identifier());
+ }
+ break;
+
+ case Scanner::SquareBegin:
+ in_array = true;
+ break;
+
+ case Scanner::SquareEnd:
+ in_array = false;
+ stack.top()->arrays += array;
+ break;
+
+
+ default:
+ break;
+ }
+
+ tok = scanner.nextToken();
+ }
+
+ return info;
+}
+
+QString TypeParser::Info::instantiationName() const
+{
+ QString s(qualified_name.join("::"));
+ if (!template_instantiations.isEmpty()) {
+ QStringList insts;
+ foreach (Info info, template_instantiations)
+ insts << info.toString();
+ s += QString("< %1 >").arg(insts.join(", "));
+ }
+
+ return s;
+}
+
+QString TypeParser::Info::toString() const
+{
+ QString s;
+
+ if (is_constant) s += "const ";
+ s += instantiationName();
+ for (int i = 0; i < arrays.size(); ++i)
+ s += "[" + arrays.at(i) + "]";
+ s += QString(indirections, '*');
+ if (is_reference) s += '&';
+
+ return s;
+}
diff --git a/typeparser.h b/typeparser.h
new file mode 100644
index 000000000..1d0c019db
--- /dev/null
+++ b/typeparser.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TYPEPARSER_H
+#define TYPEPARSER_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+class TypeParser
+{
+public:
+ struct Info
+ {
+ Info() : is_reference(false), is_constant(false), is_busted(false), indirections(0) { }
+ QStringList qualified_name;
+ QStringList arrays;
+ QList<Info> template_instantiations;
+ uint is_reference : 1;
+ uint is_constant : 1;
+ uint is_busted : 1;
+ uint indirections : 5;
+
+ QString toString() const;
+ QString instantiationName() const;
+ };
+
+ static Info parse(const QString &str);
+};
+
+#endif // TYPEPARSER_H
diff --git a/typesystem.cpp b/typesystem.cpp
new file mode 100644
index 000000000..2a17d703b
--- /dev/null
+++ b/typesystem.cpp
@@ -0,0 +1,2085 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "typesystem.h"
+#include "generator.h"
+
+#include <reporthandler.h>
+
+#include <Qt/QtXml>
+
+QString strings_Object = QLatin1String("Object");
+QString strings_String = QLatin1String("String");
+QString strings_Thread = QLatin1String("Thread");
+QString strings_char = QLatin1String("char");
+QString stringsJavaLang = QLatin1String("java.lang");
+QString strings_jchar = QLatin1String("jchar");
+QString strings_jobject = QLatin1String("jobject");
+
+class StackElement
+{
+public:
+ enum ElementType {
+ None = 0x0,
+
+ // Type tags (0x1, ... , 0xff)
+ ObjectTypeEntry = 0x1,
+ ValueTypeEntry = 0x2,
+ InterfaceTypeEntry = 0x3,
+ NamespaceTypeEntry = 0x4,
+ ComplexTypeEntryMask = 0x7,
+
+ // Non-complex type tags (0x8, 0x9, ... , 0xf)
+ PrimitiveTypeEntry = 0x8,
+ EnumTypeEntry = 0x9,
+ ContainerTypeEntry = 0xa,
+ TypeEntryMask = 0xf,
+
+ // Documentation tags
+ InjectDocumentation = 0x10,
+ ModifyDocumentation = 0x20,
+ DocumentationMask = 0xf0,
+
+ // Simple tags (0x100, 0x200, ... , 0xf00)
+ ExtraIncludes = 0x100,
+ Include = 0x200,
+ ModifyFunction = 0x300,
+ ModifyField = 0x400,
+ Root = 0x500,
+ CustomMetaConstructor = 0x600,
+ CustomMetaDestructor = 0x700,
+ ArgumentMap = 0x800,
+ SuppressedWarning = 0x900,
+ Rejection = 0xa00,
+ LoadTypesystem = 0xb00,
+ RejectEnumValue = 0xc00,
+ Template = 0xd00,
+ TemplateInstanceEnum = 0xe00,
+ Replace = 0xf00,
+ SimpleMask = 0xf00,
+
+ // Code snip tags (0x1000, 0x2000, ... , 0xf000)
+ InjectCode = 0x1000,
+ InjectCodeInFunction = 0x2000,
+ CodeSnipMask = 0xf000,
+
+ // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
+ Access = 0x010000,
+ Removal = 0x020000,
+ Rename = 0x040000,
+ ModifyArgument = 0x080000,
+ Thread = 0x100000,
+ FunctionModifiers = 0xff0000,
+
+ // Argument modifier tags (0x01000000 ... 0xf0000000)
+ ConversionRule = 0x01000000,
+ ReplaceType = 0x02000000,
+ ReplaceDefaultExpression = 0x04000000,
+ RemoveArgument = 0x08000000,
+ DefineOwnership = 0x10000000,
+ RemoveDefaultExpression = 0x20000000,
+ NoNullPointers = 0x40000000,
+#if 0
+ ReferenceCount = 0x80000000,
+#endif
+ ParentOwner = 0x80000000,
+ ArgumentModifiers = 0xff000000
+ };
+
+ StackElement(StackElement *p) : entry(0), type(None), parent(p) { }
+
+ TypeEntry *entry;
+ ElementType type;
+ StackElement *parent;
+
+ union {
+ TemplateInstance *templateInstance;
+ TemplateEntry *templateEntry;
+ CustomFunction *customFunction;
+ } value;
+};
+
+class Handler : public QXmlDefaultHandler
+{
+public:
+ Handler(TypeDatabase *database, bool generate)
+ : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+ {
+ m_currentEnum = 0;
+ current = 0;
+
+ tagNames["rejection"] = StackElement::Rejection;
+ tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
+ tagNames["container-type"] = StackElement::ContainerTypeEntry;
+ tagNames["object-type"] = StackElement::ObjectTypeEntry;
+ tagNames["value-type"] = StackElement::ValueTypeEntry;
+ tagNames["interface-type"] = StackElement::InterfaceTypeEntry;
+ tagNames["namespace-type"] = StackElement::NamespaceTypeEntry;
+ tagNames["enum-type"] = StackElement::EnumTypeEntry;
+ tagNames["extra-includes"] = StackElement::ExtraIncludes;
+ tagNames["include"] = StackElement::Include;
+ tagNames["inject-code"] = StackElement::InjectCode;
+ tagNames["modify-function"] = StackElement::ModifyFunction;
+ tagNames["modify-field"] = StackElement::ModifyField;
+ tagNames["access"] = StackElement::Access;
+ tagNames["remove"] = StackElement::Removal;
+ tagNames["rename"] = StackElement::Rename;
+ tagNames["typesystem"] = StackElement::Root;
+ tagNames["custom-constructor"] = StackElement::CustomMetaConstructor;
+ tagNames["custom-destructor"] = StackElement::CustomMetaDestructor;
+ tagNames["argument-map"] = StackElement::ArgumentMap;
+ tagNames["suppress-warning"] = StackElement::SuppressedWarning;
+ tagNames["load-typesystem"] = StackElement::LoadTypesystem;
+ tagNames["define-ownership"] = StackElement::DefineOwnership;
+ tagNames["replace-default-expression"] = StackElement::ReplaceDefaultExpression;
+ tagNames["reject-enum-value"] = StackElement::RejectEnumValue;
+ tagNames["replace-type"] = StackElement::ReplaceType;
+ tagNames["conversion-rule"] = StackElement::ConversionRule;
+ tagNames["modify-argument"] = StackElement::ModifyArgument;
+ tagNames["remove-argument"] = StackElement::RemoveArgument;
+ tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression;
+ tagNames["template"] = StackElement::Template;
+ tagNames["insert-template"] = StackElement::TemplateInstanceEnum;
+ tagNames["replace"] = StackElement::Replace;
+ tagNames["no-null-pointer"] = StackElement::NoNullPointers;
+#if 0
+ tagNames["reference-count"] = StackElement::ReferenceCount;
+#endif
+ tagNames["parent"] = StackElement::ParentOwner;
+ tagNames["inject-documentation"] = StackElement::InjectDocumentation;
+ tagNames["modify-documentation"] = StackElement::ModifyDocumentation;
+ }
+
+ bool startElement(const QString &namespaceURI, const QString &localName,
+ const QString &qName, const QXmlAttributes &atts);
+ bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+
+ QString errorString() const
+ {
+ return m_error;
+ }
+ bool error(const QXmlParseException &exception);
+ bool fatalError(const QXmlParseException &exception);
+ bool warning(const QXmlParseException &exception);
+
+ bool characters(const QString &ch);
+
+private:
+ void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
+ QHash<QString, QString> *acceptedAttributes);
+
+ bool importFileElement(const QXmlAttributes &atts);
+ bool convertBoolean(const QString &, const QString &, bool);
+
+ TypeDatabase *m_database;
+ StackElement* current;
+ QString m_defaultPackage;
+ QString m_defaultSuperclass;
+ QString m_error;
+ TypeEntry::CodeGeneration m_generate;
+
+ EnumTypeEntry *m_currentEnum;
+
+ CodeSnipList m_codeSnips;
+ FunctionModificationList m_functionMods;
+ FieldModificationList m_fieldMods;
+ DocModificationList m_docModifications;
+
+ QHash<QString, StackElement::ElementType> tagNames;
+ QString m_currentSignature;
+};
+
+bool Handler::error(const QXmlParseException &e)
+{
+ qWarning("Error: line=%d, column=%d, message=%s\n",
+ e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+ return false;
+}
+
+bool Handler::fatalError(const QXmlParseException &e)
+{
+ qWarning("Fatal error: line=%d, column=%d, message=%s\n",
+ e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+
+ return false;
+}
+
+bool Handler::warning(const QXmlParseException &e)
+{
+ qWarning("Warning: line=%d, column=%d, message=%s\n",
+ e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+
+ return false;
+}
+
+void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
+ QHash<QString, QString> *acceptedAttributes)
+{
+ Q_ASSERT(acceptedAttributes);
+
+ for (int i = 0; i < atts.length(); ++i) {
+ QString key = atts.localName(i).toLower();
+ QString val = atts.value(i);
+
+ if (!acceptedAttributes->contains(key))
+ ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key));
+ else
+ (*acceptedAttributes)[key] = val;
+
+ }
+}
+
+bool Handler::endElement(const QString &, const QString &localName, const QString &)
+{
+ QString tagName = localName.toLower();
+ if (tagName == "import-file")
+ return true;
+
+ if (!current)
+ return true;
+
+ switch (current->type) {
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::NamespaceTypeEntry: {
+ ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(current->entry);
+ centry->setFunctionModifications(m_functionMods);
+ centry->setFieldModifications(m_fieldMods);
+ centry->setCodeSnips(m_codeSnips);
+ centry->setDocModification(m_docModifications);
+
+ if (centry->designatedInterface()) {
+ centry->designatedInterface()->setCodeSnips(m_codeSnips);
+ centry->designatedInterface()->setFunctionModifications(m_functionMods);
+ }
+ m_codeSnips = CodeSnipList();
+ m_functionMods = FunctionModificationList();
+ m_fieldMods = FieldModificationList();
+ m_docModifications = DocModificationList();
+ }
+ break;
+ case StackElement::CustomMetaConstructor: {
+ current->entry->setCustomConstructor(*current->value.customFunction);
+ delete current->value.customFunction;
+ }
+ break;
+ case StackElement::CustomMetaDestructor: {
+ current->entry->setCustomDestructor(*current->value.customFunction);
+ delete current->value.customFunction;
+ }
+ break;
+ case StackElement::EnumTypeEntry:
+ current->entry->setDocModification(m_docModifications);
+ m_docModifications = DocModificationList();
+ m_currentEnum = 0;
+ break;
+ case StackElement::Template:
+ m_database->addTemplate(current->value.templateEntry);
+ break;
+ case StackElement::TemplateInstanceEnum:
+ if (current->parent->type == StackElement::InjectCode)
+ m_codeSnips.last().addTemplateInstance(current->value.templateInstance);
+ else if (current->parent->type == StackElement::Template)
+ current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance);
+ else if (current->parent->type == StackElement::CustomMetaConstructor
+ || current->parent->type == StackElement::CustomMetaConstructor)
+ current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance);
+ else if (current->parent->type == StackElement::ConversionRule)
+ m_functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance);
+ else if (current->parent->type == StackElement::InjectCodeInFunction)
+ m_functionMods.last().snips.last().addTemplateInstance(current->value.templateInstance);
+
+ break;
+ default:
+ break;
+ }
+
+ StackElement *child = current;
+ current = current->parent;
+ delete(child);
+
+ return true;
+}
+
+bool Handler::characters(const QString &ch)
+{
+ if (current->type == StackElement::Template) {
+ current->value.templateEntry->addCode(ch);
+ return true;
+ }
+
+ if (current->type == StackElement::CustomMetaConstructor || current->type == StackElement::CustomMetaDestructor) {
+ current->value.customFunction->addCode(ch);
+ return true;
+ }
+
+ if (current->type == StackElement::ConversionRule
+ && current->parent->type == StackElement::ModifyArgument) {
+ m_functionMods.last().argument_mods.last().conversion_rules.last().addCode(ch);
+ return true;
+ }
+
+ if (current->parent) {
+ if ((current->type & StackElement::CodeSnipMask)) {
+ switch (current->parent->type) {
+ case StackElement::Root:
+ ((TypeSystemTypeEntry *) current->parent->entry)->codeSnips().last().addCode(ch);
+ break;
+ case StackElement::ModifyFunction:
+ m_functionMods.last().snips.last().addCode(ch);
+ m_functionMods.last().modifiers |= FunctionModification::CodeInjection;
+ break;
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ m_codeSnips.last().addCode(ch);
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+ return true;
+ }
+ }
+
+ if (current->type & StackElement::DocumentationMask)
+ m_docModifications.last().setCode(ch);
+
+ return true;
+}
+
+bool Handler::importFileElement(const QXmlAttributes &atts)
+{
+ QString fileName = atts.value("name");
+ if (fileName.isEmpty()) {
+ m_error = "Required attribute 'name' missing for include-file tag.";
+ return false;
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ file.setFileName(":/trolltech/generator/" + fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_error = QString("Could not open file: '%1'").arg(fileName);
+ return false;
+ }
+ }
+
+ QString quoteFrom = atts.value("quote-after-line");
+ bool foundFromOk = quoteFrom.isEmpty();
+ bool from = quoteFrom.isEmpty();
+
+ QString quoteTo = atts.value("quote-before-line");
+ bool foundToOk = quoteTo.isEmpty();
+ bool to = true;
+
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ if (from && to && line.contains(quoteTo)) {
+ to = false;
+ foundToOk = true;
+ break;
+ }
+ if (from && to)
+ characters(line + "\n");
+ if (!from && line.contains(quoteFrom)) {
+ from = true;
+ foundFromOk = true;
+ }
+ }
+ if (!foundFromOk || !foundToOk) {
+ QString fromError = QString("Could not find quote-after-line='%1' in file '%2'.").arg(quoteFrom).arg(fileName);
+ QString toError = QString("Could not find quote-before-line='%1' in file '%2'.").arg(quoteTo).arg(fileName);
+
+ if (!foundToOk)
+ m_error = toError;
+ if (!foundFromOk)
+ m_error = fromError;
+ if (!foundFromOk && !foundToOk)
+ m_error = fromError + " " + toError;
+ return false;
+ }
+
+ return true;
+}
+
+bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue)
+{
+ QString value = _value.toLower();
+ if (value == "true" || value == "yes")
+ return true;
+ else if (value == "false" || value == "no")
+ return false;
+ else {
+ QString warn = QString("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
+ .arg(value).arg(attributeName).arg(defaultValue ? "yes" : "no");
+
+ ReportHandler::warning(warn);
+ return defaultValue;
+ }
+}
+
+bool Handler::startElement(const QString &, const QString &n,
+ const QString &, const QXmlAttributes &atts)
+{
+ QString tagName = n.toLower();
+ if (tagName == "import-file")
+ return importFileElement(atts);
+
+
+ StackElement *element = new StackElement(current);
+
+ if (!tagNames.contains(tagName)) {
+ m_error = QString("Unknown tag name: '%1'").arg(tagName);
+ return false;
+ }
+
+ element->type = tagNames[tagName];
+ if (element->type & StackElement::TypeEntryMask) {
+ if (current->type != StackElement::Root) {
+ m_error = "Nested types not supported";
+ return false;
+ }
+
+ QHash<QString, QString> attributes;
+ attributes["name"] = QString();
+
+ switch (element->type) {
+ case StackElement::PrimitiveTypeEntry:
+ attributes["target-lang-name"] = QString();
+ attributes["target-lang-api-name"] = QString();
+ attributes["preferred-conversion"] = "yes";
+ attributes["preferred-target-lang-type"] = "yes";
+ break;
+ case StackElement::ContainerTypeEntry:
+ attributes["type"] = QString();
+ break;
+ case StackElement::EnumTypeEntry:
+ attributes["flags"] = "no";
+ attributes["upper-bound"] = QString();
+ attributes["lower-bound"] = QString();
+ attributes["force-integer"] = "no";
+ attributes["extensible"] = "no";
+
+ break;
+
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ attributes["force-abstract"] = QString("no");
+ attributes["deprecated"] = QString("no");
+ attributes["hash-function"] = QString("");
+ // fall throooough
+ case StackElement::InterfaceTypeEntry:
+ attributes["default-superclass"] = m_defaultSuperclass;
+ attributes["polymorphic-id-expression"] = QString();
+ attributes["delete-in-main-thread"] = QString("no");
+ attributes["held-type"] = QString();
+ attributes["copyable"] = QString();
+ // fall through
+ case StackElement::NamespaceTypeEntry:
+ attributes["target-lang-name"] = QString();
+ attributes["package"] = m_defaultPackage;
+ attributes["expense-cost"] = "1";
+ attributes["expense-limit"] = "none";
+ attributes["polymorphic-base"] = QString("no");
+ attributes["generate"] = QString("yes");
+ attributes["target-type"] = QString();
+ attributes["generic-class"] = QString("no");
+ break;
+ default:
+ { } // nada
+ };
+
+ fetchAttributeValues(tagName, atts, &attributes);
+
+ QString name = attributes["name"];
+
+ // We need to be able to have duplicate primitive type entries,
+ // or it's not possible to cover all primitive target language
+ // types (which we need to do in order to support fake meta objects)
+ if (element->type != StackElement::PrimitiveTypeEntry) {
+ TypeEntry *tmp = m_database->findType(name);
+ if (tmp)
+ ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name));
+ }
+
+ if (name.isEmpty()) {
+ m_error = "no 'name' attribute specified";
+ return false;
+ }
+ switch (element->type) {
+ case StackElement::PrimitiveTypeEntry: {
+ QString targetLangName = attributes["target-lang-name"];
+ QString targetLangApiName = attributes["target-lang-api-name"];
+ QString preferredConversion = attributes["preferred-conversion"].toLower();
+ QString preferredTargetLangType = attributes["preferred-target-lang-type"].toLower();
+
+ if (targetLangName.isEmpty())
+ targetLangName = name;
+ if (targetLangApiName.isEmpty())
+ targetLangApiName = name;
+
+ PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name);
+ type->setCodeGeneration(m_generate);
+ type->setTargetLangName(targetLangName);
+ type->setTargetLangApiName(targetLangApiName);
+
+ bool preferred;
+ preferred = convertBoolean(preferredConversion, "preferred-conversion", true);
+ type->setPreferredConversion(preferred);
+ preferred = convertBoolean(preferredTargetLangType,
+ "preferred-target-lang-type", true);
+ type->setPreferredTargetLangType(preferred);
+
+ element->entry = type;
+ }
+ break;
+ case StackElement::ContainerTypeEntry:
+ {
+ QString typeName = attributes["type"];
+ ContainerTypeEntry::Type containerType =
+ ContainerTypeEntry::containerTypeFromString(typeName);
+ if (typeName.isEmpty()) {
+ m_error = "no 'type' attribute specified";
+ return false;
+ } else if (containerType == ContainerTypeEntry::NoContainer) {
+ m_error = "there is no container of type " + containerType;
+ return false;
+ }
+
+ ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType);
+ type->setCodeGeneration(m_generate);
+ element->entry = type;
+ }
+ break;
+ case StackElement::EnumTypeEntry: {
+ QStringList names = name.split(QLatin1String("::"));
+
+ if (names.size() == 1)
+ m_currentEnum = new EnumTypeEntry(QString(), name);
+ else
+ m_currentEnum =
+ new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join("::"),
+ names.last());
+ element->entry = m_currentEnum;
+ m_currentEnum->setCodeGeneration(m_generate);
+ m_currentEnum->setTargetLangPackage(m_defaultPackage);
+ m_currentEnum->setUpperBound(attributes["upper-bound"]);
+ m_currentEnum->setLowerBound(attributes["lower-bound"]);
+ m_currentEnum->setForceInteger(convertBoolean(attributes["force-integer"], "force-integer", false));
+ m_currentEnum->setExtensible(convertBoolean(attributes["extensible"], "extensible", false));
+
+ // put in the flags parallel...
+ if (!attributes["flags"].isEmpty() && attributes["flags"].toLower() != "no") {
+ FlagsTypeEntry *ftype = new FlagsTypeEntry("QFlags<" + name + ">");
+ ftype->setOriginator(m_currentEnum);
+ ftype->setOriginalName(attributes["flags"]);
+ ftype->setCodeGeneration(m_generate);
+ QString n = ftype->originalName();
+
+ QStringList lst = n.split("::");
+ if (QStringList(lst.mid(0, lst.size() - 1)).join("::") != m_currentEnum->targetLangQualifier()) {
+ ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
+ .arg(m_currentEnum->targetLangQualifier())
+ .arg(lst.at(0)));
+ }
+
+ ftype->setFlagsName(lst.last());
+ m_currentEnum->setFlags(ftype);
+
+ m_database->addFlagsType(ftype);
+ m_database->addType(ftype);
+ }
+ }
+ break;
+
+ case StackElement::InterfaceTypeEntry: {
+ ObjectTypeEntry *otype = new ObjectTypeEntry(name);
+ QString targetLangName = attributes["target-lang-name"];
+ if (targetLangName.isEmpty())
+ targetLangName = name;
+ InterfaceTypeEntry *itype =
+ new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName));
+
+ if (!convertBoolean(attributes["generate"], "generate", true))
+ itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+ else
+ itype->setCodeGeneration(m_generate);
+ otype->setDesignatedInterface(itype);
+ itype->setOrigin(otype);
+ element->entry = otype;
+ }
+ // fall through
+ case StackElement::NamespaceTypeEntry:
+ if (!element->entry)
+ element->entry = new NamespaceTypeEntry(name);
+
+ // fall through
+ case StackElement::ObjectTypeEntry:
+ if (!element->entry)
+ element->entry = new ObjectTypeEntry(name);
+
+ // fall through
+ case StackElement::ValueTypeEntry: {
+ if (!element->entry)
+ element->entry = new ValueTypeEntry(name);
+
+
+ ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+ ctype->setTargetLangPackage(attributes["package"]);
+ ctype->setDefaultSuperclass(attributes["default-superclass"]);
+ ctype->setGenericClass(convertBoolean(attributes["generic-class"], "generic-class", false));
+
+ if (!convertBoolean(attributes["generate"], "generate", true))
+ element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
+ else
+ element->entry->setCodeGeneration(m_generate);
+
+ QString targetLangName = attributes["target-lang-name"];
+ if (!targetLangName.isEmpty())
+ ctype->setTargetLangName(targetLangName);
+
+ // The expense policy
+ QString limit = attributes["expense-limit"];
+ if (!limit.isEmpty() && limit != "none") {
+ ExpensePolicy ep;
+ ep.limit = limit.toInt();
+ ep.cost = attributes["expense-cost"];
+ ctype->setExpensePolicy(ep);
+ }
+
+
+ ctype->setIsPolymorphicBase(convertBoolean(attributes["polymorphic-base"], "polymorphic-base", false));
+ ctype->setPolymorphicIdValue(attributes["polymorphic-id-expression"]);
+ //Copyable
+ if (attributes["copyable"].isEmpty())
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ else {
+ if (convertBoolean(attributes["copyable"], "copyable", false))
+ ctype->setCopyable(ComplexTypeEntry::CopyableSet);
+ else
+ ctype->setCopyable(ComplexTypeEntry::NonCopyableSet);
+
+ }
+
+ if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry)
+ ctype->setHashFunction(attributes["hash-function"]);
+
+
+ ctype->setHeldType(attributes["held-type"]);
+
+ if (element->type == StackElement::ObjectTypeEntry
+ || element->type == StackElement::ValueTypeEntry) {
+ if (convertBoolean(attributes["force-abstract"], "force-abstract", false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
+ if (convertBoolean(attributes["deprecated"], "deprecated", false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ }
+
+ if (element->type == StackElement::InterfaceTypeEntry
+ || element->type == StackElement::ValueTypeEntry
+ || element->type == StackElement::ObjectTypeEntry) {
+ if (convertBoolean(attributes["delete-in-main-thread"], "delete-in-main-thread", false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
+ }
+
+ QString targetType = attributes["target-type"];
+ if (!targetType.isEmpty() && element->entry->isComplex())
+ static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
+
+ // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
+ ctype = ctype->designatedInterface();
+ if (ctype)
+ ctype->setTargetLangPackage(attributes["package"]);
+
+ }
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+
+ if (element->entry)
+ m_database->addType(element->entry);
+ else
+ ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name));
+
+ } else if (element->type == StackElement::InjectDocumentation) {
+ // check the XML tag attributes
+ QHash<QString, QString> attributes;
+ attributes["mode"] = "replace";
+ attributes["format"] = "native";
+
+ fetchAttributeValues(tagName, atts, &attributes);
+
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (current->parent && current->parent->type & validParent) {
+ QString modeName = attributes["mode"];
+ DocModification::Mode mode;
+ if (modeName == "append") {
+ mode = DocModification::Append;
+ } else if (modeName == "prepend") {
+ mode = DocModification::Prepend;
+ } else if (modeName == "replace") {
+ mode = DocModification::Replace;
+ } else {
+ m_error = "Unknow documentation injection mode: " + modeName;
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames["target"] = TypeSystem::TargetLangCode;
+ languageNames["native"] = TypeSystem::NativeCode;
+ }
+
+ QString format = attributes["format"].toLower();
+ TypeSystem::Language lang = languageNames.value(format, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QString("unsupported class attribute: '%1'").arg(format);
+ return false;
+ }
+
+ QString signature = current->type & StackElement::TypeEntryMask ? QString() : m_currentSignature;
+ DocModification mod(mode, signature);
+ mod.format = lang;
+ m_docModifications << mod;
+ } else {
+ m_error = "inject-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type";
+ return false;
+ }
+ } else if (element->type == StackElement::ModifyDocumentation) {
+ // check the XML tag attributes
+ QHash<QString, QString> attributes;
+ attributes["xpath"] = QString();
+ fetchAttributeValues(tagName, atts, &attributes);
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (current->parent && current->parent->type & validParent)
+ m_docModifications << DocModification(attributes["xpath"], m_currentSignature);
+ else {
+ m_error = "modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type";
+ return false;
+ }
+ } else if (element->type != StackElement::None) {
+ bool topLevel = element->type == StackElement::Root
+ || element->type == StackElement::SuppressedWarning
+ || element->type == StackElement::Rejection
+ || element->type == StackElement::LoadTypesystem
+ || element->type == StackElement::InjectCode
+ || element->type == StackElement::ConversionRule
+ || element->type == StackElement::Template;
+
+ if (!topLevel && current->type == StackElement::Root) {
+ m_error = QString("Tag requires parent: '%1'").arg(tagName);
+ return false;
+ }
+
+ StackElement topElement = !current ? StackElement(0) : *current;
+ element->entry = topElement.entry;
+
+ QHash<QString, QString> attributes;
+ switch (element->type) {
+ case StackElement::Root:
+ attributes["package"] = QString();
+ attributes["default-superclass"] = QString();
+ break;
+ case StackElement::LoadTypesystem:
+ attributes["name"] = QString();
+ attributes["generate"] = "yes";
+ break;
+ case StackElement::NoNullPointers:
+ attributes["default-value"] = QString();
+ break;
+ case StackElement::SuppressedWarning:
+ attributes["text"] = QString();
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ attributes["with"] = QString();
+ break;
+ case StackElement::DefineOwnership:
+ attributes["class"] = "target";
+ attributes["owner"] = "";
+ break;
+ case StackElement::ModifyFunction:
+ attributes["signature"] = QString();
+ attributes["access"] = QString();
+ attributes["remove"] = QString();
+ attributes["rename"] = QString();
+ attributes["deprecated"] = QString("no");
+ attributes["associated-to"] = QString();
+ attributes["virtual-slot"] = QString("no");
+ attributes["thread"] = QString("no");
+ attributes["allow-thread"] = QString("no");
+ break;
+ case StackElement::ModifyArgument:
+ attributes["index"] = QString();
+ attributes["replace-value"] = QString();
+ attributes["invalidate-after-use"] = QString("no");
+ break;
+ case StackElement::ModifyField:
+ attributes["name"] = QString();
+ attributes["write"] = "true";
+ attributes["read"] = "true";
+ break;
+ case StackElement::Access:
+ attributes["modifier"] = QString();
+ break;
+ case StackElement::Include:
+ attributes["file-name"] = QString();
+ attributes["location"] = QString();
+ break;
+ case StackElement::CustomMetaConstructor:
+ attributes["name"] = topElement.entry->name().toLower() + "_create";
+ attributes["param-name"] = "copy";
+ break;
+ case StackElement::CustomMetaDestructor:
+ attributes["name"] = topElement.entry->name().toLower() + "_delete";
+ attributes["param-name"] = "copy";
+ break;
+ case StackElement::ReplaceType:
+ attributes["modified-type"] = QString();
+ break;
+ case StackElement::InjectCode:
+ attributes["class"] = "target";
+ attributes["position"] = "beginning";
+ attributes["file"] = QString();
+ break;
+ case StackElement::ConversionRule:
+ attributes["class"] = "";
+ attributes["file"] = "";
+ break;
+ case StackElement::RejectEnumValue:
+ attributes["name"] = "";
+ break;
+ case StackElement::ArgumentMap:
+ attributes["index"] = "1";
+ attributes["meta-name"] = QString();
+ break;
+ case StackElement::Rename:
+ attributes["to"] = QString();
+ break;
+ case StackElement::Rejection:
+ attributes["class"] = "*";
+ attributes["function-name"] = "*";
+ attributes["field-name"] = "*";
+ attributes["enum-name"] = "*";
+ break;
+ case StackElement::Removal:
+ attributes["class"] = "all";
+ break;
+ case StackElement::Template:
+ attributes["name"] = QString();
+ break;
+ case StackElement::TemplateInstanceEnum:
+ attributes["name"] = QString();
+ break;
+ case StackElement::Replace:
+ attributes["from"] = QString();
+ attributes["to"] = QString();
+ break;
+#if 0
+ case StackElement::ReferenceCount:
+ attributes["action"] = QString();
+ break;
+#endif
+ case StackElement::ParentOwner:
+ attributes["index"] = QString();
+ attributes["action"] = QString();
+ default:
+ { } // nada
+ };
+
+ if (attributes.count() > 0)
+ fetchAttributeValues(tagName, atts, &attributes);
+
+ switch (element->type) {
+ case StackElement::Root:
+ m_defaultPackage = attributes["package"];
+ m_defaultSuperclass = attributes["default-superclass"];
+ element->type = StackElement::Root;
+ element->entry = new TypeSystemTypeEntry(m_defaultPackage);
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && m_defaultPackage != "")
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+
+ if (!element->entry->qualifiedCppName().isEmpty())
+ m_database->addType(element->entry);
+ break;
+ case StackElement::LoadTypesystem: {
+ QString name = attributes["name"];
+ if (name.isEmpty()) {
+ m_error = "No typesystem name specified";
+ return false;
+ }
+
+ if (!m_database->parseFile(name, convertBoolean(attributes["generate"], "generate", true))) {
+ m_error = QString("Failed to parse: '%1'").arg(name);
+ return false;
+ }
+ }
+ break;
+ case StackElement::RejectEnumValue: {
+ if (!m_currentEnum) {
+ m_error = "<reject-enum-value> node must be used inside a <enum-type> node";
+ return false;
+ }
+ QString name = attributes["name"];
+
+ bool added = false;
+ if (!name.isEmpty()) {
+ added = true;
+ m_currentEnum->addEnumValueRejection(name);
+ }
+
+ } break;
+ case StackElement::ReplaceType: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "Type replacement can only be specified for argument modifications";
+ return false;
+ }
+
+ if (attributes["modified-type"].isEmpty()) {
+ m_error = "Type replacement requires 'modified-type' attribute";
+ return false;
+ }
+
+ m_functionMods.last().argument_mods.last().modified_type = attributes["modified-type"];
+ }
+ break;
+ case StackElement::ConversionRule: {
+ if (topElement.type != StackElement::ModifyArgument
+ && topElement.type != StackElement::PrimitiveTypeEntry
+ && topElement.type != StackElement::ContainerTypeEntry) {
+ m_error = "Conversion rules can only be specified for argument modification"
+ " and to primitive or container types conversion.";
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyArgument) {
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames["target"] = TypeSystem::TargetLangCode;
+ languageNames["native"] = TypeSystem::NativeCode;
+ }
+
+ QString languageAttribute = attributes["class"].toLower();
+ TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QString("unsupported class attribute: '%1'").arg(lang);
+ return false;
+ }
+
+ CodeSnip snip;
+ snip.language = lang;
+ m_functionMods.last().argument_mods.last().conversion_rules.append(snip);
+ } else {
+ QString sourceFile = attributes["file"].toLower();
+ if (sourceFile.isEmpty()) {
+ m_error = QString("'file' attribute required; the source file containing the"
+ " containing the conversion functions must be provided");
+ return false;
+ }
+
+ //Handler constructor....
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+ if (QFile::exists(sourceFile)) {
+ QFile conversionSource(sourceFile);
+ if (conversionSource.open(QIODevice::ReadOnly)) {
+ CodeSnip snip;
+ snip.addCode(conversionSource.readAll());
+ topElement.entry->addCodeSnip(snip);
+ }
+ } else {
+ ReportHandler::warning("File containing conversion code for "
+ + topElement.entry->name()
+ + " type does not exist: "
+ + sourceFile);
+ }
+ }
+
+ }
+ }
+
+ break;
+ case StackElement::ModifyArgument: {
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = QString::fromLatin1("argument modification requires function"
+ " modification as parent, was %1")
+ .arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString index = attributes["index"];
+ if (index == "return")
+ index = "0";
+ else if (index == "this")
+ index = "-1";
+
+ bool ok = false;
+ int idx = index.toInt(&ok);
+ if (!ok) {
+ m_error = QString("Cannot convert '%1' to integer").arg(index);
+ return false;
+ }
+
+ QString replace_value = attributes["replace-value"];
+
+ if (!replace_value.isEmpty() && idx) {
+ m_error = QString("replace-value is only supported for return values (index=0).");
+ return false;
+ }
+
+ ArgumentModification argumentModification = ArgumentModification(idx);
+ argumentModification.replace_value = replace_value;
+ argumentModification.resetAfterUse = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false);
+ m_functionMods.last().argument_mods.append(argumentModification);
+ }
+ break;
+ case StackElement::NoNullPointers: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "no-null-pointer requires argument modification as parent";
+ return false;
+ }
+
+ m_functionMods.last().argument_mods.last().noNullPointers = true;
+ if (!m_functionMods.last().argument_mods.last().index)
+ m_functionMods.last().argument_mods.last().nullPointerDefaultValue = attributes["default-value"];
+ else if (!attributes["default-value"].isEmpty())
+ ReportHandler::warning("default values for null pointer guards are only effective for return values");
+
+ }
+ break;
+ case StackElement::DefineOwnership: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "define-ownership requires argument modification as parent";
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames["target"] = TypeSystem::TargetLangCode;
+ languageNames["shell"] = TypeSystem::ShellCode;
+ }
+
+ QString classAttribute = attributes["class"].toLower();
+ TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QString("unsupported class attribute: '%1'").arg(classAttribute);
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Ownership> ownershipNames;
+ if (ownershipNames.isEmpty()) {
+ ownershipNames["target"] = TypeSystem::TargetLangOwnership;
+ ownershipNames["c++"] = TypeSystem::CppOwnership;
+ ownershipNames["default"] = TypeSystem::DefaultOwnership;
+ }
+
+ QString ownershipAttribute = attributes["owner"].toLower();
+ TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
+ if (owner == TypeSystem::InvalidOwnership) {
+ m_error = QString("unsupported owner attribute: '%1'").arg(ownershipAttribute);
+ return false;
+ }
+
+ m_functionMods.last().argument_mods.last().ownerships[lang] = owner;
+ }
+ break;
+ case StackElement::SuppressedWarning:
+ if (attributes["text"].isEmpty())
+ ReportHandler::warning("Suppressed warning with no text specified");
+ else
+ m_database->addSuppressedWarning(attributes["text"]);
+ break;
+ case StackElement::ArgumentMap: {
+ if (!(topElement.type & StackElement::CodeSnipMask)) {
+ m_error = "Argument maps requires code injection as parent";
+ return false;
+ }
+
+ bool ok;
+ int pos = attributes["index"].toInt(&ok);
+ if (!ok) {
+ m_error = QString("Can't convert position '%1' to integer")
+ .arg(attributes["position"]);
+ return false;
+ }
+
+ if (pos <= 0) {
+ m_error = QString("Argument position %1 must be a positive number").arg(pos);
+ return false;
+ }
+
+ QString meta_name = attributes["meta-name"];
+ if (meta_name.isEmpty())
+ ReportHandler::warning("Empty meta name in argument map");
+
+
+ if (topElement.type == StackElement::InjectCodeInFunction)
+ m_functionMods.last().snips.last().argumentMap[pos] = meta_name;
+ else {
+ ReportHandler::warning("Argument maps are only useful for injection of code "
+ "into functions.");
+ }
+ }
+ break;
+ case StackElement::Removal: {
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = "Function modification parent required";
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames["target"] = TypeSystem::TargetLangAndNativeCode;
+ languageNames["all"] = TypeSystem::All;
+ }
+
+ QString languageAttribute = attributes["class"].toLower();
+ TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
+ return false;
+ }
+
+ m_functionMods.last().removal = lang;
+ }
+ break;
+ case StackElement::Rename:
+ case StackElement::Access: {
+ if (topElement.type != StackElement::ModifyField
+ && topElement.type != StackElement::ModifyFunction) {
+ m_error = "Function or field modification parent required";
+ return false;
+ }
+
+ Modification *mod = 0;
+ if (topElement.type == StackElement::ModifyFunction)
+ mod = &m_functionMods.last();
+ else
+ mod = &m_fieldMods.last();
+
+ QString modifier;
+ if (element->type == StackElement::Rename) {
+ modifier = "rename";
+ QString renamed_to = attributes["to"];
+ if (renamed_to.isEmpty()) {
+ m_error = "Rename modifier requires 'to' attribute";
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction)
+ mod->setRenamedTo(renamed_to);
+ else
+ mod->setRenamedTo(renamed_to);
+ } else
+ modifier = attributes["modifier"].toLower();
+
+
+ if (modifier.isEmpty()) {
+ m_error = "No access modification specified";
+ return false;
+ }
+
+ static QHash<QString, FunctionModification::Modifiers> modifierNames;
+ if (modifierNames.isEmpty()) {
+ modifierNames["private"] = Modification::Private;
+ modifierNames["public"] = Modification::Public;
+ modifierNames["protected"] = Modification::Protected;
+ modifierNames["friendly"] = Modification::Friendly;
+ modifierNames["rename"] = Modification::Rename;
+ modifierNames["final"] = Modification::Final;
+ modifierNames["non-final"] = Modification::NonFinal;
+ }
+
+ if (!modifierNames.contains(modifier)) {
+ m_error = QString("Unknown access modifier: '%1'").arg(modifier);
+ return false;
+ }
+
+ mod->modifiers |= modifierNames[modifier];
+ }
+ break;
+ case StackElement::RemoveArgument:
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "Removing argument requires argument modification as parent";
+ return false;
+ }
+
+ m_functionMods.last().argument_mods.last().removed = true;
+
+ break;
+
+ case StackElement::ModifyField: {
+ QString name = attributes["name"];
+ if (name.isEmpty())
+ break;
+ FieldModification fm;
+ fm.name = name;
+ fm.modifiers = 0;
+
+ QString read = attributes["read"];
+ QString write = attributes["write"];
+
+ if (read == "true") fm.modifiers |= FieldModification::Readable;
+ if (write == "true") fm.modifiers |= FieldModification::Writable;
+
+ m_fieldMods << fm;
+ }
+ break;
+ case StackElement::ModifyFunction: {
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString signature = attributes["signature"];
+
+ signature = QMetaObject::normalizedSignature(signature.toLocal8Bit().constData());
+ if (signature.isEmpty()) {
+ m_error = "No signature for modified function";
+ return false;
+ }
+
+ FunctionModification mod;
+ m_currentSignature = mod.signature = signature;
+
+ QString access = attributes["access"].toLower();
+ if (!access.isEmpty()) {
+ if (access == QLatin1String("private"))
+ mod.modifiers |= Modification::Private;
+ else if (access == QLatin1String("protected"))
+ mod.modifiers |= Modification::Protected;
+ else if (access == QLatin1String("public"))
+ mod.modifiers |= Modification::Public;
+ else if (access == QLatin1String("final"))
+ mod.modifiers |= Modification::Final;
+ else if (access == QLatin1String("non-final"))
+ mod.modifiers |= Modification::NonFinal;
+ else {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ }
+
+ if (convertBoolean(attributes["deprecated"], "deprecated", false))
+ mod.modifiers |= Modification::Deprecated;
+
+
+ QString remove = attributes["remove"].toLower();
+ if (!remove.isEmpty()) {
+ if (remove == QLatin1String("all"))
+ mod.removal = TypeSystem::All;
+ else if (remove == QLatin1String("target"))
+ mod.removal = TypeSystem::TargetLangAndNativeCode;
+ else {
+ m_error = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+ return false;
+ }
+ }
+
+ QString rename = attributes["rename"];
+ if (!rename.isEmpty()) {
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ }
+
+ QString association = attributes["associated-to"];
+ if (!association.isEmpty())
+ mod.association = association;
+
+ mod.setIsThread(convertBoolean(attributes["thread"], "thread", false));
+ mod.setAllowThread(convertBoolean(attributes["allow-thread"], "allow-thread", false));
+
+ mod.modifiers |= (convertBoolean(attributes["virtual-slot"], "virtual-slot", false) ? Modification::VirtualSlot : 0);
+
+ m_functionMods << mod;
+ }
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ if (!(topElement.type & StackElement::ModifyArgument)) {
+ m_error = "Replace default expression only allowed as child of argument modification";
+ return false;
+ }
+
+ if (attributes["with"].isEmpty()) {
+ m_error = "Default expression replaced with empty string. Use remove-default-expression instead.";
+ return false;
+ }
+
+ m_functionMods.last().argument_mods.last().replacedDefaultExpression = attributes["with"];
+ break;
+ case StackElement::RemoveDefaultExpression:
+ m_functionMods.last().argument_mods.last().removedDefaultExpression = true;
+ break;
+ case StackElement::CustomMetaConstructor:
+ case StackElement::CustomMetaDestructor: {
+ CustomFunction *func = new CustomFunction(attributes["name"]);
+ func->paramName = attributes["param-name"];
+ element->value.customFunction = func;
+ }
+ break;
+#if 0
+ case StackElement::ReferenceCount: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "reference-count must be child of modify-argument";
+ return false;
+ }
+
+ ReferenceCount rc;
+
+ static QHash<QString, ReferenceCount::Action> actions;
+ if (actions.isEmpty()) {
+ actions["add"] = ReferenceCount::Add;
+ actions["add-all"] = ReferenceCount::AddAll;
+ actions["remove"] = ReferenceCount::Remove;
+ actions["set"] = ReferenceCount::Set;
+ actions["ignore"] = ReferenceCount::Ignore;
+ }
+ rc.action = actions.value(attributes["action"].toLower(), ReferenceCount::Invalid);
+
+ if (rc.action == ReferenceCount::Invalid) {
+ m_error = "unrecognized value for action attribute. supported actions:";
+ foreach (QString action, actions.keys())
+ m_error += " " + action;
+ }
+
+ m_functionMods.last().argument_mods.last().referenceCounts.append(rc);
+ }
+ break;
+#endif
+
+ case StackElement::ParentOwner: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = "parent-policy must be child of modify-argument";
+ return false;
+ }
+
+ ArgumentOwner ao;
+
+ QString index = attributes["index"];
+ if (index == "return")
+ index = "0";
+ else if (index == "this")
+ index = "-1";
+
+ bool ok = false;
+ int idx = index.toInt(&ok);
+ if (!ok) {
+ m_error = QString("Cannot convert '%1' to integer").arg(index);
+ return false;
+ }
+
+ static QHash<QString, ArgumentOwner::Action> actions;
+ if (actions.isEmpty()) {
+ actions["add"] = ArgumentOwner::Add;
+ actions["remove"] = ArgumentOwner::Remove;
+ }
+
+ ao.action = actions.value(attributes["action"].toLower(), ArgumentOwner::Invalid);
+ if (!ao.action) {
+ m_error = QString("Invalid parent actionr");
+ return false;
+ }
+ ao.index = idx;
+ m_functionMods.last().argument_mods.last().owner = ao;
+ }
+ break;
+
+
+ case StackElement::InjectCode: {
+ if (((!topElement.type & StackElement::ComplexTypeEntryMask))
+ && (topElement.type != StackElement::ModifyFunction)
+ && (topElement.type != StackElement::Root)) {
+ m_error = "wrong parent type for code injection";
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames["target"] = TypeSystem::TargetLangCode; // em algum lugar do cpp
+ languageNames["native"] = TypeSystem::NativeCode; // em algum lugar do cpp
+ languageNames["shell"] = TypeSystem::ShellCode; // coloca no header, mas antes da declaracao da classe
+ languageNames["shell-declaration"] = TypeSystem::ShellDeclaration; // coloca no header, dentro da declaracao da classe
+ languageNames["library-initializer"] = TypeSystem::PackageInitializer;
+ languageNames["destructor-function"] = TypeSystem::DestructorFunction;
+ languageNames["constructors"] = TypeSystem::Constructors;
+ languageNames["interface"] = TypeSystem::Interface;
+ }
+
+ QString className = attributes["class"].toLower();
+ if (!languageNames.contains(className)) {
+ m_error = QString("Invalid class specifier: '%1'").arg(className);
+ return false;
+ }
+
+
+ static QHash<QString, CodeSnip::Position> positionNames;
+ if (positionNames.isEmpty()) {
+ positionNames["beginning"] = CodeSnip::Beginning;
+ positionNames["end"] = CodeSnip::End;
+ // QtScript
+ positionNames["declaration"] = CodeSnip::Declaration;
+ positionNames["prototype-initialization"] = CodeSnip::PrototypeInitialization;
+ positionNames["constructor-initialization"] = CodeSnip::ConstructorInitialization;
+ positionNames["constructor"] = CodeSnip::Constructor;
+ }
+
+ QString position = attributes["position"].toLower();
+ if (!positionNames.contains(position)) {
+ m_error = QString("Invalid position: '%1'").arg(position);
+ return false;
+ }
+
+ CodeSnip snip;
+ snip.language = languageNames[className];
+ snip.position = positionNames[position];
+ bool in_file = false;
+
+ QString file_name = attributes["file"];
+
+ //Handler constructor....
+ if (m_generate != TypeEntry::GenerateForSubclass &&
+ m_generate != TypeEntry::GenerateNothing &&
+ !file_name.isEmpty()) {
+ if (QFile::exists(file_name)) {
+ QFile code_file(file_name);
+ if (code_file.open(QIODevice::ReadOnly)) {
+ QString content;
+ content = code_file.readAll();
+ content.prepend("// ========================================================================\n"
+ "// START of custom code block [file: " + file_name + "]\n");
+ content.append("\n// END of custom code block [file: " + file_name + "]\n"
+ "// ========================================================================\n");
+ snip.addCode(content);
+ in_file = true;
+ }
+ } else
+ ReportHandler::warning("File for inject code not exist: " + file_name);
+
+ }
+
+ if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
+ m_error = "Interface code injections must be direct child of an interface type entry";
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction) {
+ FunctionModification mod = m_functionMods.last();
+ if (snip.language == TypeSystem::ShellDeclaration) {
+ m_error = "no function implementation in shell declaration in which to inject code";
+ return false;
+ }
+
+ m_functionMods.last().snips << snip;
+ if (in_file)
+ m_functionMods.last().modifiers |= FunctionModification::CodeInjection;
+ element->type = StackElement::InjectCodeInFunction;
+
+ } else if (topElement.type == StackElement::Root) {
+ ((TypeSystemTypeEntry *) element->entry)->addCodeSnip(snip);
+
+ } else if (topElement.type != StackElement::Root)
+ m_codeSnips << snip;
+
+ }
+ break;
+ case StackElement::Include: {
+ QString location = attributes["location"].toLower();
+
+ static QHash<QString, Include::IncludeType> locationNames;
+ if (locationNames.isEmpty()) {
+ locationNames["global"] = Include::IncludePath;
+ locationNames["local"] = Include::LocalPath;
+ locationNames["target"] = Include::TargetLangImport;
+ }
+
+ if (!locationNames.contains(location)) {
+ m_error = QString("Location not recognized: '%1'").arg(location);
+ return false;
+ }
+
+ Include::IncludeType loc = locationNames[location];
+ Include inc(loc, attributes["file-name"]);
+
+ ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+ if (topElement.type & StackElement::ComplexTypeEntryMask)
+ ctype->setInclude(inc);
+ else if (topElement.type == StackElement::ExtraIncludes)
+ ctype->addExtraInclude(inc);
+ else {
+ m_error = "Only supported parents are complex types and extra-includes";
+ return false;
+ }
+
+ inc = ctype->include();
+ IncludeList lst = ctype->extraIncludes();
+ ctype = ctype->designatedInterface();
+ if (ctype) {
+ ctype->setExtraIncludes(lst);
+ ctype->setInclude(inc);
+ }
+ }
+ break;
+ case StackElement::Rejection: {
+ QString cls = attributes["class"];
+ QString function = attributes["function-name"];
+ QString field = attributes["field-name"];
+ QString enum_ = attributes["enum-name"];
+ if (cls == "*" && function == "*" && field == "*" && enum_ == "*") {
+ m_error = "bad reject entry, neither 'class', 'function-name' nor "
+ "'field' specified";
+ return false;
+ }
+ m_database->addRejection(cls, function, field, enum_);
+ }
+ break;
+ case StackElement::Template:
+ element->value.templateEntry = new TemplateEntry(attributes["name"]);
+ break;
+ case StackElement::TemplateInstanceEnum:
+ if (!(topElement.type & StackElement::CodeSnipMask) &&
+ (topElement.type != StackElement::Template) &&
+ (topElement.type != StackElement::CustomMetaConstructor) &&
+ (topElement.type != StackElement::CustomMetaDestructor) &&
+ (topElement.type != StackElement::ConversionRule)) {
+ m_error = "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule.";
+ return false;
+ }
+ element->value.templateInstance = new TemplateInstance(attributes["name"]);
+ break;
+ case StackElement::Replace:
+ if (topElement.type != StackElement::TemplateInstanceEnum) {
+ m_error = "Can only insert replace rules into insert-template.";
+ return false;
+ }
+ element->parent->value.templateInstance->addReplaceRule(attributes["from"], attributes["to"]);
+ break;
+ default:
+ break; // nada
+ };
+ }
+
+ current = element;
+ return true;
+}
+
+TypeDatabase *TypeDatabase::instance()
+{
+ static TypeDatabase *db = new TypeDatabase();
+ return db;
+}
+
+TypeDatabase::TypeDatabase() : m_suppressWarnings(true)
+{
+ StringTypeEntry* e = new StringTypeEntry("QXmlStreamStringRef");
+ e->setPreferredConversion(false);
+ addType(e);
+
+ addType(new VoidTypeEntry());
+}
+
+QString TypeDatabase::modifiedTypesystemFilepath(const QString &ts_file)
+{
+ if (!QFile::exists(ts_file)) {
+ foreach (const QString &path, m_typesystemPaths) {
+ QString filepath(path + '/' + ts_file);
+ if (QFile::exists(filepath))
+ return filepath;
+ }
+ }
+ return ts_file;
+}
+
+bool TypeDatabase::parseFile(const QString &filename, bool generate)
+{
+ QString filepath;
+ if (filename[0] != '/')
+ filepath = modifiedTypesystemFilepath(filename);
+ else
+ filepath = filename;
+
+ if (m_parsedTypesystemFiles.contains(filepath))
+ return m_parsedTypesystemFiles[filepath];
+
+ QFile file(filepath);
+ Q_ASSERT_X(file.exists(), __FUNCTION__, ("Can't find " + filename).toLocal8Bit().data());
+
+ int count = m_entries.size();
+ bool ok = parseFile(&file, generate);
+ m_parsedTypesystemFiles[filepath] = ok;
+ int newCount = m_entries.size();
+
+ ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries")
+ .arg(filename)
+ .arg(newCount - count));
+ return ok;
+}
+
+bool TypeDatabase::parseFile(QIODevice* device, bool generate)
+{
+ QXmlInputSource source(device);
+ QXmlSimpleReader reader;
+ Handler handler(this, generate);
+
+ reader.setContentHandler(&handler);
+ reader.setErrorHandler(&handler);
+
+ return reader.parse(&source, false);
+}
+
+QString PrimitiveTypeEntry::javaObjectName() const
+{
+ static QHash<QString, QString> table;
+ if (table.isEmpty()) {
+ table["boolean"] = "Boolean";
+ table["byte"] = "Byte";
+ table["char"] = "Character";
+ table["short"] = "Short";
+ table["int"] = "Integer";
+ table["long"] = "Long";
+ table["float"] = "Float";
+ table["double"] = "Double";
+ }
+ Q_ASSERT(table.contains(targetLangName()));
+ return table[targetLangName()];
+}
+
+PrimitiveTypeEntry* PrimitiveTypeEntry::basicAliasedTypeEntry() const
+{
+ if (!m_aliasedTypeEntry)
+ return 0;
+
+ PrimitiveTypeEntry* baseAliasTypeEntry = m_aliasedTypeEntry->basicAliasedTypeEntry();
+ if (baseAliasTypeEntry)
+ return baseAliasTypeEntry;
+ else
+ return m_aliasedTypeEntry;
+}
+
+ContainerTypeEntry *TypeDatabase::findContainerType(const QString &name)
+{
+ QString template_name = name;
+
+ int pos = name.indexOf('<');
+ if (pos > 0)
+ template_name = name.left(pos);
+
+ TypeEntry *type_entry = findType(template_name);
+ if (type_entry && type_entry->isContainer())
+ return static_cast<ContainerTypeEntry *>(type_entry);
+ return 0;
+}
+
+PrimitiveTypeEntry *TypeDatabase::findTargetLangPrimitiveType(const QString &targetLangName)
+{
+ foreach (QList<TypeEntry *> entries, m_entries.values()) {
+ foreach (TypeEntry *e, entries) {
+ if (e && e->isPrimitive()) {
+ PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(e);
+ if (pe->targetLangName() == targetLangName && pe->preferredConversion())
+ return pe;
+ }
+ }
+ }
+
+ return 0;
+}
+
+IncludeList TypeDatabase::extraIncludes(const QString &className)
+{
+ ComplexTypeEntry *typeEntry = findComplexType(className);
+ if (typeEntry)
+ return typeEntry->extraIncludes();
+ else
+ return IncludeList();
+}
+
+
+
+QString Include::toString() const
+{
+ if (type == IncludePath)
+ return "#include <" + name + '>';
+ else if (type == LocalPath)
+ return "#include \"" + name + "\"";
+ else
+ return "import " + name + ";";
+}
+
+QString Modification::accessModifierString() const
+{
+ if (isPrivate()) return "private";
+ if (isProtected()) return "protected";
+ if (isPublic()) return "public";
+ if (isFriendly()) return "friendly";
+ return QString();
+}
+
+FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
+{
+ FunctionModificationList lst;
+ for (int i = 0; i < m_functionMods.count(); ++i) {
+ const FunctionModification &mod = m_functionMods.at(i);
+ if (mod.signature == signature)
+ lst << mod;
+
+ }
+
+ return lst;
+}
+
+FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
+{
+ for (int i = 0; i < m_fieldMods.size(); ++i)
+ if (m_fieldMods.at(i).name == name)
+ return m_fieldMods.at(i);
+ FieldModification mod;
+ mod.name = name;
+ mod.modifiers = FieldModification::Readable | FieldModification::Writable;
+ return mod;
+}
+
+QString ContainerTypeEntry::targetLangPackage() const
+{
+ if (m_type == PairContainer)
+ return "com.trolltech.qt";
+ return "java.util";
+}
+
+QString ContainerTypeEntry::targetLangName() const
+{
+
+ switch (m_type) {
+ case StringListContainer: return "QStringList";
+ case ListContainer: return "QList";
+ case LinkedListContainer: return "LinkedList";
+ case VectorContainer: return "QVector";
+ case StackContainer: return "QStack";
+ case QueueContainer: return "QQueue";
+ case SetContainer: return "QSet";
+ case MapContainer: return "QMap";
+ case MultiMapContainer: return "QMultiMap";
+ case HashContainer: return "QHashMap";
+ //case MultiHashCollectio: return "MultiHash";
+ case PairContainer: return "QPair";
+ default:
+ qWarning("bad type... %d", m_type);
+ break;
+ }
+ return QString();
+}
+
+QString ContainerTypeEntry::qualifiedCppName() const
+{
+ if (m_type == StringListContainer)
+ return "QStringList";
+ return ComplexTypeEntry::qualifiedCppName();
+}
+
+QString EnumTypeEntry::targetLangQualifier() const
+{
+ TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
+ if (te)
+ return te->targetLangName();
+ else
+ return m_qualifier;
+}
+
+QString EnumTypeEntry::targetLangApiName() const
+{
+ return "jint";
+}
+
+QString FlagsTypeEntry::targetLangApiName() const
+{
+ return "jint";
+}
+
+void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
+{
+ m_enumRedirections << EnumValueRedirection(rejected, usedValue);
+}
+
+QString EnumTypeEntry::enumValueRedirection(const QString &value) const
+{
+ for (int i = 0; i < m_enumRedirections.size(); ++i)
+ if (m_enumRedirections.at(i).rejected == value)
+ return m_enumRedirections.at(i).used;
+ return QString();
+}
+
+QString FlagsTypeEntry::qualifiedTargetLangName() const
+{
+ return targetLangPackage() + "." + m_enum->targetLangQualifier() + "." + targetLangName();
+}
+
+
+void TypeDatabase::addRejection(const QString &class_name, const QString &function_name,
+ const QString &field_name, const QString &enum_name)
+{
+ TypeRejection r;
+ r.class_name = class_name;
+ r.function_name = function_name;
+ r.field_name = field_name;
+ r.enum_name = enum_name;
+
+ m_rejections << r;
+}
+
+bool TypeDatabase::isClassRejected(const QString &class_name)
+{
+ if (!m_rebuildClasses.isEmpty())
+ return !m_rebuildClasses.contains(class_name);
+
+ foreach (const TypeRejection &r, m_rejections)
+ if (r.class_name == class_name && r.function_name == "*" && r.field_name == "*" && r.enum_name == "*")
+ return true;
+
+ return false;
+}
+
+bool TypeDatabase::isEnumRejected(const QString &class_name, const QString &enum_name)
+{
+ foreach (const TypeRejection &r, m_rejections) {
+ if (r.enum_name == enum_name
+ && (r.class_name == class_name || r.class_name == "*")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool TypeDatabase::isFunctionRejected(const QString &class_name, const QString &function_name)
+{
+ foreach (const TypeRejection &r, m_rejections)
+ if (r.function_name == function_name &&
+ (r.class_name == class_name || r.class_name == "*"))
+ return true;
+ return false;
+}
+
+
+bool TypeDatabase::isFieldRejected(const QString &class_name, const QString &field_name)
+{
+ foreach (const TypeRejection &r, m_rejections)
+ if (r.field_name == field_name &&
+ (r.class_name == class_name || r.class_name == "*"))
+ return true;
+ return false;
+}
+
+FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const
+{
+ FlagsTypeEntry *fte = (FlagsTypeEntry *) findType(name);
+ return fte ? fte : (FlagsTypeEntry *) m_flagsEntries.value(name);
+}
+
+QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/)
+{
+ return QLatin1String("Global");
+}
+
+
+/*!
+ * The Visual Studio 2002 compiler doesn't support these symbols,
+ * which our typedefs unforntuatly expand to.
+ */
+QString fixCppTypeName(const QString &name)
+{
+ if (name == "long long") return "qint64";
+ else if (name == "unsigned long long") return "quint64";
+ return name;
+}
+
+QString formattedCodeHelper(QTextStream &s, Indentor &indentor, QStringList &lines)
+{
+ bool multilineComment = false;
+ bool lastEmpty = true;
+ QString lastLine;
+ while (!lines.isEmpty()) {
+ const QString line = lines.takeFirst().trimmed();
+ if (line.isEmpty()) {
+ if (!lastEmpty)
+ s << endl;
+ lastEmpty = true;
+ continue;
+ } else
+ lastEmpty = false;
+
+ if (line.startsWith("/*"))
+ multilineComment = true;
+
+ if (multilineComment) {
+ s << indentor;
+ if (line.startsWith("*"))
+ s << " ";
+ s << line << endl;
+ if (line.endsWith("*/"))
+ multilineComment = false;
+ } else if (line.startsWith("}"))
+ return line;
+ else if (line.endsWith("")) {
+ s << indentor << line << endl;
+ return 0;
+ } else if (line.endsWith("{")) {
+ s << indentor << line << endl;
+ QString tmp;
+ {
+ Indentation indent(indentor);
+ tmp = formattedCodeHelper(s, indentor, lines);
+ }
+ if (!tmp.isNull())
+ s << indentor << tmp << endl;
+
+ lastLine = tmp;
+ continue;
+ } else {
+ s << indentor;
+ if (!lastLine.isEmpty() &&
+ !lastLine.endsWith(";") &&
+ !line.startsWith("@") &&
+ !line.startsWith("//") &&
+ !lastLine.startsWith("//") &&
+ !lastLine.endsWith("}") &&
+ !line.startsWith("{"))
+ s << " ";
+ s << line << endl;
+ }
+ lastLine = line;
+ }
+ return 0;
+}
+
+
+QTextStream &CodeSnip::formattedCode(QTextStream &s, Indentor &indentor) const
+{
+ QStringList lst(code().split("\n"));
+ while (!lst.isEmpty()) {
+ QString tmp = formattedCodeHelper(s, indentor, lst);
+ if (!tmp.isNull())
+ s << indentor << tmp << endl;
+
+ }
+ s.flush();
+ return s;
+}
+
+QString TemplateInstance::expandCode() const
+{
+ TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
+ if (templateEntry) {
+ QString res = templateEntry->code();
+ foreach (QString key, replaceRules.keys())
+ res.replace(key, replaceRules[key]);
+
+ return "// TEMPLATE - " + m_name + " - START" + res + "// TEMPLATE - " + m_name + " - END";
+ } else
+ ReportHandler::warning("insert-template referring to non-existing template '" + m_name + "'");
+
+ return QString();
+}
+
+
+QString CodeSnipAbstract::code() const
+{
+ QString res;
+ foreach (CodeSnipFragment *codeFrag, codeList)
+ res.append(codeFrag->code());
+
+ return res;
+}
+
+QString CodeSnipFragment::code() const
+{
+ if (m_instance)
+ return m_instance->expandCode();
+ else
+ return m_code;
+}
+
+QString FunctionModification::toString() const
+{
+ QString str = signature + QLatin1String("->");
+ if (modifiers & AccessModifierMask) {
+ switch (modifiers & AccessModifierMask) {
+ case Private: str += QLatin1String("private"); break;
+ case Protected: str += QLatin1String("protected"); break;
+ case Public: str += QLatin1String("public"); break;
+ case Friendly: str += QLatin1String("friendly"); break;
+ }
+ }
+
+ if (modifiers & Final) str += QLatin1String("final");
+ if (modifiers & NonFinal) str += QLatin1String("non-final");
+
+ if (modifiers & Readable) str += QLatin1String("readable");
+ if (modifiers & Writable) str += QLatin1String("writable");
+
+ if (modifiers & CodeInjection) {
+ foreach (CodeSnip s, snips) {
+ str += QLatin1String("\n//code injection:\n");
+ str += s.code();
+ }
+ }
+
+ if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName;
+
+ if (modifiers & Deprecated) str += QLatin1String("deprecate");
+
+ if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression");
+
+ return str;
+}
+
+/*
+static void injectCode(ComplexTypeEntry *e,
+ const char *signature,
+ const QByteArray &code,
+ const ArgumentMap &args)
+{
+ CodeSnip snip;
+ snip.language = TypeSystem::NativeCode;
+ snip.position = CodeSnip::Beginning;
+ snip.addCode(QString::fromLatin1(code));
+ snip.argumentMap = args;
+
+ FunctionModification mod;
+ mod.signature = QMetaObject::normalizedSignature(signature);
+ mod.snips << snip;
+ mod.modifiers = Modification::CodeInjection;
+ e->addFunctionModification(mod);
+}
+*/
+
diff --git a/typesystem.h b/typesystem.h
new file mode 100644
index 000000000..f03fd04ee
--- /dev/null
+++ b/typesystem.h
@@ -0,0 +1,1958 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TYPESYSTEM_H
+#define TYPESYSTEM_H
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QDebug>
+
+class Indentor;
+
+class AbstractMetaType;
+class QTextStream;
+
+class EnumTypeEntry;
+class FlagsTypeEntry;
+
+extern QString strings_Object;
+extern QString strings_String;
+extern QString strings_Thread;
+extern QString strings_char;
+extern QString stringsJavaLang;
+extern QString strings_jchar;
+extern QString strings_jobject;
+
+struct Include
+{
+ enum IncludeType {
+ IncludePath,
+ LocalPath,
+ TargetLangImport
+ };
+
+ Include() : type(IncludePath) {}
+ Include(IncludeType t, const QString &nam) : type(t), name(nam) {};
+
+ bool isValid()
+ {
+ return !name.isEmpty();
+ }
+
+ IncludeType type;
+ QString name;
+
+ QString toString() const;
+
+ bool operator<(const Include &other) const
+ {
+ return name < other.name;
+ }
+};
+typedef QList<Include> IncludeList;
+
+typedef QMap<int, QString> ArgumentMap;
+
+class TemplateInstance;
+
+namespace TypeSystem
+{
+enum Language {
+ NoLanguage = 0x0000,
+ TargetLangCode = 0x0001,
+ NativeCode = 0x0002,
+ ShellCode = 0x0004,
+ ShellDeclaration = 0x0008,
+ PackageInitializer = 0x0010,
+ DestructorFunction = 0x0020,
+ Constructors = 0x0040,
+ Interface = 0x0080,
+
+ // masks
+ All = TargetLangCode
+ | NativeCode
+ | ShellCode
+ | ShellDeclaration
+ | PackageInitializer
+ | Constructors
+ | Interface
+ | DestructorFunction,
+
+ TargetLangAndNativeCode = TargetLangCode | NativeCode
+};
+
+enum Ownership {
+ InvalidOwnership,
+ DefaultOwnership,
+ TargetLangOwnership,
+ CppOwnership
+};
+};
+
+struct ReferenceCount
+{
+ ReferenceCount() {}
+ enum Action { // 0x01 - 0xff
+ Invalid = 0x00,
+ Add = 0x01,
+ AddAll = 0x02,
+ Remove = 0x04,
+ Set = 0x08,
+ Ignore = 0x10,
+
+ ActionsMask = 0xff,
+
+ Padding = 0xffffffff
+ };
+
+ Action action;
+};
+
+struct ArgumentOwner
+{
+ enum Action {
+ Invalid = 0x00,
+ Add = 0x01,
+ Remove = 0x02
+ };
+ ArgumentOwner() : action(ArgumentOwner::Invalid), index(-2) {}
+
+ Action action;
+ int index;
+};
+
+class CodeSnipFragment
+{
+private:
+ const QString m_code;
+ TemplateInstance *m_instance;
+
+public:
+ CodeSnipFragment(const QString &code)
+ : m_code(code),
+ m_instance(0) {}
+
+ CodeSnipFragment(TemplateInstance *instance)
+ : m_instance(instance) {}
+
+ QString code() const;
+};
+
+class CodeSnipAbstract
+{
+public:
+ QString code() const;
+
+ void addCode(const QString &code)
+ {
+ codeList.append(new CodeSnipFragment(code));
+ }
+
+ void addTemplateInstance(TemplateInstance *ti)
+ {
+ codeList.append(new CodeSnipFragment(ti));
+ }
+
+ QList<CodeSnipFragment*> codeList;
+};
+
+class CustomFunction : public CodeSnipAbstract
+{
+public:
+ CustomFunction(const QString &n = QString()) : name(n) { }
+
+ QString name;
+ QString paramName;
+};
+
+class TemplateEntry : public CodeSnipAbstract
+{
+public:
+ TemplateEntry(const QString &name)
+ : m_name(name)
+ {
+ };
+
+ QString name() const
+ {
+ return m_name;
+ };
+
+private:
+ QString m_name;
+};
+
+typedef QHash<QString, TemplateEntry *> TemplateEntryHash;
+
+class TemplateInstance
+{
+public:
+ TemplateInstance(const QString &name)
+ : m_name(name) {}
+
+ void addReplaceRule(const QString &name, const QString &value)
+ {
+ replaceRules[name] = value;
+ }
+
+ QString expandCode() const;
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+private:
+ const QString m_name;
+ QHash<QString, QString> replaceRules;
+};
+
+
+class CodeSnip : public CodeSnipAbstract
+{
+public:
+ enum Position {
+ Beginning,
+ End,
+ AfterThis,
+ // QtScript
+ Declaration,
+ PrototypeInitialization,
+ ConstructorInitialization,
+ Constructor
+ };
+
+ CodeSnip() : language(TypeSystem::TargetLangCode) { }
+ CodeSnip(TypeSystem::Language lang) : language(lang) { }
+
+ // Very simple, easy to make code ugly if you try
+ QTextStream &formattedCode(QTextStream &s, Indentor &indentor) const;
+
+ TypeSystem::Language language;
+ Position position;
+ ArgumentMap argumentMap;
+};
+typedef QList<CodeSnip> CodeSnipList;
+
+struct ArgumentModification
+{
+ ArgumentModification(int idx)
+ : removedDefaultExpression(false), removed(false),
+ noNullPointers(false), index(idx) {}
+
+ // Should the default expression be removed?
+ uint removedDefaultExpression : 1;
+ uint removed : 1;
+ uint noNullPointers : 1;
+ uint resetAfterUse : 1;
+
+ // The index of this argument
+ int index;
+
+ // Reference count flags for this argument
+ QList<ReferenceCount> referenceCounts;
+
+ // The text given for the new type of the argument
+ QString modified_type;
+
+ QString replace_value;
+
+ // The code to be used to construct a return value when noNullPointers is true and
+ // the returned value is null. If noNullPointers is true and this string is
+ // empty, then the base class implementation will be used (or a default construction
+ // if there is no implementation)
+ QString nullPointerDefaultValue;
+
+ // The text of the new default expression of the argument
+ QString replacedDefaultExpression;
+
+ // The new definition of ownership for a specific argument
+ QHash<TypeSystem::Language, TypeSystem::Ownership> ownerships;
+
+ // Different conversion rules
+ CodeSnipList conversion_rules;
+
+ //QObject parent(owner) of this argument
+ ArgumentOwner owner;
+};
+
+struct Modification
+{
+ enum Modifiers {
+ Private = 0x0001,
+ Protected = 0x0002,
+ Public = 0x0003,
+ Friendly = 0x0004,
+ AccessModifierMask = 0x000f,
+
+ Final = 0x0010,
+ NonFinal = 0x0020,
+ FinalMask = Final | NonFinal,
+
+ Readable = 0x0100,
+ Writable = 0x0200,
+
+ CodeInjection = 0x1000,
+ Rename = 0x2000,
+ Deprecated = 0x4000,
+ ReplaceExpression = 0x8000,
+ VirtualSlot = 0x10000 | NonFinal
+ };
+
+ Modification() : modifiers(0) { }
+
+ bool isAccessModifier() const
+ {
+ return modifiers & AccessModifierMask;
+ }
+ Modifiers accessModifier() const
+ {
+ return Modifiers(modifiers & AccessModifierMask);
+ }
+ bool isPrivate() const
+ {
+ return accessModifier() == Private;
+ }
+ bool isProtected() const
+ {
+ return accessModifier() == Protected;
+ }
+ bool isPublic() const
+ {
+ return accessModifier() == Public;
+ }
+ bool isFriendly() const
+ {
+ return accessModifier() == Friendly;
+ }
+ bool isFinal() const
+ {
+ return modifiers & Final;
+ }
+ bool isNonFinal() const
+ {
+ return modifiers & NonFinal;
+ }
+ bool isVirtualSlot() const
+ {
+ return (modifiers & VirtualSlot) == VirtualSlot;
+ }
+ QString accessModifierString() const;
+
+ bool isDeprecated() const
+ {
+ return modifiers & Deprecated;
+ }
+
+ void setRenamedTo(const QString &name)
+ {
+ renamedToName = name;
+ }
+ QString renamedTo() const
+ {
+ return renamedToName;
+ }
+ bool isRenameModifier() const
+ {
+ return modifiers & Rename;
+ }
+
+ uint modifiers;
+ QString renamedToName;
+};
+
+struct FunctionModification: public Modification
+{
+ FunctionModification() : removal(TypeSystem::NoLanguage), m_thread(false), m_allowThread(false) {}
+
+ bool isCodeInjection() const
+ {
+ return modifiers & CodeInjection;
+ }
+ bool isRemoveModifier() const
+ {
+ return removal != TypeSystem::NoLanguage;
+ }
+ void setIsThread(bool flag)
+ {
+ m_thread = flag;
+ }
+ bool isThread() const
+ {
+ return m_thread;
+ }
+ bool allowThread() const
+ {
+ return m_allowThread;
+ }
+ void setAllowThread(bool allow)
+ {
+ m_allowThread = allow;
+ }
+
+ QString toString() const;
+
+ QString signature;
+ QString association;
+ CodeSnipList snips;
+ TypeSystem::Language removal;
+
+ QList<ArgumentModification> argument_mods;
+
+private:
+ bool m_thread;
+ bool m_allowThread;
+
+};
+typedef QList<FunctionModification> FunctionModificationList;
+
+struct FieldModification: public Modification
+{
+ bool isReadable() const
+ {
+ return modifiers & Readable;
+ }
+ bool isWritable() const
+ {
+ return modifiers & Writable;
+ }
+
+ QString name;
+};
+typedef QList<FieldModification> FieldModificationList;
+
+struct ExpensePolicy
+{
+ ExpensePolicy() : limit(-1) {}
+ int limit;
+ QString cost;
+ bool isValid() const
+ {
+ return limit >= 0;
+ }
+};
+
+class InterfaceTypeEntry;
+class ObjectTypeEntry;
+
+class DocModification
+{
+public:
+ enum Mode {
+ Append,
+ Prepend,
+ Replace,
+ XPathReplace
+ };
+
+ DocModification(const QString& xpath, const QString& signature)
+ : format(TypeSystem::NativeCode), m_mode(XPathReplace),
+ m_xpath(xpath), m_signature(signature) {}
+ DocModification(Mode mode, const QString& signature)
+ : m_mode(mode), m_signature(signature) {}
+
+ void setCode(const QString& code)
+ {
+ m_code = code;
+ }
+ QString code() const
+ {
+ return m_code;
+ }
+ QString xpath() const
+ {
+ return m_xpath;
+ }
+ QString signature() const
+ {
+ return m_signature;
+ }
+ Mode mode() const
+ {
+ return m_mode;
+ }
+
+ TypeSystem::Language format;
+
+private:
+ Mode m_mode;
+ QString m_code;
+ QString m_xpath;
+ QString m_signature;
+};
+
+typedef QList<DocModification> DocModificationList;
+
+class TypeEntry
+{
+public:
+ enum Type {
+ PrimitiveType,
+ VoidType,
+ FlagsType,
+ EnumType,
+ TemplateArgumentType,
+ ThreadType,
+ BasicValueType,
+ StringType,
+ ContainerType,
+ InterfaceType,
+ ObjectType,
+ NamespaceType,
+ VariantType,
+ JObjectWrapperType,
+ CharType,
+ ArrayType,
+ TypeSystemType,
+ CustomType,
+ };
+
+ enum CodeGeneration {
+ GenerateTargetLang = 0x0001,
+ GenerateCpp = 0x0002,
+ GenerateForSubclass = 0x0004,
+
+ GenerateNothing = 0,
+ GenerateAll = 0xffff,
+ GenerateCode = GenerateTargetLang | GenerateCpp
+ };
+
+ TypeEntry(const QString &name, Type t)
+ : m_name(name),
+ m_type(t),
+ m_codeGeneration(GenerateAll),
+ m_preferredConversion(true)
+ {
+ };
+
+ virtual ~TypeEntry() { }
+
+ Type type() const
+ {
+ return m_type;
+ }
+ bool isPrimitive() const
+ {
+ return m_type == PrimitiveType;
+ }
+ bool isEnum() const
+ {
+ return m_type == EnumType;
+ }
+ bool isFlags() const
+ {
+ return m_type == FlagsType;
+ }
+ bool isInterface() const
+ {
+ return m_type == InterfaceType;
+ }
+ bool isObject() const
+ {
+ return m_type == ObjectType;
+ }
+ bool isString() const
+ {
+ return m_type == StringType;
+ }
+ bool isChar() const
+ {
+ return m_type == CharType;
+ }
+ bool isNamespace() const
+ {
+ return m_type == NamespaceType;
+ }
+ bool isContainer() const
+ {
+ return m_type == ContainerType;
+ }
+ bool isVariant() const
+ {
+ return m_type == VariantType;
+ }
+ bool isJObjectWrapper() const
+ {
+ return m_type == JObjectWrapperType;
+ }
+ bool isArray() const
+ {
+ return m_type == ArrayType;
+ }
+ bool isTemplateArgument() const
+ {
+ return m_type == TemplateArgumentType;
+ }
+ bool isVoid() const
+ {
+ return m_type == VoidType;
+ }
+ bool isThread() const
+ {
+ return m_type == ThreadType;
+ }
+ bool isCustom() const
+ {
+ return m_type == CustomType;
+ }
+ bool isBasicValue() const
+ {
+ return m_type == BasicValueType;
+ }
+ bool isTypeSystem() const
+ {
+ return m_type == TypeSystemType;
+ }
+
+ virtual bool preferredConversion() const
+ {
+ return m_preferredConversion;
+ }
+ virtual void setPreferredConversion(bool b)
+ {
+ m_preferredConversion = b;
+ }
+
+ // The type's name in C++, fully qualified
+ QString name() const
+ {
+ return m_name;
+ }
+
+ uint codeGeneration() const
+ {
+ return m_codeGeneration;
+ }
+ void setCodeGeneration(uint cg)
+ {
+ m_codeGeneration = cg;
+ }
+
+ // Returns true if code must be generated for this entry,
+ // it will return false in case of types coming from typesystems
+ // included for reference only.
+ // NOTE: 'GenerateForSubclass' means 'generate="no"'
+ // on 'load-typesystem' tag
+ inline bool generateCode() const
+ {
+ return m_codeGeneration != TypeEntry::GenerateForSubclass
+ && m_codeGeneration != TypeEntry::GenerateNothing;
+ }
+
+ virtual QString qualifiedCppName() const
+ {
+ return m_name;
+ }
+
+ /**
+ * Its type's name in target language API
+ * The target language API name represents how this type is
+ * referred on low level code for the target language.
+ * Examples: for Java this would be a JNI name, for Python
+ * it should represent the CPython type name.
+ * /return string representing the target language API name
+ * for this type entry
+ */
+ virtual QString targetLangApiName() const
+ {
+ return m_name;
+ }
+
+ // The type's name in TargetLang
+ virtual QString targetLangName() const
+ {
+ return m_name;
+ }
+
+ // The type to lookup when converting to TargetLang
+ virtual QString lookupName() const
+ {
+ return targetLangName();
+ }
+
+ // The package
+ virtual QString targetLangPackage() const
+ {
+ return QString();
+ }
+
+ virtual QString qualifiedTargetLangName() const
+ {
+ QString pkg = targetLangPackage();
+ if (pkg.isEmpty())
+ return targetLangName();
+ return pkg + '.' + targetLangName();
+ }
+
+ virtual InterfaceTypeEntry *designatedInterface() const
+ {
+ return 0;
+ }
+
+ void setCustomConstructor(const CustomFunction &func)
+ {
+ m_customConstructor = func;
+ }
+ CustomFunction customConstructor() const
+ {
+ return m_customConstructor;
+ }
+
+ void setCustomDestructor(const CustomFunction &func)
+ {
+ m_customDestructor = func;
+ }
+ CustomFunction customDestructor() const
+ {
+ return m_customDestructor;
+ }
+
+ virtual bool isValue() const
+ {
+ return false;
+ }
+ virtual bool isComplex() const
+ {
+ return false;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return false;
+ }
+
+ CodeSnipList codeSnips() const
+ {
+ return m_codeSnips;
+ }
+ void setCodeSnips(const CodeSnipList &codeSnips)
+ {
+ m_codeSnips = codeSnips;
+ }
+ void addCodeSnip(const CodeSnip &codeSnip)
+ {
+ m_codeSnips << codeSnip;
+ }
+
+ void setDocModification(const DocModificationList& docMods)
+ {
+ m_docModifications << docMods;
+ }
+ DocModificationList docModifications() const
+ {
+ return m_docModifications;
+ }
+
+private:
+ QString m_name;
+ Type m_type;
+ uint m_codeGeneration;
+ CustomFunction m_customConstructor;
+ CustomFunction m_customDestructor;
+ bool m_preferredConversion;
+ CodeSnipList m_codeSnips;
+ DocModificationList m_docModifications;
+};
+typedef QHash<QString, QList<TypeEntry *> > TypeEntryHash;
+typedef QHash<QString, TypeEntry *> SingleTypeEntryHash;
+
+
+class TypeSystemTypeEntry : public TypeEntry
+{
+public:
+ TypeSystemTypeEntry(const QString &name)
+ : TypeEntry(name, TypeSystemType)
+ {
+ };
+};
+
+
+class ThreadTypeEntry : public TypeEntry
+{
+public:
+ ThreadTypeEntry() : TypeEntry("QThread", ThreadType)
+ {
+ setCodeGeneration(GenerateNothing);
+ }
+
+ QString targetLangApiName() const
+ {
+ return strings_jobject;
+ }
+ QString targetLangName() const
+ {
+ return strings_Thread;
+ }
+ QString targetLangPackage() const
+ {
+ return stringsJavaLang;
+ }
+};
+
+class VoidTypeEntry : public TypeEntry
+{
+public:
+ VoidTypeEntry() : TypeEntry("void", VoidType) { }
+};
+
+class TemplateArgumentEntry : public TypeEntry
+{
+public:
+ TemplateArgumentEntry(const QString &name)
+ : TypeEntry(name, TemplateArgumentType), m_ordinal(0)
+ {
+ }
+
+ int ordinal() const
+ {
+ return m_ordinal;
+ }
+ void setOrdinal(int o)
+ {
+ m_ordinal = o;
+ }
+
+private:
+ int m_ordinal;
+};
+
+class ArrayTypeEntry : public TypeEntry
+{
+public:
+ ArrayTypeEntry(const TypeEntry *nested_type)
+ : TypeEntry("Array", ArrayType), m_nestedType(nested_type)
+ {
+ Q_ASSERT(m_nestedType);
+ }
+
+ void setNestedTypeEntry(TypeEntry *nested)
+ {
+ m_nestedType = nested;
+ }
+ const TypeEntry *nestedTypeEntry() const
+ {
+ return m_nestedType;
+ }
+
+ QString targetLangName() const
+ {
+ return m_nestedType->targetLangName() + "[]";
+ }
+ QString targetLangApiName() const
+ {
+ if (m_nestedType->isPrimitive())
+ return m_nestedType->targetLangApiName() + "Array";
+ else
+ return "jobjectArray";
+ }
+
+private:
+ const TypeEntry *m_nestedType;
+};
+
+
+class PrimitiveTypeEntry : public TypeEntry
+{
+public:
+ PrimitiveTypeEntry(const QString &name)
+ : TypeEntry(name, PrimitiveType),
+ m_preferredConversion(true),
+ m_preferredTargetLangType(true),
+ m_aliasedTypeEntry(0)
+ {
+ }
+
+ QString targetLangName() const
+ {
+ return m_targetLangName;
+ }
+ void setTargetLangName(const QString &targetLangName)
+ {
+ m_targetLangName = targetLangName;
+ }
+
+ QString targetLangApiName() const
+ {
+ return m_targetLangApiName;
+ }
+ void setTargetLangApiName(const QString &targetLangApiName)
+ {
+ m_targetLangApiName = targetLangApiName;
+ }
+
+ /**
+ * The PrimitiveTypeEntry pointed by this type entry if it
+ * represents an alias (i.e. a typedef).
+ * /return the type pointed by the alias, or a null pointer
+ * if the current object is not an alias
+ */
+ PrimitiveTypeEntry* aliasedTypeEntry() const { return m_aliasedTypeEntry; }
+
+ /**
+ * Defines type aliased by this entry.
+ * /param aliasedTypeEntry type aliased by this entry
+ */
+ void setAliasedTypeEntry(PrimitiveTypeEntry* aliasedTypeEntry)
+ {
+ m_aliasedTypeEntry = aliasedTypeEntry;
+ }
+
+ /**
+ * Finds the most basic primitive type that the typedef represents,
+ * i.e. a type that is not an alias.
+ * /return the most basic non-aliased primitive type represented
+ * by this typedef
+ */
+ PrimitiveTypeEntry* basicAliasedTypeEntry() const;
+
+ QString javaObjectFullName() const
+ {
+ return javaObjectPackage() + "." + javaObjectName();
+ }
+ QString javaObjectName() const;
+ QString javaObjectPackage() const
+ {
+ return stringsJavaLang;
+ }
+
+ virtual bool preferredConversion() const
+ {
+ return m_preferredConversion;
+ }
+ virtual void setPreferredConversion(bool b)
+ {
+ m_preferredConversion = b;
+ }
+
+ virtual bool preferredTargetLangType() const
+ {
+ return m_preferredTargetLangType;
+ }
+ virtual void setPreferredTargetLangType(bool b)
+ {
+ m_preferredTargetLangType = b;
+ }
+
+private:
+ QString m_targetLangName;
+ QString m_targetLangApiName;
+ uint m_preferredConversion : 1;
+ uint m_preferredTargetLangType : 1;
+ PrimitiveTypeEntry* m_aliasedTypeEntry;
+};
+
+
+
+
+struct EnumValueRedirection
+{
+ EnumValueRedirection(const QString &rej, const QString &us)
+ : rejected(rej),
+ used(us)
+ {
+ }
+ QString rejected;
+ QString used;
+};
+
+class EnumTypeEntry : public TypeEntry
+{
+public:
+ EnumTypeEntry(const QString &nspace, const QString &enumName)
+ : TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
+ EnumType),
+ m_flags(0),
+ m_extensible(false)
+ {
+ m_qualifier = nspace;
+ m_targetLangName = enumName;
+ }
+
+ QString targetLangPackage() const
+ {
+ return m_packageName;
+ }
+ void setTargetLangPackage(const QString &package)
+ {
+ m_packageName = package;
+ }
+
+ QString targetLangName() const
+ {
+ return m_targetLangName;
+ }
+ QString targetLangQualifier() const;
+ QString qualifiedTargetLangName() const
+ {
+ QString qualifiedName;
+ QString pkg = targetLangPackage();
+ QString qualifier = targetLangQualifier();
+
+ if (!pkg.isEmpty())
+ qualifiedName += pkg + '.';
+ if (!qualifier.isEmpty())
+ qualifiedName += qualifier + '.';
+ qualifiedName += targetLangName();
+
+ return qualifiedName;
+ }
+
+ QString targetLangApiName() const;
+
+ QString qualifier() const
+ {
+ return m_qualifier;
+ }
+ void setQualifier(const QString &q)
+ {
+ m_qualifier = q;
+ }
+
+ virtual bool preferredConversion() const
+ {
+ return false;
+ }
+
+ bool isBoundsChecked() const
+ {
+ return m_lowerBound.isEmpty() && m_upperBound.isEmpty();
+ }
+
+ QString upperBound() const
+ {
+ return m_upperBound;
+ }
+ void setUpperBound(const QString &bound)
+ {
+ m_upperBound = bound;
+ }
+
+ QString lowerBound() const
+ {
+ return m_lowerBound;
+ }
+ void setLowerBound(const QString &bound)
+ {
+ m_lowerBound = bound;
+ }
+
+ void setFlags(FlagsTypeEntry *flags)
+ {
+ m_flags = flags;
+ }
+ FlagsTypeEntry *flags() const
+ {
+ return m_flags;
+ }
+
+ bool isExtensible() const
+ {
+ return m_extensible;
+ }
+ void setExtensible(bool is)
+ {
+ m_extensible = is;
+ }
+
+ bool isEnumValueRejected(const QString &name)
+ {
+ return m_rejectedEnums.contains(name);
+ }
+ void addEnumValueRejection(const QString &name)
+ {
+ m_rejectedEnums << name;
+ }
+ QStringList enumValueRejections() const
+ {
+ return m_rejectedEnums;
+ }
+
+ void addEnumValueRedirection(const QString &rejected, const QString &usedValue);
+ QString enumValueRedirection(const QString &value) const;
+
+ bool forceInteger() const
+ {
+ return m_forceInteger;
+ }
+ void setForceInteger(bool force)
+ {
+ m_forceInteger = force;
+ }
+
+private:
+ QString m_packageName;
+ QString m_qualifier;
+ QString m_targetLangName;
+
+ QString m_lowerBound;
+ QString m_upperBound;
+
+ QStringList m_rejectedEnums;
+ QList<EnumValueRedirection> m_enumRedirections;
+
+ FlagsTypeEntry *m_flags;
+
+ bool m_extensible;
+ bool m_forceInteger;
+};
+
+class FlagsTypeEntry : public TypeEntry
+{
+public:
+ FlagsTypeEntry(const QString &name) : TypeEntry(name, FlagsType), m_enum(0)
+ {
+ }
+
+ QString qualifiedTargetLangName() const;
+ QString targetLangName() const
+ {
+ return m_targetLangName;
+ }
+ QString targetLangApiName() const;
+ virtual bool preferredConversion() const
+ {
+ return false;
+ }
+
+ QString originalName() const
+ {
+ return m_originalName;
+ }
+ void setOriginalName(const QString &s)
+ {
+ m_originalName = s;
+ }
+
+ QString flagsName() const
+ {
+ return m_targetLangName;
+ }
+ void setFlagsName(const QString &name)
+ {
+ m_targetLangName = name;
+ }
+
+ bool forceInteger() const
+ {
+ return m_enum->forceInteger();
+ }
+
+ EnumTypeEntry *originator() const
+ {
+ return m_enum;
+ }
+ void setOriginator(EnumTypeEntry *e)
+ {
+ m_enum = e;
+ }
+
+ QString targetLangPackage() const
+ {
+ return m_enum->targetLangPackage();
+ }
+
+private:
+ QString m_originalName;
+ QString m_targetLangName;
+ EnumTypeEntry *m_enum;
+};
+
+
+class ComplexTypeEntry : public TypeEntry
+{
+public:
+ enum TypeFlag {
+ ForceAbstract = 0x1,
+ DeleteInMainThread = 0x2,
+ Deprecated = 0x4
+ };
+ typedef QFlags<TypeFlag> TypeFlags;
+
+ enum CopyableFlag {
+ CopyableSet,
+ NonCopyableSet,
+ Unknown
+ };
+
+ ComplexTypeEntry(const QString &name, Type t)
+ : TypeEntry(QString(name).replace(".*::", ""), t),
+ m_qualifiedCppName(name),
+ m_qobject(false),
+ m_polymorphicBase(false),
+ m_genericClass(false),
+ m_typeFlags(0),
+ m_copyableFlag(Unknown),
+ m_hashFunction("")
+ {
+ }
+
+ bool isComplex() const
+ {
+ return true;
+ }
+
+ IncludeList extraIncludes() const
+ {
+ return m_extraIncludes;
+ }
+ void setExtraIncludes(const IncludeList &includes)
+ {
+ m_extraIncludes = includes;
+ }
+ void addExtraInclude(const Include &include)
+ {
+ if (!m_includesUsed.value(include.name, false)) {
+ m_extraIncludes << include;
+ m_includesUsed[include.name] = true;
+ }
+ }
+
+ ComplexTypeEntry *copy() const
+ {
+ ComplexTypeEntry *centry = new ComplexTypeEntry(name(), type());
+ centry->setInclude(include());
+ centry->setExtraIncludes(extraIncludes());
+ centry->setFunctionModifications(functionModifications());
+ centry->setFieldModifications(fieldModifications());
+ centry->setQObject(isQObject());
+ centry->setDefaultSuperclass(defaultSuperclass());
+ centry->setCodeSnips(codeSnips());
+ centry->setTargetLangPackage(targetLangPackage());
+
+ return centry;
+ }
+
+ void setLookupName(const QString &name)
+ {
+ m_lookupName = name;
+ }
+
+ virtual QString lookupName() const
+ {
+ return m_lookupName.isEmpty() ? targetLangName() : m_lookupName;
+ }
+
+ QString targetLangApiName() const
+ {
+ return strings_jobject;
+ }
+
+
+ Include include() const
+ {
+ return m_include;
+ }
+ void setInclude(const Include &inc)
+ {
+ m_include = inc;
+ }
+
+ void setTypeFlags(TypeFlags flags)
+ {
+ m_typeFlags = flags;
+ }
+
+ TypeFlags typeFlags() const
+ {
+ return m_typeFlags;
+ }
+
+ FunctionModificationList functionModifications() const
+ {
+ return m_functionMods;
+ }
+ void setFunctionModifications(const FunctionModificationList &functionModifications)
+ {
+ m_functionMods = functionModifications;
+ }
+ void addFunctionModification(const FunctionModification &functionModification)
+ {
+ m_functionMods << functionModification;
+ }
+ FunctionModificationList functionModifications(const QString &signature) const;
+
+ FieldModification fieldModification(const QString &name) const;
+ void setFieldModifications(const FieldModificationList &mods)
+ {
+ m_fieldMods = mods;
+ }
+ FieldModificationList fieldModifications() const
+ {
+ return m_fieldMods;
+ }
+
+ QString targetLangPackage() const
+ {
+ return m_package;
+ }
+ void setTargetLangPackage(const QString &package)
+ {
+ m_package = package;
+ }
+
+ bool isQObject() const
+ {
+ return m_qobject;
+ }
+ void setQObject(bool qobject)
+ {
+ m_qobject = qobject;
+ }
+
+ QString defaultSuperclass() const
+ {
+ return m_defaultSuperclass;
+ }
+ void setDefaultSuperclass(const QString &sc)
+ {
+ m_defaultSuperclass = sc;
+ }
+
+ virtual QString qualifiedCppName() const
+ {
+ return m_qualifiedCppName;
+ }
+
+
+ void setIsPolymorphicBase(bool on)
+ {
+ m_polymorphicBase = on;
+ }
+ bool isPolymorphicBase() const
+ {
+ return m_polymorphicBase;
+ }
+
+ void setPolymorphicIdValue(const QString &value)
+ {
+ m_polymorphicIdValue = value;
+ }
+ QString polymorphicIdValue() const
+ {
+ return m_polymorphicIdValue;
+ }
+
+ void setHeldType(const QString &value)
+ {
+ m_heldTypeValue = value;
+ }
+ QString heldTypeValue() const
+ {
+ return m_heldTypeValue;
+ }
+
+
+ void setExpensePolicy(const ExpensePolicy &policy)
+ {
+ m_expensePolicy = policy;
+ }
+ const ExpensePolicy &expensePolicy() const
+ {
+ return m_expensePolicy;
+ }
+
+ QString targetType() const
+ {
+ return m_targetType;
+ }
+ void setTargetType(const QString &code)
+ {
+ m_targetType = code;
+ }
+
+ QString targetLangName() const
+ {
+ return m_targetLangName.isEmpty()
+ ? TypeEntry::targetLangName()
+ : m_targetLangName;
+ }
+ void setTargetLangName(const QString &name)
+ {
+ m_targetLangName = name;
+ }
+
+ bool isGenericClass() const
+ {
+ return m_genericClass;
+ }
+ void setGenericClass(bool isGeneric)
+ {
+ m_genericClass = isGeneric;
+ }
+
+ CopyableFlag copyable() const
+ {
+ return m_copyableFlag;
+ }
+ void setCopyable(CopyableFlag flag)
+ {
+ m_copyableFlag = flag;
+ }
+
+ QString hashFunction() const
+ {
+ return m_hashFunction;
+ }
+ void setHashFunction(QString hashFunction)
+ {
+ m_hashFunction = hashFunction;
+ }
+
+
+private:
+ IncludeList m_extraIncludes;
+ Include m_include;
+ QHash<QString, bool> m_includesUsed;
+ FunctionModificationList m_functionMods;
+ FieldModificationList m_fieldMods;
+ QString m_package;
+ QString m_defaultSuperclass;
+ QString m_qualifiedCppName;
+ QString m_targetLangName;
+
+ uint m_qobject : 1;
+ uint m_polymorphicBase : 1;
+ uint m_genericClass : 1;
+
+ QString m_polymorphicIdValue;
+ QString m_heldTypeValue;
+ QString m_lookupName;
+ QString m_targetType;
+ ExpensePolicy m_expensePolicy;
+ TypeFlags m_typeFlags;
+ CopyableFlag m_copyableFlag;
+ QString m_hashFunction;
+};
+
+class ContainerTypeEntry : public ComplexTypeEntry
+{
+public:
+ enum Type {
+ NoContainer,
+ ListContainer,
+ StringListContainer,
+ LinkedListContainer,
+ VectorContainer,
+ StackContainer,
+ QueueContainer,
+ SetContainer,
+ MapContainer,
+ MultiMapContainer,
+ HashContainer,
+ MultiHashContainer,
+ PairContainer,
+ };
+
+ ContainerTypeEntry(const QString &name, Type type)
+ : ComplexTypeEntry(name, ContainerType), m_type(type)
+ {
+ setCodeGeneration(GenerateForSubclass);
+ }
+
+ Type type() const
+ {
+ return m_type;
+ }
+ QString targetLangName() const;
+ QString targetLangPackage() const;
+ QString qualifiedCppName() const;
+
+ static Type containerTypeFromString(QString typeName)
+ {
+ static QHash<QString, Type> m_stringToContainerType;
+ if (m_stringToContainerType.isEmpty()) {
+ m_stringToContainerType["list"] = ListContainer;
+ m_stringToContainerType["string-list"] = StringListContainer;
+ m_stringToContainerType["linked-list"] = LinkedListContainer;
+ m_stringToContainerType["vector"] = VectorContainer;
+ m_stringToContainerType["stack"] = StackContainer;
+ m_stringToContainerType["queue"] = QueueContainer;
+ m_stringToContainerType["set"] = SetContainer;
+ m_stringToContainerType["map"] = MapContainer;
+ m_stringToContainerType["multi-map"] = MultiMapContainer;
+ m_stringToContainerType["hash"] = HashContainer;
+ m_stringToContainerType["multi-hash"] = MultiHashContainer;
+ m_stringToContainerType["pair"] = PairContainer;
+ }
+ return m_stringToContainerType.value(typeName, NoContainer);
+ }
+
+private:
+ Type m_type;
+};
+
+
+class NamespaceTypeEntry : public ComplexTypeEntry
+{
+public:
+ NamespaceTypeEntry(const QString &name) : ComplexTypeEntry(name, NamespaceType) { }
+};
+
+
+class ValueTypeEntry : public ComplexTypeEntry
+{
+public:
+ ValueTypeEntry(const QString &name) : ComplexTypeEntry(name, BasicValueType) { }
+
+ bool isValue() const
+ {
+ return true;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return true;
+ }
+
+protected:
+ ValueTypeEntry(const QString &name, Type t) : ComplexTypeEntry(name, t) { }
+};
+
+
+class StringTypeEntry : public ValueTypeEntry
+{
+public:
+ StringTypeEntry(const QString &name)
+ : ValueTypeEntry(name, StringType)
+ {
+ setCodeGeneration(GenerateNothing);
+ }
+
+ QString targetLangApiName() const
+ {
+ return strings_jobject;
+ }
+ QString targetLangName() const
+ {
+ return strings_String;
+ }
+ QString targetLangPackage() const
+ {
+ return stringsJavaLang;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return false;
+ }
+};
+
+class CharTypeEntry : public ValueTypeEntry
+{
+public:
+ CharTypeEntry(const QString &name) : ValueTypeEntry(name, CharType)
+ {
+ setCodeGeneration(GenerateNothing);
+ }
+
+ QString targetLangApiName() const
+ {
+ return strings_jchar;
+ }
+ QString targetLangName() const
+ {
+ return strings_char;
+ }
+ QString targetLangPackage() const
+ {
+ return QString();
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return false;
+ }
+};
+
+class JObjectWrapperTypeEntry: public ValueTypeEntry
+{
+public:
+ JObjectWrapperTypeEntry(const QString &name) : ValueTypeEntry(name, JObjectWrapperType) { }
+
+ QString targetLangApiName() const
+ {
+ return strings_jobject;
+ }
+ QString targetLangName() const
+ {
+ return strings_Object;
+ }
+ QString targetLangPackage() const
+ {
+ return stringsJavaLang;
+ }
+
+ bool isNativeIdBased() const
+ {
+ return false;
+ }
+};
+
+class VariantTypeEntry: public ValueTypeEntry
+{
+public:
+ VariantTypeEntry(const QString &name) : ValueTypeEntry(name, VariantType) { }
+
+ QString targetLangApiName() const
+ {
+ return strings_jobject;
+ }
+ QString targetLangName() const
+ {
+ return strings_Object;
+ }
+ QString targetLangPackage() const
+ {
+ return stringsJavaLang;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return false;
+ }
+};
+
+
+class InterfaceTypeEntry : public ComplexTypeEntry
+{
+public:
+ InterfaceTypeEntry(const QString &name)
+ : ComplexTypeEntry(name, InterfaceType) {}
+
+ static QString interfaceName(const QString &name)
+ {
+ return name + "Interface";
+ }
+
+ ObjectTypeEntry *origin() const
+ {
+ return m_origin;
+ }
+ void setOrigin(ObjectTypeEntry *origin)
+ {
+ m_origin = origin;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return true;
+ }
+ virtual QString qualifiedCppName() const
+ {
+ return ComplexTypeEntry::qualifiedCppName().left(ComplexTypeEntry::qualifiedCppName().length() - interfaceName("").length());
+ }
+
+private:
+ ObjectTypeEntry *m_origin;
+};
+
+
+class ObjectTypeEntry : public ComplexTypeEntry
+{
+public:
+ ObjectTypeEntry(const QString &name)
+ : ComplexTypeEntry(name, ObjectType), m_interface(0) {}
+
+ InterfaceTypeEntry *designatedInterface() const
+ {
+ return m_interface;
+ }
+ void setDesignatedInterface(InterfaceTypeEntry *entry)
+ {
+ m_interface = entry;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return true;
+ }
+
+private:
+ InterfaceTypeEntry *m_interface;
+};
+
+class CustomTypeEntry : public ComplexTypeEntry
+{
+public:
+ CustomTypeEntry(const QString &name) : ComplexTypeEntry(name, CustomType) {}
+
+ virtual void generateCppTargetLangToQt(QTextStream &s,
+ const AbstractMetaType* targetLangType,
+ const QString &envName,
+ const QString &qtName,
+ const QString &targetLangName) const = 0;
+
+ virtual void generateCppQtToTargetLang(QTextStream &s,
+ const AbstractMetaType* targetLangType,
+ const QString &envName,
+ const QString &qtName,
+ const QString &targetLangName) const = 0;
+};
+
+struct TypeRejection
+{
+ QString class_name;
+ QString function_name;
+ QString field_name;
+ QString enum_name;
+};
+
+class TypeDatabase
+{
+public:
+ TypeDatabase();
+
+ static TypeDatabase *instance();
+
+ QStringList requiredTargetImports()
+ {
+ return m_requiredTargetImports;
+ }
+
+ void addRequiredTargetImport(const QString &moduleName)
+ {
+ if (!m_requiredTargetImports.contains(moduleName))
+ m_requiredTargetImports << moduleName;
+ }
+
+ QStringList typesystemPaths()
+ {
+ return m_typesystemPaths;
+ }
+ void addTypesystemPath(const QString &typesystem_paths)
+ {
+#if defined(Q_OS_WIN32)
+ char *path_splitter = const_cast<char *>(";");
+#else
+ char *path_splitter = const_cast<char *>(":");
+#endif
+ m_typesystemPaths += typesystem_paths.split(path_splitter);
+ }
+
+ IncludeList extraIncludes(const QString &className);
+
+ inline PrimitiveTypeEntry *findPrimitiveType(const QString &name);
+ inline ComplexTypeEntry *findComplexType(const QString &name);
+ inline ObjectTypeEntry *findObjectType(const QString &name);
+ inline NamespaceTypeEntry *findNamespaceType(const QString &name);
+ ContainerTypeEntry *findContainerType(const QString &name);
+
+ TypeEntry *findType(const QString &name) const
+ {
+ QList<TypeEntry *> entries = findTypes(name);
+ foreach (TypeEntry *entry, entries) {
+ if (entry &&
+ (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
+ return entry;
+ }
+ }
+ return 0;
+ }
+ QList<TypeEntry *> findTypes(const QString &name) const
+ {
+ return m_entries.value(name);
+ }
+ TypeEntryHash allEntries()
+ {
+ return m_entries;
+ }
+
+ SingleTypeEntryHash entries()
+ {
+ TypeEntryHash entries = allEntries();
+
+ SingleTypeEntryHash returned;
+ QList<QString> keys = entries.keys();
+
+ foreach (QString key, keys)
+ returned[key] = findType(key);
+
+ return returned;
+ }
+
+ PrimitiveTypeEntry *findTargetLangPrimitiveType(const QString &targetLangName);
+
+ QList<const PrimitiveTypeEntry*> primitiveTypes() {
+ TypeEntryHash entries = allEntries();
+ QList<const PrimitiveTypeEntry*> returned;
+ foreach(QString key, entries.keys()) {
+ foreach(const TypeEntry* typeEntry, entries[key]) {
+ if (typeEntry->isPrimitive())
+ returned.append((PrimitiveTypeEntry*) typeEntry);
+ }
+ }
+ return returned;
+ }
+ QList<const ContainerTypeEntry*> containerTypes() {
+ TypeEntryHash entries = allEntries();
+ QList<const ContainerTypeEntry*> returned;
+ foreach(QString key, entries.keys()) {
+ foreach(const TypeEntry* typeEntry, entries[key]) {
+ if (typeEntry->isContainer())
+ returned.append((ContainerTypeEntry*) typeEntry);
+ }
+ }
+ return returned;
+ }
+
+ void addRejection(const QString &class_name, const QString &function_name,
+ const QString &field_name, const QString &enum_name);
+ bool isClassRejected(const QString &class_name);
+ bool isFunctionRejected(const QString &class_name, const QString &function_name);
+ bool isFieldRejected(const QString &class_name, const QString &field_name);
+ bool isEnumRejected(const QString &class_name, const QString &enum_name);
+
+ void addType(TypeEntry *e)
+ {
+ m_entries[e->qualifiedCppName()].append(e);
+ }
+
+ SingleTypeEntryHash flagsEntries() const
+ {
+ return m_flagsEntries;
+ }
+ FlagsTypeEntry *findFlagsType(const QString &name) const;
+ void addFlagsType(FlagsTypeEntry *fte)
+ {
+ m_flagsEntries[fte->originalName()] = fte;
+ }
+
+ TemplateEntry *findTemplate(const QString &name)
+ {
+ return m_templates[name];
+ }
+ void addTemplate(TemplateEntry *t)
+ {
+ m_templates[t->name()] = t;
+ }
+
+ void setSuppressWarnings(bool on)
+ {
+ m_suppressWarnings = on;
+ }
+ void addSuppressedWarning(const QString &s)
+ {
+ m_suppressedWarnings.append(s);
+ }
+
+ bool isSuppressedWarning(const QString &s)
+ {
+ if (!m_suppressWarnings)
+ return false;
+
+ foreach (const QString &_warning, m_suppressedWarnings) {
+ QString warning(QString(_warning).replace("\\*", "&place_holder_for_asterisk;"));
+
+ QStringList segs = warning.split("*", QString::SkipEmptyParts);
+ if (!segs.size())
+ continue;
+
+ int i = 0;
+ int pos = s.indexOf(QString(segs.at(i++)).replace("&place_holder_for_asterisk;", "*"));
+ //qDebug() << "s == " << s << ", warning == " << segs;
+ while (pos != -1) {
+ if (i == segs.size())
+ return true;
+ pos = s.indexOf(QString(segs.at(i++)).replace("&place_holder_for_asterisk;", "*"), pos);
+ }
+ }
+
+ return false;
+ }
+
+ void setRebuildClasses(const QStringList &cls)
+ {
+ m_rebuildClasses = cls;
+ }
+
+ static QString globalNamespaceClassName(const TypeEntry *te);
+ QString filename() const
+ {
+ return "typesystem.txt";
+ }
+
+ QString modifiedTypesystemFilepath(const QString &ts_file);
+ bool parseFile(const QString &filename, bool generate = true);
+ bool parseFile(QIODevice* device, bool generate = true);
+
+private:
+ bool m_suppressWarnings;
+ TypeEntryHash m_entries;
+ SingleTypeEntryHash m_flagsEntries;
+ TemplateEntryHash m_templates;
+ QStringList m_suppressedWarnings;
+
+ QStringList m_requiredTargetImports;
+
+ QStringList m_typesystemPaths;
+ QHash<QString, bool> m_parsedTypesystemFiles;
+
+ QList<TypeRejection> m_rejections;
+ QStringList m_rebuildClasses;
+};
+
+inline PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString &name)
+{
+ QList<TypeEntry *> entries = findTypes(name);
+
+ foreach (TypeEntry *entry, entries) {
+ if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())
+ return static_cast<PrimitiveTypeEntry *>(entry);
+ }
+
+ return 0;
+}
+
+inline ComplexTypeEntry *TypeDatabase::findComplexType(const QString &name)
+{
+ TypeEntry *entry = findType(name);
+ if (entry && entry->isComplex())
+ return static_cast<ComplexTypeEntry *>(entry);
+ else
+ return 0;
+}
+
+inline ObjectTypeEntry *TypeDatabase::findObjectType(const QString &name)
+{
+ TypeEntry *entry = findType(name);
+ if (entry && entry->isObject())
+ return static_cast<ObjectTypeEntry *>(entry);
+ else
+ return 0;
+}
+
+inline NamespaceTypeEntry *TypeDatabase::findNamespaceType(const QString &name)
+{
+ TypeEntry *entry = findType(name);
+ if (entry && entry->isNamespace())
+ return static_cast<NamespaceTypeEntry *>(entry);
+ else
+ return 0;
+}
+
+QString fixCppTypeName(const QString &name);
+
+#endif // TYPESYSTEM_H