aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@nokia.com>2012-02-15 15:56:22 +0100
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>2012-02-15 21:57:41 +0100
commit5672fa8fd3bd6b09125d9e143a7bb277cea2e87f (patch)
treec945b6ad76bd8c8f6af8b520cf3ce72ef298d4b5
Long live qbs!
-rw-r--r--.gitignore22
-rw-r--r--LGPL_EXCEPTION.txt22
-rw-r--r--LICENSE.LGPL503
-rw-r--r--README20
-rw-r--r--bin/ibmsvc.xml12
-rw-r--r--bin/ibqbs.bat1
-rw-r--r--doc/classic.css295
-rw-r--r--doc/config/compat.qdocconf31
-rw-r--r--doc/config/macros.qdocconf40
-rw-r--r--doc/config/qbs-project.qdocconf37
-rw-r--r--doc/config/qt-cpp-ignore.qdocconf99
-rw-r--r--doc/config/qt-defines.qdocconf19
-rw-r--r--doc/config/qt-html-default-styles.qdocconf33
-rw-r--r--doc/config/qt-html-online-styles.qdocconf73
-rw-r--r--doc/config/qt-html-templates-online.qdocconf185
-rw-r--r--doc/config/qt-html-templates.qdocconf56
-rw-r--r--doc/doc.pri60
-rw-r--r--doc/fixnavi.pl144
-rw-r--r--doc/qbs-online.qdocconf4
-rw-r--r--doc/qbs.qdoc770
-rw-r--r--doc/qbs.qdocconf3
-rw-r--r--doc/templates/images/arrow_down.pngbin0 -> 177 bytes
-rw-r--r--doc/templates/images/bg_l.pngbin0 -> 100 bytes
-rw-r--r--doc/templates/images/bg_l_blank.pngbin0 -> 84 bytes
-rw-r--r--doc/templates/images/bg_ll_blank.pngbin0 -> 320 bytes
-rw-r--r--doc/templates/images/bg_r.pngbin0 -> 96 bytes
-rw-r--r--doc/templates/images/bg_ul_blank.pngbin0 -> 304 bytes
-rw-r--r--doc/templates/images/box_bg.pngbin0 -> 89 bytes
-rw-r--r--doc/templates/images/breadcrumb.pngbin0 -> 134 bytes
-rw-r--r--doc/templates/images/bullet_dn.pngbin0 -> 230 bytes
-rw-r--r--doc/templates/images/bullet_gt.pngbin0 -> 124 bytes
-rw-r--r--doc/templates/images/bullet_sq.pngbin0 -> 74 bytes
-rw-r--r--doc/templates/images/bullet_up.pngbin0 -> 210 bytes
-rw-r--r--doc/templates/images/feedbackground.pngbin0 -> 263 bytes
-rw-r--r--doc/templates/images/header.pngbin0 -> 3768 bytes
-rw-r--r--doc/templates/images/header_bg.pngbin0 -> 114 bytes
-rw-r--r--doc/templates/images/horBar.pngbin0 -> 2807 bytes
-rw-r--r--doc/templates/images/page.pngbin0 -> 3102 bytes
-rw-r--r--doc/templates/images/page_bg.pngbin0 -> 84 bytes
-rw-r--r--doc/templates/images/qt_icon.pngbin0 -> 4775 bytes
-rw-r--r--doc/templates/images/spinner.gifbin0 -> 2037 bytes
-rw-r--r--doc/templates/images/sprites-combined.pngbin0 -> 62534 bytes
-rw-r--r--doc/templates/scripts/functions.js194
-rw-r--r--doc/templates/scripts/jquery.js152
-rw-r--r--doc/templates/scripts/narrow.js89
-rw-r--r--doc/templates/scripts/superfish.js121
-rw-r--r--doc/templates/style/narrow.css270
-rw-r--r--doc/templates/style/offline.css675
-rw-r--r--doc/templates/style/style.css1592
-rw-r--r--doc/templates/style/style_ie6.css54
-rw-r--r--doc/templates/style/style_ie7.css19
-rw-r--r--doc/templates/style/style_ie8.css0
-rw-r--r--doc/templates/style/superfish.css51
-rw-r--r--doc/templates/style/superfish_skin.css83
-rw-r--r--qbs.pro25
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs3
-rw-r--r--share/qbs/imports/qbs/base/DynamicLibrary.qbs3
-rw-r--r--share/qbs/imports/qbs/base/QmlApp.qbs22
-rw-r--r--share/qbs/imports/qbs/base/StaticLibrary.qbs3
-rw-r--r--share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp174
-rw-r--r--share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h46
-rw-r--r--share/qbs/imports/qbs/fileinfo/fileinfo.js62
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs75
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs300
-rw-r--r--share/qbs/modules/cpp/gcc.js113
-rw-r--r--share/qbs/modules/cpp/linux-gcc.qbs6
-rw-r--r--share/qbs/modules/cpp/mac-gcc.qbs69
-rw-r--r--share/qbs/modules/cpp/msvc.js173
-rw-r--r--share/qbs/modules/cpp/ponyphone.qbs28
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs199
-rw-r--r--share/qbs/modules/qbs/common.qbs50
-rw-r--r--share/qbs/modules/qt/QtModule.qbs19
-rw-r--r--share/qbs/modules/qt/core/moc.js15
-rw-r--r--share/qbs/modules/qt/core/qtcore.qbs130
-rw-r--r--share/qbs/modules/qt/declarative/module.qbs9
-rw-r--r--share/qbs/modules/qt/designer/module.qbs8
-rw-r--r--share/qbs/modules/qt/designercomponents/module.qbs8
-rw-r--r--share/qbs/modules/qt/gui/qtgui.qbs33
-rw-r--r--share/qbs/modules/qt/help/module.qbs8
-rw-r--r--share/qbs/modules/qt/network/module.qbs8
-rw-r--r--share/qbs/modules/qt/opengl/module.qbs8
-rw-r--r--share/qbs/modules/qt/qtfunctions.js12
-rw-r--r--share/qbs/modules/qt/script/module.qbs8
-rw-r--r--share/qbs/modules/qt/sql/module.qbs8
-rw-r--r--share/qbs/modules/qt/svg/module.qbs8
-rw-r--r--share/qbs/modules/qt/webkit/module.qbs8
-rw-r--r--share/qbs/modules/qt/xml/module.qbs8
-rw-r--r--share/qbs/modules/utils.js133
-rw-r--r--src/app/app.pro6
-rw-r--r--src/app/graph/graph.cpp465
-rw-r--r--src/app/graph/graph.pro12
-rw-r--r--src/app/platforms/main.cpp299
-rw-r--r--src/app/platforms/platforms.pro12
-rw-r--r--src/app/platforms/probe.cpp393
-rw-r--r--src/app/qbs/application.cpp61
-rw-r--r--src/app/qbs/application.h63
-rw-r--r--src/app/qbs/ctrlchandler.cpp74
-rw-r--r--src/app/qbs/ctrlchandler.h43
-rw-r--r--src/app/qbs/main.cpp304
-rw-r--r--src/app/qbs/qbs.pro16
-rw-r--r--src/lib/Qbs/Qbs.pri37
-rw-r--r--src/lib/Qbs/buildexecutor.cpp156
-rw-r--r--src/lib/Qbs/buildexecutor.h94
-rw-r--r--src/lib/Qbs/buildproduct.cpp121
-rw-r--r--src/lib/Qbs/buildproduct.h86
-rw-r--r--src/lib/Qbs/buildproject.cpp139
-rw-r--r--src/lib/Qbs/buildproject.h88
-rw-r--r--src/lib/Qbs/error.h74
-rw-r--r--src/lib/Qbs/globals.h63
-rw-r--r--src/lib/Qbs/ilogsink.cpp52
-rw-r--r--src/lib/Qbs/ilogsink.h90
-rw-r--r--src/lib/Qbs/logmessageevent.cpp72
-rw-r--r--src/lib/Qbs/logmessageevent.h67
-rw-r--r--src/lib/Qbs/mainthreadcommunication.cpp123
-rw-r--r--src/lib/Qbs/mainthreadcommunication.h78
-rw-r--r--src/lib/Qbs/oldsourceproject.cpp193
-rw-r--r--src/lib/Qbs/oldsourceproject.h74
-rw-r--r--src/lib/Qbs/processoutput.cpp124
-rw-r--r--src/lib/Qbs/processoutput.h80
-rw-r--r--src/lib/Qbs/processoutputevent.cpp65
-rw-r--r--src/lib/Qbs/processoutputevent.h62
-rw-r--r--src/lib/Qbs/qbserror.cpp76
-rw-r--r--src/lib/Qbs/sourceproject.cpp255
-rw-r--r--src/lib/Qbs/sourceproject.h95
-rw-r--r--src/lib/buildgraph/artifact.cpp97
-rw-r--r--src/lib/buildgraph/artifact.h112
-rw-r--r--src/lib/buildgraph/artifactlist.cpp57
-rw-r--r--src/lib/buildgraph/artifactlist.h109
-rw-r--r--src/lib/buildgraph/automoc.cpp273
-rw-r--r--src/lib/buildgraph/automoc.h86
-rw-r--r--src/lib/buildgraph/buildgraph.cpp1384
-rw-r--r--src/lib/buildgraph/buildgraph.h216
-rw-r--r--src/lib/buildgraph/buildgraph.pri26
-rw-r--r--src/lib/buildgraph/command.cpp231
-rw-r--r--src/lib/buildgraph/command.h154
-rw-r--r--src/lib/buildgraph/commandexecutor.cpp376
-rw-r--r--src/lib/buildgraph/commandexecutor.h106
-rw-r--r--src/lib/buildgraph/executor.cpp885
-rw-r--r--src/lib/buildgraph/executor.h147
-rw-r--r--src/lib/buildgraph/executorjob.cpp128
-rw-r--r--src/lib/buildgraph/executorjob.h86
-rw-r--r--src/lib/buildgraph/rulegraph.cpp201
-rw-r--r--src/lib/buildgraph/rulegraph.h77
-rw-r--r--src/lib/buildgraph/scanresultcache.cpp56
-rw-r--r--src/lib/buildgraph/scanresultcache.h71
-rw-r--r--src/lib/buildgraph/transformer.cpp119
-rw-r--r--src/lib/buildgraph/transformer.h85
-rw-r--r--src/lib/language/language.cpp453
-rw-r--r--src/lib/language/language.h264
-rw-r--r--src/lib/language/language.pri9
-rw-r--r--src/lib/language/loader.cpp2647
-rw-r--r--src/lib/language/loader.h408
-rw-r--r--src/lib/lib.pro16
-rw-r--r--src/lib/parser/cmd.sed13
-rw-r--r--src/lib/parser/gen-parser.sh14
-rw-r--r--src/lib/parser/parser.pri23
-rw-r--r--src/lib/parser/qmlerror.cpp285
-rw-r--r--src/lib/parser/qmlerror.h82
-rw-r--r--src/lib/parser/qmljs.g3138
-rw-r--r--src/lib/parser/qmljsast.cpp947
-rw-r--r--src/lib/parser/qmljsast_p.h2537
-rw-r--r--src/lib/parser/qmljsastfwd_p.h180
-rw-r--r--src/lib/parser/qmljsastvisitor.cpp49
-rw-r--r--src/lib/parser/qmljsastvisitor_p.h326
-rw-r--r--src/lib/parser/qmljsengine_p.cpp203
-rw-r--r--src/lib/parser/qmljsengine_p.h158
-rw-r--r--src/lib/parser/qmljsglobal_p.h56
-rw-r--r--src/lib/parser/qmljsgrammar.cpp1007
-rw-r--r--src/lib/parser/qmljsgrammar_p.h201
-rw-r--r--src/lib/parser/qmljslexer.cpp1249
-rw-r--r--src/lib/parser/qmljslexer_p.h240
-rw-r--r--src/lib/parser/qmljsmemorypool_p.h124
-rw-r--r--src/lib/parser/qmljsnodepool_p.h130
-rw-r--r--src/lib/parser/qmljsparser.cpp1893
-rw-r--r--src/lib/parser/qmljsparser_p.h237
-rw-r--r--src/lib/qtconcurrent/QtConcurrentTools39
-rw-r--r--src/lib/qtconcurrent/multitask.h202
-rw-r--r--src/lib/qtconcurrent/qtconcurrent.pri6
-rw-r--r--src/lib/qtconcurrent/qtconcurrent_global.h49
-rw-r--r--src/lib/qtconcurrent/runextensions.h431
-rw-r--r--src/lib/tools/codelocation.h91
-rw-r--r--src/lib/tools/coloredoutput.cpp103
-rw-r--r--src/lib/tools/coloredoutput.h73
-rw-r--r--src/lib/tools/error.cpp70
-rw-r--r--src/lib/tools/error.h90
-rw-r--r--src/lib/tools/fakeconcurrent.h103
-rw-r--r--src/lib/tools/fileinfo.cpp247
-rw-r--r--src/lib/tools/fileinfo.h90
-rw-r--r--src/lib/tools/filetime.h128
-rw-r--r--src/lib/tools/filetime_unix.cpp78
-rw-r--r--src/lib/tools/filetime_win.cpp104
-rw-r--r--src/lib/tools/logger.cpp325
-rw-r--r--src/lib/tools/logger.h138
-rw-r--r--src/lib/tools/logsink.cpp81
-rw-r--r--src/lib/tools/logsink.h60
-rw-r--r--src/lib/tools/options.cpp450
-rw-r--r--src/lib/tools/options.h113
-rw-r--r--src/lib/tools/persistence.cpp227
-rw-r--r--src/lib/tools/persistence.h237
-rw-r--r--src/lib/tools/platform.cpp82
-rw-r--r--src/lib/tools/platform.h59
-rw-r--r--src/lib/tools/runenvironment.cpp134
-rw-r--r--src/lib/tools/runenvironment.h60
-rw-r--r--src/lib/tools/scannerpluginmanager.cpp113
-rw-r--r--src/lib/tools/scannerpluginmanager.h67
-rw-r--r--src/lib/tools/scripttools.cpp139
-rw-r--r--src/lib/tools/scripttools.h83
-rw-r--r--src/lib/tools/settings.cpp117
-rw-r--r--src/lib/tools/settings.h83
-rw-r--r--src/lib/tools/tools.pri40
-rw-r--r--src/lib/use.pri43
-rw-r--r--src/plugins/plugins.pro2
-rw-r--r--src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h151
-rw-r--r--src/plugins/scanner/cpp/Lexer.cpp669
-rw-r--r--src/plugins/scanner/cpp/Lexer.h162
-rw-r--r--src/plugins/scanner/cpp/Token.cpp154
-rw-r--r--src/plugins/scanner/cpp/Token.h371
-rw-r--r--src/plugins/scanner/cpp/cpp.cpp281
-rw-r--r--src/plugins/scanner/cpp/cpp.pro15
-rw-r--r--src/plugins/scanner/cpp/cpp_global.h47
-rw-r--r--src/plugins/scanner/qt/qt.cpp227
-rw-r--r--src/plugins/scanner/qt/qt.pro12
-rw-r--r--src/plugins/scanner/scanner.h93
-rw-r--r--src/plugins/scanner/scanner.pro3
-rw-r--r--src/plugins/script/file/file.cpp91
-rw-r--r--src/plugins/script/file/file.h58
-rw-r--r--src/plugins/script/file/file.pro20
-rw-r--r--src/plugins/script/file/plugin.cpp75
-rw-r--r--src/plugins/script/file/textfile.cpp186
-rw-r--r--src/plugins/script/file/textfile.h76
-rw-r--r--src/plugins/script/script.pro2
-rw-r--r--static.pro70
-rw-r--r--tests/auto/auto.pro8
-rw-r--r--tests/auto/blackbox/blackbox.pro14
-rw-r--r--tests/auto/blackbox/testdata/buildproperties_source/bp_source.qbp16
-rw-r--r--tests/auto/blackbox/testdata/buildproperties_source/main.cpp47
-rw-r--r--tests/auto/blackbox/testdata/moc_h/bla.cpp44
-rw-r--r--tests/auto/blackbox/testdata/moc_h/bla_noqobject.h43
-rw-r--r--tests/auto/blackbox/testdata/moc_h/bla_qobject.h44
-rw-r--r--tests/auto/blackbox/testdata/moc_h/i.qbp18
-rw-r--r--tests/auto/blackbox/testdata/qrc/bla.cpp42
-rw-r--r--tests/auto/blackbox/testdata/qrc/bla.qrc5
-rw-r--r--tests/auto/blackbox/testdata/qrc/i.qbp19
-rw-r--r--tests/auto/blackbox/testdata/qrc/stuff.txt1
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/after/main.cpp50
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/after/project.qbp15
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp44
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/after/zort.h47
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/before/main.cpp47
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp44
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/before/narf.h47
-rw-r--r--tests/auto/blackbox/testdata/trackAddFile/before/project.qbp11
-rw-r--r--tests/auto/blackbox/testdata/trackFileTags/after/main.cpp46
-rw-r--r--tests/auto/blackbox/testdata/trackFileTags/after/project.qbp51
-rw-r--r--tests/auto/blackbox/testdata/trackFileTags/before/main.cpp44
-rw-r--r--tests/auto/blackbox/testdata/trackFileTags/before/project.qbp51
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp395
-rw-r--r--tests/auto/dependencyFinder/dependencyFinder.pro10
-rw-r--r--tests/auto/dependencyFinder/order_basic1.qbs4
-rw-r--r--tests/auto/dependencyFinder/order_basic2.qbs5
-rw-r--r--tests/auto/dependencyFinder/order_complex1.qbs8
-rw-r--r--tests/auto/dependencyFinder/order_nodeps.qbs4
-rw-r--r--tests/auto/dependencyFinder/test1.qbs16
-rw-r--r--tests/auto/dependencyFinder/tst_dependencyFinder.cpp569
-rw-r--r--tests/auto/options/app.xml5
-rw-r--r--tests/auto/options/options.pro12
-rw-r--r--tests/auto/options/tst_options.cpp61
-rw-r--r--tests/auto/tools/tools.pro12
-rw-r--r--tests/auto/tools/tst_tools.cpp64
-rw-r--r--tests/manual/application/foo.c9
-rw-r--r--tests/manual/application/main.cpp61
-rw-r--r--tests/manual/application/main_dbg.cpp61
-rw-r--r--tests/manual/application/object1.cpp43
-rw-r--r--tests/manual/application/object1.h50
-rw-r--r--tests/manual/application/object2.cpp46
-rw-r--r--tests/manual/application/object2.h50
-rw-r--r--tests/manual/application/somecustomfeature.cpp44
-rw-r--r--tests/manual/application/test.qbp43
-rw-r--r--tests/manual/baseProperties/Bar.qbs6
-rw-r--r--tests/manual/baseProperties/Foo.qbs7
-rw-r--r--tests/manual/baseProperties/main.cpp51
-rw-r--r--tests/manual/baseProperties/prj.qbp9
-rw-r--r--tests/manual/codegen/codegen.qbp42
-rw-r--r--tests/manual/codegen/foo.txt1
-rw-r--r--tests/manual/collidingmice/collidingmice.qbp18
-rw-r--r--tests/manual/collidingmice/images/cheese.jpgbin0 -> 3029 bytes
-rw-r--r--tests/manual/collidingmice/main.cpp88
-rw-r--r--tests/manual/collidingmice/mice.qrc5
-rw-r--r--tests/manual/collidingmice/mouse.cpp197
-rw-r--r--tests/manual/collidingmice/mouse.h65
-rw-r--r--tests/manual/hello/hello.qbp24
-rw-r--r--tests/manual/hello/src/foo.cpp5
-rw-r--r--tests/manual/hello/src/foo.h7
-rw-r--r--tests/manual/hello/src/main.cpp17
-rw-r--r--tests/manual/inheritModuleSearchPath/Foo.qbs7
-rw-r--r--tests/manual/inheritModuleSearchPath/main.cpp9
-rw-r--r--tests/manual/inheritModuleSearchPath/prj.qbp10
-rw-r--r--tests/manual/inheritModuleSearchPath/subdir/bli/m.qbs7
-rw-r--r--tests/manual/lib_samesource/lib.qbp22
-rw-r--r--tests/manual/lib_samesource/main.cpp43
-rw-r--r--tests/manual/lib_subdir/app/app.qbs10
-rw-r--r--tests/manual/lib_subdir/app/main.cpp44
-rw-r--r--tests/manual/lib_subdir/lib/lib.cpp48
-rw-r--r--tests/manual/lib_subdir/lib/lib.qbs10
-rw-r--r--tests/manual/lib_subdir/lib_subdir.qbp8
-rw-r--r--tests/manual/link_dynamiclib/lib1.cpp55
-rw-r--r--tests/manual/link_dynamiclib/lib2.cpp55
-rw-r--r--tests/manual/link_dynamiclib/lib3.cpp58
-rw-r--r--tests/manual/link_dynamiclib/link_dynamiclib.qbp43
-rw-r--r--tests/manual/link_dynamiclib/main.cpp55
-rw-r--r--tests/manual/link_staticlib/helper/helper.cpp43
-rw-r--r--tests/manual/link_staticlib/helper/helper.h43
-rw-r--r--tests/manual/link_staticlib/link_staticlib.qbp30
-rw-r--r--tests/manual/link_staticlib/main.cpp46
-rw-r--r--tests/manual/link_staticlib/mystaticlib.cpp46
-rw-r--r--tests/manual/link_staticlib/mystaticlibhelper.cpp5
-rw-r--r--tests/manual/localDeployment/localDeployment.qbp20
-rw-r--r--tests/manual/localDeployment/main.cpp49
-rw-r--r--tests/manual/moc_cpp/bla.cpp15
-rw-r--r--tests/manual/moc_cpp/moc_cpp.qbp14
-rw-r--r--tests/manual/moc_hpp/moc_hpp.qbp16
-rw-r--r--tests/manual/moc_hpp/object.cpp13
-rw-r--r--tests/manual/moc_hpp/object.h13
-rw-r--r--tests/manual/moc_hpp_included/moc_hpp_included.qbp18
-rw-r--r--tests/manual/moc_hpp_included/object.cpp15
-rw-r--r--tests/manual/moc_hpp_included/object.h13
-rw-r--r--tests/manual/pch/main.cpp27
-rw-r--r--tests/manual/pch/myobject.cpp13
-rw-r--r--tests/manual/pch/myobject.h12
-rw-r--r--tests/manual/pch/pch.qbp13
-rw-r--r--tests/manual/pch/stable.h9
-rw-r--r--tests/manual/productmoduledeps/lib1.cpp52
-rw-r--r--tests/manual/productmoduledeps/main.cpp55
-rw-r--r--tests/manual/productmoduledeps/productmoduledeps.qbp47
-rw-r--r--tests/manual/proper quoting/main.cpp55
-rw-r--r--tests/manual/proper quoting/my static lib helper.cpp5
-rw-r--r--tests/manual/proper quoting/my static lib.cpp46
-rw-r--r--tests/manual/proper quoting/proper quoting.qbp42
-rw-r--r--tests/manual/proper quoting/some helper/some helper.cpp44
-rw-r--r--tests/manual/proper quoting/some helper/some helper.h44
-rw-r--r--tests/manual/propertiesblocks/hello.qbp28
-rw-r--r--tests/manual/propertiesblocks/main.cpp52
-rw-r--r--tests/manual/qrc2/bla.cpp40
-rw-r--r--tests/manual/qrc2/bla.qrc5
-rw-r--r--tests/manual/qrc2/foo.qrc5
-rw-r--r--tests/manual/qrc2/i.qbp19
-rw-r--r--tests/manual/qrc2/stuff.txt1
-rw-r--r--tests/manual/symhello/hello.qbp10
-rw-r--r--tests/manual/symhello/main.cpp46
-rw-r--r--tests/manual/transformers/main.cpp77
-rw-r--r--tests/manual/transformers/transformers.qbp53
-rw-r--r--tests/manual/uic/bla.cpp44
-rw-r--r--tests/manual/uic/bla.h38
-rw-r--r--tests/manual/uic/ui.h38
-rw-r--r--tests/manual/uic/ui.ui31
-rw-r--r--tests/manual/uic/uic.qbp17
-rw-r--r--tests/tests.pro3
357 files changed, 45680 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..22a51099e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+.qbs
+build
+*.pdb
+*.pro.user
+*~
+*.o
+*.lib
+*.so
+moc_*.cpp
+*.moc
+*.qch
+*.a
+*.cpp.orig
+
+Makefile
+testOptions
+testTools
+
+bin/*
+doc/html/*
+
+
diff --git a/LGPL_EXCEPTION.txt b/LGPL_EXCEPTION.txt
new file mode 100644
index 000000000..a54c00e44
--- /dev/null
+++ b/LGPL_EXCEPTION.txt
@@ -0,0 +1,22 @@
+Nokia Qt LGPL Exception version 1.1
+
+As an additional permission to the GNU Lesser General Public License version
+2.1, the object code form of a "work that uses the Library" may incorporate
+material from a header file that is part of the Library. You may distribute
+such object code under terms of your choice, provided that:
+ (i) the header files of the Library have not been modified; and
+ (ii) the incorporated material is limited to numerical parameters, data
+ structure layouts, accessors, macros, inline functions and
+ templates; and
+ (iii) you comply with the terms of Section 6 of the GNU Lesser General
+ Public License version 2.1.
+
+Moreover, you may apply this exception to a modified version of the Library,
+provided that such modification does not involve copying material from the
+Library into the modified Library's header files unless such material is
+limited to (i) numerical parameters; (ii) data structure layouts;
+(iii) accessors; and (iv) small macros, templates and inline functions of
+five lines or less in length.
+
+Furthermore, you are not required to apply this additional permission to a
+modified version of the Library.
diff --git a/LICENSE.LGPL b/LICENSE.LGPL
new file mode 100644
index 000000000..e11c2af3e
--- /dev/null
+++ b/LICENSE.LGPL
@@ -0,0 +1,503 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, 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.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/README b/README
new file mode 100644
index 000000000..b1cf84347
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+This is qbs; the "Qt Build Salvation".
+The main documentation is available as qdoc files in the doc subdirectory.
+
+
+1. Build Prerequisites
+======================
+
+For building qbs you need:
+
+ - a C++ compiler
+ - Qt >= 4.7
+
+
+2. Building qbs
+===============
+
+ - qmake -r
+ - make
+ - make docs
+
diff --git a/bin/ibmsvc.xml b/bin/ibmsvc.xml
new file mode 100644
index 000000000..cea5990c1
--- /dev/null
+++ b/bin/ibmsvc.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<Profile FormatVersion="1">
+ <Tools>
+ <Tool Filename="qbs" AllowIntercept="true" />
+ <Tool Filename="cl" AllowRemote="true" VCCompiler="true" DeriveCaptionFrom="lastparam"/>
+ <Tool Filename="moc" AllowRemote="true" DeriveCaptionFrom="lastparam"/>
+ <Tool Filename="uic" AllowRemote="true" DeriveCaptionFrom="lastparam"/>
+ <Tool Filename="rcc" AllowRemote="true" DeriveCaptionFrom="lastparam"/>
+ <Tool Filename="link" AllowRemote="false" DeriveCaptionFrom="lastparam"/>
+ </Tools>
+</Profile>
+
diff --git a/bin/ibqbs.bat b/bin/ibqbs.bat
new file mode 100644
index 000000000..0e1cb2bdb
--- /dev/null
+++ b/bin/ibqbs.bat
@@ -0,0 +1 @@
+@xgConsole /profile=%~dp0\ibmsvc.xml /command="qbs -j 20 %*"
diff --git a/doc/classic.css b/doc/classic.css
new file mode 100644
index 000000000..f97bdbeab
--- /dev/null
+++ b/doc/classic.css
@@ -0,0 +1,295 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Arial, Geneva, Helvetica, sans-serif;
+}
+H1 {
+ text-align: center;
+ font-size: 160%;
+}
+H2 {
+ font-size: 120%;
+}
+H3 {
+ font-size: 100%;
+}
+
+h3.fn,span.fn
+{
+ background-color: #eee;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #ddd;
+ font-weight: bold;
+ padding: 6px 0px 6px 10px;
+ margin: 42px 0px 0px 0px;
+}
+
+hr {
+ border: 0;
+ color: #a0a0a0;
+ background-color: #ccc;
+ height: 1px;
+ width: 100%;
+ text-align: left;
+ margin: 34px 0px 34px 0px;
+}
+
+table.valuelist {
+ border-width: 1px 1px 1px 1px;
+ border-style: solid;
+ border-color: #dddddd;
+ border-collapse: collapse;
+ background-color: #f0f0f0;
+}
+
+table.indextable {
+ border-width: 1px 1px 1px 1px;
+ border-collapse: collapse;
+ background-color: #f0f0f0;
+ border-color:#555;
+ font-size: 110%;
+}
+
+table td.largeindex {
+ border-width: 1px 1px 1px 1px;
+ border-collapse: collapse;
+ background-color: #f0f0f0;
+ border-color:#555;
+ font-size: 120%;
+}
+
+table.valuelist th {
+ border-width: 1px 1px 1px 2px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #666;
+ color:white;
+ background-color:#666;
+}
+
+th.titleheader {
+ border-width: 1px 0px 1px 0px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #444;
+ color:white;
+ background-color:#555555;
+ font-size: 110%;
+}
+
+th.largeheader {
+ border-width: 1px 0px 1px 0px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #444;
+ color:white;
+ background-color:#555555;
+ font-size: 120%;
+}
+
+p {
+
+ margin-left: 4px;
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+
+a:link
+{
+ color: #0046ad;
+ text-decoration: none
+}
+
+a:visited
+{
+ color: #672967;
+ text-decoration: none
+}
+
+a.obsolete
+{
+ color: #661100;
+ text-decoration: none
+}
+
+a.compat
+{
+ color: #661100;
+ text-decoration: none
+}
+
+a.obsolete:visited
+{
+ color: #995500;
+ text-decoration: none
+}
+
+a.compat:visited
+{
+ color: #995500;
+ text-decoration: none
+}
+
+body
+{
+ background: #ffffff;
+ color: black
+}
+
+table.generic, table.annotated
+{
+ border-width: 1px;
+ border-color:#bbb;
+ border-style:solid;
+ border-collapse:collapse;
+}
+
+table td.memItemLeft {
+ width: 180px;
+ padding: 2px 0px 0px 8px;
+ margin: 4px;
+ border-width: 1px;
+ border-color: #E0E0E0;
+ border-style: none;
+ font-size: 100%;
+ white-space: nowrap
+}
+
+table td.memItemRight {
+ padding: 2px 8px 0px 8px;
+ margin: 4px;
+ border-width: 1px;
+ border-color: #E0E0E0;
+ border-style: none;
+ font-size: 100%;
+}
+
+table tr.odd {
+ background: #f0f0f0;
+ color: black;
+}
+
+table tr.even {
+ background: #e4e4e4;
+ color: black;
+}
+
+table.annotated th {
+ padding: 3px;
+ text-align: left
+}
+
+table.annotated td {
+ padding: 3px;
+}
+
+table tr pre
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ border: none;
+ background: none
+}
+
+tr.qt-style
+{
+ background: #96E066;
+ color: black
+}
+
+body pre
+{
+ padding: 0.2em;
+ border: #e7e7e7 1px solid;
+ background: #f1f1f1;
+ color: black
+}
+
+table tr.qt-code pre
+{
+ padding: 0.2em;
+ border: #e7e7e7 1px solid;
+ background: #f1f1f1;
+ color: black
+}
+
+span.preprocessor, span.preprocessor a
+{
+ color: darkblue;
+}
+
+span.comment
+{
+ color: darkred;
+ font-style: italic
+}
+
+span.string,span.char
+{
+ color: darkgreen;
+}
+
+.title
+{
+ text-align: center
+}
+
+.subtitle
+{
+ font-size: 0.8em
+}
+
+.small-subtitle
+{
+ font-size: 0.65em
+}
+
+.qmlitem {
+ padding: 0;
+}
+
+.qmlname {
+ white-space: nowrap;
+ font-weight: bold;
+ font-size: 125%;
+}
+
+.qmltype {
+ font-weight: bold;
+ font-size: 125%;
+}
+
+.qmlproto, .qmldoc {
+ // border-top: 1px solid #84b0c7;
+}
+
+.qmlproto {
+ padding: 0;
+ //background-color: #e4e4e4;//#d5e1e8;
+ //font-weight: bold;
+ //-webkit-border-top-left-radius: 8px;
+ //-webkit-border-top-right-radius: 8px;
+ //-moz-border-radius-topleft: 8px;
+ //-moz-border-radius-topright: 8px;
+}
+
+.qmldoc {
+ border-top: 1px solid #e4e4e4;
+ //padding: 2px 5px;
+ //background-color: #eef3f5;
+ //border-top-width: 0;
+ //-webkit-border-bottom-left-radius: 8px;
+ //-webkit-border-bottom-right-radius: 8px;
+ //-moz-border-radius-bottomleft: 8px;
+ //-moz-border-radius-bottomright: 8px;
+}
+
+.qmldoc p, .qmldoc dl, .qmldoc ul {
+ //margin: 6px 0;
+}
+
+*.qmlitem p {
+ //margin-top: 0px;
+ //margin-bottom: 0px;
+}
diff --git a/doc/config/compat.qdocconf b/doc/config/compat.qdocconf
new file mode 100644
index 000000000..5745ed93b
--- /dev/null
+++ b/doc/config/compat.qdocconf
@@ -0,0 +1,31 @@
+alias.i = e
+alias.include = input
+
+macro.0 = "\\\\0"
+macro.b = "\\\\b"
+macro.n = "\\\\n"
+macro.r = "\\\\r"
+macro.i = "\\o"
+macro.i11 = "\\o{1,1}"
+macro.i12 = "\\o{1,2}"
+macro.i13 = "\\o{1,3}"
+macro.i14 = "\\o{1,4}"
+macro.i15 = "\\o{1,5}"
+macro.i16 = "\\o{1,6}"
+macro.i17 = "\\o{1,7}"
+macro.i18 = "\\o{1,8}"
+macro.i19 = "\\o{1,9}"
+macro.i21 = "\\o{2,1}"
+macro.i31 = "\\o{3,1}"
+macro.i41 = "\\o{4,1}"
+macro.i51 = "\\o{5,1}"
+macro.i61 = "\\o{6,1}"
+macro.i71 = "\\o{7,1}"
+macro.i81 = "\\o{8,1}"
+macro.i91 = "\\o{9,1}"
+macro.img = "\\image"
+macro.endquote = "\\endquotation"
+macro.relatesto = "\\relates"
+
+spurious = "Missing comma in .*" \
+ "Missing pattern .*"
diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf
new file mode 100644
index 000000000..1997fd9c3
--- /dev/null
+++ b/doc/config/macros.qdocconf
@@ -0,0 +1,40 @@
+macro.aacute.HTML = "&aacute;"
+macro.Aring.HTML = "&Aring;"
+macro.aring.HTML = "&aring;"
+macro.Auml.HTML = "&Auml;"
+macro.author = "\\bold{Author:}"
+macro.br.HTML = "<br />"
+macro.BR.HTML = "<br />"
+macro.copyright.HTML = "&copy;"
+macro.eacute.HTML = "&eacute;"
+macro.gui = "\\bold"
+macro.hr.HTML = "<hr />"
+macro.iacute.HTML = "&iacute;"
+macro.key = "\\bold"
+macro.menu = "\\bold"
+macro.note = "\\bold{Note:}"
+macro.oslash.HTML = "&oslash;"
+macro.ouml.HTML = "&ouml;"
+macro.QA = "\\e{Qt Assistant}"
+macro.QD = "\\e{Qt Designer}"
+macro.QL = "\\e{Qt Linguist}"
+macro.QMLD = "\\e{Qt Quick Designer}"
+macro.QQV = "\\e{Qt QML Viewer}"
+macro.QSDK = "\\e{Qt SDK}"
+macro.qtcversion = $QTC_VERSION
+macro.param = "\\e"
+macro.raisedaster.HTML = "<sup>*</sup>"
+macro.rarrow.HTML = "&rarr;"
+macro.reg.HTML = "<sup>&reg;</sup>"
+macro.return = "Returns"
+macro.starslash = "\\c{*/}"
+macro.begincomment = "\\c{/*}"
+macro.endcomment = "\\c{*/}"
+macro.uuml.HTML = "&uuml;"
+macro.mdash.HTML = "&mdash;"
+
+macro.beginfloatleft.HTML = "<div style=\"float: left; margin-right: 2em\">"
+macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">"
+macro.endfloat.HTML = "</div>"
+macro.clearfloat.HTML = "<br style=\"clear: both\" />"
+macro.emptyspan.HTML = "<span></span>"
diff --git a/doc/config/qbs-project.qdocconf b/doc/config/qbs-project.qdocconf
new file mode 100644
index 000000000..a72a23dda
--- /dev/null
+++ b/doc/config/qbs-project.qdocconf
@@ -0,0 +1,37 @@
+project = "Qt Build System"
+description = "Qbs Manual"
+
+headerdirs =
+sourcedirs = $SRCDIR
+imagedirs = $SRCDIR/images $SRCDIR/templates/images
+outputdir = $OUTDIR
+exampledirs = $SRCDIR
+indexes = qt.index
+
+include(compat.qdocconf)
+include(macros.qdocconf)
+include(qt-cpp-ignore.qdocconf)
+include(qt-defines.qdocconf)
+
+sources.fileextensions = "qbs.qdoc"
+
+
+qhp.projects = Qbs
+qhp.Qbs.file = qbs.qhp
+qhp.Qbs.namespace = com.nokia.qbs.$QTC_VERSION_TAG
+qhp.Qbs.virtualFolder = doc
+qhp.Qbs.indexTitle = Qt Build System
+qhp.Qbs.filterAttributes = qbs $QTC_VERSION
+qhp.Qbs.customFilters.Qbs.name = Qt Build System $QTC_VERSION
+qhp.Qbs.customFilters.Qbs.filterAttributes = qbs $QTC_VERSION
+qhp.Qbs.indexRoot =
+
+qhp.Qbs.subprojects = manual
+qhp.Qbs.subprojects.manual.title = Qbs Manual
+qhp.Qbs.subprojects.manual.indexTitle = Qbs Manual
+qhp.Qbs.subprojects.manual.type = manual
+
+# Doxygen compatibility commands
+
+macro.see = "\\sa"
+macro.function = "\\fn"
diff --git a/doc/config/qt-cpp-ignore.qdocconf b/doc/config/qt-cpp-ignore.qdocconf
new file mode 100644
index 000000000..ce8de2406
--- /dev/null
+++ b/doc/config/qt-cpp-ignore.qdocconf
@@ -0,0 +1,99 @@
+Cpp.ignoretokens = QAXFACTORY_EXPORT \
+ QDESIGNER_COMPONENTS_LIBRARY \
+ QDESIGNER_EXTENSION_LIBRARY \
+ QDESIGNER_SDK_LIBRARY \
+ QDESIGNER_SHARED_LIBRARY \
+ QDESIGNER_UILIB_LIBRARY \
+ QM_EXPORT_CANVAS \
+ QM_EXPORT_DNS \
+ QM_EXPORT_DOM \
+ QM_EXPORT_FTP \
+ QM_EXPORT_HTTP \
+ QM_EXPORT_ICONVIEW \
+ QM_EXPORT_NETWORK \
+ QM_EXPORT_OPENGL \
+ QM_EXPORT_OPENVG \
+ QM_EXPORT_SQL \
+ QM_EXPORT_TABLE \
+ QM_EXPORT_WORKSPACE \
+ QM_EXPORT_XML \
+ QT_ASCII_CAST_WARN \
+ QT_ASCII_CAST_WARN_CONSTRUCTOR \
+ QT_BEGIN_HEADER \
+ QT_DESIGNER_STATIC \
+ QT_END_HEADER \
+ QT_FASTCALL \
+ QT_WIDGET_PLUGIN_EXPORT \
+ Q_COMPAT_EXPORT \
+ Q_CORE_EXPORT \
+ Q_CORE_EXPORT_INLINE \
+ Q_EXPLICIT \
+ Q_EXPORT \
+ Q_EXPORT_CODECS_CN \
+ Q_EXPORT_CODECS_JP \
+ Q_EXPORT_CODECS_KR \
+ Q_EXPORT_PLUGIN \
+ Q_GFX_INLINE \
+ Q_AUTOTEST_EXPORT \
+ Q_GUI_EXPORT \
+ Q_GUI_EXPORT_INLINE \
+ Q_GUI_EXPORT_STYLE_CDE \
+ Q_GUI_EXPORT_STYLE_COMPACT \
+ Q_GUI_EXPORT_STYLE_MAC \
+ Q_GUI_EXPORT_STYLE_MOTIF \
+ Q_GUI_EXPORT_STYLE_MOTIFPLUS \
+ Q_GUI_EXPORT_STYLE_PLATINUM \
+ Q_GUI_EXPORT_STYLE_POCKETPC \
+ Q_GUI_EXPORT_STYLE_SGI \
+ Q_GUI_EXPORT_STYLE_WINDOWS \
+ Q_GUI_EXPORT_STYLE_WINDOWSXP \
+ QHELP_EXPORT \
+ Q_INLINE_TEMPLATE \
+ Q_INTERNAL_WIN_NO_THROW \
+ Q_NETWORK_EXPORT \
+ Q_OPENGL_EXPORT \
+ Q_OPENVG_EXPORT \
+ Q_OUTOFLINE_TEMPLATE \
+ Q_SQL_EXPORT \
+ Q_SVG_EXPORT \
+ Q_SCRIPT_EXPORT \
+ Q_SCRIPTTOOLS_EXPORT \
+ Q_TESTLIB_EXPORT \
+ Q_TYPENAME \
+ Q_XML_EXPORT \
+ Q_XMLSTREAM_EXPORT \
+ Q_XMLPATTERNS_EXPORT \
+ QDBUS_EXPORT \
+ Q_DBUS_EXPORT \
+ QT_BEGIN_NAMESPACE \
+ QT_BEGIN_INCLUDE_NAMESPACE \
+ QT_END_NAMESPACE \
+ QT_END_INCLUDE_NAMESPACE \
+ PHONON_EXPORT \
+ Q_DECLARATIVE_EXPORT \
+ Q_GADGET \
+ QWEBKIT_EXPORT \
+ Q_INVOKABLE \
+ EXTENSIONSYSTEM_EXPORT
+Cpp.ignoredirectives = Q_DECLARE_HANDLE \
+ Q_DECLARE_INTERFACE \
+ Q_DECLARE_METATYPE \
+ Q_DECLARE_OPERATORS_FOR_FLAGS \
+ Q_DECLARE_PRIVATE \
+ Q_DECLARE_PUBLIC \
+ Q_DECLARE_SHARED \
+ Q_DECLARE_TR_FUNCTIONS \
+ Q_DECLARE_TYPEINFO \
+ Q_DISABLE_COPY \
+ QT_FORWARD_DECLARE_CLASS \
+ Q_DUMMY_COMPARISON_OPERATOR \
+ Q_ENUMS \
+ Q_FLAGS \
+ Q_INTERFACES \
+ __attribute__ \
+ K_DECLARE_PRIVATE \
+ PHONON_OBJECT \
+ PHONON_HEIR \
+ Q_PRIVATE_PROPERTY \
+ Q_DECLARE_PRIVATE_D \
+ Q_CLASSINFO
diff --git a/doc/config/qt-defines.qdocconf b/doc/config/qt-defines.qdocconf
new file mode 100644
index 000000000..1ce9a8045
--- /dev/null
+++ b/doc/config/qt-defines.qdocconf
@@ -0,0 +1,19 @@
+defines = Q_QDOC \
+ QT_.*_SUPPORT \
+ QT_.*_LIB \
+ QT_COMPAT \
+ QT_KEYPAD_NAVIGATION \
+ QT_NO_EGL \
+ QT3_SUPPORT \
+ Q_WS_.* \
+ Q_OS_.* \
+ Q_BYTE_ORDER \
+ QT_DEPRECATED \
+ Q_NO_USING_KEYWORD \
+ __cplusplus \
+ qtquick \
+ qcmanual
+
+versionsym = QT_VERSION_STR
+
+codeindent = 1
diff --git a/doc/config/qt-html-default-styles.qdocconf b/doc/config/qt-html-default-styles.qdocconf
new file mode 100644
index 000000000..2d4f25a57
--- /dev/null
+++ b/doc/config/qt-html-default-styles.qdocconf
@@ -0,0 +1,33 @@
+# Define the location of the templates to use. Style sheets and scripts are
+# specified relative to the template directory and will be copied into
+# subdirectories of the output directory.
+
+HTML.templatedir = $SRCDIR/templates
+
+HTML.stylesheets = style/offline.css
+
+HTML.scripts =
+
+# Files not referenced in any qdoc file (last four needed by qtdemo)
+# See also qhp.Qt.extraFiles
+extraimages.HTML = qt-logo.png \
+ arrow_down.png \
+ breadcrumb.png \
+ bullet_gt.png \
+ bullet_dn.png \
+ bullet_sq.png \
+ bullet_up.png \
+ horBar.png \
+ sprites-combined.png \
+ qtcreator-screenshots.png
+
+# Include the style sheets and scripts used.
+
+HTML.headerstyles = \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
+
+HTML.headerscripts =
+
+HTML.endheader = \
+ "</head>\n" \
+ "<body>\n"
diff --git a/doc/config/qt-html-online-styles.qdocconf b/doc/config/qt-html-online-styles.qdocconf
new file mode 100644
index 000000000..f6480dc25
--- /dev/null
+++ b/doc/config/qt-html-online-styles.qdocconf
@@ -0,0 +1,73 @@
+# Define the location of the templates to use. Style sheets and scripts are
+# specified relative to the template directory and will be copied into
+# subdirectories of the output directory.
+
+HTML.templatedir = $SRCDIR/templates
+
+HTML.stylesheets = style/narrow.css \
+ style/style.css \
+ style/style_ie6.css \
+ style/style_ie7.css \
+ style/style_ie8.css \
+ style/superfish.css
+
+# Adding jquery and functions - providing online tools and search features
+HTML.scripts = scripts/functions.js \
+ scripts/narrow.js \
+ scripts/superfish.js \
+ scripts/jquery.js
+
+
+# Files not referenced in any qdoc file.
+# See also qhp.Qt.extraFiles
+extraimages.HTML = qt-logo.png \
+ bg_l.png \
+ bg_l_blank.png \
+ bg_ll_blank.png \
+ bg_ul_blank.png \
+ header_bg.png \
+ bg_r.png \
+ box_bg.png \
+ breadcrumb.png \
+ bullet_gt.png \
+ bullet_dn.png \
+ bullet_sq.png \
+ bullet_up.png \
+ arrow_down.png \
+ feedbackground.png \
+ horBar.png \
+ page.png \
+ page_bg.png \
+ sprites-combined.png \
+ spinner.gif \
+ qtcreator-screenshots.png
+
+# Include the style sheets and scripts used.
+
+HTML.headerstyles = \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n" \
+ " <script src=\"scripts/jquery.js\" type=\"text/javascript\"></script>\n" \
+ " <script src=\"scripts/functions.js\" type=\"text/javascript\"></script>\n" \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/superfish.css\" />\n" \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/narrow.css\" />\n" \
+ " <!--[if IE]>\n" \
+ "<meta name=\"MSSmartTagsPreventParsing\" content=\"true\">\n" \
+ "<meta http-equiv=\"imagetoolbar\" content=\"no\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if lt IE 7]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie6.css\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if IE 7]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie7.css\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if IE 8]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie8.css\">\n" \
+ "<![endif]-->\n\n"
+
+HTML.headerscripts = \
+ "<script src=\"scripts/superfish.js\" type=\"text/javascript\"></script>\n" \
+ "<script src=\"scripts/narrow.js\" type=\"text/javascript\"></script>\n\n"
+
+HTML.endheader = \
+ "</head>\n" \
+ "<body class=\"\" onload=\"CheckEmptyAndLoadList();\">\n"
diff --git a/doc/config/qt-html-templates-online.qdocconf b/doc/config/qt-html-templates-online.qdocconf
new file mode 100644
index 000000000..198ef6c44
--- /dev/null
+++ b/doc/config/qt-html-templates-online.qdocconf
@@ -0,0 +1,185 @@
+include(qt-html-online-styles.qdocconf)
+
+HTML.postheader = \
+ " <div class=\"header\" id=\"qtdocheader\">\n" \
+ " <div class=\"content\"> \n" \
+ " <div id=\"nav-logo\">\n" \
+ " <a href=\"index.html\">Home</a></div>\n" \
+ " <a href=\"index.html\" class=\"qtref\"><span>Qbs Manual</span></a>\n" \
+ " <div id=\"narrowsearch\"></div>\n" \
+ " <div id=\"nav-topright\">\n" \
+ " <ul>\n" \
+ " <li class=\"nav-topright-home\"><a href=\"http://qt.nokia.com/\">Qt HOME</a></li>\n" \
+ " <li class=\"nav-topright-dev\"><a href=\"http://developer.qt.nokia.com/\">DEV</a></li>\n" \
+ " <li class=\"nav-topright-labs\"><a href=\"http://labs.qt.nokia.com/blogs/\">LABS</a></li>\n" \
+ " <li class=\"nav-topright-doc nav-topright-doc-active\"><a href=\"http://doc.qt.nokia.com/\">\n" \
+ " DOC</a></li>\n" \
+ " <li class=\"nav-topright-blog\"><a href=\"http://blog.qt.nokia.com/\">BLOG</a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div id=\"shortCut\">\n" \
+ " <ul>\n" \
+ " <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt Creator</a></span></li>\n" \
+ " </a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"wrapper\">\n" \
+ " <div class=\"hd\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ " <div class=\"bd group\">\n" \
+ " <div class=\"sidebar\">\n" \
+ " <div class=\"box first bottombar\" id=\"lookup\">\n" \
+ " <h2 title=\"API Lookup\">\n" \
+ " API Lookup</h2>\n" \
+ " <div id=\"list001\" class=\"list\">\n" \
+ " <ul id=\"ul001\" >\n" \
+ " <li class=\"defaultLink\"><a href=\"classes.html\">Class index</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"functions.html\">Function index</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"modules.html\">Modules</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"namespaces.html\">Namespaces</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"qtglobal.html\">Global Declarations</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"qdeclarativeelements.html\">QML elements</a></li>\n" \
+ " </ul> \n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"box bottombar\" id=\"topics\">\n" \
+ " <h2 title=\"Qt Topics\"><span></span>\n" \
+ " Qt Topics</h2>\n" \
+ " <div id=\"list002\" class=\"list\">\n" \
+ " <ul id=\"ul002\" >\n" \
+ " <li class=\"defaultLink\"><a href=\"qt-basic-concepts.html\">Programming with Qt</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"qtquick.html\">Device UIs &amp; Qt Quick</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"qt-gui-concepts.html\">UI Design with Qt</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"developing-with-qt.html\">Cross-platform and Platform-specific</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"platform-specific.html\">Platform-specific info</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"technology-apis.html\">Qt and Key Technologies</a></li> \n" \
+ " <li class=\"defaultLink\"><a href=\"best-practices.html\">How-To's and Best Practices</a></li> \n" \
+ " </ul> \n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"box\" id=\"examples\">\n" \
+ " <h2 title=\"Examples\"><span></span>\n" \
+ " Examples</h2>\n" \
+ " <div id=\"list003\" class=\"list\">\n" \
+ " <ul id=\"ul003\">\n" \
+ " <li class=\"defaultLink\"><a href=\"all-examples.html\">Examples</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"tutorials.html\">Tutorials</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"demos.html\">Demos</a></li>\n" \
+ " <li class=\"defaultLink\"><a href=\"qdeclarativeexamples.html\">QML Examples</a></li>\n" \
+ " </ul> \n" \
+ " </div>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"wrap\">\n" \
+ " <div class=\"toolbar\">\n" \
+ " <div class=\"breadcrumb toolblock\">\n" \
+ " <ul>\n" \
+ " <li class=\"first\"><a href=\"index.html\">Home</a></li>\n" \
+ " <!-- Breadcrumbs go here -->\n"
+
+HTML.postpostheader = \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div class=\"toolbuttons toolblock\">\n" \
+ " <ul>\n" \
+ " <li id=\"smallA\" class=\"t_button\">A</li>\n" \
+ " <li id=\"medA\" class=\"t_button active\">A</li>\n" \
+ " <li id=\"bigA\" class=\"t_button\">A</li>\n" \
+ " <li id=\"print\" class=\"t_button\"><a href=\"javascript:this.print();\">\n" \
+ " <span>Print</span></a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"content mainContent\">\n"
+
+HTML.footer = \
+ " <div class=\"feedback t_button\">\n" \
+ " [+] Documentation Feedback</div>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " </div> \n" \
+ " <div class=\"ft\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ " </div> \n" \
+ " <div class=\"footer\">\n" \
+ " <p>\n" \
+ " <acronym title=\"Copyright\">&copy;</acronym> 2008-2012 Nokia Corporation and/or its\n" \
+ " subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation \n" \
+ " in Finland and/or other countries worldwide.</p>\n" \
+ " <p>\n" \
+ " All other trademarks are property of their respective owners. <a title=\"Privacy Policy\"\n" \
+ " href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \
+ " <br />\n" \
+ " <p>\n" \
+ " Licensees holding valid Qt Commercial licenses may use this document in accordance with the" \
+ " Qt Commercial License Agreement provided with the Software or, alternatively, in accordance" \
+ " with the terms contained in a written agreement between you and Nokia.</p>\n" \
+ " <p>\n" \
+ " Alternatively, this document may be used under the terms of the <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU\n" \
+ " Free Documentation License version 1.3</a>\n" \
+ " as published by the Free Software Foundation.</p>\n" \
+ " </div>\n" \
+ " <div id=\"feedbackBox\">\n" \
+ " <div id=\"feedcloseX\" class=\"feedclose t_button\">X</div>\n" \
+ " <form id=\"feedform\" action=\"http://doc.qt.nokia.com/docFeedbck/feedback.php\" method=\"get\">\n" \
+ " <p id=\"noteHead\">Thank you for giving your feedback.</p> <p class=\"note\">Make sure it is related to this specific page. For more general bugs and \n" \
+ " requests, please use the <a href=\"http://bugreports.qt.nokia.com/secure/Dashboard.jspa\">Qt Bug Tracker</a>.</p>\n" \
+ " <p><textarea id=\"feedbox\" name=\"feedText\" rows=\"5\" cols=\"40\"></textarea></p>\n" \
+ " <p><input id=\"feedsubmit\" class=\"feedclose\" type=\"submit\" name=\"feedback\" /></p>\n" \
+ " </form>\n" \
+ " </div>\n" \
+ " <div id=\"blurpage\">\n" \
+ " </div>\n" \
+ "\n" \
+ " <script src=\"scripts/functions.js\" type=\"text/javascript\"></script>\n" \
+ " <script type=\"text/javascript\">\n" \
+ " var _gaq = _gaq || [];\n" \
+ " _gaq.push(['_setAccount', 'UA-4457116-5']);\n" \
+ " _gaq.push(['_trackPageview']);\n" \
+ " (function() {\n" \
+ " var ga = document.createElement('script'); " \
+ "ga.type = 'text/javascript'; ga.async = true;\n" \
+ " ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + " \
+ "'.google-analytics.com/ga.js';\n" \
+ " var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n" \
+ " })();\n" \
+ " </script>\n"
+
+
+# Files not referenced in any qdoc file.
+# See also extraimages.HTML
+qhp.QtCreator.extraFiles = index.html \
+ images/bg_l.png \
+ images/bg_l_blank.png \
+ images/bg_ll_blank.png \
+ images/bg_ul_blank.png \
+ images/header_bg.png \
+ images/bg_r.png \
+ images/box_bg.png \
+ images/breadcrumb.png \
+ images/bullet_gt.png \
+ images/bullet_dn.png \
+ images/bullet_sq.png \
+ images/bullet_up.png \
+ images/arrow_down.png \
+ images/feedbackground.png \
+ images/horBar.png \
+ images/page.png \
+ images/page_bg.png \
+ images/sprites-combined.png \
+ images/spinner.gif \
+ images/qtcreator-screenshots.png \
+ scripts/functions.js \
+ scripts/jquery.js \
+ scripts/narrow.js \
+ scripts/superfish.js \
+ style/narrow.css \
+ style/superfish.css \
+ style/style_ie6.css \
+ style/style_ie7.css \
+ style/style_ie8.css \
+ style/style.css
diff --git a/doc/config/qt-html-templates.qdocconf b/doc/config/qt-html-templates.qdocconf
new file mode 100644
index 000000000..12f207a85
--- /dev/null
+++ b/doc/config/qt-html-templates.qdocconf
@@ -0,0 +1,56 @@
+include(qt-html-default-styles.qdocconf)
+
+HTML.postheader = \
+ "<div class=\"header\" id=\"qtdocheader\">\n" \
+ " <div class=\"content\"> \n" \
+ " <a href=\"index.html\" class=\"qtref\"><span>Qbs Documentation</span></a>\n" \
+ " </div>\n" \
+ " <div class=\"breadcrumb\">\n" \
+ " <ul>\n" \
+ " <li class=\"first\"><a href=\"index.html\">Home</a></li>\n" \
+ " <!-- Breadcrumbs go here -->\n"
+
+HTML.postpostheader = \
+ "\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ "</div>\n" \
+ "<div class=\"content mainContent\">\n"
+
+HTML.footer = \
+ " <div class=\"ft\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ "</div> \n" \
+ "<div class=\"footer\">\n" \
+ " <p>\n" \
+ " <acronym title=\"Copyright\">&copy;</acronym> 2008-2012 Nokia Corporation and/or its\n" \
+ " subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation \n" \
+ " in Finland and/or other countries worldwide.</p>\n" \
+ " <p>\n" \
+ " All other trademarks are property of their respective owners. <a title=\"Privacy Policy\"\n" \
+ " href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \
+ " <br />\n" \
+ " <p>\n" \
+ " Licensees holding valid Qt Commercial licenses may use this document in accordance with the" \
+ " Qt Commercial License Agreement provided with the Software or, alternatively, in accordance" \
+ " with the terms contained in a written agreement between you and Nokia.</p>\n" \
+ " <p>\n" \
+ " Alternatively, this document may be used under the terms of the <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU\n" \
+ " Free Documentation License version 1.3</a>\n" \
+ " as published by the Free Software Foundation.</p>\n" \
+ "</div>\n" \
+
+# Files not referenced in any qdoc file.
+# See also extraimages.HTML
+qhp.QtCreator.extraFiles = index.html \
+ images/arrow_down.png \
+ images/breadcrumb.png \
+ images/bullet_gt.png \
+ images/bullet_dn.png \
+ images/bullet_sq.png \
+ images/bullet_up.png \
+ images/horBar.png \
+ images/sprites-combined.png \
+ images/qtcreator-screenshots.png \
+ style/offline.css
diff --git a/doc/doc.pri b/doc/doc.pri
new file mode 100644
index 000000000..bbb6bea69
--- /dev/null
+++ b/doc/doc.pri
@@ -0,0 +1,60 @@
+defineReplace(targetPath) {
+ return($$replace(1, /, $$QMAKE_DIR_SEP))
+}
+
+QDOC_BIN = $$targetPath($$[QT_INSTALL_BINS]/qdoc3)
+HELPGENERATOR = $$targetPath($$[QT_INSTALL_BINS]/qhelpgenerator)
+
+VERSION_TAG = $$replace(QBS_VERSION, "[-.]", )
+
+equals(QMAKE_DIR_SEP, /) { # unix, mingw+msys
+ QDOC = SRCDIR=$$PWD OUTDIR=$$OUT_PWD/doc/html QTC_VERSION=$$QBS_VERSION QTC_VERSION_TAG=$$VERSION_TAG $$QDOC_BIN
+} else:win32-g++* { # just mingw
+ # The lack of spaces in front of the && is necessary!
+ QDOC = set SRCDIR=$$PWD&& set OUTDIR=$$OUT_PWD/doc/html&& set QTC_VERSION=$$QBS_VERSION&& set QTC_VERSION_TAG=$$VERSION_TAG&& $$QDOC_BIN
+} else { # nmake
+ QDOC = set SRCDIR=$$PWD $$escape_expand(\\n\\t) \
+ set OUTDIR=$$OUT_PWD/doc/html $$escape_expand(\\n\\t) \
+ set QTC_VERSION=$$QBS_VERSION $$escape_expand(\\n\\t) \
+ set QTC_VERSION_TAG=$$VERSION_TAG $$escape_expand(\\n\\t) \
+ $$QDOC_BIN
+}
+
+QHP_FILE = $$OUT_PWD/doc/html/qbs.qhp
+QCH_FILE = $$OUT_PWD/doc/qbs.qch
+
+HELP_DEP_FILES = $$PWD/qbs.qdoc \
+ $$PWD/config/compat.qdocconf \
+ $$PWD/config/macros.qdocconf \
+ $$PWD/config/qt-cpp-ignore.qdocconf \
+ $$PWD/config/qt-defines.qdocconf \
+ $$PWD/config/qt-html-templates.qdocconf \
+ $$PWD/config/qt-html-default-styles.qdocconf \
+ $$PWD/qbs.qdocconf
+
+html_docs.commands = $$QDOC $$PWD/qbs.qdocconf
+html_docs.depends += $$HELP_DEP_FILES
+html_docs.files = $$QHP_FILE
+
+html_docs_online.commands = $$QDOC $$PWD/qbs-online.qdocconf
+html_docs_online.depends += $$HELP_DEP_FILES
+
+qch_docs.commands = $$HELPGENERATOR -o \"$$QCH_FILE\" $$QHP_FILE
+qch_docs.depends += html_docs
+qch_docs.files = $$QCH_FILE
+
+unix:!macx {
+ qch_docs.path = /share/doc/qbs
+ qch_docs.CONFIG += no_check_exist
+ INSTALLS += qch_docs
+}
+
+docs_online.depends = html_docs_online
+docs.depends = qch_docs
+QMAKE_EXTRA_TARGETS += html_docs html_docs_online qch_docs docs docs_online
+
+fixnavi.commands = \
+ cd $$targetPath($$PWD) && \
+ perl fixnavi.pl -Dqcmanual -Dqtquick \
+ qbs.qdoc
+QMAKE_EXTRA_TARGETS += fixnavi
diff --git a/doc/fixnavi.pl b/doc/fixnavi.pl
new file mode 100644
index 000000000..1d9d76d5a
--- /dev/null
+++ b/doc/fixnavi.pl
@@ -0,0 +1,144 @@
+#! /usr/bin/perl -w
+
+use strict;
+
+my @files = ();
+my %defines = ();
+for (@ARGV) {
+ if (/^-D(.*)$/) {
+ $defines{$1} = 1;
+ } elsif (/^-/) {
+ printf STDERR "Unknown option '".$_."'\n";
+ exit 1;
+ } else {
+ push @files, $_;
+ }
+}
+
+int(@files) or die "usage: $0 [-D<define>]... <qdoc-file>\n";
+
+my @toc = ();
+my %title2page = ();
+my $doctitle = "";
+my $curpage = "";
+my $intoc = 0;
+my %prev_skips = ();
+my %next_skips = ();
+my %define_skips = ();
+my %polarity_skips = ();
+my $prev_skip = "";
+my $next_skip = "";
+my $define_skip = "";
+my $polarity_skip = 0;
+for my $file (@files) {
+ my $skipping = 0; # no nested ifs!
+ open FILE, $file or die "File $file cannot be opened.\n";
+ while (<FILE>) {
+ if (/^\h*\\if\h+defined\h*\(\h*(\H+)\h*\)/) {
+ $skipping = !defined($defines{$1});
+ if (!$intoc) {
+ $define_skip = $1;
+ $polarity_skip = $skipping;
+ }
+ } elsif (/^\h*\\else/) {
+ $skipping = 1 - $skipping;
+ } elsif (/^\h*\\endif/) {
+ $skipping = 0;
+ } elsif (keys(%title2page) == 1 && /^\h*\\list/) {
+ $intoc++;
+ } elsif (!$intoc) {
+ if ($skipping && /^\h*\\previouspage\h+(\H+)/) {
+ $prev_skip = $1;
+ } elsif ($skipping && /^\h*\\nextpage\h+(\H+)/) {
+ $next_skip = $1;
+ } elsif (/^\h*\\page\h+(\H+)/) {
+ $curpage = $1;
+ } elsif (/^\h*\\title\h+(.+)$/) {
+ if ($curpage eq "") {
+ die "Title '$1' appears in no \\page.\n";
+ }
+ if (length($define_skip)) {
+ $define_skips{$1} = $define_skip;
+ $polarity_skips{$1} = $polarity_skip;
+ $prev_skips{$1} = $prev_skip;
+ $next_skips{$1} = $next_skip;
+ $define_skip = $prev_skip = $next_skip = "";
+ }
+ $title2page{$1} = $curpage;
+ $doctitle = $1 if (!$doctitle);
+ $curpage = "";
+ }
+ } else {
+ if (/^\h*\\endlist/) {
+ $intoc--;
+ } elsif (!$skipping && /^\h*\\o\h+\\l\h*{(.*)}$/) {
+ push @toc, $1;
+ }
+ }
+ }
+ close FILE;
+}
+
+my %prev = ();
+my %next = ();
+my $last = $doctitle;
+for my $title (@toc) {
+ $next{$last} = $title2page{$title};
+ $prev{$title} = $title2page{$last};
+ $last = $title;
+}
+
+for my $file (@files) {
+ open IN, $file or die "File $file cannot be opened a second time?!\n";
+ open OUT, '>'.$file.".out" or die "File $file.out cannot be created.\n";
+ my $cutting = 0;
+ while (<IN>) {
+ if (!$cutting) {
+ if (/^\h*\\contentspage/) {
+ $cutting = 1;
+ }
+ } else {
+ if (/^\h*\\title\h+(.+)$/) {
+ if (defined($define_skips{$1})) {
+ print OUT " \\if defined(".$define_skips{$1}.")\n";
+ if ($polarity_skips{$1}) {
+ print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1});
+ print OUT " \\else\n";
+ }
+ }
+ print OUT " \\previouspage ".$prev{$1} if ($prev{$1});
+ if (defined($define_skips{$1})) {
+ if (!$polarity_skips{$1}) {
+ print OUT " \\else\n";
+ print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1});
+ }
+ print OUT " \\endif\n";
+ }
+ print OUT " \\page ".$title2page{$1};
+ if (defined($define_skips{$1})) {
+ print OUT " \\if defined(".$define_skips{$1}.")\n";
+ if ($polarity_skips{$1}) {
+ print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1});
+ print OUT " \\else\n";
+ }
+ }
+ print OUT " \\nextpage ".$next{$1} if ($next{$1});
+ if (defined($define_skips{$1})) {
+ if (!$polarity_skips{$1}) {
+ print OUT " \\else\n";
+ print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1});
+ }
+ print OUT " \\endif\n";
+ }
+ print OUT "\n";
+ $cutting = 0;
+ } else {
+ next;
+ }
+ }
+ print OUT $_;
+ }
+ close OUT;
+ close IN;
+ rename($file.".out", $file) or die "Cannot replace $file with new version.\n";
+}
diff --git a/doc/qbs-online.qdocconf b/doc/qbs-online.qdocconf
new file mode 100644
index 000000000..3cf115a18
--- /dev/null
+++ b/doc/qbs-online.qdocconf
@@ -0,0 +1,4 @@
+# Run qdoc from the directory that contains this file.
+include(config/qbs-project.qdocconf)
+include(config/qt-html-templates-online.qdocconf)
+
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
new file mode 100644
index 000000000..90b8834cc
--- /dev/null
+++ b/doc/qbs.qdoc
@@ -0,0 +1,770 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// **********************************************************************
+// NOTE: the sections are not ordered by their logical order to avoid
+// reshuffling the file each time the index order changes (i.e., often).
+// Run the fixnavi.pl script to adjust the links to the index order.
+// **********************************************************************
+
+
+/*!
+ \contentspage{index.html}{Qt Build Suite}
+ \page index.html
+ \nextpage qbs-overview.html
+
+ \title Qbs Manual
+
+ \section1 Version \qtcversion
+
+ Qt Build Suite (qbs) is a tool that helps simplify the build process for
+ developing projects across multiple platforms. Qbs can be used for any
+ software project, whether it is written in Qt or not.
+
+ Qbs is an all-in-one tool that generates a build graph from a high-level
+ project description (like qmake or cmake) and additionally undertakes the
+ task of executing the commands in the low-level build graph (like make).
+
+ \note Please report bugs and suggestions to the
+ \l{http://bugreports.qt-project.com/}{Qt Bug Tracker}.
+
+ \list
+ \o \l{Introducing Qbs}
+ \o \l{Setting Up Qbs}
+ \list
+ \o \l{System Requirements}
+ \o \l{Building Qbs}
+ \o \l{Configuring Qbs}
+ \endlist
+ \o \l{Using Qbs}
+ \list
+ \o \l{Language Introduction}
+ \o \l{Building Applications with Qbs}
+ \o \l{Running Applications}
+ \o \l{Using Qbs Graph}
+ \o \l{Using Qbs Shell}
+ \endlist
+ \o \l{Reference}
+ \list
+ \o \l{Qbs Functions}
+ \o \l{Rules}
+ \endlist
+ \endlist
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage index.html
+ \page qbs-overview.html
+ \nextpage qbs-setup.html
+
+ \title Introducing Qbs
+
+ Qbs builds applications based on the information in a project file that you
+ specify in a QML dialect. Each project file specifies one project that can
+ contain several products. You specify the type of the product: application,
+ library, and so on.
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-overview.html
+ \page qbs-setup.html
+ \nextpage qbs-system-requirements.html
+
+ \title Setting Up Qbs
+
+ \list
+ \o \l{System Requirements}
+ \o \l{Building Qbs}
+ \o \l{Configuring Qbs}
+ \endlist
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-setup.html
+ \page qbs-system-requirements.html
+ \nextpage qbs-building.html
+
+ \title System Requirements
+
+ To build Qbs from the source, you need the following:
+
+ \list
+
+ \o Qt 4.7
+
+ \endlist
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-system-requirements.html
+ \page qbs-building.html
+ \nextpage qbs-configuring.html
+
+ \title Building Qbs
+
+ To build Qbs:
+
+ \list 1
+
+ \o Enter the following command:
+ \c {qmake -r qbs.pro && make}
+
+ \endlist
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-building.html
+ \page qbs-configuring.html
+ \nextpage qbs-usage.html
+
+ \title Configuring Qbs
+
+ When you run Qbs from an in-source build most paths are set up
+ automatically. If you do not build in-source, configure the following
+ paths:
+
+ \code
+ QBS_SOURCE_DIR=/path/to/qbs-source
+ QBS_BUILD_DIR=/path/to/qbs-build
+ qbs config --global paths/cubes $QBS_SOURCE_DIR/share/qbs
+ qbs config --global paths/plugins $QBS_BUILD_DIR/plugins
+ \endcode
+
+ Currently, you also must tell qbs where it can find Qt.
+ Qt installations are grouped by a free form name, like in Qt Creator.
+ The default Qt installation name is "default".
+
+ \code
+ qbs config --global qt/default/path /home/icke/dev/qt/4.7-build
+ \endcode
+
+ This is the case where the bin, include, lib and mkspecs directories
+ of your Qt build are below the qtPath. This is usually the case on Windows
+ or if you build Qt yourself without installing it.
+ For installed Qt versions we need to set up some more paths.
+ Here's an example for registering an Qt, installed on Ubuntu GNU/Linux:
+
+ \code
+ qbs config --global qt/default/binPath /usr/bin
+ qbs config --global qt/default/incPath /usr/include/qt4
+ qbs config --global qt/default/libPath /usr/lib/x86_64-linux-gnu
+ qbs config --global qt/default/mkspecsPath /usr/share/qt4/mkspecs
+ \endcode
+
+ If you have built your Qt with the option -qtnamespace MyNamespace
+ then you must set the following config value.
+
+ \code
+ qbs config --global qt/default/namespace MyNamespace
+ \endcode
+
+ Now open a build shell (on Windows open a MSVC command prompt,
+ on other platforms the default shell is usually ok):
+ \code
+ qbs platforms probe
+ \endcode
+
+ You will be prompted to enter a name for a new platform.
+ For your desktop build environment choose "desktop".
+ This will be used as default build platform.
+
+ Now you should be ready to build your first project with qbs.
+ Go into qbs/tests/manual/hello and type
+
+ \code
+ qbs
+ \endcode
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-configuring.html
+ \page qbs-usage.html
+ \nextpage qbs-language-introduction.html
+
+ \title Using Qbs
+
+ \list
+ \o \l{Language Introduction}
+ \o \l{Building Applications with Qbs}
+ \o \l{Running Applications}
+ \o \l{Using Qbs Graph}
+ \o \l{Using Qbs Shell}
+ \endlist
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-usage.html
+ \page qbs-language-introduction.html
+ \nextpage qbs-building-applications.html
+
+ \title Language Introduction
+
+ Qbs uses project files (*.qbp) to describe the contents of a project.
+ A project contains one or more products. A product is the target of a build
+ process, typically an application, library or maybe a tar ball.
+
+ \section1 The obligatory Hello World example
+
+ These project files are written using a QML dialect.
+ A very simple C++ hello world project looks like this:
+ \code ---helloworld.qbp---
+ import qbs.base 1.0
+
+ Application {
+ name: "helloworld"
+ files: "main.cpp"
+ Depends { name: "cpp" }
+ }
+ \endcode
+
+ The import statement gives us access to some inbuilt types and specifies the
+ used language version.
+
+ \a Application describes a product we want to build. In this case an
+ application. This is just a short cut for writing
+ \code
+ Product {
+ type: "application"
+ // ...
+ }
+ \endcode
+
+ The \a name obviously is the name of the product and in this case is also the
+ name of the produced executable.
+ In the property \a files we specify the source files for our product.
+ Unlike QML the right hand side can be either a string or a string list.
+ A single string is converted to a stringlist containing just one element.
+
+ \a Depends adds the dependency to the module \a{cpp} (see below for an
+ explanation of qbs modules).
+ This is necessary to let qbs know that we're having a C++ project and want
+ to compile main.cpp with a C++ compiler.
+
+
+ \section1 Reusing qbs project file code
+ QML-like inheritance is also working in qbs.
+
+ \code
+ ---CrazyProduct.qbs---
+ import qbs.base 1.0
+
+ Product {
+ property string craziness: "low"
+ }
+
+ ---hellocrazyworld.qbp---
+ CrazyProduct {
+ craziness: "enormous"
+ name: "hellocrazyworld"
+ // ...
+ }
+ \endcode
+
+ You can put JS code into separate \c{.js} files and then import then.
+ \code
+ ---helpers.js---
+ function planetsCorrectlyAligned()
+ {
+ // implementation
+ }
+
+ ---myproject.qbs---
+ import qbs.base 1.0
+ import "helpers.js" as Helpers
+
+ Product {
+ name: "myproject"
+ Group {
+ condition: Helpers.planetsCorrectlyAligned()
+ file: "magic_hack.cpp"
+ }
+ // ...
+ }
+ \endcode
+
+
+ \section1 Modules
+
+ So what are these "modules"?
+ A module is a collection of properties and language items that are used for
+ building a product, if the product depends on (or loads) the module.
+
+ For example the \a cpp module looks like this (simplified):
+ \code
+ Module {
+ name: "cpp"
+ property string warningLevel
+ property string optimization
+ property bool debugInformation
+ property string precompiledHeader
+ // ...
+ FileTagger {
+ pattern: "*.cpp"
+ fileTags: ["cpp"]
+ }
+ Rule {...} // compiler
+ Rule {...} // application linker
+ Rule {...} // static lib linker
+ Rule {...} // dynamic lib linker
+ }
+ \endcode
+
+ What we see here is a bunch of properties that can be set for the \a cpp
+ module. These are used to control the behaviour of your C++ toolchain.
+ Also we have things like FileTaggers and Rules. These are covered later.
+
+ As soon as your product depends on a module it can set properties of this
+ module. This is how you specify the optimization level for your product (and
+ all build variants):
+
+ \code ---helloworld.qbp---
+ import qbs.base 1.0
+
+ Application {
+ name: "helloworld"
+ files: ["main.cpp"]
+ cpp.optimization: "ludicrousSpeed"
+ Depends { name: "cpp" }
+ }
+ \endcode
+
+ A module can implicitly depend on other modules. E.g. the \c Qt.core module depends
+ on \c{cpp}. But to set properties of a module you must explicitly import
+ it.
+
+ \code
+ // DOES NOT WORK
+ Application {
+ name: "helloworld"
+ files: ["main.cpp"]
+ Depends { name: "Qt.core" }
+ cpp.optimization: "ludicrousSpeed"
+ // ERROR! We don't know about "cpp" here,
+ // though "Qt.core" depends on "cpp".
+ }
+
+ // THIS IS WORKING
+ Application {
+ name: "helloworld"
+ files: ["main.cpp"]
+ Depends { name: "Qt.core" }
+ Depends { name: "cpp" }
+ cpp.optimization: "ludicrousSpeed"
+ }
+ \endcode
+
+ \section2 Different properties for a single file
+
+ Not only the product but all source files of the product can have their own
+ set of module properties. For example you have a file that's known to crash
+ your compiler if you turn on optimizations. You want to turn off
+ optimizations for just this file and this is how you do it:
+
+ \code
+ Application {
+ name: "helloworld"
+ files: "main.cpp"
+ Group {
+ files: "bad_file.cpp"
+ cpp.optimization: "none"
+ }
+ Depends { name: "cpp" }
+ }
+ \endcode
+
+ With a group you can set the properties of a whole set of files, not just
+ single ones.
+
+ \section2 Selecting files by properties
+
+ The classical (pre-lighthouse) Qt case: you have a file that's only going to
+ be compiled on a certain platform. This is how you do it:
+ \code
+ Group {
+ condition: qbs.target == "windows"
+ files: [
+ "harddiskdeleter_win.cpp",
+ "blowupmonitor_win.cpp",
+ "setkeyboardonfire_win.cpp"
+ ]
+ }
+ Group {
+ condition: qbs.target == "linux"
+ files: [
+ "harddiskdeleter_linux.cpp",
+ "blowupmonitor_linux.cpp",
+ "setkeyboardonfire_linux.cpp"
+ ]
+ }
+ \endcode
+
+ That odd \a qbs.target thingy is the property \a target of the module \a
+ qbs. The module \a qbs is always implicitly loaded. Its main properties
+ are:
+
+ \table
+ \header
+ \o Property
+ \o Type
+ \o Default
+ \o Description
+ \row
+ \o buildVariant
+ \o string
+ \o "debug"
+ \o Name of the current build variant. By default "debug" and "release"
+ are valid values but the user can add more in a project file.
+ \row
+ \o host
+ \o string
+ \o platform-dependent
+ \o The host platform. Currently "windows", "linux" or "mac".
+ \row
+ \o target
+ \o string
+ \o platform-dependent
+ \o The target platform. Currently "windows", "linux", "mac" or
+ "ponyphone".
+ \endtable
+
+ You can set these properties on the command line. Property \a
+ qbs.buildVariant is handled in a special way.
+
+ \code
+ $ qbs # qbs.buildVariant:debug, qbs.target:qbs.host
+ $ qbs release # qbs.buildVariant:release, qbs.target:qbs.host
+ $ qbs target:ponyphone # qbs.buildVariant:debug, qbs.target:ponyphone
+ $ qbs debug release # builds two variants of the project
+ \endcode
+
+ So if you want to select files by build variant, this is how you do it:
+ \code
+ Group {
+ condition: qbs.buildVariant == "debug"
+ files: "debughelper.cpp"
+ }
+ \endcode
+
+ Setting properties for a build variant goes like this:
+ \code
+ Properties {
+ condition: qbs.buildVariant == "debug"
+ cpp.debugInformation: "on"
+ cpp.optimization: "none"
+ }
+ \endcode
+ or more QML style:
+ \code
+ cpp.debugInformation: qbs.buildVariant == "debug" ? "on" : "off"
+ cpp.optimization: qbs.buildVariant == "debug" ? "none" : "fast"
+ \endcode
+
+
+ \section1 File tags and taggers
+
+ Qbs knows nothing about C++ files or its file extensions. All source file
+ in a product are handled equally. There's the concept of a \a{file tag},
+ which is basically a marker or a type that can be assigned to an artifact.
+
+ An artifact can have multiple file tags.
+ Use the \a Group item to group files with the same file tags (and/or set of
+ properties).
+
+ Example:
+ \code
+ Product {
+ Group {
+ files: ["file1.cpp", "file2.cpp"]
+ fileTags: ["cpp"]
+ }
+ Group {
+ files: "mydsl_scanner.l"
+ fileTags: ["flex", "foobar"]
+ }
+ // ...
+ }
+ \endcode
+
+ When you load the \a cpp module then you also load the following item:
+ \code
+ FileTagger {
+ pattern: "*.cpp"
+ fileTags: ["cpp"]
+ }
+ \endcode
+ This thing means that every source file that matches the glob *.cpp (and
+ hasn't explicitly set a file tag) gets the file tag \c{cpp}.
+
+ The above example can be simplified to
+ \code
+ Product {
+ Depends: "cpp"
+ files: ["file1.cpp", "file2.cpp"]
+ Group {
+ files: "mydsl_scanner.l"
+ fileTags: ["flex", "foobar"]
+ }
+ // ...
+ }
+ \endcode
+
+ The \a FileTagger from the \a cpp module automatically assigns the \c cpp
+ file tag to the source files. Groups that just contain the \a files
+ property can be simply expressed by using the \a files property of the product.
+
+ File tags are used by \a rules to transform one type of artifact into
+ another. E.g. the C++ compiler rule transforms artifacts with the file tag
+ \c cpp to artifacts with the file tag \c{obj}.
+
+ \section1 Rules
+
+ A rule looks at the pool of artifacts (in the beginning it's just the set of
+ source files of the project) and chooses the ones that match its input file
+ tags. Then it creates output artifacts in the build graph that have other
+ filenames and file tags. It also creates a transformer which is basically a
+ script that, well, transforms the input artifact into the output artifact.
+
+ For examples of rules see the share/qbs/modules directory in the qbs
+ repository.
+
+ You can define rules in your own module, which can be provided along with
+ your project. Or you can put a rule directly into your project file.
+
+ Rules reference: \l{Rules}.
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-language-introduction.html
+ \page qbs-building-applications.html
+ \nextpage qbs-running-applications.html
+
+ \title Building Applications with Qbs
+
+ To build applications from the command line, enter the following commands:
+
+ \code
+ cd tests/manual/collidingmice
+ qbs
+ \endcode
+
+ The application is built for the default target, which is the system on the
+ development PC. To build for other targets, specify options for the build
+ command. For example, to build debug and release configurations for the
+ default target and the Symbian target in parallel, enter the following
+ command:
+
+ \code
+ qbs build debug release target:symbian
+ \endcode
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-building-applications.html
+ \page qbs-running-applications.html
+ \nextpage qbs-graph.html
+
+ \title Running Applications
+
+ Running ./targets/debug/CollidingMice fails if Qt 4.8 is not in your PATH
+ (in Windows) or LD_LIBRARY_PATH (in Linux).
+
+ Therefore, enter the following command:
+
+ \code
+ qbs run CollidingMice
+ \endcode
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-running-applications.html
+ \page qbs-graph.html
+ \nextpage qbs-shell.html
+
+ \title Using Qbs Graph
+
+ Qbs uses a very simple graph drawing algorithm to visualize the
+ build graph.
+
+ This is currently mostly used to debug Qbs.
+
+ Download and install dot and add it to the system PATH.
+
+ To visualize the project structure, enter the following command:
+
+ \code
+ qbs graph
+ \endcode
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-graph.html
+ \page qbs-shell.html
+ \nextpage qbs-reference.html
+
+ \title Using Qbs Shell
+
+ \code
+ qbs shell
+ \endcode
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-shell.html
+ \page qbs-reference.html
+ \nextpage qbs-functions.html
+
+ \title Reference
+
+ \list
+ \o \l{Qbs Functions}
+ \o \l{Rules}
+ \endlist
+
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-functions.html
+ \page qbs-rules.html
+
+ \title Rules
+
+ A "multiplex rule" creates one transformer that takes all
+ input artifacts with the matching input file tag and creates
+ one or more artifacts (e.g. C++ linker).
+ A "non-multiplex rule" creates one transformer per matching input file (e.g. C++
+ compiler).
+
+ \section1 Rule properties
+
+ \table
+ \header
+ \o Property
+ \o Type
+ \o Default
+ \o Description
+ \row
+ \o multiplex
+ \o bool
+ \o false
+ \o Determines if this is a multiplex rule.
+ \row
+ \o inputs
+ \o string list
+ \o undefined
+ \o File tags the input artifacts must match.
+ All output artifacts will depend on all artifacts in the product with
+ the given input file tags. Also these artifacts are available in the
+ inputs variable of the prepare script.
+ \row
+ \o usings
+ \o string list
+ \o undefined
+ \o File tags the artifacts of product dependencies must match.
+ Let there be a product \a foo which appears as
+ \code
+ Depends {
+ name: "foo"
+ }
+ \endcode
+ in the current product. All artifacts of \a foo that match the given
+ file tags will appear in the \a inputs variable of the prepare
+ script. Also, every output artifact of this rule will be dependent on
+ those artifacts.
+ \row
+ \o explicitlyDependsOn
+ \o string list
+ \o undefined
+ \o Every artifact that matches the file tags in \a explicitlyDependsOn
+ is added to the dependencies of every output node.
+ \row
+ \o scanners
+ \o string list
+ \o undefined
+ \o List of dependency scanner ids for this rule. The scanners are
+ running just before the prepare script is executed.
+ \row
+ \o prepare
+ \o script
+ \o undefined
+ \o Script that prepares the commands to transform the inputs to outputs.
+ \endtable
+
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage qbs-reference.html
+ \page qbs-functions.html
+ \nextpage qbs-rules.html
+
+ \title Qbs Functions
+
+*/
+
diff --git a/doc/qbs.qdocconf b/doc/qbs.qdocconf
new file mode 100644
index 000000000..516d4e796
--- /dev/null
+++ b/doc/qbs.qdocconf
@@ -0,0 +1,3 @@
+# Run qdoc from the directory that contains this file.
+include(config/qbs-project.qdocconf)
+include(config/qt-html-templates.qdocconf)
diff --git a/doc/templates/images/arrow_down.png b/doc/templates/images/arrow_down.png
new file mode 100644
index 000000000..9d01e97f6
--- /dev/null
+++ b/doc/templates/images/arrow_down.png
Binary files differ
diff --git a/doc/templates/images/bg_l.png b/doc/templates/images/bg_l.png
new file mode 100644
index 000000000..90b1da10b
--- /dev/null
+++ b/doc/templates/images/bg_l.png
Binary files differ
diff --git a/doc/templates/images/bg_l_blank.png b/doc/templates/images/bg_l_blank.png
new file mode 100644
index 000000000..5a9673d81
--- /dev/null
+++ b/doc/templates/images/bg_l_blank.png
Binary files differ
diff --git a/doc/templates/images/bg_ll_blank.png b/doc/templates/images/bg_ll_blank.png
new file mode 100644
index 000000000..95a1c45e0
--- /dev/null
+++ b/doc/templates/images/bg_ll_blank.png
Binary files differ
diff --git a/doc/templates/images/bg_r.png b/doc/templates/images/bg_r.png
new file mode 100644
index 000000000..f0fb121de
--- /dev/null
+++ b/doc/templates/images/bg_r.png
Binary files differ
diff --git a/doc/templates/images/bg_ul_blank.png b/doc/templates/images/bg_ul_blank.png
new file mode 100644
index 000000000..70512614c
--- /dev/null
+++ b/doc/templates/images/bg_ul_blank.png
Binary files differ
diff --git a/doc/templates/images/box_bg.png b/doc/templates/images/box_bg.png
new file mode 100644
index 000000000..3322f923f
--- /dev/null
+++ b/doc/templates/images/box_bg.png
Binary files differ
diff --git a/doc/templates/images/breadcrumb.png b/doc/templates/images/breadcrumb.png
new file mode 100644
index 000000000..0ded5514d
--- /dev/null
+++ b/doc/templates/images/breadcrumb.png
Binary files differ
diff --git a/doc/templates/images/bullet_dn.png b/doc/templates/images/bullet_dn.png
new file mode 100644
index 000000000..f7762472e
--- /dev/null
+++ b/doc/templates/images/bullet_dn.png
Binary files differ
diff --git a/doc/templates/images/bullet_gt.png b/doc/templates/images/bullet_gt.png
new file mode 100644
index 000000000..7561b4edc
--- /dev/null
+++ b/doc/templates/images/bullet_gt.png
Binary files differ
diff --git a/doc/templates/images/bullet_sq.png b/doc/templates/images/bullet_sq.png
new file mode 100644
index 000000000..a84845e3c
--- /dev/null
+++ b/doc/templates/images/bullet_sq.png
Binary files differ
diff --git a/doc/templates/images/bullet_up.png b/doc/templates/images/bullet_up.png
new file mode 100644
index 000000000..7de2f0695
--- /dev/null
+++ b/doc/templates/images/bullet_up.png
Binary files differ
diff --git a/doc/templates/images/feedbackground.png b/doc/templates/images/feedbackground.png
new file mode 100644
index 000000000..3a38d995d
--- /dev/null
+++ b/doc/templates/images/feedbackground.png
Binary files differ
diff --git a/doc/templates/images/header.png b/doc/templates/images/header.png
new file mode 100644
index 000000000..3c68d9c52
--- /dev/null
+++ b/doc/templates/images/header.png
Binary files differ
diff --git a/doc/templates/images/header_bg.png b/doc/templates/images/header_bg.png
new file mode 100644
index 000000000..a436aa61e
--- /dev/null
+++ b/doc/templates/images/header_bg.png
Binary files differ
diff --git a/doc/templates/images/horBar.png b/doc/templates/images/horBar.png
new file mode 100644
index 000000000..100fe91c6
--- /dev/null
+++ b/doc/templates/images/horBar.png
Binary files differ
diff --git a/doc/templates/images/page.png b/doc/templates/images/page.png
new file mode 100644
index 000000000..1db151bd3
--- /dev/null
+++ b/doc/templates/images/page.png
Binary files differ
diff --git a/doc/templates/images/page_bg.png b/doc/templates/images/page_bg.png
new file mode 100644
index 000000000..9b3bd999d
--- /dev/null
+++ b/doc/templates/images/page_bg.png
Binary files differ
diff --git a/doc/templates/images/qt_icon.png b/doc/templates/images/qt_icon.png
new file mode 100644
index 000000000..fbaee3584
--- /dev/null
+++ b/doc/templates/images/qt_icon.png
Binary files differ
diff --git a/doc/templates/images/spinner.gif b/doc/templates/images/spinner.gif
new file mode 100644
index 000000000..1ed786f2e
--- /dev/null
+++ b/doc/templates/images/spinner.gif
Binary files differ
diff --git a/doc/templates/images/sprites-combined.png b/doc/templates/images/sprites-combined.png
new file mode 100644
index 000000000..3a48b21f6
--- /dev/null
+++ b/doc/templates/images/sprites-combined.png
Binary files differ
diff --git a/doc/templates/scripts/functions.js b/doc/templates/scripts/functions.js
new file mode 100644
index 000000000..faa4ca493
--- /dev/null
+++ b/doc/templates/scripts/functions.js
@@ -0,0 +1,194 @@
+/* START non link areas where cursor should change to pointing hand */
+$('.t_button').mouseover(function() {
+ $('.t_button').css('cursor','pointer');
+ /*document.getElementById(this.id).style.cursor='pointer';*/
+});
+/* END non link areas */
+$('#smallA').click(function() {
+ $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('font-size','smaller');
+ $('.t_button').removeClass('active')
+ $(this).addClass('active')
+});
+
+$('#medA').click(function() {
+ $('.content .heading').css('font','600 16px/1 Arial');
+ $('.content h1').css('font','600 18px/1.2 Arial');
+ $('.content h2').css('font','600 16px/1.2 Arial');
+ $('.content h3').css('font','600 14px/1.2 Arial');
+ $('.content p').css('font','13px/20px Verdana');
+ $('.content li').css('font','400 13px/1 Verdana');
+ $('.content li').css('line-height','14px');
+ $('.content .toc li').css('font', 'normal 10px/1.2 Verdana');
+ $('.content table').css('font','13px/1.2 Verdana');
+ $('.content .heading').css('font','600 16px/1 Arial');
+ $('.content .indexboxcont li').css('font','600 13px/1 Verdana');
+ $('.t_button').removeClass('active')
+ $(this).addClass('active')
+});
+
+$('#bigA').click(function() {
+ $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('font-size','large');
+ $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('line-height','25px');
+ $('.t_button').removeClass('active')
+ $(this).addClass('active')
+});
+
+$('.feedclose').click(function() {
+ $('.bd').show();
+ $('.hd').show();
+ $('.footer').show();
+ $('#feedbackBox').hide();
+ $('#blurpage').hide();
+});
+
+$('.feedback').click(function() {
+ $('.bd').hide();
+ $('.hd').hide();
+ $('.footer').hide();
+ $('#feedbackBox').show();
+ $('#blurpage').show();
+});
+var lookupCount = 0;
+var articleCount = 0;
+var exampleCount = 0;
+var qturl = ""; // change from "http://doc.qt.nokia.com/4.6/" to 0 so we can have relative links
+
+function processNokiaData(response){
+ var propertyTags = response.getElementsByTagName('page');
+
+ for (var i=0; i< propertyTags.length; i++) {
+ var linkStart = "<li class=\"liveResult\"><a href='"+qturl+"";
+ var linkEnd = "</a></li>";
+
+ if(propertyTags[i].getElementsByTagName('pageType')[0].firstChild.nodeValue == 'APIPage'){
+ lookupCount++;
+
+ for (var j=0; j< propertyTags[i].getElementsByTagName('pageWords').length; j++){
+ full_li_element = linkStart + propertyTags[i].getElementsByTagName('pageUrl')[j].firstChild.nodeValue;
+ full_li_element = full_li_element + "'>" + propertyTags[i].getElementsByTagName('pageTitle')[0].firstChild.nodeValue + linkEnd;
+ $('#ul001').append(full_li_element);
+ $('#ul001 .defaultLink').css('display','none');
+
+ }
+ }
+
+ if(propertyTags[i].getElementsByTagName('pageType')[0].firstChild.nodeValue == 'Article'){
+ articleCount++;
+
+ for (var j=0; j< propertyTags[i].getElementsByTagName('pageWords').length; j++){
+ full_li_element = linkStart + propertyTags[i].getElementsByTagName('pageUrl')[j].firstChild.nodeValue;
+ full_li_element =full_li_element + "'>" + propertyTags[i].getElementsByTagName('pageTitle')[0].firstChild.nodeValue + linkEnd ;
+
+ $('#ul002').append(full_li_element);
+ $('#ul002 .defaultLink').css('display','none');
+
+ }
+ }
+ if(propertyTags[i].getElementsByTagName('pageType')[0].firstChild.nodeValue == 'Example'){
+ exampleCount++;
+
+
+ for (var j=0; j< propertyTags[i].getElementsByTagName('pageWords').length; j++){
+ full_li_element = linkStart + propertyTags[i].getElementsByTagName('pageUrl')[j].firstChild.nodeValue;
+ full_li_element =full_li_element + "'>" + propertyTags[i].getElementsByTagName('pageTitle')[0].firstChild.nodeValue + linkEnd ;
+
+ $('#ul003').append(full_li_element);
+ $('#ul003 .defaultLink').css('display','none');
+
+ }
+ }
+ if(i==propertyTags.length){$('#pageType').removeClass('loading');}
+
+ }
+ if(lookupCount > 0){$('#ul001 .menuAlert').remove();$('#ul001').prepend('<li class=\"menuAlert liveResult hit\">Found ' + lookupCount + ' hits</li>');$('#ul001 li').css('display','block');$('.sidebar .search form input').removeClass('loading');}
+ if(articleCount > 0){$('#ul002 .menuAlert').remove();$('#ul002').prepend('<li class=\"menuAlert liveResult hit\">Found ' + articleCount + ' hits</li>');$('#ul002 li').css('display','block');}
+ if(exampleCount > 0){$('#ul003 .menuAlert').remove();$('#ul003').prepend('<li class=\"menuAlert liveResult hit\">Found ' + articleCount + ' hits</li>');$('#ul003 li').css('display','block');}
+
+ if(lookupCount == 0){$('#ul001 .menuAlert').remove();$('#ul001').prepend('<li class=\"menuAlert liveResult noMatch\">Found no result</li>');$('#ul001 li').css('display','block');$('.sidebar .search form input').removeClass('loading');}
+ if(articleCount == 0){$('#ul002 .menuAlert').remove();$('#ul002').prepend('<li class=\"menuAlert liveResult noMatch\">Found no result</li>');$('#ul002 li').css('display','block');}
+ if(exampleCount == 0){$('#ul003 .menuAlert').remove();$('#ul003').prepend('<li class=\"menuAlert liveResult noMatch\">Found no result</li>');$('#ul003 li').css('display','block');}
+ // reset count variables;
+ lookupCount=0;
+ articleCount = 0;
+ exampleCount = 0;
+
+}
+//build regular expression object to find empty string or any number of blank
+var blankRE=/^\s*$/;
+function CheckEmptyAndLoadList()
+{
+ var pageUrl = window.location.href;
+ var pageVal = $('title').html();
+ $('#feedUrl').remove();
+ $('#pageVal').remove();
+ $('.menuAlert').remove();
+ $('#feedform').append('<input id="feedUrl" name="feedUrl" value="'+pageUrl+'" style="display:none;">');
+ $('#feedform').append('<input id="pageVal" name="pageVal" value="'+pageVal+'" style="display:none;">');
+ $('.liveResult').remove();
+ $('.defaultLink').css('display','block');
+ var value = document.getElementById('pageType').value;
+ if((blankRE.test(value)) || (value.length < 3))
+ {
+ //empty inputbox
+ // load default li elements into the ul if empty
+ // loadAllList(); // replaced
+ $('.defaultLink').css('display','block');
+ // $('.liveResult').css('display','none');
+ }else{
+ $('.defaultLink').css('display','none');
+ }
+}
+/*
+$(window).resize(function(){
+if($(window).width()<400)
+ $('body').addClass('offline');
+else
+ $('body').removeClass('offline');
+ });
+ */
+// Loads on doc ready
+ $(document).ready(function () {
+ //alert(pageUrl);
+ //$('#pageUrl').attr('foo',pageUrl);
+ var pageTitle = $('title').html();
+ var currentString = $('#pageType').val() ;
+ if(currentString.length < 1){
+ $('.defaultLink').css('display','block');
+ CheckEmptyAndLoadList();
+ }
+
+ $('#pageType').keyup(function () {
+ var searchString = $('#pageType').val() ;
+ if ((searchString == null) || (searchString.length < 3)) {
+ $('#pageType').removeClass('loading');
+ $('.liveResult').remove();
+ $('.searching').remove();
+ CheckEmptyAndLoadList();
+ $('.report').remove();
+ // debug$('.content').prepend('<li>too short or blank</li>'); // debug
+ return;
+ }
+ if (this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(function () {
+ $('#pageType').addClass('loading');
+ $('.searching').remove();
+ $('.list ul').prepend('<li class="menuAlert searching">Searching...</li>');
+ $.ajax({
+ contentType: "application/x-www-form-urlencoded",
+ url: 'http://' + location.host + '/nokiasearch/GetDataServlet',
+ data: 'searchString='+searchString,
+ dataType:'xml',
+ type: 'post',
+ success: function (response, textStatus) {
+
+ $('.liveResult').remove();
+ $('.searching').remove();
+ $('#pageType').removeClass('loading');
+ $('.list ul').prepend('<li class="menuAlert searching">Searching...</li>');
+ processNokiaData(response);
+
+ }
+ });
+ }, 500);
+ });
+ });
diff --git a/doc/templates/scripts/jquery.js b/doc/templates/scripts/jquery.js
new file mode 100644
index 000000000..0c7294c90
--- /dev/null
+++ b/doc/templates/scripts/jquery.js
@@ -0,0 +1,152 @@
+/*!
+ * jQuery JavaScript Library v1.4.1
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Mon Jan 25 19:43:33 2010 -0500
+ */
+(function(z,v){function la(){if(!c.isReady){try{r.documentElement.doScroll("left")}catch(a){setTimeout(la,1);return}c.ready()}}function Ma(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var n in b)X(a,n,b[n],f,e,d);return a}if(d!==v){f=!i&&f&&c.isFunction(d);for(n=0;n<j;n++)e(a[n],b,f?d.call(a[n],n,e(a[n],b)):d,i);return a}return j?
+e(a[0],b):null}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function ma(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function na(a){var b,d=[],f=[],e=arguments,i,j,n,o,m,s,x=c.extend({},c.data(this,"events").live);if(!(a.button&&a.type==="click")){for(o in x){j=x[o];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete x[o]}i=c(a.target).closest(f,
+a.currentTarget);m=0;for(s=i.length;m<s;m++)for(o in x){j=x[o];n=i[m].elem;f=null;if(i[m].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==n)d.push({elem:n,fn:j})}}m=0;for(s=d.length;m<s;m++){i=d[m];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}}function oa(a,b){return"live."+(a?a+".":"")+b.replace(/\./g,"`").replace(/ /g,"&")}function pa(a){return!a||!a.parentNode||a.parentNode.nodeType===
+11}function qa(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ra(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0&&(c.support.checkClone||!sa.test(a[0]))){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:r;f=b.createDocumentFragment();
+c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=i?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(ta.concat.apply([],ta.slice(0,b)),function(){d[this]=a});return d}function ua(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Na=z.jQuery,Oa=z.$,r=z.document,S,Pa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Qa=/^.[^:#\[\.,]*$/,Ra=/\S/,Sa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Ta=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,O=navigator.userAgent,
+va=false,P=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,Q=Array.prototype.slice,wa=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Pa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:r;if(a=Ta.exec(a))if(c.isPlainObject(b)){a=[r.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ra([d[1]],
+[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=r.getElementById(d[2])){if(b.id!==d[2])return S.find(a);this.length=1;this[0]=b}this.context=r;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=r;a=r.getElementsByTagName(a)}else return!b||b.jquery?(b||S).find(a):c(b).find(a);else if(c.isFunction(a))return S.ready(a);if(a.selector!==v){this.selector=a.selector;this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,
+this)},selector:"",jquery:"1.4.1",length:0,size:function(){return this.length},toArray:function(){return Q.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=0;ba.apply(this,a);return this},each:function(a,b){return c.each(this,
+a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(r,c);else P&&P.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(Q.apply(this,arguments),"slice",Q.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};
+c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,n;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];n=e[i];if(a!==n)if(f&&n&&(c.isPlainObject(n)||c.isArray(n))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(n)?[]:{};a[i]=c.extend(f,j,n)}else if(n!==v)a[i]=n}return a};c.extend({noConflict:function(a){z.$=
+Oa;if(a)z.jQuery=Na;return c},isReady:false,ready:function(){if(!c.isReady){if(!r.body)return setTimeout(c.ready,13);c.isReady=true;if(P){for(var a,b=0;a=P[b++];)a.call(r,c);P=null}c.fn.triggerHandler&&c(r).triggerHandler("ready")}},bindReady:function(){if(!va){va=true;if(r.readyState==="complete")return c.ready();if(r.addEventListener){r.addEventListener("DOMContentLoaded",L,false);z.addEventListener("load",c.ready,false)}else if(r.attachEvent){r.attachEvent("onreadystatechange",L);z.attachEvent("onload",
+c.ready);var a=false;try{a=z.frameElement==null}catch(b){}r.documentElement.doScroll&&a&&la()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===v||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;
+return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return z.JSON&&z.JSON.parse?z.JSON.parse(a):(new Function("return "+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Ra.test(a)){var b=r.getElementsByTagName("head")[0]||
+r.documentElement,d=r.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(r.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===v||c.isFunction(a);if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=
+a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Sa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==
+v;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=v}else if(b&&!c.isFunction(b)){d=b;b=v}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},
+uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});O=c.uaMatch(O);if(O.browser){c.browser[O.browser]=true;c.browser.version=O.version}if(c.browser.webkit)c.browser.safari=true;if(wa)c.inArray=function(a,b){return wa.call(b,a)};S=c(r);if(r.addEventListener)L=function(){r.removeEventListener("DOMContentLoaded",
+L,false);c.ready()};else if(r.attachEvent)L=function(){if(r.readyState==="complete"){r.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=r.documentElement,b=r.createElement("script"),d=r.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support=
+{leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:r.createElement("select").appendChild(r.createElement("option")).selected,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};
+b.type="text/javascript";try{b.appendChild(r.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,a.firstChild);if(z[f]){c.support.scriptEval=true;delete z[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function n(){c.support.noCloneEvent=false;d.detachEvent("onclick",n)});d.cloneNode(true).fireEvent("onclick")}d=r.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=r.createDocumentFragment();a.appendChild(d.firstChild);
+c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var n=r.createElement("div");n.style.width=n.style.paddingLeft="1px";r.body.appendChild(n);c.boxModel=c.support.boxModel=n.offsetWidth===2;r.body.removeChild(n).style.display="none"});a=function(n){var o=r.createElement("div");n="on"+n;var m=n in o;if(!m){o.setAttribute(n,"return;");m=typeof o[n]==="function"}return m};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props=
+{"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ua=0,xa={},Va={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var f=a[G],e=c.cache;if(!b&&!f)return null;f||(f=++Ua);if(typeof b==="object"){a[G]=f;e=e[f]=c.extend(true,
+{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Va:(e[f]={});if(d!==v){a[G]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[G]}catch(i){a.removeAttribute&&a.removeAttribute(G)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,
+a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===v){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===v&&this.length)f=c.data(this[0],a);return f===v&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);
+return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===v)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||
+a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var ya=/[\n\t]/g,ca=/\s+/,Wa=/\r/g,Xa=/href|src|style/,Ya=/(button|input)/i,Za=/(button|input|object|select|textarea)/i,$a=/^(a|area)$/i,za=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=
+c(this);m.addClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,n=b.length;j<n;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=c(this);m.removeClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string"||a===v)for(var b=(a||"").split(ca),
+d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(ya," "),j=0,n=b.length;j<n;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),n=b,o=
+a.split(ca);e=o[i++];){n=f?n:!j.hasClass(e);j[n?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(ya," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===v){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||
+{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(za.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Wa,"")}return v}var n=c.isFunction(a);return this.each(function(o){var m=c(this),s=a;if(this.nodeType===1){if(n)s=a.call(this,o,m.val());
+if(typeof s==="number")s+="";if(c.isArray(s)&&za.test(this.type))this.checked=c.inArray(m.val(),s)>=0;else if(c.nodeName(this,"select")){var x=c.makeArray(s);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),x)>=0});if(!x.length)this.selectedIndex=-1}else this.value=s}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return v;if(f&&b in c.attrFn)return c(a)[b](d);
+f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==v;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Xa.test(b);if(b in a&&f&&!i){if(e){b==="type"&&Ya.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Za.test(a.nodeName)||$a.test(a.nodeName)&&a.href?0:v;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=
+""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?v:a}return c.style(a,b,d)}});var ab=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==z&&!a.frameElement)a=z;if(!d.guid)d.guid=c.guid++;if(f!==v){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=
+function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):v};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var n,o=0;n=b[o++];){var m=n.split(".");n=m.shift();if(o>1){d=c.proxy(d);if(f!==v)d.data=f}d.type=m.slice(0).sort().join(".");var s=e[n],x=this.special[n]||{};if(!s){s=e[n]={};if(!x.setup||x.setup.call(a,f,m,d)===false)if(a.addEventListener)a.addEventListener(n,i,false);else a.attachEvent&&a.attachEvent("on"+n,i)}if(x.add)if((m=x.add.call(a,
+d,f,m,s))&&c.isFunction(m)){m.guid=m.guid||d.guid;m.data=m.data||d.data;m.type=m.type||d.type;d=m}s[d.guid]=d;this.global[n]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===v||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);for(var n=0;i=b[n++];){var o=i.split(".");i=o.shift();var m=!o.length,s=c.map(o.slice(0).sort(),ab);s=new RegExp("(^|\\.)"+
+s.join("\\.(?:.*\\.)?")+"(\\.|$)");var x=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var A in f[i])if(m||s.test(f[i][A].type))delete f[i][A];x.remove&&x.remove.call(a,o,j);for(e in f[i])break;if(!e){if(!x.teardown||x.teardown.call(a,o)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(A=c.data(a,"handle"))A.elem=null;c.removeData(a,
+"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return v;a.result=v;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,
+b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(i){}if(!a.isPropagationStopped()&&f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){d=a.target;var j;if(!(c.nodeName(d,"a")&&e==="click")&&!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){try{if(d[e]){if(j=d["on"+e])d["on"+e]=null;this.triggered=true;d[e]()}}catch(n){}if(j)d["on"+e]=j;this.triggered=false}}},handle:function(a){var b,
+d;a=arguments[0]=c.event.fix(a||z.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==v){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||r;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=r.documentElement;d=r.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==v)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;b.liveProxy=a;c.event.add(this,b.live,na,b)},remove:function(a){if(a.length){var b=
+0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],na)}},special:{}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};
+c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y};var Aa=function(a){for(var b=
+a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ba=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ba:Aa,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ba:Aa)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!==
+"form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return ma("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return ma("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,
+"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var da=/textarea|input|select/i;function Ca(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ea(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Ca(d);if(a.type!=="focusout"||
+d.type!=="radio")c.data(d,"_change_data",e);if(!(f===v||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}}c.event.special.change={filters:{focusout:ea,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ea.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ea.call(this,a)},beforeactivate:function(a){a=
+a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Ca(a))}},setup:function(a,b,d){for(var f in T)c.event.add(this,f+".specialChange."+d.guid,T[f]);return da.test(this.nodeName)},remove:function(a,b){for(var d in T)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),T[d]);return da.test(this.nodeName)}};var T=c.event.special.change.filters}r.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,
+f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){e=f;f=v}var j=b==="one"?c.proxy(e,function(n){c(this).unbind(n,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,
+b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+
+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e){var i,j=0;if(c.isFunction(f)){e=f;f=v}for(d=(d||"").split(/\s+/);(i=d[j++])!=null;){i=i==="focus"?"focusin":i==="blur"?"focusout":i==="hover"?d.push("mouseleave")&&"mouseenter":i;b==="live"?c(this.context).bind(oa(i,this.selector),{data:f,selector:this.selector,
+live:i},e):c(this.context).unbind(oa(i,this.selector),e?{guid:e.guid+this.selector+i}:null)}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});z.attachEvent&&!z.addEventListener&&z.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g){for(var h="",k,l=0;g[l];l++){k=g[l];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===k){y=l[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=k;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}l[q]=y}}}function d(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===
+k){y=l[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=k;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(o.filter(h,[t]).length>0){y=t;break}}t=t[g]}l[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,i=Object.prototype.toString,j=false,n=true;[0,0].sort(function(){n=false;return 0});var o=function(g,h,k,l){k=k||[];var q=h=h||r;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||
+typeof g!=="string")return k;for(var p=[],u,t,y,R,H=true,M=w(h),I=g;(f.exec(""),u=f.exec(I))!==null;){I=u[3];p.push(u[1]);if(u[2]){R=u[3];break}}if(p.length>1&&s.exec(g))if(p.length===2&&m.relative[p[0]])t=fa(p[0]+p[1],h);else for(t=m.relative[p[0]]?[h]:o(p.shift(),h);p.length;){g=p.shift();if(m.relative[g])g+=p.shift();t=fa(g,t)}else{if(!l&&p.length>1&&h.nodeType===9&&!M&&m.match.ID.test(p[0])&&!m.match.ID.test(p[p.length-1])){u=o.find(p.shift(),h,M);h=u.expr?o.filter(u.expr,u.set)[0]:u.set[0]}if(h){u=
+l?{expr:p.pop(),set:A(l)}:o.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=u.expr?o.filter(u.expr,u.set):u.set;if(p.length>0)y=A(t);else H=false;for(;p.length;){var D=p.pop();u=D;if(m.relative[D])u=p.pop();else D="";if(u==null)u=h;m.relative[D](y,u,M)}}else y=[]}y||(y=t);y||o.error(D||g);if(i.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))k.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&
+y[g].nodeType===1&&k.push(t[g]);else k.push.apply(k,y);else A(y,k);if(R){o(R,q,k,l);o.uniqueSort(k)}return k};o.uniqueSort=function(g){if(C){j=n;g.sort(C);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};o.matches=function(g,h){return o(g,null,null,h)};o.find=function(g,h,k){var l,q;if(!g)return[];for(var p=0,u=m.order.length;p<u;p++){var t=m.order[p];if(q=m.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");l=m.find[t](q,
+h,k);if(l!=null){g=g.replace(m.match[t],"");break}}}}l||(l=h.getElementsByTagName("*"));return{set:l,expr:g}};o.filter=function(g,h,k,l){for(var q=g,p=[],u=h,t,y,R=h&&h[0]&&w(h[0]);g&&h.length;){for(var H in m.filter)if((t=m.leftMatch[H].exec(g))!=null&&t[2]){var M=m.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(u===p)p=[];if(m.preFilter[H])if(t=m.preFilter[H](t,u,k,p,l,R)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=u[U])!=null;U++)if(D){I=M(D,t,U,u);var Da=
+l^!!I;if(k&&I!=null)if(Da)y=true;else u[U]=false;else if(Da){p.push(D);y=true}}if(I!==v){k||(u=p);g=g.replace(m.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)o.error(g);else break;q=g}return u};o.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var m=o.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,h){var k=typeof h==="string",l=k&&!/\W/.test(h);k=k&&!l;if(l)h=h.toLowerCase();l=0;for(var q=g.length,
+p;l<q;l++)if(p=g[l]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[l]=k||p&&p.nodeName.toLowerCase()===h?p||false:p===h}k&&o.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var l=0,q=g.length;l<q;l++){var p=g[l];if(p){k=p.parentNode;g[l]=k.nodeName.toLowerCase()===h?k:false}}}else{l=0;for(q=g.length;l<q;l++)if(p=g[l])g[l]=k?p.parentNode:p.parentNode===h;k&&o.filter(h,g,true)}},"":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=
+h=h.toLowerCase();q=b}q("parentNode",h,l,g,p,k)},"~":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,l,g,p,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];h=h.getElementsByName(g[1]);for(var l=0,q=h.length;l<q;l++)h[l].getAttribute("name")===g[1]&&k.push(h[l]);return k.length===0?null:k}},
+TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,l,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var u;(u=h[p])!=null;p++)if(u)if(q^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||l.push(u);else if(k)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&
+"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,l,q,p){h=g[1].replace(/\\/g,"");if(!p&&m.attrMap[h])g[1]=m.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,l,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=o(g[3],null,null,h);else{g=o.filter(g[3],h,k,true^q);k||l.push.apply(l,g);return false}else if(m.match.POS.test(g[0])||m.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);
+return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!o(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===
+g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,h){return h===0},last:function(g,h,k,l){return h===l.length-1},even:function(g,h){return h%2===
+0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,l){var q=h[1],p=m.filters[q];if(p)return p(g,k,h,l);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=h[3];k=0;for(l=h.length;k<l;k++)if(h[k]===g)return false;return true}else o.error("Syntax error, unrecognized expression: "+
+q)},CHILD:function(g,h){var k=h[1],l=g;switch(k){case "only":case "first":for(;l=l.previousSibling;)if(l.nodeType===1)return false;if(k==="first")return true;l=g;case "last":for(;l=l.nextSibling;)if(l.nodeType===1)return false;return true;case "nth":k=h[2];var q=h[3];if(k===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var u=0;for(l=p.firstChild;l;l=l.nextSibling)if(l.nodeType===1)l.nodeIndex=++u;p.sizcache=h}g=g.nodeIndex-q;return k===0?g===0:g%k===0&&g/k>=
+0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=m.attrHandle[k]?m.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var l=h[2];h=h[4];return g==null?l==="!=":l==="="?k===h:l==="*="?k.indexOf(h)>=0:l==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:l==="!="?k!==h:l==="^="?
+k.indexOf(h)===0:l==="$="?k.substr(k.length-h.length)===h:l==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,l){var q=m.setFilters[h[2]];if(q)return q(g,k,h,l)}}},s=m.match.POS;for(var x in m.match){m.match[x]=new RegExp(m.match[x].source+/(?![^\[]*\])(?![^\(]*\))/.source);m.leftMatch[x]=new RegExp(/(^(?:.|\r|\n)*?)/.source+m.match[x].source.replace(/\\(\d+)/g,function(g,h){return"\\"+(h-0+1)}))}var A=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};
+try{Array.prototype.slice.call(r.documentElement.childNodes,0)}catch(B){A=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,l=g.length;k<l;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var C;if(r.documentElement.compareDocumentPosition)C=function(g,h){if(!g.compareDocumentPosition||!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===
+h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in r.documentElement)C=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(r.createRange)C=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),l=h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);l.setStart(h,0);l.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END,
+l);if(g===0)j=true;return g};(function(){var g=r.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=r.documentElement;k.insertBefore(g,k.firstChild);if(r.getElementById(h)){m.find.ID=function(l,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(l[1]))?q.id===l[1]||typeof q.getAttributeNode!=="undefined"&&q.getAttributeNode("id").nodeValue===l[1]?[q]:v:[]};m.filter.ID=function(l,q){var p=typeof l.getAttributeNode!=="undefined"&&l.getAttributeNode("id");
+return l.nodeType===1&&p&&p.nodeValue===q}}k.removeChild(g);k=g=null})();(function(){var g=r.createElement("div");g.appendChild(r.createComment(""));if(g.getElementsByTagName("*").length>0)m.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var l=0;k[l];l++)k[l].nodeType===1&&h.push(k[l]);k=h}return k};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")m.attrHandle.href=function(h){return h.getAttribute("href",
+2)};g=null})();r.querySelectorAll&&function(){var g=o,h=r.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){o=function(l,q,p,u){q=q||r;if(!u&&q.nodeType===9&&!w(q))try{return A(q.querySelectorAll(l),p)}catch(t){}return g(l,q,p,u)};for(var k in g)o[k]=g[k];h=null}}();(function(){var g=r.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
+0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){m.order.splice(1,0,"CLASS");m.find.CLASS=function(h,k,l){if(typeof k.getElementsByClassName!=="undefined"&&!l)return k.getElementsByClassName(h[1])};g=null}}})();var E=r.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,h){return g!==h&&(g.contains?g.contains(h):true)},w=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},fa=function(g,h){var k=[],
+l="",q;for(h=h.nodeType?[h]:h;q=m.match.PSEUDO.exec(g);){l+=q[0];g=g.replace(m.match.PSEUDO,"")}g=m.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)o(g,h[q],k);return o.filter(l,k)};c.find=o;c.expr=o.selectors;c.expr[":"]=c.expr.filters;c.unique=o.uniqueSort;c.getText=a;c.isXMLDoc=w;c.contains=E})();var bb=/Until$/,cb=/^(?:parents|prevUntil|prevAll)/,db=/,/;Q=Array.prototype.slice;var Ea=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a,
+function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Qa.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=
+0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ea(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ea(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i={},j;if(f&&a.length){e=0;for(var n=a.length;e<n;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)>
+-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var o=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(m,s){for(;s&&s.ownerDocument&&s!==b;){if(o?o.index(s)>-1:c(s).is(a))return s;s=s.parentNode}return null})},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),
+a);return this.pushStack(pa(a[0])||pa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},
+nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);bb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):
+e;if((this.length>1||db.test(f))&&cb.test(a))e=e.reverse();return this.pushStack(e,a,Q.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===v||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==
+b&&d.push(a);return d}});var Fa=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ga=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,sa=/checked\s*(?:[^=]|=\s*.checked.)/i,Ia=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],
+col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==v)return this.empty().append((this[0]&&this[0].ownerDocument||r).createTextNode(a));return c.getText(this)},
+wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?
+d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,
+false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&
+!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Fa,"").replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){qa(this,b);qa(this.find("*"),b.find("*"))}return b},html:function(a){if(a===v)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Fa,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(Ha.exec(a)||
+["",""])[1].toLowerCase()]){a=a.replace(Ga,Ia);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,
+b,f))});else a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(s){return c.nodeName(s,"table")?s.getElementsByTagName("tbody")[0]||s.appendChild(s.ownerDocument.createElement("tbody")):s}var e,i,j=a[0],n=[];if(!c.support.checkClone&&arguments.length===3&&typeof j===
+"string"&&sa.test(j))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(j))return this.each(function(s){var x=c(this);a[0]=j.call(this,s,b?x.html():v);x.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ra(a,this,n);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var o=0,m=this.length;o<m;o++)d.call(b?f(this[o],i):this[o],e.cacheable||this.length>1||o>0?e.fragment.cloneNode(true):e.fragment)}n&&c.each(n,
+Ma)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){c.cleanData(this.getElementsByTagName("*"));c.cleanData([this])}this.parentNode&&
+this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&c.cleanData(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||r;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||r;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j===
+"string"){j=j.replace(Ga,Ia);var n=(Ha.exec(j)||["",""])[1].toLowerCase(),o=F[n]||F._default,m=o[0];i=b.createElement("div");for(i.innerHTML=o[1]+j+o[2];m--;)i=i.lastChild;if(!c.support.tbody){m=fb.test(j);n=n==="table"&&!m?i.firstChild&&i.firstChild.childNodes:o[1]==="<table>"&&!m?i.childNodes:[];for(o=n.length-1;o>=0;--o)c.nodeName(n[o],"tbody")&&!n[o].childNodes.length&&n[o].parentNode.removeChild(n[o])}!c.support.leadingWhitespace&&V.test(j)&&i.insertBefore(b.createTextNode(V.exec(j)[0]),i.firstChild);
+j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()==="text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e},cleanData:function(a){for(var b=0,d;(d=a[b])!=null;b++){c.event.remove(d);c.removeData(d)}}});var hb=/z-?index|font-?weight|opacity|zoom|line-?height/i,
+Ja=/alpha\([^)]*\)/,Ka=/opacity=([^)]*)/,ga=/float/i,ha=/-([a-z])/ig,ib=/([A-Z])/g,jb=/^-?\d+(?:px)?$/i,kb=/^-?\d/,lb={position:"absolute",visibility:"hidden",display:"block"},mb=["Left","Right"],nb=["Top","Bottom"],ob=r.defaultView&&r.defaultView.getComputedStyle,La=c.support.cssFloat?"cssFloat":"styleFloat",ia=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===v)return c.curCSS(d,f);if(typeof e==="number"&&!hb.test(f))e+="px";c.style(d,f,e)})};
+c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return v;if((b==="width"||b==="height")&&parseFloat(d)<0)d=v;var f=a.style||a,e=d!==v;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ja.test(a)?a.replace(Ja,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ka.exec(f.filter)[1])/100+"":""}if(ga.test(b))b=La;b=b.replace(ha,ia);if(e)f[b]=d;return f[b]},css:function(a,
+b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?mb:nb;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,lb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&
+a.currentStyle){f=Ka.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ga.test(b))b=La;if(!d&&e&&e[b])f=e[b];else if(ob){if(ga.test(b))b="float";b=b.replace(ib,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ha,ia);f=a.currentStyle[b]||a.currentStyle[d];if(!jb.test(f)&&kb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left=
+a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var pb=
+J(),qb=/<script(.|\s)*?\/script>/gi,rb=/select|textarea/i,sb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ja=/\?/,tb=/(\?|&)_=.*?(&|$)/,ub=/^(\w+:)?\/\/([^\/?#]+)/,vb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=
+c.param(b,c.ajaxSettings.traditional);f="POST"}var i=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(j,n){if(n==="success"||n==="notmodified")i.html(e?c("<div />").append(j.responseText.replace(qb,"")).find(e):j.responseText);d&&i.each(d,[j.responseText,n,j])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&
+(this.checked||rb.test(this.nodeName)||sb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,
+b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:z.XMLHttpRequest&&(z.location.protocol!=="file:"||!z.ActiveXObject)?function(){return new z.XMLHttpRequest}:
+function(){try{return new z.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(o,n,j,w);e.global&&f("ajaxSuccess",[w,e])}function d(){e.complete&&e.complete.call(o,w,j);e.global&&f("ajaxComplete",[w,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}
+function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,n,o=a&&a.context||e,m=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(m==="GET")N.test(e.url)||(e.url+=(ja.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||
+N.test(e.url))){i=e.jsonpCallback||"jsonp"+pb++;if(e.data)e.data=(e.data+"").replace(N,"="+i+"$1");e.url=e.url.replace(N,"="+i+"$1");e.dataType="script";z[i]=z[i]||function(q){n=q;b();d();z[i]=v;try{delete z[i]}catch(p){}A&&A.removeChild(B)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&m==="GET"){var s=J(),x=e.url.replace(tb,"$1_="+s+"$2");e.url=x+(x===e.url?(ja.test(e.url)?"&":"?")+"_="+s:"")}if(e.data&&m==="GET")e.url+=(ja.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&
+c.event.trigger("ajaxStart");s=(s=ub.exec(e.url))&&(s[1]&&s[1]!==location.protocol||s[2]!==location.host);if(e.dataType==="script"&&m==="GET"&&s){var A=r.getElementsByTagName("head")[0]||r.documentElement,B=r.createElement("script");B.src=e.url;if(e.scriptCharset)B.charset=e.scriptCharset;if(!i){var C=false;B.onload=B.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;b();d();B.onload=B.onreadystatechange=null;A&&B.parentNode&&
+A.removeChild(B)}}}A.insertBefore(B,A.firstChild);return v}var E=false,w=e.xhr();if(w){e.username?w.open(m,e.url,e.async,e.username,e.password):w.open(m,e.url,e.async);try{if(e.data||a&&a.contentType)w.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&w.setRequestHeader("If-None-Match",c.etag[e.url])}s||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",
+e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(fa){}if(e.beforeSend&&e.beforeSend.call(o,w,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");w.abort();return false}e.global&&f("ajaxSend",[w,e]);var g=w.onreadystatechange=function(q){if(!w||w.readyState===0||q==="abort"){E||d();E=true;if(w)w.onreadystatechange=c.noop}else if(!E&&w&&(w.readyState===4||q==="timeout")){E=true;w.onreadystatechange=c.noop;j=q==="timeout"?"timeout":!c.httpSuccess(w)?
+"error":e.ifModified&&c.httpNotModified(w,e.url)?"notmodified":"success";var p;if(j==="success")try{n=c.httpData(w,e.dataType,e)}catch(u){j="parsererror";p=u}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,w,j,p);d();q==="timeout"&&w.abort();if(e.async)w=null}};try{var h=w.abort;w.abort=function(){w&&h.call(w);g("abort")}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){w&&!E&&g("timeout")},e.timeout);try{w.send(m==="POST"||m==="PUT"||m==="DELETE"?e.data:null)}catch(l){c.handleError(e,
+w,null,l);d()}e.async||g();return w}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=
+f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(j,n){if(c.isArray(n))c.each(n,
+function(o,m){b?f(j,m):d(j+"["+(typeof m==="object"||c.isArray(m)?o:"")+"]",m)});else!b&&n!=null&&typeof n==="object"?c.each(n,function(o,m){d(j+"["+o+"]",m)}):f(j,n)}function f(j,n){n=c.isFunction(n)?n():n;e[e.length]=encodeURIComponent(j)+"="+encodeURIComponent(n)}var e=[];if(b===v)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var i in a)d(i,a[i]);return e.join("&").replace(vb,"+")}});var ka={},wb=/toggle|show|hide/,xb=/^([+-]=)?([\d+-.]+)(.*)$/,
+W,ta=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(ka[d])f=ka[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();
+ka[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&
+c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,n=this.nodeType===1&&c(this).is(":hidden"),
+o=this;for(j in a){var m=j.replace(ha,ia);if(j!==m){a[m]=a[j];delete a[j];j=m}if(a[j]==="hide"&&n||a[j]==="show"&&!n)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(s,x){var A=new c.fx(o,i,s);if(wb.test(x))A[x==="toggle"?n?"show":"hide":x](a);
+else{var B=xb.exec(x),C=A.cur(true)||0;if(B){x=parseFloat(B[2]);var E=B[3]||"px";if(E!=="px"){o.style[s]=(x||1)+E;C=(x||1)/A.cur(true)*C;o.style[s]=C+E}if(B[1])x=(B[1]==="-="?-1:1)*x+C;A.custom(C,x,E)}else A.custom(C,x,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",
+1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,
+b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==
+null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===
+"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=
+this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=
+c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=
+null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in r.documentElement?function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),
+f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=
+b,e=b.ownerDocument,i,j=e.documentElement,n=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var o=b.offsetTop,m=b.offsetLeft;(b=b.parentNode)&&b!==n&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;o-=b.scrollTop;m-=b.scrollLeft;if(b===d){o+=b.offsetTop;m+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){o+=parseFloat(i.borderTopWidth)||
+0;m+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){o+=parseFloat(i.borderTopWidth)||0;m+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){o+=n.offsetTop;m+=n.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){o+=Math.max(j.scrollTop,n.scrollTop);m+=Math.max(j.scrollLeft,n.scrollLeft)}return{top:o,left:m}};c.offset={initialize:function(){var a=r.body,b=r.createElement("div"),
+d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);
+d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop},
+bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left-
+e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=
+this.offsetParent||r.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==v)return this.each(function(){if(i=ua(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=ua(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}});
+c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(i){var j=c(this);j[d](f.call(this,i,j[d]()))});return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||
+e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===v?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});z.jQuery=z.$=c})(window);
diff --git a/doc/templates/scripts/narrow.js b/doc/templates/scripts/narrow.js
new file mode 100644
index 000000000..35c81bf4a
--- /dev/null
+++ b/doc/templates/scripts/narrow.js
@@ -0,0 +1,89 @@
+var narrowInit = function() {
+ /* TODO:
+ Could probably be more efficient, not hardcoding each element to be created
+ */
+ // 1: Create search form
+ var narrowSearch = $('<div id="narrowsearch"></div>');
+ var searchform = $("#qtdocsearch");
+ narrowSearch.append(searchform);
+ $("#qtdocheader .content .qtref").after(narrowSearch);
+
+ // 2: Create dropdowns
+ var narrowmenu = $('<ul id="narrowmenu" class="sf-menu"></ul>');
+
+ // Lookup
+ var lookuptext = $("#lookup h2").attr("title");
+ $("#lookup ul").removeAttr("id");
+ $("#lookup ul li").removeAttr("class");
+ $("#lookup ul li").removeAttr("style");
+ var lookupul = $("#lookup ul");
+ var lookuplist = $('<li></li>');
+ var lookuplink = $('<a href="#"></a>');
+ lookuplink.append(lookuptext);
+ lookuplist.append(lookuplink);
+ lookuplist.append(lookupul);
+ narrowmenu.append(lookuplist);
+
+ // Topics
+ var topicstext = $("#topics h2").attr("title");
+ $("#topics ul").removeAttr("id");
+ $("#topics ul li").removeAttr("class");
+ $("#topics ul li").removeAttr("style");
+ var topicsul = $("#topics ul");
+ var topicslist = $('<li></li>');
+ var topicslink = $('<a href="#"></a>');
+ topicslink.append(topicstext);
+ topicslist.append(topicslink);
+ topicslist.append(topicsul);
+ narrowmenu.append(topicslist);
+
+ // Examples
+ var examplestext = $("#examples h2").attr("title");
+ $("#examples ul").removeAttr("id");
+ $("#examples ul li").removeAttr("class");
+ $("#examples ul li").removeAttr("style");
+ var examplesul = $("#examples ul");
+ var exampleslist = $('<li></li>');
+ var exampleslink = $('<a href="#"></a>');
+ exampleslink.append(examplestext);
+ exampleslist.append(exampleslink);
+ exampleslist.append(examplesul);
+ narrowmenu.append(exampleslist);
+
+ $("#shortCut").after(narrowmenu);
+ $('ul#narrowmenu').superfish({
+ delay: 100,
+ autoArrows: false,
+ disableHI: true
+ });
+}
+
+$(document).ready(function(){
+/* if ($('body').hasClass('narrow')) {
+ narrowInit();
+ }
+ */
+ if($(window).width()<600) {
+ $('body').addClass('narrow');
+
+ if ($("#narrowsearch").length == 0) {
+ narrowInit();
+ }
+ }
+ else {
+ $('body').removeClass('narrow');
+ }
+});
+
+$(window).bind('resize', function () {
+ if($(window).width()<600) {
+ $('body').addClass('narrow');
+
+ if ($("#narrowsearch").length == 0) {
+ narrowInit();
+ }
+ }
+ else {
+ $('body').removeClass('narrow');
+ }
+}); \ No newline at end of file
diff --git a/doc/templates/scripts/superfish.js b/doc/templates/scripts/superfish.js
new file mode 100644
index 000000000..c6a9c7de0
--- /dev/null
+++ b/doc/templates/scripts/superfish.js
@@ -0,0 +1,121 @@
+
+/*
+ * Superfish v1.4.8 - jQuery menu widget
+ * Copyright (c) 2008 Joel Birch
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
+ */
+
+;(function($){
+ $.fn.superfish = function(op){
+
+ var sf = $.fn.superfish,
+ c = sf.c,
+ $arrow = $(['<span class="',c.arrowClass,'"> &#187;</span>'].join('')),
+ over = function(){
+ var $$ = $(this), menu = getMenu($$);
+ clearTimeout(menu.sfTimer);
+ $$.showSuperfishUl().siblings().hideSuperfishUl();
+ },
+ out = function(){
+ var $$ = $(this), menu = getMenu($$), o = sf.op;
+ clearTimeout(menu.sfTimer);
+ menu.sfTimer=setTimeout(function(){
+ o.retainPath=($.inArray($$[0],o.$path)>-1);
+ $$.hideSuperfishUl();
+ if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
+ },o.delay);
+ },
+ getMenu = function($menu){
+ var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
+ sf.op = sf.o[menu.serial];
+ return menu;
+ },
+ addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
+
+ return this.each(function() {
+ var s = this.serial = sf.o.length;
+ var o = $.extend({},sf.defaults,op);
+ o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
+ $(this).addClass([o.hoverClass,c.bcClass].join(' '))
+ .filter('li:has(ul)').removeClass(o.pathClass);
+ });
+ sf.o[s] = sf.op = o;
+
+ $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
+ if (o.autoArrows) addArrow( $('>a:first-child',this) );
+ })
+ .not('.'+c.bcClass)
+ .hideSuperfishUl();
+
+ var $a = $('a',this);
+ $a.each(function(i){
+ var $li = $a.eq(i).parents('li');
+ $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
+ });
+ o.onInit.call(this);
+
+ }).each(function() {
+ var menuClasses = [c.menuClass];
+ if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
+ $(this).addClass(menuClasses.join(' '));
+ });
+ };
+
+ var sf = $.fn.superfish;
+ sf.o = [];
+ sf.op = {};
+ sf.IE7fix = function(){
+ var o = sf.op;
+ if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
+ this.toggleClass(sf.c.shadowClass+'-off');
+ };
+ sf.c = {
+ bcClass : 'sf-breadcrumb',
+ menuClass : 'sf-js-enabled',
+ anchorClass : 'sf-with-ul',
+ arrowClass : 'sf-sub-indicator',
+ shadowClass : 'sf-shadow'
+ };
+ sf.defaults = {
+ hoverClass : 'sfHover',
+ pathClass : 'overideThisToUse',
+ pathLevels : 1,
+ delay : 800,
+ animation : {opacity:'show'},
+ speed : 'normal',
+ autoArrows : true,
+ dropShadows : true,
+ disableHI : false, // true disables hoverIntent detection
+ onInit : function(){}, // callback functions
+ onBeforeShow: function(){},
+ onShow : function(){},
+ onHide : function(){}
+ };
+ $.fn.extend({
+ hideSuperfishUl : function(){
+ var o = sf.op,
+ not = (o.retainPath===true) ? o.$path : '';
+ o.retainPath = false;
+ var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
+ .find('>ul').hide().css('visibility','hidden');
+ o.onHide.call($ul);
+ return this;
+ },
+ showSuperfishUl : function(){
+ var o = sf.op,
+ sh = sf.c.shadowClass+'-off',
+ $ul = this.addClass(o.hoverClass)
+ .find('>ul:hidden').css('visibility','visible');
+ sf.IE7fix.call($ul);
+ o.onBeforeShow.call($ul);
+ $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
+ return this;
+ }
+ });
+
+})(jQuery);
diff --git a/doc/templates/style/narrow.css b/doc/templates/style/narrow.css
new file mode 100644
index 000000000..de5b0a09f
--- /dev/null
+++ b/doc/templates/style/narrow.css
@@ -0,0 +1,270 @@
+ /* start narrow mode */
+
+ body.narrow
+ {
+ background-image: none;
+ }
+
+ .narrow a {
+ color: #44a51c;
+ }
+
+ .narrow .header, .narrow .header .content, .narrow .footer, .narrow .wrapper {
+ margin: 0 7px;
+ min-width: 300px;
+ }
+
+ .narrow .footer {
+ margin: 0px;
+ }
+
+ .creator .header, .creator .header .content, .creator .footer, .creator .wrapper {
+ margin: 0px;
+ min-width: 300px;
+ }
+ .narrow .header
+ {
+ width: 100%;
+ margin: 0;
+ height: auto;
+ background: #fff url(../images/header_bg.png) repeat-x 0 100%;
+ padding: 10px 0 5px 0;
+ overflow: visible;
+ }
+
+ .narrow .header .content
+ {
+ }
+
+ .narrow .header #nav-logo
+ {
+ display: none;
+ }
+
+ .narrow .header .qtref
+ {
+ width: auto;
+ height: auto;
+ color: #363534;
+ position: static;
+ float: left;
+ margin-left: 25px;
+ font: bold 18px/1 Arial;
+ }
+
+ .narrow .header .qtref a
+ {
+ color: #00732F;
+ }
+
+ .narrow .header .qtref span
+ {
+ background-image: none;
+ text-indent: 0;
+ }
+
+ .narrow .header #nav-topright
+ {
+ display: none;
+ }
+
+ .narrow .header #shortCut
+ {
+ clear: both;
+ font-weight: normal;
+ position: static;
+ float: left;
+ margin: 15px 0 0 25px;
+ overflow: hidden;
+ padding: 0;
+ height: auto;
+ }
+
+ .narrow .header #shortCut ul
+ {
+ float: none;
+ margin: 0;
+ width: auto;
+ font-size: 11px;
+ }
+
+ .narrow .header #shortCut ul li
+ {
+ background-image: none;
+ }
+
+ .narrow .header #shortCut ul .shortCut-topleft-active,
+ .narrow .header #shortCut ul .shortCut-topleft-inactive
+ {
+ background-image: none;
+ height: auto;
+ padding: 0;
+ width: auto;
+ }
+ .narrow .header #shortCut ul li a
+ {
+ color: #00732F;
+ }
+
+ .narrow .wrapper .hd
+ {
+ background: url(../images/bg_ul_blank.png) no-repeat 0 0;
+ }
+
+ .narrow .wrapper .bd
+ {
+ background: url(../images/bg_l_blank.png) repeat-y 0 0;
+ }
+
+ .narrow .wrapper .ft
+ {
+ background: url(../images/bg_ll_blank.png) no-repeat 0 0;
+ }
+
+ .narrow .sidebar
+ {
+ display: none;
+ }
+
+ .narrow .wrap
+ {
+ margin: 0 5px 0 5px;
+ }
+
+ .creator .wrap
+ {
+ margin: 0px;
+ background:#FFFFFF;
+ }
+ .narrow .wrap .toolbar
+ {
+ border-bottom: none;
+ }
+
+ .narrow .wrap .content
+ {
+ padding-top: 15px;
+ }
+ .creator .wrap .content
+ {
+ padding-top: 10px;
+ }
+ .creator .wrap .content .guide
+ {
+ padding-top: 15px;
+ }
+ .narrow .wrap .feedback
+ {
+ display: none;
+ }
+
+ .narrow .wrap .breadcrumb ul li {
+ font-weight: normal;
+ }
+
+ .narrow .wrap .breadcrumb ul li a {
+ color: #44a51c;
+ }
+
+ .narrow .wrap .breadcrumb ul li.last a {
+ color: #363534;
+ }
+
+ #narrowsearch {
+ display: none;
+ }
+
+ .narrow #narrowsearch {
+ display: block;
+ float: right;
+ margin-right: 25px;
+ _position: relative;
+ }
+
+ .narrow #narrowsearch fieldset {
+ _position: absolute;
+ _margin-top: -1px;
+ }
+
+ .narrow #narrowsearch {
+ background: url("http://doc.qt.nokia.com/prototype/html/images/sprites-combined.png") no-repeat scroll -6px -348px transparent;
+ height: 21px;
+ padding: 2px 0 0 5px;
+ width: 167px;
+ }
+
+ .narrow #narrowsearch input {
+ border: none;
+ font: 13px/1.2 Verdana;
+ height: 19px;
+ outline: none;
+ padding: 0;
+ width: 158px;
+ *border: 1px solid #fff;
+ *height: 17px;
+ _height: 18px;
+ /* to be fixed */
+ display: none;
+ /* to be fixed */
+ }
+
+ .narrow .indexbox .indexIcon {
+ display: none;
+ }
+
+ .narrow .indexboxcont .section {
+ width: 64%;
+ padding-left: 0;
+ }
+
+ .narrow .indexboxcont .sectionlist {
+ width: 32.5%;
+ }
+
+ #narrowmenu {
+ display: none;
+ float: right;
+ margin: 15px 40px 0 0;
+ font-size: 11px;
+ }
+
+ .narrow #narrowmenu {
+ display: block;
+ }
+
+ #narrowmenu a {
+ line-height: 1.1;
+ background: url(../images/arrow_down.png) no-repeat 100% 50%;
+ white-space: nowrap;
+ padding: 0 16px 0 5px;
+ }
+
+ #narrowmenu li {
+ margin-left: 20px;
+ }
+
+ #narrowmenu li li {
+ margin: 0 0 5px 0;
+ }
+
+ #narrowmenu li li a {
+ padding: 0;
+ background-image: none;
+ }
+
+ #narrowmenu li,
+ #narrowmenu li ul {
+ background-color: #fff;
+ margin-top:-1px;
+ }
+
+ #narrowmenu li ul {
+ width: auto;
+ padding: 5px;
+ }
+
+ .sf-menu li:hover ul, .sf-menu li.sfHover ul {
+ top: 1.2em;
+ }
+
+ /* end narrow mode */
diff --git a/doc/templates/style/offline.css b/doc/templates/style/offline.css
new file mode 100644
index 000000000..c3f90c36a
--- /dev/null
+++ b/doc/templates/style/offline.css
@@ -0,0 +1,675 @@
+@media screen
+{
+
+/* basic elements */
+ html
+ {
+ color: #000000;
+ background: #FFFFFF;
+ }
+ table
+ {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+ fieldset, img
+ {
+ border: 0;
+ max-width:100%;
+ }
+ address, caption, cite, code, dfn, em, strong, th, var, optgroup
+ {
+ font-style: inherit;
+ font-weight: inherit;
+ }
+ del, ins
+ {
+ text-decoration: none;
+ }
+ ol li
+ {
+ list-style: decimal;
+ }
+ ul li
+ {
+ list-style: none;
+ }
+ caption, th
+ {
+ text-align: left;
+ }
+ h1, h2, h3, h4, h5, h6
+ {
+ font-size: 100%;
+ }
+ q:before, q:after
+ {
+ content: '';
+ }
+ abbr, acronym
+ {
+ border: 0;
+ font-variant: normal;
+ }
+ sup, sub
+ {
+ vertical-align: baseline;
+ }
+ tt, .qmlreadonly span, .qmldefault span
+ {
+ word-spacing:0.5em;
+ }
+ legend
+ {
+ color: #000000;
+ }
+ strong
+ {
+ font-weight: bold;
+ }
+ em
+ {
+ font-style: italic;
+ }
+
+ body
+ {
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ font-family: sans-serif;
+ line-height: normal
+ }
+ a
+ {
+ color: #00732F;
+ text-decoration: none;
+ }
+ hr
+ {
+ background-color: #E6E6E6;
+ border: 1px solid #E6E6E6;
+ height: 1px;
+ width: 100%;
+ text-align: left;
+ margin: 1.5em 0 1.5em 0;
+ }
+
+ pre
+ {
+ border: 1px solid #DDDDDD;
+ -moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ border-radius: 0.7em 0.7em 0.7em 0.7em;
+ margin: 0 1.5em 1em 1em;
+ padding: 1em 1em 1em 1em;
+ overflow-x: auto;
+ }
+ table, pre
+ {
+ -moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ border-radius: 0.7em 0.7em 0.7em 0.7em;
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ margin-bottom: 2.5em;
+ }
+ pre {
+ font-size: 90%;
+ display: block;
+ overflow:hidden;
+ }
+ thead
+ {
+ margin-top: 0.5em;
+ font-weight: bold
+ }
+ th
+ {
+ padding: 0.5em 1.5em 0.5em 1em;
+ background-color: #E1E1E1;
+ border-left: 1px solid #E6E6E6;
+ }
+ td
+ {
+ padding: 0.25em 1.5em 0.25em 1em;
+ }
+
+ td.rightAlign
+ {
+ padding: 0.25em 0.5em 0.25em 1em;
+ }
+ table tr.odd
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #F6F6F6;
+ color: #66666E;
+ }
+ table tr.even
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #ffffff;
+ color: #66666E;
+ }
+
+ div.float-left
+ {
+ float: left; margin-right: 2em
+ }
+ div.float-right
+ {
+ float: right; margin-left: 2em
+ }
+
+ span.comment
+ {
+ color: #008B00;
+ }
+ span.string, span.char
+ {
+ color: #000084;
+ }
+ span.number
+ {
+ color: #a46200;
+ }
+ span.operator
+ {
+ color: #202020;
+ }
+ span.keyword
+ {
+ color: #840000;
+ }
+ span.name
+ {
+ color: black
+ }
+ span.type
+ {
+ font-weight: bold
+ }
+ span.type a:visited
+ {
+ color: #0F5300;
+ }
+ span.preprocessor
+ {
+ color: #404040
+ }
+/* end basic elements */
+
+/* font style elements */
+ .heading
+ {
+ font-weight: bold;
+ font-size: 125%;
+ }
+ .subtitle
+ {
+ font-size: 110%
+ }
+ .small-subtitle
+ {
+ font-size: 100%
+ }
+ .red
+ {
+ color:red;
+ }
+/* end font style elements */
+
+/* global settings*/
+ .header, .footer
+ {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ }
+/* end global settings*/
+
+/* header elements */
+ .header .qtref
+ {
+ color: #00732F;
+ font-weight: bold;
+ font-size: 130%;
+ }
+
+ .header .content
+ {
+ margin-bottom: 0.5em
+ }
+
+ .header .breadcrumb
+ {
+ font-size: 90%;
+ padding: 0.5em 0 0.5em 1em;
+ margin: 0;
+ background-color: #fafafa;
+ height: 1.35em;
+ border-bottom: 1px solid #d1d1d1;
+ }
+
+ .header .breadcrumb ul
+ {
+ margin: 0;
+ padding: 0;
+ }
+
+ .header .content
+ {
+ word-wrap: break-word;
+ }
+
+ .header .breadcrumb ul li
+ {
+ float: left;
+ background: url(../images/breadcrumb.png) no-repeat 0 3px;
+ padding-left: 1.5em;
+ margin-left: 1.5em;
+ }
+
+ .header .breadcrumb ul li.last
+ {
+ font-weight: normal;
+ }
+
+ .header .breadcrumb ul li a
+ {
+ color: #00732F;
+ }
+
+ .header .breadcrumb ul li.first
+ {
+ background-image: none;
+ padding-left: 0;
+ margin-left: 0;
+ }
+
+ .header .content ol li {
+ background: none;
+ margin-bottom: 1.0em;
+ margin-left: 1.2em;
+ padding-left: 0
+ }
+
+ .header .content li
+ {
+ background: url(../images/bullet_sq.png) no-repeat 0 5px;
+ margin-bottom: 1em;
+ padding-left: 1.2em;
+ }
+
+/* end header elements */
+
+/* content elements */
+ .content h1
+ {
+ font-weight: bold;
+ font-size: 130%
+ }
+
+ .content h2
+ {
+ font-weight: bold;
+ font-size: 120%;
+ width: 100%;
+ }
+ .content h3
+ {
+ font-weight: bold;
+ font-size: 110%;
+ width: 100%;
+ }
+ .content table p
+ {
+ margin: 0
+ }
+ .content ul
+ {
+ padding-left: 2.5em;
+ }
+ .content li
+ {
+ padding-top: 0.25em;
+ padding-bottom: 0.25em;
+ }
+ .content ul img {
+ vertical-align: middle;
+ }
+
+ .content a:visited
+ {
+ color: #4c0033;
+ text-decoration: none;
+ }
+
+ .content a:visited:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+
+ a:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+ descr p a
+ {
+ text-decoration: underline;
+ }
+
+ .descr p a:visited
+ {
+ text-decoration: underline;
+ }
+
+ .alphaChar{
+ width:95%;
+ background-color:#F6F6F6;
+ border:1px solid #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ font-size:12pt;
+ padding-left:10px;
+ margin-top:10px;
+ margin-bottom:10px;
+ }
+ .flowList{
+ /*vertical-align:top;*/
+ /*margin:20px auto;*/
+
+ column-count:3;
+ -webkit-column-count:3;
+ -moz-column-count:3;
+/*
+ column-width:100%;
+ -webkit-column-width:200px;
+ -col-column-width:200px;
+*/
+ column-gap:41px;
+ -webkit-column-gap:41px;
+ -moz-column-gap:41px;
+
+ column-rule: 1px dashed #ccc;
+ -webkit-column-rule: 1px dashed #ccc;
+ -moz-column-rule: 1px dashed #ccc;
+ }
+
+ .flowList dl{
+ }
+ .flowList dd{
+ /*display:inline-block;*/
+ margin-left:10px;
+ min-width:250px;
+ line-height: 1.5;
+ min-width:100%;
+ min-height:15px;
+ }
+
+ .flowList dd a{
+ }
+
+ .content .flowList p{
+ padding:0px;
+ }
+
+ .content .alignedsummary
+ {
+ margin: 15px;
+ }
+
+
+ .qmltype
+ {
+ text-align: center;
+ font-size: 120%;
+ }
+ .qmlreadonly
+ {
+ padding-left: 5px;
+ float: right;
+ color: #254117;
+ }
+
+ .qmldefault
+ {
+ padding-left: 5px;
+ float: right;
+ color: red;
+ }
+
+ .qmldoc
+ {
+ }
+
+ .generic .alphaChar{
+ margin-top:5px;
+ }
+
+ .generic .odd .alphaChar{
+ background-color: #F6F6F6;
+ }
+
+ .generic .even .alphaChar{
+ background-color: #FFFFFF;
+ }
+
+ .memItemRight{
+ padding: 0.25em 1.5em 0.25em 0;
+ }
+ .highlightedCode
+ {
+ margin: 1.0em;
+ }
+ .annotated td {
+ padding: 0.25em 0.5em 0.25em 0.5em;
+ }
+
+ .toc
+ {
+ font-size: 80%
+ }
+
+ .header .content .toc ul
+ {
+ padding-left: 0px;
+ }
+
+ .content .toc h3 {
+ border-bottom: 0px;
+ margin-top: 0px;
+ }
+
+ .content .toc h3 a:hover {
+ color: #00732F;
+ text-decoration: none;
+ }
+
+ .content .toc .level2
+ {
+ margin-left: 1.5em;
+ }
+
+ .content .toc .level3
+ {
+ margin-left: 3.0em;
+ }
+
+ .content ul li
+ {
+ background: url(../images/bullet_sq.png) no-repeat 0 0.7em;
+ padding-left: 1em
+ }
+
+ .content .toc li
+ {
+ background: url(../images/bullet_dn.png) no-repeat 0 5px;
+ padding-left: 1em
+ }
+
+ .relpage
+ {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ border: 1px solid #DDDDDD;
+ padding: 25px 25px;
+ clear: both;
+ }
+ .relpage ul
+ {
+ float: none;
+ padding: 1.5em;
+ }
+
+ h3.fn, span.fn
+ {
+ -moz-border-radius:7px 7px 7px 7px;
+ -webkit-border-radius:7px 7px 7px 7px;
+ border-radius:7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ font-weight: bold;
+ word-spacing:3px;
+ padding:3px 5px;
+ }
+
+ .functionIndex {
+ font-size:12pt;
+ word-spacing:10px;
+ margin-bottom:10px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ width:100%;
+ }
+
+ .centerAlign
+ {
+ text-align:center;
+ }
+
+ .rightAlign
+ {
+ text-align:right;
+ }
+
+ .leftAlign
+ {
+ text-align:left;
+ }
+
+ .topAlign{
+ vertical-align:top
+ }
+
+ .functionIndex a{
+ display:inline-block;
+ }
+
+/* end content elements */
+/* footer elements */
+
+ .footer
+ {
+ color: #393735;
+ font-size: 0.75em;
+ text-align: center;
+ padding-top: 1.5em;
+ padding-bottom: 1em;
+ background-color: #E6E7E8;
+ margin: 0;
+ }
+ .footer p
+ {
+ margin: 0.25em
+ }
+ .small
+ {
+ font-size: 0.5em;
+ }
+/* end footer elements */
+
+ .item {
+ float: left;
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+ }
+
+
+ .item .primary {
+ margin-right: 220px;
+ position: relative;
+ }
+
+ .item hr {
+ margin-left: -220px;
+ }
+
+ .item .secondary {
+ float: right;
+ width: 200px;
+ position: relative;
+ }
+
+ .item .cols {
+ clear: both;
+ display: block;
+ }
+
+ .item .cols .col {
+ float: left;
+ margin-left: 1.5%;
+ }
+
+ .item .cols .col.first {
+ margin-left: 0;
+ }
+
+ .item .cols.two .col {
+ width: 45%;
+ }
+
+ .item .box {
+ margin: 0 0 10px 0;
+ }
+
+ .item .box h3 {
+ margin: 0 0 10px 0;
+ }
+
+ .cols.unclear {
+ clear:none;
+ }
+}
+
+/* end of screen media */
+
+/* start of print media */
+
+@media print
+{
+ input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult
+ {
+ display: none;
+ background: none;
+ }
+ .content
+ {
+ background: none;
+ display: block;
+ width: 100%; margin: 0; float: none;
+ }
+}
+/* end of print media */
diff --git a/doc/templates/style/style.css b/doc/templates/style/style.css
new file mode 100644
index 000000000..af16d41e7
--- /dev/null
+++ b/doc/templates/style/style.css
@@ -0,0 +1,1592 @@
+@media screen
+{
+
+/* basic elements */
+ html
+ {
+ color: #000000;
+ background: #FFFFFF;
+ }
+ body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, th, td
+ {
+ margin: 0;
+ padding: 0;
+ }
+ table
+ {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+ fieldset, img
+ {
+ border: 0;
+ max-width:100%;
+ }
+ address, caption, cite, code, dfn, em, strong, th, var, optgroup
+ {
+ font-style: inherit;
+ font-weight: inherit;
+ }
+ del, ins
+ {
+ text-decoration: none;
+ }
+ li
+ {
+ list-style: none;
+ }
+ ol li
+ {
+ list-style: decimal;
+ }
+ caption, th
+ {
+ text-align: left;
+ }
+ h1, h2, h3, h4, h5, h6
+ {
+ font-size: 100%;
+ }
+ q:before, q:after
+ {
+ content: '';
+ }
+ abbr, acronym
+ {
+ border: 0;
+ font-variant: normal;
+ }
+ sup, sub
+ {
+ vertical-align: baseline;
+ }
+ tt, .qmlreadonly span, .qmldefault span
+ {
+ word-spacing:5px;
+ }
+ legend
+ {
+ color: #000000;
+ }
+ input, button, textarea, select, optgroup, option
+ {
+ font-family: inherit;
+ font-size: inherit;
+ font-style: inherit;
+ font-weight: inherit;
+ }
+ input, button, textarea, select
+ {
+ font-size: 100%;
+ }
+ strong
+ {
+ font-weight: bold;
+ }
+ em
+ {
+ font-style: italic;
+ }
+
+ /* adding Qt theme */
+ html
+ {
+ /* background-color: #e5e5e5;*/
+ }
+ body
+ {
+ background: #e6e7e8 url(../images/page_bg.png) repeat-x 0 0;
+ font: normal 13px/1.2 Verdana;
+ color: #363534;
+ }
+ a
+ {
+ color: #00732f;
+ text-decoration: none;
+ }
+ hr
+ {
+ background-color: #E6E6E6;
+ border: 1px solid #E6E6E6;
+ height: 1px;
+ width: 100%;
+ text-align: left;
+ margin: 15px 0px 15px 0px;
+ }
+
+ pre
+ {
+ border: 1px solid #DDDDDD;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ margin: 0 20px 10px 10px;
+ padding: 20px 15px 20px 20px;
+ overflow-x: auto;
+ }
+ table, pre
+ {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ font-size: 11px;
+ margin-bottom: 25px;
+ }
+ pre.highlightedCode {
+ display: block;
+ overflow:hidden;
+ }
+ thead
+ {
+ margin-top: 5px;
+ font:600 12px/1.2 Arial;
+ }
+ th
+ {
+ padding: 5px 15px 5px 15px;
+ background-color: #E1E1E1;
+ border-left: 1px solid #E6E6E6;
+ }
+ td
+ {
+ padding: 3px 15px 3px 15px;
+ }
+ tr.odd td:hover, tr.even td:hover {}
+
+ td.rightAlign
+ {
+ padding: 3px 5px 3px 10px;
+ }
+ table tr.odd
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #F6F6F6;
+ color: #66666E;
+ }
+ table tr.even
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #ffffff;
+ color: #66666E;
+ }
+ table tr.odd td:hover, table tr.even td:hover
+ {
+ /* background-color: #E6E6E6;*/ /* disabled until further notice */
+ }
+
+ span.comment
+ {
+ color: #8B0000;
+ font-style: italic;
+ }
+ span.string, span.char
+ {
+ color: #254117;
+ }
+
+
+/* end basic elements */
+
+/* font style elements */
+ .heading
+ {
+ font: normal bold 16px/1.2 Arial;
+ padding-bottom: 15px;
+ }
+ .subtitle
+ {
+ font-size: 13px;
+ }
+ .small-subtitle
+ {
+ font-size: 13px;
+ }
+/* end font style elements */
+
+/* global settings*/
+ .header, .footer, .wrapper
+ {
+ min-width: 600px;
+ max-width: 1500px;
+ margin: 0 30px;
+ }
+ .header, .footer
+ {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ }
+ .header:after, .footer:after, .breadcrumb:after, .wrap .content:after, .group:after
+ {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+
+/* end global settings*/
+/* header elements */
+ .header
+ {
+ height: 115px;
+ position: relative;
+ }
+ .header .icon
+ {
+ position: absolute;
+ top: 13px;
+ left: 0;
+ }
+ .header .qtref
+ {
+ position: absolute;
+ top: 28px;
+ left: 88px;
+ width: 302px;
+ height: 22px;
+ }
+ .header .qtref span
+ {
+ display: block;
+ width: 302px;
+ height: 22px;
+ text-indent: -999em;
+ background: url(../images/sprites-combined.png) no-repeat -78px -235px;
+ }
+ .content a:visited
+ {
+ color: #4c0033;
+ text-decoration: none;
+ }
+ .content a:visited:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+
+ #nav-topright
+ {
+ height: 70px;
+ }
+
+ #nav-topright ul
+ {
+ list-style-type: none;
+ float: right;
+ width: 370px;
+ margin-top: 11px;
+ }
+
+ #nav-topright li
+ {
+ display: inline-block;
+ margin-right: 20px;
+ float: left;
+ }
+
+ #nav-topright li.nav-topright-last
+ {
+ margin-right: 0;
+ }
+
+ #nav-topright li a
+ {
+ background: transparent url(../images/sprites-combined.png) no-repeat;
+ height: 18px;
+ display: block;
+ overflow: hidden;
+ text-indent: -9999px;
+ }
+
+ #nav-topright li.nav-topright-home a
+ {
+ width: 65px;
+ background-position: -2px -91px;
+ }
+
+ #nav-topright li.nav-topright-home a:hover
+ {
+ background-position: -2px -117px;
+ }
+
+
+ #nav-topright li.nav-topright-dev a
+ {
+ width: 30px;
+ background-position: -76px -91px;
+ }
+
+ #nav-topright li.nav-topright-dev a:hover
+ {
+ background-position: -76px -117px;
+ }
+
+
+ #nav-topright li.nav-topright-labs a
+ {
+ width: 40px;
+ background-position: -114px -91px;
+ }
+
+ #nav-topright li.nav-topright-labs a:hover
+ {
+ background-position: -114px -117px;
+ }
+
+ #nav-topright li.nav-topright-doc a
+ {
+ width: 32px;
+ background-position: -162px -91px;
+ }
+
+ #nav-topright li.nav-topright-doc a:hover, #nav-topright li.nav-topright-doc-active a
+ {
+ background-position: -162px -117px;
+ }
+
+ #nav-topright li.nav-topright-blog a
+ {
+ width: 40px;
+ background-position: -203px -91px;
+ }
+
+ #nav-topright li.nav-topright-blog a:hover, #nav-topright li.nav-topright-blog-active a
+ {
+ background-position: -203px -117px;
+ }
+
+ #nav-topright li.nav-topright-shop a
+ {
+ width: 40px;
+ background-position: -252px -91px;
+ }
+
+ #nav-topright li.nav-topright-shop a:hover, #nav-topright li.nav-topright-shop-active a
+ {
+ background-position: -252px -117px;
+ }
+
+ #nav-logo
+ {
+ background: transparent url(../images/sprites-combined.png ) no-repeat 0 -225px;
+ left: -3px;
+ position: absolute;
+ width: 75px;
+ height: 75px;
+ top: 13px;
+ }
+ #nav-logo a
+ {
+ width: 75px;
+ height: 75px;
+ display: block;
+ text-indent: -9999px;
+ overflow: hidden;
+ }
+
+
+ .shortCut-topleft-inactive
+ {
+ padding-left: 3px;
+ padding-right: 3px;
+ background: transparent url( ../images/sprites-combined.png) no-repeat 0px -58px;
+ height: 20px;
+ }
+ .shortCut-topleft-inactive span
+ {
+ font-variant: normal;
+ }
+ .shortCut-topleft-inactive span a:hover, .shortCut-topleft-active a:hover
+ {
+ text-decoration:none;
+ }
+ #shortCut
+ {
+ padding-top: 10px;
+ font-weight: bolder;
+ color: #b0adab;
+ }
+ #shortCut ul
+ {
+ list-style-type: none;
+ float: left;
+ width: 347px;
+ margin-left: 100px;
+ }
+ #shortCut li
+ {
+ display: inline-block;
+ margin-right: 25px;
+ float: left;
+ white-space: nowrap;
+ }
+ #shortCut li a
+ {
+ color: #b0adab;
+ }
+ #shortCut li a:hover
+ {
+ color: #44a51c;
+ }
+
+
+
+/* end header elements */
+/* content and sidebar elements */
+ .wrapper
+ {
+ background: url(../images/bg_r.png) repeat-y 100% 0;
+ }
+ .wrapper .hd
+ {
+ padding-left: 216px;
+ height: 15px;
+ background: url(../images/page.png) no-repeat 0 0;
+ overflow: hidden;
+ }
+
+
+
+
+ .wrapper .hd span
+ {
+ height: 15px;
+ display: block;
+ overflow: hidden;
+ background: url(../images/page.png) no-repeat 100% -30px;
+ }
+ .wrapper .bd
+ {
+ background: url(../images/bg_l.png) repeat-y 0 0;
+ position: relative;
+ }
+
+
+
+
+ .wrapper .ft
+ {
+ padding-left: 216px;
+ height: 15px;
+ background: url(../images/page.png) no-repeat 0 -75px;
+ overflow: hidden;
+ }
+
+
+
+
+ .wrapper .ft span
+ {
+ height: 15px;
+ display: block;
+ background: url(../images/page.png) no-repeat 100% -60px;
+ overflow: hidden;
+ }
+ .navTop{
+ float:right;
+ display:block;
+ padding-right:15px;
+
+
+ }
+
+
+
+/* end content and sidebar elements */
+/* sidebar elements */
+ .sidebar
+ {
+ float: left;
+ margin-left: 5px;
+ width: 200px;
+ font-size: 11px;
+ }
+
+
+
+
+
+
+ .sidebar .searchlabel
+ {
+ padding: 0 0 2px 17px;
+ font: normal bold 11px/1.2 Verdana;
+ }
+
+ .sidebar .search
+ {
+ padding: 0 15px 0 16px;
+ }
+
+ .sidebar .search form
+ {
+ background: url(../images/sprites-combined.png) no-repeat -6px -348px;
+ height:21px;
+ padding:2px 0 0 5px;
+ width:167px;
+ }
+
+ .sidebar .search form input#pageType
+ {
+ width: 158px;
+ height: 19px;
+ padding: 0;
+ border: 0px;
+ outline: none;
+ font: 13px/1.2 Verdana;
+ }
+
+ .sidebar .box
+ {
+ padding: 17px 15px 5px 16px;
+ }
+
+ .sidebar .box .first
+ {
+ background-image: none;
+ }
+
+ .sidebar .box h2
+ {
+ font: bold 16px/1.2 Arial;
+ padding: 0;
+ }
+ .sidebar .box h2 span
+ {
+ overflow: hidden;
+ display: inline-block;
+ }
+ .sidebar .box#lookup h2
+ {
+ background-image: none;
+ }
+ .sidebar #lookup.box h2 span
+ {
+ }
+ .sidebar .box#topics h2
+ {
+ background-image: none;
+ }
+ .sidebar #topics.box h2 span
+ {
+ }
+ .sidebar .box#examples h2
+ {
+ background-image: none;
+ }
+ .sidebar #examples.box h2 span
+ {
+ }
+
+ .sidebar .box .list
+ {
+ display: block;
+ max-height:200px;
+ min-height:120px;
+ overflow-y:auto;
+ overflow-x:none;
+ }
+ .list li a:hover
+ {
+ text-decoration: underline;
+ }
+ .sidebar .box ul
+ {
+ padding-bottom:5px;
+ padding-left:10px;
+ padding-top:5px;
+ }
+ .sidebar .box ul li
+ {
+ padding-left: 12px;
+ background: url(../images/bullet_gt.png) no-repeat 0 5px;
+ margin-bottom: 5px;
+ }
+ .sidebar .bottombar
+ {
+ background: url(../images/box_bg.png) repeat-x 0 bottom;
+ }
+ .sidebar .box ul li.noMatch
+ {
+ background: none;
+ color:#FF2A00;
+ font-style:italic;
+ }
+ .sidebar .box ul li.hit
+ {
+ background: none;
+ color:#AAD2F0;
+ font-style:italic;
+ }
+ .sidebar .search form input.loading
+ {
+ background:url("../images/spinner.gif") no-repeat scroll right center transparent;
+ }
+
+.floatingResult{
+ z-index:1;
+ position:relative;
+ padding-top:0px;
+ background-color:white;
+ border:solid 1px black;
+ height:250px;
+ width:600px;
+ overflow-x:hidden;
+ overflow-y:auto;
+}
+
+ .floatingResult:hover{
+ display:block;
+ }
+ .floatingResult:hover{
+ }
+
+/* end sidebar elements */
+/* content elements */
+ .wrap
+ {
+ margin: 0 5px 0 208px;
+ overflow: visible;
+ }
+
+
+
+
+ .wrap .toolbar
+ {
+ background-color: #fafafa;
+ border-bottom: 1px solid #d1d1d1;
+ height: 20px;
+ position: relative;
+ }
+ .wrap .toolbar .toolblock
+ {
+ position: absolute;
+ }
+ .wrap .toolbar .breadcrumb
+ {
+ font-size: 11px;
+ line-height: 1.2;
+ padding: 0 0 10px 21px;
+ height: 10px;
+ }
+ .wrap .toolbar .toolbuttons
+ {
+ padding: 0 0 10px 21px;
+ right: 5px;
+ vertical-align: middle;
+ overflow: hidden;
+ }
+ .wrap .toolbar .toolbuttons .active
+ {
+ color: #00732F;
+ }
+ .wrap .toolbar .toolbuttons ul
+ {
+ float: right;
+ }
+ .wrap .toolbar .toolbuttons li
+ {
+ float: left;
+ text-indent: -10px;
+ margin-top: -5px;
+ margin-right: 15px;
+ font-weight: bold;
+ color: #B0ADAB;
+ }
+
+ .toolbuttons #print
+ {
+ border-left: 1px solid #c5c4c4;
+ margin-top: 0;
+ padding-left: 7px;
+ text-indent: 0;
+ }
+ .toolbuttons #print a
+ {
+ width: 16px;
+ height: 16px;
+ }
+
+ .toolbuttons #print a span
+ {
+ width: 16px;
+ height: 16px;
+ text-indent: -999em;
+ display: block;
+ overflow: hidden;
+ background: url(../images/sprites-combined.png) no-repeat -137px -311px;
+ }
+
+ .toolbuttons #smallA
+ {
+ font-size: 10pt;
+ }
+ .toolbuttons #medA
+ {
+ font-size: 12pt;
+ }
+ .toolbuttons #bigA
+ {
+ font-size: 14pt;
+ margin-right: 7px;
+ }
+
+ #smallA:hover, #medA:hover, #bigA:hover
+ {
+ color: #00732F;
+ }
+
+
+ .wrap .content
+ {
+ padding: 30px;
+ word-wrap:break-word;
+ }
+
+ .wrap .breadcrumb ul
+ {
+ }
+ .wrap .breadcrumb ul li
+ {
+ float: left;
+ background: url(../images/breadcrumb.png) no-repeat 0 3px;
+ padding-left: 15px;
+ margin-left: 15px;
+ font-weight: bold;
+ }
+ .wrap .breadcrumb ul li.last
+ {
+ font-weight: normal;
+ }
+ .wrap .breadcrumb ul li a
+ {
+ color: #363534;
+ }
+ .wrap .breadcrumb ul li.first
+ {
+ background-image: none;
+ padding-left: 0;
+ margin-left: 0;
+ }
+
+
+
+
+ .wrap .content ol li {
+ background:none;
+ font:normal 10pt/1.2 Verdana;
+
+ margin-bottom:10px;
+ margin-left:12px;
+ /*list-style-type:disc;*/
+ }
+
+ .wrap .content ol li
+ {
+ background:none;
+ margin-bottom: 10px;
+ padding-left:0px;
+ margin-left:52px;
+ }
+
+ .wrap .content li
+ {
+ background: url(../images/bullet_sq.png) no-repeat 0 5px;
+ font: normal 400 10pt/1.2 Verdana;
+ margin-bottom: 10px;
+ padding-left:12px;
+ }
+
+ .content li:hover {}
+
+ .wrap .content h1
+ {
+ font: bold 18px/1.2 Arial;
+ }
+ .wrap .content h2
+ {
+ border-bottom:1px solid #DDDDDD;
+ font:600 16px/1.2 Arial;
+ margin-top:15px;
+ width:100%;
+ }
+ .wrap .content h3
+ {
+ font: bold 14px/1.2 Arial;
+ font:600 16px/1.2 Arial;
+ margin-top:15px;
+ width:100%;
+ }
+ .wrap .content p
+ {
+ line-height: 20px;
+ padding: 5px;
+ }
+ .wrap .content table p
+ {
+ line-height: 20px;
+ /* padding: 0px;*/
+ }
+ .wrap .content ul
+ {
+ padding-left: 25px;
+ padding-top: 10px;
+ }
+ .wrap .content ul img {
+ vertical-align:middle;
+ }
+ a:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+ .feedback
+ {
+ float: none;
+ position: absolute;
+ right: 15px;
+ bottom: 10px;
+ font: normal 8px/1 Verdana;
+ color: #B0ADAB;
+ }
+ .feedback:hover
+ {
+ float: right;
+ font: normal 8px/1 Verdana;
+ color: #00732F;
+ text-decoration: underline;
+ }
+ .alphaChar{
+ width:95%;
+ background-color:#F6F6F6;
+ border:1px solid #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ font-size:12pt;
+ padding-left:10px;
+ margin-top:10px;
+ margin-bottom:10px;
+ }
+ .flowList{
+ /*vertical-align:top;*/
+ /*margin:20px auto;*/
+
+ column-count:3;
+ -webkit-column-count:3;
+ -moz-column-count:3;
+/*
+ column-width:100%;
+ -webkit-column-width:200px;
+ -col-column-width:200px;
+*/
+ column-gap:41px;
+ -webkit-column-gap:41px;
+ -moz-column-gap:41px;
+
+ column-rule: 1px dashed #ccc;
+ -webkit-column-rule: 1px dashed #ccc;
+ -moz-column-rule: 1px dashed #ccc;
+ }
+
+ .flowList dl{
+ }
+ .flowList dd{
+ /*display:inline-block;*/
+ margin-left:10px;
+ min-width:250px;
+ line-height: 1.2;
+ min-width:100%;
+
+ }
+
+ .flowList dd a{
+ }
+
+ .wrap .content .flowList p{
+ padding:0px;
+ }
+
+ .content .alignedsummary
+ {
+ margin: 15px;
+ }
+
+
+ .qmltype
+ {
+ text-align: center;
+ font-size: 160%;
+ }
+ .qmlreadonly
+ {
+ padding-left: 5px;
+ float: right;
+ color: #254117;
+ }
+
+ .qmldefault
+ {
+ padding-left: 5px;
+ float: right;
+ color: red;
+ }
+
+ .qmldoc
+ {
+ }
+
+ *.qmlitem p
+ {
+ }
+ #feedbackBox
+ {
+ display: none;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ border: 1px solid #DDDDDD;
+ position: fixed;
+ top: 100px;
+ left: 33%;
+ height: 230px;
+ width: 400px;
+ padding: 5px;
+ background-color: #e6e7e8;
+ z-index: 4;
+ }
+ #feedcloseX
+ {
+ display: inline;
+ padding: 5px 5px 0 0;
+ margin-bottom: 3px;
+ color: #363534;
+ font-weight: bold;
+ float: right;
+ text-decoration: none;
+ }
+
+ #feedbox
+ {
+ display: inline;
+ width: 370px;
+ height: 120px;
+ margin: 0px 25px 10px 15px;
+ }
+ #noteHead
+ {
+ font-weight:bold;
+ padding:10px 10px 10px 20px;
+ }
+ #feedsubmit
+ {
+ display: inline;
+ float: right;
+ margin: 4px 32px 0 0;
+ }
+
+ .note
+ {
+ font-size:7pt;
+ padding-bottom:3px;
+ padding-left:20px;
+ }
+
+ #blurpage
+ {
+ display: none;
+ position: fixed;
+ float: none;
+ top: 0px;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+ background: transparent url(../images/feedbackground.png) 0 0;
+ z-index: 3;
+ }
+ .toc
+ {
+ float: right;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #DDDDDD;
+ margin: 0 20px 10px 10px;
+ padding: 20px 15px 20px 20px;
+ height: auto;
+ width: 200px;
+ }
+
+ .toc h3, .generic a
+ {
+ font: bold 12px/1.2 Arial;
+ }
+
+ .generic{
+ }
+ .generic td{
+ /* padding:5px;*/
+ }
+ .generic .alphaChar{
+ margin-top:5px;
+ }
+
+ .generic .odd .alphaChar{
+ background-color: #F6F6F6;
+ }
+
+ .generic .even .alphaChar{
+ background-color: #FFFFFF;
+ }
+
+ .alignedsummary{}
+ .propsummary{}
+ .memItemLeft{}
+ .memItemRight{
+ padding:3px 15px 3px 0;
+ }
+ .bottomAlign{}
+ .highlightedCode
+ {
+ margin:10px;
+ }
+ .LegaleseLeft{}
+ .valuelist{}
+ .annotated td{
+ padding: 3px 5px 3px 5px;
+ }
+ .obsolete{}
+ .compat{}
+ .flags{}
+ .qmlsummary{}
+ .qmlitem{}
+ .qmlproto{}
+ .qmlname{}
+ .qmlreadonly{}
+ .qmldefault{}
+ .qmldoc{}
+ .qt-style{}
+ .redFont{}
+ code{}
+
+ .wrap .content .toc ul
+ {
+ padding-left: 0px;
+ }
+
+ .wrap .content .toc h3{
+ border-bottom:0px;
+ margin-top:0px;
+ }
+
+ .wrap .content .toc h3 a:hover{
+ color:#00732F;
+ text-decoration:none;
+ }
+
+
+ .wrap .content .toc .level2
+ {
+ margin-left: 15px;
+ }
+
+ .wrap .content .toc .level3
+ {
+ margin-left: 30px;
+ }
+
+ .content .toc li
+ {
+ font: normal 10px/1.2 Verdana;
+ background: url(../images/bullet_dn.png) no-repeat 0 5px;
+ }
+ .relpage
+ {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ border: 1px solid #DDDDDD;
+ padding: 25px 25px;
+ clear: both;
+ }
+ .relpage ul
+ {
+ float: none;
+ padding: 15px;
+ }
+ .content .relpage li
+ {
+ font: normal 11px/1.2 Verdana;
+ }
+ h3.fn, span.fn
+ {
+ -moz-border-radius:7px 7px 7px 7px;
+ -webkit-border-radius:7px 7px 7px 7px;
+ border-radius:7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ font-weight: bold;
+ word-spacing:3px;
+ padding:3px 5px;
+ }
+
+ .functionIndex {
+ font-size:12pt;
+ word-spacing:10px;
+ margin-bottom:10px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ width:100%;
+ }
+
+ .centerAlign
+ {
+ text-align:center;
+ }
+
+ .rightAlign
+ {
+ text-align:right;
+ }
+
+
+ .leftAlign
+ {
+ text-align:left;
+ }
+
+ .topAlign{
+ vertical-align:top
+ }
+
+ .functionIndex a{
+ display:inline-block;
+ }
+
+/* end content elements */
+/* footer elements */
+
+ .footer
+ {
+ min-height: 100px;
+ color: #797775;
+ font: normal 9px/1 Verdana;
+ text-align: center;
+ padding-top: 40px;
+ background-color: #E6E7E8;
+ margin: 0;
+ }
+/* end footer elements */
+
+
+
+
+ /* start index box */
+ .indexbox
+ {
+ width: 100%;
+ display:inline-block;
+ }
+
+ .indexboxcont
+ {
+ display: block;
+
+ }
+
+ .indexboxbar
+ {
+ background: transparent url(../images/horBar.png ) repeat-x left bottom;
+ margin-bottom: 25px;
+
+
+ }
+
+ .indexboxcont .section
+ {
+ display: inline-block;
+ width: 49%;
+ *width:42%;
+ _width:42%;
+ padding:0 2% 0 1%;
+ vertical-align:top;
+
+}
+
+ .indexboxcont .indexIcon
+ {
+ width: 11%;
+ *width:18%;
+ _width:18%;
+ overflow:hidden;
+
+}
+
+.indexboxcont .section {
+ float: left;
+}
+
+ .indexboxcont .section p
+ {
+ padding-top: 20px;
+ padding-bottom: 20px;
+ }
+ .indexboxcont .sectionlist
+ {
+ display: inline-block;
+ vertical-align:top;
+ width: 32.5%;
+ padding: 0;
+ }
+ .indexboxcont .sectionlist ul
+ {
+ margin-bottom: 20px;
+ }
+
+ .indexboxcont .sectionlist ul li
+ {
+ line-height: 12px;
+ }
+
+ .content .indexboxcont li
+ {
+ font: normal bold 13px/1 Verdana;
+ }
+
+ .indexbox a:hover, .indexbox a:visited:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+
+ .indexbox a:visited
+ {
+ color: #00732f;
+ text-decoration: none;
+ }
+
+ .indexbox .indexIcon {
+ width: 11%;
+ }
+
+
+ .indexbox .indexIcon span
+ {
+ display: block;
+ }
+
+ .indexbox.guide .indexIcon span
+ {
+ width: 96px;
+ height: 137px;
+ background: url(../images/sprites-combined.png) no-repeat -5px -376px;
+ padding: 0;
+ }
+
+ .indexbox.tools .indexIcon span
+ {
+ width: 115px;
+ height: 137px;
+ background: url(../images/sprites-combined.png) no-repeat -111px -376px;
+ padding: 0;
+ }
+ .indexboxcont:after
+ {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+
+
+
+/* start of creator spec*/
+ .creator
+ {
+ margin-left:0px;
+ margin-right:0px;
+ padding-left:0px;
+ padding-right:0px;
+ }
+ .creator .wrap .content ol li {
+ list-style-type:decimal;
+
+ }
+ .creator .header .icon,
+ .creator .feedback,
+ .creator .t_button,
+ .creator .feedback,
+ .creator #feedbackBox,
+ .creator #feedback,
+ .creator #blurpage,
+ /*.creator .indexbox .indexIcon span,*/
+ .creator .wrapper .hd,
+/* .creator .indexbox .indexIcon,*/
+ .creator .header #nav-logo,
+ .creator #offlinemenu,
+ .creator #offlinesearch,
+ .creator .header #nav-topright,
+ .creator .header #shortCut ,
+ .creator .wrapper .hd,
+ .creator .wrapper .ft,
+ .creator .sidebar,
+ .creator .wrap .feedback
+ {
+ display:none;
+ }
+
+ body.creator
+ {
+ background: none;
+
+ font: normal 13px/1.2 Verdana;
+ color: #363534;
+ background-color: #FAFAFA;
+ }
+
+ .wrap .content ol li {
+
+ }
+
+
+ .creator .header, .footer, .wrapper
+ {
+ max-width: 1500px;
+ margin: 0px;
+ }
+
+ .creator .wrapper
+ {
+ position:relative;
+ top:5px;
+ }
+ .creator .wrapper .bd
+ {
+
+ background:#FFFFFF;
+ }
+
+
+ .creator .header, .footer
+ {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ }
+ .creator .wrap .content p
+
+ {
+ line-height: 20px;
+ padding: 5px;
+ }
+
+ .creator .header .qtref span
+ {
+ background:none;
+ }
+
+
+
+ .creator .footer
+ {
+ border-top:1px solid #E5E5E5;
+ height: 50px;
+ margin:0px;
+ padding:10px;
+ }
+
+ .creator .footer p
+ {
+ text-align:justify;
+ max-width:900px;
+ }
+
+ .creator .wrap
+ {
+
+ padding:0 5px 0 5px;
+ margin: 0px;
+ }
+ .creator .wrap .toolbar
+ {
+
+
+ border-bottom:1px solid #E5E5E5;
+ /*width:100%;*/
+ margin-left:-5px;
+ margin-right:-5px;
+ }
+ .creator .wrap .breadcrumb ul li a
+ {
+ /* color: #363534;*/
+ color: #00732F;
+ }
+
+ .creator .wrap .content
+ {
+ padding: 0px;
+ word-wrap:break-word;
+ }
+
+ .creator .wrap .content ol li {
+ background:none;
+ font: inherit;
+ padding-left: 0px;
+ }
+
+ .creator .wrap .content .descr ol li {
+ margin-left: 45px;
+
+ }
+ .creator .content .alignedsummary
+ {
+ margin: 5px;
+ width:100%;
+ }
+ .creator .generic{
+ max-width:75%;
+ }
+ .creator .generic td{
+ /* padding:0;*/
+ }
+ .creator .indexboxbar
+ {
+ border-bottom:1px solid #E5E5E5;
+ margin-bottom: 25px;
+ background: none;
+ }
+
+
+
+ .creator .header
+ {
+ width: 100%;
+ margin: 0;
+ height: auto;
+ background-color: #ffffff;
+ padding: 10px 0 5px 0;
+ overflow: visible;
+ border-bottom: solid #E5E5E5 1px;
+ z-index:1;
+
+
+
+
+
+
+
+
+ /* position:fixed;*/
+ }
+
+
+ .creator .header .content
+ {
+ }
+ .creator .header .qtref
+ {
+ color: #00732F;
+ position: static;
+ float: left;
+ margin-left: 5px;
+ font: bold 18px/1 Arial;
+ }
+
+ .creator .header .qtref:visited
+ {
+ color: #00732F;
+ }
+ .creator .header .qtref:hover
+ {
+ color: #00732F;
+ text-decoration:none;
+ }
+ .creator .header .qtref span
+ {
+ background-image: none;
+ text-indent: 0;
+ text-decoration:none;
+ }
+
+
+
+
+
+
+ .creator .wrap .toolbar
+ {
+ display:block;
+ padding-top:0px;
+ }
+
+
+
+ .creator .wrap .breadcrumb ul li {
+ font-weight: normal;
+ }
+
+ .creator .wrap .breadcrumb ul li a {
+ /*color: #44a51c;*/
+ }
+
+ .creator .wrap .breadcrumb ul li.last a {
+ /*color: #363534;*/
+ }
+
+ .creator #narrowmenu ul
+ {
+ border-bottom:solid 1px #E5E5E5;
+ border-left:solid 1px #E5E5E5;
+ border-right:solid 1px #E5E5E5;
+ }
+
+ .creator #narrowmenu li ul {
+ margin-top:-15px;
+ }
+
+
+ .creator .toc {
+ margin:10px 20px 10px 10px;
+ }
+
+ .creator #narrowsearch, .creator #narrowmenu{
+ display:none;
+ }
+/* end of creator spec*/
+
+}
+
+/* end of screen media */
+
+/* start of print media */
+
+@media print
+{
+ input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult
+ {
+ display: none;
+ background: none;
+ }
+ .content
+ {
+ background: none;
+ display: block;
+ width: 100%; margin: 0; float: none;
+
+ }
+}
+/* end of print media */
diff --git a/doc/templates/style/style_ie6.css b/doc/templates/style/style_ie6.css
new file mode 100644
index 000000000..16fb8505d
--- /dev/null
+++ b/doc/templates/style/style_ie6.css
@@ -0,0 +1,54 @@
+.indexbox, .indexboxcont, .group {
+ zoom: 1;
+ height: 1%;
+}
+
+.sidebar {
+ margin-left: 3px;
+ width: 199px;
+ overflow: hidden;
+}
+
+.sidebar .search form {
+ position: relative;
+}
+
+.sidebar .search form fieldset {
+ position: absolute;
+ margin-top: -1px;
+}
+
+.sidebar .search form input#searchstring {
+ border: 1px solid #fff;
+ height: 18px;
+}
+
+.wrap {
+ zoom: 1;
+}
+
+.content,
+.toolbar {
+ zoom: 1;
+ margin-left: -3px;
+ position: relative;
+}
+
+.indexbox {
+ clear: both;
+}
+
+.indexboxcont .section {
+ zoom: 1;
+ float: left;
+}
+
+.indexboxcont .sectionlist {
+ zoom: 1;
+ float: left;
+}
+
+.wrap .toolbar .toolbuttons li {
+ text-indent: 0;
+ margin-right: 8px;
+} \ No newline at end of file
diff --git a/doc/templates/style/style_ie7.css b/doc/templates/style/style_ie7.css
new file mode 100644
index 000000000..afbff5f88
--- /dev/null
+++ b/doc/templates/style/style_ie7.css
@@ -0,0 +1,19 @@
+.indexbox, .indexboxcont, .group {
+ min-height: 1px;
+}
+
+.sidebar .search form input#searchstring {
+ border: 1px solid #fff;
+ height: 17px;
+}
+
+
+.indexboxcont .section {
+ zoom: 1;
+ float: left;
+}
+
+.indexboxcont .sectionlist {
+ zoom: 1;
+ float: left;
+}
diff --git a/doc/templates/style/style_ie8.css b/doc/templates/style/style_ie8.css
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/doc/templates/style/style_ie8.css
diff --git a/doc/templates/style/superfish.css b/doc/templates/style/superfish.css
new file mode 100644
index 000000000..2bdaef4d9
--- /dev/null
+++ b/doc/templates/style/superfish.css
@@ -0,0 +1,51 @@
+.sf-menu, .sf-menu * {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.sf-menu {
+ line-height: 1.0;
+}
+.sf-menu ul {
+ position: absolute;
+ top: -999em;
+ width: 10em; /* left offset of submenus need to match (see below) */
+}
+.sf-menu ul li {
+ width: 100%;
+}
+.sf-menu li:hover {
+ visibility: inherit; /* fixes IE7 'sticky bug' */
+}
+.sf-menu li {
+ float: left;
+ position: relative;
+}
+.sf-menu a {
+ display: block;
+ position: relative;
+}
+.sf-menu li:hover ul,
+.sf-menu li.sfHover ul {
+ left: 0;
+ top: 2.5em; /* match top ul list item height */
+ z-index: 99;
+}
+ul.sf-menu li:hover li ul,
+ul.sf-menu li.sfHover li ul {
+ top: -999em;
+}
+ul.sf-menu li li:hover ul,
+ul.sf-menu li li.sfHover ul {
+ left: 10em; /* match ul width */
+ top: 0;
+}
+ul.sf-menu li li:hover li ul,
+ul.sf-menu li li.sfHover li ul {
+ top: -999em;
+}
+ul.sf-menu li li li:hover ul,
+ul.sf-menu li li li.sfHover ul {
+ left: 10em; /* match ul width */
+ top: 0;
+}
diff --git a/doc/templates/style/superfish_skin.css b/doc/templates/style/superfish_skin.css
new file mode 100644
index 000000000..8d84827c4
--- /dev/null
+++ b/doc/templates/style/superfish_skin.css
@@ -0,0 +1,83 @@
+
+/*** DEMO SKIN ***/
+.sf-menu {
+ float: left;
+ margin-bottom: 1em;
+}
+.sf-menu a {
+ border-left: 1px solid #fff;
+ border-top: 1px solid #CFDEFF;
+ padding: .75em 1em;
+ text-decoration:none;
+}
+.sf-menu a, .sf-menu a:visited { /* visited pseudo selector so IE6 applies text colour*/
+ color: #13a;
+}
+.sf-menu li {
+ background: #BDD2FF;
+}
+.sf-menu li li {
+ background: #AABDE6;
+}
+.sf-menu li li li {
+ background: #9AAEDB;
+}
+.sf-menu li:hover, .sf-menu li.sfHover,
+.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active {
+ background: #CFDEFF;
+ outline: 0;
+}
+
+/*** arrows **/
+.sf-menu a.sf-with-ul {
+ padding-right: 2.25em;
+ min-width: 1px; /* trigger IE7 hasLayout so spans position accurately */
+}
+.sf-sub-indicator {
+ position: absolute;
+ display: block;
+ right: .75em;
+ top: 1.05em; /* IE6 only */
+ width: 10px;
+ height: 10px;
+ text-indent: -999em;
+ overflow: hidden;
+ background: url('../images/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */
+}
+a > .sf-sub-indicator { /* give all except IE6 the correct values */
+ top: .8em;
+ background-position: 0 -100px; /* use translucent arrow for modern browsers*/
+}
+/* apply hovers to modern browsers */
+a:focus > .sf-sub-indicator,
+a:hover > .sf-sub-indicator,
+a:active > .sf-sub-indicator,
+li:hover > a > .sf-sub-indicator,
+li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px -100px; /* arrow hovers for modern browsers*/
+}
+
+/* point right for anchors in subs */
+.sf-menu ul .sf-sub-indicator { background-position: -10px 0; }
+.sf-menu ul a > .sf-sub-indicator { background-position: 0 0; }
+/* apply hovers to modern browsers */
+.sf-menu ul a:focus > .sf-sub-indicator,
+.sf-menu ul a:hover > .sf-sub-indicator,
+.sf-menu ul a:active > .sf-sub-indicator,
+.sf-menu ul li:hover > a > .sf-sub-indicator,
+.sf-menu ul li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px 0; /* arrow hovers for modern browsers*/
+}
+
+/*** shadows for all but IE6 ***/
+.sf-shadow ul {
+ background: url('../images/shadow.png') no-repeat bottom right;
+ padding: 0 8px 9px 0;
+ -moz-border-radius-bottomleft: 17px;
+ -moz-border-radius-topright: 17px;
+ -webkit-border-top-right-radius: 17px;
+ -webkit-border-bottom-left-radius: 17px;
+}
+.sf-shadow ul.sf-shadow-off {
+ background: transparent;
+}
diff --git a/qbs.pro b/qbs.pro
new file mode 100644
index 000000000..44019617c
--- /dev/null
+++ b/qbs.pro
@@ -0,0 +1,25 @@
+QBS_VERSION = 1.0.0
+TEMPLATE = subdirs
+CONFIG += ordered
+lib.file = src/lib/lib.pro
+src_app.subdir = src/app
+src_app.depends = lib
+SUBDIRS += \
+ lib\
+ src_app\
+ src/plugins\
+ static.pro\
+ tests
+
+OTHER_FILES += \
+ share/qbs/imports/qbs/base/* \
+ share/qbs/imports/qbs/fileinfo/* \
+ share/qbs/modules/*.* \
+ share/qbs/modules/cpp/*.* \
+ share/qbs/modules/qbs/*.* \
+ share/qbs/modules/qt/*.* \
+ share/qbs/modules/qt/core/*.* \
+ share/qbs/modules/qt/gui/*.* \
+ doc/qbs.qdoc
+
+include(doc/doc.pri)
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
new file mode 100644
index 000000000..5865e6a99
--- /dev/null
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: qbs.targetOS == 'mac' ? "applicationbundle" : "application"
+}
diff --git a/share/qbs/imports/qbs/base/DynamicLibrary.qbs b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
new file mode 100644
index 000000000..bf71dc8d5
--- /dev/null
+++ b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: "dynamiclibrary"
+}
diff --git a/share/qbs/imports/qbs/base/QmlApp.qbs b/share/qbs/imports/qbs/base/QmlApp.qbs
new file mode 100644
index 000000000..2d1ce228c
--- /dev/null
+++ b/share/qbs/imports/qbs/base/QmlApp.qbs
@@ -0,0 +1,22 @@
+import qbs.base 1.0
+
+Product {
+ type: ["application", "installed_content"]
+ Depends { name: "qt.declarative" }
+ Depends { name: "cpp" }
+ property string appViewerPath: localPath + "/qmlapplicationviewer"
+ cpp.includePaths: [appViewerPath]
+
+ Group {
+ files: [
+ appViewerPath + "/qmlapplicationviewer.h",
+ appViewerPath + "/qmlapplicationviewer.cpp"
+ ]
+ }
+
+ FileTagger {
+ pattern: "*.qml"
+ fileTags: ["install"]
+ }
+}
+
diff --git a/share/qbs/imports/qbs/base/StaticLibrary.qbs b/share/qbs/imports/qbs/base/StaticLibrary.qbs
new file mode 100644
index 000000000..da0416bee
--- /dev/null
+++ b/share/qbs/imports/qbs/base/StaticLibrary.qbs
@@ -0,0 +1,3 @@
+Product {
+ type: "staticlibrary"
+}
diff --git a/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp
new file mode 100644
index 000000000..997bbfcc7
--- /dev/null
+++ b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.cpp
@@ -0,0 +1,174 @@
+// checksum 0xee24 version 0x70013
+/*
+ This file was generated by the Qt Quick Application wizard of Qt Creator.
+ QmlApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#include "qmlapplicationviewer.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtGui/QApplication>
+#include <QtDeclarative/QDeclarativeComponent>
+#include <QtDeclarative/QDeclarativeEngine>
+#include <QtDeclarative/QDeclarativeContext>
+
+#include <qplatformdefs.h> // MEEGO_EDITION_HARMATTAN
+
+#ifdef HARMATTAN_BOOSTER
+#include <MDeclarativeCache>
+#endif
+
+#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800
+
+#include <qt_private/qdeclarativedebughelper_p.h>
+
+#if !defined(NO_JSDEBUGGER)
+#include <jsdebuggeragent.h>
+#endif
+#if !defined(NO_QMLOBSERVER)
+#include <qdeclarativeviewobserver.h>
+#endif
+
+// Enable debugging before any QDeclarativeEngine is created
+struct QmlJsDebuggingEnabler
+{
+ QmlJsDebuggingEnabler()
+ {
+ QDeclarativeDebugHelper::enableDebugging();
+ }
+};
+
+// Execute code in constructor before first QDeclarativeEngine is instantiated
+static QmlJsDebuggingEnabler enableDebuggingHelper;
+
+#endif // QMLJSDEBUGGER
+
+class QmlApplicationViewerPrivate
+{
+ QString mainQmlFile;
+ friend class QmlApplicationViewer;
+ static QString adjustPath(const QString &path);
+};
+
+QString QmlApplicationViewerPrivate::adjustPath(const QString &path)
+{
+#ifdef Q_OS_UNIX
+#ifdef Q_OS_MAC
+ if (!QDir::isAbsolutePath(path))
+ return QString::fromLatin1("%1/../Resources/%2")
+ .arg(QCoreApplication::applicationDirPath(), path);
+#else
+ const QString pathInInstallDir =
+ QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path);
+ if (QFileInfo(pathInInstallDir).exists())
+ return pathInInstallDir;
+#endif
+#endif
+ return path;
+}
+
+QmlApplicationViewer::QmlApplicationViewer(QWidget *parent)
+ : QDeclarativeView(parent)
+ , d(new QmlApplicationViewerPrivate())
+{
+ connect(engine(), SIGNAL(quit()), SLOT(close()));
+ setResizeMode(QDeclarativeView::SizeRootObjectToView);
+ // Qt versions prior to 4.8.0 don't have QML/JS debugging services built in
+#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800
+#if !defined(NO_JSDEBUGGER)
+ new QmlJSDebugger::JSDebuggerAgent(engine());
+#endif
+#if !defined(NO_QMLOBSERVER)
+ new QmlJSDebugger::QDeclarativeViewObserver(this, this);
+#endif
+#endif
+}
+
+QmlApplicationViewer::~QmlApplicationViewer()
+{
+ delete d;
+}
+
+QmlApplicationViewer *QmlApplicationViewer::create()
+{
+ return new QmlApplicationViewer();
+}
+
+void QmlApplicationViewer::setMainQmlFile(const QString &file)
+{
+ d->mainQmlFile = QmlApplicationViewerPrivate::adjustPath(file);
+ setSource(QUrl::fromLocalFile(d->mainQmlFile));
+}
+
+void QmlApplicationViewer::addImportPath(const QString &path)
+{
+ engine()->addImportPath(QmlApplicationViewerPrivate::adjustPath(path));
+}
+
+void QmlApplicationViewer::setOrientation(ScreenOrientation orientation)
+{
+#if defined(Q_OS_SYMBIAN)
+ // If the version of Qt on the device is < 4.7.2, that attribute won't work
+ if (orientation != ScreenOrientationAuto) {
+ const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
+ if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
+ qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
+ return;
+ }
+ }
+#endif // Q_OS_SYMBIAN
+
+ Qt::WidgetAttribute attribute;
+ switch (orientation) {
+#if QT_VERSION < 0x040702
+ // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
+ case ScreenOrientationLockPortrait:
+ attribute = static_cast<Qt::WidgetAttribute>(128);
+ break;
+ case ScreenOrientationLockLandscape:
+ attribute = static_cast<Qt::WidgetAttribute>(129);
+ break;
+ default:
+ case ScreenOrientationAuto:
+ attribute = static_cast<Qt::WidgetAttribute>(130);
+ break;
+#else // QT_VERSION < 0x040702
+ case ScreenOrientationLockPortrait:
+ attribute = Qt::WA_LockPortraitOrientation;
+ break;
+ case ScreenOrientationLockLandscape:
+ attribute = Qt::WA_LockLandscapeOrientation;
+ break;
+ default:
+ case ScreenOrientationAuto:
+ attribute = Qt::WA_AutoOrientation;
+ break;
+#endif // QT_VERSION < 0x040702
+ };
+ setAttribute(attribute, true);
+}
+
+void QmlApplicationViewer::showExpanded()
+{
+#if defined(Q_OS_SYMBIAN) || defined(MEEGO_EDITION_HARMATTAN) || defined(Q_WS_SIMULATOR)
+ showFullScreen();
+#elif defined(Q_WS_MAEMO_5)
+ showMaximized();
+#else
+ show();
+#endif
+}
+
+QApplication *createApplication(int &argc, char **argv)
+{
+#ifdef HARMATTAN_BOOSTER
+ return MDeclarativeCache::qApplication(argc, argv);
+#else
+ return new QApplication(argc, argv);
+#endif
+}
diff --git a/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h
new file mode 100644
index 000000000..b01cc886f
--- /dev/null
+++ b/share/qbs/imports/qbs/base/qmlapplicationviewer/qmlapplicationviewer.h
@@ -0,0 +1,46 @@
+// checksum 0x898f version 0x70013
+/*
+ This file was generated by the Qt Quick Application wizard of Qt Creator.
+ QmlApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#ifndef QMLAPPLICATIONVIEWER_H
+#define QMLAPPLICATIONVIEWER_H
+
+#include <QtDeclarative/QDeclarativeView>
+
+class QmlApplicationViewer : public QDeclarativeView
+{
+ Q_OBJECT
+
+public:
+ enum ScreenOrientation {
+ ScreenOrientationLockPortrait,
+ ScreenOrientationLockLandscape,
+ ScreenOrientationAuto
+ };
+
+ explicit QmlApplicationViewer(QWidget *parent = 0);
+ virtual ~QmlApplicationViewer();
+
+ static QmlApplicationViewer *create();
+
+ void setMainQmlFile(const QString &file);
+ void addImportPath(const QString &path);
+
+ // Note that this will only have an effect on Symbian and Fremantle.
+ void setOrientation(ScreenOrientation orientation);
+
+ void showExpanded();
+
+private:
+ class QmlApplicationViewerPrivate *d;
+};
+
+QApplication *createApplication(int &argc, char **argv);
+
+#endif // QMLAPPLICATIONVIEWER_H
diff --git a/share/qbs/imports/qbs/fileinfo/fileinfo.js b/share/qbs/imports/qbs/fileinfo/fileinfo.js
new file mode 100644
index 000000000..b65e4073c
--- /dev/null
+++ b/share/qbs/imports/qbs/fileinfo/fileinfo.js
@@ -0,0 +1,62 @@
+function path(fp) {
+ if (fp[fp.length -1] == '/')
+ return fp;
+ var last = fp.lastIndexOf('/');
+ if (last < 0)
+ return '.';
+ return fp.slice(0, last);
+}
+
+function fileName(fph) {
+ var fp = fph.toString();
+ if (fp[fp.length -1] == '/')
+ return fp;
+ var last = fp.lastIndexOf('/');
+ if (last < 0)
+ return '.';
+ return fp.slice(last + 1);
+}
+
+function baseName(fph) {
+ var fn = fileName(fph);
+ return fn.split('.')[0];
+}
+
+function relativePath(base, rel)
+{
+ var basel = base.split('/');
+ var rell = rel.split('/');
+ var i = 0;
+
+ while (i < basel.length && i < rell.length && basel[i] == rell[i])
+ i++;
+
+ var j = i;
+ var r = [];
+
+ for (; i < basel.length; i++)
+ r.push('..');
+
+ for (; j < rell.length; j++)
+ r.push(rell[j]);
+
+ return r.join('/');
+}
+
+function isAbsolutePath(path)
+{
+ if (!path)
+ return false;
+ return (path.charAt(0) == '/');
+}
+
+function toWindowsSeparators(str)
+{
+ return str.toString().replace(/\//g, '\\');
+}
+
+function fromWindowsSeparators(str)
+{
+ return str.toString().replace(/\\/g, '/');
+}
+
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
new file mode 100644
index 000000000..f4204dad1
--- /dev/null
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -0,0 +1,75 @@
+// base for Cpp modules
+
+Module {
+ condition: false
+ additionalProductFileTags: ["hpp"] // to include all rules that generate hpp files
+
+ property string warningLevel : 'all' // 'none', 'all'
+ property bool treatWarningsAsErrors : false
+ property string architecture: qbs.architecture
+ property string optimization: qbs.optimization
+ property bool debugInformation: qbs.debugInformation
+ property string precompiledHeader
+ property paths precompiledHeaderDir: [product.buildDirectory]
+ property var defines
+ property paths includePaths
+ property paths libraryPaths
+ property paths frameworkPaths
+ property var compilerFlags
+ property string compilerPath
+ // ### same separation in msvc?
+ property var dynamicLibraries // list of names, will be linked with -lname
+ property var staticLibraries // list of static library files
+ property var frameworks // list of frameworks, will be linked with '-framework <name>'
+ property var rpaths
+
+ FileTagger {
+ pattern: "*.c"
+ fileTags: ["c"]
+ }
+
+ FileTagger {
+ pattern: "*.C"
+ fileTags: ["c"]
+ }
+
+ FileTagger {
+ pattern: "*.cpp"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.cxx"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.c++"
+ fileTags: ["cpp"]
+ }
+
+ FileTagger {
+ pattern: "*.h"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.H"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.hpp"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.hxx"
+ fileTags: ["hpp"]
+ }
+
+ FileTagger {
+ pattern: "*.h++"
+ fileTags: ["hpp"]
+ }
+}
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
new file mode 100644
index 000000000..14ee2753f
--- /dev/null
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -0,0 +1,300 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import 'gcc.js' as Gcc
+import '../utils.js' as ModUtils
+
+CppModule {
+ condition: false
+
+ property var transitiveSOs
+ property string toolchainPrefix
+ property string toolchainInstallPath
+ property string compilerName: 'g++'
+
+ property string compilerPath: {
+ var path = ''
+ if (toolchainInstallPath) {
+ path += toolchainInstallPath
+ if (path.substr(-1) !== '/')
+ path += '/'
+ }
+ if (toolchainPrefix)
+ path += toolchainPrefix
+ path += compilerName
+ return path
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/lib" + product.name + ".so"
+ fileTags: ["dynamiclibrary"]
+ cpp.transitiveSOs: {
+ var result = []
+ for (var i in inputs.dynamiclibrary) {
+ var lib = inputs.dynamiclibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'transitiveSOs')
+ result = result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAll(product, 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAll(product, 'staticLibraries')
+ property var rpaths: ModUtils.appendAll(product, 'rpaths')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(product);
+ if (product.modules.qbs.targetOS == 'linux')
+ args = args.concat([
+ '-Wl,--hash-style=gnu',
+ '-Wl,--as-needed',
+ '-Wl,--allow-shlib-undefined',
+ '-Wl,--no-undefined',
+ '-Wl,-soname=' + FileInfo.fileName(output.fileName)
+ ]);
+ args = args.concat([
+ '-Wl,-rpath,\$ORIGIN',
+ '-shared'
+ ]);
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName);
+
+ var staticLibrariesI = [];
+ for (i in inputs.staticlibrary) {
+ staticLibrariesI.push(inputs.staticlibrary[i].fileName);
+ }
+ staticLibrariesI = staticLibrariesI.concat(staticLibraries);
+
+ var dynamicLibrariesI = [];
+ for (i in inputs.dynamiclibrary) {
+ libraryPaths.push(FileInfo.path(inputs.dynamiclibrary[i].fileName))
+ var fileName = FileInfo.fileName(inputs.dynamiclibrary[i].fileName)
+ fileName = fileName.substr(3, fileName.length - 6)
+ dynamicLibrariesI.push(fileName)
+ }
+ dynamicLibrariesI = dynamicLibrariesI.concat(dynamicLibraries);
+
+ args.push('-o');
+ args.push(output.fileName);
+ args = args.concat(Gcc.libs(libraryPaths, rpaths, dynamicLibrariesI, staticLibrariesI));
+ var cmd = new Command(product.module.compilerPath, args);
+ Gcc.linkEnv(cmd)
+ cmd.description = 'linking ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker';
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: staticLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/lib" + product.name + ".a"
+ fileTags: ["staticlibrary"]
+ cpp.staticLibraries: {
+ var result = []
+ for (var i in inputs.staticlibrary) {
+ var lib = inputs.staticlibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'staticLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ cpp.dynamicLibraries: {
+ var result = []
+ for (var i in inputs.dynamiclibrary) {
+ var lib = inputs.dynamiclibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'dynamicLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ prepare: {
+ var args = ['rcs', output.fileName];
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName);
+ var cmd = new Command('ar', args);
+ cmd.description = 'creating ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker'
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ["obj"]
+ usings: ['dynamiclibrary', 'staticlibrary']
+
+ Artifact {
+ fileName: product.destinationDirectory + "/" + product.name
+ fileTags: ["application"]
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary, 'cpp', 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, inputs.staticlibrary, 'cpp', 'staticLibraries')
+ property var rpaths: ModUtils.appendAll(product, 'rpaths')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(product);
+ for (var i in inputs.obj)
+ args.push(inputs.obj[i].fileName)
+ args.push('-Wl,-rpath,\$ORIGIN');
+ args.push('-o');
+ args.push(output.fileName);
+
+ var staticLibrariesI = [];
+ for (i in inputs.staticlibrary) {
+ staticLibrariesI.push(inputs.staticlibrary[i].fileName);
+ }
+ staticLibrariesI = staticLibrariesI.concat(staticLibraries);
+
+ var dynamicLibrariesI = [];
+ for (i in dynamicLibraries) {
+ if (dynamicLibraries[i].match("lib.*\\.so$") != null) {
+ // shared object filename found
+ var libDir = FileInfo.path(dynamicLibraries[i])
+ var libName = FileInfo.fileName(dynamicLibraries[i])
+ libName = libName.substr(3, libName.length - 6)
+ libraryPaths.push(libDir)
+ dynamicLibrariesI.push(libName)
+ } else {
+ // shared object libname found
+ dynamicLibrariesI.push(dynamicLibraries[i])
+ }
+ }
+
+ if (product.modules.qbs.targetOS === 'linux') {
+ var transitiveSOs = ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary, 'cpp', 'transitiveSOs')
+ for (i in transitiveSOs) {
+ args.push("-Wl,-rpath-link=" + FileInfo.path(transitiveSOs[i]))
+ }
+ }
+
+ for (i in inputs.dynamiclibrary) {
+ libraryPaths.push(FileInfo.path(inputs.dynamiclibrary[i].fileName))
+ var fileName = FileInfo.fileName(inputs.dynamiclibrary[i].fileName)
+ fileName = fileName.substr(3, fileName.length - 6)
+ dynamicLibrariesI.push(fileName)
+ }
+
+ args = args.concat(Gcc.libs(libraryPaths, rpaths, dynamicLibrariesI, staticLibrariesI));
+ var cmd = new Command(product.module.compilerPath, args);
+ Gcc.linkEnv(cmd, product)
+ cmd.description = 'linking ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'linker'
+ return cmd;
+ }
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ explicitlyDependsOn: ["c++_pch"]
+
+ Artifact {
+ fileTags: ["obj"]
+ // ### make it possible to override ".obj" in a project file
+ fileName: ".obj/" + product.name + "/" + input.baseDir + "/" + input.baseName + ".o"
+ }
+
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+
+ prepare: {
+ var args = Gcc.configFlags(input);
+
+ // ### what we actually need here is something like product.usedFileTags
+ // that contains all fileTags that have been used when applying the rules.
+ if (product.type.indexOf('staticlibrary') >= 0 || product.type.indexOf('dynamiclibrary') >= 0) {
+ args.push('-fPIC');
+ } else if (product.type.indexOf('application') < 0) {
+ throw ("OK, now we got a problem... The product's type must be in {staticlibrary, dynamiclibrary, application}. But it is " + product.type + '.');
+ }
+
+ for (var i in defines)
+ args.push('-D' + defines[i]);
+ for (var i in includePaths)
+ args.push('-I' + includePaths[i]);
+ if (product.module.precompiledHeader) {
+ args.push('-include')
+ args.push(product.name)
+ var pchPath = product.module.precompiledHeaderDir[0]
+ var pchPathIncluded = false
+ for (var i in includePaths) {
+ if (includePaths[i] == pchPath) {
+ pchPathIncluded = true
+ break
+ }
+ }
+ if (!pchPathIncluded)
+ args.push('-I' + pchPath)
+ }
+ if (input.fileTags.indexOf("c") >= 0) {
+ args.push('-x')
+ args.push('c')
+ }
+ args.push('-c');
+ args.push(input.fileName);
+ args.push('-o');
+ args.push(output.fileName);
+ args = args.concat(compilerFlags);
+ var cmd = new Command(product.module.compilerPath, args);
+ cmd.description = 'compiling ';
+ Gcc.describe(cmd, input.fileName, output.fileName);
+ cmd.highlight = "compiler";
+ return cmd;
+ }
+ }
+
+ Transformer {
+ condition: precompiledHeader != null
+ inputs: precompiledHeader
+ Artifact {
+ fileName: product.name + ".gch"
+ fileTags: "c++_pch"
+ }
+ prepare: {
+ var args = Gcc.configFlags(product);
+ for (var i in product.module.defines)
+ args.push('-D' + defines[i]);
+ for (var i in product.module.includePaths)
+ args.push('-I' + includePaths[i]);
+ args.push('-x');
+ args.push('c++-header');
+ args.push('-c');
+ args.push(product.module.precompiledHeader);
+ args.push('-o');
+ args.push(output.fileName);
+ if (product.module.compilerFlags)
+ args = args.concat(product.module.compilerFlags);
+ var cmd = new Command(product.module.compilerPath, args);
+ cmd.description = 'precompiling ' + FileInfo.fileName(input.fileName);
+ return cmd;
+ }
+ }
+}
+
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
new file mode 100644
index 000000000..a4155ad9b
--- /dev/null
+++ b/share/qbs/modules/cpp/gcc.js
@@ -0,0 +1,113 @@
+function collectDynamicLinkPaths(config) {
+ var paths = []
+
+ var linkProducts = config.linkProducts || []
+ for (var libPath in linkProducts) {
+ var linkedConfig = linkProducts[libPath]
+ var fileTags = linkedConfig['fileTags']
+ if (fileTags.indexOf('dynamiclibrary') >= 0) {
+ paths.push(FileInfo.path(libPath))
+ paths = paths.concat(collectDynamicLinkPaths(linkedConfig))
+ }
+ }
+ return paths
+}
+
+function linkEnv(cmd) {
+ // ### setup LD_LIBRARY_PATH for ProductModule dynamiclibrary depends
+// var paths = []
+// for (var i in config.linkProducts) {
+// var linkedConfig = config.linkProducts[i]
+// var fileTags = linkedConfig['fileTags']
+// if (fileTags.indexOf('dynamiclibrary') >= 0) {
+// paths = paths.concat(collectDynamicLinkPaths(linkedConfig))
+// }
+// }
+
+// if (paths.length) {
+// var envdef = newEnvironmentDefinition("LD_LIBRARY_PATH")
+// envdef.pathNames = true
+// envdef.separator = ':'
+// envdef.prepend = paths
+// cmd.addEnvironmentDefinition(envdef)
+// }
+}
+
+function libs(libraryPaths, rpaths, dynamicLibraries, staticLibraries) {
+
+ var args = [];
+ if (rpaths && rpaths.length)
+ args.push('-Wl,-rpath,' + rpaths.join(':'));
+ for (var i in libraryPaths) {
+ args.push('-L' + libraryPaths[i]);
+ }
+ for (var i in staticLibraries) {
+ args.push(staticLibraries[i]);
+ }
+ for (var i in dynamicLibraries) {
+ if (FileInfo.isAbsolutePath(dynamicLibraries[i])) {
+ args.push(dynamicLibraries[i]);
+ } else {
+ args.push('-l' + dynamicLibraries[i]);
+ }
+ }
+ return args;
+}
+
+function macLibs(libraryPaths, rpaths, dynamicLibraries, staticLibraries, frameworks)
+{
+ var args = libs(libraryPaths, rpaths, dynamicLibraries, staticLibraries);
+ for (var i in libraryPaths) {
+ args.push('-F' + libraryPaths[i]);
+ }
+ for (var i in frameworks) {
+ args.push('-framework');
+ args.push(frameworks[i]);
+ }
+ return args;
+}
+
+function configFlags(config) {
+ var args = [];
+ // optimization:
+ if (config.module.debugInformation === 'on')
+ args.push('-g');
+ if (config.module.optimization === 'fast')
+ args.push('-O2');
+ if (config.module.optimization === 'small')
+ args.push('-Os');
+ // warnings:
+ if (config.module.warningLevel === 'none')
+ args.push('-w');
+ if (config.module.warningLevel === 'all') {
+ args.push('-Wall');
+ args.push('-W');
+ }
+ if (config.module.treatWarningsAsErrors)
+ args.push('-Werror');
+
+ return args;
+}
+
+function frameworkPaths(config) {
+ var args = [];
+ for (var i in config.frameworkPaths) {
+ args.push('-F' + config.frameworkPaths[i]);
+ }
+ return args;
+}
+
+function frameworks(config) {
+ var args = [];
+ for (var i in config.frameworks) {
+ args.push('-framework');
+ args.push(config.frameworks[i]
+ .replace(/.framework$/,''));
+ }
+ return args;
+}
+
+function describe(cmd, input, output)
+{
+ cmd.description += FileInfo.fileName(input);
+}
diff --git a/share/qbs/modules/cpp/linux-gcc.qbs b/share/qbs/modules/cpp/linux-gcc.qbs
new file mode 100644
index 000000000..ff1827ebb
--- /dev/null
+++ b/share/qbs/modules/cpp/linux-gcc.qbs
@@ -0,0 +1,6 @@
+import qbs.base 1.0
+
+GenericGCC {
+ condition: qbs.hostOS == 'linux' && qbs.targetOS == 'linux' && qbs.toolchain == 'gcc'
+}
+
diff --git a/share/qbs/modules/cpp/mac-gcc.qbs b/share/qbs/modules/cpp/mac-gcc.qbs
new file mode 100644
index 000000000..fda5da3f2
--- /dev/null
+++ b/share/qbs/modules/cpp/mac-gcc.qbs
@@ -0,0 +1,69 @@
+import qbs.base 1.0
+
+GenericGCC {
+ condition: qbs.hostOS == 'mac' && qbs.targetOS == 'mac' && qbs.toolchain == 'gcc'
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.name + ".app/Info.plist"
+ fileTags: ["infoplist"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating Info.plist";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var infoplist = new TextFile(outputs.infoplist[0].fileName, TextFile.WriteOnly);
+ infoplist.write("<foobar>");
+ infoplist.close();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.name + ".app/PkgInfo"
+ fileTags: ["pkginfo"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating PkgInfo";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var pkginfo = new TextFile(outputs.pkginfo[0].fileName, TextFile.WriteOnly);
+ pkginfo.write("FOO");
+ pkginfo.close();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["application", "infoplist", "pkginfo"]
+
+ Artifact {
+ fileName: product.name + ".app/Contents/MacOS/" + product.name
+ fileTags: ["applicationbundle"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating app bundle";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ File.copy(inputs.application[0].fileName, outputs.applicationbundle[0].fileName);
+ }
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
new file mode 100644
index 000000000..0f306eced
--- /dev/null
+++ b/share/qbs/modules/cpp/msvc.js
@@ -0,0 +1,173 @@
+function prepareCompiler(product, input, outputs, defines, includePaths, compilerFlags)
+{
+ var optimization = input.module.optimization
+ var debugInformation = input.module.debugInformation
+ var architecture = input.module.architecture
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo', '/c', '/Zm200', '/Zc:wchar_t-']
+
+ // C or C++
+ if (input.fileTags.indexOf('c') >= 0) {
+ args.push('/TC')
+ }
+
+ // enable unwind semantics
+ args.push("/EHsc")
+ // optimization:
+ if (optimization === 'small')
+ args.push('/Os')
+ else if (optimization === 'fast')
+ args.push('/O2')
+ if (debugInformation) {
+ args.push('/Zi')
+ args.push('/MDd')
+ } else {
+ args.push('/MD')
+ }
+ // warnings:
+ var warningLevel = input.module.warningLevel
+ if (warningLevel === 'none')
+ args.push('/w')
+ if (warningLevel === 'all')
+ args.push('/Wall')
+ for (var i in includePaths)
+ args.push('/I' + FileInfo.toWindowsSeparators(includePaths[i]))
+ for (i in defines)
+ args.push('/D' + defines[i])
+
+ var objOutput = outputs.obj ? outputs.obj[0] : undefined
+ var pchOutput = outputs["c++_pch"] ? outputs["c++_pch"][0] : undefined
+
+ // precompiled header file
+ if (product.module.precompiledHeader) {
+ if (pchOutput) {
+ // create pch
+ args.push('/Yc')
+ args.push('/Fp' + FileInfo.toWindowsSeparators(pchOutput.fileName))
+ args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.fileName))
+ args.push('/TP')
+ args.push(FileInfo.toWindowsSeparators(input.fileName))
+ } else {
+ // use pch
+ var pchHeaderName = FileInfo.toWindowsSeparators(product.module.precompiledHeader)
+ var pchName = FileInfo.toWindowsSeparators(product.module.precompiledHeaderDir[0] + "\\.obj\\" + product.name + "\\" + product.name + ".pch")
+ args.push("/FI" + pchHeaderName)
+ args.push("/Yu" + pchHeaderName)
+ args.push("/Fp" + pchName)
+ }
+ }
+ args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.fileName))
+ args.push(FileInfo.toWindowsSeparators(input.fileName))
+
+ var clPath = toolchainInstallPath + '/VC/bin/'
+ var is64bit = (architecture === "x86_64")
+ if (is64bit)
+ clPath += 'amd64/'
+ clPath += 'cl.exe'
+
+ for (var i in compilerFlags) {
+ args.push(i)
+ }
+
+ var cmd = new Command(clPath, args)
+ cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + FileInfo.fileName(input.fileName)
+ cmd.highlight = "compiler";
+ cmd.workingDirectory = FileInfo.path(objOutput.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ // cl.exe outputs the cpp file name. We filter that out.
+ cmd.stdoutFilterFunction = "function(output) {";
+ cmd.stdoutFilterFunction += "return output.replace('" + FileInfo.fileName(input.fileName) + "\\r\\n', '');";
+ cmd.stdoutFilterFunction += "}";
+ return cmd;
+}
+
+function prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+{
+ var linkDLL = (outputs.dynamiclibrary ? true : false)
+ var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0])
+ var optimization = product.module.optimization
+ var debugInformation = product.module.debugInformation
+ var architecture = product.module.architecture
+ var windowsSDKPath = product.module.windowsSDKPath
+ var generateManifestFiles = !linkDLL && product.module.generateManifestFiles
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo']
+ if (linkDLL) {
+ args.push('/DLL');
+ args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].fileName));
+ }
+
+ if (debugInformation)
+ args.push('/DEBUG')
+ else
+ args.push('/INCREMENTAL:NO')
+
+ var manifestFileName
+ if (generateManifestFiles) {
+ manifestFileName = FileInfo.toWindowsSeparators(primaryOutput.fileName)
+ manifestFileName += '.intermediate.manifest'
+ args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName)
+ }
+
+ var allInputs = inputs.obj.concat(inputs.staticlibrary || [])
+ if (inputs.dynamiclibrary_import)
+ allInputs = inputs.obj.concat(inputs.dynamiclibrary_import)
+ for (var i in allInputs) {
+ var fileName = FileInfo.toWindowsSeparators(allInputs[i].fileName)
+ args.push(fileName)
+ }
+ for (var i in staticLibraries) {
+ var staticLibrary = staticLibraries[i];
+ if (!staticLibrary.match(/\.lib$/i))
+ staticLibrary += ".lib";
+ args.push(staticLibrary)
+ }
+ for (var i in dynamicLibraries) {
+ var dynamicLibrary = dynamicLibraries[i];
+ if (!dynamicLibrary.match(/\.lib$/i))
+ dynamicLibrary += ".lib";
+ args.push(dynamicLibrary)
+ }
+
+ var nativeOutputFileName = FileInfo.toWindowsSeparators(primaryOutput.fileName)
+ args.push('/OUT:' + nativeOutputFileName)
+ for (var i in libraryPaths) {
+ args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
+ }
+ args = args.concat(dynamicLibraries)
+ var is64bit = (architecture == "x86_64")
+
+ var linkerPath = toolchainInstallPath + '/VC/bin/'
+ if (is64bit)
+ linkerPath += 'amd64/'
+ linkerPath += 'link.exe'
+
+ var commands = [];
+ var cmd = new Command(linkerPath, args)
+ cmd.description = 'linking ' + FileInfo.fileName(primaryOutput.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(primaryOutput.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ commands.push(cmd);
+
+ if (generateManifestFiles) {
+ // embed the generated manifest files
+ var args = [
+ '/nologo', '/manifest', manifestFileName,
+ '/outputresource:' + nativeOutputFileName + ';1'
+ ]
+ var mtPath = windowsSDKPath + '/bin/mt.exe'
+ var cmd = new Command(mtPath, args)
+ cmd.description = 'embedding manifest into ' + FileInfo.fileName(primaryOutput.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(primaryOutput.fileName)
+ commands.push(cmd);
+ }
+
+ return commands;
+}
+
diff --git a/share/qbs/modules/cpp/ponyphone.qbs b/share/qbs/modules/cpp/ponyphone.qbs
new file mode 100644
index 000000000..e7ea9dfe4
--- /dev/null
+++ b/share/qbs/modules/cpp/ponyphone.qbs
@@ -0,0 +1,28 @@
+/*
+ Giddyup, pony pony pony!
+
+ How to setup this crazy horsey platform?
+ - install the pony SDK
+ - call the following
+ qbs config --global ponyphone/substitute theLittlePrancingPony
+ qbs config --global ponyphone/sdkInstallPath ~/theLittlePrancingPonySDK
+ - stand up and sing the Mr. Ed theme song!
+*/
+
+import qbs.base 1.0
+
+GenericGCC {
+ property string substitute: qbs.configurationValue('ponyphone/substitute')
+
+ condition: qbs.hostOS == 'linux' && qbs.targetOS == 'linux' && qbs.toolchain == 'gcc' && qbs.platform == 'ponyphone'
+
+ toolchainPrefix: {
+ if (architecture == 'i586')
+ return architecture + '-' + substitute + '-linux-'
+ else if (architecture == 'armv7hl')
+ return architecture + '-' + substitute + '-linux-gnueabi-'
+ throw "unknown target architecture: " + architecture
+ }
+ toolchainInstallPath: qbs.configurationValue('ponyphone/sdkInstallPath') + "/" + substitute + "/" + architecture + "/toolchain/bin"
+}
+
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
new file mode 100644
index 000000000..535df9491
--- /dev/null
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -0,0 +1,199 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../utils.js' as ModUtils
+import 'msvc.js' as MSVC
+
+CppModule {
+ condition: qbs.hostOS == 'windows' && qbs.targetOS == 'windows' && qbs.toolchain == 'msvc'
+
+ id: module
+
+ defines: ['UNICODE', 'WIN32']
+ warningLevel: "default"
+
+ property bool generateManifestFiles: true
+ property string toolchainInstallPath: "UNKNOWN"
+ property string windowsSDKPath: "UNKNOWN"
+ property string architecture: "x86"
+ property int responseFileThreshold: 32000
+
+ setupBuildEnvironment: {
+ var v = new ModUtils.EnvironmentVariable("INCLUDE", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/INCLUDE")
+ v.prepend(toolchainInstallPath + "/VC/INCLUDE")
+ v.prepend(windowsSDKPath + "/include")
+ v.set()
+
+ if (architecture == 'x86') {
+ v = new ModUtils.EnvironmentVariable("PATH", ";", true)
+ v.prepend(toolchainInstallPath + "/Common7/IDE")
+ v.prepend(toolchainInstallPath + "/VC/bin")
+ v.prepend(toolchainInstallPath + "/Common7/Tools")
+ v.set()
+
+ v = new ModUtils.EnvironmentVariable("LIB", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/LIB")
+ v.prepend(toolchainInstallPath + "/VC/LIB")
+ v.prepend(windowsSDKPath + "/lib")
+ v.set()
+ } else if (architecture == 'x86_64') {
+ v = new ModUtils.EnvironmentVariable("PATH", ";", true)
+ v.prepend(toolchainInstallPath + "/Common7/IDE")
+ v.prepend(toolchainInstallPath + "/VC/bin/amd64")
+ v.prepend(toolchainInstallPath + "/Common7/Tools")
+ v.set()
+
+ v = new ModUtils.EnvironmentVariable("LIB", ";", true)
+ v.prepend(toolchainInstallPath + "/VC/ATLMFC/LIB/amd64")
+ v.prepend(toolchainInstallPath + "/VC/LIB/amd64")
+ v.prepend(windowsSDKPath + "/lib/x64")
+ v.set()
+ }
+ }
+
+ Artifact {
+ // This adds the filename in precompiledHeader to the set of source files.
+ // If its already in there, then this makes sure it has the right file tag.
+ condition: precompiledHeader != null
+ fileName: precompiledHeader
+ fileTags: ["hpp_pch"]
+ }
+
+ Rule {
+ id: pchCompiler
+ inputs: ["hpp_pch"]
+ Artifact {
+ fileTags: ['obj']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + input.baseName + '.obj'
+ }
+ Artifact {
+ fileTags: ['c++_pch']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + product.name + '.pch'
+ }
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+ prepare: {
+ return MSVC.prepareCompiler(product, input, outputs)
+ }
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ explicitlyDependsOn: ["c++_pch"]
+ Artifact {
+ fileTags: ['obj']
+ // ### make the object file dir overridable
+ fileName: ".obj/" + product.name + "/" + input.baseDir + "/" + input.baseName + ".obj"
+ }
+
+ TransformProperties {
+ property var defines: ModUtils.appendAll(input, 'defines')
+ property var includePaths: ModUtils.appendAll(input, 'includePaths')
+ property var compilerFlags: ModUtils.appendAll(input, 'compilerFlags')
+ }
+
+ prepare: {
+ return MSVC.prepareCompiler(product, input, outputs, defines, includePaths, compilerFlags)
+ }
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ['obj']
+ usings: ['staticlibrary', 'dynamiclibrary_import']
+ Artifact {
+ fileTags: ["application"]
+ fileName: product.destinationDirectory + "/" + product.name + ".exe"
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAllFromArtifacts(product, inputs.dynamiclibrary_import, 'cpp', 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, (inputs.staticlibrary || []).concat(inputs.obj), 'cpp', 'staticLibraries')
+ }
+
+ prepare: {
+ return MSVC.prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+ }
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ multiplex: true
+ inputs: ['obj']
+ usings: ['staticlibrary', 'dynamiclibrary_import']
+
+ Artifact {
+ fileTags: ["dynamiclibrary"]
+ fileName: product.destinationDirectory + "/" + product.name + ".dll"
+ }
+
+ Artifact {
+ fileTags: ["dynamiclibrary_import"]
+ fileName: product.destinationDirectory + "/" + product.name + "_imp.lib"
+ }
+
+ TransformProperties {
+ property var libraryPaths: ModUtils.appendAll(product, 'libraryPaths')
+ property var dynamicLibraries: ModUtils.appendAll(product, 'dynamicLibraries')
+ property var staticLibraries: ModUtils.appendAllFromArtifacts(product, (inputs.staticlibrary || []).concat(inputs.obj), 'cpp', 'staticLibraries')
+ }
+
+ prepare: {
+ return MSVC.prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, staticLibraries)
+ }
+ }
+
+ Rule {
+ id: libtool
+ multiplex: true
+ inputs: ["obj"]
+ usings: ["staticlibrary"]
+
+ Artifact {
+ fileTags: ["staticlibrary"]
+ fileName: product.destinationDirectory + "/" + product.name + ".lib"
+ cpp.staticLibraries: {
+ var result = []
+ for (var i in inputs.staticlibrary) {
+ var lib = inputs.staticlibrary[i]
+ result.push(lib.fileName)
+ var impliedLibs = ModUtils.appendAll(lib, 'staticLibraries')
+ result.concat(impliedLibs)
+ }
+ return result
+ }
+ }
+
+ prepare: {
+ var toolchainInstallPath = product.module.toolchainInstallPath
+
+ var args = ['/nologo']
+ var nativeOutputFileName = FileInfo.toWindowsSeparators(output.fileName)
+ args.push('/OUT:' + nativeOutputFileName)
+ for (var i in inputs.obj) {
+ var fileName = FileInfo.toWindowsSeparators(inputs.obj[i].fileName)
+ args.push(fileName)
+ }
+ var is64bit = (product.module.architecture == "x86_64")
+ var linkerPath = toolchainInstallPath + '/VC/bin/'
+ if (is64bit)
+ linkerPath += 'amd64/'
+ linkerPath += 'lib.exe'
+ var cmd = new Command(linkerPath, args)
+ cmd.description = 'creating ' + FileInfo.fileName(output.fileName)
+ cmd.highlight = 'linker';
+ cmd.workingDirectory = FileInfo.path(output.fileName)
+ cmd.responseFileThreshold = product.module.responseFileThreshold
+ cmd.responseFileUsagePrefix = '@';
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/qbs/common.qbs b/share/qbs/modules/qbs/common.qbs
new file mode 100644
index 000000000..e9e311e93
--- /dev/null
+++ b/share/qbs/modules/qbs/common.qbs
@@ -0,0 +1,50 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+
+Module {
+ property list<string> references;
+ property string buildVariant: "debug"
+ property bool debugInformation: (buildVariant == "debug")
+ property string optimization: (buildVariant == "debug" ? "none" : "fast")
+ property string platform: null
+ property string hostOS: getHostOS()
+ property string hostArchitecture: getHostDefaultArchitecture()
+ property string targetOS: null
+ property string targetName: null
+ property string toolchain: null
+ property string architecture: null
+ property string endianness: null
+ property string installDir: '.'
+
+ PropertyOptions {
+ name: "buildVariant"
+ allowedValues: ['debug', 'release']
+ description: "Defines the consistence of your ice cream sandwich"
+ }
+
+ PropertyOptions {
+ name: "optimization"
+ allowedValues: ['none', 'fast', 'small']
+ description: "optimization level"
+ }
+
+ Rule {
+ inputs: ["install"]
+ Artifact {
+ fileTags: ["installed_content"]
+ fileName: input.modules.qbs.installDir + "/" + input.fileName
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = function() {
+ File.remove(output.fileName);
+ File.copy(input.fileName, output.fileName);
+ }
+ cmd.description = "installing " + FileInfo.fileName(output.fileName);
+ cmd.highlight = "linker";
+ return cmd;
+ }
+
+ }
+}
diff --git a/share/qbs/modules/qt/QtModule.qbs b/share/qbs/modules/qt/QtModule.qbs
new file mode 100644
index 000000000..b1a03d4c2
--- /dev/null
+++ b/share/qbs/modules/qt/QtModule.qbs
@@ -0,0 +1,19 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import 'qtfunctions.js' as QtFunctions
+
+Module {
+ condition: false
+
+ Depends { name: "cpp" }
+ Depends { id: qtcore; name: "Qt.core" }
+
+ property string binPath: qtcore.binPath
+ property string incPath: qtcore.incPath
+ property string libPath: qtcore.libPath
+ property string qtModuleName: ''
+ property string internalQtModuleName: 'Qt' + qtModuleName
+ cpp.includePaths: [incPath + '/' + internalQtModuleName]
+ cpp.dynamicLibraries: [QtFunctions.getLibraryName(internalQtModuleName, qbs.targetOS, cpp.debugInformation)]
+ cpp.frameworks: [QtFunctions.getLibraryName(internalQtModuleName, qbs.targetOS, cpp.debugInformation)]
+}
diff --git a/share/qbs/modules/qt/core/moc.js b/share/qbs/modules/qt/core/moc.js
new file mode 100644
index 000000000..c0845220c
--- /dev/null
+++ b/share/qbs/modules/qt/core/moc.js
@@ -0,0 +1,15 @@
+function args(input, output, config) {
+ var args = [];
+
+ // ### fixme
+ var defines = ModUtils.appendAll_internal(config.modules, 'cpp', 'defines') //config.modules.cpp.compiler.defines
+ var includePaths = ModUtils.appendAll_internal(config.modules, 'cpp', 'includePaths') //config.modules.cpp.compiler.includePaths
+ for (var i in defines)
+ args.push('-D' + defines[i]);
+ for (var i in includePaths)
+ args.push('-I' + includePaths[i]);
+ args.push('-o', output);
+ args.push(input);
+ return args;
+}
+
diff --git a/share/qbs/modules/qt/core/qtcore.qbs b/share/qbs/modules/qt/core/qtcore.qbs
new file mode 100644
index 000000000..075b462b6
--- /dev/null
+++ b/share/qbs/modules/qt/core/qtcore.qbs
@@ -0,0 +1,130 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../../utils.js' as ModUtils
+import "moc.js" 1.0 as Moc
+import '../qtfunctions.js' as QtFunctions
+
+Module {
+ Depends { name: "cpp" }
+
+ property string qtVersionName: "default"
+ property string configKey: "qt/" + qtVersionName + "/"
+ property string qtNamespace: qbs.configurationValue(configKey + "namespace", undefined)
+ property string qtPath: qbs.configurationValue(configKey + "path", undefined)
+ property string binPath: qtPath ? qtPath + "/bin" : qbs.configurationValue(configKey + "binPath", undefined)
+ property string incPath: qtPath ? qtPath + "/include" : qbs.configurationValue(configKey + "incPath", undefined)
+ property string libPath: qtPath ? qtPath + "/lib" : qbs.configurationValue(configKey + "libPath", undefined)
+ property string mkspecsPath: qtPath ? qtPath + "/mkspecs" : qbs.configurationValue(configKey + "mkspecsPath", undefined)
+ property string generatedFilesDir: 'GeneratedFiles/' + product.name // ### TODO: changing this property does not change the path in the rule ATM.
+ property string libraryInfix: cpp.debugInformation ? 'd' : ''
+ cpp.defines: {
+ if (!qtNamespace)
+ return undefined;
+ return ["QT_NAMESPACE=" + qtNamespace]
+ }
+ cpp.includePaths: [
+ mkspecsPath + '/default',
+ incPath + '/QtCore',
+ incPath,
+ product.buildDirectory + '/' + generatedFilesDir
+ ]
+ cpp.libraryPaths: [libPath]
+ cpp.dynamicLibraries: qbs.targetOS != 'mac' ? [QtFunctions.getLibraryName('QtCore', qbs.targetOS, cpp.debugInformation)] : []
+ cpp.frameworkPaths: [libPath]
+ cpp.frameworks: [QtFunctions.getLibraryName('QtCore', qbs.targetOS, cpp.debugInformation)]
+ cpp.rpaths: [libPath]
+
+ setupBuildEnvironment: {
+ // Not really a setup in this case. Just some sanity checks.
+ if (!binPath)
+ throw "qt/core.binPath not set. Set the configuration values qt/default/binPath or qt/default/path.";
+ if (!incPath)
+ throw "qt/core.incPath not set. Set the configuration values qt/default/incPath or qt/default/path.";
+ if (!libPath)
+ throw "qt/core.libPath not set. Set the configuration values qt/default/libPath or qt/default/path.";
+ if (!mkspecsPath)
+ throw "qt/core.mkspecsPath not set. Set the configuration values qt/default/mkspecsPath or qt/default/path.";
+ }
+
+ setupRunEnvironment: {
+ var v = getenv('PATH') || ''
+ if (v.length > 0 && v.charAt(0) != ';')
+ v = ';' + v
+ var y = binPath
+ if (qbs.targetOS === 'windows')
+ v = FileInfo.toWindowsSeparators(y) + v
+ else
+ v = y + v
+ putenv('PATH', v)
+ }
+
+ FileTagger {
+ pattern: "*.qrc"
+ fileTags: ["qrc"]
+ }
+
+ Rule {
+ inputs: ["moc_cpp"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/' + input.baseName + '.moc'
+// fileName: input.baseDir + '/' + input.baseName + '.moc'
+ fileTags: ["hpp"]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["moc_hpp"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/moc_' + input.baseName + '.cpp'
+ fileTags: [ "cpp" ]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["moc_hpp_inc"]
+
+ Artifact {
+ fileName: 'GeneratedFiles/' + product.name + '/moc_' + input.baseName + '.cpp'
+ fileTags: [ "hpp" ]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/moc', Moc.args(input.fileName, output.fileName, input));
+ cmd.description = 'moc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["qrc"]
+
+ Artifact {
+// ### TODO we want to access the module's property "generatedFilesDir" here. But without evaluating all available properties a priori.
+ fileName: 'GeneratedFiles/' + product.name + '/qrc_' + input.baseName + '.cpp'
+ fileTags: ["cpp"]
+ }
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/rcc', [input.fileName, '-name', FileInfo.baseName(input.fileName), '-o', output.fileName]);
+ cmd.description = 'rcc ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/qt/declarative/module.qbs b/share/qbs/modules/qt/declarative/module.qbs
new file mode 100644
index 000000000..3f4bf5b0f
--- /dev/null
+++ b/share/qbs/modules/qt/declarative/module.qbs
@@ -0,0 +1,9 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: "Declarative"
+ Depends { name: "Qt.gui" }
+}
+
diff --git a/share/qbs/modules/qt/designer/module.qbs b/share/qbs/modules/qt/designer/module.qbs
new file mode 100644
index 000000000..c2e319d88
--- /dev/null
+++ b/share/qbs/modules/qt/designer/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Designer'
+}
+
diff --git a/share/qbs/modules/qt/designercomponents/module.qbs b/share/qbs/modules/qt/designercomponents/module.qbs
new file mode 100644
index 000000000..eb700eb7f
--- /dev/null
+++ b/share/qbs/modules/qt/designercomponents/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'DesignerComponents'
+}
+
diff --git a/share/qbs/modules/qt/gui/qtgui.qbs b/share/qbs/modules/qt/gui/qtgui.qbs
new file mode 100644
index 000000000..2a300a00c
--- /dev/null
+++ b/share/qbs/modules/qt/gui/qtgui.qbs
@@ -0,0 +1,33 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ qtModuleName: "Gui"
+
+ Depends { id: qtcore; name: "Qt.core" }
+
+ FileTagger {
+ pattern: "*.ui"
+ fileTags: ["ui"]
+ }
+
+ Rule {
+ inputs: ["ui"]
+
+ Artifact {
+// ### TODO we want to access the module's property "qtcore.generatedFilesDir" here. But without evaluating all available properties a priori.
+// fileName: input.baseDir + '/qrc_' + input.baseName + '.cpp'
+ fileName: 'GeneratedFiles/' + product.name + '/ui_' + input.baseName + '.h'
+ fileTags: ["hpp"]
+ }
+
+ prepare: {
+ var cmd = new Command(product.module.binPath + '/uic', [input.fileName, '-o', output.fileName])
+ cmd.description = 'uic ' + FileInfo.fileName(input.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+}
+
diff --git a/share/qbs/modules/qt/help/module.qbs b/share/qbs/modules/qt/help/module.qbs
new file mode 100644
index 000000000..6bf5616f9
--- /dev/null
+++ b/share/qbs/modules/qt/help/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Help'
+}
+
diff --git a/share/qbs/modules/qt/network/module.qbs b/share/qbs/modules/qt/network/module.qbs
new file mode 100644
index 000000000..00aa5386a
--- /dev/null
+++ b/share/qbs/modules/qt/network/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Network'
+}
+
diff --git a/share/qbs/modules/qt/opengl/module.qbs b/share/qbs/modules/qt/opengl/module.qbs
new file mode 100644
index 000000000..fed343603
--- /dev/null
+++ b/share/qbs/modules/qt/opengl/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'OpenGL'
+}
+
diff --git a/share/qbs/modules/qt/qtfunctions.js b/share/qbs/modules/qt/qtfunctions.js
new file mode 100644
index 000000000..c6dbf4de5
--- /dev/null
+++ b/share/qbs/modules/qt/qtfunctions.js
@@ -0,0 +1,12 @@
+// helper functions for the Qt modules
+
+function getLibraryName(qtModule, targetOS, debugInfo)
+{
+ var isUnix = (targetOS == 'linux' || targetOS == 'mac')
+ var libName
+ if (isUnix)
+ libName = qtModule
+ else if (targetOS == 'windows')
+ libName = qtModule + (debugInfo ? 'd' : '') + '4.lib'
+ return libName
+}
diff --git a/share/qbs/modules/qt/script/module.qbs b/share/qbs/modules/qt/script/module.qbs
new file mode 100644
index 000000000..96e292bb4
--- /dev/null
+++ b/share/qbs/modules/qt/script/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Script'
+}
+
diff --git a/share/qbs/modules/qt/sql/module.qbs b/share/qbs/modules/qt/sql/module.qbs
new file mode 100644
index 000000000..23892e162
--- /dev/null
+++ b/share/qbs/modules/qt/sql/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Sql'
+}
+
diff --git a/share/qbs/modules/qt/svg/module.qbs b/share/qbs/modules/qt/svg/module.qbs
new file mode 100644
index 000000000..e06e9277a
--- /dev/null
+++ b/share/qbs/modules/qt/svg/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Svg'
+}
+
diff --git a/share/qbs/modules/qt/webkit/module.qbs b/share/qbs/modules/qt/webkit/module.qbs
new file mode 100644
index 000000000..ea598d61f
--- /dev/null
+++ b/share/qbs/modules/qt/webkit/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'WebKit'
+}
+
diff --git a/share/qbs/modules/qt/xml/module.qbs b/share/qbs/modules/qt/xml/module.qbs
new file mode 100644
index 000000000..5b4a462a7
--- /dev/null
+++ b/share/qbs/modules/qt/xml/module.qbs
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+import '../QtModule.qbs' as QtModule
+
+QtModule {
+ condition: true
+ qtModuleName: 'Xml'
+}
+
diff --git a/share/qbs/modules/utils.js b/share/qbs/modules/utils.js
new file mode 100644
index 000000000..4d1e08418
--- /dev/null
+++ b/share/qbs/modules/utils.js
@@ -0,0 +1,133 @@
+//
+// utility functions for modules
+//
+
+function appendAll_internal2(modules, name, property, seenValues)
+{
+ var result = []
+ for (var m in modules) {
+ if (m == name) {
+ var value = modules[m][property]
+ if (value) {
+ if (!seenValues[value]) {
+ seenValues[value] = true
+ result = result.concat(value)
+ }
+ }
+ } else {
+ var values = appendAll_internal2(modules[m].modules, name, property, seenValues)
+ if (values && values.length > 0)
+ result = result.concat(values)
+ }
+ }
+ return result
+}
+
+function appendAll_internal(modules, name, property)
+{
+ var seenValues = []
+ return appendAll_internal2(modules, name, property, seenValues)
+}
+
+function appendAll(config, property)
+{
+ return appendAll_internal(config.modules, config.module.name, property)
+}
+
+function appendAllFromArtifacts(product, artifacts, moduleName, propertyName)
+{
+ var seenValues = []
+ var result = appendAll_internal2(product.modules, moduleName, propertyName, seenValues)
+ for (var i in artifacts)
+ result = result.concat(appendAll_internal2(artifacts[i].modules, moduleName, propertyName, seenValues))
+ return result
+}
+
+function findFirst(modules, name, property)
+{
+ for (var m in modules) {
+ if (m == name) {
+ var value = modules[m][property]
+ if (value)
+ return value
+ } else {
+ var value = findFirst(m.modules, name, property)
+ if (value)
+ return value
+ }
+ }
+ return null
+}
+
+function dumpProperty(key, value, level)
+{
+ var indent = ''
+ for (var k=0; k < level; ++k)
+ indent += ' '
+ print(indent + key + ': ' + value)
+}
+
+function traverseObject(obj, func, level)
+{
+ if (!level)
+ level = 0
+ var children = {}
+ for (var i in obj) {
+ if (typeof(obj[i]) == "object" && !(obj[i] instanceof Array))
+ children[i] = obj[i]
+ else
+ func.apply(this, [i, obj[i], level])
+ }
+ level++
+ for (var i in children) {
+ func.apply(this, [i, children[i], level - 1])
+ traverseObject(children[i], func, level)
+ }
+ level--
+}
+
+function dumpObject(obj, description)
+{
+ if (!description)
+ description = 'object dump'
+ print('+++++++++ ' + description + ' +++++++++')
+ traverseObject(obj, dumpProperty)
+}
+
+
+//////////////////////////////////////////////////////////
+// The EnvironmentVariable class
+//
+function EnvironmentVariable(name, separator, convertPathSeparators)
+{
+ if (!name)
+ throw "EnvironmentVariable c'tor needs a name as first argument."
+ this.name = name
+ this.value = getenv(name).toString()
+ this.separator = separator || ''
+ this.convertPathSeparators = convertPathSeparators || false
+}
+
+EnvironmentVariable.prototype.prepend = function(v)
+{
+ if (this.value.length > 0 && this.value.charAt(0) != this.separator)
+ this.value = this.separator + this.value
+ if (this.convertPathSeparators)
+ v = FileInfo.toWindowsSeparators(v)
+ this.value = v + this.value
+}
+
+EnvironmentVariable.prototype.append = function(v)
+{
+ if (this.value.length > 0)
+ this.value += this.separator
+ if (this.convertPathSeparators)
+ v = FileInfo.toWindowsSeparators(v)
+ this.value += v
+}
+
+EnvironmentVariable.prototype.set = function()
+{
+ putenv(this.name, this.value)
+}
+
diff --git a/src/app/app.pro b/src/app/app.pro
new file mode 100644
index 000000000..ae37990db
--- /dev/null
+++ b/src/app/app.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+SUBDIRS =\
+ qbs\
+ graph \
+ platforms \
+
diff --git a/src/app/graph/graph.cpp b/src/app/graph/graph.cpp
new file mode 100644
index 000000000..f93ebc057
--- /dev/null
+++ b/src/app/graph/graph.cpp
@@ -0,0 +1,465 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <tools/logger.h>
+#include <tools/options.h>
+#include <buildgraph/artifact.h>
+#include <buildgraph/buildgraph.h>
+#include <tools/fileinfo.h>
+#include <Qbs/oldsourceproject.h>
+
+#include <cassert>
+
+#include <QCoreApplication>
+#include <QProcess>
+#include <QDir>
+#include <QFileInfo>
+#include <QDebug>
+#include <cstdlib>
+#include <cstdio>
+#include <cassert>
+#include <cmath>
+
+#include <QGraphicsView>
+#include <QWheelEvent>
+#include <QGraphicsScene>
+#include <QGraphicsItem>
+#include <QApplication>
+#include <QFile>
+#include <QTextStream>
+#include <QDebug>
+#include <QProcess>
+#include <QFont>
+#include <QStyle>
+#include <QLineEdit>
+#include <QGridLayout>
+#include <QAbstractListModel>
+#include <QTimer>
+
+#include <qtconcurrent/runextensions.h>
+#include <QtCore/QFuture>
+
+class QGV : public QGraphicsView
+{
+public:
+ QGV(QGraphicsScene *scene) : QGraphicsView(scene)
+ {
+ setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ setDragMode(ScrollHandDrag);
+ scaleView(0.5);
+ }
+
+protected:
+ void wheelEvent ( QWheelEvent * event )
+ {
+ scaleView(pow((double)2, event->delta() / 240.0));
+ }
+
+ void scaleView(qreal scaleFactor)
+ {
+ qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
+ if (factor < 0.07 || factor > 100)
+ return;
+
+ scale(scaleFactor, scaleFactor);
+ }
+};
+
+struct ArtifactC
+{
+ qbs::Artifact *artifact;
+ QString text;
+ QString label;
+ int grade;
+ QRectF rectangle;
+ int row;
+ int col;
+ QGraphicsRectItem *graphicsRectItem;
+};
+
+QHash<qbs::Artifact *, ArtifactC *> cartifacts;
+const qreal SCALE = 100.0f;
+const qreal VSPACE = 200.0f;
+
+class MainWaffl : public QWidget
+{
+Q_OBJECT
+public:
+ MainWaffl(QGraphicsScene *scene)
+ : grid(this)
+ , qgv(scene)
+ {
+ grid.addWidget(&qgv, 0,0,1,1);
+ grid.addWidget(&searchBox, 1,0,1,1);
+
+ connect(&searchBox, SIGNAL(textChanged ( const QString &)),
+ this, SLOT(startSearchTimer()));
+ connect(&searchTimer, SIGNAL(timeout()),
+ this, SLOT(search()));
+ l = cartifacts.values();
+ qgv.centerOn(0,0);
+ }
+private slots:
+ void startSearchTimer()
+ {
+ searchTimer.start(100);
+ }
+ void search()
+ {
+ searchTimer.stop();
+ foreach (ArtifactC *nc, currentHis) {
+ nc->graphicsRectItem->setBrush(QColor(Qt::white));
+ }
+ currentHis.clear();
+
+ QString t = searchBox.text();
+ if (t.isEmpty())
+ return;
+ foreach (ArtifactC *nc, l) {
+ if (nc->label.contains(t)) {
+ currentHis.append(nc);
+ nc->graphicsRectItem->setBrush(QColor(Qt::red));
+ qgv.ensureVisible(nc->graphicsRectItem);
+ }
+ }
+ }
+private:
+ QList<ArtifactC *> currentHis;
+ QTimer searchTimer;
+ QGridLayout grid;
+ QLineEdit searchBox;
+ QGV qgv;
+ QList<ArtifactC *> l;
+};
+
+qbs::CommandLineOptions options;
+
+void targetToScene(QGraphicsScene *scene, qbs::BuildProduct *t);
+int main(int argc, char *argv[])
+{
+//#ifndef Q_OS_WIN
+// QApplication::setGraphicsSystem("opengl");
+//#endif
+ QApplication app(argc, argv);
+ app.setApplicationName("qbs");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("qt.nokia.com");
+
+ // read commandline
+ QStringList arguments = app.arguments();
+ arguments.removeFirst();
+
+ if (!options.readCommandLineArguments(arguments)) {
+ qbs::CommandLineOptions::printHelp();
+ return 1;
+ }
+ if (options.isHelpSet()) {
+ qbs::CommandLineOptions::printHelp();
+ return 0;
+ }
+
+ qbs::SourceProject sourceProject(options.settings());
+ sourceProject.setSearchPaths(options.searchPaths());
+ sourceProject.loadPlugins(options.pluginPaths());
+ QFuture<bool> loadProjectFuture = QtConcurrent::run(&qbs::SourceProject::loadProject,
+ &sourceProject,
+ options.projectFileName(),
+ options.buildConfigurations());
+ loadProjectFuture.waitForFinished();
+ foreach (const qbs::Error &error, sourceProject.errors()) {
+ qbsError() << error.toString();
+ return 4;
+ }
+
+ QGraphicsScene scene;
+ foreach (qbs::BuildProject::Ptr t, sourceProject.buildProjects()) {
+ foreach (qbs::BuildProduct::Ptr p, t->buildProducts()) {
+ targetToScene(&scene, p.data());
+ }
+ }
+ QRectF sr = scene.sceneRect();
+ sr.adjust(-50, -50, 50, 50);
+ scene.setSceneRect(sr);
+ MainWaffl waffl(&scene);
+ waffl.showMaximized();
+
+ return app.exec();
+}
+
+
+QMap<int, QMap<int, ArtifactC *> > table;
+
+int startcol = 0;
+int endcol = 0;
+void step1(qbs::Artifact *artifact, int l)
+{
+ if (!cartifacts.contains(artifact)) {
+ ArtifactC *nc = new ArtifactC;
+ cartifacts.insert(artifact, nc);
+ nc->text = artifact->fileName;
+ nc->label = qbs::FileInfo::fileName(artifact->fileName);
+ nc->artifact = artifact;
+ QMap<int, ArtifactC *> & line = table[l];
+ int col = startcol;
+ while (line.contains(col)) {
+ col++;
+ }
+ table[l][col] = nc;
+ endcol = qMax(endcol, col);
+ foreach (qbs::Artifact *n2, artifact->children) {
+ step1(n2, l + 1);
+ }
+ startcol = endcol + 1;
+ }
+}
+
+
+QList<ArtifactC *> ncl;
+QMap<int, int> layerx;
+QMap<int, int> layerC;
+QMultiMap<ArtifactC *, ArtifactC *> edges;
+
+void targetToScene(QGraphicsScene *scene, qbs::BuildProduct *t)
+{
+ QFont sceneFont = scene->font();
+ sceneFont.setPointSize(14);
+ scene->setFont(sceneFont);
+
+ QPen pen = QColor(Qt::black);
+ QBrush brush = QColor(Qt::white);
+
+ foreach (qbs::Artifact *targetArtifact, t->targetArtifacts)
+ step1(targetArtifact, 1);
+ startcol = endcol + 1;
+ QFontMetricsF metrics(sceneFont);
+
+ // draw artifacts
+ pen.setWidth(1);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setJoinStyle(Qt::MiterJoin);
+ for (QMap<int, QMap<int, ArtifactC *> >::const_iterator i = table.constBegin(); i != table.constEnd(); i++) {
+ int row = i.key();
+ QMap<int, ArtifactC *> line = i.value();
+ for (QMap<int, ArtifactC *>::const_iterator j = line.constBegin(); j != line.constEnd(); j++) {
+ int col = j.key();
+ ArtifactC *nc = j.value();
+ QRectF textRect = metrics.boundingRect(nc->label);
+ nc->row = row;
+ nc->col = col;
+ int x = row * (400 + VSPACE);
+ int y = col * 200;
+ nc->rectangle = textRect;
+ nc->rectangle.setWidth(400);
+ nc->rectangle.moveCenter(QPointF(x , y));
+
+ QGraphicsRectItem *item = scene->addRect(nc->rectangle, pen, brush);
+ item->setToolTip(nc->text);
+ nc->graphicsRectItem = item;
+
+ QGraphicsSimpleTextItem *slabel = scene->addSimpleText(nc->label);
+ slabel->setBrush(Qt::black);
+ slabel->setFont(sceneFont);
+
+ QRect textrect = QStyle::alignedRect (Qt::LeftToRight,
+ Qt::AlignCenter,
+ textRect.size().toSize(),
+ nc->rectangle.toRect());
+ slabel->setPos(textrect.topLeft());
+
+ // insert edges
+ foreach (qbs::Artifact *c, nc->artifact->children) {
+ edges.insert(nc, cartifacts[c]);
+ }
+ }
+ }
+
+ // draw edges
+ pen.setWidth(3);
+
+ for (QMap<ArtifactC *, ArtifactC *>::const_iterator i = edges.constBegin();
+ i != edges.constEnd();
+ i++) {
+ ArtifactC * k = i.key();
+ ArtifactC * v = i.value();
+ assert(v);
+ QPainterPath path;
+
+ QPointF fromP;
+ QPointF toP;
+
+
+ if (k->row < v->row) {
+ fromP = QPointF(k->rectangle.x() + k->rectangle.width(), k->rectangle.y() + k->rectangle.height()/2);
+ toP = QPointF(v->rectangle.x(), v->rectangle.y() + v->rectangle.height()/2);
+ } else {
+ fromP = QPointF(k->rectangle.x() + k->rectangle.width(), k->rectangle.y() + k->rectangle.height()/2);
+ toP = QPointF(v->rectangle.x(), v->rectangle.y() + v->rectangle.height()/2);
+ }
+ /*
+ } else if (k->row > v->row) {
+ fromP = QPointF(k->rc.x() + k->rc.width()/2, k->rc.y());
+ toP = QPointF(v->rc.x() + v->rc.width()/2, v->rc.y() + v->rc.height());
+ } else if (k->row < v->row) {
+ fromP = QPointF(k->rc.x() + k->rc.width()/2, k->rc.y() + v->rc.height());
+ toP = QPointF(v->rc.x() + v->rc.width()/2, v->rc.y() );
+ }
+ */
+
+ path.moveTo(fromP);
+
+ QPointF c1 = fromP;
+ c1.setX(c1.x() + VSPACE/2);
+ QPointF c2 = toP;
+ c2.setX(c2.x() - VSPACE/2);
+
+ path.cubicTo(c1, c2, toP);
+
+ scene->addPath(path)->setPen(pen);
+
+ QPolygonF poly;
+ poly.append(QPointF(toP.x() - 4, toP.y()));
+ poly.append(QPointF(toP.x() + 4, toP.y()));
+ poly.append(QPointF(toP.x(), toP.y() - 12));
+
+ QGraphicsItem *arrow = scene->addPolygon(poly, pen, QBrush(Qt::black));
+ arrow->setTransformOriginPoint(toP.x(), toP.y());
+ arrow->setRotation(-path.angleAtPercent(1) + 90);
+ }
+
+
+
+
+}
+
+
+#if 0
+ if (directive == QLatin1String("graph")) {
+ qreal scale, width, height;
+ in >> scale >> width >> height;
+ scene->setSceneRect(0, 0, width * SCALE, height * SCALE);
+
+ } else if (directive == QLatin1String("artifact")) {
+ QString name, label, style, shape, color, fillcolor;
+ qreal x, y, width, height;
+ in >> name >> x >> y >> width >> height;
+
+ unsigned char labelReadState = 0;
+ while (!in.atEnd() && labelReadState != 2) {
+ QString s = in.read(1);
+ switch (labelReadState) {
+ case 0:
+ if (s.at(0) == QLatin1Char('"'))
+ labelReadState = 1;
+ break;
+ case 1:
+ if (s == QLatin1String("\"")) {
+ labelReadState = 2;
+ } else {
+ label.append(s);
+ }
+ break;
+ }
+ }
+ in >> style >> shape >> color >> fillcolor;
+
+ label.replace(QLatin1String("\\n"), QLatin1String("\n"));
+ QPen pen = QColor(color);
+ QBrush brush = QColor(fillcolor);
+
+ QRectF rc;
+ rc.setSize(QSizeF(width * SCALE, height * SCALE));
+ rc.moveCenter(QPointF(x * SCALE, toY(y * SCALE)));
+
+ QGraphicsItem *item = 0;
+ if (shape == QLatin1String("ellipse"))
+ item = scene->addEllipse(rc, pen, brush);
+ else
+ item = scene->addRect(rc, pen, brush);
+ item->setToolTip(label);
+
+ QGraphicsSimpleTextItem *slabel = scene->addSimpleText(label);
+ slabel->setBrush(Qt::black);
+ slabel->setFont(sceneFont);
+
+ QRect textrect = QStyle::alignedRect (Qt::LeftToRight,
+ Qt::AlignCenter,
+ slabel->boundingRect().size().toSize(),
+ rc.toRect());
+ slabel->setPos(textrect.topLeft());
+
+ } else if (directive == QLatin1String("edge")) {
+ QString tail, head;
+ int n;
+ QString color;
+
+ in >> tail >> head >> n;
+ color = line.split(' ').last();
+
+ QVector<QPointF> points;
+ for (int i = 0; i < n; ++i) {
+ qreal x, y;
+ in >> x >> y;
+ points.append(QPointF(x * SCALE, toY(y * SCALE)));
+ }
+
+ QPainterPath path = fromControlPoints(points);
+
+ QPen pen;
+ pen.setWidth(2);
+ if (color != "black") {
+ pen = QPen(QColor(0x33,0x33,0xff));
+ pen.setWidth(1);
+ }
+
+ scene->addPath(path)->setPen(pen);
+
+ QPointF endPt = points.last();
+
+ QPolygonF poly;
+ poly.append(QPointF(endPt.x() - 4, endPt.y()));
+ poly.append(QPointF(endPt.x() + 4, endPt.y()));
+ poly.append(QPointF(endPt.x(), endPt.y() - 12));
+
+ QGraphicsItem *arrow = scene->addPolygon(poly, pen, QBrush(color
+ == "black"? Qt::black : QColor(0x33,0x33,0xff)));
+ arrow->setTransformOriginPoint(endPt.x(), endPt.y());
+ arrow->setRotation(-path.angleAtPercent(1) + 90);
+
+#endif
+
+
+#include "graph.moc"
diff --git a/src/app/graph/graph.pro b/src/app/graph/graph.pro
new file mode 100644
index 000000000..49d8f1e2a
--- /dev/null
+++ b/src/app/graph/graph.pro
@@ -0,0 +1,12 @@
+QT = core script gui
+
+TEMPLATE = app
+TARGET = qbs-graph
+DESTDIR = ../../../bin/
+
+CONFIG += console
+CONFIG -= app_bundle
+
+SOURCES += graph.cpp
+
+include(../../lib/use.pri)
diff --git a/src/app/platforms/main.cpp b/src/app/platforms/main.cpp
new file mode 100644
index 000000000..dbb22a986
--- /dev/null
+++ b/src/app/platforms/main.cpp
@@ -0,0 +1,299 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QSettings>
+
+#include <tools/platform.h>
+#include <tools/settings.h>
+
+#ifdef Q_OS_UNIX
+#include <iostream>
+#include <termios.h>
+#endif
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#include <Shlobj.h>
+#endif
+
+void showUsage()
+{
+ QTextStream s(stderr);
+ s << "platform [action]\n"
+ << "actions:\n"
+ << " s|shell <name> -- open a shell, setting up the named platform\n"
+ << " ls|list -- list available platforms\n"
+ << " mv|rename <from> <to> -- rename a platform\n"
+ << " rm|remove <name> -- irrevocably remove the given target\n"
+ << " config <name> [<key>] [<value>] -- show or change configuration\n"
+ << " probe -- probe the current environment\n"
+ << " and construct qbs platforms for each compiler found\n"
+ ;
+}
+
+static int ask(const QString &msg, const QString &choices);
+static QString prompt(const QString &msg);
+
+int probe (const QString &settingsPath,
+ QHash<QString, qbs::Platform*> &platforms,
+ int (* ask)(const QString &msg, const QString &choices),
+ QString ( *prompt)(const QString &msg)
+ );
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QTextStream qstdout(stdout);
+
+ qbs::Settings::Ptr settings = qbs::Settings::create();
+ QString defaultPlatform = settings->value("defaults/platform").toString();
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
+ QString localSettingsPath = QDir::homePath() + "/.config/Nokia/qbs/platforms/";
+#elif defined(Q_OS_WIN)
+ QString localSettingsPath;
+ wchar_t wszPath[MAX_PATH];
+ if (SHGetSpecialFolderPath(NULL, wszPath, CSIDL_APPDATA, TRUE))
+ localSettingsPath = QString::fromUtf16(wszPath) + "/qbs/platforms";
+#else
+#error port me!
+#endif
+ QDir().mkpath(localSettingsPath);
+
+ enum Action {
+ ListPlatform,
+ ProbePlatform,
+ RenamePlatform,
+ RemovePlatform,
+ ShellPlatform,
+ ConfigPlatform
+ };
+
+ Action action = ListPlatform;
+
+ QStringList arguments = app.arguments();
+ arguments.takeFirst();
+ if (arguments.count()) {
+ QString cmd = arguments.takeFirst();
+ if (cmd == "probe") {
+ action = ProbePlatform;
+ } else if (cmd == "rename" || cmd == "mv") {
+ action = RenamePlatform;
+ } else if (cmd == "rm" || cmd == "remove") {
+ action = RemovePlatform;
+ } else if (cmd == "shell" || cmd == "s") {
+ action = ShellPlatform;
+ } else if (cmd == "config") {
+ action = ConfigPlatform;
+ } else if (cmd == "list" || cmd == "ls") {
+ action = ListPlatform;
+ } else {
+ showUsage();
+ return 3;
+ }
+ }
+
+ QHash<QString, qbs::Platform*> targets;
+ QDirIterator i(localSettingsPath, QDir::Dirs | QDir::NoDotAndDotDot);
+ while (i.hasNext()) {
+ i.next();
+ qbs::Platform *t = new qbs::Platform(i.fileName(), i.filePath());
+ targets.insert(t->name, t);
+ }
+
+ if (action == ListPlatform) {
+ qstdout << "Platforms:\n";
+ foreach (qbs::Platform *t, targets.values()) {
+ qstdout << "\t- " << t->name;
+ if (t->name == defaultPlatform)
+ qstdout << " (default)";
+ qstdout << " "<< t->settings.value("target-triplet").toString() << "\n";
+ }
+ } else if (action == RenamePlatform) {
+ if (arguments.count() < 2) {
+ showUsage();
+ return 3;
+ }
+ QString from = arguments.takeFirst();
+ if (!targets.contains(from)) {
+ qDebug("cannot rename: no such target: %s", qPrintable(from));
+ return 5;
+ }
+ QString to = arguments.takeFirst();
+ if (targets.contains(to)) {
+ qDebug("cannot rename: already exists: %s", qPrintable(to));
+ return 5;
+ }
+ if (!QFile(localSettingsPath + from).rename(localSettingsPath + to)) {
+ qDebug("file error moving %s to %s",
+ qPrintable(localSettingsPath + from),
+ qPrintable(localSettingsPath + to)
+ );
+ return 5;
+ }
+ targets.insert(to, targets.take(from));
+ } else if (action == RemovePlatform) {
+ if (arguments.count() < 1) {
+ showUsage();
+ return 3;
+ }
+ QString targetName = arguments.takeFirst();
+ if (!targets.contains(targetName)) {
+ qDebug("cannot remove: no such target: %s", qPrintable(targetName));
+ return 5;
+ }
+ QDirIterator i1(localSettingsPath + targetName,
+ QDir::Files | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden,
+ QDirIterator::Subdirectories);
+ while (i1.hasNext()) {
+ i1.next();
+ QFile(i1.filePath()).remove();
+ }
+ QDirIterator i2(localSettingsPath + targetName,
+ QDir::Dirs| QDir::NoDotAndDotDot | QDir::System | QDir::Hidden,
+ QDirIterator::Subdirectories);
+ while (i2.hasNext()) {
+ i2.next();
+ QDir().rmdir(i2.filePath());
+ }
+ QDir().rmdir(localSettingsPath + targetName);
+ delete targets.take(targetName);
+ } else if (action == ConfigPlatform) {
+ if (arguments.count() < 1) {
+ showUsage();
+ return 3;
+ }
+ QString targetName= arguments.takeFirst();
+ if (!targets.contains(targetName)) {
+ qDebug("no such target: %s", qPrintable(targetName));
+ return 5;
+ }
+ qbs::Platform *p = targets.value(targetName);
+ if (arguments.count()) {
+ QString key = arguments.takeFirst();
+ if (arguments.count()) {
+ QString value = arguments.takeFirst();
+ p->settings.setValue(key, value);
+ }
+ if (!p->settings.contains(key)) {
+ qDebug("no such configuration key: %s", qPrintable(key));
+ return 7;
+ }
+ qstdout << p->settings.value(key).toString() << "\n";
+ } else {
+ foreach (const QString &key, p->settings.allKeys()) {
+ qstdout << key << "=" << p->settings.value(key).toString() << "\n";
+ }
+ }
+
+ } else if (action == ProbePlatform) {
+ bool firstRun = targets.isEmpty();
+ probe(localSettingsPath, targets, ask, prompt);
+ if (firstRun && !targets.isEmpty()) {
+ settings->setValue(qbs::Settings::Global, "defaults/platform", targets.values().at(0)->name);
+ }
+ }
+ return 0;
+}
+
+
+static int ask(const QString &msg, const QString &choices)
+{
+#ifdef Q_OS_UNIX
+ termios stored_settings;
+ tcgetattr(0, &stored_settings);
+ termios new_settings = stored_settings;
+ new_settings.c_lflag &= (~ICANON);
+ new_settings.c_lflag &= (~ECHO); // don't echo the character
+ // apply the new settings
+ tcsetattr(0, TCSANOW, &new_settings);
+#endif
+
+ setvbuf ( stdin , NULL , _IONBF , 0 );
+
+
+ QTextStream qstdout(stdout);
+ qstdout << msg << " (";
+
+ QHash<QChar, int> cs;
+
+ for (int i = 0; i < choices.count(); i++) {
+ QChar c = choices.at(i);
+ cs.insert(c.toLower(), i);
+ if (i == 0)
+ qstdout << c.toUpper();
+ else
+ qstdout << c.toLower();
+ if (i != choices.count() -1)
+ qstdout << "/";
+ }
+ qstdout << ") " << flush;
+
+ while (true) {
+ QChar i = QChar(getc(stdin)).toLower();
+ if (i == '\n' || i == '\r') {
+#ifdef Q_OS_UNIX
+ tcsetattr(0, TCSANOW, &stored_settings);
+#endif
+ qstdout << choices.at(0).toUpper() << "\n" << flush;
+ return 0;
+ }
+ if (cs.contains(i)) {
+#ifdef Q_OS_UNIX
+ tcsetattr(0, TCSANOW, &stored_settings);
+#endif
+ qstdout << i << "\n" << flush;
+ return cs.value(i);
+ }
+ }
+}
+
+static QString prompt(const QString &msg)
+{
+ QTextStream qstdout(stdout);
+ qstdout << msg << " "<< flush;
+ QTextStream qstdin(stdin);
+ QString s;
+ qstdin >> s;
+ return s;
+}
diff --git a/src/app/platforms/platforms.pro b/src/app/platforms/platforms.pro
new file mode 100644
index 000000000..7fa483cac
--- /dev/null
+++ b/src/app/platforms/platforms.pro
@@ -0,0 +1,12 @@
+QT = core script gui
+
+TEMPLATE = app
+TARGET = qbs-platforms
+DESTDIR = ../../../bin/
+
+CONFIG += console
+CONFIG -= app_bundle
+
+SOURCES += main.cpp probe.cpp
+
+include(../../lib/use.pri)
diff --git a/src/app/platforms/probe.cpp b/src/app/platforms/probe.cpp
new file mode 100644
index 000000000..efd0a69e7
--- /dev/null
+++ b/src/app/platforms/probe.cpp
@@ -0,0 +1,393 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QSettings>
+
+#include <tools/platform.h>
+
+using namespace qbs;
+
+static QString searchPath(const QString &path, const QString &me)
+{
+ //TODO: use native seperator
+ foreach (const QString &ppath, path.split(":")) {
+ if (QFileInfo(ppath + "/" + me).exists()) {
+ return QDir::cleanPath(ppath + "/" + me);
+ }
+ }
+ return QString();
+}
+
+static QString qsystem(const QString &exe, const QStringList &args = QStringList())
+{
+ QProcess p;
+ p.setProcessChannelMode(QProcess::MergedChannels);
+ p.start(exe, args);
+ p.waitForStarted();
+ p.waitForFinished();
+ return QString::fromLocal8Bit(p.readAll());
+}
+
+static int specific_probe(const QString &settingsPath,
+ QHash<QString, Platform*> &platforms,
+ int (* ask)(const QString &msg, const QString &choices),
+ QString ( *prompt)(const QString &msg),
+ QString cc,
+ bool printComfortingMessage = false
+ )
+{
+ QTextStream qstdout(stdout);
+
+ QString toolchainType;
+ if(cc.contains("clang"))
+ toolchainType = "clang";
+ else if (cc.contains("gcc"))
+ toolchainType = "gcc";
+
+ QString path = QString::fromLocal8Bit(qgetenv("PATH"));
+ QString cxx = QString::fromLocal8Bit(qgetenv("CXX"));
+ QString ld = QString::fromLocal8Bit(qgetenv("LD"));
+ QString cflags = QString::fromLocal8Bit(qgetenv("CFLAGS"));
+ QString cxxflags = QString::fromLocal8Bit(qgetenv("CXXFLAGS"));
+ QString ldflags = QString::fromLocal8Bit(qgetenv("LDFLAGS"));
+ QString cross = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
+ QString arch = QString::fromLocal8Bit(qgetenv("ARCH"));
+
+ QString pathToGcc;
+ QString architecture;
+ QString endianness;
+
+ QString name;
+ QString sysroot;
+
+ bool isACrossCompiler = false;
+
+ QString uname = qsystem("uname", QStringList() << "-m").simplified();
+
+ if (arch.isEmpty())
+ arch = uname;
+
+#ifdef Q_OS_MAC
+ // HACK: "uname -m" reports "i386" but "gcc -dumpmachine" reports "i686" on MacOS.
+ if (arch == "i386")
+ arch = "i686";
+#endif
+
+ if (ld.isEmpty())
+ ld = "ld";
+ if (cxx.isEmpty()) {
+ if (toolchainType == "gcc")
+ cxx = "g++";
+ else if(toolchainType == "clang")
+ cxx = "clang++";
+ }
+ if(!cross.isEmpty() && !cc.startsWith("/")) {
+ pathToGcc = searchPath(path, cross + cc);
+ if (QFileInfo(pathToGcc).exists()) {
+ if (!cc.contains(cross))
+ cc.prepend(cross);
+ if (!cxx.contains(cross))
+ cxx.prepend(cross);
+ if (!ld.contains(cross))
+ ld.prepend(cross);
+ }
+ }
+ if (cc.startsWith("/"))
+ pathToGcc = cc;
+ else
+ pathToGcc = searchPath(path, cc);
+
+ if (!QFileInfo(pathToGcc).exists()) {
+ fprintf(stderr, "Cannot find %s.", qPrintable(cc));
+ if (printComfortingMessage)
+ fprintf(stderr, " But that's not a problem. I've already found other platforms.\n");
+ else
+ fprintf(stderr, "\n");
+ return 1;
+ }
+
+ Platform *s = 0;
+ foreach (Platform *p, platforms.values()) {
+ QString path = p->settings.value("ev/completeccpath").toString();
+ if (path == pathToGcc) {
+ name = p->name;
+ s = p;
+ name = s->name;
+ break;
+ }
+ }
+
+ QString compilerTriplet = qsystem(pathToGcc, QStringList() << "-dumpmachine").simplified();
+ QStringList compilerTripletl = compilerTriplet.split('-');
+ if (compilerTripletl.count() < 2 ||
+ !(compilerTripletl.at(0).contains(QRegExp(".86")) ||
+ compilerTripletl.at(0).contains("arm") )
+ ) {
+ qDebug("detected %s , but i don't understand it's architecture: %s",
+ qPrintable(pathToGcc), qPrintable(compilerTriplet));
+ return 12;
+ }
+
+ architecture = compilerTripletl.at(0);
+ if (architecture.contains("arm")) {
+ endianness = "big-endian";
+ } else {
+ endianness = "little-endian";
+ }
+
+ QStringList pathToGccL = pathToGcc.split('/');
+ QString compilerName = pathToGccL.takeLast().replace(cc, cxx);
+
+ if (architecture != arch) {
+ isACrossCompiler = true;
+ }
+ if (!cross.isEmpty()) {
+ isACrossCompiler = true;
+ }
+
+ if (isACrossCompiler && !cross.contains(compilerTriplet)) {
+ if (s) {
+ compilerTriplet = s->settings.value("ev/target-triplet").toString();
+ } else {
+ qDebug("==> detected %s (%s), but it doesn't seem to fit your cross target (%s)",
+ qPrintable(pathToGcc),
+ qPrintable(compilerTriplet),
+ qPrintable(cross)
+ );
+ if (ask(" assume this compiler produces "+cross+" and carry on?", "ny") == 0)
+ return 2;
+
+ compilerTriplet = cross;
+ }
+ compilerTripletl = compilerTriplet.split('-');
+ architecture = compilerTripletl.at(0);
+ }
+
+ if (
+ (isACrossCompiler) &&
+ (!cflags.contains("--sysroot"))
+ ) {
+ qDebug("==> detected cross compiler %s (%s), but CFLAGS don't contain a --syroot option "
+ "\n If you did not want to cross-compiler, or you are in a chroot that is not arch %s,"
+ "\n try overriding uname -m by setting ARCH=%s in the environment and/or unset CROSS_COMPILE"
+ "\n ",
+ qPrintable(pathToGcc), qPrintable(compilerTriplet), qPrintable(arch), qPrintable(architecture));
+ return 3;
+ } else {
+ }
+
+ if (cflags.contains("--sysroot")) {
+ QStringList flagl = cflags.split(' ');
+
+ bool nextitis = false;
+ foreach (const QString &flag, flagl) {
+ if (nextitis) {
+ sysroot = flag;
+ break;
+ }
+ if (flag == "--sysroot") {
+ nextitis = true;
+ }
+ }
+ }
+
+
+
+ qstdout << "==> " << (s?"reconfiguring " + name :"detected")
+ << " " << (isACrossCompiler ? "cross compiler" : "native compiler")
+ << " " << pathToGcc << "\n"
+ << " triplet: " << compilerTriplet << "\n"
+ << " arch: " << architecture << "\n"
+ << " bin: " << pathToGccL.join("/") << "\n"
+ << " cc: " << cc << "\n"
+ ;
+
+ if (!cxx.isEmpty())
+ qstdout << " cxx: " << cxx << "\n";
+ if (!ld.isEmpty())
+ qstdout << " ld: " << ld << "\n";
+
+ if (!sysroot.isEmpty())
+ qstdout << " sysroot: " << sysroot << "\n";
+ if (!cflags.isEmpty())
+ qstdout << " CFLAGS: " << cflags << "\n";
+ if (!cxxflags.isEmpty())
+ qstdout << " CXXFLAGS: " << cxxflags << "\n";
+ if (!ldflags.isEmpty())
+ qstdout << " CXXFLAGS: " << ldflags << "\n";
+
+ qstdout << flush;
+
+ if (!s) {
+ while (name.isEmpty())
+ name = prompt("give a name to this platform:");
+ s = new Platform(name, settingsPath + "/" + name);
+ }
+
+ // fixme should be cpp.toolchain
+ // also there is no toolchain:clang
+ s->settings.setValue("toolchain", "gcc");
+ s->settings.setValue("ev/completeccpath", pathToGcc);
+ s->settings.setValue("ev/target-triplet", compilerTriplet);
+ s->settings.setValue("architecture", architecture);
+ s->settings.setValue("endianness", endianness);
+
+#if defined(Q_OS_MAC)
+ s->settings.setValue("targetOS", "mac");
+#elif defined(Q_OS_LINUX)
+ s->settings.setValue("targetOS", "linux");
+#else
+ s->settings.setValue("targetOS", "unknown"); //fixme
+#endif
+
+ if (compilerName.contains('-')) {
+ QStringList nl = compilerName.split('-');
+ s->settings.setValue("cpp/compilerName", nl.takeLast());
+ s->settings.setValue("cpp/toolchainPrefix", nl.join("-") + '-');
+ } else {
+ s->settings.setValue("cpp/compilerName", compilerName);
+ }
+ s->settings.setValue("cpp/toolchainInstallPath", pathToGccL.join("/"));
+
+ s->settings.setValue("environment/PATH", s->settings.value("cpp/toolchainInstallPath"));
+ if (!cross.isEmpty())
+ s->settings.setValue("environment/CROSS_COMPILE", cross);
+ if (!cflags.isEmpty())
+ s->settings.setValue("environment/CFLAGS", cflags);
+ if (!cxxflags.isEmpty())
+ s->settings.setValue("environment/CXXFLAGS", cxxflags);
+ if (!ldflags.isEmpty())
+ s->settings.setValue("environment/LDFLAGS", ldflags);
+
+ platforms.insert(s->name, s);
+
+ s->settings.sync();
+ return 0;
+}
+
+#ifdef Q_OS_WIN
+static void msvc_probe(const QString &settingsPath,
+ QHash<QString, Platform*> &platforms)
+{
+ QTextStream qstdout(stdout);
+
+ QString vcInstallDir = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv("VCINSTALLDIR")));
+ if (vcInstallDir.endsWith('/'))
+ vcInstallDir.chop(1);
+ if (vcInstallDir.isEmpty())
+ return;
+ QString winSDKPath = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv("WindowsSdkDir")));
+ if (winSDKPath.endsWith('/'))
+ winSDKPath.chop(1);
+ QString clOutput = qsystem(vcInstallDir + "/bin/cl.exe");
+ if (clOutput.isEmpty())
+ return;
+
+ QRegExp rex("C/C\\+\\+ Optimizing Compiler Version ((\\d|\\.)+) for ((x|\\d)+)");
+ int idx = rex.indexIn(clOutput);
+ if (idx < 0)
+ return;
+
+ QStringList clVersion = rex.cap(1).split(".");
+ if (clVersion.isEmpty())
+ return;
+ QString clArch = rex.cap(3);
+ QString msvcVersion = "msvc";
+ switch (clVersion.first().toInt()) {
+ case 14:
+ msvcVersion += "2005";
+ break;
+ case 15:
+ msvcVersion += "2008";
+ break;
+ case 16:
+ msvcVersion += "2010";
+ break;
+ default:
+ return;
+ }
+
+ Platform *s = platforms.value(msvcVersion);
+ if (!s)
+ s = new Platform(msvcVersion, settingsPath + "/" + msvcVersion);
+
+ QString vsInstallDir = vcInstallDir;
+ idx = vsInstallDir.lastIndexOf("/");
+ if (idx < 0)
+ return;
+ vsInstallDir.truncate(idx);
+
+ s->settings.setValue("targetOS", "windows");
+ s->settings.setValue("cpp/toolchainInstallPath", vsInstallDir);
+ s->settings.setValue("toolchain", "msvc");
+ s->settings.setValue("cpp/windowsSDKPath", winSDKPath);
+ platforms.insert(s->name, s);
+ qstdout << "Detected platform " << msvcVersion << " for " << clArch << ".\n";
+ qstdout << "When building projects, the architecture can be chosen by passing\narchitecture:x86 or architecture:x86_64 to qbs.\n";
+ s->settings.sync();
+}
+#endif
+
+int probe (const QString &settingsPath,
+ QHash<QString, Platform*> &platforms,
+ int (* ask)(const QString &msg, const QString &choices),
+ QString ( *prompt)(const QString &msg)
+ )
+{
+#ifdef Q_OS_WIN
+ Q_UNUSED(prompt);
+ Q_UNUSED(ask);
+ msvc_probe(settingsPath, platforms);
+#else
+ QString cc = QString::fromLocal8Bit(qgetenv("CC"));
+ if (cc.isEmpty()) {
+ bool somethingFound = false;
+ if (specific_probe(settingsPath, platforms, ask, prompt, "gcc") == 0)
+ somethingFound = true;
+ specific_probe(settingsPath, platforms, ask, prompt, "clang", somethingFound);
+ } else {
+ specific_probe(settingsPath, platforms, ask, prompt, cc);
+ }
+#endif
+ return 0;
+}
diff --git a/src/app/qbs/application.cpp b/src/app/qbs/application.cpp
new file mode 100644
index 000000000..d91b99cb2
--- /dev/null
+++ b/src/app/qbs/application.cpp
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "application.h"
+#include "ctrlchandler.h"
+#include <QtCore/QDebug>
+
+Application::Application(int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+{
+ // ### TODO reactivate the Ctrl-C handler
+ //installCtrlCHandler();
+}
+
+void Application::init()
+{
+ setApplicationName("qbs");
+ setOrganizationName("Nokia");
+ setOrganizationDomain("qt.nokia.com");
+
+ connect(&m_buildProjectFutureWatcher, SIGNAL(finished()), this, SLOT(quit()), Qt::QueuedConnection);
+}
+
+void Application::userInterrupt()
+{
+ fprintf(stderr, "qbs terminated by user (pid=%u)\n", (uint)QCoreApplication::applicationPid());
+ m_buildProjectFutureWatcher.cancel();
+}
diff --git a/src/app/qbs/application.h b/src/app/qbs/application.h
new file mode 100644
index 000000000..247dd813d
--- /dev/null
+++ b/src/app/qbs/application.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include <Qbs/buildexecutor.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFutureWatcher>
+
+class Application : public QCoreApplication
+{
+ Q_OBJECT
+public:
+ Application(int &argc, char **argv);
+
+ void init();
+
+ Qbs::BuildExecutor *buildExecutor() { return &m_buildExecutor; }
+ QFutureWatcher<bool> *buildProjectFutureWatcher() { return &m_buildProjectFutureWatcher; }
+
+public slots:
+ void userInterrupt();
+
+private:
+ Qbs::BuildExecutor m_buildExecutor;
+ QFutureWatcher<bool> m_buildProjectFutureWatcher;
+};
+
+#endif // APPLICATION_H
diff --git a/src/app/qbs/ctrlchandler.cpp b/src/app/qbs/ctrlchandler.cpp
new file mode 100644
index 000000000..5932c8bb0
--- /dev/null
+++ b/src/app/qbs/ctrlchandler.cpp
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+#if defined(Q_OS_WIN) && defined(Q_CC_MSVC)
+
+#include <qt_windows.h>
+
+static BOOL WINAPI consoleCtrlHandlerRoutine(__in DWORD dwCtrlType)
+{
+ Q_UNUSED(dwCtrlType);
+ QTimer::singleShot(0, qApp, SLOT(userInterrupt()));
+ return TRUE;
+}
+
+void installCtrlCHandler()
+{
+ SetConsoleCtrlHandler(&consoleCtrlHandlerRoutine, TRUE);
+}
+
+#else
+
+#include <csignal>
+
+static void sigIntHandler(int sig)
+{
+ Q_UNUSED(sig);
+ QTimer::singleShot(0, qApp, SLOT(userInterrupt()));
+}
+
+void installCtrlCHandler()
+{
+ signal(SIGINT, sigIntHandler);
+}
+
+#endif
diff --git a/src/app/qbs/ctrlchandler.h b/src/app/qbs/ctrlchandler.h
new file mode 100644
index 000000000..75c9c12b0
--- /dev/null
+++ b/src/app/qbs/ctrlchandler.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef CTRLCHANDLER_H
+#define CTRLCHANDLER_H
+
+void installCtrlCHandler();
+
+#endif // CTRLCHANDLER_H
diff --git a/src/app/qbs/main.cpp b/src/app/qbs/main.cpp
new file mode 100644
index 000000000..6c86741d0
--- /dev/null
+++ b/src/app/qbs/main.cpp
@@ -0,0 +1,304 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "application.h"
+#include <Qbs/oldsourceproject.h>
+#include <Qbs/mainthreadcommunication.h>
+#include <tools/logger.h>
+#include <tools/options.h>
+#include <buildgraph/buildgraph.h>
+#include <buildgraph/executor.h>
+#include <tools/runenvironment.h>
+#include <tools/fakeconcurrent.h>
+#include <tools/fileinfo.h>
+#include <tools/persistence.h>
+#include <tools/logsink.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+
+#if defined(Q_OS_UNIX)
+#include <errno.h>
+#endif
+
+enum ExitCodes
+{
+ ExitCodeOK = 0,
+ ExitCodeErrorParsingCommandLine = 1,
+ ExitCodeErrorCommandNotImplemented = 2,
+ ExitCodeErrorExecutionFailed = 3,
+ ExitCodeErrorLoadingProjectFailed = 4,
+ ExitCodeErrorBuildFailure = 5
+};
+
+int main(int argc, char *argv[])
+{
+ Application app(argc, argv);
+ app.init();
+
+ qbs::CommandLineOptions options;
+ qbs::ConsolePrintLogSink *logSink = new qbs::ConsolePrintLogSink;
+ logSink->setColoredOutputEnabled(options.configurationValue("defaults/useColoredOutput", true).toBool());
+ Qbs::ILogSink::setGlobalLogSink(logSink);
+ Qbs::MainThreadCommunication::registerMetaType();
+ QStringList arguments = app.arguments();
+ arguments.removeFirst();
+
+ if (arguments.count()) {
+#if defined(Q_OS_UNIX)
+ qputenv("PATH", QCoreApplication::applicationDirPath().toLocal8Bit() + ':' + QByteArray(qgetenv("PATH")));
+#elif defined(Q_OS_WIN)
+ qputenv("PATH", QCoreApplication::applicationDirPath().toLocal8Bit() + ';' + QByteArray(qgetenv("PATH")));
+#endif
+ QStringList args = app.arguments();
+ args.takeFirst();
+ QString app = args.takeFirst();
+ if (!app.startsWith('-')) {
+#if defined(Q_OS_UNIX)
+ char **argvp = new char*[args.count() + 2];
+ QList<QByteArray> bargs;
+ bargs.append("qbs-" + app.toLocal8Bit());
+ argvp[0] = bargs.last().data();
+ int i = 1;
+ foreach (const QString &s, args) {
+ bargs.append(s.toLocal8Bit());
+ argvp[i++] = bargs.last().data();
+ }
+ argvp[i] = 0;
+
+ execvp(argvp[0], argvp);
+ if (errno != ENOENT) {
+ perror("execvp");
+ return errno;
+ }
+#else
+ int r = QProcess::execute ( "qbs-" + app, args );
+ if (r != -2)
+ return r;
+#endif
+ }
+ }
+
+ // read commandline
+ if (!options.readCommandLineArguments(arguments)) {
+ qbs::CommandLineOptions::printHelp();
+ return ExitCodeErrorParsingCommandLine;
+ }
+
+ if (options.isHelpSet()) {
+ qbs::CommandLineOptions::printHelp();
+ return 0;
+ }
+
+ try {
+ if (options.command() == qbs::CommandLineOptions::ConfigCommand) {
+ options.configure();
+ return 0;
+ }
+ } catch (qbs::Error &e) {
+ fputs("qbs config: ", stderr);
+ fputs(qPrintable(e.toString()), stderr);
+ fputs("\n", stderr);
+ return ExitCodeErrorParsingCommandLine;
+ }
+
+ if (options.projectFileName().isEmpty()) {
+ qbsError("No project file found.");
+ return ExitCodeErrorParsingCommandLine;
+ } else {
+ qbsInfo() << qbs::DontPrintLogLevel << "Found project file " << qPrintable(QDir::toNativeSeparators(options.projectFileName()));
+ }
+
+ if (options.command() == qbs::CommandLineOptions::CleanCommand) {
+ // ### TODO: take selected products into account!
+ QString errorMessage;
+
+ const QString buildPath = qbs::FileInfo::resolvePath(QDir::currentPath(), QLatin1String("build"));
+ qbs::removeDirectoryWithContents(buildPath, &errorMessage);
+
+ if (!errorMessage.isEmpty()) {
+ qbsError() << errorMessage;
+ return ExitCodeErrorExecutionFailed;
+ }
+ return 0;
+ }
+
+ // some sanity checks
+ foreach (const QString &searchPath, options.searchPaths()) {
+ if (!qbs::FileInfo::exists(searchPath)) {
+ qbsError("search path '%s' does not exist.\n"
+ "run 'qbs config --global paths/cubes $QBS_SOURCE_TREE/share/qbs'",
+ qPrintable(searchPath));
+
+ return ExitCodeErrorParsingCommandLine;
+ }
+ }
+ foreach (const QString &pluginPath, options.pluginPaths()) {
+ if (!qbs::FileInfo::exists(pluginPath)) {
+ qbsError("plugin path '%s' does not exist.\n"
+ "run 'qbs config --global paths/plugins $QBS_BUILD_TREE/plugins'",
+ qPrintable(pluginPath));
+ return ExitCodeErrorParsingCommandLine;
+ }
+ }
+
+ qbs::SourceProject sourceProject(options.settings());
+ sourceProject.setSearchPaths(options.searchPaths());
+ sourceProject.loadPlugins(options.pluginPaths());
+ QFuture<bool> loadProjectFuture = qbs::FakeConcurrent::run(&qbs::SourceProject::loadProject,
+ &sourceProject,
+ options.projectFileName(),
+ options.buildConfigurations());
+ loadProjectFuture.waitForFinished();
+ foreach (const qbs::Error &error, sourceProject.errors()) {
+ qbsError() << error.toString();
+ return ExitCodeErrorLoadingProjectFailed;
+ }
+
+ if (options.command() == qbs::CommandLineOptions::StartShellCommand) {
+ qbs::BuildProject::Ptr buildProject = sourceProject.buildProjects().first();
+ qbs::BuildProduct::Ptr buildProduct = *buildProject->buildProducts().begin();
+ qbs::RunEnvironment run(buildProduct->rProduct);
+ return run.runShell();
+ }
+ if (options.isDumpGraphSet()) {
+ foreach (qbs::BuildProject::Ptr buildPrj, sourceProject.buildProjects())
+ foreach (qbs::BuildProduct::Ptr buildProduct, buildPrj->buildProducts())
+ qbs::BuildGraph().dump(buildProduct);
+ return 0;
+ }
+
+ // execute the build graph
+ Qbs::BuildExecutor *buildExecutor = app.buildExecutor();
+ buildExecutor->setMaximumJobs(options.jobs());
+ buildExecutor->setRunOnceAndForgetModeEnabled(true);
+ buildExecutor->setKeepGoingEnabled(options.isKeepGoingSet());
+ buildExecutor->setDryRunEnabled(options.isDryRunSet());
+
+ QDir currentDir;
+ QStringList absoluteNamesChangedFiles;
+ foreach (const QString &fileName, options.changedFiles())
+ absoluteNamesChangedFiles += QDir::fromNativeSeparators(currentDir.absoluteFilePath(fileName));
+
+ int result = 0;
+ QFuture<bool> buildProjectFuture = qbs::FakeConcurrent::run(&Qbs::BuildExecutor::executeBuildProjects, buildExecutor,
+ sourceProject.buildProjects(), absoluteNamesChangedFiles, options.selectedProductNames());
+ app.buildProjectFutureWatcher()->setFuture(buildProjectFuture);
+ result = app.exec();
+
+ // store the projects on disk
+ try {
+ foreach (qbs::BuildProject::Ptr project, sourceProject.buildProjects())
+ project->store();
+ } catch (qbs::Error &e) {
+ qbsError() << e.toString();
+ return ExitCodeErrorExecutionFailed;
+ }
+
+ if (buildExecutor->state() == Qbs::BuildExecutor::ExecutorError)
+ return ExitCodeErrorBuildFailure;
+
+ if (options.command() == qbs::CommandLineOptions::RunCommand) {
+ qbs::BuildProject::Ptr project = sourceProject.buildProjects().first();
+ qbs::BuildProduct::Ptr productToRun;
+ QString productFileName;
+ QSet<QString> runnableFileTags;
+#ifdef Q_OS_MAC
+ runnableFileTags << "applicationbundle";
+#else
+ runnableFileTags << "application";
+#endif
+#ifdef Q_OS_MAC
+ bool openProduct = false;
+#endif // Q_OS_MAC
+ if (options.runTargetName().isEmpty()) {
+ foreach (qbs::BuildProduct::Ptr product, project->buildProducts()) {
+ foreach (qbs::Artifact *targetArtifact, product->targetArtifacts) {
+ if (!targetArtifact->fileTags.intersect(runnableFileTags).isEmpty()) {
+ productToRun = product;
+ productFileName = targetArtifact->fileName;
+#ifdef Q_OS_MAC
+ if (targetArtifact->fileTags.contains("applicationbundle"))
+ openProduct = true;
+#endif // Q_OS_MAC
+ break;
+ }
+ }
+ if (productToRun)
+ break;
+ }
+ } else {
+ foreach (qbs::BuildProduct::Ptr product, project->buildProducts()) {
+ if (product->rProduct->name == options.runTargetName()) {
+ productToRun = product;
+ foreach (qbs::Artifact *targetArtifact, product->targetArtifacts) {
+ if (!targetArtifact->fileTags.intersect(runnableFileTags).isEmpty()) {
+ productToRun = product;
+ productFileName = targetArtifact->fileName;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (!productToRun) {
+ if (options.runTargetName().isEmpty())
+ qbsError() << QObject::tr("Can't find a suitable product to run.");
+ else
+ qbsError() << QObject::tr("No such product: '%1'").arg(options.runTargetName());
+ return ExitCodeErrorBuildFailure;
+ }
+
+ qbs::RunEnvironment run(productToRun->rProduct);
+#ifdef Q_OS_MAC
+ if (openProduct) {
+ QStringList runArgs = options.runArgs();
+ QString appBundleName = productFileName; // TODO: make appBundleName be the app bundle dir
+ runArgs.prepend(appBundleName);
+ return run.runTarget("/usr/bin/open", runArgs);
+ }
+#endif // Q_OS_MAC
+ return run.runTarget(productFileName, options.runArgs());
+ }
+
+ return result;
+}
diff --git a/src/app/qbs/qbs.pro b/src/app/qbs/qbs.pro
new file mode 100644
index 000000000..0a15fb139
--- /dev/null
+++ b/src/app/qbs/qbs.pro
@@ -0,0 +1,16 @@
+QT = core script
+TEMPLATE = app
+TARGET = qbs
+DESTDIR = ../../../bin
+
+CONFIG += console
+CONFIG -= app_bundle
+
+SOURCES += main.cpp \
+ ctrlchandler.cpp \
+ application.cpp
+HEADERS += \
+ ctrlchandler.h \
+ application.h
+
+include(../../lib/use.pri)
diff --git a/src/lib/Qbs/Qbs.pri b/src/lib/Qbs/Qbs.pri
new file mode 100644
index 000000000..d981359fd
--- /dev/null
+++ b/src/lib/Qbs/Qbs.pri
@@ -0,0 +1,37 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/sourceproject.h \
+ $$PWD/oldsourceproject.h \
+ $$PWD/buildproject.h \
+ $$PWD/error.h \
+ $$PWD/buildproduct.h \
+ $$PWD/buildexecutor.h \
+ $$PWD/processoutput.h \
+ $$PWD/ilogsink.h \
+ $$PWD/globals.h \
+ $$PWD/mainthreadcommunication.h \
+ $$PWD/logmessageevent.h \
+ $$PWD/processoutputevent.h
+
+SOURCES += \
+ $$PWD/sourceproject.cpp \
+ $$PWD/oldsourceproject.cpp \
+ $$PWD/buildproject.cpp \
+ $$PWD/qbserror.cpp \
+ $$PWD/buildproduct.cpp \
+ $$PWD/buildexecutor.cpp \
+ $$PWD/processoutput.cpp \
+ $$PWD/ilogsink.cpp \
+ $$PWD/mainthreadcommunication.cpp \
+ $$PWD/logmessageevent.cpp \
+ $$PWD/processoutputevent.cpp
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/Qbs/buildexecutor.cpp b/src/lib/Qbs/buildexecutor.cpp
new file mode 100644
index 000000000..b1a99063a
--- /dev/null
+++ b/src/lib/Qbs/buildexecutor.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#include "buildexecutor.h"
+
+#include <buildgraph/executor.h>
+#include <Qbs/buildproduct.h>
+#include <Qbs/buildproject.h>
+
+namespace Qbs {
+
+BuildExecutor::BuildExecutor()
+ : m_maximumJobs(1),
+ m_runOnceAndForgetModeEnabled(false),
+ m_dryRun(false),
+ m_keepGoing(false),
+ m_state(ExecutorIdle)
+{
+}
+
+
+void BuildExecutor::setMaximumJobs(int numberOfJobs)
+{
+ QWriteLocker locker(&m_lock);
+ m_maximumJobs = numberOfJobs;
+}
+
+int BuildExecutor::maximumJobs() const
+{
+ QReadLocker locker(&m_lock);
+ return m_maximumJobs;
+}
+
+void BuildExecutor::setRunOnceAndForgetModeEnabled(bool enable)
+{
+ QWriteLocker locker(&m_lock);
+ m_runOnceAndForgetModeEnabled = enable;
+}
+
+bool BuildExecutor::runOnceAndForgetModeIsEnabled() const
+{
+ QReadLocker locker(&m_lock);
+ return m_runOnceAndForgetModeEnabled;
+}
+
+void BuildExecutor::setDryRunEnabled(bool enable)
+{
+ QWriteLocker locker(&m_lock);
+ m_dryRun = enable;
+}
+
+bool BuildExecutor::isDryRunEnabled() const
+{
+ QReadLocker locker(&m_lock);
+ return m_dryRun;
+}
+
+void BuildExecutor::setKeepGoingEnabled(bool enable)
+{
+ QWriteLocker locker(&m_lock);
+ m_keepGoing = enable;
+}
+
+bool BuildExecutor::isKeepGoingEnabled() const
+{
+ QReadLocker locker(&m_lock);
+ return m_keepGoing;
+}
+
+void BuildExecutor::executeBuildProject(QFutureInterface<bool> &futureInterface, const BuildProject &buildProject)
+{
+ QList<qbs::BuildProject::Ptr> internalBuildProjects;
+ internalBuildProjects.append(buildProject.internalBuildProject());
+ QStringList changedFiles; // ### populate
+ QStringList selectedProductNames; // ### populate
+ executeBuildProjects(futureInterface, internalBuildProjects, changedFiles, selectedProductNames);
+}
+
+/*!
+ Starts the build for the given list of projects.
+
+ Args:
+ changedFiles - absolute file names of changed files (optional)
+ */
+void BuildExecutor::executeBuildProjects(QFutureInterface<bool> &futureInterface, const QList<QSharedPointer<qbs::BuildProject> > internalBuildProjects,
+ QStringList changedFiles, QStringList selectedProductNames)
+{
+ QEventLoop eventLoop;
+
+ m_state = ExecutorRunning;
+ qbs::Executor executor(maximumJobs());
+ executor.setRunOnceAndForgetModeEnabled(runOnceAndForgetModeIsEnabled());
+ executor.setKeepGoing(isDryRunEnabled());
+ executor.setDryRun(isDryRunEnabled());
+
+ QObject::connect(&executor, SIGNAL(finished()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
+ QObject::connect(&executor, SIGNAL(error()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
+
+ executor.build(internalBuildProjects, changedFiles, selectedProductNames, futureInterface);
+
+ eventLoop.exec();
+
+ setState(static_cast<ExecutorState>(executor.state()));
+
+ if (futureInterface.resultCount() == 0)
+ futureInterface.reportResult(true);
+}
+
+BuildExecutor::ExecutorState BuildExecutor::state() const
+{
+ QReadLocker locker(&m_lock);
+ return m_state;
+}
+
+void BuildExecutor::setState(const BuildExecutor::ExecutorState &state)
+{
+ QWriteLocker locker(&m_lock);
+ m_state = state;
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/buildexecutor.h b/src/lib/Qbs/buildexecutor.h
new file mode 100644
index 000000000..67047e1ff
--- /dev/null
+++ b/src/lib/Qbs/buildexecutor.h
@@ -0,0 +1,94 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_BUILDEXECUTOR_H
+#define QBS_BUILDEXECUTOR_H
+
+#include "buildproduct.h"
+
+#include <QtCore/QFutureInterface>
+#include <QtCore/QReadWriteLock>
+
+namespace qbs {
+ class Executor;
+ class BuildProject;
+}
+
+namespace Qbs {
+
+class BuildExecutor
+{
+public:
+ BuildExecutor();
+
+ enum ExecutorState {
+ ExecutorIdle,
+ ExecutorRunning,
+ ExecutorError
+ };
+
+ void setMaximumJobs(int numberOfJobs);
+ int maximumJobs() const;
+
+ void setRunOnceAndForgetModeEnabled(bool enable);
+ bool runOnceAndForgetModeIsEnabled() const;
+ void setDryRunEnabled(bool enable);
+ bool isDryRunEnabled() const;
+ void setKeepGoingEnabled(bool enable);
+ bool isKeepGoingEnabled() const;
+
+ void executeBuildProject(QFutureInterface<bool> &futureInterface, const BuildProject &buildProject);
+ void executeBuildProjects(QFutureInterface<bool> &futureInterface, const QList<QSharedPointer<qbs::BuildProject> > internalBuildProjects, QStringList changedFiles, QStringList selectedProductNames);
+
+ ExecutorState state() const;
+
+private: //functions
+ void setState(const ExecutorState &state);
+
+private: // variables
+ mutable QReadWriteLock m_lock;
+ int m_maximumJobs;
+ bool m_runOnceAndForgetModeEnabled;
+ bool m_dryRun;
+ bool m_keepGoing;
+ ExecutorState m_state;
+};
+
+} // namespace Qbs
+
+#endif // QBS_BUILDEXECUTOR_H
diff --git a/src/lib/Qbs/buildproduct.cpp b/src/lib/Qbs/buildproduct.cpp
new file mode 100644
index 000000000..82733beb5
--- /dev/null
+++ b/src/lib/Qbs/buildproduct.cpp
@@ -0,0 +1,121 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#include "buildproduct.h"
+
+#include <buildgraph/buildgraph.h>
+#include <tools/scripttools.h>
+
+namespace Qbs {
+
+BuildProduct::BuildProduct()
+{
+}
+
+BuildProduct::~BuildProduct()
+{
+}
+
+BuildProduct::BuildProduct(const BuildProduct &other)
+ : m_internalBuildProduct(other.m_internalBuildProduct)
+{
+}
+
+BuildProduct &BuildProduct::operator =(const BuildProduct &other)
+{
+ m_internalBuildProduct = other.m_internalBuildProduct;
+
+ return *this;
+}
+
+QVector<SourceFile> BuildProduct::sourceFiles() const
+{
+ QVector<SourceFile> artifactList;
+ artifactList.reserve(m_internalBuildProduct->rProduct->sources.size());
+
+ if (m_internalBuildProduct) {
+ foreach (const qbs::SourceArtifact::Ptr &artifact, m_internalBuildProduct->rProduct->sources)
+ artifactList.append(SourceFile(artifact->absoluteFilePath, artifact->fileTags));
+ }
+
+ return artifactList;
+}
+
+static QStringList findProjectIncludePathsRecursive(const QVariantMap &variantMap)
+{
+ QStringList includePathList;
+ QMapIterator<QString, QVariant> mapIternator(variantMap);
+
+ while (mapIternator.hasNext()) {
+ mapIternator.next();
+ if (mapIternator.key() == QLatin1String("includePaths")) {
+ includePathList.append(mapIternator.value().toStringList());
+ } else if (mapIternator.value().userType() == QVariant::Map) {
+ includePathList.append(findProjectIncludePathsRecursive(mapIternator.value().toMap()));
+ }
+ }
+
+ return includePathList;
+}
+
+QStringList BuildProduct::projectIncludePaths() const
+{
+ return findProjectIncludePathsRecursive(m_internalBuildProduct->rProduct->configuration->value());
+}
+
+BuildProduct::BuildProduct(const QSharedPointer<qbs::BuildProduct> &internalBuildProduct)
+ : m_internalBuildProduct(internalBuildProduct)
+{
+}
+
+QString BuildProduct::displayName() const
+{
+ return m_internalBuildProduct->rProduct->name;
+}
+
+QString BuildProduct::filePath() const
+{
+ return m_internalBuildProduct->rProduct->qbsFile;
+}
+
+SourceFile::SourceFile(const QString &fileNameArg, const QSet<QString> &tagsArg)
+ : fileName(fileNameArg), tags(tagsArg)
+{
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/buildproduct.h b/src/lib/Qbs/buildproduct.h
new file mode 100644
index 000000000..08b111548
--- /dev/null
+++ b/src/lib/Qbs/buildproduct.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_QBSBUILDPRODUCT_H
+#define QBS_QBSBUILDPRODUCT_H
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+
+namespace qbs {
+ class BuildProduct;
+}
+
+namespace Qbs {
+
+class BuildProject;
+
+class SourceFile
+{
+public:
+ SourceFile(const QString &fileName = QString(), const QSet<QString> &tags = QSet<QString>());
+ QString fileName;
+ QSet<QString> tags;
+};
+
+
+class BuildProduct
+{
+ friend class BuildProject;
+public:
+ BuildProduct();
+ ~BuildProduct();
+ BuildProduct(const BuildProduct &other);
+ BuildProduct &operator =(const BuildProduct &other);
+
+ QString displayName() const;
+ QString filePath() const;
+ QVector<SourceFile> sourceFiles() const;
+ QStringList projectIncludePaths() const;
+
+private: // functions
+ BuildProduct(const QSharedPointer<qbs::BuildProduct> &internalBuildProduct);
+
+private: // variables
+ QSharedPointer<qbs::BuildProduct> m_internalBuildProduct;
+};
+
+} // namespace Qbs
+
+#endif // QBS_QBSBUILDPRODUCT_H
diff --git a/src/lib/Qbs/buildproject.cpp b/src/lib/Qbs/buildproject.cpp
new file mode 100644
index 000000000..abbd693d2
--- /dev/null
+++ b/src/lib/Qbs/buildproject.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#include "buildproject.h"
+
+#include <QSharedData>
+
+#include <buildgraph/buildgraph.h>
+#include <tools/scripttools.h>
+
+namespace Qbs {
+
+
+
+BuildProject::BuildProject()
+{
+}
+
+BuildProject::~BuildProject()
+{
+}
+
+BuildProject::BuildProject(const BuildProject &other)
+ : m_internalBuildProject(other.m_internalBuildProject)
+{
+}
+
+BuildProject &BuildProject::operator =(const BuildProject &other)
+{
+ m_internalBuildProject = other.m_internalBuildProject;
+
+ return *this;
+}
+
+QVector<BuildProduct> BuildProject::buildProducts() const
+{
+ QVector<BuildProduct> buildProductList;
+ buildProductList.reserve(m_internalBuildProject->buildProducts().size());
+
+ foreach (const qbs::BuildProduct::Ptr &internalBuildProduct, m_internalBuildProject->buildProducts())
+ buildProductList.append(BuildProduct(internalBuildProduct));
+
+ return buildProductList;
+}
+
+QString BuildProject::buildDirectory() const
+{
+ return QString(m_internalBuildProject->buildGraph()->buildDirectoryRoot()
+ + m_internalBuildProject->resolvedProject()->id
+ + QLatin1String("/"));
+}
+
+QString BuildProject::displayName() const
+{
+ return m_internalBuildProject->resolvedProject()->id;
+}
+
+void BuildProject::storeBuildGraph()
+{
+ m_internalBuildProject->store();
+}
+
+bool BuildProject::isValid() const
+{
+ return m_internalBuildProject.data();
+}
+
+QString BuildProject::qtSourcePath() const
+{
+ return qbs::getConfigProperty(m_internalBuildProject->resolvedProject()->configuration->value(),
+ QStringList() << "qt/core" << "qtPath").toString();
+}
+
+BuildProject::BuildProject(const QSharedPointer<qbs::BuildProject> &internalBuildProject)
+ : m_internalBuildProject(internalBuildProject)
+{
+}
+
+qbs::BuildProject::Ptr BuildProject::internalBuildProject() const
+{
+ return m_internalBuildProject;
+}
+
+bool BuildProject::removeBuildDirectory()
+{
+ bool filesRemoved = false;
+
+#if defined(Q_OS_LINUX)
+ QStringList arguments;
+ arguments.append("-rf");
+ arguments.append(buildDirectory());
+ filesRemoved = !QProcess::execute("/bin/rm", arguments);
+#elif defined(Q_OS_WIN)
+ QString command = QString("rd /s /q \"%1\"").arg(QDir::toNativeSeparators(buildDirectory()));
+ QStringList arguments;
+ arguments.append("/c");
+ arguments.append(command);
+ filesRemoved = !QProcess::execute("cmd", arguments);
+#endif
+
+ return filesRemoved;
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/buildproject.h b/src/lib/Qbs/buildproject.h
new file mode 100644
index 000000000..3521226b9
--- /dev/null
+++ b/src/lib/Qbs/buildproject.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_QBSBUILDPROJECT_H
+#define QBS_QBSBUILDPROJECT_H
+
+#include "buildproduct.h"
+
+#include <QtCore/QSharedPointer>
+
+namespace qbs {
+ class BuildProject;
+}
+
+namespace Qbs {
+
+class SourceProject;
+
+class BuildProject
+{
+ friend class SourceProject;
+public:
+ BuildProject();
+ ~BuildProject();
+ BuildProject(const BuildProject &other);
+ BuildProject &operator =(const BuildProject &other);
+
+ QVector<BuildProduct> buildProducts() const;
+
+ QString buildDirectory() const;
+ QString displayName() const;
+
+ void storeBuildGraph();
+
+ bool isValid() const;
+
+ QString qtSourcePath() const;
+
+ QSharedPointer<qbs::BuildProject> internalBuildProject() const;
+
+ bool removeBuildDirectory();
+
+
+private: // functions
+ BuildProject(const QSharedPointer<qbs::BuildProject> &internalBuildProject);
+
+private: // variables
+ QSharedPointer<qbs::BuildProject> m_internalBuildProject;
+};
+
+} // namespace Qbs
+
+#endif // QBS_QBSBUILDPROJECT_H
diff --git a/src/lib/Qbs/error.h b/src/lib/Qbs/error.h
new file mode 100644
index 000000000..6e4ff4d57
--- /dev/null
+++ b/src/lib/Qbs/error.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_ERROR_H
+#define QBS_ERROR_H
+
+#include <QtCore/QSharedPointer>
+
+namespace qbs {
+ class Error;
+}
+
+namespace Qbs {
+
+class SourceProject;
+
+class Error
+{
+ friend class SourceProject;
+public:
+ Error();
+ ~Error();
+
+ Error(const Error &other);
+ Error &operator=(const Error &other);
+
+ QString toString() const;
+
+private:
+ Error(const qbs::Error &error);
+
+
+private:
+ QSharedPointer<qbs::Error> m_error;
+};
+
+} // namespace Qbs
+
+#endif // QBS_ERROR_H
diff --git a/src/lib/Qbs/globals.h b/src/lib/Qbs/globals.h
new file mode 100644
index 000000000..e420ee211
--- /dev/null
+++ b/src/lib/Qbs/globals.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBSGLOBALS_H
+#define QBSGLOBALS_H
+
+
+namespace Qbs {
+
+enum LoggerLevel
+{
+ LoggerFatal = 0,
+ LoggerError,
+ LoggerWarning,
+ LoggerInfo,
+ LoggerDebug,
+ LoggerTrace,
+ LoggerMaxLevel = LoggerTrace
+};
+
+}
+
+
+namespace qbs {
+using namespace Qbs;
+}
+
+#endif // QBSGLOBALS_H
diff --git a/src/lib/Qbs/ilogsink.cpp b/src/lib/Qbs/ilogsink.cpp
new file mode 100644
index 000000000..573bb7d25
--- /dev/null
+++ b/src/lib/Qbs/ilogsink.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <tools/logger.h>
+
+namespace Qbs {
+
+void ILogSink::setGlobalLogSink(ILogSink *logSink)
+{
+ qbs::Logger::instance().setLogSink(logSink);
+}
+
+void ILogSink::cleanupGlobalLogSink()
+{
+ qbs::Logger::instance().setLogSink(0);
+}
+
+}
diff --git a/src/lib/Qbs/ilogsink.h b/src/lib/Qbs/ilogsink.h
new file mode 100644
index 000000000..85a11617c
--- /dev/null
+++ b/src/lib/Qbs/ilogsink.h
@@ -0,0 +1,90 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_ILOGSINK_H
+#define QBS_ILOGSINK_H
+
+#include "globals.h"
+#include "processoutput.h"
+#include <tools/coloredoutput.h>
+
+namespace qbs {
+class Logger;
+}
+
+namespace Qbs {
+
+enum LogOutputChannel
+{
+ LogOutputStdOut,
+ LogOutputStdErr
+};
+
+struct LogMessage
+{
+ LogMessage()
+ : printLogLevel(true)
+ , outputChannel(LogOutputStdErr)
+ , textColor(qbs::TextColorDefault)
+ , backgroundColor(qbs::TextColorDefault)
+ {}
+
+ QByteArray data;
+ bool printLogLevel;
+ LogOutputChannel outputChannel;
+ qbs::TextColor textColor;
+ qbs::TextColor backgroundColor;
+};
+
+class ILogSink
+{
+ friend class qbs::Logger;
+public:
+ virtual ~ILogSink() { }
+
+ static void setGlobalLogSink(ILogSink *logSink);
+ static void cleanupGlobalLogSink();
+
+protected:
+ virtual void outputLogMessage(LoggerLevel /*level*/, const LogMessage &/*logMessage*/) {}
+ virtual void processOutput(const Qbs::ProcessOutput &/*processOutput*/) {}
+};
+
+} // namespace Qbs
+
+#endif // QBS_ILOGSINK_H
diff --git a/src/lib/Qbs/logmessageevent.cpp b/src/lib/Qbs/logmessageevent.cpp
new file mode 100644
index 000000000..1ba591203
--- /dev/null
+++ b/src/lib/Qbs/logmessageevent.cpp
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "logmessageevent.h"
+
+namespace Qbs {
+
+int LogMessageEvent::s_eventType = QEvent::registerEventType();
+
+
+LogMessageEvent::LogMessageEvent(LoggerLevel level, const QString &message)
+ : QEvent(static_cast<QEvent::Type>(s_eventType)),
+ m_level(level),
+ m_message(message)
+{
+}
+
+LogMessageEvent *LogMessageEvent::toLogMessageEvent(QEvent *event)
+{
+ Q_ASSERT(isLogMessageEvent(event));
+ return static_cast<LogMessageEvent*>(event);
+}
+
+LoggerLevel LogMessageEvent::level() const
+{
+ return m_level;
+}
+
+QString LogMessageEvent::message() const
+{
+ return m_message;
+}
+
+bool LogMessageEvent::isLogMessageEvent(QEvent *event)
+{
+ return static_cast<QEvent::Type>(s_eventType) == event->type();
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/logmessageevent.h b/src/lib/Qbs/logmessageevent.h
new file mode 100644
index 000000000..cb979baef
--- /dev/null
+++ b/src/lib/Qbs/logmessageevent.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef QBS_QBSLOGMESSAGEEVENT_H
+#define QBS_QBSLOGMESSAGEEVENT_H
+
+#include "globals.h"
+
+#include <QtCore/QEvent>
+#include <QtCore/QString>
+
+namespace Qbs {
+
+class LogMessageEvent : public QEvent
+{
+public:
+ LogMessageEvent(LoggerLevel level, const QString &message);
+
+ static LogMessageEvent *toLogMessageEvent(QEvent *event);
+ static bool isLogMessageEvent(QEvent *event);
+
+ LoggerLevel level() const;
+ QString message() const;
+
+
+private:
+ static int s_eventType;
+ LoggerLevel m_level;
+ QString m_message;
+};
+
+} // namespace Qbs
+
+#endif // QBS_QBSLOGMESSAGEEVENT_H
diff --git a/src/lib/Qbs/mainthreadcommunication.cpp b/src/lib/Qbs/mainthreadcommunication.cpp
new file mode 100644
index 000000000..b8c705868
--- /dev/null
+++ b/src/lib/Qbs/mainthreadcommunication.cpp
@@ -0,0 +1,123 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "mainthreadcommunication.h"
+
+#include <tools/logger.h>
+
+#include "logmessageevent.h"
+#include "processoutputevent.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QReadLocker>
+#include <QtCore/QWriteLocker>
+
+namespace Qbs {
+
+typedef QWeakPointer<QObject> ObjectPointer;
+
+MainThreadCommunication::MainThreadCommunication()
+{
+ qbs::Logger::instance().setLevel(LoggerMaxLevel);
+ setGlobalLogSink(this);
+}
+
+MainThreadCommunication::~MainThreadCommunication()
+{
+ cleanupGlobalLogSink();
+}
+
+MainThreadCommunication &MainThreadCommunication::instance()
+{
+ static MainThreadCommunication instance;
+ return instance;
+}
+
+void MainThreadCommunication::addLogEventReceiver(QObject *object)
+{
+ QWriteLocker locker(&m_lock);
+ if (!m_logReceiverList.contains(ObjectPointer(object)))
+ m_logReceiverList.append(ObjectPointer(object));
+}
+
+void MainThreadCommunication::removeLogEventReceiver(QObject *object)
+{
+ QReadLocker locker(&m_lock);
+ m_logReceiverList.removeOne(ObjectPointer(object));
+}
+
+void MainThreadCommunication::addProcessOutputEventReceiver(QObject *object)
+{
+ QWriteLocker locker(&m_lock);
+ if (!m_processOutputReceiverList.contains(ObjectPointer(object)))
+ m_processOutputReceiverList.append(ObjectPointer(object));}
+
+void MainThreadCommunication::removeProcessOutputEventReceiver(QObject *object)
+{
+ QReadLocker locker(&m_lock);
+ m_processOutputReceiverList.append(ObjectPointer(object));
+}
+
+void MainThreadCommunication::registerMetaType()
+{
+ qRegisterMetaType<Qbs::ProcessOutput>("Qbs::ProcessOutput");
+ qRegisterMetaTypeStreamOperators<Qbs::ProcessOutput>("Qbs::ProcessOutput");
+ qRegisterMetaType<Qbs::LoggerLevel>("Qbs::LoggerLevel");
+}
+
+void MainThreadCommunication::outputLogMessage(LoggerLevel level, const LogMessage &message)
+{
+ QReadLocker locker(&m_lock);
+ foreach (const ObjectPointer &logReceiver, m_logReceiverList) {
+ if (logReceiver.data()) {
+ LogMessageEvent *logMessageEvent = new LogMessageEvent(level, QString::fromLocal8Bit(message.data));
+ QCoreApplication::postEvent(logReceiver.data(), logMessageEvent);
+ }
+ }
+}
+
+void MainThreadCommunication::processOutput(const Qbs::ProcessOutput &processOutput)
+{
+ QReadLocker locker(&m_lock);
+ foreach (const ObjectPointer &processOutputReceiver, m_processOutputReceiverList) {
+ if (processOutputReceiver.data()) {
+ ProcessOutputEvent *processOutputEvent = new ProcessOutputEvent(processOutput);
+ QCoreApplication::postEvent(processOutputReceiver.data(), processOutputEvent);
+ }
+ }
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/mainthreadcommunication.h b/src/lib/Qbs/mainthreadcommunication.h
new file mode 100644
index 000000000..1cbc6c81b
--- /dev/null
+++ b/src/lib/Qbs/mainthreadcommunication.h
@@ -0,0 +1,78 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef QBS_MAINTHREADCOMMUNICATION_H
+#define QBS_MAINTHREADCOMMUNICATION_H
+
+#include "globals.h"
+#include "processoutput.h"
+#include "ilogsink.h"
+
+#include <QtCore/QWeakPointer>
+#include <QtCore/QReadWriteLock>
+
+namespace Qbs {
+
+class MainThreadCommunication : public ILogSink
+{
+public:
+ MainThreadCommunication();
+ ~MainThreadCommunication();
+
+ static MainThreadCommunication &instance();
+
+ void addLogEventReceiver(QObject *object);
+ void removeLogEventReceiver(QObject *object);
+
+ void addProcessOutputEventReceiver(QObject *object);
+ void removeProcessOutputEventReceiver(QObject *object);
+
+ static void registerMetaType();
+
+public:
+ void outputLogMessage(LoggerLevel level, const LogMessage &message);
+ void processOutput(const Qbs::ProcessOutput &processOutput);
+
+private:
+ QReadWriteLock m_lock;
+ QList<QWeakPointer<QObject> > m_logReceiverList;
+ QList<QWeakPointer<QObject> > m_processOutputReceiverList;
+
+};
+
+} // namespace Qbs
+
+#endif // QBS_MAINTHREADCOMMUNICATION_H
diff --git a/src/lib/Qbs/oldsourceproject.cpp b/src/lib/Qbs/oldsourceproject.cpp
new file mode 100644
index 000000000..95ba074a4
--- /dev/null
+++ b/src/lib/Qbs/oldsourceproject.cpp
@@ -0,0 +1,193 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "oldsourceproject.h"
+
+#include <buildgraph/buildgraph.h>
+#include <buildgraph/executor.h>
+#include <language/loader.h>
+#include <tools/runenvironment.h>
+#include <tools/fileinfo.h>
+#include <tools/persistence.h>
+#include <tools/logger.h>
+#include <tools/scannerpluginmanager.h>
+#include <tools/scripttools.h>
+#include <tools/platform.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QSettings>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QElapsedTimer>
+
+namespace qbs {
+
+SourceProject::SourceProject(qbs::Settings::Ptr settings)
+ : m_settings(settings)
+{
+}
+
+void SourceProject::setSearchPaths(const QStringList &searchPaths)
+{
+ m_searchPaths = searchPaths;
+}
+
+void SourceProject::loadPlugins(const QStringList &pluginPaths)
+{
+ static bool alreadyCalled = false;
+ if (alreadyCalled) {
+ qbsWarning("qbs::SourceProject::loadPlugins was called more than once.");
+ }
+
+ alreadyCalled = true;
+
+ foreach (const QString &pluginPath, pluginPaths)
+ QCoreApplication::addLibraryPath(pluginPath);
+
+ qbs::ScannerPluginManager::instance()->loadPlugins(pluginPaths);
+}
+
+void SourceProject::loadProject(QFutureInterface<bool> &futureInterface, QString projectFileName, QList<QVariantMap> buildConfigs)
+{
+ QHash<QString, qbs::Platform::Ptr > platforms = Platform::platforms();
+ if (platforms.isEmpty()) {
+ qbsFatal("no platforms configured. maybe you want to run 'qbs platforms probe' first.");
+ futureInterface.reportResult(false);
+ return;
+ }
+ if (buildConfigs.isEmpty()) {
+ qbsFatal("SourceProject::loadProject: no build configuration given.");
+ futureInterface.reportResult(false);
+ return;
+ }
+ QList<qbs::Configuration::Ptr> configurations;
+ foreach (QVariantMap buildCfg, buildConfigs) {
+ if (!buildCfg.value("platform").isValid()) {
+ if (!m_settings->value("defaults/platform").isValid()) {
+ qbsFatal("SourceProject::loadProject: no platform given and no default set.");
+ continue;
+ }
+ buildCfg.insert("platform", m_settings->value("defaults/platform").toString());
+ }
+ Platform::Ptr platform = platforms.value(buildCfg.value("platform").toString());
+ if (platform.isNull()) {
+ qbsFatal("SourceProject::loadProject: unknown platform: %s", qPrintable(buildCfg.value("platform").toString()));
+ continue;
+ }
+ foreach (const QString &key, platform->settings.allKeys()) {
+ buildCfg.insert(QString(key).replace('/','.'),
+ platform->settings.value(key));
+ }
+
+ if (!buildCfg.value("buildVariant").isValid()) {
+ qbsFatal("SourceProject::loadProject: property 'buildVariant' missing in build configuration.");
+ continue;
+ }
+ qbs::Configuration::Ptr configure(new qbs::Configuration);
+ configurations.append(configure);
+
+ foreach (const QString &property, buildCfg.keys()) {
+ QStringList nameElements = property.split('.');
+ if (nameElements.count() == 1)
+ nameElements.prepend("qbs");
+ QVariantMap configValue = configure->value();
+ qbs::setConfigProperty(configValue, nameElements, buildCfg.value(property));
+ configure->setValue(configValue);
+ }
+ }
+
+ qbs::Loader loader;
+ loader.setSearchPaths(m_searchPaths);
+ m_buildGraph = QSharedPointer<qbs::BuildGraph>(new qbs::BuildGraph);
+ m_buildGraph->setOutputDirectoryRoot(QDir::currentPath());
+ const QString buildDirectoryRoot = m_buildGraph->buildDirectoryRoot();
+
+ try {
+ foreach (const qbs::Configuration::Ptr &configure, configurations) {
+ qbs::BuildProject::Ptr bProject;
+ const qbs::FileTime projectFileTimeStamp = qbs::FileInfo(projectFileName).lastModified();
+ bProject = qbs::BuildProject::load(m_buildGraph.data(), projectFileTimeStamp, configure, m_searchPaths);
+ if (!bProject) {
+ QElapsedTimer timer;
+ timer.start();
+ if (!loader.hasLoaded())
+ loader.loadProject(projectFileName);
+ qbs::ResolvedProject::Ptr rProject = loader.resolveProject(buildDirectoryRoot, configure, futureInterface);
+ if (rProject->products.isEmpty())
+ throw qbs::Error(QString("'%1' does not contain products.").arg(projectFileName));
+ qDebug() << "loading project took: " << timer.elapsed() << "ms";
+ timer.start();
+ bProject = m_buildGraph->resolveProject(rProject, futureInterface);
+ qDebug() << "build graph took: " << timer.elapsed() << "ms";
+ }
+
+ m_buildProjects.append(bProject);
+
+ printf("for %s:\n", qPrintable(bProject->resolvedProject()->id));
+ foreach (qbs::ResolvedProduct::Ptr p, bProject->resolvedProject()->products) {
+ printf(" - [%s] %s as %s\n"
+ ,qPrintable(p->fileTags.join(", "))
+ ,qPrintable(p->name)
+ ,qPrintable(p->project->id)
+ );
+ }
+ printf("\n");
+ }
+
+ } catch (qbs::Error &e) {
+ m_errors.append(e);
+ futureInterface.reportResult(false);
+ return;
+ }
+
+ futureInterface.reportResult(true);
+}
+
+QList<BuildProject::Ptr> SourceProject::buildProjects() const
+{
+ return m_buildProjects;
+}
+
+QList<Error> SourceProject::errors() const
+{
+ return m_errors;
+}
+
+} // namespace qbs
+
diff --git a/src/lib/Qbs/oldsourceproject.h b/src/lib/Qbs/oldsourceproject.h
new file mode 100644
index 000000000..98a30a8b2
--- /dev/null
+++ b/src/lib/Qbs/oldsourceproject.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QBSINTERFACE_H
+#define QBSINTERFACE_H
+
+#include <language/language.h>
+#include <buildgraph/buildgraph.h>
+
+#include <QtCore/QFutureInterface>
+
+namespace qbs {
+
+class SourceProject
+{
+public:
+ SourceProject(qbs::Settings::Ptr settings);
+
+ void setSearchPaths(const QStringList &searchPaths);
+ void loadPlugins(const QStringList &pluginPaths);
+ void loadProject(QFutureInterface<bool> &futureInterface, QString projectFileName, QList<QVariantMap> buildConfigs);
+
+ QList<qbs::BuildProject::Ptr> buildProjects() const;
+
+ QList<qbs::Error> errors() const;
+
+private:
+ QStringList m_searchPaths;
+ QList<qbs::Configuration::Ptr> m_configurations;
+
+ QSharedPointer<qbs::BuildGraph> m_buildGraph;
+ QList<qbs::BuildProject::Ptr> m_buildProjects;
+
+ qbs::Settings::Ptr m_settings;
+ QList<qbs::Error> m_errors;
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/Qbs/processoutput.cpp b/src/lib/Qbs/processoutput.cpp
new file mode 100644
index 000000000..f633576f4
--- /dev/null
+++ b/src/lib/Qbs/processoutput.cpp
@@ -0,0 +1,124 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#include "processoutput.h"
+#include <QSharedData>
+
+#include <QtDebug>
+
+namespace Qbs {
+
+class ProcessOutputData : public QSharedData
+{
+public:
+ QByteArray standardOutput;
+ QByteArray standardError;
+ QString commandLine;
+};
+
+ProcessOutput::ProcessOutput()
+ : data(new ProcessOutputData)
+{
+}
+
+ProcessOutput::ProcessOutput(const ProcessOutput &other)
+ : data(other.data)
+{
+}
+
+ProcessOutput &ProcessOutput::operator=(const ProcessOutput &other)
+{
+ if (this != &other)
+ data = other.data;
+
+ return *this;
+}
+
+ProcessOutput::~ProcessOutput()
+{
+}
+
+void ProcessOutput::setStandardOutput(const QByteArray &standardOutput)
+{
+ data->standardOutput = standardOutput;
+}
+
+QByteArray ProcessOutput::standardOutput() const
+{
+ return data->standardOutput;
+}
+
+void ProcessOutput::setStandardError(const QByteArray &standardError)
+{
+ data->standardError = standardError;
+}
+
+QByteArray ProcessOutput::standardError() const
+{
+ return data->standardError;
+}
+
+void ProcessOutput::setCommandLine(const QString &commandLine)
+{
+ data->commandLine = commandLine;
+}
+
+QString ProcessOutput::commandLine() const
+{
+ return data->commandLine;
+}
+
+QDataStream &operator<<(QDataStream &out, const ProcessOutput &processOutput)
+{
+ out << processOutput.commandLine();
+ out << processOutput.standardOutput();
+ out << processOutput.standardError();
+
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, ProcessOutput &processOutput)
+{
+ in >> processOutput.data->commandLine;
+ in >> processOutput.data->standardOutput;
+ in >> processOutput.data->standardError;
+
+ return in;
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/processoutput.h b/src/lib/Qbs/processoutput.h
new file mode 100644
index 000000000..ca9f8bd16
--- /dev/null
+++ b/src/lib/Qbs/processoutput.h
@@ -0,0 +1,80 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#ifndef QBS_PROCESSOUTPUT_H
+#define QBS_PROCESSOUTPUT_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QString>
+#include <QtCore/QMetaType>
+
+namespace Qbs {
+
+class ProcessOutputData;
+
+class ProcessOutput
+{
+ friend QDataStream &operator>>(QDataStream &in, ProcessOutput &processOutput);
+public:
+ ProcessOutput();
+ ProcessOutput(const ProcessOutput &other);
+ ProcessOutput &operator=(const ProcessOutput &other);
+ ~ProcessOutput();
+
+ void setStandardOutput(const QByteArray &standardOutput);
+ QByteArray standardOutput() const;
+
+ void setStandardError(const QByteArray &standardError);
+ QByteArray standardError() const;
+
+ void setCommandLine(const QString &commandLine);
+ QString commandLine() const;
+
+private:
+ QSharedDataPointer<ProcessOutputData> data;
+};
+
+QDataStream &operator<<(QDataStream &out, const ProcessOutput &processOutput);
+QDataStream &operator>>(QDataStream &in, ProcessOutput &processOutput);
+
+} // namespace Qbs
+
+Q_DECLARE_METATYPE(Qbs::ProcessOutput)
+
+#endif // QBS_PROCESSOUTPUT_H
diff --git a/src/lib/Qbs/processoutputevent.cpp b/src/lib/Qbs/processoutputevent.cpp
new file mode 100644
index 000000000..e3576f619
--- /dev/null
+++ b/src/lib/Qbs/processoutputevent.cpp
@@ -0,0 +1,65 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "processoutputevent.h"
+
+namespace Qbs {
+
+int ProcessOutputEvent::s_eventType = QEvent::registerEventType();
+
+ProcessOutputEvent::ProcessOutputEvent(const ProcessOutput &processOutput)
+ : QEvent(static_cast<QEvent::Type>(s_eventType)),
+ m_processOutput(processOutput)
+{
+}
+
+ProcessOutputEvent *ProcessOutputEvent::toProcessOutputEvent(QEvent *event)
+{
+ Q_ASSERT(isProcessOutputEvent(event));
+ return static_cast<ProcessOutputEvent*>(event);
+}
+
+ProcessOutput ProcessOutputEvent::processOutput() const
+{
+ return m_processOutput;
+}
+
+bool ProcessOutputEvent::isProcessOutputEvent(QEvent *event)
+{
+ return static_cast<QEvent::Type>(s_eventType) == event->type();
+}
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/processoutputevent.h b/src/lib/Qbs/processoutputevent.h
new file mode 100644
index 000000000..74ebd24aa
--- /dev/null
+++ b/src/lib/Qbs/processoutputevent.h
@@ -0,0 +1,62 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef QBS_PROCESSOUTPUTEVENT_H
+#define QBS_PROCESSOUTPUTEVENT_H
+
+#include <QEvent>
+#include "processoutput.h"
+
+namespace Qbs {
+
+class ProcessOutputEvent : public QEvent
+{
+public:
+ ProcessOutputEvent(const ProcessOutput &processOutput);
+
+ static ProcessOutputEvent *toProcessOutputEvent(QEvent *event);
+ static bool isProcessOutputEvent(QEvent *event);
+
+ ProcessOutput processOutput() const;
+
+private:
+ static int s_eventType;
+ ProcessOutput m_processOutput;
+};
+
+} // namespace Qbs
+
+#endif // QBS_PROCESSOUTPUTEVENT_H
diff --git a/src/lib/Qbs/qbserror.cpp b/src/lib/Qbs/qbserror.cpp
new file mode 100644
index 000000000..2ccfe0884
--- /dev/null
+++ b/src/lib/Qbs/qbserror.cpp
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "error.h"
+
+#include <tools/error.h>
+
+namespace Qbs {
+
+Error::Error()
+{
+}
+
+Error::Error(const Error &other)
+ : m_error(other.m_error)
+{
+}
+
+Error &Error::operator =(const Error &other)
+{
+ m_error = other.m_error;
+
+ return *this;
+}
+
+QString Error::toString() const
+{
+ return m_error->toString();
+}
+
+Error::~Error()
+{
+}
+
+Error::Error(const qbs::Error &error)
+ : m_error(new qbs::Error(error))
+{
+
+}
+
+
+} // namespace Qbs
diff --git a/src/lib/Qbs/sourceproject.cpp b/src/lib/Qbs/sourceproject.cpp
new file mode 100644
index 000000000..bc61220b5
--- /dev/null
+++ b/src/lib/Qbs/sourceproject.cpp
@@ -0,0 +1,255 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "sourceproject.h"
+
+#include <language/loader.h>
+#include <tools/logger.h>
+#include <tools/scannerpluginmanager.h>
+#include <tools/scripttools.h>
+#include <tools/platform.h>
+
+#include <QtCore/QDebug>
+
+using namespace qbs;
+
+namespace Qbs {
+
+class SourceProjectPrivate : public QSharedData
+{
+public:
+ QStringList searchPaths;
+ QList<qbs::Configuration::Ptr> configurations;
+
+ QSharedPointer<qbs::BuildGraph> buildGraph;
+ QVector<Qbs::BuildProject> buildProjects;
+
+ qbs::Settings::Ptr settings;
+ QList<Error> errors;
+
+ QString buildDirectoryRoot;
+
+};
+
+SourceProject::SourceProject()
+ : d(new SourceProjectPrivate)
+{
+ d->settings = qbs::Settings::create(); // fix it
+}
+
+SourceProject::~SourceProject()
+{
+}
+
+SourceProject::SourceProject(const SourceProject &other)
+ : d(other.d)
+{
+}
+
+SourceProject &SourceProject::operator =(const SourceProject &other)
+{
+ d = other.d;
+
+ return *this;
+}
+
+void SourceProject::setSearchPaths(const QStringList &searchPaths)
+{
+ d->searchPaths = searchPaths;
+}
+
+void SourceProject::loadPlugins(const QStringList &pluginPaths)
+{
+ static bool alreadyCalled = false;
+ if (alreadyCalled) {
+ qbsWarning("qbs::SourceProject::loadPlugins was called more than once.");
+ }
+
+ alreadyCalled = true;
+
+ foreach (const QString &pluginPath, pluginPaths)
+ QCoreApplication::addLibraryPath(pluginPath);
+
+ qbs::ScannerPluginManager::instance()->loadPlugins(pluginPaths);
+}
+
+void SourceProject::loadProject(QFutureInterface<bool> &futureInterface,
+ const QString projectFileName,
+ const QList<QVariantMap> buildConfigs)
+{
+ QHash<QString, qbs::Platform::Ptr > platforms = Platform::platforms();
+ if (platforms.isEmpty()) {
+ qbsFatal("no platforms configured. maybe you want to run 'qbs platforms probe' first.");
+ futureInterface.reportResult(false);
+ return;
+ }
+ if (buildConfigs.isEmpty()) {
+ qbsFatal("SourceProject::loadProject: no build configuration given.");
+ futureInterface.reportResult(false);
+ return;
+ }
+ QList<qbs::Configuration::Ptr> configurations;
+ foreach (QVariantMap buildConfig, buildConfigs) {
+ if (!buildConfig.value("platform").isValid()) {
+ if (!d->settings->value("defaults/platform").isValid()) {
+ qbsFatal("SourceProject::loadProject: no platform given and no default set.");
+ continue;
+ }
+ buildConfig.insert("platform", d->settings->value("defaults/platform").toString());
+ }
+ Platform::Ptr platform = platforms.value(buildConfig.value("platform").toString());
+ if (platform.isNull()) {
+ qbsFatal("SourceProject::loadProject: unknown platform: %s", qPrintable(buildConfig.value("platform").toString()));
+ continue;
+ }
+ foreach (const QString &key, platform->settings.allKeys()) {
+ buildConfig.insert(QString(key).replace('/','.'),
+ platform->settings.value(key));
+ }
+
+ if (!buildConfig.value("buildVariant").isValid()) {
+ qbsFatal("SourceProject::loadProject: property 'buildVariant' missing in build configuration.");
+ continue;
+ }
+ qbs::Configuration::Ptr configuration(new qbs::Configuration);
+ configurations.append(configuration);
+
+ foreach (const QString &property, buildConfig.keys()) {
+ QStringList nameElements = property.split('.');
+ if (nameElements.count() == 1)
+ nameElements.prepend("qbs");
+ QVariantMap configValue = configuration->value();
+ qbs::setConfigProperty(configValue, nameElements, buildConfig.value(property));
+ configuration->setValue(configValue);
+ }
+ }
+
+ qbs::Loader loader;
+ loader.setSearchPaths(d->searchPaths);
+ d->buildGraph = QSharedPointer<qbs::BuildGraph>(new qbs::BuildGraph);
+ if (buildDirectoryRoot().isEmpty()) {
+ QByteArray buildDirectoryRootFromEnvironment = qgetenv("QBS_BUILD_ROOT_DIRECTORY");
+ if (buildDirectoryRootFromEnvironment.isEmpty()) {
+ d->buildGraph->setOutputDirectoryRoot(QDir::currentPath());
+ } else {
+ d->buildGraph->setOutputDirectoryRoot(buildDirectoryRootFromEnvironment);
+ }
+ } else {
+ d->buildGraph->setOutputDirectoryRoot(d->buildDirectoryRoot);
+ }
+
+ const QString buildDirectoryRoot = d->buildGraph->buildDirectoryRoot();
+
+
+ try {
+ int productCount = 0;
+ foreach (const qbs::Configuration::Ptr &configure, configurations) {
+ qbs::BuildProject::Ptr buildProject;
+ const qbs::FileTime projectFileTimeStamp = qbs::FileInfo(projectFileName).lastModified();
+ buildProject = qbs::BuildProject::load(d->buildGraph.data(), projectFileTimeStamp, configure, d->searchPaths);
+ if (!buildProject) {
+ if (!loader.hasLoaded())
+ loader.loadProject(projectFileName);
+ productCount += loader.productCount(configure);
+ }
+ }
+ futureInterface.setProgressRange(0, productCount * 2);
+
+
+ foreach (const qbs::Configuration::Ptr &configure, configurations) {
+ qbs::BuildProject::Ptr buildProject;
+ const qbs::FileTime projectFileTimeStamp = qbs::FileInfo(projectFileName).lastModified();
+ buildProject = qbs::BuildProject::load(d->buildGraph.data(), projectFileTimeStamp, configure, d->searchPaths);
+ if (!buildProject) {
+ if (!loader.hasLoaded())
+ loader.loadProject(projectFileName);
+ qbs::ResolvedProject::Ptr rProject = loader.resolveProject(buildDirectoryRoot, configure, futureInterface);
+ if (rProject->products.isEmpty())
+ throw qbs::Error(QString("'%1' does not contain products.").arg(projectFileName));
+ buildProject = d->buildGraph->resolveProject(rProject, futureInterface);
+ }
+
+ d->buildProjects.append(BuildProject(buildProject));
+
+ printf("for %s:\n", qPrintable(buildProject->resolvedProject()->id));
+ foreach (qbs::ResolvedProduct::Ptr p, buildProject->resolvedProject()->products) {
+ printf(" - [%s] %s as %s\n"
+ ,qPrintable(p->fileTags.join(", "))
+ ,qPrintable(p->name)
+ ,qPrintable(p->project->id)
+ );
+ }
+ printf("\n");
+ }
+
+ } catch (qbs::Error &error) {
+ d->errors.append(Error(error));
+ futureInterface.reportResult(false);
+ return;
+ }
+
+ futureInterface.reportResult(true);
+}
+
+void SourceProject::storeBuildProjectsBuildGraph()
+{
+ foreach (BuildProject buildProject, d->buildProjects)
+ buildProject.storeBuildGraph();
+}
+
+void SourceProject::setBuildDirectoryRoot(const QString &buildDirectoryRoot)
+{
+ d->buildDirectoryRoot = buildDirectoryRoot;
+}
+
+QString SourceProject::buildDirectoryRoot() const
+{
+ return d->buildDirectoryRoot;
+}
+
+QVector<BuildProject> SourceProject::buildProjects() const
+{
+ return d->buildProjects;
+}
+
+QList<Error> SourceProject::errors() const
+{
+ return d->errors;
+}
+
+}
+
diff --git a/src/lib/Qbs/sourceproject.h b/src/lib/Qbs/sourceproject.h
new file mode 100644
index 000000000..fef7ad187
--- /dev/null
+++ b/src/lib/Qbs/sourceproject.h
@@ -0,0 +1,95 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QBSINTERFACE_H
+#define QBSINTERFACE_H
+
+#include <language/language.h>
+#include <buildgraph/buildgraph.h>
+
+#include "buildproject.h"
+#include "error.h"
+
+#include <QFutureInterface>
+
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QSharedPointer>
+
+
+namespace qbs {
+ class BuildProject;
+}
+
+
+namespace Qbs {
+
+class SourceProjectPrivate;
+
+class SourceProject
+{
+ friend class BuildProject;
+public:
+ SourceProject();
+ ~SourceProject();
+
+ SourceProject(const SourceProject &other);
+ SourceProject &operator=(const SourceProject &other);
+
+
+ void setSearchPaths(const QStringList &searchPaths);
+ void loadPlugins(const QStringList &pluginPaths);
+ void loadProject(QFutureInterface<bool> &futureInterface,
+ const QString projectFileName,
+ const QList<QVariantMap> buildConfigs);
+ void storeBuildProjectsBuildGraph();
+
+ void setBuildDirectoryRoot(const QString &buildDirectoryRoot);
+ QString buildDirectoryRoot() const;
+
+ QVector<BuildProject> buildProjects() const;
+
+ QList<Qbs::Error> errors() const;
+
+private: // functions
+ QList<QSharedPointer<qbs::BuildProject> > toInternalBuildProjectList(const QVector<Qbs::BuildProject> &buildProjects) const;
+
+private:
+ QExplicitlySharedDataPointer<SourceProjectPrivate> d;
+};
+
+}
+#endif
diff --git a/src/lib/buildgraph/artifact.cpp b/src/lib/buildgraph/artifact.cpp
new file mode 100644
index 000000000..d7cf5e60d
--- /dev/null
+++ b/src/lib/buildgraph/artifact.cpp
@@ -0,0 +1,97 @@
+/*************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).*
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "artifact.h"
+#include "transformer.h"
+#include "buildgraph.h"
+
+QT_BEGIN_NAMESPACE
+
+static QDataStream &operator >>(QDataStream &s, qbs::Artifact::ArtifactType &t)
+{
+ int i;
+ s >> i;
+ t = static_cast<qbs::Artifact::ArtifactType>(i);
+ return s;
+}
+
+static QDataStream &operator <<(QDataStream &s, const qbs::Artifact::ArtifactType &t)
+{
+ return s << (int)t;
+}
+
+QT_END_NAMESPACE
+
+namespace qbs {
+
+Artifact::Artifact(BuildProject *p)
+ : project(p)
+ , product(0)
+ , transformer(0)
+ , artifactType(Unknown)
+ , buildState(Untouched)
+ , outOfDateCheckPerformed(false)
+ , isOutOfDate(false)
+ , isExistingFile(false)
+{
+}
+
+Artifact::~Artifact()
+{
+}
+
+void Artifact::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ fileName = pool.idLoadString(s);
+ fileTags = pool.idLoadStringSet(s);
+ configuration = pool.idLoadS<Configuration>(s);
+ transformer = pool.idLoadS<Transformer>(s);
+ s >> artifactType;
+ product = pool.idLoadS<BuildProduct>(s).data();
+}
+
+void Artifact::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << pool.storeString(fileName);
+ s << pool.storeStringSet(fileTags);
+ s << pool.store(configuration);
+ s << pool.store(transformer);
+ s << artifactType;
+ s << pool.store(product);
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/artifact.h b/src/lib/buildgraph/artifact.h
new file mode 100644
index 000000000..7663410fe
--- /dev/null
+++ b/src/lib/buildgraph/artifact.h
@@ -0,0 +1,112 @@
+/*************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).*
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef ARTIFACT_H
+#define ARTIFACT_H
+
+#include "artifactlist.h"
+#include <language/language.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QString>
+
+namespace qbs {
+
+class BuildProduct;
+class BuildProject;
+class Transformer;
+
+class Artifact : public PersistentObject
+{
+public:
+ Artifact(BuildProject *p = 0);
+ ~Artifact();
+
+ ArtifactList parents;
+ ArtifactList children;
+ ArtifactList fileDependencies;
+ ArtifactList sideBySideArtifacts; /// all artifacts that have been produced by the same rule
+ QString fileName;
+ QSet<QString> fileTags;
+ BuildProject *project;
+ BuildProduct *product; // Note: file dependency artifacts don't belong to a product.
+ QSharedPointer<Transformer> transformer;
+ Configuration::Ptr configuration;
+
+ enum ArtifactType
+ {
+ Unknown,
+ SourceFile,
+ Generated,
+ FileDependency
+ };
+ ArtifactType artifactType;
+
+ enum BuildState
+ {
+ Untouched = 0,
+ Buildable,
+ Building,
+ Built
+ };
+ BuildState buildState;
+
+ bool outOfDateCheckPerformed : 1;
+ bool isOutOfDate : 1;
+ bool isExistingFile : 1;
+
+private:
+ void load(PersistentPool &pool, PersistentObjectData &data);
+ void store(PersistentPool &pool, PersistentObjectData &data) const;
+};
+
+// debugging helper
+inline QString toString(Artifact::BuildState s)
+{
+ switch (s) {
+ case Artifact::Buildable:
+ return "Initialized";
+ case Artifact::Building:
+ return "Processing";
+ case Artifact::Built:
+ return "Finished";
+ default:
+ return "Unknown";
+ }
+}
+
+} // namespace qbs
+
+#endif // ARTIFACT_H
diff --git a/src/lib/buildgraph/artifactlist.cpp b/src/lib/buildgraph/artifactlist.cpp
new file mode 100644
index 000000000..f9e80b232
--- /dev/null
+++ b/src/lib/buildgraph/artifactlist.cpp
@@ -0,0 +1,57 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "artifactlist.h"
+#include <algorithm>
+
+namespace qbs {
+
+ArtifactList::ArtifactList()
+{}
+
+ArtifactList::ArtifactList(const ArtifactList &other)
+ : m_data(other.m_data)
+{}
+
+void ArtifactList::remove(Artifact *artifact)
+{
+ iterator it = m_data.find(artifact);
+ if (it != m_data.end())
+ m_data.erase(it);
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/artifactlist.h b/src/lib/buildgraph/artifactlist.h
new file mode 100644
index 000000000..018547740
--- /dev/null
+++ b/src/lib/buildgraph/artifactlist.h
@@ -0,0 +1,109 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef ARTIFACTLIST_H
+#define ARTIFACTLIST_H
+
+#include <set>
+
+namespace qbs {
+
+class Artifact;
+
+/**
+ * List that holds a bunch of build graph artifacts.
+ * This is faster than QSet when iterating over the container.
+ */
+class ArtifactList
+{
+public:
+ ArtifactList();
+ ArtifactList(const ArtifactList &other);
+
+ typedef std::set<Artifact *>::const_iterator const_iterator;
+ typedef std::set<Artifact *>::iterator iterator;
+ typedef Artifact * value_type;
+
+ iterator begin() { return m_data.begin(); }
+ iterator end() { return m_data.end(); }
+ const_iterator begin() const { return m_data.begin(); }
+ const_iterator end() const { return m_data.end(); }
+
+ void insert(Artifact *artifact)
+ {
+ m_data.insert(artifact);
+ }
+
+ void operator +=(Artifact *artifact)
+ {
+ insert(artifact);
+ }
+
+ void remove(Artifact *artifact);
+
+ bool contains(Artifact *artifact) const
+ {
+ return m_data.find(artifact) != m_data.end();
+ }
+
+ void clear()
+ {
+ m_data.clear();
+ }
+
+ bool isEmpty() const
+ {
+ return m_data.empty();
+ }
+
+ int count() const
+ {
+ return m_data.size();
+ }
+
+ void reserve(int)
+ {
+ // no-op
+ }
+
+private:
+ mutable std::set<Artifact *> m_data;
+};
+
+} // namespace qbs
+
+#endif // ARTIFACTLIST_H
diff --git a/src/lib/buildgraph/automoc.cpp b/src/lib/buildgraph/automoc.cpp
new file mode 100644
index 000000000..3a7f03ffa
--- /dev/null
+++ b/src/lib/buildgraph/automoc.cpp
@@ -0,0 +1,273 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "automoc.h"
+#include "scanresultcache.h"
+#include <buildgraph/artifact.h>
+#include <tools/error.h>
+#include <tools/logger.h>
+#include <tools/scannerpluginmanager.h>
+
+namespace qbs {
+
+AutoMoc::AutoMoc()
+ : m_scanResultCache(0)
+{
+}
+
+void AutoMoc::setScanResultCache(ScanResultCache *scanResultCache)
+{
+ m_scanResultCache = scanResultCache;
+}
+
+void AutoMoc::apply(BuildProduct::Ptr product)
+{
+ if (scanners().isEmpty())
+ throw Error("C++ scanner cannot be loaded.");
+
+ QList<QPair<Artifact *, FileType> > artifactsToMoc;
+ QSet<QString> includedMocCppFiles;
+ QHash<QString, Artifact *>::const_iterator it = product->artifacts.begin();
+ for (; it != product->artifacts.end(); ++it) {
+ Artifact *artifact = it.value();
+ FileType fileType = UnknownFileType;
+ if (artifact->fileTags.contains("hpp"))
+ fileType = HppFileType;
+ if (artifact->fileTags.contains("cpp"))
+ fileType = CppFileType;
+ if (fileType == UnknownFileType)
+ continue;
+ QString mocFileTag;
+ bool alreadyMocced = isVictimOfMoc(artifact, fileType, mocFileTag);
+ bool hasQObjectMacro;
+ apply(artifact, hasQObjectMacro, includedMocCppFiles);
+ if (hasQObjectMacro && !alreadyMocced) {
+ artifactsToMoc += qMakePair(artifact, fileType);
+ } else if (!hasQObjectMacro && alreadyMocced) {
+ unmoc(artifact, mocFileTag);
+ }
+ }
+
+ QMap<QString, QSet<Artifact *> > artifactsPerFileTag;
+ for (int i = artifactsToMoc.count(); --i >= 0;) {
+ const QPair<Artifact *, FileType> &p = artifactsToMoc.at(i);
+ Artifact * const artifact = p.first;
+ FileType fileType = p.second;
+ QString fileTag;
+ if (fileType == CppFileType) {
+ fileTag = "moc_cpp";
+ } else if (fileType == HppFileType) {
+ QString mocFileName = generateMocFileName(artifact, fileType);
+ if (includedMocCppFiles.contains(mocFileName))
+ fileTag = "moc_hpp_inc";
+ else
+ fileTag = "moc_hpp";
+ }
+ artifactsPerFileTag[fileTag].insert(artifact);
+ }
+
+ BuildGraph *buildGraph = product->project->buildGraph();
+ if (!artifactsPerFileTag.isEmpty()) {
+ qbsInfo() << DontPrintLogLevel << "Applying moc rules for '" << product->rProduct->name << "'.";
+ buildGraph->applyRules(product.data(), artifactsPerFileTag);
+ }
+ buildGraph->updateNodesThatMustGetNewTransformer();
+}
+
+QString AutoMoc::generateMocFileName(Artifact *artifact, FileType fileType)
+{
+ QString mocFileName;
+ switch (fileType) {
+ case UnknownFileType:
+ break;
+ case HppFileType:
+ mocFileName = "moc_" + FileInfo::baseName(artifact->fileName) + ".cpp";
+ break;
+ case CppFileType:
+ mocFileName = FileInfo::baseName(artifact->fileName) + ".moc";
+ break;
+ }
+ return mocFileName;
+}
+
+void AutoMoc::apply(Artifact *artifact, bool &hasQObjectMacro, QSet<QString> &includedMocCppFiles)
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] checks " << fileName(artifact);
+
+ hasQObjectMacro = false;
+ const int numFileTags = artifact->fileTags.count();
+ char **cFileTags = createCFileTags(artifact->fileTags);
+
+ foreach (ScannerPlugin *scanner, scanners()) {
+ void *opaq = scanner->open(artifact->fileName.utf16(), cFileTags, numFileTags);
+ if (!opaq || !scanner->additionalFileTags)
+ continue;
+
+ // HACK: misuse the file dependency scanner as provider for file tags
+ int length = 0;
+ const char **szFileTagsFromScanner = scanner->additionalFileTags(opaq, &length);
+ if (szFileTagsFromScanner && length > 0) {
+ for (int i=length; --i >= 0;) {
+ const QString fileTagFromScanner = QString::fromLocal8Bit(szFileTagsFromScanner[i]);
+ artifact->fileTags.insert(fileTagFromScanner);
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] finds Q_OBJECT macro";
+ if (fileTagFromScanner.startsWith("moc"))
+ hasQObjectMacro = true;
+ }
+ }
+
+ scanner->close(opaq);
+
+ ScanResultCache::Result scanResult;
+ if (m_scanResultCache)
+ scanResult = m_scanResultCache->value(artifact->fileName);
+ if (!scanResult.visited) {
+ scanResult.visited = true;
+ opaq = scanner->open(artifact->fileName.utf16(), 0, 0);
+ if (!opaq)
+ continue;
+
+ forever {
+ int flags = 0;
+ const char *szOutFilePath = scanner->next(opaq, &length, &flags);
+ if (szOutFilePath == 0)
+ break;
+ QString includedFilePath = QString::fromLocal8Bit(szOutFilePath, length);
+ if (includedFilePath.isEmpty())
+ continue;
+ bool isLocalInclude = (flags & SC_LOCAL_INCLUDE_FLAG);
+ scanResult.deps.insert(includedFilePath, isLocalInclude);
+ }
+
+ scanner->close(opaq);
+ if (m_scanResultCache)
+ m_scanResultCache->insert(artifact->fileName, scanResult);
+ }
+
+ for (QHash<QString, bool>::const_iterator it = scanResult.deps.constBegin(); it != scanResult.deps.constEnd(); ++it) {
+ const QString &includedFilePath = it.key();
+ if (includedFilePath.startsWith("moc_") && includedFilePath.endsWith(".cpp")) {
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] finds included file: " << includedFilePath;
+ includedMocCppFiles += includedFilePath;
+ }
+ }
+ }
+
+ freeCFileTags(cFileTags, numFileTags);
+}
+
+bool AutoMoc::isVictimOfMoc(Artifact *artifact, FileType fileType, QString &foundMocFileTag)
+{
+ foundMocFileTag.clear();
+ switch (fileType) {
+ case UnknownFileType:
+ break;
+ case HppFileType:
+ if (artifact->fileTags.contains("moc_hpp"))
+ foundMocFileTag = "moc_hpp";
+ else if (artifact->fileTags.contains("moc_hpp_inc"))
+ foundMocFileTag = "moc_hpp_inc";
+ break;
+ case CppFileType:
+ if (artifact->fileTags.contains("moc_cpp"))
+ foundMocFileTag = "moc_cpp";
+ break;
+ }
+ return !foundMocFileTag.isEmpty();
+}
+
+void AutoMoc::unmoc(Artifact *artifact, const QString &mocFileTag)
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] unmoc'ing " << fileName(artifact);
+
+ artifact->fileTags.remove(mocFileTag);
+
+ Artifact *generatedMocArtifact = 0;
+ foreach (Artifact *parent, artifact->parents) {
+ foreach (const QString &fileTag, parent->fileTags) {
+ if (fileTag == "hpp" || fileTag == "cpp") {
+ generatedMocArtifact = parent;
+ break;
+ }
+ }
+ }
+
+ if (!generatedMocArtifact) {
+ qbsTrace() << "[AUTOMOC] generated moc artifact could not be found";
+ return;
+ }
+
+ BuildGraph *buildGraph = artifact->project->buildGraph();
+ if (mocFileTag == "moc_hpp") {
+ Artifact *mocObjArtifact = 0;
+ foreach (Artifact *parent, generatedMocArtifact->parents) {
+ foreach (const QString &fileTag, parent->fileTags) {
+ if (fileTag == "obj" || fileTag == "fpicobj") {
+ mocObjArtifact = parent;
+ break;
+ }
+ }
+ }
+
+ if (!mocObjArtifact) {
+ qbsTrace() << "[AUTOMOC] generated moc obj artifact could not be found";
+ } else {
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] removing moc obj artifact " << fileName(mocObjArtifact);
+ buildGraph->remove(mocObjArtifact);
+ }
+ }
+
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[AUTOMOC] removing generated artifact " << fileName(generatedMocArtifact);
+ buildGraph->remove(generatedMocArtifact);
+ delete generatedMocArtifact;
+}
+
+QList<ScannerPlugin *> AutoMoc::scanners() const
+{
+ if (m_scanners.isEmpty())
+ m_scanners = ScannerPluginManager::scannersForFileTag("hpp");
+
+ return m_scanners;
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/automoc.h b/src/lib/buildgraph/automoc.h
new file mode 100644
index 000000000..ac0025dcc
--- /dev/null
+++ b/src/lib/buildgraph/automoc.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef AUTOMOC_H
+#define AUTOMOC_H
+
+#include "buildgraph.h"
+
+struct ScannerPlugin;
+
+namespace qbs {
+
+class ScanResultCache;
+
+/**
+ * Scans cpp and hpp files for the Q_OBJECT / Q_GADGET macro and
+ * applies the corresponding rule then.
+ * Also scans the files for moc_XXX.cpp files to find out if we must
+ * compile and link a moc_XXX.cpp file or not.
+ *
+ * This whole thing is an ugly hack, I know.
+ */
+class AutoMoc
+{
+public:
+ AutoMoc();
+
+ void setScanResultCache(ScanResultCache *scanResultCache);
+ void apply(BuildProduct::Ptr product);
+
+private:
+ enum FileType
+ {
+ UnknownFileType,
+ HppFileType,
+ CppFileType
+ };
+
+private:
+ static QString generateMocFileName(Artifact *artifact, FileType fileType);
+ void apply(Artifact *artifact, bool &hasQObjectMacro, QSet<QString> &includedMocCppFiles);
+ bool isVictimOfMoc(Artifact *artifact, FileType fileType, QString &foundMocFileTag);
+ void unmoc(Artifact *artifact, const QString &mocFileTag);
+ QList<ScannerPlugin *> scanners() const;
+private:
+ mutable QList<ScannerPlugin *> m_scanners;
+ ScanResultCache *m_scanResultCache;
+};
+
+} // namespace qbs
+
+#endif // AUTOMOC_H
diff --git a/src/lib/buildgraph/buildgraph.cpp b/src/lib/buildgraph/buildgraph.cpp
new file mode 100644
index 000000000..b9225881d
--- /dev/null
+++ b/src/lib/buildgraph/buildgraph.cpp
@@ -0,0 +1,1384 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "buildgraph.h"
+#include "artifact.h"
+#include "command.h"
+#include "rulegraph.h"
+#include "transformer.h"
+
+#include <language/loader.h>
+#include <tools/fileinfo.h>
+#include <tools/persistence.h>
+#include <tools/scannerpluginmanager.h>
+#include <tools/logger.h>
+#include <tools/scripttools.h>
+
+#include <QFileInfo>
+#include <QDebug>
+#include <QDir>
+#include <QtCore/QDirIterator>
+#include <QDataStream>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QMutex>
+#include <QtScript/QScriptProgram>
+#include <QtScript/QScriptValueIterator>
+
+namespace qbs {
+
+BuildProduct::BuildProduct()
+ : project(0)
+{
+}
+
+BuildProduct::~BuildProduct()
+{
+ qDeleteAll(artifacts);
+}
+
+const QList<Rule::Ptr> &BuildProduct::topSortedRules() const
+{
+ if (m_topSortedRules.isEmpty()) {
+ RuleGraph ruleGraph;
+ ruleGraph.build(rProduct->rules, rProduct->fileTags);
+// ruleGraph.dump();
+ m_topSortedRules = ruleGraph.topSorted();
+// int i=0;
+// foreach (Rule::Ptr r, m_topSortedRules)
+// qDebug() << ++i << r->toString() << (void*)r.data();
+ }
+ return m_topSortedRules;
+}
+
+BuildGraph::BuildGraph()
+{
+ ProcessCommand::setupForJavaScript(&m_scriptEngine);
+ JavaScriptCommand::setupForJavaScript(&m_scriptEngine);
+}
+
+BuildGraph::~BuildGraph()
+{
+}
+
+static void internalDump(BuildProduct *product, Artifact *n, QByteArray indent)
+{
+ Artifact *artifactInProduct = product->artifacts.value(n->fileName);
+ if (artifactInProduct && artifactInProduct != n) {
+ fprintf(stderr,"\ntree corrupted. %p ('%s') resolves to %p ('%s')\n",
+ n, qPrintable(n->fileName), product->artifacts.value(n->fileName),
+ qPrintable(product->artifacts.value(n->fileName)->fileName));
+
+ abort();
+ }
+ printf("%s", indent.constData());
+ printf("Artifact (%p) ", n);
+ printf("%s%s %s [%s]",
+ qPrintable(QString(toString(n->buildState).at(0))),
+ artifactInProduct ? "" : " SBS", // SBS == side-by-side artifact from other product
+ qPrintable(n->fileName),
+ qPrintable(QStringList(n->fileTags.toList()).join(",")));
+ printf("\n");
+ indent.append(" ");
+ foreach (Artifact *child, n->children) {
+ internalDump(product, child, indent);
+ }
+}
+
+void BuildGraph::dump(BuildProduct::Ptr product) const
+{
+ Q_ASSERT(product->artifacts.uniqueKeys() == product->artifacts.keys());
+
+ foreach (Artifact *n, product->artifacts)
+ if (n->parents.isEmpty())
+ internalDump(product.data(), n, QByteArray());
+}
+
+void BuildGraph::insert(BuildProduct::Ptr product, Artifact *n) const
+{
+ insert(product.data(), n);
+}
+
+void BuildGraph::insert(BuildProduct *product, Artifact *n) const
+{
+ Q_ASSERT(n->product == 0);
+ Q_ASSERT(!n->fileName.isEmpty());
+ Q_ASSERT(!product->artifacts.contains(n->fileName));
+#ifdef QT_DEBUG
+ foreach (BuildProduct::Ptr otherProduct, product->project->buildProducts()) {
+ if (otherProduct->artifacts.contains(n->fileName)) {
+ if (n->artifactType == Artifact::Generated) {
+ QString pl;
+ pl.append(QString(" - %1 \n").arg(product->rProduct->name));
+ foreach (BuildProduct::Ptr p, product->project->buildProducts()) {
+ if (p->artifacts.contains(n->fileName)) {
+ pl.append(QString(" - %1 \n").arg(p->rProduct->name));
+ }
+ }
+ throw Error(QString ("BUG: already inserted in this project: %1\n%2"
+ )
+ .arg(n->fileName)
+ .arg(pl)
+ );
+ }
+ }
+ }
+#endif
+ product->artifacts.insert(n->fileName, n);
+ n->product = product;
+ product->project->markDirty();
+
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace("[BG] insert artifact '%s'", qPrintable(n->fileName));
+}
+
+void BuildGraph::setupScriptEngineForProduct(QScriptEngine *scriptEngine, ResolvedProduct::Ptr product, Rule::Ptr rule, BuildGraph *bg)
+{
+ ResolvedProduct *lastSetupProduct = (ResolvedProduct *)scriptEngine->property("lastSetupProduct").toULongLong();
+
+ QScriptValue productScriptValue;
+ if (lastSetupProduct != product.data()) {
+ scriptEngine->setProperty("lastSetupProduct", QVariant((qulonglong)product.data()));
+ productScriptValue = scriptEngine->toScriptValue(product->configuration->value());
+ productScriptValue.setProperty("name", product->name);
+ QString destinationDirectory = product->destinationDirectory;
+ if (destinationDirectory.isEmpty())
+ destinationDirectory = ".";
+ productScriptValue.setProperty("destinationDirectory", destinationDirectory);
+ scriptEngine->globalObject().setProperty("product", productScriptValue, QScriptValue::ReadOnly);
+ } else {
+ productScriptValue = scriptEngine->globalObject().property("product");
+ }
+
+ // If the Rule is in a Module, set up the 'module' property
+ if (!rule->module->name.isEmpty())
+ productScriptValue.setProperty("module", productScriptValue.property("modules").property(rule->module->name));
+
+ if (rule) {
+ for (JsImports::const_iterator it = rule->jsImports.begin(); it != rule->jsImports.end(); ++it) {
+ foreach (const QString &fileName, it.value()) {
+ QScriptValue jsImportValue;
+ if (bg)
+ jsImportValue = bg->m_jsImportCache.value(fileName, scriptEngine->undefinedValue());
+ if (jsImportValue.isUndefined()) {
+// qDebug() << "CACHE MISS" << fileName;
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly))
+ throw Error(QString("Cannot open '%1'.").arg(fileName));
+ const QString sourceCode = QTextStream(&file).readAll();
+ QScriptProgram program(sourceCode, fileName);
+ addJSImport(scriptEngine, program, jsImportValue);
+ addJSImport(scriptEngine, jsImportValue, it.key());
+ if (bg)
+ bg->m_jsImportCache.insert(fileName, jsImportValue);
+ } else {
+// qDebug() << "CACHE HIT" << fileName;
+ addJSImport(scriptEngine, jsImportValue, it.key());
+ }
+ }
+ }
+ } else {
+ // ### TODO remove the imports we added before
+ }
+}
+
+void BuildGraph::setupScriptEngineForArtifact(BuildProduct *product, Artifact *artifact)
+{
+ QString inFileName = FileInfo::fileName(artifact->fileName);
+ QString inBaseName = FileInfo::baseName(artifact->fileName);
+ QString inCompleteBaseName = FileInfo::completeBaseName(artifact->fileName);
+
+ QString basedir;
+ if (artifact->artifactType == Artifact::SourceFile) {
+ QDir sourceDir(product->rProduct->sourceDirectory);
+ basedir = FileInfo::path(sourceDir.relativeFilePath(artifact->fileName));
+ } else {
+ QDir buildDir(product->project->buildGraph()->buildDirectoryRoot() + product->project->resolvedProject()->id);
+ basedir = FileInfo::path(buildDir.relativeFilePath(artifact->fileName));
+ }
+
+ QScriptValue modulesScriptValue = artifact->configuration->cachedScriptValue(&m_scriptEngine);
+ if (!modulesScriptValue.isValid()) {
+ modulesScriptValue = m_scriptEngine.toScriptValue(artifact->configuration->value());
+ artifact->configuration->cacheScriptValue(&m_scriptEngine, modulesScriptValue);
+ }
+ modulesScriptValue = modulesScriptValue.property("modules");
+
+ // expose per file properties we want to use in an Artifact within a Rule
+ QScriptValue scriptValue = m_scriptEngine.newObject();
+ scriptValue.setProperty("fileName", inFileName);
+ scriptValue.setProperty("baseName", inBaseName);
+ scriptValue.setProperty("completeBaseName", inCompleteBaseName);
+ scriptValue.setProperty("baseDir", basedir);
+ scriptValue.setProperty("modules", modulesScriptValue);
+
+ QScriptValue globalObj = m_scriptEngine.globalObject();
+ globalObj.setProperty("input", scriptValue);
+}
+
+void BuildGraph::applyRules(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag)
+{
+ foreach (Rule::Ptr rule, product->topSortedRules())
+ applyRule(product, artifactsPerFileTag, rule);
+}
+
+/*!
+ * Runs a cycle detection on the BG and throws an exception if there is one.
+ */
+void BuildGraph::detectCycle(BuildProject *project)
+{
+ QElapsedTimer *t = 0;
+ if (qbsLogLevel(LoggerTrace)) {
+ t = new QElapsedTimer;
+ qbsTrace() << "[BG] running cycle detection on project '" + project->resolvedProject()->id + "'";
+ }
+
+ foreach (BuildProduct::Ptr product, project->buildProducts())
+ foreach (Artifact *artifact, product->targetArtifacts)
+ detectCycle(artifact);
+
+ if (qbsLogLevel(LoggerTrace)) {
+ qint64 elapsed = t->elapsed();
+ qbsTrace() << "[BG] cycle detection for project '" + project->resolvedProject()->id + "' took " << elapsed << " ms";
+ delete t;
+ }
+}
+
+void BuildGraph::detectCycle(Artifact *a)
+{
+ QSet<Artifact *> done, currentBranch;
+ detectCycle(a, done, currentBranch);
+}
+
+void BuildGraph::detectCycle(Artifact *v, QSet<Artifact *> &done, QSet<Artifact *> &currentBranch)
+{
+ currentBranch += v;
+ for (ArtifactList::const_iterator it = v->children.begin(); it != v->children.end(); ++it) {
+ Artifact *u = *it;
+ if (currentBranch.contains(u))
+ throw Error("Cycle in build graph detected.");
+ if (!done.contains(u))
+ detectCycle(u, done, currentBranch);
+ }
+ currentBranch -= v;
+ done += v;
+}
+
+static AbstractCommand *createCommandFromScriptValue(const QScriptValue &scriptValue)
+{
+ if (scriptValue.isUndefined() || !scriptValue.isValid())
+ return 0;
+ AbstractCommand *cmdBase = 0;
+ QString className = scriptValue.property("className").toString();
+ if (className == "Command")
+ cmdBase = new ProcessCommand;
+ else if (className == "JavaScriptCommand")
+ cmdBase = new JavaScriptCommand;
+ if (cmdBase)
+ cmdBase->fillFromScriptValue(&scriptValue);
+ return cmdBase;
+}
+
+void BuildGraph::applyRule(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag,
+ Rule::Ptr rule)
+{
+ setupScriptEngineForProduct(&m_scriptEngine, product->rProduct, rule, this);
+
+ if (rule->isMultiplexRule()) {
+ // apply the rule once for a set of inputs
+
+ QSet<Artifact*> inputArtifacts;
+ foreach (const QString &fileTag, rule->inputs)
+ inputArtifacts.unite(artifactsPerFileTag.value(fileTag));
+
+ if (!inputArtifacts.isEmpty())
+ applyRule(product, artifactsPerFileTag, rule, inputArtifacts);
+ } else {
+ // apply the rule once for each input
+
+ QSet<Artifact*> inputArtifacts;
+ foreach (const QString &fileTag, rule->inputs) {
+ foreach (Artifact *inputArtifact, artifactsPerFileTag.value(fileTag)) {
+ inputArtifacts.insert(inputArtifact);
+ applyRule(product, artifactsPerFileTag, rule, inputArtifacts);
+ inputArtifacts.clear();
+ }
+ }
+ }
+}
+
+void BuildGraph::createOutputArtifact(
+ BuildProduct *product,
+ const Rule::Ptr &rule, const RuleArtifact::Ptr &ruleArtifact,
+ const QSet<Artifact *> &inputArtifacts,
+ QList< QPair<RuleArtifact*, Artifact *> > *ruleArtifactArtifactMap,
+ QList<Artifact *> *outputArtifacts,
+ QSharedPointer<Transformer> &transformer)
+{
+ QScriptValue scriptValue = m_scriptEngine.evaluate(ruleArtifact->fileScript);
+ if (scriptValue.isError() || m_scriptEngine.hasUncaughtException())
+ throw Error("Error in Rule.Artifact fileName: " + scriptValue.toString());
+ QString outputPath = scriptValue.toString();
+ outputPath.replace("..", "dotdot"); // don't let the output artifact "escape" its build dir
+ outputPath = resolveOutPath(outputPath, product);
+
+ Artifact *outputArtifact = product->artifacts.value(outputPath);
+ if (outputArtifact) {
+ if (outputArtifact->transformer && outputArtifact->transformer != transformer) {
+ // This can happen when applying rules after scanning for additional file tags.
+ // We just regenerate the transformer.
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace("[BG] regenerating transformer for '%s'", qPrintable(fileName(outputArtifact)));
+ transformer = outputArtifact->transformer;
+ transformer->inputs += inputArtifacts;
+
+ if (transformer->inputs.count() > 1 && !rule->isMultiplexRule()) {
+ QString th = "[" + QStringList(outputArtifact->fileTags.toList()).join(", ") + "]";
+ QString e = tr("Conflicting rules for producing %1 %2 \n").arg(outputArtifact->fileName, th);
+ th = "[" + rule->inputs.join(", ")
+ + "] -> [" + QStringList(outputArtifact->fileTags.toList()).join(", ") + "]";
+
+ e += QString(" while trying to apply: %1:%2:%3 %4\n")
+ .arg(rule->script->location.fileName)
+ .arg(rule->script->location.line)
+ .arg(rule->script->location.column)
+ .arg(th);
+
+ e += QString(" was already defined in: %1:%2:%3 %4\n")
+ .arg(outputArtifact->transformer->rule->script->location.fileName)
+ .arg(outputArtifact->transformer->rule->script->location.line)
+ .arg(outputArtifact->transformer->rule->script->location.column)
+ .arg(th);
+ throw Error(e);
+ }
+ }
+ outputArtifact->fileTags += ruleArtifact->fileTags.toSet();
+ } else {
+ outputArtifact = new Artifact(product->project);
+ outputArtifact->artifactType = Artifact::Generated;
+ outputArtifact->fileName = outputPath;
+ outputArtifact->fileTags = ruleArtifact->fileTags.toSet();
+ insert(product, outputArtifact);
+ }
+
+ if (rule->isMultiplexRule())
+ outputArtifact->configuration = product->rProduct->configuration;
+ else
+ outputArtifact->configuration = (*inputArtifacts.constBegin())->configuration;
+
+ foreach (Artifact *inputArtifact, inputArtifacts) {
+ Q_ASSERT(outputArtifact != inputArtifact);
+ loggedConnect(outputArtifact, inputArtifact);
+ }
+ ruleArtifactArtifactMap->append(qMakePair(ruleArtifact.data(), outputArtifact));
+ outputArtifacts->append(outputArtifact);
+
+ // create transformer if not already done so
+ if (!transformer) {
+ transformer = QSharedPointer<Transformer>(new Transformer);
+ transformer->rule = rule;
+ transformer->inputs = inputArtifacts;
+ }
+ outputArtifact->transformer = transformer;
+}
+
+void BuildGraph::applyRule(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag, Rule::Ptr rule, const QSet<Artifact *> &inputArtifacts)
+{
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug() << "[BG] apply rule " << rule->toString() << " " << toStringList(inputArtifacts).join(",\n ");
+
+ QList< QPair<RuleArtifact*, Artifact *> > ruleArtifactArtifactMap;
+ QList<Artifact *> outputArtifacts;
+
+ QSet<Artifact *> usingArtifacts;
+ foreach (BuildProduct *dep, product->usings) {
+ foreach (Artifact *targetArtifact, dep->targetArtifacts) {
+ ArtifactList sbsArtifacts = targetArtifact->sideBySideArtifacts;
+ sbsArtifacts.insert(targetArtifact);
+ foreach (Artifact *artifact, sbsArtifacts) {
+ QString matchingTag;
+ foreach (const QString &tag, rule->usings) {
+ if (artifact->fileTags.contains(tag)) {
+ matchingTag = tag;
+ break;
+ }
+ }
+ if (matchingTag.isEmpty())
+ continue;
+ usingArtifacts.insert(artifact);
+ }
+ }
+ }
+
+ // create the output artifacts from the set of input artifacts
+ QSharedPointer<Transformer> transformer;
+ foreach (RuleArtifact::Ptr ruleArtifact, rule->artifacts) {
+ if (!rule->isMultiplexRule()) {
+ foreach (Artifact *inputArtifact, inputArtifacts) {
+ setupScriptEngineForArtifact(product, inputArtifact);
+ QSet<Artifact *> oneInputArtifact;
+ oneInputArtifact.insert(inputArtifact);
+ createOutputArtifact(product, rule, ruleArtifact, oneInputArtifact,
+ &ruleArtifactArtifactMap, &outputArtifacts, transformer);
+ }
+ } else {
+ createOutputArtifact(product, rule, ruleArtifact, inputArtifacts,
+ &ruleArtifactArtifactMap, &outputArtifacts, transformer);
+ }
+ }
+
+ foreach (Artifact *outputArtifact, outputArtifacts) {
+ // insert the output artifacts into the pool of artifacts
+ foreach (const QString &fileTag, outputArtifact->fileTags)
+ artifactsPerFileTag[fileTag].insert(outputArtifact);
+
+ // connect artifacts that match the file tags in explicitlyDependsOn
+ foreach (const QString &fileTag, rule->explicitlyDependsOn)
+ foreach (Artifact *dependency, artifactsPerFileTag.value(fileTag))
+ loggedConnect(outputArtifact, dependency);
+
+ // Transformer setup
+ transformer->outputs.insert(outputArtifact);
+ for (QSet<Artifact *>::const_iterator it = usingArtifacts.constBegin(); it != usingArtifacts.constEnd(); ++it) {
+ Artifact *dep = *it;
+ loggedConnect(outputArtifact, dep);
+ transformer->inputs.insert(dep);
+ foreach (Artifact *sideBySideDep, dep->sideBySideArtifacts) {
+ loggedConnect(outputArtifact, sideBySideDep);
+ transformer->inputs.insert(sideBySideDep);
+ }
+ }
+
+ m_artifactsThatMustGetNewTransformers -= outputArtifact;
+ }
+
+ // setup side-by-side artifacts
+ if (outputArtifacts.count() > 1)
+ foreach (Artifact *sbs1, outputArtifacts)
+ foreach (Artifact *sbs2, outputArtifacts)
+ if (sbs1 != sbs2)
+ sbs1->sideBySideArtifacts.insert(sbs2);
+
+ transformer->setupInputs(&m_scriptEngine, m_scriptEngine.globalObject());
+
+ // change the transformer outputs according to the bindings in Artifact
+ QScriptValue scriptValue;
+ for (int i=ruleArtifactArtifactMap.count(); --i >= 0;) {
+ RuleArtifact *ra = ruleArtifactArtifactMap.at(i).first;
+ if (ra->bindings.isEmpty())
+ continue;
+
+ // expose attributes of this artifact
+ Artifact *outputArtifact = ruleArtifactArtifactMap.at(i).second;
+ outputArtifact->configuration = Configuration::Ptr(new Configuration(*outputArtifact->configuration));
+
+ // ### clean m_scriptEngine first?
+ m_scriptEngine.globalObject().setProperty("fileName", m_scriptEngine.toScriptValue(outputArtifact->fileName), QScriptValue::ReadOnly);
+ m_scriptEngine.globalObject().setProperty("fileTags", toScriptValue(&m_scriptEngine, outputArtifact->fileTags), QScriptValue::ReadOnly);
+
+ QVariantMap artifactModulesCfg = outputArtifact->configuration->value().value("modules").toMap();
+ for (int i=0; i < ra->bindings.count(); ++i) {
+ const QStringList &name = ra->bindings.at(i).first;
+ const QString &code = ra->bindings.at(i).second;
+ scriptValue = m_scriptEngine.evaluate(code);
+ if (scriptValue.isError())
+ throw Error(QLatin1String("evaluating rule bindings: ") + scriptValue.toString());
+ setConfigProperty(artifactModulesCfg, name, scriptValue.toVariant());
+ }
+ QVariantMap outputArtifactConfiguration = outputArtifact->configuration->value();
+ outputArtifactConfiguration.insert("modules", artifactModulesCfg);
+ outputArtifact->configuration->setValue(outputArtifactConfiguration);
+ }
+
+ transformer->setupOutputs(&m_scriptEngine, m_scriptEngine.globalObject());
+
+ // setup transform properties
+ {
+ const QVariantMap overriddenTransformProperties = product->rProduct->configuration->value().value("modules").toMap().value(rule->module->name).toMap().value(rule->objectId).toMap();
+ /*
+ overriddenTransformProperties contains the rule's transform properties that have been overridden in the project file.
+ For example, if you set cpp.compiler.defines in your project file, that property appears here.
+ */
+
+ QMap<QString, QScriptProgram>::const_iterator it = rule->transformProperties.begin();
+ for (; it != rule->transformProperties.end(); ++it)
+ {
+ const QString &propertyName = it.key();
+ QScriptValue sv;
+ if (overriddenTransformProperties.contains(propertyName)) {
+ sv = m_scriptEngine.toScriptValue(overriddenTransformProperties.value(propertyName));
+ } else {
+ const QScriptProgram &myProgram = it.value();
+ sv = m_scriptEngine.evaluate(myProgram);
+ if (m_scriptEngine.hasUncaughtException()) {
+ CodeLocation errorLocation;
+ errorLocation.fileName = m_scriptEngine.uncaughtExceptionBacktrace().join("\n");
+ errorLocation.line = m_scriptEngine.uncaughtExceptionLineNumber();
+ throw Error(QLatin1String("transform property evaluation: ") + m_scriptEngine.uncaughtException().toString(), errorLocation);
+ } else if (sv.isError()) {
+ CodeLocation errorLocation(myProgram.fileName(), myProgram.firstLineNumber());
+ throw Error(QLatin1String("transform property evaluation: ") + sv.toString(), errorLocation);
+ }
+ }
+ m_scriptEngine.globalObject().setProperty(propertyName, sv);
+ }
+ }
+
+ createTransformerCommands(rule->script, transformer.data());
+ if (transformer->commands.isEmpty())
+ throw Error(QString("There's a rule without commands: %1.").arg(rule->toString()), rule->script->location);
+}
+
+void BuildGraph::createTransformerCommands(RuleScript::Ptr script, Transformer *transformer)
+{
+ QScriptProgram &scriptProgram = m_scriptProgramCache[script->script];
+ if (scriptProgram.isNull())
+ scriptProgram = QScriptProgram(script->script);
+
+ QScriptValue scriptValue = m_scriptEngine.evaluate(scriptProgram);
+ if (m_scriptEngine.hasUncaughtException())
+ throw Error("evaluating prepare script: " + m_scriptEngine.uncaughtException().toString(),
+ script->location);
+
+ QList<AbstractCommand*> commands;
+ if (scriptValue.isArray()) {
+ const int count = scriptValue.property("length").toInt32();
+ for (qint32 i=0; i < count; ++i) {
+ QScriptValue item = scriptValue.property(i);
+ if (item.isValid() && !item.isUndefined()) {
+ AbstractCommand *cmd = createCommandFromScriptValue(item);
+ if (cmd)
+ commands += cmd;
+ }
+ }
+ } else {
+ AbstractCommand *cmd = createCommandFromScriptValue(scriptValue);
+ if (cmd)
+ commands += cmd;
+ }
+
+ transformer->commands = commands;
+}
+
+QString BuildGraph::buildDirectoryRoot() const
+{
+ Q_ASSERT(!m_outputDirectoryRoot.isEmpty());
+ QString path = FileInfo::resolvePath(m_outputDirectoryRoot, QLatin1String("build"));
+ if (!path.endsWith('/'))
+ path.append(QLatin1Char('/'));
+ return path;
+}
+
+/*
+ * c must be built before p
+ * p ----> c
+ * p.children = c
+ * c.parents = p
+ *
+ * also: children means i depend on or i am produced by
+ * parent means "produced by me" or "depends on me"
+ */
+void BuildGraph::connect(Artifact *p, Artifact *c)
+{
+ Q_ASSERT(p != c);
+ p->children.insert(c);
+ c->parents.insert(p);
+ p->project->markDirty();
+}
+
+void BuildGraph::loggedConnect(Artifact *u, Artifact *v)
+{
+ Q_ASSERT(u != v);
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace("[BG] connect '%s' -> '%s'",
+ qPrintable(fileName(u)),
+ qPrintable(fileName(v)));
+ connect(u, v);
+}
+
+static bool findPath(Artifact *u, Artifact *v, QList<Artifact*> &path)
+{
+ if (u == v) {
+ path.append(v);
+ return true;
+ }
+
+ for (ArtifactList::const_iterator it = u->children.begin(); it != u->children.end(); ++it) {
+ if (findPath(*it, v, path)) {
+ path.prepend(u);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool existsPath(Artifact *u, Artifact *v)
+{
+ if (u == v)
+ return true;
+
+ for (ArtifactList::const_iterator it = u->children.begin(); it != u->children.end(); ++it)
+ if (existsPath(*it, v))
+ return true;
+
+ return false;
+}
+
+bool BuildGraph::safeConnect(Artifact *u, Artifact *v)
+{
+ Q_ASSERT(u != v);
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace("[BG] safeConnect: '%s' '%s'",
+ qPrintable(fileName(u)),
+ qPrintable(fileName(v)));
+
+ if (existsPath(v, u)) {
+ QList<Artifact *> circle;
+ findPath(v, u, circle);
+ qbsTrace() << "[BG] safeConnect: circle detected " << toStringList(circle);
+ return false;
+ }
+
+ connect(u, v);
+ return true;
+}
+
+void BuildGraph::disconnect(Artifact *u, Artifact *v)
+{
+ u->children.remove(v);
+ v->parents.remove(u);
+}
+
+QSet<Artifact *> BuildGraph::disconnect(Artifact *n) const
+{
+ QSet<Artifact *> r;
+ if (n->children.count() == 1) {
+ Artifact * c = *(n->children.begin());
+ c->parents.remove(n);
+ n->children.clear();
+ r += n;
+ foreach (Artifact * p, n->parents) {
+ r += disconnect(p);
+ p->children.remove(n);
+ if (p->transformer)
+ p->transformer->inputs.remove(n);
+ }
+ }
+ return r;
+}
+
+void BuildGraph::remove(Artifact *artifact) const
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[BG] remove artifact " << fileName(artifact);
+
+ if (artifact->artifactType == Artifact::Generated)
+ QFile::remove(artifact->fileName);
+ artifact->product->artifacts.remove(artifact->fileName);
+ artifact->product->targetArtifacts.remove(artifact);
+ foreach (Artifact *parent, artifact->parents) {
+ parent->children.remove(artifact);
+ if (parent->transformer) {
+ parent->transformer->inputs.remove(artifact);
+ m_artifactsThatMustGetNewTransformers += parent;
+ }
+ }
+ foreach (Artifact *child, artifact->children) {
+ child->parents.remove(artifact);
+ }
+ artifact->children.clear();
+ artifact->parents.clear();
+ artifact->project->markDirty();
+}
+
+/**
+ * Removes the artifact and all the artifacts that depend exclusively on it.
+ * Example: if you remove a cpp artifact then the obj artifact is removed but
+ * not the resulting application (if there's more then one cpp artifact).
+ */
+void BuildGraph::removeArtifactAndExclusiveDependents(Artifact *artifact, QList<Artifact*> *removedArtifacts)
+{
+ if (removedArtifacts)
+ removedArtifacts->append(artifact);
+ foreach (Artifact *parent, artifact->parents) {
+ if (parent->children.count() == 1)
+ removeArtifactAndExclusiveDependents(parent, removedArtifacts);
+ }
+ remove(artifact);
+}
+
+BuildProject::Ptr BuildGraph::resolveProject(ResolvedProject::Ptr rProject, QFutureInterface<bool> &futureInterface)
+{
+ BuildProject::Ptr project = BuildProject::Ptr(new BuildProject(this));
+ project->setResolvedProject(rProject);
+ foreach (ResolvedProduct::Ptr rProduct, rProject->products) {
+ resolveProduct(project.data(), rProduct, futureInterface);
+ }
+ detectCycle(project.data());
+ return project;
+}
+
+BuildProduct::Ptr BuildGraph::resolveProduct(BuildProject *project, ResolvedProduct::Ptr rProduct, QFutureInterface<bool> &futureInterface)
+{
+ BuildProduct::Ptr product = m_productCache.value(rProduct);
+ if (product)
+ return product;
+
+ futureInterface.setProgressValue(futureInterface.progressValue() + 1);
+ product = BuildProduct::Ptr(new BuildProduct);
+ m_productCache.insert(rProduct, product);
+ product->project = project;
+ product->rProduct = rProduct;
+ QMap<QString, QSet<Artifact *> > artifactsPerFileTag;
+
+ foreach (ResolvedProduct::Ptr t2, rProduct->uses) {
+ if (t2 == rProduct) {
+ throw Error(tr("circular using"));
+ }
+ BuildProduct::Ptr referencedProduct = resolveProduct(project, t2, futureInterface);
+ product->usings.append(referencedProduct.data());
+ }
+
+ //add qbsFile artifact
+ Artifact *qbsFileArtifact = product->artifacts.value(rProduct->qbsFile);
+ if (!qbsFileArtifact) {
+ qbsFileArtifact = new Artifact(project);
+ qbsFileArtifact->artifactType = Artifact::SourceFile;
+ qbsFileArtifact->fileName = rProduct->qbsFile;
+ qbsFileArtifact->configuration = rProduct->configuration;
+ insert(product, qbsFileArtifact);
+ }
+ qbsFileArtifact->fileTags.insert("qbs");
+ artifactsPerFileTag["qbs"].insert(qbsFileArtifact);
+
+ // read sources
+ foreach (SourceArtifact::Ptr sourceArtifact, rProduct->sources) {
+ QString filePath = sourceArtifact->absoluteFilePath;
+ if (product->artifacts.contains(filePath)) {
+ // ignore duplicate artifacts
+ continue;
+ }
+
+ Artifact *artifact = createArtifact(product, sourceArtifact);
+
+ foreach (const QString &fileTag, artifact->fileTags)
+ artifactsPerFileTag[fileTag].insert(artifact);
+ }
+
+ // read manually added transformers
+ QList<Artifact *> transformerOutputs;
+ foreach (const ResolvedTransformer::Ptr rtrafo, rProduct->transformers) {
+ QList<Artifact *> inputArtifacts;
+ foreach (const QString &inputFileName, rtrafo->inputs) {
+ Artifact *artifact = product->artifacts.value(inputFileName);
+ if (!artifact)
+ throw Error(QString("Can't find artifact '%0' in the list of source files.").arg(inputFileName));
+ if (artifact->fileTags.isEmpty())
+ artifact->fileTags += "unknown";
+ inputArtifacts += artifact;
+ }
+ QSharedPointer<Transformer> transformer(new Transformer);
+ transformer->inputs = inputArtifacts.toSet();
+ transformer->rule = Rule::Ptr(new Rule);
+ transformer->rule->inputs = rtrafo->inputs;
+ transformer->rule->jsImports = rtrafo->jsImports;
+ transformer->rule->module = ResolvedModule::Ptr(new ResolvedModule);
+ transformer->rule->module->name = rtrafo->module->name;
+ transformer->rule->script = rtrafo->transform;
+ foreach (SourceArtifact::Ptr sourceArtifact, rtrafo->outputs) {
+ Artifact *outputArtifact = createArtifact(product, sourceArtifact);
+ outputArtifact->artifactType = Artifact::Generated;
+ outputArtifact->transformer = transformer;
+ transformer->outputs += outputArtifact;
+ transformerOutputs += outputArtifact;
+ foreach (Artifact *inputArtifact, inputArtifacts)
+ safeConnect(outputArtifact, inputArtifact);
+ foreach (const QString &fileTag, outputArtifact->fileTags)
+ artifactsPerFileTag[fileTag].insert(outputArtifact);
+
+ RuleArtifact::Ptr ruleArtifact(new RuleArtifact);
+ ruleArtifact->fileScript = outputArtifact->fileName;
+ ruleArtifact->fileTags = outputArtifact->fileTags.toList();
+ transformer->rule->artifacts += ruleArtifact;
+ }
+ setupScriptEngineForProduct(&m_scriptEngine, rProduct, transformer->rule, this);
+ transformer->setupInputs(&m_scriptEngine, m_scriptEngine.globalObject());
+ transformer->setupOutputs(&m_scriptEngine, m_scriptEngine.globalObject());
+ createTransformerCommands(rtrafo->transform, transformer.data());
+ if (transformer->commands.isEmpty())
+ throw Error(QString("There's a transformer without commands."), rtrafo->transform->location);
+ }
+
+ applyRules(product.data(), artifactsPerFileTag);
+
+ QSet<Artifact *> productArtifactCandidates;
+ for (int i=0; i < product->rProduct->fileTags.count(); ++i)
+ foreach (Artifact *artifact, artifactsPerFileTag.value(product->rProduct->fileTags.at(i)))
+ if (artifact->artifactType == Artifact::Generated)
+ productArtifactCandidates += artifact;
+
+ if (productArtifactCandidates.isEmpty()) {
+ // this should already be catched in the rule graph
+ throw Error("The impossible happenend! The rules generate no product.");
+ }
+
+ foreach (Artifact *productArtifact, productArtifactCandidates) {
+ product->targetArtifacts.insert(productArtifact);
+ project->addBuildProduct(product);
+
+ foreach (Artifact *trafoOutputArtifact, transformerOutputs)
+ if (productArtifact != trafoOutputArtifact)
+ loggedConnect(productArtifact, trafoOutputArtifact);
+ }
+
+ return product;
+}
+
+void BuildGraph::onProductChanged(BuildProduct::Ptr product, ResolvedProduct::Ptr changedProduct)
+{
+ qbsDebug() << "[BG] product '" << product->rProduct->name << "' changed.";
+
+ QMap<QString, QSet<Artifact *> > artifactsPerFileTag;
+ QList<Artifact *> addedArtifacts, artifactsToRemove;
+ QHash<QString, SourceArtifact::Ptr> oldArtifacts, newArtifacts;
+ foreach (SourceArtifact::Ptr a, product->rProduct->sources)
+ oldArtifacts.insert(a->absoluteFilePath, a);
+ foreach (SourceArtifact::Ptr a, changedProduct->sources) {
+ newArtifacts.insert(a->absoluteFilePath, a);
+ if (!oldArtifacts.contains(a->absoluteFilePath)) {
+ // artifact added
+ qbsDebug() << "[BG] artifact '" << a->absoluteFilePath << "' added to product " << product->rProduct->name;
+ product->rProduct->sources.insert(a);
+ addedArtifacts += createArtifact(product, a);
+ }
+ }
+ foreach (SourceArtifact::Ptr a, product->rProduct->sources) {
+ SourceArtifact::Ptr changedArtifact = newArtifacts.value(a->absoluteFilePath);
+ if (!changedArtifact) {
+ // artifact removed
+ qbsDebug() << "[BG] artifact '" << a->absoluteFilePath << "' removed from product " << product->rProduct->name;
+ Artifact *artifact = product->artifacts.value(a->absoluteFilePath);
+ Q_ASSERT(artifact);
+ removeArtifactAndExclusiveDependents(artifact, &artifactsToRemove);
+ continue;
+ }
+ if (changedArtifact->fileTags != a->fileTags) {
+ // artifact's filetags have changed
+ qbsDebug() << "[BG] filetags have changed for artifact '" << a->absoluteFilePath
+ << "' from " << a->fileTags << " to " << changedArtifact->fileTags;
+ Artifact *artifact = product->artifacts.value(a->absoluteFilePath);
+ Q_ASSERT(artifact);
+
+ // handle added filetags
+ foreach (const QString &addedFileTag, changedArtifact->fileTags - a->fileTags)
+ artifactsPerFileTag[addedFileTag] += artifact;
+
+ // handle removed filetags
+ foreach (const QString &removedFileTag, a->fileTags - changedArtifact->fileTags) {
+ artifact->fileTags -= removedFileTag;
+ foreach (Artifact *parent, artifact->parents) {
+ if (parent->transformer && parent->transformer->rule->inputs.contains(removedFileTag)) {
+ // this parent has been created because of the removed filetag
+ removeArtifactAndExclusiveDependents(parent, &artifactsToRemove);
+ }
+ }
+ }
+ }
+ if (changedArtifact->configuration->value() != a->configuration->value()) // ### TODO
+ {
+ qWarning("Some properties changed. Consider rebuild or fix QBS-7. File name: %s", qPrintable(changedArtifact->absoluteFilePath));
+ QVariantMap m = a->configuration->value();
+
+ for (QVariantMap::iterator it = m.begin(); it != m.end(); ++it) {
+ if (it.value() != changedArtifact->configuration->value().value(it.key())) {
+ qDebug() << " old:" << it.value();
+ qDebug() << " new:" << changedArtifact->configuration->value().value(it.key());
+ }
+ }
+ }
+ }
+
+ // apply rules for new artifacts
+ foreach (Artifact *artifact, addedArtifacts)
+ foreach (const QString &ft, artifact->fileTags)
+ artifactsPerFileTag[ft] += artifact;
+ applyRules(product.data(), artifactsPerFileTag);
+
+ // parents of removed artifacts must update their transformers
+ foreach (Artifact *removedArtifact, artifactsToRemove)
+ foreach (Artifact *parent, removedArtifact->parents)
+ m_artifactsThatMustGetNewTransformers += parent;
+ updateNodesThatMustGetNewTransformer();
+
+ // delete all removed artifacts physically from the disk
+ foreach (Artifact *artifact, artifactsToRemove) {
+ if (artifact->artifactType == Artifact::Generated) {
+ qbsDebug() << "[BG] deleting stale artifact " << artifact->fileName;
+ QFile::remove(artifact->fileName);
+ }
+ delete artifact;
+ }
+}
+
+void BuildGraph::updateNodesThatMustGetNewTransformer()
+{
+ foreach (Artifact *artifact, m_artifactsThatMustGetNewTransformers)
+ updateNodeThatMustGetNewTransformer(artifact);
+ m_artifactsThatMustGetNewTransformers.clear();
+}
+
+void BuildGraph::updateNodeThatMustGetNewTransformer(Artifact *artifact)
+{
+ Q_CHECK_PTR(artifact->transformer);
+
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug() << "[BG] updating transformer for " << fileName(artifact);
+
+ Rule::Ptr rule = artifact->transformer->rule;
+ artifact->product->project->markDirty();
+ artifact->transformer = QSharedPointer<Transformer>();
+
+ QMap<QString, QSet<Artifact *> > artifactsPerFileTag;
+ foreach (Artifact *input, artifact->children)
+ foreach (const QString &fileTag, input->fileTags)
+ artifactsPerFileTag[fileTag] += input;
+
+ applyRule(artifact->product, artifactsPerFileTag, rule);
+}
+
+Artifact *BuildGraph::createArtifact(BuildProduct::Ptr product, SourceArtifact::Ptr sourceArtifact)
+{
+ Artifact *artifact = new Artifact(product->project);
+ artifact->artifactType = Artifact::SourceFile;
+ artifact->fileName = sourceArtifact->absoluteFilePath;
+ artifact->fileTags = sourceArtifact->fileTags;
+ artifact->configuration = sourceArtifact->configuration;
+ insert(product, artifact);
+ return artifact;
+}
+
+QString BuildGraph::resolveOutPath(const QString &path, BuildProduct *product) const
+{
+ QString result;
+ QString buildDir = product->rProduct->buildDirectory;
+ result = FileInfo::resolvePath(buildDir, path);
+
+ Q_ASSERT(result.startsWith(buildDir));
+ result = QDir::cleanPath(result);
+ return result;
+}
+
+void Transformer::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ rule = pool.idLoadS<Rule>(s);
+ loadContainer(inputs, s, pool);
+ loadContainer(outputs, s, pool);
+ int count, cmdType;
+ s >> count;
+ commands.reserve(count);
+ while (--count >= 0) {
+ s >> cmdType;
+ AbstractCommand *cmd = AbstractCommand::createByType(static_cast<AbstractCommand::CommandType>(cmdType));
+ cmd->load(s);
+ commands += cmd;
+ }
+}
+
+void Transformer::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << pool.store(rule);
+ storeContainer(inputs, s, pool);
+ storeContainer(outputs, s, pool);
+ s << commands.count();
+ foreach (AbstractCommand *cmd, commands) {
+ s << int(cmd->type());
+ cmd->store(s);
+ }
+}
+
+void BuildProduct::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ int i, count;
+
+ // artifacts
+ artifacts.clear();
+ s >> count;
+ for (i = count; --i >= 0;) {
+ QString key;
+ s >> key;
+ artifacts.insert(key, pool.idLoad<Artifact>(s));
+ }
+
+ // edges
+ for (i = count; --i >= 0;) {
+ Artifact *artifact = pool.idLoad<Artifact>(s);
+ int count2, j;
+ s >> count2;
+ artifact->parents.clear();
+ artifact->parents.reserve(count2);
+ for (j = count2; --j >= 0;)
+ artifact->parents.insert(pool.idLoad<Artifact>(s));
+
+ s >> count2;
+ artifact->children.clear();
+ artifact->children.reserve(count2);
+ for (j = count2; --j >= 0;)
+ artifact->children.insert(pool.idLoad<Artifact>(s));
+
+ s >> count2;
+ artifact->fileDependencies.clear();
+ artifact->fileDependencies.reserve(count2);
+ for (j = count2; --j >= 0;)
+ artifact->fileDependencies.insert(pool.idLoad<Artifact>(s));
+
+ s >> count2;
+ artifact->sideBySideArtifacts.clear();
+ artifact->sideBySideArtifacts.reserve(count2);
+ for (j = count2; --j >= 0;)
+ artifact->sideBySideArtifacts.insert(pool.idLoad<Artifact>(s));
+ }
+
+ // other data
+ rProduct = pool.idLoadS<ResolvedProduct>(s);
+ loadContainer(targetArtifacts, s, pool);
+ loadContainer(usings, s, pool);
+}
+
+void BuildProduct::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << artifacts.count();
+
+ //artifacts
+ for (QHash<QString, Artifact *>::const_iterator i = artifacts.constBegin(); i != artifacts.constEnd(); i++) {
+ s << i.key();
+ PersistentObjectId artifactId = pool.store(i.value());
+ s << artifactId;
+ }
+
+ // edges
+ for (QHash<QString, Artifact *>::const_iterator i = artifacts.constBegin(); i != artifacts.constEnd(); i++) {
+ Artifact * artifact = i.value();
+ s << pool.store(artifact);
+
+ s << artifact->parents.count();
+ foreach (Artifact * n, artifact->parents)
+ s << pool.store(n);
+ s << artifact->children.count();
+ foreach (Artifact * n, artifact->children)
+ s << pool.store(n);
+ s << artifact->fileDependencies.count();
+ foreach (Artifact * n, artifact->fileDependencies)
+ s << pool.store(n);
+ s << artifact->sideBySideArtifacts.count();
+ foreach (Artifact *n, artifact->sideBySideArtifacts)
+ s << pool.store(n);
+ }
+
+ // other data
+ s << pool.store(rProduct);
+ storeContainer(targetArtifacts, s, pool);
+ storeContainer(usings, s, pool);
+}
+
+BuildProject::BuildProject(BuildGraph *bg)
+ : m_buildGraph(bg)
+ , m_dirty(false)
+{
+}
+
+BuildProject::~BuildProject()
+{
+ qDeleteAll(m_dependencyArtifacts);
+}
+
+static bool isConfigCompatible(const QVariantMap &userCfg, const QVariantMap &projectCfg)
+{
+ QVariantMap::const_iterator it = userCfg.begin();
+ for (; it != userCfg.end(); ++it) {
+ if (it.value().type() == QVariant::Map) {
+ if (!isConfigCompatible(it.value().toMap(), projectCfg.value(it.key()).toMap()))
+ return false;
+ } else {
+ QVariant value = projectCfg.value(it.key());
+ if (!value.isNull() && value != it.value()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+BuildProject::Ptr BuildProject::load(BuildGraph *bg, const FileTime &minTimeStamp, Configuration::Ptr cfg, const QStringList &loaderSearchPaths)
+{
+ PersistentPool pool;
+ QString fileName;
+ QStringList bgFiles = storedProjectFiles(bg);
+ foreach (const QString &fn, bgFiles) {
+ if (!pool.load(fn, PersistentPool::LoadHeadData))
+ continue;
+ PersistentPool::HeadData headData = pool.headData();
+ if (isConfigCompatible(cfg->value(), headData.projectConfig)) {
+ fileName = fn;
+ break;
+ }
+ }
+ if (fileName.isNull()) {
+ qbsDebug() << "[BG] No stored build graph found that's compatible to the desired build configuration.";
+ return BuildProject::Ptr();
+ }
+
+ BuildProject::Ptr project;
+ qbsDebug() << "[BG] trying to load: " << fileName;
+ FileInfo bgfi(fileName);
+ if (!bgfi.exists()) {
+ qbsDebug() << "[BG] stored build graph file does not exist";
+ return project;
+ }
+ if (!pool.load(fileName))
+ throw Error("Cannot load stored build graph.");
+ project = BuildProject::Ptr(new BuildProject(bg));
+ PersistentObjectData data = pool.getData(0);
+ project->load(pool, data);
+ project->resolvedProject()->configuration = Configuration::Ptr(new Configuration);
+ project->resolvedProject()->configuration->setValue(pool.headData().projectConfig);
+ qbsDebug() << "[BG] stored project loaded.";
+
+ bool projectFileChanged = false;
+ if (bgfi.lastModified() < minTimeStamp) {
+ projectFileChanged = true;
+ }
+
+ QList<BuildProduct::Ptr> changedProducts;
+ foreach (BuildProduct::Ptr product, project->buildProducts()) {
+ FileInfo pfi(product->rProduct->qbsFile);
+ if (!pfi.exists())
+ throw Error(QString("The product file '%1' is gone.").arg(product->rProduct->qbsFile));
+ if (bgfi.lastModified() < pfi.lastModified())
+ changedProducts += product;
+ }
+
+ if (projectFileChanged || !changedProducts.isEmpty()) {
+
+ Loader ldr;
+ ldr.setSearchPaths(loaderSearchPaths);
+ ldr.loadProject(project->resolvedProject()->qbsFile);
+ QFutureInterface<bool> dummyFutureInterface;
+ ResolvedProject::Ptr changedProject = ldr.resolveProject(bg->buildDirectoryRoot(), cfg, dummyFutureInterface);
+ if (!changedProject) {
+ QString msg("Trying to load '%1' failed.");
+ throw Error(msg.arg(project->resolvedProject()->qbsFile));
+ }
+
+ if (projectFileChanged) {
+ qWarning("[BG] project file changed: %s", qPrintable(project->resolvedProject()->qbsFile));
+ qWarning("[BG] ### HANDLING THAT PROPERLY IS NOT YET IMPLEMENTED");
+ qWarning("[BG] ### CONSIDER DELETING THE STORED BUILD GRAPH");
+ }
+
+ QMap<QString, ResolvedProduct::Ptr> changedProductsMap;
+ foreach (BuildProduct::Ptr product, changedProducts) {
+ if (changedProductsMap.isEmpty())
+ foreach (ResolvedProduct::Ptr cp, changedProject->products)
+ changedProductsMap.insert(cp->name, cp);
+ bg->onProductChanged(product, changedProductsMap.value(product->rProduct->name));
+ }
+
+ BuildGraph::detectCycle(project.data());
+ }
+
+ return project;
+}
+
+void BuildProject::store()
+{
+ if (!dirty()) {
+ qbsDebug() << "[BG] build graph is unchanged in project " << resolvedProject()->id << ".";
+ return;
+ }
+ const QString fileName = storedProjectFilePath(buildGraph(), resolvedProject()->id);
+ qbsDebug() << "[BG] storing: " << fileName;
+ PersistentPool pool;
+ PersistentPool::HeadData headData;
+ headData.projectConfig = resolvedProject()->configuration->value();
+ pool.setHeadData(headData);
+ PersistentObjectData data;
+ store(pool, data);
+ pool.setData(0, data);
+ pool.store(fileName);
+}
+
+QString BuildProject::storedProjectFilePath(BuildGraph *bg, const QString &projectId)
+{
+ return bg->buildDirectoryRoot() + projectId + ".bg";
+}
+
+QStringList BuildProject::storedProjectFiles(BuildGraph *bg)
+{
+ QStringList result;
+ QDirIterator dirit(bg->buildDirectoryRoot(), QStringList() << "*.bg", QDir::Files);
+ while (dirit.hasNext())
+ result += dirit.next();
+ return result;
+}
+
+void BuildProject::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+
+ setResolvedProject(pool.idLoadS<ResolvedProject>(s));
+
+ int count, i;
+ s >> count;
+ for (i = count; --i >= 0;) {
+ BuildProduct::Ptr product = pool.idLoadS<BuildProduct>(s);
+ product->project = this;
+ foreach (Artifact *artifact, product->artifacts)
+ artifact->project = this;
+ addBuildProduct(product);
+ }
+
+ s >> count;
+ m_dependencyArtifacts.clear();
+ m_dependencyArtifacts.reserve(count);
+ for (i = count; --i >= 0;) {
+ Artifact *artifact = pool.idLoad<Artifact>(s);
+ artifact->project = this;
+ m_dependencyArtifacts.insert(artifact->fileName, artifact);
+ }
+}
+
+void BuildProject::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+
+ s << pool.store(resolvedProject());
+ storeContainer(m_buildProducts, s, pool);
+ storeHashContainer(m_dependencyArtifacts, s, pool);
+}
+
+char **createCFileTags(const QSet<QString> &fileTags)
+{
+ if (fileTags.isEmpty())
+ return 0;
+
+ char **buf = new char*[fileTags.count()];
+ size_t i = 0;
+ foreach (const QString &fileTag, fileTags) {
+ buf[i] = qstrdup(fileTag.toLocal8Bit().data());
+ ++i;
+ }
+ return buf;
+}
+
+void freeCFileTags(char **cFileTags, int numFileTags)
+{
+ if (!cFileTags)
+ return;
+ for (int i = numFileTags; --i >= 0;)
+ delete[] cFileTags[i];
+ delete[] cFileTags;
+}
+
+BuildGraph * BuildProject::buildGraph() const
+{
+ return m_buildGraph;
+}
+
+ResolvedProject::Ptr BuildProject::resolvedProject() const
+{
+ return m_resolvedProject;
+}
+
+QSet<BuildProduct::Ptr> BuildProject::buildProducts() const
+{
+ return m_buildProducts;
+}
+
+QHash<QString, Artifact *> &BuildProject::dependencyArtifacts()
+{
+ return m_dependencyArtifacts;
+}
+
+bool BuildProject::dirty() const
+{
+ return m_dirty;
+}
+
+Artifact *BuildProject::findArtifact(const QString &filePath) const
+{
+ Artifact *artifact = m_dependencyArtifacts.value(filePath);
+ if (!artifact) {
+ foreach (const BuildProduct::Ptr &product, m_buildProducts) {
+ artifact = product->artifacts.value(filePath);
+ if (artifact)
+ break;
+ }
+ }
+ return artifact;
+}
+
+void BuildProject::markDirty()
+{
+ m_dirty = true;
+}
+
+void BuildProject::addBuildProduct(const BuildProduct::Ptr &product)
+{
+ m_buildProducts.insert(product);
+}
+
+void BuildProject::setResolvedProject(const ResolvedProject::Ptr &resolvedProject)
+{
+ m_resolvedProject = resolvedProject;
+}
+
+QString fileName(Artifact *n)
+{
+ class BuildGraph *bg = n->project->buildGraph();
+ QString str = n->fileName;
+ if (str.startsWith(bg->outputDirectoryRoot()))
+ str.remove(0, bg->outputDirectoryRoot().count());
+ if (str.startsWith('/'))
+ str.remove(0, 1);
+ return str;
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/buildgraph.h b/src/lib/buildgraph/buildgraph.h
new file mode 100644
index 000000000..3c9992748
--- /dev/null
+++ b/src/lib/buildgraph/buildgraph.h
@@ -0,0 +1,216 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef BUILDGRAPH_H
+#define BUILDGRAPH_H
+
+#include "artifactlist.h"
+
+#include <language/language.h>
+#include <tools/error.h>
+#include <tools/persistence.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStringList>
+
+#include <QtCore/QDir>
+#include <QtCore/QVector>
+#include <QtCore/QVariant>
+#include <QtScript/QScriptEngine>
+#include <QtCore/QFutureInterface>
+
+namespace qbs {
+
+class Artifact;
+class Transformer;
+class BuildProject;
+
+class BuildProduct : public PersistentObject
+{
+public:
+ typedef QSharedPointer<BuildProduct> Ptr;
+
+ BuildProduct();
+ ~BuildProduct();
+
+ const QList<Rule::Ptr> &topSortedRules() const;
+
+ BuildProject *project;
+ ResolvedProduct::Ptr rProduct;
+ QSet<Artifact *> targetArtifacts;
+ QList<BuildProduct *> usings;
+ QHash<QString, Artifact *> artifacts;
+
+private:
+ void load(PersistentPool &pool, PersistentObjectData &data);
+ void store(PersistentPool &pool, PersistentObjectData &data) const;
+
+private:
+ mutable QList<Rule::Ptr> m_topSortedRules;
+};
+
+class BuildGraph;
+
+class BuildProject : public PersistentObject
+{
+ friend class BuildGraph;
+public:
+ typedef QSharedPointer<BuildProject> Ptr;
+
+ BuildProject(BuildGraph *bg);
+ ~BuildProject();
+
+ static BuildProject::Ptr load(BuildGraph *bg, const FileTime &minTimeStamp, Configuration::Ptr cfg, const QStringList &loaderSearchPaths);
+ void store();
+
+ BuildGraph *buildGraph() const;
+ ResolvedProject::Ptr resolvedProject() const;
+ QSet<BuildProduct::Ptr> buildProducts() const;
+ QHash<QString, Artifact *> &dependencyArtifacts();
+ bool dirty() const;
+ Artifact *findArtifact(const QString &filePath) const;
+
+private:
+ static QString storedProjectFilePath(BuildGraph *bg, const QString &configId);
+ static QStringList storedProjectFiles(BuildGraph *bg);
+ void load(PersistentPool &pool, PersistentObjectData &data);
+ void store(PersistentPool &pool, PersistentObjectData &data) const;
+ void markDirty();
+ void addBuildProduct(const BuildProduct::Ptr &product);
+ void setResolvedProject(const ResolvedProject::Ptr & resolvedProject);
+
+private:
+ BuildGraph *m_buildGraph;
+ ResolvedProject::Ptr m_resolvedProject;
+ QSet<BuildProduct::Ptr> m_buildProducts;
+ QHash<QString, Artifact *> m_dependencyArtifacts;
+ bool m_dirty;
+};
+
+class BuildGraphListener;
+
+/**
+ * N artifact, T transformer, parent -> child
+ * parent depends on child, child is a dependency of parent,
+ * parent is a dependent of child.
+ *
+ * N a.out -> N main.o -> N main.cpp
+ *
+ * Every artifact can point to a transformer which contains the commands.
+ * Multiple artifacts can point to the same transformer.
+ */
+class BuildGraph
+{
+ Q_DECLARE_TR_FUNCTIONS(BuildGraph)
+public:
+ BuildGraph();
+ ~BuildGraph();
+
+ BuildProject::Ptr resolveProject(ResolvedProject::Ptr, QFutureInterface<bool> &futureInterface);
+ BuildProduct::Ptr resolveProduct(BuildProject *, ResolvedProduct::Ptr, QFutureInterface<bool> &futureInterface);
+
+ void dump(BuildProduct::Ptr) const;
+ void applyRules(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag);
+ static void detectCycle(BuildProject *project);
+ static void detectCycle(Artifact *a);
+
+ void setOutputDirectoryRoot(const QString &buildDirectoryRoot) { m_outputDirectoryRoot = buildDirectoryRoot; }
+ const QString &outputDirectoryRoot() const { return m_outputDirectoryRoot; }
+ QString buildDirectoryRoot() const;
+ QString resolveOutPath(const QString &path, BuildProduct *) const;
+
+ void connect(Artifact *p, Artifact *c);
+ void loggedConnect(Artifact *u, Artifact *v);
+ bool safeConnect(Artifact *u, Artifact *v);
+ void insert(BuildProduct::Ptr target, Artifact *n) const;
+ void insert(BuildProduct *target, Artifact *n) const;
+ void remove(Artifact *artifact) const;
+ void removeArtifactAndExclusiveDependents(Artifact *artifact, QList<Artifact*> *removedArtifacts = 0);
+
+ void createOutputArtifact(BuildProduct *product,
+ const Rule::Ptr &rule, const RuleArtifact::Ptr &ruleArtifact,
+ const QSet<Artifact *> &inputArtifacts,
+ QList<QPair<RuleArtifact *, Artifact *> > *ruleArtifactArtifactMap,
+ QList<Artifact *> *outputArtifacts,
+ QSharedPointer<Transformer> &transformer);
+
+ void onProductChanged(BuildProduct::Ptr product, ResolvedProduct::Ptr changedProduct);
+ void updateNodesThatMustGetNewTransformer();
+
+ static void setupScriptEngineForProduct(QScriptEngine *scriptEngine, ResolvedProduct::Ptr product, Rule::Ptr rule, BuildGraph *bg = 0);
+
+private:
+ Artifact *createArtifact(BuildProduct::Ptr product, SourceArtifact::Ptr sourceArtifact);
+ void applyRule(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag, Rule::Ptr rule);
+ void applyRule(BuildProduct *product, QMap<QString, QSet<Artifact *> > &artifactsPerFileTag, Rule::Ptr rule, const QSet<Artifact *> &inputArtifacts);
+ void createTransformerCommands(RuleScript::Ptr script, Transformer *transformer);
+ static void disconnect(Artifact *u, Artifact *v);
+ QSet<Artifact *> disconnect(Artifact *n) const;
+ void setupScriptEngineForArtifact(BuildProduct *product, Artifact *artifact);
+ void updateNodeThatMustGetNewTransformer(Artifact *artifact);
+ static void detectCycle(Artifact *v, QSet<Artifact *> &done, QSet<Artifact *> &currentBranch);
+
+private:
+ QString m_outputDirectoryRoot; /// The directory where the 'build' and 'targets' subdirectories end up.
+ QScriptEngine m_scriptEngine;
+ QHash<ResolvedProduct::Ptr, BuildProduct::Ptr> m_productCache;
+ QHash<QString, QScriptValue> m_jsImportCache;
+ QHash<QString, QScriptProgram> m_scriptProgramCache;
+ mutable QSet<Artifact *> m_artifactsThatMustGetNewTransformers;
+};
+
+// debugging helper
+QString fileName(Artifact *n);
+
+// debugging helper
+template <typename T>
+static QStringList toStringList(const T &artifactContainer)
+{
+ QStringList l;
+ foreach (Artifact *n, artifactContainer)
+ l.append(fileName(n));
+ return l;
+}
+
+char **createCFileTags(const QSet<QString> &fileTags);
+void freeCFileTags(char **cFileTags, int numFileTags);
+
+} // namespace qbs
+
+#endif // BUILDGRAPH_H
diff --git a/src/lib/buildgraph/buildgraph.pri b/src/lib/buildgraph/buildgraph.pri
new file mode 100644
index 000000000..779994a74
--- /dev/null
+++ b/src/lib/buildgraph/buildgraph.pri
@@ -0,0 +1,26 @@
+INCLUDEPATH += $$PWD
+SOURCES += \
+ $$PWD/automoc.cpp\
+ $$PWD/buildgraph.cpp\
+ $$PWD/executor.cpp\
+ $$PWD/executorjob.cpp\
+ $$PWD/rulegraph.cpp\
+ $$PWD/scanresultcache.cpp \
+ $$PWD/artifactlist.cpp \
+ $$PWD/command.cpp \
+ $$PWD/commandexecutor.cpp \
+ $$PWD/transformer.cpp \
+ $$PWD/artifact.cpp
+
+HEADERS += \
+ $$PWD/automoc.h\
+ $$PWD/buildgraph.h\
+ $$PWD/executor.h\
+ $$PWD/executorjob.h\
+ $$PWD/rulegraph.h\
+ $$PWD/scanresultcache.h \
+ $$PWD/artifactlist.h \
+ $$PWD/command.h \
+ $$PWD/commandexecutor.h \
+ $$PWD/transformer.h \
+ $$PWD/artifact.h
diff --git a/src/lib/buildgraph/command.cpp b/src/lib/buildgraph/command.cpp
new file mode 100644
index 000000000..189f04b50
--- /dev/null
+++ b/src/lib/buildgraph/command.cpp
@@ -0,0 +1,231 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "command.h"
+
+#include <QDebug>
+#include <QScriptEngine>
+#include <QtScript/QScriptValueIterator>
+
+namespace qbs {
+
+AbstractCommand::AbstractCommand()
+ : m_silent(true)
+{
+}
+
+AbstractCommand::~AbstractCommand()
+{
+}
+
+AbstractCommand *AbstractCommand::createByType(AbstractCommand::CommandType commandType)
+{
+ switch (commandType) {
+ case qbs::AbstractCommand::AbstractCommandType:
+ break;
+ case qbs::AbstractCommand::ProcessCommandType:
+ return new ProcessCommand;
+ case qbs::AbstractCommand::JavaScriptCommandType:
+ return new JavaScriptCommand;
+ }
+ return 0;
+}
+
+void AbstractCommand::fillFromScriptValue(const QScriptValue *scriptValue)
+{
+ m_description = scriptValue->property("description").toString();
+ m_highlight = scriptValue->property("highlight").toString();
+ m_silent = scriptValue->property("silent").toBool();
+}
+
+void AbstractCommand::load(QDataStream &s)
+{
+ s >> m_description >> m_highlight >> m_silent;
+}
+
+void AbstractCommand::store(QDataStream &s)
+{
+ s << m_description << m_highlight << m_silent;
+}
+
+static QScriptValue js_CommandBase(QScriptContext *context, QScriptEngine *engine)
+{
+ static AbstractCommand commandPrototype;
+ QScriptValue cmd = context->thisObject();
+ cmd.setProperty("description", engine->toScriptValue(commandPrototype.description()));
+ cmd.setProperty("highlight", engine->toScriptValue(commandPrototype.highlight()));
+ cmd.setProperty("silent", engine->toScriptValue(commandPrototype.isSilent()));
+ return cmd;
+}
+
+static QScriptValue js_Command(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() != 2) {
+ return context->throwError(QScriptContext::SyntaxError,
+ "Command c'tor expects 2 arguments");
+ }
+
+ static ProcessCommand commandPrototype;
+
+ QScriptValue program = context->argument(0);
+ if (program.isUndefined())
+ program = engine->toScriptValue(commandPrototype.program());
+ QScriptValue arguments = context->argument(1);
+ if (arguments.isUndefined())
+ arguments = engine->toScriptValue(commandPrototype.arguments());
+ QScriptValue cmd = js_CommandBase(context, engine);
+ cmd.setProperty("className", engine->toScriptValue(QString("Command")));
+ cmd.setProperty("program", program);
+ cmd.setProperty("arguments", arguments);
+ cmd.setProperty("workingDir", engine->toScriptValue(commandPrototype.workingDir()));
+ cmd.setProperty("maxExitCode", engine->toScriptValue(commandPrototype.maxExitCode()));
+ cmd.setProperty("stdoutFilterFunction", engine->toScriptValue(commandPrototype.stdoutFilterFunction()));
+ cmd.setProperty("stderrFilterFunction", engine->toScriptValue(commandPrototype.stderrFilterFunction()));
+ cmd.setProperty("responseFileThreshold", engine->toScriptValue(commandPrototype.responseFileThreshold()));
+ cmd.setProperty("responseFileUsagePrefix", engine->toScriptValue(commandPrototype.responseFileUsagePrefix()));
+ return cmd;
+}
+
+
+void ProcessCommand::setupForJavaScript(QScriptEngine *engine)
+{
+ QScriptValue ctor = engine->newFunction(js_Command, 2);
+ engine->globalObject().setProperty("Command", ctor);
+}
+
+ProcessCommand::ProcessCommand()
+ : m_maxExitCode(0),
+ m_responseFileThreshold(32000)
+{
+}
+
+void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue)
+{
+ AbstractCommand::fillFromScriptValue(scriptValue);
+ m_program = scriptValue->property("program").toString();
+ m_arguments = scriptValue->property("arguments").toVariant().toStringList();
+ m_workingDir = scriptValue->property("workingDirectory").toString();
+ m_maxExitCode = scriptValue->property("maxExitCode").toInt32();
+ m_stdoutFilterFunction = scriptValue->property("stdoutFilterFunction").toString();
+ m_stderrFilterFunction = scriptValue->property("stderrFilterFunction").toString();
+ m_responseFileThreshold = scriptValue->property("responseFileThreshold").toInt32();
+ m_responseFileUsagePrefix = scriptValue->property("responseFileUsagePrefix").toString();
+}
+
+void ProcessCommand::load(QDataStream &s)
+{
+ AbstractCommand::load(s);
+ s >> m_program
+ >> m_arguments
+ >> m_workingDir
+ >> m_maxExitCode
+ >> m_stdoutFilterFunction
+ >> m_stderrFilterFunction
+ >> m_responseFileThreshold
+ >> m_responseFileUsagePrefix;
+}
+
+void ProcessCommand::store(QDataStream &s)
+{
+ AbstractCommand::store(s);
+ s << m_program
+ << m_arguments
+ << m_workingDir
+ << m_maxExitCode
+ << m_stdoutFilterFunction
+ << m_stderrFilterFunction
+ << m_responseFileThreshold
+ << m_responseFileUsagePrefix;
+}
+
+static QScriptValue js_JavaScriptCommand(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() != 0) {
+ return context->throwError(QScriptContext::SyntaxError,
+ "JavaScriptCommand c'tor doesn't take arguments.");
+ }
+
+ static JavaScriptCommand commandPrototype;
+ QScriptValue cmd = js_CommandBase(context, engine);
+ cmd.setProperty("className", engine->toScriptValue(QString("JavaScriptCommand")));
+ cmd.setProperty("sourceCode", engine->toScriptValue(commandPrototype.sourceCode()));
+ return cmd;
+}
+
+void JavaScriptCommand::setupForJavaScript(QScriptEngine *engine)
+{
+ QScriptValue ctor = engine->newFunction(js_JavaScriptCommand, 0);
+ engine->globalObject().setProperty("JavaScriptCommand", ctor);
+}
+
+JavaScriptCommand::JavaScriptCommand()
+{
+}
+
+void JavaScriptCommand::fillFromScriptValue(const QScriptValue *scriptValue)
+{
+ AbstractCommand::fillFromScriptValue(scriptValue);
+ QScriptValue sourceCode = scriptValue->property("sourceCode");
+ if (sourceCode.isFunction()) {
+ m_sourceCode = "(" + sourceCode.toString() + ")()";
+ } else {
+ m_sourceCode = sourceCode.toString();
+ }
+ static QSet<QString> predefinedProperties = QSet<QString>()
+ << "description" << "highlight" << "silent" << "className" << "sourceCode";
+
+ QScriptValueIterator it(*scriptValue);
+ while (it.hasNext()) {
+ it.next();
+ if (predefinedProperties.contains(it.name()))
+ continue;
+ m_properties.insert(it.name(), it.value().toVariant());
+ }
+}
+
+void JavaScriptCommand::load(QDataStream &s)
+{
+ AbstractCommand::load(s);
+ s >> m_sourceCode >> m_properties;
+}
+
+void JavaScriptCommand::store(QDataStream &s)
+{
+ AbstractCommand::store(s);
+ s << m_sourceCode << m_properties;
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/command.h b/src/lib/buildgraph/command.h
new file mode 100644
index 000000000..14bd11f00
--- /dev/null
+++ b/src/lib/buildgraph/command.h
@@ -0,0 +1,154 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#include <QtCore/QStringList>
+#include <QtCore/QVariantMap>
+
+QT_BEGIN_NAMESPACE
+class QScriptEngine;
+class QScriptValue;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class AbstractCommand
+{
+public:
+ AbstractCommand();
+ virtual ~AbstractCommand();
+
+ enum CommandType {
+ AbstractCommandType,
+ ProcessCommandType,
+ JavaScriptCommandType
+ };
+
+ static AbstractCommand *createByType(CommandType commandType);
+
+ virtual CommandType type() const { return AbstractCommandType; }
+ virtual void fillFromScriptValue(const QScriptValue *scriptValue);
+ virtual void load(QDataStream &s);
+ virtual void store(QDataStream &s);
+
+ const QString description() const { return m_description; }
+ void setDescription(const QString &str) { m_description = str; }
+
+ const QString highlight() const { return m_highlight; }
+ void setHighlight(const QString &str) { m_highlight = str; }
+
+ bool isSilent() const { return m_silent; }
+ void setSilent(bool b) { m_silent = b; }
+
+private:
+ QString m_description;
+ QString m_highlight;
+ bool m_silent;
+};
+
+class ProcessCommand : public AbstractCommand
+{
+public:
+ static void setupForJavaScript(QScriptEngine *engine);
+
+ ProcessCommand();
+
+ CommandType type() const { return ProcessCommandType; }
+ void fillFromScriptValue(const QScriptValue *scriptValue);
+ void load(QDataStream &s);
+ void store(QDataStream &s);
+
+ const QString program() const { return m_program; }
+ void setProgram(const QString &str) { m_program = str; }
+
+ const QStringList arguments() const { return m_arguments; }
+ void setArguments(const QStringList &l) { m_arguments = l; }
+
+ const QString workingDir() const { return m_workingDir; }
+ void setWorkingDir(const QString &str) { m_workingDir = str; }
+
+ int maxExitCode() const { return m_maxExitCode; }
+ void setMaxExitCode(int n) { m_maxExitCode = n; }
+
+ QString stdoutFilterFunction() const { return m_stdoutFilterFunction; }
+ void setStdoutFilterFunction(const QString &filter) { m_stdoutFilterFunction = filter; }
+
+ QString stderrFilterFunction() const { return m_stderrFilterFunction; }
+ void setStderrFilterFunction(const QString &filter) { m_stderrFilterFunction = filter; }
+
+ int responseFileThreshold() const { return m_responseFileThreshold; }
+ void setResponseFileThreshold(int n) { m_responseFileThreshold = n; }
+
+ QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; }
+ void setResponseFileUsagePrefix(const QString &function) { m_responseFileUsagePrefix = function; }
+
+private:
+ QString m_program;
+ QStringList m_arguments;
+ QString m_workingDir;
+ int m_maxExitCode;
+ QString m_stdoutFilterFunction;
+ QString m_stderrFilterFunction;
+ int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments).
+ QString m_responseFileUsagePrefix;
+};
+
+class JavaScriptCommand : public AbstractCommand
+{
+public:
+ static void setupForJavaScript(QScriptEngine *engine);
+
+ JavaScriptCommand();
+
+ virtual CommandType type() const { return JavaScriptCommandType; }
+ void fillFromScriptValue(const QScriptValue *scriptValue);
+ void load(QDataStream &s);
+ void store(QDataStream &s);
+
+ const QString &sourceCode() const { return m_sourceCode; }
+ void setSourceCode(const QString &str) { m_sourceCode = str; }
+ const QVariantMap &properties() const { return m_properties; }
+
+private:
+ QString m_sourceCode;
+ QVariantMap m_properties;
+};
+
+} // namespace qbs
+
+#endif // COMMAND_H
diff --git a/src/lib/buildgraph/commandexecutor.cpp b/src/lib/buildgraph/commandexecutor.cpp
new file mode 100644
index 000000000..7a72a6c98
--- /dev/null
+++ b/src/lib/buildgraph/commandexecutor.cpp
@@ -0,0 +1,376 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "commandexecutor.h"
+#include "command.h"
+#include "buildgraph.h"
+#include "processoutput.h"
+
+#include <buildgraph/artifact.h>
+#include <buildgraph/transformer.h>
+#include <tools/logger.h>
+
+#include <QtConcurrentRun>
+#include <QDebug>
+#include <QFutureWatcher>
+#include <QProcess>
+#include <QScriptEngine>
+#include <QThread>
+#include <QTemporaryFile>
+
+namespace qbs {
+
+struct JavaScriptCommandFutureResult
+{
+ bool success;
+ QString errorMessage;
+};
+
+class JavaScriptCommandFutureWatcher : public QFutureWatcher<JavaScriptCommandFutureResult>
+{
+public:
+ JavaScriptCommandFutureWatcher(QObject *parent)
+ : QFutureWatcher<JavaScriptCommandFutureResult>(parent)
+ {}
+};
+
+CommandExecutor::CommandExecutor(QObject *parent)
+ : QObject(parent)
+ , m_processCommand(0)
+ , m_process(0)
+ , m_mainThreadScriptEngine(0)
+ , m_transformer(0)
+ , m_jsCommand(0)
+ , m_jsFutureWatcher(0)
+{
+ connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onProcessError(QProcess::ProcessError)));
+ connect(&m_process, SIGNAL(finished(int)), this, SLOT(onProcessFinished(int)));
+}
+
+void CommandExecutor::setProcessEnvironment(const QProcessEnvironment &processEnvironment)
+{
+ m_process.setProcessEnvironment(processEnvironment);
+}
+
+void CommandExecutor::waitForFinished()
+{
+ if (m_process.state() == QProcess::Running)
+ m_process.waitForFinished(-1);
+ if (m_jsFutureWatcher && m_jsFutureWatcher->isRunning())
+ m_jsFutureWatcher->waitForFinished();
+}
+
+void CommandExecutor::start(Transformer *transformer, AbstractCommand *cmd)
+{
+ m_processCommand = 0;
+ m_jsCommand = 0;
+
+ switch (cmd->type()) {
+ case AbstractCommand::AbstractCommandType:
+ qWarning("CommandExecutor can't execute abstract commands.");
+ return;
+ case AbstractCommand::ProcessCommandType:
+ m_processCommand = static_cast<ProcessCommand*>(cmd);
+ startProcessCommand();
+ return;
+ case AbstractCommand::JavaScriptCommandType:
+ m_jsCommand = static_cast<JavaScriptCommand*>(cmd);
+ m_transformer = transformer;
+ startJavaScriptCommand();
+ return;
+ }
+
+ emit error("CommandExecutor: unknown command type.");
+ return;
+}
+
+static QHash<QString, TextColor> setupColorTable()
+{
+ QHash<QString, TextColor> colorTable;
+ colorTable["compiler"] = TextColorDefault;
+ colorTable["linker"] = TextColorDarkGreen;
+ colorTable["codegen"] = TextColorDarkYellow;
+ return colorTable;
+}
+
+void CommandExecutor::printCommandInfo(AbstractCommand *cmd)
+{
+ if (!cmd->description().isEmpty()) {
+ static QHash<QString, TextColor> colorTable = setupColorTable();
+ qbsInfo() << DontPrintLogLevel << LogOutputStdOut
+ << colorTable.value(cmd->highlight(), TextColorDefault)
+ << cmd->description();
+ }
+}
+
+void CommandExecutor::startProcessCommand()
+{
+ Q_ASSERT(m_process.state() == QProcess::NotRunning);
+
+ printCommandInfo(m_processCommand);
+ if (!m_processCommand->isSilent()) {
+ QString commandLine = m_processCommand->program() + QLatin1Char(' ') + m_processCommand->arguments().join(" ");
+ qbsInfo() << DontPrintLogLevel << LogOutputStdOut << commandLine;
+ }
+ if (qbsLogLevel(LoggerDebug)) {
+ qbsDebug() << "[EXEC] " << m_processCommand->program() + QLatin1Char(' ') + m_processCommand->arguments().join(" ");
+ }
+
+ // Automatically use response files, if the command line gets to long.
+ QStringList arguments = m_processCommand->arguments();
+ if (!m_processCommand->responseFileUsagePrefix().isEmpty()) {
+ int commandLineLength = m_processCommand->program().length() + 1;
+ for (int i = m_processCommand->arguments().count(); --i >= 0;)
+ commandLineLength += m_processCommand->arguments().at(i).length();
+ if (m_processCommand->responseFileThreshold() >= 0 && commandLineLength > m_processCommand->responseFileThreshold()) {
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] Using response file. Threshold is %d. Command line length %d.", m_processCommand->responseFileThreshold(), commandLineLength);
+
+ // The QTemporaryFile keeps a handle on the file, even if closed.
+ // On Windows, some commands (e.g. msvc link.exe) won't accept that.
+ // We need to delete the file manually, later.
+ QTemporaryFile responseFile;
+ responseFile.setAutoRemove(false);
+ responseFile.setFileTemplate(QDir::tempPath() + "/qbsresp");
+ if (!responseFile.open()) {
+ QString errorMessage = "Cannot create response file.";
+ emit error(errorMessage);
+ return;
+ }
+ for (int i = 0; i < m_processCommand->arguments().count(); ++i) {
+ responseFile.write(m_processCommand->arguments().at(i).toLocal8Bit());
+ responseFile.write("\n");
+ }
+ responseFile.close();
+ arguments.clear();
+ arguments += QDir::toNativeSeparators(m_processCommand->responseFileUsagePrefix() + responseFile.fileName());
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] command line with response file: %s %s", qPrintable(m_processCommand->program()), qPrintable(arguments.join(" ")));
+ }
+ }
+
+ m_process.setWorkingDirectory(m_processCommand->workingDir());
+ m_process.start(m_processCommand->program(), arguments);
+}
+
+QByteArray CommandExecutor::filterProcessOutput(const QByteArray &output, const QString &filterFunctionSource)
+{
+ if (filterFunctionSource.isEmpty())
+ return output;
+
+ QScriptValue filterFunction = m_mainThreadScriptEngine->evaluate("var f = " + filterFunctionSource + "; f");
+ if (!filterFunction.isFunction()) {
+ emit error(QString("Error in filter function: %1.\n%2").arg(filterFunctionSource, filterFunction.toString()));
+ return output;
+ }
+
+ QScriptValue outputArg = m_mainThreadScriptEngine->newArray(1);
+ outputArg.setProperty(0, m_mainThreadScriptEngine->toScriptValue(QString::fromLatin1(output)));
+ QScriptValue filteredOutput = filterFunction.call(m_mainThreadScriptEngine->undefinedValue(), outputArg);
+ if (filteredOutput.isError()) {
+ emit error(QString("Error when calling ouput filter function: %1").arg(filteredOutput.toString()));
+ return output;
+ }
+
+ return filteredOutput.toString().toLocal8Bit();
+}
+
+void CommandExecutor::sendProcessOutput(bool logCommandLine)
+{
+ QString commandLine = m_processCommand->program();
+ if (!m_processCommand->arguments().isEmpty()) {
+ commandLine += ' ';
+ commandLine += m_processCommand->arguments().join(" ");
+ }
+
+ QByteArray processStdOut = filterProcessOutput(m_process.readAllStandardOutput(), m_processCommand->stdoutFilterFunction());
+ QByteArray processStdErr = filterProcessOutput(m_process.readAllStandardError(), m_processCommand->stderrFilterFunction());
+
+ bool processOutputEmpty = processStdOut.isEmpty() && processStdErr.isEmpty();
+ if (logCommandLine || !processOutputEmpty) {
+ qbsInfo() << DontPrintLogLevel << commandLine << (processOutputEmpty ? "" : "\n")
+ << processStdOut << processStdErr;
+ }
+
+ ProcessOutput processOutput;
+ processOutput.setCommandLine(commandLine);
+ processOutput.setStandardOutput(processStdOut);
+ processOutput.setStandardError(processStdErr);
+ Logger::instance().sendProcessOutput(processOutput);
+}
+
+void CommandExecutor::onProcessError(QProcess::ProcessError processError)
+{
+ removeResponseFile();
+ sendProcessOutput(true);
+ QString errorMessage;
+ switch (processError) {
+ case QProcess::FailedToStart:
+ errorMessage = "Process could not be started.";
+ break;
+ case QProcess::Crashed:
+ errorMessage = "Process crashed.";
+ break;
+ case QProcess::Timedout:
+ errorMessage = "Process timed out.";
+ break;
+ case QProcess::ReadError:
+ errorMessage = "Error when reading process output.";
+ break;
+ case QProcess::WriteError:
+ errorMessage = "Error when writing to process.";
+ break;
+ default:
+ errorMessage = "Unknown process error.";
+ break;
+ }
+ emit error(errorMessage);
+}
+
+void CommandExecutor::onProcessFinished(int exitCode)
+{
+ removeResponseFile();
+ bool errorOccurred = exitCode > m_processCommand->maxExitCode();
+ sendProcessOutput(errorOccurred);
+ if (errorOccurred) {
+ QString msg = "Process failed with exit code %1.";
+ emit error(msg.arg(exitCode));
+ return;
+ }
+
+ emit finished();
+}
+
+class JSRunner
+{
+public:
+ typedef JavaScriptCommandFutureResult result_type;
+
+ JSRunner(JavaScriptCommand *jsCommand)
+ : m_jsCommand(jsCommand)
+ {}
+
+ JavaScriptCommandFutureResult operator() (Transformer *transformer)
+ {
+ result_type result;
+ result.success = true;
+ QThread *currentThread = QThread::currentThread();
+ QScriptEngine *scriptEngine = m_scriptEnginesPerThread.value(currentThread);
+ if (!scriptEngine) {
+ scriptEngine = new QScriptEngine();
+ m_scriptEnginesPerThread.insert(currentThread, scriptEngine);
+
+ // import script extension plugins
+ foreach (const QString &name, scriptEngine->availableExtensions()) {
+ if (!name.startsWith("qbs"))
+ continue;
+ QScriptValue e = scriptEngine->importExtension(name);
+ if (e.isError()) {
+ qbsWarning("JS thread %x, unable to load %s into QScriptEngine: %s",
+ (void*)currentThread,
+ qPrintable(name),
+ qPrintable(e.toString()));
+ }
+ qbsDebug("JS thread %x, script plugin loaded: %s", (void*)currentThread, qPrintable(name));
+ }
+ }
+
+ QString trafoPtrStr = QString::number((qulonglong)transformer);
+ if (scriptEngine->globalObject().property("_qbs_transformer_ptr").toString() != trafoPtrStr) {
+ scriptEngine->globalObject().setProperty("_qbs_transformer_ptr", scriptEngine->toScriptValue(trafoPtrStr));
+
+ Artifact *someOutputArtifact = *transformer->outputs.begin();
+ if (someOutputArtifact->product) {
+ ResolvedProduct::Ptr product = someOutputArtifact->product->rProduct;
+ BuildGraph::setupScriptEngineForProduct(scriptEngine, product, transformer->rule);
+ }
+ transformer->setupInputs(scriptEngine, scriptEngine->globalObject());
+ transformer->setupOutputs(scriptEngine, scriptEngine->globalObject());
+ }
+
+ scriptEngine->pushContext();
+ for (QVariantMap::const_iterator it = m_jsCommand->properties().constBegin(); it != m_jsCommand->properties().constEnd(); ++it)
+ scriptEngine->currentContext()->activationObject().setProperty(it.key(), scriptEngine->toScriptValue(it.value()));
+ scriptEngine->evaluate(m_jsCommand->sourceCode());
+ if (scriptEngine->hasUncaughtException()) {
+ result.success = false;
+ result.errorMessage = scriptEngine->uncaughtException().toString();
+ }
+ scriptEngine->popContext();
+ return result;
+ }
+
+private:
+ static QHash<QThread *, QScriptEngine *> m_scriptEnginesPerThread;
+ JavaScriptCommand *m_jsCommand;
+};
+
+QHash<QThread *, QScriptEngine *> JSRunner::m_scriptEnginesPerThread;
+
+void CommandExecutor::startJavaScriptCommand()
+{
+ printCommandInfo(m_jsCommand);
+ QFuture<JSRunner::result_type> future = QtConcurrent::run(JSRunner(m_jsCommand), m_transformer);
+ if (!m_jsFutureWatcher) {
+ m_jsFutureWatcher = new JavaScriptCommandFutureWatcher(this);
+ connect(m_jsFutureWatcher, SIGNAL(finished()), SLOT(onJavaScriptCommandFinished()));
+ }
+ m_jsFutureWatcher->setFuture(future);
+}
+
+void CommandExecutor::onJavaScriptCommandFinished()
+{
+ JavaScriptCommandFutureResult result = m_jsFutureWatcher->future().result();
+ if (result.success) {
+ emit finished();
+ } else {
+ qbsInfo() << DontPrintLogLevel << "JS context:\n" << m_jsCommand->properties();
+ qbsInfo() << DontPrintLogLevel << "JS code:\n" << m_jsCommand->sourceCode();
+ QString msg = "Error while executing JavaScriptCommand: ";
+ msg += result.errorMessage;
+ emit error(msg);
+ }
+}
+
+void CommandExecutor::removeResponseFile()
+{
+ if (m_responseFileName.isEmpty())
+ return;
+ QFile::remove(m_responseFileName);
+ m_responseFileName.clear();
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/commandexecutor.h b/src/lib/buildgraph/commandexecutor.h
new file mode 100644
index 000000000..3b5a1273f
--- /dev/null
+++ b/src/lib/buildgraph/commandexecutor.h
@@ -0,0 +1,106 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef COMMANDEXECUTOR_H
+#define COMMANDEXECUTOR_H
+
+#include <QObject>
+#include <QProcess>
+
+QT_BEGIN_NAMESPACE
+class QProcess;
+class QScriptEngine;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class AbstractCommand;
+class ProcessCommand;
+class JavaScriptCommand;
+class JavaScriptCommandFutureWatcher;
+class Transformer;
+
+class CommandExecutor : public QObject
+{
+ Q_OBJECT
+public:
+ explicit CommandExecutor(QObject *parent = 0);
+
+ void setMainThreadScriptEngine(QScriptEngine *engine) { m_mainThreadScriptEngine = engine; }
+ void setDryRunEnabled(bool enabled) { dryRun = enabled; }
+ void setProcessEnvironment(const QProcessEnvironment &processEnvironment);
+ void waitForFinished();
+
+signals:
+ void error(QString errorString);
+ void finished();
+
+public slots:
+ void start(Transformer *transformer, AbstractCommand *cmd);
+
+protected:
+ void printCommandInfo(AbstractCommand *cmd);
+ void startProcessCommand();
+ QByteArray filterProcessOutput(const QByteArray &output, const QString &filterFunctionSource);
+ void sendProcessOutput(bool logCommandLine = false);
+ void startJavaScriptCommand();
+
+protected slots:
+ void onProcessError(QProcess::ProcessError);
+ void onProcessFinished(int exitCode);
+ void onJavaScriptCommandFinished();
+
+private:
+ void removeResponseFile();
+
+private:
+ bool dryRun;
+
+ // members for executing ProcessCommand
+ ProcessCommand *m_processCommand;
+ QProcess m_process;
+ QString m_responseFileName;
+ QScriptEngine *m_mainThreadScriptEngine;
+
+ // members for executing JavaScriptCommand members
+ Transformer *m_transformer;
+ JavaScriptCommand *m_jsCommand;
+ JavaScriptCommandFutureWatcher *m_jsFutureWatcher;
+};
+
+} // namespace qbs
+
+#endif // COMMANDEXECUTOR_H
diff --git a/src/lib/buildgraph/executor.cpp b/src/lib/buildgraph/executor.cpp
new file mode 100644
index 000000000..4b3e8b38b
--- /dev/null
+++ b/src/lib/buildgraph/executor.cpp
@@ -0,0 +1,885 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "executor.h"
+#include "executorjob.h"
+#include "scanresultcache.h"
+#include "automoc.h"
+
+#include <buildgraph/transformer.h>
+#include <language/language.h>
+#include <tools/fileinfo.h>
+#include <tools/logger.h>
+#include <tools/scannerpluginmanager.h>
+
+#ifdef Q_OS_WIN32
+#include <Windows.h>
+#endif
+
+namespace qbs {
+
+static QHashDummyValue hashDummy;
+
+Executor::Executor(int maxJobs)
+ : m_scriptEngine(0)
+ , m_runOnceAndForgetMode(false)
+ , m_state(ExecutorIdle)
+ , m_keepGoing(false)
+ , m_maximumJobNumber(maxJobs)
+ , m_futureInterface(0)
+{
+ m_autoMoc = new AutoMoc;
+ m_autoMoc->setScanResultCache(&m_scanResultCache);
+ if (!m_runOnceAndForgetMode) {
+ connect(this, SIGNAL(finished()), SLOT(resetArtifactsToUntouched()));
+ }
+ qbsDebug("[EXEC] preparing executor for %d jobs in parallel", maxJobs);
+ addExecutorJobs(maxJobs);
+}
+
+Executor::~Executor()
+{
+ // jobs must be destroyed before deleting the shared scan result cache
+ foreach (ExecutorJob *job, m_availableJobs)
+ delete job;
+ foreach (ExecutorJob *job, m_processingJobs.keys())
+ delete job;
+ delete m_autoMoc;
+}
+
+void Executor::build(const QList<BuildProject::Ptr> projectsToBuild, const QStringList &changedFiles, const QStringList &selectedProductNames,
+ QFutureInterface<bool> &futureInterface)
+{
+ Q_ASSERT(m_state != ExecutorRunning);
+ m_leaves.clear();
+ m_futureInterface = &futureInterface;
+ bool success = true;
+
+ setState(ExecutorRunning);
+ Artifact::BuildState initialBuildState = changedFiles.isEmpty() ? Artifact::Buildable : Artifact::Built;
+
+ if (!m_scriptEngine) {
+ m_scriptEngine = new QScriptEngine(this);
+ foreach (ExecutorJob *job, findChildren<ExecutorJob *>())
+ job->setMainThreadScriptEngine(m_scriptEngine);
+ }
+
+ // determine the products we want to build
+ m_projectsToBuild = projectsToBuild;
+ if (selectedProductNames.isEmpty()) {
+ // Use all products we have in the build graph.
+ m_productsToBuild.clear();
+ foreach (BuildProject::Ptr project, m_projectsToBuild)
+ foreach (BuildProduct::Ptr product, project->buildProducts())
+ m_productsToBuild += product;
+ } else {
+ // Try to find the selected products and their dependencies.
+ QHash<QString, BuildProduct::Ptr> productsPerName;
+ foreach (BuildProject::Ptr project, m_projectsToBuild)
+ foreach (BuildProduct::Ptr product, project->buildProducts())
+ productsPerName.insert(product->rProduct->name.toLower(), product);
+
+ QSet<BuildProduct::Ptr> selectedProducts;
+ foreach (const QString &productName, selectedProductNames) {
+ BuildProduct::Ptr product = productsPerName.value(productName.toLower());
+ if (!product) {
+ qbsWarning() << "Selected product " << productName << " not found.";
+ continue;
+ }
+ selectedProducts += product;
+ }
+ QSet<BuildProduct::Ptr> s = selectedProducts;
+ do {
+ QSet<BuildProduct::Ptr> t;
+ foreach (const BuildProduct::Ptr &product, s)
+ foreach (BuildProduct *dependency, product->usings)
+ t += productsPerName.value(dependency->rProduct->name.toLower());
+ selectedProducts += t;
+ s = t;
+ } while (!s.isEmpty());
+ m_productsToBuild = selectedProducts.toList();
+ }
+
+ QList<Artifact *> changedArtifacts;
+ foreach (const QString &filePath, changedFiles) {
+ Artifact *artifact = 0;
+ foreach (BuildProject::Ptr project, m_projectsToBuild) {
+ artifact = project->findArtifact(filePath);
+ if (artifact)
+ break;
+ }
+ if (!artifact) {
+ qbsWarning() << QString("Out of date file '%1' provided but not found.").arg(QDir::toNativeSeparators(filePath));
+ continue;
+ }
+ changedArtifacts += artifact;
+ }
+
+ // prepare products
+ const QProcessEnvironment systemEnvironment = QProcessEnvironment::systemEnvironment();
+ foreach (BuildProduct::Ptr product, m_productsToBuild) {
+ try {
+ product->rProduct->setupBuildEnvironment(m_scriptEngine, systemEnvironment);
+ } catch (Error &e) {
+ setError(e.toString());
+ return;
+ }
+ foreach (Artifact *artifact, product->artifacts)
+ if (artifact->artifactType == Artifact::SourceFile)
+ artifact->buildState = initialBuildState;
+ }
+
+ // find the root nodes
+ m_roots.clear();
+ foreach (BuildProduct::Ptr product, m_productsToBuild)
+ foreach (Artifact *rootArtifact, product->targetArtifacts)
+ m_roots += rootArtifact;
+
+ // mark the artifacts we want to build
+ prepareBuildGraph(initialBuildState);
+
+ // determine which artifacts are out of date
+ const bool changedFilesProvided = !changedFiles.isEmpty();
+ if (!changedFilesProvided) {
+ doOutOfDateCheck();
+ }
+
+ if (success)
+ success = runAutoMoc();
+ if (success) {
+ if (changedFilesProvided) {
+ foreach (Artifact *artifact, changedArtifacts)
+ scanFileDependencies(artifact);
+ } else {
+ doDependencyScanTopDown();
+ updateBuildGraph(initialBuildState);
+ }
+ initLeaves(changedArtifacts);
+ }
+
+ m_futureInterface->setProgressRange(0 , m_leaves.count());
+
+ if (success) {
+ bool stillArtifactsToExecute = run(futureInterface);
+
+ if (!stillArtifactsToExecute)
+ finish();
+ }
+}
+
+void Executor::setDryRun(bool b)
+{
+ foreach (ExecutorJob *job, m_availableJobs)
+ job->setDryRun(b);
+}
+
+void Executor::setMaximumJobs(int numberOfJobs)
+{
+ if (numberOfJobs == m_maximumJobNumber)
+ return;
+
+ m_maximumJobNumber = numberOfJobs;
+ int actualJobNumber = m_availableJobs.count() + m_processingJobs.count();
+ if (actualJobNumber > m_maximumJobNumber) {
+ removeExecutorJobs(actualJobNumber - m_maximumJobNumber);
+ } else {
+ addExecutorJobs(m_maximumJobNumber - actualJobNumber);
+ }
+}
+
+int Executor::maximumJobs() const
+{
+ return m_maximumJobNumber;
+}
+
+bool Executor::isLeaf(Artifact *artifact)
+{
+ foreach (Artifact *child, artifact->children)
+ if (child->buildState != Artifact::Built)
+ return false;
+ return true;
+}
+
+static void markAsOutOfDateBottomUp(Artifact *artifact)
+{
+ if (artifact->buildState == Artifact::Untouched)
+ return;
+ artifact->buildState = Artifact::Buildable;
+ artifact->outOfDateCheckPerformed = true;
+ artifact->isOutOfDate = true;
+ artifact->isExistingFile = FileInfo(artifact->fileName).exists();
+ foreach (Artifact *parent, artifact->parents)
+ markAsOutOfDateBottomUp(parent);
+}
+
+void Executor::initLeaves(const QList<Artifact *> &changedArtifacts)
+{
+ if (changedArtifacts.isEmpty()) {
+ QSet<Artifact *> seenArtifacts;
+ foreach (Artifact *root, m_roots)
+ initLeavesTopDown(root, seenArtifacts);
+ } else {
+ foreach (Artifact *artifact, changedArtifacts) {
+ m_leaves.insert(artifact, hashDummy);
+ markAsOutOfDateBottomUp(artifact);
+ }
+ }
+}
+
+void Executor::initLeavesTopDown(Artifact *artifact, QSet<Artifact *> &seenArtifacts)
+{
+ if (seenArtifacts.contains(artifact))
+ return;
+ seenArtifacts += artifact;
+
+
+ if (artifact->children.isEmpty()) {
+ m_leaves.insert(artifact, hashDummy);
+ } else {
+ foreach (Artifact *child, artifact->children)
+ initLeavesTopDown(child, seenArtifacts);
+ }
+}
+
+/**
+ * Returns true if there are still artifacts to traverse.
+ */
+bool Executor::run(QFutureInterface<bool> &futureInterface)
+{
+ while (m_state == ExecutorRunning) {
+ if (m_futureInterface->isCanceled()) {
+ qbsInfo() << "Build canceled.";
+ cancelJobs();
+ return false;
+ }
+
+ futureInterface.setProgressValue(futureInterface.progressValue() + 1);
+ if (m_leaves.isEmpty())
+ return !m_processingJobs.isEmpty();
+
+ Artifact *leaf = m_leaves.begin().key();
+ if (!execute(leaf))
+ return true;
+ }
+ return false;
+}
+
+FileTime Executor::timeStamp(Artifact *artifact)
+{
+ FileTime result = m_timeStampCache.value(artifact);
+ if (result.isValid())
+ return result;
+
+ FileInfo fi(artifact->fileName);
+ if (!fi.exists())
+ return FileTime::currentTime();
+
+ result = fi.lastModified();
+ foreach (Artifact *child, artifact->children) {
+ const FileTime childTime = timeStamp(child);
+ if (result < childTime)
+ result = childTime;
+ }
+ foreach (Artifact *fileDependency, artifact->fileDependencies) {
+ const FileTime ft = timeStamp(fileDependency);
+ if (result < ft)
+ result = ft;
+ }
+
+ m_timeStampCache.insert(artifact, result);
+ return result;
+}
+
+bool Executor::isOutOfDate(Artifact *artifact, bool &fileExists)
+{
+ FileInfo fi(artifact->fileName);
+ fileExists = fi.exists();
+ if (!fileExists)
+ return true;
+
+ FileTime artifactTimeStamp = fi.lastModified();
+ foreach (Artifact *child, artifact->children) {
+ if (artifactTimeStamp < timeStamp(child))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Returns false if the artifact cannot be executed right now
+ * and should be looked at later.
+ */
+bool Executor::execute(Artifact *artifact)
+{
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug() << "[EXEC] " << fileName(artifact);
+
+// artifact->project->buildGraph()->dump(*artifact->products.begin());
+
+ if (m_availableJobs.isEmpty()) {
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] No jobs available. Trying later.");
+ return false;
+ }
+
+ if (!artifact->outOfDateCheckPerformed)
+ doOutOfDateCheck(artifact);
+ bool fileExists = artifact->isExistingFile;
+ bool isDirty = artifact->isOutOfDate;
+ m_leaves.remove(artifact);
+
+ if (!fileExists && artifact->artifactType == Artifact::SourceFile) {
+ setError(QString("Can't find source file '%1'.").arg(artifact->fileName));
+ return true;
+ }
+
+ if (!artifact->transformer) {
+ if (!fileExists)
+ qbsWarning() << tr("No transformer builds '%1'").arg(QDir::toNativeSeparators(artifact->fileName));
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] No transformer. Skipping.");
+ finishArtifact(artifact);
+ return true;
+ } else if (!isDirty) {
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] Up to date. Skipping.");
+ finishArtifact(artifact);
+ return true;
+ } else {
+ foreach (Artifact *sideBySideArtifact, artifact->sideBySideArtifacts) {
+ if (sideBySideArtifact->transformer != artifact->transformer)
+ continue;
+ switch (sideBySideArtifact->buildState)
+ {
+ case Artifact::Untouched:
+ case Artifact::Buildable:
+ break;
+ case Artifact::Built:
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] Side by side artifact already finished. Skipping.");
+ finishArtifact(artifact);
+ return true;
+ case Artifact::Building:
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] Side by side artifact processing. Skipping.");
+ artifact->buildState = Artifact::Building;
+ return true;
+ }
+ }
+
+ foreach (Artifact *output, artifact->transformer->outputs) {
+ // create the output directories
+ QDir outDir = QFileInfo(output->fileName).absoluteDir();
+ if (!outDir.exists())
+ outDir.mkpath(".");
+ }
+
+ ExecutorJob *job = m_availableJobs.takeFirst();
+ artifact->buildState = Artifact::Building;
+ m_processingJobs.insert(job, artifact);
+
+ if (!artifact->product)
+ qbsError() << QString("BUG: Generated artifact %1 belongs to no product.").arg(QDir::toNativeSeparators(artifact->fileName));
+
+ job->run(artifact->transformer.data(), artifact->product);
+ }
+
+ return true;
+}
+
+void Executor::finishArtifact(Artifact *leaf)
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[EXEC] finishArtifact " << fileName(leaf);
+
+ leaf->buildState = Artifact::Built;
+ foreach (Artifact *parent, leaf->parents) {
+ if (parent->buildState != Artifact::Buildable)
+ continue;
+
+ if (isLeaf(parent)) {
+ m_leaves.insert(parent, hashDummy);
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[EXEC] finishArtifact adds leaf " << fileName(parent) << " " << toString(parent->buildState);
+ }
+ }
+
+ foreach (Artifact *sideBySideArtifact, leaf->sideBySideArtifacts)
+ if (leaf->transformer == sideBySideArtifact->transformer && sideBySideArtifact->buildState == Artifact::Building)
+ finishArtifact(sideBySideArtifact);
+}
+
+void Executor::handleDependencies(Artifact *processedArtifact, Artifact *scannedArtifact, const QSet<QString> &resolvedDependencies)
+{
+ qbsTrace() << "[DEPSCAN] dependencies found for '" << fileName(scannedArtifact)
+ << "' while processing '" << fileName(processedArtifact) << "'";
+
+ foreach (const QString &dependencyFilePath, resolvedDependencies)
+ handleDependency(processedArtifact, dependencyFilePath);
+}
+
+void Executor::handleDependency(Artifact *processedArtifact, const QString &dependencyFilePath)
+{
+ BuildProduct *product = processedArtifact->product;
+ Artifact *dependency = 0;
+ bool insertIntoProduct = true;
+ Q_ASSERT(processedArtifact->artifactType == Artifact::Generated);
+ Q_CHECK_PTR(processedArtifact->product);
+ if ((dependency = product->artifacts.value(dependencyFilePath))) {
+ qbsTrace("[DEPSCAN] ok in product '%s'", qPrintable(dependencyFilePath));
+ insertIntoProduct = false;
+ } else if ((dependency = processedArtifact->project->dependencyArtifacts().value(dependencyFilePath))) {
+ qbsTrace("[DEPSCAN] ok in deps '%s'", qPrintable(dependencyFilePath));
+ } else {
+ // try to find the dependency in other products of this project
+ foreach (BuildProduct::Ptr otherProduct, product->project->buildProducts()) {
+ if (otherProduct == product)
+ continue;
+ if ((dependency = otherProduct->artifacts.value(dependencyFilePath))) {
+ insertIntoProduct = false;
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace("[DEPSCAN] found in product '%s': '%s'", qPrintable(otherProduct->rProduct->name), qPrintable(dependencyFilePath));
+ break;
+ }
+ }
+ }
+
+ // dependency not found in the whole build graph, thus create a new artifact
+ if (!dependency) {
+ qbsTrace("[DEPSCAN] + '%s'", qPrintable(dependencyFilePath));
+ dependency = new Artifact(processedArtifact->project);
+ dependency->artifactType = Artifact::FileDependency;
+ dependency->configuration = processedArtifact->configuration;
+ dependency->fileName = dependencyFilePath;
+ processedArtifact->project->dependencyArtifacts().insert(dependencyFilePath, dependency);
+ }
+
+ if (processedArtifact == dependency)
+ return;
+
+ if (dependency->artifactType == Artifact::FileDependency) {
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[DEPSCAN] new file dependency " << fileName(dependency);
+ processedArtifact->fileDependencies.insert(dependency);
+ } else {
+ if (processedArtifact->children.contains(dependency))
+ return;
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[DEPSCAN] new artifact dependency " << fileName(dependency);
+ BuildGraph *buildGraph = product->project->buildGraph();
+ if (insertIntoProduct && !product->artifacts.contains(dependency->fileName))
+ buildGraph->insert(product, dependency);
+ buildGraph->safeConnect(processedArtifact, dependency);
+ }
+}
+
+void Executor::cancelJobs()
+{
+ QList<ExecutorJob *> jobs = m_processingJobs.keys();
+ foreach (ExecutorJob *job, jobs)
+ job->cancel();
+ foreach (ExecutorJob *job, jobs)
+ job->waitForFinished();
+}
+
+void Executor::addExecutorJobs(int jobNumber)
+{
+ if (jobNumber < 1)
+ qbsError() << tr("Maximum job number must be larger than zero.");
+ for (int i = 1; i <= jobNumber; i++) {
+ ExecutorJob *job = new ExecutorJob(this);
+ job->setObjectName(QString(QLatin1String("J%1")).arg(i));
+ m_availableJobs.append(job);
+ connect(job, SIGNAL(error(QString)),
+ this, SLOT(onProcessError(QString)));
+ connect(job, SIGNAL(success()),
+ this, SLOT(onProcessSuccess()));
+ }
+}
+
+void Executor::removeExecutorJobs(int jobNumber)
+{
+ if (jobNumber >= m_availableJobs.count()) {
+ qDeleteAll(m_availableJobs);
+ m_availableJobs.clear();
+ } else {
+ for (int i = 1; i <= jobNumber; i++) {
+ delete m_availableJobs.takeLast();
+ }
+ }
+}
+
+bool Executor::runAutoMoc()
+{
+ bool autoMocApplied = false;
+ foreach (const BuildProduct::Ptr &product, m_productsToBuild) {
+ // HACK call the automoc thingy here only if we have use qt/core module
+ foreach (ResolvedModule::Ptr m, product->rProduct->modules) {
+ if (m->name == "qt/core") {
+ try {
+ autoMocApplied = true;
+ m_autoMoc->apply(product);
+ } catch (Error &e) {
+ setError(e.toString());
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ if (autoMocApplied)
+ foreach (BuildProject::Ptr prj, m_projectsToBuild)
+ BuildGraph::detectCycle(prj.data());
+
+ return true;
+}
+
+static bool scanWithScannerPlugin(ScannerPlugin *scannerPlugin,
+ const QString &filePathToBeScanned,
+ ScanResultCache *scanResultCache,
+ ScanResultCache::Result *scanResult)
+{
+ void *scannerHandle = scannerPlugin->open(filePathToBeScanned.utf16(), 0, 0);
+ if (!scannerHandle)
+ return false;
+ while (true) {
+ int flags = 0;
+ int length = 0;
+ const char *szOutFilePath = scannerPlugin->next(scannerHandle, &length, &flags);
+ if (szOutFilePath == 0)
+ break;
+ QString outFilePath = QString::fromLocal8Bit(szOutFilePath, length);
+ if (outFilePath.isEmpty())
+ continue;
+ bool isLocalInclude = (flags & SC_LOCAL_INCLUDE_FLAG);
+ scanResult->deps.insert(outFilePath, isLocalInclude);
+ }
+ scannerPlugin->close(scannerHandle);
+ scanResult->visited = true;
+ scanResultCache->insert(filePathToBeScanned, *scanResult);
+ return true;
+}
+
+static void collectIncludePaths(const QVariantMap &modules, QSet<QString> *collectedPaths)
+{
+ QMapIterator<QString, QVariant> iterator(modules);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.key() == "cpp") {
+ QVariant includePathsVariant = iterator .value().toMap().value("includePaths");
+ if (includePathsVariant.isValid())
+ collectedPaths->unite(QSet<QString>::fromList(includePathsVariant.toStringList()));
+ } else {
+ collectIncludePaths(iterator .value().toMap().value("modules").toMap(), collectedPaths);
+ }
+ }
+}
+
+static QStringList collectIncludePaths(const QVariantMap &modules)
+{
+ QSet<QString> collectedPaths;
+
+ collectIncludePaths(modules, &collectedPaths);
+ return QStringList(collectedPaths.toList());
+}
+
+void Executor::scanFileDependencies(Artifact *processedArtifact)
+{
+ if (!processedArtifact->transformer)
+ return;
+
+ foreach (Artifact *output, processedArtifact->transformer->outputs) {
+ // clear the file dependencies - they will be regenerated
+ output->fileDependencies.clear();
+ }
+
+ foreach (Artifact *inputArtifact, processedArtifact->transformer->inputs) {
+ QStringList includePaths;
+ foreach (const QString &fileTag, inputArtifact->fileTags) {
+ QList<ScannerPlugin *> scanners = ScannerPluginManager::scannersForFileTag(fileTag);
+ foreach (ScannerPlugin *scanner, scanners) {
+ if (includePaths.isEmpty())
+ includePaths = collectIncludePaths(inputArtifact->configuration->value().value("modules").toMap());
+
+ scanForFileDependencies(scanner, includePaths, processedArtifact, inputArtifact);
+ }
+ }
+ }
+}
+
+void Executor::scanForFileDependencies(ScannerPlugin *scannerPlugin, const QStringList &includePaths, Artifact *processedArtifact, Artifact *inputArtifact)
+{
+ qbsDebug("scanning %s [%s]", qPrintable(inputArtifact->fileName), scannerPlugin->fileTag);
+ qbsDebug(" from %s", qPrintable(processedArtifact->fileName));
+
+ QSet<QString> resolvedDependencies;
+ QSet<QString> visitedFilePaths;
+ QStringList filePathsToScan;
+ filePathsToScan.append(inputArtifact->fileName);
+
+ while (!filePathsToScan.isEmpty()) {
+ const QString filePathToBeScanned = filePathsToScan.takeFirst();
+ if (visitedFilePaths.contains(filePathToBeScanned))
+ continue;
+ visitedFilePaths.insert(filePathToBeScanned);
+
+ ScanResultCache::Result scanResult = m_scanResultCache.value(filePathToBeScanned);
+ if (!scanResult.visited) {
+ bool canScan = scanWithScannerPlugin(scannerPlugin, filePathToBeScanned, &m_scanResultCache, &scanResult);
+ if (!canScan)
+ continue;
+ }
+
+ resolveScanResultDependencies(includePaths, inputArtifact, scanResult, filePathToBeScanned, &resolvedDependencies, &filePathsToScan);
+ }
+
+ handleDependencies(processedArtifact, inputArtifact, resolvedDependencies);
+}
+
+static bool resolveWithIncludePath(const QString &includePath, QString &outFilePath, BuildProduct *buildProduct)
+{
+ QString filePath = FileInfo::resolvePath(includePath, outFilePath);
+ if (buildProduct->artifacts.contains(filePath)) {
+ outFilePath = filePath;
+ return true;
+ } else if (FileInfo::exists(filePath)) {
+ outFilePath = filePath;
+ return true;
+ }
+ return false;
+}
+
+void Executor::resolveScanResultDependencies(const QStringList &includePaths,
+ Artifact *inputArtifact,
+ const ScanResultCache::Result &scanResult,
+ const QString &filePathToBeScanned,
+ QSet<QString> *dependencies,
+ QStringList *filePathsToScan)
+{
+ QString baseDirOfInFilePath;
+ for (QHash<QString, bool>::const_iterator iterator = scanResult.deps.constBegin(); iterator != scanResult.deps.constEnd(); ++iterator) {
+ QString outFilePath = iterator.key();
+ const bool isLocalInclude = iterator.value();
+ bool resolved = FileInfo::isAbsolute(outFilePath);
+
+ if (!resolved && isLocalInclude) {
+ // try base directory of source file
+ if (baseDirOfInFilePath.isNull())
+ baseDirOfInFilePath = FileInfo::path(filePathToBeScanned);
+ resolved = resolveWithIncludePath(baseDirOfInFilePath, outFilePath, inputArtifact->product);
+ }
+
+ if (!resolved) {
+ // try include paths
+ foreach (const QString &includePath, includePaths) {
+ if (resolveWithIncludePath(includePath, outFilePath, inputArtifact->product)) {
+ resolved = true;
+ break;
+ }
+ }
+ }
+
+ if (resolved) {
+ outFilePath = QDir::cleanPath(outFilePath);
+ dependencies->insert(outFilePath);
+ filePathsToScan->append(outFilePath);
+ }
+ }
+}
+
+void Executor::onProcessError(QString errorString)
+{
+ if (m_keepGoing) {
+ qbsWarning() << tr("ignoring error: %1").arg(errorString);
+ onProcessSuccess();
+ } else {
+ setError(errorString);
+ cancelJobs();
+ finish();
+ }
+}
+
+void Executor::onProcessSuccess()
+{
+ ExecutorJob *job = qobject_cast<ExecutorJob *>(sender());
+ Q_ASSERT(job);
+ Artifact *processedArtifact = m_processingJobs.value(job);
+ Q_ASSERT(processedArtifact);
+ m_processingJobs.remove(job);
+ m_availableJobs.append(job);
+ finishArtifact(processedArtifact);
+
+ if (m_state == ExecutorRunning && !run(*m_futureInterface))
+ finish();
+}
+
+void Executor::finish()
+{
+ if (m_state == ExecutorIdle)
+ return;
+
+ QStringList unbuiltProductNames;
+ foreach (BuildProduct::Ptr buildProduct, m_productsToBuild) {
+ foreach (Artifact *artifact, buildProduct->targetArtifacts) {
+ if (artifact->buildState != Artifact::Built) {
+ unbuiltProductNames += buildProduct->rProduct->name;
+ break;
+ }
+ }
+ }
+ if (unbuiltProductNames.isEmpty()) {
+ qbsInfo() << DontPrintLogLevel << LogOutputStdOut << TextColorGreen
+ << "Build done.";
+ } else {
+ setError(tr("The following products could not be built: %1.").arg(unbuiltProductNames.join(", ")));
+ qbsInfo() << DontPrintLogLevel << LogOutputStdOut << TextColorRed
+ << "Build failed.";
+ return;
+ }
+
+ setState(ExecutorIdle);
+ emit finished();
+}
+
+/**
+ * Resets the state of all artifacts in the graph to "untouched".
+ * This must be done before doing another build.
+ */
+void Executor::resetArtifactsToUntouched()
+{
+ foreach (const BuildProduct::Ptr &product, m_productsToBuild) {
+ foreach (Artifact *artifact, product->artifacts) {
+ artifact->buildState = Artifact::Untouched;
+ artifact->isExistingFile = false;
+ artifact->isOutOfDate = false;
+ }
+ }
+}
+
+void Executor::prepareBuildGraph(Artifact::BuildState buildState)
+{
+ foreach (Artifact *root, m_roots)
+ prepareBuildGraph_impl(root, buildState);
+}
+
+void Executor::prepareBuildGraph_impl(Artifact *artifact, Artifact::BuildState buildState)
+{
+ if (artifact->buildState != Artifact::Untouched)
+ return;
+
+ artifact->buildState = buildState;
+
+ foreach (Artifact *child, artifact->children)
+ prepareBuildGraph_impl(child, buildState);
+}
+
+void Executor::updateBuildGraph(Artifact::BuildState buildState)
+{
+ QSet<Artifact *> seenArtifacts;
+ foreach (Artifact *root, m_roots)
+ updateBuildGraph_impl(root, buildState, seenArtifacts);
+}
+
+void Executor::updateBuildGraph_impl(Artifact *artifact, Artifact::BuildState buildState, QSet<Artifact *> &seenArtifacts)
+{
+ if (seenArtifacts.contains(artifact))
+ return;
+
+ seenArtifacts += artifact;
+ artifact->buildState = buildState;
+
+ foreach (Artifact *child, artifact->children)
+ updateBuildGraph_impl(child, buildState, seenArtifacts);
+}
+
+void Executor::doOutOfDateCheck()
+{
+ foreach (Artifact *root, m_roots)
+ doOutOfDateCheck(root);
+}
+
+void Executor::doOutOfDateCheck(Artifact *artifact)
+{
+ if (artifact->outOfDateCheckPerformed)
+ return;
+ bool fileExists;
+ if (isOutOfDate(artifact, fileExists))
+ artifact->isOutOfDate = true;
+ artifact->isExistingFile = fileExists;
+ artifact->outOfDateCheckPerformed = true;
+ foreach (Artifact *child, artifact->children)
+ doOutOfDateCheck(child);
+}
+
+void Executor::doDependencyScanTopDown()
+{
+ qbsInfo() << DontPrintLogLevel << "Scanning for file dependencies...";
+ QSet<Artifact *> seenArtifacts;
+ foreach (Artifact *root, m_roots)
+ doDependencyScan_impl(root, seenArtifacts);
+}
+
+void Executor::doDependencyScan_impl(Artifact *artifact, QSet<Artifact *> &seenArtifacts)
+{
+ if (!artifact->transformer || seenArtifacts.contains(artifact))
+ return;
+ seenArtifacts += artifact;
+ if (!artifact->outOfDateCheckPerformed)
+ doOutOfDateCheck(artifact);
+ if (artifact->isOutOfDate)
+ scanFileDependencies(artifact);
+ foreach (Artifact *child, artifact->children)
+ doDependencyScan_impl(child, seenArtifacts);
+}
+
+void Executor::setState(ExecutorState s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(s);
+}
+
+void Executor::setError(const QString &errorMessage)
+{
+ setState(ExecutorError);
+ qbsError() << errorMessage;
+ emit error();
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/executor.h b/src/lib/buildgraph/executor.h
new file mode 100644
index 000000000..45e86280b
--- /dev/null
+++ b/src/lib/buildgraph/executor.h
@@ -0,0 +1,147 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef BUILDGRAPHEXECUTOR_H
+#define BUILDGRAPHEXECUTOR_H
+
+#include "buildgraph.h"
+
+#include <buildgraph/artifact.h>
+#include <Qbs/processoutput.h>
+#include <tools/settings.h>
+#include <tools/scannerpluginmanager.h>
+#include <buildgraph/scanresultcache.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+
+namespace qbs {
+
+class AutoMoc;
+class ExecutorJob;
+class ScanResultCache;
+
+class Executor : public QObject
+{
+ Q_OBJECT
+public:
+ Executor(int maxJobs = 1);
+ ~Executor();
+
+ void build(const QList<BuildProject::Ptr> projectsToBuild, const QStringList &changedFiles, const QStringList &selectedProductNames, QFutureInterface<bool> &futureInterface);
+
+ enum ExecutorState {
+ ExecutorIdle,
+ ExecutorRunning,
+ ExecutorError
+ };
+
+ void setRunOnceAndForgetModeEnabled(bool enabled) { m_runOnceAndForgetMode = enabled; }
+ void setDryRun(bool b);
+ void setKeepGoing(bool b) { m_keepGoing = b; }
+ bool isKeepGoingSet() const { return m_keepGoing; }
+ ExecutorState state() const { return m_state; }
+
+ void setMaximumJobs(int numberOfJobs);
+ int maximumJobs() const;
+
+signals:
+ void error();
+ void finished();
+ void stateChanged(ExecutorState);
+ void progress(int jobsToDo, int jobCount, const QString &description);
+ void newProcessOutput(const Qbs::ProcessOutput &processOutput);
+
+protected slots:
+ void onProcessError(QString errorString);
+ void onProcessSuccess();
+ void resetArtifactsToUntouched();
+
+protected:
+ void prepareBuildGraph(Artifact::BuildState buildState);
+ void prepareBuildGraph_impl(Artifact *artifact, Artifact::BuildState buildState);
+ void updateBuildGraph(Artifact::BuildState buildState);
+ void updateBuildGraph_impl(Artifact *artifact, Artifact::BuildState buildState, QSet<Artifact *> &seenArtifacts);
+ void doOutOfDateCheck();
+ void doOutOfDateCheck(Artifact *root);
+ void doDependencyScanTopDown();
+ void doDependencyScan_impl(Artifact *artifact, QSet<Artifact *> &seenArtifacts);
+ static bool isLeaf(Artifact *artifact);
+ void initLeaves(const QList<Artifact *> &changedArtifacts);
+ void initLeavesTopDown(Artifact *artifact, QSet<Artifact *> &seenArtifacts);
+ bool run(QFutureInterface<bool> &futureInterface);
+ qbs::FileTime timeStamp(Artifact *artifact);
+ bool isOutOfDate(Artifact *artifact, bool &fileExists);
+ bool execute(Artifact *artifact);
+ void finishArtifact(Artifact *artifact);
+ void finish();
+ void setState(ExecutorState);
+ void setError(const QString &errorMessage);
+ void addExecutorJobs(int jobNumber);
+ void removeExecutorJobs(int jobNumber);
+ bool runAutoMoc();
+ void scanFileDependencies(Artifact *processedArtifact);
+ void scanForFileDependencies(ScannerPlugin *scannerPlugin, const QStringList &includePaths, Artifact *processedArtifact, Artifact *inputArtifact);
+ static void resolveScanResultDependencies(const QStringList &includePaths, Artifact *inputArtifact, const ScanResultCache::Result &scanResult,
+ const QString &filePathToBeScanned, QSet<QString> *dependencies, QStringList *filePathsToScan);
+ void handleDependencies(Artifact *processedArtifact, Artifact *scannedArtifact, const QSet<QString> &resolvedDependencies);
+ void handleDependency(Artifact *processedArtifact, const QString &dependencyFilePath);
+ void cancelJobs();
+
+private:
+ QScriptEngine *m_scriptEngine;
+ bool m_runOnceAndForgetMode; // This is true for the command line version.
+ QList<ExecutorJob*> m_availableJobs;
+ QHash<ExecutorJob*, Artifact *> m_processingJobs;
+ ExecutorState m_state;
+ bool m_keepGoing;
+ QList<BuildProject::Ptr> m_projectsToBuild;
+ QList<BuildProduct::Ptr> m_productsToBuild;
+ QList<Artifact *> m_roots;
+ QMap<Artifact *, QHashDummyValue> m_leaves;
+ QHash<Artifact *, qbs::FileTime> m_timeStampCache;
+ ScanResultCache m_scanResultCache;
+ AutoMoc *m_autoMoc;
+
+ friend class ExecutorJob;
+ int m_maximumJobNumber;
+ QFutureInterface<bool> *m_futureInterface; // TODO: its a hack
+};
+
+} // namespace qbs
+
+#endif // BUILDGRAPHEXECUTOR_H
diff --git a/src/lib/buildgraph/executorjob.cpp b/src/lib/buildgraph/executorjob.cpp
new file mode 100644
index 000000000..b7a16828a
--- /dev/null
+++ b/src/lib/buildgraph/executorjob.cpp
@@ -0,0 +1,128 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "executorjob.h"
+#include "executor.h"
+#include "commandexecutor.h"
+#include <buildgraph/transformer.h>
+#include <QtCore/QThread>
+
+namespace qbs {
+
+ExecutorJob::ExecutorJob(Executor *parent)
+ : QObject(parent)
+ , m_executor(parent)
+ , m_commandExecutor(new CommandExecutor(this))
+ , m_transformer(0)
+ , m_lastUsedProduct(0)
+ , m_currentCommandIdx(-1)
+{
+ connect(m_commandExecutor, SIGNAL(error(QString)), SLOT(onCommandError(QString)));
+ connect(m_commandExecutor, SIGNAL(finished()), SLOT(onCommandFinished()));
+}
+
+ExecutorJob::~ExecutorJob()
+{
+}
+
+void ExecutorJob::setMainThreadScriptEngine(QScriptEngine *engine)
+{
+ m_commandExecutor->setMainThreadScriptEngine(engine);
+}
+
+void ExecutorJob::setDryRun(bool enabled)
+{
+ m_commandExecutor->setDryRunEnabled(enabled);
+}
+
+void ExecutorJob::run(Transformer *t, BuildProduct *buildProduct)
+{
+ Q_ASSERT(m_currentCommandIdx == -1);
+
+ if (t->commands.isEmpty()) {
+ emit success();
+ return;
+ }
+
+ if (m_lastUsedProduct != buildProduct)
+ m_commandExecutor->setProcessEnvironment(buildProduct->rProduct->buildEnvironment);
+
+ m_transformer = t;
+ runNextCommand();
+}
+
+void ExecutorJob::cancel()
+{
+ if (!m_transformer)
+ return;
+ m_currentCommandIdx = m_transformer->commands.count();
+}
+
+void ExecutorJob::waitForFinished()
+{
+ m_commandExecutor->waitForFinished();
+}
+
+void ExecutorJob::runNextCommand()
+{
+ ++m_currentCommandIdx;
+ if (m_currentCommandIdx >= m_transformer->commands.count()) {
+ m_transformer = 0;
+ m_currentCommandIdx = -1;
+ emit success();
+ return;
+ }
+
+ AbstractCommand *command = m_transformer->commands.at(m_currentCommandIdx);
+ m_commandExecutor->start(m_transformer, command);
+}
+
+void ExecutorJob::onCommandError(QString errorString)
+{
+ m_transformer = 0;
+ m_currentCommandIdx = -1;
+ emit error(errorString);
+}
+
+void ExecutorJob::onCommandFinished()
+{
+ if (!m_transformer)
+ return;
+ runNextCommand();
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/executorjob.h b/src/lib/buildgraph/executorjob.h
new file mode 100644
index 000000000..db3073a9c
--- /dev/null
+++ b/src/lib/buildgraph/executorjob.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef EXECUTORJOB_H
+#define EXECUTORJOB_H
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QScriptEngine;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class CommandExecutor;
+class BuildProduct;
+class Executor;
+class Transformer;
+
+class ExecutorJob : public QObject
+{
+ Q_OBJECT
+public:
+ ExecutorJob(Executor *parent);
+ ~ExecutorJob();
+
+ void setMainThreadScriptEngine(QScriptEngine *engine);
+ void setDryRun(bool enabled);
+ void run(Transformer *t, BuildProduct *buildProduct);
+ void cancel();
+ void waitForFinished();
+
+protected slots:
+ void runNextCommand();
+ void onCommandError(QString errorString);
+ void onCommandFinished();
+
+signals:
+ void error(QString errorString);
+ void success();
+
+private:
+ Executor *m_executor;
+ CommandExecutor *m_commandExecutor;
+ Transformer *m_transformer;
+ BuildProduct *m_lastUsedProduct;
+ int m_currentCommandIdx;
+};
+
+} // namespace qbs
+
+#endif // EXECUTORJOB_H
diff --git a/src/lib/buildgraph/rulegraph.cpp b/src/lib/buildgraph/rulegraph.cpp
new file mode 100644
index 000000000..11d7712e8
--- /dev/null
+++ b/src/lib/buildgraph/rulegraph.cpp
@@ -0,0 +1,201 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "rulegraph.h"
+#include <tools/error.h>
+#include <QtCore/QDebug>
+
+namespace qbs {
+
+RuleGraph::RuleGraph()
+{
+}
+
+void RuleGraph::build(const QSet<Rule::Ptr> &rules, const QStringList &productFileTags)
+{
+ QMap<QString, QList<Rule*> > inputFileTagToRule;
+ m_artifacts.reserve(rules.count());
+ foreach (const Rule::Ptr &rule, rules) {
+ foreach (const QString &fileTag, rule->outputFileTags())
+ m_outputFileTagToRule[fileTag].append(rule.data());
+ insert(rule);
+ }
+
+ m_parents.resize(rules.count());
+ m_children.resize(rules.count());
+
+ foreach (Rule::Ptr rule, m_artifacts) {
+ QStringList inFileTags = rule->inputs;
+ inFileTags += rule->explicitlyDependsOn;
+ foreach (const QString &fileTag, inFileTags) {
+ inputFileTagToRule[fileTag].append(rule.data());
+ foreach (Rule *consumingRule, m_outputFileTagToRule.value(fileTag)) {
+ connect(rule.data(), consumingRule);
+ }
+ }
+ }
+
+ QList<Rule*> productRules;
+ for (int i=0; i < productFileTags.count(); ++i) {
+ QList<Rule*> rules = m_outputFileTagToRule.value(productFileTags.at(i));
+ productRules += rules;
+ //### check: the rule graph must be a in valid shape!
+ }
+ foreach (Rule *r, productRules)
+ m_rootRules += r->ruleGraphId;
+}
+
+QList<Rule::Ptr> RuleGraph::topSorted()
+{
+ QSet<int> rootRules = m_rootRules;
+ QList<Rule::Ptr> result;
+ foreach (int rootIndex, rootRules) {
+ Rule::Ptr rule = m_artifacts.at(rootIndex);
+ result.append(topSort(rule));
+ }
+
+ // remove duplicates from the result of our post-order traversal
+ QSet<Rule*> seenRules;
+ seenRules.reserve(result.count());
+ for (int i = 0; i < result.count();) {
+ Rule *rule = result.at(i).data();
+ if (seenRules.contains(rule))
+ result.removeAt(i);
+ else
+ ++i;
+ seenRules.insert(rule);
+ }
+
+ return result;
+}
+
+void RuleGraph::dump() const
+{
+ QByteArray indent;
+ printf("---rule graph dump:\n");
+ QSet<int> rootRules;
+ foreach (Rule::Ptr rule, m_artifacts)
+ if (m_parents[rule->ruleGraphId].isEmpty())
+ rootRules += rule->ruleGraphId;
+ foreach (int idx, rootRules) {
+ dump_impl(indent, idx);
+ }
+}
+
+void RuleGraph::dump_impl(QByteArray &indent, int rootIndex) const
+{
+ Rule::Ptr r = m_artifacts[rootIndex];
+ printf("%s", indent.constData());
+ printf("%s", qPrintable(r->toString()));
+ printf("\n");
+
+ indent.append(" ");
+ foreach (int childIndex, m_children[rootIndex])
+ dump_impl(indent, childIndex);
+ indent.chop(2);
+}
+
+int RuleGraph::insert(Rule::Ptr rule)
+{
+ rule->ruleGraphId = m_artifacts.count();
+ m_artifacts.append(rule);
+ return rule->ruleGraphId;
+}
+
+void RuleGraph::connect(Rule *creatingRule, Rule *consumingRule)
+{
+ int maxIndex = qMax(creatingRule->ruleGraphId, consumingRule->ruleGraphId);
+ if (m_parents.count() <= maxIndex) {
+ const int c = maxIndex + 1;
+ m_parents.resize(c);
+ m_children.resize(c);
+ }
+ m_parents[consumingRule->ruleGraphId].append(creatingRule->ruleGraphId);
+ m_children[creatingRule->ruleGraphId].append(consumingRule->ruleGraphId);
+}
+
+void RuleGraph::remove(Rule *rule)
+{
+ m_parents[rule->ruleGraphId].clear();
+ m_children[rule->ruleGraphId].clear();
+ m_artifacts[rule->ruleGraphId] = Rule::Ptr();
+ rule->ruleGraphId = -1;
+}
+
+void RuleGraph::removeParents(Rule *rule)
+{
+ foreach (int parentIndex, m_parents[rule->ruleGraphId]) {
+ Rule::Ptr parent = m_artifacts.at(parentIndex);
+ removeParents(parent.data());
+ remove(parent.data());
+ }
+ m_parents[rule->ruleGraphId].clear();
+}
+
+void RuleGraph::removeSiblings(Rule *rule)
+{
+ foreach (int childIndex, m_children[rule->ruleGraphId]) {
+ Rule::Ptr child = m_artifacts.at(childIndex);
+ QList<int> toRemove;
+ foreach (int siblingIndex, m_parents.at(child->ruleGraphId)) {
+ Rule::Ptr sibling = m_artifacts.at(siblingIndex);
+ if (sibling == rule)
+ continue;
+ toRemove.append(sibling->ruleGraphId);
+ remove(sibling.data());
+ }
+ QVector<int> &parents = m_parents[child->ruleGraphId];
+ qSort(parents);
+ foreach (int id, toRemove) {
+ QVector<int>::iterator it = qBinaryFind(parents.begin(), parents.end(), id);
+ if (it != parents.end())
+ parents.erase(it);
+ }
+ }
+}
+
+QList<Rule::Ptr> RuleGraph::topSort(Rule::Ptr rule)
+{
+ QList<Rule::Ptr> result;
+ foreach (int childIndex, m_children.at(rule->ruleGraphId))
+ result.append(topSort(m_artifacts.at(childIndex)));
+
+ result.append(rule);
+ return result;
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/rulegraph.h b/src/lib/buildgraph/rulegraph.h
new file mode 100644
index 000000000..d5a88b940
--- /dev/null
+++ b/src/lib/buildgraph/rulegraph.h
@@ -0,0 +1,77 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef RULEGRAPH_H
+#define RULEGRAPH_H
+
+#include <language.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QVector>
+
+namespace qbs {
+
+class RuleGraph
+{
+public:
+ RuleGraph();
+
+ void build(const QSet<qbs::Rule::Ptr> &rules, const QStringList &productFileTag);
+ QList<qbs::Rule::Ptr> topSorted();
+
+ void dump() const;
+
+private:
+ void dump_impl(QByteArray &indent, int rootIndex) const;
+ int insert(qbs::Rule::Ptr rule);
+ void connect(qbs::Rule *creatingRule, qbs::Rule *consumingRule);
+ void remove(qbs::Rule *rule);
+ void removeParents(qbs::Rule *rule);
+ void removeSiblings(qbs::Rule *rule);
+ QList<qbs::Rule::Ptr> topSort(qbs::Rule::Ptr rule);
+
+private:
+ QMap<QString, QList<qbs::Rule*> > m_outputFileTagToRule;
+ QVector<qbs::Rule::Ptr> m_artifacts;
+ QVector< QVector<int> > m_parents;
+ QVector< QVector<int> > m_children;
+ QSet<int> m_rootRules;
+};
+
+} // namespace qbs
+
+#endif // RULEGRAPH_H
diff --git a/src/lib/buildgraph/scanresultcache.cpp b/src/lib/buildgraph/scanresultcache.cpp
new file mode 100644
index 000000000..70d683337
--- /dev/null
+++ b/src/lib/buildgraph/scanresultcache.cpp
@@ -0,0 +1,56 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "scanresultcache.h"
+
+namespace qbs {
+
+ScanResultCache::Result ScanResultCache::value(const QString &fileName) const
+{
+ m_mutex.lock();
+ Result result = m_data.value(fileName);
+ m_mutex.unlock();
+ return result;
+}
+
+void ScanResultCache::insert(const QString &fileName, const ScanResultCache::Result &value)
+{
+ m_mutex.lock();
+ m_data.insert(fileName, value);
+ m_mutex.unlock();
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/scanresultcache.h b/src/lib/buildgraph/scanresultcache.h
new file mode 100644
index 000000000..23e7d811f
--- /dev/null
+++ b/src/lib/buildgraph/scanresultcache.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef SCANRESULTCACHE_H
+#define SCANRESULTCACHE_H
+
+#include <QtCore/QHash>
+#include <QtCore/QMutex>
+#include <QtCore/QSet>
+#include <QtCore/QString>
+
+namespace qbs {
+
+class ScanResultCache
+{
+public:
+
+ struct Result
+ {
+ Result()
+ : visited(false)
+ {}
+
+ QHash<QString, bool> deps;
+ bool visited;
+ };
+
+ Result value(const QString &fileName) const;
+ void insert(const QString &fileName, const Result &value);
+
+private:
+ mutable QMutex m_mutex;
+ QHash<QString, Result> m_data;
+};
+
+} // namespace qbs
+
+#endif // SCANRESULTCACHE_H
diff --git a/src/lib/buildgraph/transformer.cpp b/src/lib/buildgraph/transformer.cpp
new file mode 100644
index 000000000..e9327849a
--- /dev/null
+++ b/src/lib/buildgraph/transformer.cpp
@@ -0,0 +1,119 @@
+/*************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).*
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "transformer.h"
+#include "artifact.h"
+#include "command.h"
+
+namespace qbs {
+
+Transformer::Transformer()
+{
+}
+
+Transformer::~Transformer()
+{
+ qDeleteAll(commands);
+}
+
+QScriptValue Transformer::translateFileConfig(QScriptEngine *scriptEngine, Artifact *artifact, const QString &defaultModuleName)
+{
+ QScriptValue config = artifact->configuration->cachedScriptValue(scriptEngine);
+ if (!config.isValid()) {
+ config = scriptEngine->toScriptValue(artifact->configuration->value());
+ artifact->configuration->cacheScriptValue(scriptEngine, config);
+ }
+
+ QScriptValue artifactConfig = scriptEngine->newObject();
+ artifactConfig.setPrototype(config);
+ artifactConfig.setProperty(QLatin1String("fileName"), artifact->fileName);
+ QStringList fileTags = artifact->fileTags.toList();
+ artifactConfig.setProperty(QLatin1String("fileTags"), scriptEngine->toScriptValue(fileTags));
+ if (!defaultModuleName.isEmpty())
+ artifactConfig.setProperty(QLatin1String("module"), config.property("modules").property(defaultModuleName));
+ return artifactConfig;
+}
+
+QScriptValue Transformer::translateInOutputs(QScriptEngine *scriptEngine, const QSet<Artifact*> &artifacts, const QString &defaultModuleName)
+{
+ typedef QMap<QString, QList<Artifact*> > TagArtifactsMap;
+ TagArtifactsMap tagArtifactsMap;
+ foreach (Artifact *artifact, artifacts)
+ foreach (const QString &fileTag, artifact->fileTags)
+ tagArtifactsMap[fileTag].append(artifact);
+
+ QScriptValue jsTagFiles = scriptEngine->newObject();
+ for (TagArtifactsMap::const_iterator tag = tagArtifactsMap.constBegin(); tag != tagArtifactsMap.constEnd(); ++tag) {
+ const QList<Artifact*> &artifactList = tag.value();
+ QScriptValue jsFileConfig = scriptEngine->newArray(artifactList.count());
+ int i=0;
+ foreach (Artifact *artifact, artifactList) {
+ jsFileConfig.setProperty(i++, translateFileConfig(scriptEngine, artifact, defaultModuleName));
+ }
+ jsTagFiles.setProperty(tag.key(), jsFileConfig);
+ }
+
+ return jsTagFiles;
+}
+
+void Transformer::setupInputs(QScriptEngine *scriptEngine, QScriptValue targetScriptValue)
+{
+ const QString &defaultModuleName = rule->module->name;
+ QScriptValue scriptValue = translateInOutputs(scriptEngine, inputs, defaultModuleName);
+ targetScriptValue.setProperty("inputs", scriptValue, QScriptValue::ReadOnly);
+ if (inputs.count() == 1) {
+ Artifact *input = *inputs.begin();
+ const QSet<QString> &fileTags = input->fileTags;
+ QScriptValue inputsForFileTag = scriptValue.property(*fileTags.begin());
+ QScriptValue inputScriptValue = inputsForFileTag.property(0);
+ targetScriptValue.setProperty("input", inputScriptValue, QScriptValue::ReadOnly);
+ }
+}
+
+void Transformer::setupOutputs(QScriptEngine *scriptEngine, QScriptValue targetScriptValue)
+{
+ const QString &defaultModuleName = rule->module->name;
+ QScriptValue scriptValue = translateInOutputs(scriptEngine, outputs, defaultModuleName);
+ targetScriptValue.setProperty("outputs", scriptValue, QScriptValue::ReadOnly);
+ if (outputs.count() == 1) {
+ Artifact *output = *outputs.begin();
+ const QSet<QString> &fileTags = output->fileTags;
+ QScriptValue outputsForFileTag = scriptValue.property(*fileTags.begin());
+ QScriptValue outputScriptValue = outputsForFileTag.property(0);
+ targetScriptValue.setProperty("output", outputScriptValue, QScriptValue::ReadOnly);
+ }
+}
+
+} // namespace qbs
diff --git a/src/lib/buildgraph/transformer.h b/src/lib/buildgraph/transformer.h
new file mode 100644
index 000000000..d52d9dd3b
--- /dev/null
+++ b/src/lib/buildgraph/transformer.h
@@ -0,0 +1,85 @@
+/*************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).*
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef TRANSFORMER_H
+#define TRANSFORMER_H
+
+#include "tools/persistence.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtScript/QScriptEngine>
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class Artifact;
+class AbstractCommand;
+class Rule;
+
+class Transformer : public PersistentObject
+{
+public:
+ typedef QSharedPointer<Transformer> Ptr;
+
+ Transformer();
+ ~Transformer();
+
+ QSet<Artifact*> inputs; // can be different from "children of all outputs"
+ QSet<Artifact*> outputs;
+ QSharedPointer<Rule> rule;
+ QList<AbstractCommand *> commands;
+
+ static QScriptValue translateFileConfig(QScriptEngine *scriptEngine,
+ Artifact *artifact,
+ const QString &defaultModuleName);
+ static QScriptValue translateInOutputs(QScriptEngine *scriptEngine,
+ const QSet<Artifact*> &artifacts,
+ const QString &defaultModuleName);
+
+ void setupInputs(QScriptEngine *scriptEngine, QScriptValue targetScriptValue);
+ void setupOutputs(QScriptEngine *scriptEngine, QScriptValue targetScriptValue);
+
+private:
+ void load(PersistentPool &pool, PersistentObjectData &data);
+ void store(PersistentPool &pool, PersistentObjectData &data) const;
+};
+
+} // namespace qbs
+
+#endif // TRANSFORMER_H
diff --git a/src/lib/language/language.cpp b/src/lib/language/language.cpp
new file mode 100644
index 000000000..4640ecdc4
--- /dev/null
+++ b/src/lib/language/language.cpp
@@ -0,0 +1,453 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "language.h"
+#include <tools/scripttools.h>
+#include <QtCore/QCryptographicHash>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
+#include <algorithm>
+
+namespace qbs {
+
+QMutex Configuration::m_scriptValueCacheMutex;
+
+void Configuration::setValue(const QVariantMap &map)
+{
+ m_value = map;
+ m_scriptValueCache.clear();
+}
+
+QScriptValue Configuration::cachedScriptValue(QScriptEngine *scriptEngine) const
+{
+ m_scriptValueCacheMutex.lock();
+ const QScriptValue result = m_scriptValueCache.value(scriptEngine);
+ m_scriptValueCacheMutex.unlock();
+ Q_ASSERT(!result.isValid() || result.engine() == scriptEngine);
+ return result;
+}
+
+void Configuration::cacheScriptValue(QScriptEngine *scriptEngine, const QScriptValue &scriptValue)
+{
+ Q_ASSERT(scriptEngine == scriptValue.engine());
+ m_scriptValueCacheMutex.lock();
+ m_scriptValueCache.insert(scriptEngine, scriptValue);
+ m_scriptValueCacheMutex.unlock();
+}
+
+void Configuration::load(PersistentPool &, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ s >> m_value;
+}
+
+void Configuration::store(PersistentPool &, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << m_value;
+}
+
+void FileTagger::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ artifactExpression = pool.idLoadString(s);
+ fileTags = pool.idLoadStringList(s);
+}
+
+void FileTagger::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << pool.storeString(artifactExpression);
+ s << pool.storeStringList(fileTags);
+}
+
+void SourceArtifact::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ s >> absoluteFilePath;
+ s >> fileTags;
+ configuration = pool.idLoadS<Configuration>(s);
+}
+
+void SourceArtifact::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << absoluteFilePath;
+ s << fileTags;
+ s << pool.store(configuration);
+}
+
+void RuleArtifact::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ Q_UNUSED(pool);
+ QDataStream s(data);
+ s >> fileScript;
+ s >> fileTags;
+ s >> bindings;
+}
+
+void RuleArtifact::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ Q_UNUSED(pool);
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << fileScript;
+ s << fileTags;
+ s << bindings;
+}
+
+void RuleScript::load(PersistentPool &, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ s >> script;
+ s >> location;
+}
+
+void RuleScript::store(PersistentPool &, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << script;
+ s << location;
+}
+
+void ResolvedModule::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ Q_UNUSED(pool);
+ QDataStream s(data);
+ name = pool.idLoadString(s);
+ moduleDependencies = pool.idLoadStringList(s);
+ setupBuildEnvironmentScript = pool.idLoadString(s);
+ setupRunEnvironmentScript = pool.idLoadString(s);
+ s >> jsImports
+ >> setupBuildEnvironmentScript
+ >> setupRunEnvironmentScript;
+}
+
+void ResolvedModule::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ Q_UNUSED(pool);
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << pool.storeString(name)
+ << pool.storeStringList(moduleDependencies)
+ << pool.storeString(setupBuildEnvironmentScript)
+ << pool.storeString(setupRunEnvironmentScript)
+ << jsImports
+ << setupBuildEnvironmentScript
+ << setupRunEnvironmentScript;
+}
+
+QString Rule::toString() const
+{
+ return "[" + inputs.join(",") + " -> " + outputFileTags().join(",") + "]";
+}
+
+QStringList Rule::outputFileTags() const
+{
+ QStringList result;
+ foreach (RuleArtifact::Ptr artifact, artifacts)
+ result.append(artifact->fileTags);
+ result.sort();
+ std::unique(result.begin(), result.end());
+ return result;
+}
+
+void Rule::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ script = pool.idLoadS<RuleScript>(s);
+ module = pool.idLoadS<ResolvedModule>(s);
+ s >> jsImports
+ >> inputs
+ >> usings
+ >> explicitlyDependsOn
+ >> multiplex
+ >> objectId
+ >> transformProperties;
+
+ loadContainerS(artifacts, s, pool);
+}
+
+void Rule::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << pool.store(script)
+ << pool.store(module)
+ << jsImports
+ << inputs
+ << usings
+ << explicitlyDependsOn
+ << multiplex
+ << objectId
+ << transformProperties;
+
+ storeContainer(artifacts, s, pool);
+}
+
+ResolvedProduct::ResolvedProduct()
+ : project(0)
+{
+}
+
+QSet<QString> ResolvedProduct::fileTagsForFileName(const QString &fileName) const
+{
+ QSet<QString> result;
+ foreach (FileTagger::Ptr tagger, fileTaggers) {
+ if (FileInfo::globMatches(tagger->artifactExpression, fileName)) {
+ result.unite(tagger->fileTags.toSet());
+ }
+ }
+ return result;
+}
+
+void ResolvedProduct::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ s >> fileTags
+ >> name
+ >> buildDirectory
+ >> sourceDirectory
+ >> destinationDirectory
+ >> qbsFile;
+
+ configuration = pool.idLoadS<Configuration>(s);
+ loadContainerS(sources, s, pool);
+ loadContainerS(rules, s, pool);
+ loadContainerS(uses, s, pool);
+ loadContainerS(fileTaggers, s, pool);
+ loadContainerS(modules, s, pool);
+}
+
+void ResolvedProduct::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << fileTags
+ << name
+ << buildDirectory
+ << sourceDirectory
+ << destinationDirectory
+ << qbsFile;
+
+ s << pool.store(configuration);
+ storeContainer(sources, s, pool);
+ storeContainer(rules, s, pool);
+ storeContainer(uses, s, pool);
+ storeContainer(fileTaggers, s, pool);
+ storeContainer(modules, s, pool);
+}
+
+QList<ResolvedModule*> topSortModules(const QHash<ResolvedModule*, QList<ResolvedModule*> > &moduleChildren,
+ const QList<ResolvedModule*> &modules,
+ QSet<QString> &seenModuleNames)
+{
+ QList<ResolvedModule*> result;
+ foreach (ResolvedModule *m, modules) {
+ result.append(topSortModules(moduleChildren, moduleChildren.value(m), seenModuleNames));
+ if (!seenModuleNames.contains(m->name)) {
+ seenModuleNames.insert(m->name);
+ result.append(m);
+ }
+ }
+ return result;
+}
+
+static QScriptValue js_getenv(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() < 1)
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("getenv expects 1 argument"));
+ QVariant v = engine->property("_qbs_procenv");
+ QProcessEnvironment *procenv = reinterpret_cast<QProcessEnvironment*>(v.value<void*>());
+ return engine->toScriptValue(procenv->value(context->argument(0).toString()));
+}
+
+static QScriptValue js_putenv(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() < 2)
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("putenv expects 2 arguments"));
+ QVariant v = engine->property("_qbs_procenv");
+ QProcessEnvironment *procenv = reinterpret_cast<QProcessEnvironment*>(v.value<void*>());
+ procenv->insert(context->argument(0).toString(), context->argument(1).toString());
+ return engine->undefinedValue();
+}
+
+enum EnvType
+{
+ BuildEnv, RunEnv
+};
+
+static QProcessEnvironment getProcessEnvironment(QScriptEngine *scriptEngine, EnvType envType,
+ const QList<ResolvedModule::Ptr> &modules,
+ const Configuration::Ptr &productConfiguration,
+ const QProcessEnvironment &systemEnvironment)
+{
+ QProcessEnvironment procenv = systemEnvironment;
+ QMap<QString, ResolvedModule*> moduleMap;
+ foreach (ResolvedModule::Ptr module, modules)
+ moduleMap.insert(module->name, module.data());
+
+ QHash<ResolvedModule*, QList<ResolvedModule*> > moduleParents;
+ QHash<ResolvedModule*, QList<ResolvedModule*> > moduleChildren;
+ foreach (ResolvedModule::Ptr module, modules) {
+ foreach (const QString &moduleName, module->moduleDependencies) {
+ ResolvedModule *depmod = moduleMap.value(moduleName);
+ moduleParents[depmod].append(module.data());
+ moduleChildren[module.data()].append(depmod);
+ }
+ }
+
+ QList<ResolvedModule*> rootModules;
+ foreach (ResolvedModule::Ptr module, modules)
+ if (moduleParents.value(module.data()).isEmpty())
+ rootModules.append(module.data());
+
+ {
+ QVariant v;
+ v.setValue<void*>(&procenv);
+ scriptEngine->setProperty("_qbs_procenv", v);
+ }
+
+ QSet<QString> seenModuleNames;
+ QList<ResolvedModule*> topSortedModules = topSortModules(moduleChildren, rootModules, seenModuleNames);
+ foreach (ResolvedModule *module, topSortedModules) {
+ if ((envType == BuildEnv && module->setupBuildEnvironmentScript.isEmpty()) ||
+ (envType == RunEnv && module->setupBuildEnvironmentScript.isEmpty() && module->setupRunEnvironmentScript.isEmpty()))
+ continue;
+
+ // expose functions
+ scriptEngine->globalObject().setProperty("getenv", scriptEngine->newFunction(js_getenv, 1));
+ scriptEngine->globalObject().setProperty("putenv", scriptEngine->newFunction(js_putenv, 2));
+
+ QScriptContext *ctx = scriptEngine->pushContext();
+
+ // handle imports
+ QScriptValue scriptValue;
+ for (JsImports::const_iterator it = module->jsImports.begin(); it != module->jsImports.end(); ++it) {
+ foreach (const QString &fileName, it.value()) {
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly))
+ throw Error(QString("Can't open '%1'.").arg(fileName));
+ QScriptProgram program(file.readAll(), fileName);
+ scriptValue = addJSImport(scriptEngine, program, it.key());
+ if (scriptValue.isError())
+ throw Error(scriptValue.toString());
+ }
+ }
+
+ // expose properties of direct module dependencies
+ QScriptValue activationObject = ctx->activationObject();
+ QVariantMap productModules = productConfiguration->value().value("modules").toMap();
+ foreach (ResolvedModule *depmod, moduleChildren.value(module)) {
+ scriptValue = scriptEngine->newObject();
+ QVariantMap moduleCfg = productModules.value(depmod->name).toMap();
+ for (QVariantMap::const_iterator it = moduleCfg.constBegin(); it != moduleCfg.constEnd(); ++it)
+ scriptValue.setProperty(it.key(), scriptEngine->toScriptValue(it.value()));
+ activationObject.setProperty(depmod->name, scriptValue);
+ }
+
+ // expose the module's properties
+ QVariantMap moduleCfg = productModules.value(module->name).toMap();
+ for (QVariantMap::const_iterator it = moduleCfg.constBegin(); it != moduleCfg.constEnd(); ++it)
+ activationObject.setProperty(it.key(), scriptEngine->toScriptValue(it.value()));
+
+ QString setupScript;
+ if (envType == BuildEnv) {
+ setupScript = module->setupBuildEnvironmentScript;
+ } else {
+ if (module->setupRunEnvironmentScript.isEmpty()) {
+ setupScript = module->setupBuildEnvironmentScript;
+ } else {
+ setupScript = module->setupRunEnvironmentScript;
+ }
+ }
+ scriptValue = scriptEngine->evaluate(setupScript);
+ if (scriptValue.isError() || scriptEngine->hasUncaughtException()) {
+ QString envTypeStr = (envType == BuildEnv ? "build" : "run");
+ throw Error(QString("Error while setting up %1 environment: %2").arg(envTypeStr, scriptValue.toString()));
+ }
+
+ scriptEngine->popContext();
+ }
+
+ scriptEngine->setProperty("_qbs_procenv", QVariant());
+ return procenv;
+}
+
+void ResolvedProduct::setupBuildEnvironment(QScriptEngine *scriptEngine, const QProcessEnvironment &systemEnvironment) const
+{
+ if (!buildEnvironment.isEmpty())
+ return;
+
+ buildEnvironment = getProcessEnvironment(scriptEngine, BuildEnv, modules, configuration, systemEnvironment);
+}
+
+void ResolvedProduct::setupRunEnvironment(QScriptEngine *scriptEngine, const QProcessEnvironment &systemEnvironment) const
+{
+ if (!runEnvironment.isEmpty())
+ return;
+
+ runEnvironment = getProcessEnvironment(scriptEngine, RunEnv, modules, configuration, systemEnvironment);
+}
+
+void ResolvedProject::load(PersistentPool &pool, PersistentObjectData &data)
+{
+ QDataStream s(data);
+ s >> id;
+ s >> qbsFile;
+
+ int count, i;
+ s >> count;
+ products.clear();
+ products.reserve(count);
+ for (i = count; --i >= 0;) {
+ ResolvedProduct::Ptr rProduct = pool.idLoadS<ResolvedProduct>(s);
+ rProduct->project = this;
+ products.insert(rProduct);
+ }
+}
+
+void ResolvedProject::store(PersistentPool &pool, PersistentObjectData &data) const
+{
+ QDataStream s(&data, QIODevice::WriteOnly);
+ s << id;
+ s << qbsFile;
+
+ s << products.count();
+ foreach (ResolvedProduct::Ptr product, products)
+ s << pool.store(product);
+}
+
+} // namespace qbs
diff --git a/src/lib/language/language.h b/src/lib/language/language.h
new file mode 100644
index 000000000..255f4c369
--- /dev/null
+++ b/src/lib/language/language.h
@@ -0,0 +1,264 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef L2_LANGUAGE_HPP
+#define L2_LANGUAGE_HPP
+
+#include <tools/codelocation.h>
+#include <tools/persistence.h>
+#include <tools/settings.h>
+#include <tools/fileinfo.h>
+
+#include <QtCore/QString>
+#include <QtCore/QDataStream>
+#include <QtCore/QProcessEnvironment>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QVariant>
+#include <QtCore/QMutex>
+#include <QtScript/QScriptProgram>
+#include <QtScript/QScriptValue>
+
+QT_BEGIN_NAMESPACE
+class QScriptEngine;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+/**
+ * Represents JavaScript import.
+ * Key: scope name, Value: list of JS file names.
+ * There can be several filenames per scope
+ * if we import a whole directory.
+ */
+typedef QHash<QString, QStringList> JsImports;
+
+class Rule;
+
+class Configuration: public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<Configuration> Ptr;
+
+ const QVariantMap &value() const { return m_value; }
+ void setValue(const QVariantMap &value);
+ QScriptValue cachedScriptValue(QScriptEngine *scriptEngine) const;
+ void cacheScriptValue(QScriptEngine *scriptEngine, const QScriptValue &scriptValue);
+
+private:
+ void load(qbs::PersistentPool &, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &, qbs::PersistentObjectData &data) const;
+
+private:
+ QVariantMap m_value;
+ QHash<QScriptEngine *, QScriptValue> m_scriptValueCache;
+ static QMutex m_scriptValueCacheMutex;
+};
+
+struct FileTagger : public qbs::PersistentObject
+{
+ typedef QSharedPointer<FileTagger> Ptr;
+ QString artifactExpression;
+ QStringList fileTags;
+
+private:
+ void load(qbs::PersistentPool &, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &, qbs::PersistentObjectData &data) const;
+};
+
+class RuleArtifact : public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<RuleArtifact> Ptr;
+ QString fileScript;
+ QStringList fileTags;
+ QList<QPair<QStringList, QString> > bindings;
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+class SourceArtifact : public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<SourceArtifact> Ptr;
+ QString absoluteFilePath;
+ QSet<QString> fileTags;
+ Configuration::Ptr configuration;
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+class RuleScript: public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<RuleScript> Ptr;
+ QString script;
+ qbs::CodeLocation location;
+
+private:
+ void load(qbs::PersistentPool &, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &, qbs::PersistentObjectData &data) const;
+};
+
+class ResolvedModule : public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<ResolvedModule> Ptr;
+ QString name;
+ QStringList moduleDependencies;
+ JsImports jsImports;
+ QString setupBuildEnvironmentScript;
+ QString setupRunEnvironmentScript;
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+/**
+ * Per default each rule is a "non-multiplex rule".
+ *
+ * A "multiplex rule" creates one transformer that takes all
+ * input artifacts with the matching input file tag and creates
+ * one or more artifacts. (e.g. linker rule)
+ *
+ * A "non-multiplex rule" creates one transformer per matching input file.
+ */
+class Rule : public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<Rule> Ptr;
+ ResolvedModule::Ptr module;
+ JsImports jsImports;
+ RuleScript::Ptr script;
+ QStringList inputs;
+ QStringList usings;
+ QStringList explicitlyDependsOn;
+ bool multiplex;
+ QString objectId;
+ QList<RuleArtifact::Ptr> artifacts;
+ QMap<QString, QScriptProgram> transformProperties;
+
+ // members that we don't need to save
+ int ruleGraphId;
+
+ Rule()
+ : multiplex(false)
+ , ruleGraphId(-1)
+ {}
+
+ QString toString() const;
+ QStringList outputFileTags() const;
+
+ inline bool isMultiplexRule() const
+ {
+ return multiplex;
+ }
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+class ResolvedTransformer
+{
+public:
+ typedef QSharedPointer<ResolvedTransformer> Ptr;
+
+ ResolvedModule::Ptr module;
+ QStringList inputs;
+ QList<SourceArtifact::Ptr> outputs;
+ RuleScript::Ptr transform;
+ JsImports jsImports;
+};
+
+class ResolvedProject;
+class ResolvedProduct: public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<ResolvedProduct> Ptr;
+ ResolvedProduct();
+
+ QStringList fileTags;
+ QString name;
+ QString buildDirectory;
+ QString sourceDirectory;
+ QString destinationDirectory;
+ QString qbsFile;
+ ResolvedProject *project;
+ Configuration::Ptr configuration;
+ QSet<SourceArtifact::Ptr> sources;
+ QSet<Rule::Ptr> rules;
+ QSet<ResolvedProduct::Ptr> uses;
+ QSet<FileTagger::Ptr> fileTaggers;
+ QList<ResolvedModule::Ptr> modules;
+ QList<ResolvedTransformer::Ptr> transformers;
+
+ mutable QProcessEnvironment buildEnvironment; // must not be saved
+ mutable QProcessEnvironment runEnvironment; // must not be saved
+
+ QSet<QString> fileTagsForFileName(const QString &fileName) const;
+ void setupBuildEnvironment(QScriptEngine *scriptEngine, const QProcessEnvironment &systemEnvironment) const;
+ void setupRunEnvironment(QScriptEngine *scriptEngine, const QProcessEnvironment &systemEnvironment) const;
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+class ResolvedProject: public qbs::PersistentObject
+{
+public:
+ typedef QSharedPointer<ResolvedProject> Ptr;
+ QString id;
+ QString qbsFile;
+ QSet<ResolvedProduct::Ptr> products;
+ Configuration::Ptr configuration;
+
+private:
+ void load(qbs::PersistentPool &pool, qbs::PersistentObjectData &data);
+ void store(qbs::PersistentPool &pool, qbs::PersistentObjectData &data) const;
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/language/language.pri b/src/lib/language/language.pri
new file mode 100644
index 000000000..d2b5bdf83
--- /dev/null
+++ b/src/lib/language/language.pri
@@ -0,0 +1,9 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/loader.h \
+ $$PWD/language.h
+
+SOURCES += \
+ $$PWD/loader.cpp \
+ $$PWD/language.cpp
diff --git a/src/lib/language/loader.cpp b/src/lib/language/loader.cpp
new file mode 100644
index 000000000..4fcd4abb3
--- /dev/null
+++ b/src/lib/language/loader.cpp
@@ -0,0 +1,2647 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+
+#include "loader.h"
+
+#include "language.h"
+#include <tools/error.h>
+#include <tools/settings.h>
+#include <tools/fileinfo.h>
+#include <tools/runenvironment.h>
+#include <tools/scripttools.h>
+#include <tools/logger.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSettings>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtCore/QDirIterator>
+
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptProgram>
+#include <QtScript/QScriptValueIterator>
+
+#include <parser/qmljsparser_p.h>
+#include <parser/qmljsnodepool_p.h>
+#include <parser/qmljsengine_p.h>
+#include <parser/qmljslexer_p.h>
+
+QT_BEGIN_NAMESPACE
+static uint qHash(const QStringList &list)
+{
+ uint hash = 0;
+ foreach (const QString &n, list)
+ hash ^= qHash(n);
+ return hash;
+}
+QT_END_NAMESPACE
+
+using namespace QmlJS::AST;
+
+
+namespace qbs {
+
+const QString dumpIndent(" ");
+
+PropertyDeclaration::PropertyDeclaration()
+ : type(UnknownType)
+ , flags(DefaultFlags)
+{
+}
+
+PropertyDeclaration::PropertyDeclaration(const QString &name, Type type, Flags flags)
+ : name(name)
+ , type(type)
+ , flags(flags)
+{
+}
+
+PropertyDeclaration::~PropertyDeclaration()
+{
+}
+
+LanguageObject::LanguageObject(ProjectFile *owner)
+ : file(owner)
+{
+ file->registerLanguageObject(this);
+}
+
+LanguageObject::LanguageObject(const LanguageObject &other)
+ : id(other.id)
+ , prototype(other.prototype)
+ , prototypeFileName(other.prototypeFileName)
+ , prototypeLocation(other.prototypeLocation)
+ , file(other.file)
+ , bindings(other.bindings)
+ , functions(other.functions)
+ , propertyDeclarations(other.propertyDeclarations)
+{
+ file->registerLanguageObject(this);
+ children.reserve(other.children.size());
+ for (int i = 0; i < other.children.size(); ++i)
+ children.append(new LanguageObject(*other.children.at(i)));
+}
+
+LanguageObject::~LanguageObject()
+{
+ if (!file->isDestructing())
+ file->registerLanguageObject(this);
+}
+
+ScopeChain::ScopeChain(QScriptEngine *engine, const QSharedPointer<Scope> &root)
+ : QScriptClass(engine)
+{
+ m_value = engine->newObject(this);
+ m_globalObject = engine->globalObject();
+ if (root)
+ m_scopes.append(root);
+}
+
+ScopeChain::~ScopeChain()
+{
+}
+
+ScopeChain *ScopeChain::clone() const
+{
+ ScopeChain *s = new ScopeChain(engine(), m_scopes.last());
+ s->m_scopes = m_scopes;
+ return s;
+}
+
+QScriptValue ScopeChain::value()
+{
+ return m_value;
+}
+
+Scope::Ptr ScopeChain::first() const
+{
+ return m_scopes.first();
+}
+
+Scope::Ptr ScopeChain::last() const
+{
+ return m_scopes.last();
+}
+
+ScopeChain *ScopeChain::prepend(const QSharedPointer<Scope> &newTop)
+{
+ if (!newTop)
+ return this;
+ m_scopes.prepend(newTop);
+ return this;
+}
+
+QSharedPointer<Scope> ScopeChain::findNonEmpty(const QString &name) const
+{
+ foreach (const Scope::Ptr &scope, m_scopes) {
+ if (scope->name() == name && !scope->properties.isEmpty())
+ return scope;
+ }
+ return Scope::Ptr();
+}
+
+QSharedPointer<Scope> ScopeChain::find(const QString &name) const
+{
+ foreach (const Scope::Ptr &scope, m_scopes) {
+ if (scope->name() == name)
+ return scope;
+ }
+ return Scope::Ptr();
+}
+
+Property ScopeChain::lookupProperty(const QString &name) const
+{
+ foreach (const Scope::Ptr &scope, m_scopes) {
+ Property p = scope->properties.value(name);
+ if (p.isValid())
+ return p;
+ }
+ return Property();
+}
+
+ScopeChain::QueryFlags ScopeChain::queryProperty(const QScriptValue &object, const QScriptString &name,
+ QueryFlags flags, uint *id)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(name);
+ Q_UNUSED(id);
+ return (HandlesReadAccess | HandlesWriteAccess) & flags;
+}
+
+QScriptValue ScopeChain::property(const QScriptValue &object, const QScriptString &name, uint id)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(id);
+ QScriptValue value;
+ foreach (const Scope::Ptr &scope, m_scopes) {
+ value = scope->value.property(name);
+ if (value.isError()) {
+ engine()->clearExceptions();
+ } else if (value.isValid()) {
+ return value;
+ }
+ }
+ value = m_globalObject.property(name);
+ if (!value.isValid() || (value.isUndefined() && name.toString() != QLatin1String("undefined"))) {
+ QString msg("Undefined property '%1'");
+ value = engine()->currentContext()->throwError(msg.arg(name.toString()));
+ }
+ return value;
+}
+
+void ScopeChain::setProperty(QScriptValue &, const QScriptString &name, uint, const QScriptValue &)
+{
+ QString msg("Removing or setting property '%1' in a binding is invalid.");
+ engine()->currentContext()->throwError(msg.arg(name.toString()));
+}
+
+Property::Property(EvaluationObject * object)
+ : scope(object->scope)
+{
+}
+
+Property::Property(const QScriptValue &scriptValue)
+ : value(scriptValue)
+{
+}
+
+static QScriptValue evaluate(QScriptEngine *engine, const QScriptProgram &expression)
+{
+ QScriptValue result = engine->evaluate(expression);
+ if (engine->hasUncaughtException()) {
+ QString errorMessage = engine->uncaughtException().toString();
+ int errorLine = engine->uncaughtExceptionLineNumber();
+ engine->clearExceptions();
+ throw Error(errorMessage, expression.fileName(), errorLine);
+ }
+ if (result.isError())
+ throw Error(result.toString());
+ return result;
+}
+
+std::set<Scope *> Scope::scopesWithEvaluatedProperties;
+
+Scope::Scope(QScriptEngine *engine, const QString &name)
+ : QScriptClass(engine)
+ , m_name(name)
+{
+}
+
+QSharedPointer<Scope> Scope::create(QScriptEngine *engine, const QString &name, ProjectFile *owner)
+{
+ QSharedPointer<Scope> obj(new Scope(engine, name));
+ obj->value = engine->newObject(obj.data());
+ owner->registerScope(obj);
+ return obj;
+}
+
+Scope::~Scope()
+{
+}
+
+QString Scope::name() const
+{
+ return m_name;
+}
+
+static const bool debugProperties = false;
+
+Scope::QueryFlags Scope::queryProperty(const QScriptValue &object, const QScriptString &name,
+ QueryFlags flags, uint *id)
+{
+ const QString nameString = name.toString();
+ if (properties.contains(nameString)) {
+ *id = 0;
+ return (HandlesReadAccess | HandlesWriteAccess) & flags;
+ }
+ if (fallbackScope && fallbackScope.data()->queryProperty(object, name, flags, id)) {
+ *id = 1;
+ return (HandlesReadAccess | HandlesWriteAccess) & flags;
+ }
+
+ QScriptValue proto = value.prototype();
+ if (proto.isValid()) {
+ QScriptValue v = proto.property(name);
+ if (!v.isValid()) {
+ *id = 2;
+ return (HandlesReadAccess | HandlesWriteAccess) & flags;
+ }
+ }
+
+ if (debugProperties)
+ qbsTrace() << "PROPERTIES: we don't handle " << name.toString();
+ return 0;
+}
+
+QScriptValue Scope::property(const QScriptValue &object, const QScriptString &name, uint id)
+{
+ if (id == 1)
+ return fallbackScope.data()->property(object, name, 0);
+ else if (id == 2) {
+ QString msg = "Property %0.%1 is undefined.";
+ return engine()->currentContext()->throwError(msg.arg(m_name, name));
+ }
+
+ const QString nameString = name.toString();
+
+ Property property = properties.value(nameString);
+
+ if (debugProperties)
+ qbsTrace() << "PROPERTIES: evaluating " << nameString;
+
+ if (!property.isValid()) {
+ if (debugProperties)
+ qbsTrace() << " : no such property";
+ return QScriptValue(); // does this raise an error?
+ }
+
+ if (property.scope) {
+ if (debugProperties)
+ qbsTrace() << " : object property";
+ return property.scope->value;
+ }
+
+ if (property.value.isValid()) {
+ if (debugProperties)
+ qbsTrace() << " : pre-evaluated property: " << property.value.toVariant();
+ return property.value;
+ }
+
+ // evaluate now
+ if (debugProperties)
+ qbsTrace() << " : evaluating now: " << property.valueSource.sourceCode();
+ QScriptContext *context = engine()->currentContext();
+ const QScriptValue oldActivation = context->activationObject();
+ const QString &sourceCode = property.valueSource.sourceCode();
+
+ // evaluate base properties
+ QLatin1String baseValueName("base");
+ const bool usesBaseProperty = sourceCode.contains(baseValueName);
+ if (usesBaseProperty) {
+ foreach (const Property &baseProperty, property.baseProperties) {
+ context->setActivationObject(baseProperty.scopeChain->value());
+ QScriptValue baseValue;
+ try {
+ baseValue = evaluate(engine(), baseProperty.valueSource);
+ }
+ catch (Error &e)
+ {
+ baseValue = engine()->currentContext()->throwError("error while evaluating:\n" + e.toString());
+ }
+ engine()->globalObject().setProperty(baseValueName, baseValue);
+ }
+ }
+
+ context->setActivationObject(property.scopeChain->value());
+
+ QLatin1String oldValueName("outer");
+ const bool usesOldProperty = fallbackScope && sourceCode.contains(oldValueName);
+ if (usesOldProperty) {
+ QScriptValue oldValue = fallbackScope.data()->value.property(name);
+ if (oldValue.isValid() && !oldValue.isError())
+ engine()->globalObject().setProperty(oldValueName, oldValue);
+ }
+
+ QScriptValue result;
+ // Do not throw exceptions through the depths of the script engine.
+ try {
+ result = evaluate(engine(), property.valueSource);
+ }
+ catch (Error &e)
+ {
+ result = engine()->currentContext()->throwError("error while evaluating:\n" + e.toString());
+ }
+
+ if (debugProperties) {
+ qbsTrace() << "PROPERTIES: evaluated " << nameString << " to " << result.toVariant() << " " << result.toString();
+ if (result.isError())
+ qbsTrace() << " was error!";
+ }
+
+ Scope::scopesWithEvaluatedProperties.insert(this);
+ property.value = result;
+ properties.insert(nameString, property);
+
+ if (usesOldProperty)
+ engine()->globalObject().setProperty(oldValueName, engine()->undefinedValue());
+ if (usesBaseProperty)
+ engine()->globalObject().setProperty(baseValueName, engine()->undefinedValue());
+ context->setActivationObject(oldActivation);
+
+ return result;
+}
+
+QScriptValue Scope::property(const QString &name) const
+{
+ QScriptValue result = value.property(name);
+ if (result.isError())
+ throw Error(result.toString());
+ return result;
+}
+
+bool Scope::boolValue(const QString &name, bool defaultValue) const
+{
+ QScriptValue scriptValue = property(name);
+ if (scriptValue.isBool())
+ return scriptValue.toBool();
+ return defaultValue;
+}
+
+QString Scope::stringValue(const QString &name) const
+{
+ QScriptValue scriptValue = property(name);
+ if (scriptValue.isString())
+ return scriptValue.toString();
+ QVariant v = scriptValue.toVariant();
+ if (v.type() == QVariant::String) {
+ return v.toString();
+ } else if (v.type() == QVariant::StringList) {
+ const QStringList lst = v.toStringList();
+ if (lst.count() == 1)
+ return lst.first();
+ }
+ return QString();
+}
+
+QStringList Scope::stringListValue(const QString &name) const
+{
+ QScriptValue scriptValue = property(name);
+ if (scriptValue.isString()) {
+ return QStringList(scriptValue.toString());
+ } else if (scriptValue.isArray()) {
+ QStringList lst;
+ int i=0;
+ forever {
+ QScriptValue item = scriptValue.property(i++);
+ if (!item.isValid())
+ break;
+ if (!item.isString())
+ continue;
+ lst.append(item.toString());
+ }
+ return lst;
+ }
+ return QStringList();
+}
+
+QString Scope::verbatimValue(const QString &name) const
+{
+ const Property &property = properties.value(name);
+ return property.valueSource.sourceCode();
+}
+
+void Scope::dump(const QByteArray &aIndent) const
+{
+ QByteArray indent = aIndent;
+ printf("%sScope: {\n", indent.constData());
+ indent.append(dumpIndent);
+ printf("%sName: '%s'\n", indent.constData(), qPrintable(m_name));
+ if (!properties.isEmpty()) {
+ printf("%sProperties: [\n", indent.constData());
+ indent.append(dumpIndent);
+ foreach (const QString &propertyName, properties.keys()) {
+ QScriptValue scriptValue = property(propertyName);
+ QString propertyValue;
+ if (scriptValue.isString())
+ propertyValue = stringValue(propertyName);
+ else if (scriptValue.isArray())
+ propertyValue = stringListValue(propertyName).join(", ");
+ else if (scriptValue.isBool())
+ propertyValue = boolValue(propertyName) ? "true" : "false";
+ else
+ propertyValue = verbatimValue(propertyName);
+ printf("%s'%s': %s\n", indent.constData(), qPrintable(propertyName), qPrintable(propertyValue));
+ }
+ indent.chop(dumpIndent.length());
+ printf("%s]\n", indent.constData());
+ }
+ if (!declarations.isEmpty())
+ printf("%sPropertyDeclarations: [%s]\n", indent.constData(), qPrintable(QStringList(declarations.keys()).join(", ")));
+
+ indent.chop(dumpIndent.length());
+ printf("%s}\n", indent.constData());
+}
+
+EvaluationObject::EvaluationObject(LanguageObject *instantiatingObject)
+{
+ instantiatingObject->file->registerEvaluationObject(this);
+ objects.append(instantiatingObject);
+}
+
+EvaluationObject::~EvaluationObject()
+{
+ ProjectFile *file = instantiatingObject()->file;
+ if (!file->isDestructing())
+ file->unregisterEvaluationObject(this);
+}
+
+LanguageObject *EvaluationObject::instantiatingObject() const
+{
+ return objects.first();
+}
+
+void EvaluationObject::dump(QByteArray &indent)
+{
+ printf("%sEvaluationObject: {\n", indent.constData());
+ indent.append(dumpIndent);
+ printf("%sProtoType: '%s'\n", indent.constData(), qPrintable(prototype));
+ if (!modules.isEmpty()) {
+ printf("%sModules: [\n", indent.constData());
+ indent.append(dumpIndent);
+ foreach (const QSharedPointer<Module> module, modules)
+ module->dump(indent);
+ indent.chop(dumpIndent.length());
+ printf("%s]\n", indent.constData());
+ }
+ scope->dump(indent);
+ foreach (EvaluationObject *child, children)
+ child->dump(indent);
+ indent.chop(dumpIndent.length());
+ printf("%s}\n", indent.constData());
+}
+
+Module::Module()
+ : object(0)
+{
+}
+
+Module::~Module()
+{
+}
+
+ProjectFile *Module::file() const
+{
+ return object->instantiatingObject()->file;
+}
+
+void Module::dump(QByteArray &indent)
+{
+ printf("%s'%s': %s\n", indent.constData(), qPrintable(name), qPrintable(dependsLocation.fileName));
+}
+
+static QStringList resolvePaths(const QStringList &paths, const QString &base)
+{
+ QStringList resolved;
+ foreach (const QString &path, paths) {
+ QString resolvedPath = FileInfo::resolvePath(base, path);
+ resolvedPath = QDir::cleanPath(resolvedPath);
+ resolved += resolvedPath;
+ }
+ return resolved;
+}
+
+
+static const char szLoaderPropertyName[] = "qbs_loader_ptr";
+static const QLatin1String name_FileTagger("FileTagger");
+static const QLatin1String name_Rule("Rule");
+static const QLatin1String name_Transformer("Transformer");
+static const QLatin1String name_TransformProperties("TransformProperties");
+static const QLatin1String name_Artifact("Artifact");
+static const QLatin1String name_Group("Group");
+static const QLatin1String name_Project("Project");
+static const QLatin1String name_Product("Product");
+static const QLatin1String name_ProductModule("ProductModule");
+static const QLatin1String name_Module("Module");
+static const QLatin1String name_Properties("Properties");
+static const QLatin1String name_PropertyOptions("PropertyOptions");
+static const QLatin1String name_Depends("Depends");
+static const QLatin1String name_moduleSearchPaths("moduleSearchPaths");
+static const uint hashName_FileTagger = qHash(name_FileTagger);
+static const uint hashName_Rule = qHash(name_Rule);
+static const uint hashName_Transformer = qHash(name_Transformer);
+static const uint hashName_TransformProperties = qHash(name_TransformProperties);
+static const uint hashName_Artifact = qHash(name_Artifact);
+static const uint hashName_Group = qHash(name_Group);
+static const uint hashName_Project = qHash(name_Project);
+static const uint hashName_Product = qHash(name_Product);
+static const uint hashName_ProductModule = qHash(name_ProductModule);
+static const uint hashName_Module = qHash(name_Module);
+static const uint hashName_Properties = qHash(name_Properties);
+static const uint hashName_PropertyOptions = qHash(name_PropertyOptions);
+static const uint hashName_Depends = qHash(name_Depends);
+QHash<QString, PropertyDeclaration> Loader::m_dependsPropertyDeclarations;
+
+static const QLatin1String name_productPropertyScope("product property scope");
+static const QLatin1String name_projectPropertyScope("project property scope");
+
+Loader::Loader()
+{
+ m_settings = Settings::create();
+
+ QVariant v;
+ v.setValue(static_cast<void*>(this));
+ m_engine.setProperty(szLoaderPropertyName, v);
+ m_engine.pushContext(); // this preserves the original global object
+
+ m_jsFunction_getHostOS = m_engine.newFunction(js_getHostOS, 0);
+ m_jsFunction_getHostDefaultArchitecture = m_engine.newFunction(js_getHostDefaultArchitecture, 0);
+ m_jsFunction_configurationValue = m_engine.newFunction(js_configurationValue, 2);
+
+ if (m_dependsPropertyDeclarations.isEmpty()) {
+ QList<PropertyDeclaration> depends;
+ depends += PropertyDeclaration("name", PropertyDeclaration::String);
+ depends += PropertyDeclaration("submodules", PropertyDeclaration::Variant);
+ depends += PropertyDeclaration("condition", PropertyDeclaration::Boolean);
+ depends += PropertyDeclaration("required", PropertyDeclaration::Boolean);
+ depends += PropertyDeclaration("failureMessage", PropertyDeclaration::String);
+ foreach (const PropertyDeclaration &pd, depends)
+ m_dependsPropertyDeclarations.insert(pd.name, pd);
+ }
+}
+
+Loader::~Loader()
+{
+}
+
+static bool compare(const QStringList &list, const QString &value)
+{
+ if (list.size() != 1)
+ return false;
+ return list.first() == value;
+}
+
+void Loader::setSearchPaths(const QStringList &searchPaths)
+{
+ m_searchPaths = searchPaths;
+}
+
+ProjectFile::Ptr Loader::loadProject(const QString &fileName)
+{
+ m_settings->loadProjectSettings(fileName);
+ m_project = parseFile(fileName);
+ return m_project;
+}
+
+static void setPathAndFilePath(const Scope::Ptr &scope, const QString &filePath, const QString &prefix = QString())
+{
+ QString filePathPropertyName("filePath");
+ QString pathPropertyName("path");
+ if (!prefix.isEmpty()) {
+ filePathPropertyName = prefix + QLatin1String("FilePath");
+ pathPropertyName = prefix + QLatin1String("Path");
+ }
+ scope->properties.insert(filePathPropertyName, Property(QScriptValue(filePath)));
+ scope->properties.insert(pathPropertyName, Property(QScriptValue(FileInfo::path(filePath))));
+}
+
+Scope::Ptr Loader::buildFileContext(ProjectFile *file)
+{
+ Scope::Ptr context = Scope::create(&m_engine, QLatin1String("global file context"), file);
+ setPathAndFilePath(context, file->fileName, QLatin1String("local"));
+ evaluateImports(context, file->jsImports);
+
+ return context;
+}
+
+void Loader::resolveInheritance(LanguageObject *object, EvaluationObject *evaluationObject,
+ ScopeChain::Ptr moduleScope, const QVariantMap &userProperties)
+{
+ if (object->prototypeFileName.isEmpty()) {
+ if (object->prototype.size() != 1)
+ throw Error("prototype with dots does not resolve to a file", object->prototypeLocation);
+ evaluationObject->prototype = object->prototype.first();
+
+ setupInternalPrototype(evaluationObject);
+
+ // once we know something is a project/product, add a property to
+ // the correct scope
+ if (evaluationObject->prototype == name_Project) {
+ if (Scope::Ptr projectPropertyScope = moduleScope->find(name_projectPropertyScope))
+ projectPropertyScope->properties.insert("project", Property(evaluationObject));
+ }
+ else if (evaluationObject->prototype == name_Product) {
+ if (Scope::Ptr productPropertyScope = moduleScope->find(name_productPropertyScope))
+ productPropertyScope->properties.insert("product", Property(evaluationObject));
+ }
+
+ return;
+ }
+
+ // load prototype (cache result)
+ ProjectFile::Ptr file = parseFile(object->prototypeFileName);
+
+ // recurse to prototype's prototype
+ if (evaluationObject->objects.contains(file->root)) {
+ QString msg("circular prototypes in instantiation of '%1', '%2' recurred");
+ throw Error(msg.arg(evaluationObject->instantiatingObject()->prototype.join("."),
+ object->prototype.join(".")));
+ }
+ evaluationObject->objects.append(file->root);
+ resolveInheritance(file->root, evaluationObject, moduleScope, userProperties);
+
+ // ### expensive, and could be shared among all builds of this prototype instance
+ Scope::Ptr context = buildFileContext(file.data());
+
+ // project and product scopes are always available
+ ScopeChain::Ptr scopeChain(new ScopeChain(&m_engine, context));
+ if (Scope::Ptr projectPropertyScope = moduleScope->findNonEmpty(name_projectPropertyScope))
+ scopeChain->prepend(projectPropertyScope);
+ if (Scope::Ptr productPropertyScope = moduleScope->findNonEmpty(name_productPropertyScope))
+ scopeChain->prepend(productPropertyScope);
+
+ scopeChain->prepend(evaluationObject->scope);
+
+ // having a module scope enables resolving of Depends blocks
+ if (moduleScope)
+ evaluateDependencies(file->root, evaluationObject, scopeChain, moduleScope, userProperties);
+
+ fillEvaluationObject(scopeChain, file->root, evaluationObject->scope, evaluationObject, userProperties);
+
+// QByteArray indent;
+// evaluationObject->dump(indent);
+}
+
+static bool checkFileCondition(QScriptEngine *engine, const ScopeChain::Ptr &scope, const ProjectFile *file)
+{
+ static const bool debugCondition = false;
+ if (debugCondition)
+ qbsTrace() << "Checking condition";
+
+ const Binding &condition = file->root->bindings.value(QStringList("condition"));
+ if (!condition.isValid())
+ return true;
+
+ QScriptContext *context = engine->currentContext();
+ const QScriptValue oldActivation = context->activationObject();
+ context->setActivationObject(scope->value());
+
+ if (debugCondition)
+ qbsTrace() << " code is: " << condition.valueSource.sourceCode();
+ const QScriptValue value = evaluate(engine, condition.valueSource);
+ bool result = false;
+ if (value.isBool())
+ result = value.toBool();
+ else
+ throw Error(QString("Condition return type must be boolean."), CodeLocation(condition.valueSource.fileName(), condition.valueSource.firstLineNumber()));
+ if (debugCondition)
+ qbsTrace() << " result: " << value.toString();
+
+ context->setActivationObject(oldActivation);
+ return result;
+}
+
+static void applyFunctions(QScriptEngine *engine, LanguageObject *object, EvaluationObject *evaluationObject, ScopeChain::Ptr scope)
+{
+ if (object->functions.isEmpty())
+ return;
+
+ // set the activation object to the correct scope
+ QScriptValue oldActivation = engine->currentContext()->activationObject();
+ engine->currentContext()->setActivationObject(scope->value());
+
+ foreach (const Function &func, object->functions) {
+ Property property;
+ property.value = evaluate(engine, func.source);
+ evaluationObject->scope->properties.insert(func.name, property);
+ }
+
+ engine->currentContext()->setActivationObject(oldActivation);
+}
+
+static void testIfValueIsAllowed(const QVariant &value, const QVariant &allowedValues,
+ const QString &propertyName, const CodeLocation &location)
+{
+ bool valueIsAllowed = false;
+
+ if (value.type() == QVariant::String && allowedValues.type() == QVariant::List)
+ valueIsAllowed = allowedValues.toStringList().contains(value.toString());
+ else if (value.type() == QVariant::Int && allowedValues.type() == QVariant::List)
+ valueIsAllowed = allowedValues.toList().contains(value);
+ else {
+ const QString msg = "The combination of the type of Property '%1' and the type of its allowedValues is not supported";
+ throw Error(msg.arg(propertyName), location);
+ }
+
+ if (!valueIsAllowed) {
+ const QString msg = "Value '%1' is not allowed for Property '%2'";
+ throw Error(msg.arg(value.toString()).arg(propertyName), location); // TODO: print out allowed values?
+ }
+}
+
+static void applyBinding(LanguageObject *object, const Binding &binding, const ScopeChain::Ptr &scopeChain)
+{
+ CodeLocation bindingLocation(binding.valueSource.fileName(),
+ binding.valueSource.firstLineNumber());
+ Scope *target;
+ if (binding.name.size() == 1) {
+ target = scopeChain->first().data(); // assume the top scope is the 'current' one
+ } else {
+ if (compare(object->prototype, name_Artifact))
+ return;
+ QScriptValue targetValue = scopeChain->value().property(binding.name.first());
+ if (!targetValue.isValid() || targetValue.isError()) {
+ QString msg = "Binding '%1' failed, no property '%2' in the scope of %3";
+ throw Error(msg.arg(binding.name.join("."),
+ binding.name.first(),
+ scopeChain->first()->name()),
+ bindingLocation);
+ }
+ target = dynamic_cast<Scope *>(targetValue.scriptClass());
+ if (!target) {
+ QString msg = "Binding '%1' failed, property '%2' in the scope of %3 has no properties";
+ throw Error(msg.arg(binding.name.join("."),
+ binding.name.first(),
+ scopeChain->first()->name()),
+ bindingLocation);
+ }
+ }
+
+ for (int i = 1; i < binding.name.size() - 1; ++i) {
+ Scope *oldTarget = target;
+ const QString &bindingName = binding.name.at(i);
+ const QScriptValue &value = target->property(bindingName);
+ if (!value.isValid()) {
+ QString msg = "Binding '%1' failed, no property '%2' in %3";
+ throw Error(msg.arg(binding.name.join("."),
+ binding.name.at(i),
+ target->name()),
+ bindingLocation);
+ }
+ target = dynamic_cast<Scope *>(value.scriptClass());
+ if (!target) {
+ QString msg = "Binding '%1' failed, property '%2' in %3 has no properties";
+ throw Error(msg.arg(binding.name.join("."),
+ bindingName,
+ oldTarget->name()),
+ bindingLocation);
+ }
+ }
+
+ const QString name = binding.name.last();
+
+ if (!target->declarations.contains(name)) {
+ QString msg = "Binding '%1' failed, no property '%2' in %3";
+ throw Error(msg.arg(binding.name.join("."),
+ name,
+ target->name()),
+ bindingLocation);
+ }
+
+ Property newProperty;
+ newProperty.valueSource = binding.valueSource;
+ newProperty.scopeChain = scopeChain;
+
+ Property &property = target->properties[name];
+ if (!property.valueSource.isNull()) {
+ newProperty.baseProperties += property.baseProperties;
+ property.baseProperties.clear();
+ newProperty.baseProperties += property;
+ }
+ property = newProperty;
+
+ const PropertyDeclaration &decl = object->propertyDeclarations.value(name);
+ // ### testIfValueIsAllowed is wrong here...
+ if (!decl.allowedValues.isNull())
+ testIfValueIsAllowed(target->property(name).toVariant(), decl.allowedValues, name, bindingLocation);
+}
+
+static void applyBindings(LanguageObject *object, ScopeChain::Ptr scopeChain)
+{
+ foreach (const Binding &binding, object->bindings)
+ applyBinding(object, binding, scopeChain);
+}
+
+void Loader::fillEvaluationObjectForProperties(const ScopeChain::Ptr &scope, LanguageObject *object, Scope::Ptr ids, EvaluationObject *evaluationObject, const QVariantMap &userProperties)
+{
+ if (!object->children.isEmpty())
+ throw Error("Properties block may not have children", object->children.first()->prototypeLocation);
+
+ const QStringList conditionName("condition");
+ Binding condition = object->bindings.value(conditionName);
+ if (!condition.isValid())
+ throw Error("Properties block must have a condition property", object->prototypeLocation);
+
+ LanguageObject *ifCopy = new LanguageObject(*object);
+
+ // adjust bindings to be if (condition) { original-source }
+ QMutableHashIterator<QStringList, Binding> it(ifCopy->bindings);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key() == conditionName) {
+ it.remove();
+ continue;
+ }
+ Binding &binding = it.value();
+ binding.valueSource = QScriptProgram(
+ QString("if (%1) { %2 }").arg(
+ condition.valueSource.sourceCode(),
+ binding.valueSource.sourceCode()),
+ binding.valueSource.fileName(),
+ binding.valueSource.firstLineNumber());
+ }
+
+ fillEvaluationObject(scope, ifCopy, ids, evaluationObject, userProperties);
+}
+
+void Loader::setupInternalPrototype(EvaluationObject *evaluationObject)
+{
+ // special builtins
+ static QHash<QString, QList<PropertyDeclaration> > builtinDeclarations;
+ if (builtinDeclarations.isEmpty()) {
+ builtinDeclarations.insert(name_Depends, m_dependsPropertyDeclarations.values());
+ PropertyDeclaration conditionProperty("condition", PropertyDeclaration::Boolean);
+
+ QList<PropertyDeclaration> project;
+ project += PropertyDeclaration("references", PropertyDeclaration::Variant);
+ project += PropertyDeclaration(name_moduleSearchPaths, PropertyDeclaration::Variant);
+ builtinDeclarations.insert(name_Project, project);
+
+ QList<PropertyDeclaration> product;
+ product += PropertyDeclaration("type", PropertyDeclaration::String);
+ product += PropertyDeclaration("name", PropertyDeclaration::String);
+ product += PropertyDeclaration("destination", PropertyDeclaration::String);
+ product += PropertyDeclaration("files", PropertyDeclaration::Variant, PropertyDeclaration::PropertyNotAvailableInConfig);
+ product += PropertyDeclaration("module", PropertyDeclaration::Variant);
+ product += PropertyDeclaration("modules", PropertyDeclaration::Variant);
+ product += PropertyDeclaration(name_moduleSearchPaths, PropertyDeclaration::Variant);
+ builtinDeclarations.insert(name_Product, product);
+
+ QList<PropertyDeclaration> fileTagger;
+ fileTagger += PropertyDeclaration("pattern", PropertyDeclaration::String);
+ fileTagger += PropertyDeclaration("fileTags", PropertyDeclaration::Variant);
+ builtinDeclarations.insert(name_FileTagger, fileTagger);
+
+ QList<PropertyDeclaration> group;
+ group += conditionProperty;
+ group += PropertyDeclaration("files", PropertyDeclaration::Variant, PropertyDeclaration::PropertyNotAvailableInConfig);
+ group += PropertyDeclaration("fileTags", PropertyDeclaration::Variant, PropertyDeclaration::PropertyNotAvailableInConfig);
+ group += PropertyDeclaration("prefix", PropertyDeclaration::Variant, PropertyDeclaration::PropertyNotAvailableInConfig);
+ builtinDeclarations.insert(name_Group, group);
+
+ QList<PropertyDeclaration> artifact;
+ artifact += conditionProperty;
+ artifact += PropertyDeclaration("fileName", PropertyDeclaration::Verbatim);
+ artifact += PropertyDeclaration("fileTags", PropertyDeclaration::Variant);
+ builtinDeclarations.insert(name_Artifact, artifact);
+
+ QList<PropertyDeclaration> rule;
+ rule += PropertyDeclaration("multiplex", PropertyDeclaration::Boolean);
+ rule += PropertyDeclaration("inputs", PropertyDeclaration::Variant);
+ rule += PropertyDeclaration("usings", PropertyDeclaration::Variant);
+ rule += PropertyDeclaration("explicitlyDependsOn", PropertyDeclaration::Variant);
+ rule += PropertyDeclaration("prepare", PropertyDeclaration::Verbatim);
+ builtinDeclarations.insert(name_Rule, rule);
+
+ QList<PropertyDeclaration> transformer;
+ transformer += PropertyDeclaration("inputs", PropertyDeclaration::Variant);
+ transformer += PropertyDeclaration("prepare", PropertyDeclaration::Verbatim);
+ transformer += conditionProperty;
+ builtinDeclarations.insert(name_Transformer, transformer);
+
+ QList<PropertyDeclaration> transformProperties;
+ builtinDeclarations.insert(name_TransformProperties, transformProperties);
+
+ QList<PropertyDeclaration> productModule;
+ builtinDeclarations.insert(name_ProductModule, productModule);
+
+ QList<PropertyDeclaration> module;
+ module += PropertyDeclaration("name", PropertyDeclaration::String);
+ module += PropertyDeclaration("setupBuildEnvironment", PropertyDeclaration::Verbatim);
+ module += PropertyDeclaration("setupRunEnvironment", PropertyDeclaration::Verbatim);
+ module += PropertyDeclaration("additionalProductFileTags", PropertyDeclaration::Variant);
+ module += conditionProperty;
+ builtinDeclarations.insert(name_Module, module);
+
+ QList<PropertyDeclaration> propertyOptions;
+ propertyOptions += PropertyDeclaration("name", PropertyDeclaration::String);
+ propertyOptions += PropertyDeclaration("allowedValues", PropertyDeclaration::Variant);
+ propertyOptions += PropertyDeclaration("description", PropertyDeclaration::String);
+ builtinDeclarations.insert(name_PropertyOptions, propertyOptions);
+ }
+
+ if (!builtinDeclarations.contains(evaluationObject->prototype))
+ throw Error(QString("Type name '%1' is unknown.").arg(evaluationObject->prototype),
+ evaluationObject->instantiatingObject()->prototypeLocation);
+
+ foreach (const PropertyDeclaration &pd, builtinDeclarations.value(evaluationObject->prototype)) {
+ evaluationObject->scope->declarations.insert(pd.name, pd);
+ evaluationObject->scope->properties.insert(pd.name, Property(m_engine.undefinedValue()));
+ }
+}
+
+void Loader::fillEvaluationObject(const ScopeChain::Ptr &scope, LanguageObject *object, Scope::Ptr ids, EvaluationObject *evaluationObject, const QVariantMap &userProperties)
+{
+ // fill subobjects recursively
+ foreach (LanguageObject *child, object->children) {
+ // 'Properties' objects are treated specially, they don't introduce a scope
+ // and don't get added as a child object
+ if (compare(child->prototype, name_Properties)) {
+ fillEvaluationObjectForProperties(scope, child, ids, evaluationObject, userProperties);
+ continue;
+ }
+
+ // 'Depends' blocks are already handled before this function is called
+ // and should not appear in the children list
+ if (compare(child->prototype, name_Depends))
+ continue;
+
+ EvaluationObject *childEvObject = new EvaluationObject(child);
+ const QString propertiesName = child->prototype.join(QLatin1String("."));
+ childEvObject->scope = Scope::create(&m_engine, propertiesName, object->file);
+
+ resolveInheritance(child, childEvObject); // ### need to pass 'moduleScope' for product/project property scopes
+ const uint childPrototypeHash = qHash(childEvObject->prototype);
+
+ ScopeChain::Ptr childScope(scope->clone()->prepend(childEvObject->scope));
+
+ if (!child->id.isEmpty()) {
+ ids->properties.insert(child->id, Property(childEvObject));
+ }
+
+ // for Group and ProjectModule, add new module instances
+ const bool isProductModule = (childPrototypeHash == hashName_ProductModule);
+ const bool isArtifact = (childPrototypeHash == hashName_Artifact);
+ if (isProductModule || isArtifact || childPrototypeHash == hashName_Group) {
+ QHashIterator<QString, Module::Ptr> moduleIt(evaluationObject->modules);
+ while (moduleIt.hasNext()) {
+ moduleIt.next();
+ Module::Ptr module = moduleIt.value();
+ if (module->id.isEmpty())
+ continue;
+ Scope::Ptr moduleInstance = Scope::create(&m_engine, module->object->scope->name(), module->file());
+ if (isProductModule) {
+ // A ProductModule does not inherit module values set in the product
+ // but has its own module instance.
+ ScopeChain::Ptr moduleScope(new ScopeChain(&m_engine));
+ moduleScope->prepend(scope->findNonEmpty(name_productPropertyScope));
+ moduleScope->prepend(scope->findNonEmpty(name_projectPropertyScope));
+ moduleScope->prepend(childEvObject->scope);
+ module = loadModule(module->file(), module->id, module->name, moduleScope, userProperties, module->dependsLocation);
+ childEvObject->modules.insert(module->name, module);
+ }
+ if (!isArtifact)
+ moduleInstance->fallbackScope = module->object->scope;
+ moduleInstance->declarations = module->object->scope->declarations;
+ Property property(moduleInstance);
+ childEvObject->scope->properties.insert(module->id, property);
+ }
+ }
+
+ // for TransformProperties, add declarations to parent
+ if (childPrototypeHash == hashName_TransformProperties) {
+ for (QHash<QString, PropertyDeclaration>::const_iterator it = child->propertyDeclarations.begin();
+ it != child->propertyDeclarations.end(); ++it) {
+ evaluationObject->scope->declarations.insert(it.key(), it.value());
+ }
+ }
+
+ fillEvaluationObject(childScope, child, ids, childEvObject, userProperties);
+ evaluationObject->children.append(childEvObject);
+ }
+
+ fillEvaluationObjectBasics(scope, object, evaluationObject);
+}
+
+void Loader::fillEvaluationObjectBasics(const ScopeChain::Ptr &scopeChain, LanguageObject *object, EvaluationObject *evaluationObject)
+{
+ // append the property declarations
+ foreach (const PropertyDeclaration &pd, object->propertyDeclarations)
+ if (!evaluationObject->scope->declarations.contains(pd.name))
+ evaluationObject->scope->declarations.insert(pd.name, pd);
+
+ applyFunctions(&m_engine, object, evaluationObject, scopeChain);
+ applyBindings(object, scopeChain);
+}
+
+void Loader::evaluateImports(Scope::Ptr target, const JsImports &jsImports)
+{
+ for (JsImports::const_iterator importIt = jsImports.begin();
+ importIt != jsImports.end(); ++importIt) {
+
+ QScriptValue targetObject = m_engine.newObject();
+ foreach (const QString &fileName, importIt.value()) {
+ QScriptValue importResult = m_jsImports.value(fileName);
+ if (importResult.isValid()) {
+ targetObject = importResult;
+ } else {
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ QString msg("Couldn't open js import '%1'.");
+ // ### location
+ throw Error(msg.arg(fileName));
+ continue;
+ }
+ const QString source = QTextStream(&file).readAll();
+ file.close();
+ const QScriptProgram program(source, fileName);
+ importResult = addJSImport(&m_engine, program, targetObject);
+ if (importResult.isError())
+ throw Error(QLatin1String("error while evaluating import: ") + importResult.toString());
+
+ m_jsImports.insert(fileName, targetObject);
+ }
+ }
+
+ target->properties.insert(importIt.key(), Property(targetObject));
+ }
+}
+
+void Loader::evaluatePropertyOptions(LanguageObject *object)
+{
+ foreach (LanguageObject *child, object->children) {
+ if (child->prototype.last() != name_PropertyOptions)
+ continue;
+
+ const Binding nameBinding = child->bindings.value(QStringList("name"));
+
+ if (!nameBinding.isValid())
+ throw Error(name_PropertyOptions + " needs to define a 'name'");
+
+ const QScriptValue nameScriptValue = evaluate(&m_engine, nameBinding.valueSource);
+ const QString name = nameScriptValue.toString();
+
+ if (!object->propertyDeclarations.contains(name))
+ throw Error(QString("no propery with name '%1' found").arg(name));
+
+ PropertyDeclaration &decl = object->propertyDeclarations[name];
+
+ const Binding allowedValuesBinding = child->bindings.value(QStringList("allowedValues"));
+ if (allowedValuesBinding.isValid()) {
+ const QScriptValue allowedValuesScriptValue = evaluate(&m_engine, allowedValuesBinding.valueSource);
+ decl.allowedValues = allowedValuesScriptValue.toVariant();
+ }
+
+ const Binding descriptionBinding = child->bindings.value(QStringList("description"));
+ if (descriptionBinding.isValid()) {
+ const QScriptValue description = evaluate(&m_engine, descriptionBinding.valueSource);
+ decl.description = description.toString();
+ }
+ }
+}
+
+Module::Ptr Loader::loadModule(ProjectFile *file, const QString &moduleId, const QString &moduleName,
+ ScopeChain::Ptr moduleBaseScope, const QVariantMap &userProperties,
+ const CodeLocation &dependsLocation)
+{
+ const bool isBaseModule = (moduleName == "qbs");
+
+ Module::Ptr module = Module::Ptr(new Module);
+ module->id = moduleId;
+ module->name = moduleName;
+ module->dependsLocation = dependsLocation;
+ module->object = new EvaluationObject(file->root);
+ const QString propertiesName = QString("module %1").arg(moduleName);
+ module->object->scope = Scope::create(&m_engine, propertiesName, file);
+
+ resolveInheritance(file->root, module->object, moduleBaseScope, userProperties);
+ if (module->object->prototype != name_Module)
+ return Module::Ptr();
+
+ module->object->scope->properties.insert("name", Property(m_engine.toScriptValue(moduleName)));
+ module->context = buildFileContext(file);
+
+ ScopeChain::Ptr moduleScope(moduleBaseScope->clone());
+ moduleScope->prepend(module->context);
+ moduleScope->prepend(module->object->scope);
+ if (isBaseModule) {
+ // setup helper properties of the base module
+ Property p;
+ p.value = m_jsFunction_getHostOS;
+ module->object->scope->properties.insert("getHostOS", p);
+ p.value = m_jsFunction_getHostDefaultArchitecture;
+ module->object->scope->properties.insert("getHostDefaultArchitecture", p);
+ p.value = m_jsFunction_configurationValue;
+ module->object->scope->properties.insert("configurationValue", p);
+ }
+
+ evaluatePropertyOptions(file->root);
+ evaluateDependencies(file->root, module->object, moduleScope, moduleBaseScope, userProperties, !isBaseModule);
+ if (!module->object->unknownModules.isEmpty()) {
+ QString msg;
+ foreach (const UnknownModule &missingModule, module->object->unknownModules) {
+ msg.append(Error(QString("Module '%1' cannot be loaded.").arg(missingModule.name),
+ missingModule.dependsLocation).toString());
+ msg.append("\n");
+ }
+ throw Error(msg);
+ }
+ buildModulesProperty(module->object);
+
+ if (checkFileCondition(&m_engine, moduleScope, file)) {
+ qbsTrace() << "loading module '" << moduleName << "' from " << file->fileName;
+ if (!file->root->id.isEmpty())
+ module->context->properties.insert(file->root->id, Property(module->object));
+ fillEvaluationObject(moduleScope, file->root, module->object->scope, module->object, userProperties);
+
+ // override properties given on the command line
+ const QVariantMap userModuleProperties = userProperties.value(moduleName).toMap();
+ for (QVariantMap::const_iterator vmit = userModuleProperties.begin(); vmit != userModuleProperties.end(); ++vmit) {
+ if (!module->object->scope->properties.contains(vmit.key()))
+ throw Error("Unknown property: " + module->id + '.' + vmit.key());
+ module->object->scope->properties.insert(vmit.key(), Property(m_engine.toScriptValue(vmit.value())));
+
+ const PropertyDeclaration &decl = module->object->scope->declarations.value(vmit.key());
+ if (!decl.allowedValues.isNull())
+ testIfValueIsAllowed(vmit.value(), decl.allowedValues, vmit.key(), dependsLocation);
+ }
+
+ return module;
+ }
+
+ return Module::Ptr();
+}
+
+/// load all module.qbs files, checking their conditions
+Module::Ptr Loader::loadModule(const QString &moduleId, const QString &moduleName, ScopeChain::Ptr moduleBaseScope,
+ const QVariantMap &userProperties, const CodeLocation &dependsLocation,
+ const QStringList &extraSearchPaths)
+{
+ Q_ASSERT(!moduleName.isEmpty());
+
+ Module::Ptr module;
+ QStringList searchPaths = extraSearchPaths;
+
+ const QString searchSubDir("modules");
+ foreach (const QString &path, m_searchPaths)
+ searchPaths += FileInfo::resolvePath(path, searchSubDir);
+
+ foreach (const QString &path, searchPaths) {
+ QString dirPath = FileInfo::resolvePath(path, moduleName);
+ QFileInfo dirInfo(dirPath);
+ if (!dirInfo.isDir()) {
+ bool found = false;
+#ifndef Q_OS_WIN
+ // On case sensitive file systems try to find the path.
+ QStringList subPaths = moduleName.split("/", QString::SkipEmptyParts);
+ QDir dir(path);
+ if (!dir.cd(searchSubDir))
+ continue;
+ do {
+ QStringList lst = dir.entryList(QStringList(subPaths.takeFirst()), QDir::Dirs);
+ if (lst.count() != 1)
+ break;
+ if (!dir.cd(lst.first()))
+ break;
+ if (subPaths.isEmpty()) {
+ found = true;
+ dirPath = dir.absolutePath();
+ }
+ } while (!found);
+#endif
+ if (!found)
+ continue;
+ }
+
+ QDirIterator dirIter(dirPath, QStringList("*.qbs"));
+ while (dirIter.hasNext()) {
+ QString fileName = dirIter.next();
+ ProjectFile::Ptr file = parseFile(fileName);
+ if (!file)
+ throw Error("Error while parsing file: " + fileName, dependsLocation);
+
+ module = loadModule(file.data(), moduleId, moduleName, moduleBaseScope, userProperties, dependsLocation);
+ if (module)
+ break;
+ }
+ if (module)
+ break;
+ }
+
+ return module;
+}
+
+void Loader::evaluateDependencies(LanguageObject *object, EvaluationObject *evaluationObject, const ScopeChain::Ptr &localScope,
+ ScopeChain::Ptr moduleScope, const QVariantMap &userProperties, bool loadBaseModule)
+{
+ // check for additional module search paths in the product
+ Binding searchPathsBinding = object->bindings.value(QStringList(name_moduleSearchPaths));
+ if (searchPathsBinding.isValid())
+ applyBinding(object, searchPathsBinding, localScope);
+
+ // if none found, check for additional module search paths in the project
+ QStringList extraSearchPaths;
+ Property projectProperty = localScope->lookupProperty("project");
+ if (projectProperty.isValid() && projectProperty.scope) {
+ extraSearchPaths = projectProperty.scope->stringListValue(name_moduleSearchPaths);
+ // ### depends on the project.path property
+ extraSearchPaths = resolvePaths(extraSearchPaths, projectProperty.scope->stringValue("path"));
+ }
+
+ if (loadBaseModule) {
+ Module::Ptr baseModule = loadModule("qbs", "qbs", moduleScope, userProperties, CodeLocation(object->file->fileName));
+ if (!baseModule)
+ throw Error("Cannot load the qbs base module.");
+ evaluationObject->modules.insert(baseModule->name, baseModule);
+ evaluationObject->scope->properties.insert(baseModule->id, Property(baseModule->object));
+ }
+
+ foreach (LanguageObject *child, object->children) {
+ if (compare(child->prototype, name_Depends)) {
+ QList<UnknownModule> unknownModules;
+ foreach (const Module::Ptr &m, evaluateDependency(evaluationObject, child, moduleScope, extraSearchPaths, &unknownModules, userProperties)) {
+ evaluationObject->modules.insert(m->name, m);
+ evaluationObject->scope->properties.insert(m->id, Property(m->object));
+ }
+ evaluationObject->unknownModules.append(unknownModules);
+ }
+ }
+}
+
+void Loader::buildModulesProperty(EvaluationObject *evaluationObject)
+{
+ // set up a XXX.modules property
+ Scope::Ptr modules = Scope::create(&m_engine, QLatin1String("modules property"), evaluationObject->instantiatingObject()->file);
+ for (QHash<QString, Module::Ptr>::const_iterator it = evaluationObject->modules.begin();
+ it != evaluationObject->modules.end(); ++it)
+ {
+ modules->properties.insert(it.key(), Property(it.value()->object));
+ modules->declarations.insert(it.key(), PropertyDeclaration(it.key(), PropertyDeclaration::Variant));
+ }
+ evaluationObject->scope->properties.insert("modules", Property(modules));
+ evaluationObject->scope->declarations.insert("modules", PropertyDeclaration("modules", PropertyDeclaration::Variant));
+}
+
+QList<Module::Ptr> Loader::evaluateDependency(EvaluationObject *parentEObj, LanguageObject *depends, ScopeChain::Ptr moduleScope,
+ const QStringList &extraSearchPaths,
+ QList<UnknownModule> *unknownModules, const QVariantMap &userProperties)
+{
+ const CodeLocation dependsLocation = depends->prototypeLocation;
+
+ // check for the use of undeclared properties
+ foreach (const Binding &binding, depends->bindings) {
+ if (binding.name.count() > 1)
+ throw Error("Bindings with dots are forbidden in Depends.", dependsLocation);
+ if (!m_dependsPropertyDeclarations.contains(binding.name.first()))
+ throw Error(QString("There's no property '%1' in Depends.").arg(binding.name.first()),
+ CodeLocation(depends->file->fileName, binding.valueSource.firstLineNumber()));
+ }
+
+ // check condition
+ Binding binding = depends->bindings.value(QStringList("condition"));
+ if (binding.isValid()) {
+ QScriptValue v = evaluate(&m_engine, binding.valueSource);
+ if (!v.toBool())
+ return QList<Module::Ptr>();
+ }
+
+ bool isRequired = true;
+ binding = depends->bindings.value(QStringList("required"));
+ if (!binding.valueSource.isNull())
+ isRequired = evaluate(&m_engine, binding.valueSource).toBool();
+
+ QString failureMessage;
+ binding = depends->bindings.value(QStringList("failureMessage"));
+ if (!binding.valueSource.isNull())
+ failureMessage = evaluate(&m_engine, binding.valueSource).toString();
+
+ QString moduleName;
+ binding = depends->bindings.value(QStringList("name"));
+ if (!binding.valueSource.isNull()) {
+ moduleName = evaluate(&m_engine, binding.valueSource).toString();
+ } else {
+ moduleName = depends->id;
+ }
+
+ if (parentEObj->modules.contains(moduleName)) {
+ // If the module is already in the target object then don't add it a second time.
+ // This is for the case where you have the same module in the instantiating object
+ // and in a base object.
+ //
+ // ---Foo.qbs---
+ // Product {
+ // cpp.defines: ["BEAGLE"]
+ // Depends { name: "cpp" }
+ // }
+ //
+ // ---bar.qbp---
+ // Foo {
+ // Depends { name: "cpp" }
+ // }
+ //
+ return QList<Module::Ptr>();
+ }
+
+ QString moduleId = depends->id;
+ if (moduleId.isEmpty())
+ moduleId = moduleName;
+
+ QStringList subModules;
+ Binding subModulesBinding = depends->bindings.value(QStringList("submodules"));
+ if (!subModulesBinding.valueSource.isNull())
+ subModules = evaluate(&m_engine, subModulesBinding.valueSource).toVariant().toStringList();
+
+ QStringList fullModuleIds;
+ QStringList fullModuleNames;
+ if (subModules.isEmpty()) {
+ fullModuleIds.append(moduleId);
+ fullModuleNames.append(moduleName.toLower().replace('.', "/"));
+ } else {
+ foreach (const QString &subModuleName, subModules) {
+ fullModuleIds.append(moduleId + "." + subModuleName);
+ fullModuleNames.append(moduleName.toLower().replace('.', "/") + "/" + subModuleName.toLower().replace('.', "/"));
+ }
+ }
+
+ QList<Module::Ptr> modules;
+ unknownModules->clear();
+ for (int i=0; i < fullModuleNames.count(); ++i) {
+ const QString &fullModuleName = fullModuleNames.at(i);
+ Module::Ptr module = loadModule(fullModuleIds.at(i), fullModuleName, moduleScope, userProperties, dependsLocation, extraSearchPaths);
+ if (module) {
+ modules.append(module);
+ } else {
+ UnknownModule unknownModule;
+ unknownModule.name = fullModuleName;
+ unknownModule.required = isRequired;
+ unknownModule.failureMessage = failureMessage;
+ unknownModule.dependsLocation = dependsLocation;
+ unknownModules->append(unknownModule);
+ }
+ }
+ return modules;
+}
+
+static void findModuleDependencies_impl(const Module::Ptr &module, QHash<QString, ProjectFile *> &result)
+{
+ QString moduleName = module->name;
+ ProjectFile *file = module->file();
+ ProjectFile *otherFile = result.value(moduleName);
+ if (otherFile && otherFile != file) {
+ throw Error(QString("two different versions of '%1' were included: '%2' and '%3'").arg(
+ moduleName, file->fileName, otherFile->fileName));
+ } else if (otherFile) {
+ return;
+ }
+
+ result.insert(moduleName, file);
+ foreach (const Module::Ptr &depModule, module->object->modules) {
+ findModuleDependencies_impl(depModule, result);
+ }
+}
+
+static QHash<QString, ProjectFile *> findModuleDependencies(EvaluationObject *root)
+{
+ QHash<QString, ProjectFile *> result;
+ foreach (const Module::Ptr &module, root->modules) {
+ foreach (const Module::Ptr &depModule, module->object->modules) {
+ findModuleDependencies_impl(depModule, result);
+ }
+ }
+ return result;
+}
+
+static QVariantMap evaluateAll(const ResolvedProduct::Ptr &rproduct, const Scope::Ptr &properties)
+{
+ QVariantMap result;
+
+ if (properties->fallbackScope)
+ result = evaluateAll(rproduct, properties->fallbackScope);
+
+ typedef QHash<QString, PropertyDeclaration>::const_iterator iter;
+ iter end = properties->declarations.end();
+ for (iter it = properties->declarations.begin(); it != end; ++it) {
+ const PropertyDeclaration &decl = it.value();
+ if (decl.type == PropertyDeclaration::Verbatim || decl.flags.testFlag(PropertyDeclaration::PropertyNotAvailableInConfig))
+ continue;
+
+ Property property = properties->properties.value(it.key());
+ if (!property.isValid())
+ continue;
+
+ QVariant value;
+ if (property.scope) {
+ value = evaluateAll(rproduct, property.scope);
+ } else {
+ value = properties->property(it.key()).toVariant();
+ }
+
+ if (decl.type == PropertyDeclaration::Paths) {
+ QStringList lst = value.toStringList();
+ value = resolvePaths(lst, rproduct->sourceDirectory);
+ }
+
+ result.insert(it.key(), value);
+ }
+ return result;
+}
+
+static void clearCachedValues()
+{
+ QScriptValue nullScriptValue;
+ const std::set<Scope *>::const_iterator scopeEnd = Scope::scopesWithEvaluatedProperties.end();
+ for (std::set<Scope *>::const_iterator it = Scope::scopesWithEvaluatedProperties.begin(); it != scopeEnd; ++it) {
+ const QHash<QString, Property>::iterator propertiesEnd = (*it)->properties.end();
+ for (QHash<QString, Property>::iterator pit = (*it)->properties.begin(); pit != propertiesEnd; ++pit) {
+ Property &property = pit.value();
+ if (!property.valueSource.isNull())
+ property.value = nullScriptValue;
+ }
+ }
+ Scope::scopesWithEvaluatedProperties.clear();
+}
+
+int Loader::productCount(Configuration::Ptr userProperties)
+{
+ Q_ASSERT(hasLoaded());
+
+ LanguageObject *object = m_project->root;
+ EvaluationObject *evaluationObject = new EvaluationObject(object);
+
+ const QString propertiesName = object->prototype.join(".");
+ evaluationObject->scope = Scope::create(&m_engine, propertiesName, m_project->root->file);
+
+ Scope::Ptr productProperty = Scope::create(&m_engine, name_productPropertyScope, m_project->root->file);
+ Scope::Ptr projectProperty = Scope::create(&m_engine, name_projectPropertyScope, m_project->root->file);
+
+ // for the 'product' and 'project' property available to the modules
+ ScopeChain::Ptr moduleScope(new ScopeChain(&m_engine));
+ moduleScope->prepend(productProperty);
+ moduleScope->prepend(projectProperty);
+
+ ScopeChain::Ptr localScope(new ScopeChain(&m_engine));
+ localScope->prepend(productProperty);
+ localScope->prepend(projectProperty);
+ localScope->prepend(evaluationObject->scope);
+
+ resolveInheritance(object, evaluationObject, moduleScope, userProperties->value());
+
+ if (evaluationObject->prototype != name_Project)
+ return 0;
+
+ fillEvaluationObjectBasics(localScope, object, evaluationObject);
+ QStringList referencedProducts = evaluationObject->scope->stringListValue("references");
+
+ setPathAndFilePath(evaluationObject->scope, object->file->fileName);
+ int productChildrenCount = 0;
+ foreach (LanguageObject *child, object->children) {
+ EvaluationObject *eoChild = new EvaluationObject(child);
+ eoChild->scope = Scope::Ptr(evaluationObject->scope);
+ resolveInheritance(child, eoChild, moduleScope, userProperties->value());
+ if (eoChild->prototype == name_Product)
+ ++productChildrenCount;
+ }
+
+ return referencedProducts.count() + productChildrenCount;
+}
+
+ResolvedProject::Ptr Loader::resolveProject(const QString &buildDirectoryRoot,
+ Configuration::Ptr userProperties,
+ QFutureInterface<bool> &futureInterface,
+ bool resolveProductDependencies)
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[LDR] resolving " << m_project->fileName;
+ ResolvedProject::Ptr rproject(new ResolvedProject);
+ rproject->qbsFile = m_project->fileName;
+
+ Scope::Ptr context = buildFileContext(m_project.data());
+ ScopeChain::Ptr scope(new ScopeChain(&m_engine, context));
+
+ ResolvedModule::Ptr dummyModule(new ResolvedModule);
+ dummyModule->jsImports = m_project->jsImports;
+ QList<Rule::Ptr> globalRules;
+
+ ProjectData products;
+ resolveTopLevel(rproject,
+ m_project->root,
+ m_project->fileName,
+ &products,
+ &globalRules,
+ userProperties,
+ scope,
+ dummyModule,
+ futureInterface);
+
+ QSet<QString> uniqueStrings;
+ QMultiMap<QString, ResolvedProduct::Ptr> resolvedProducts;
+ QHash<ResolvedProduct::Ptr, ProductData>::iterator it = products.begin();
+ for (; it != products.end(); ++it) {
+ futureInterface.setProgressValue(futureInterface.progressValue() + 1);
+ ResolvedProduct::Ptr rproduct = it.key();
+ ProductData &data = it.value();
+ Scope *productProps = data.product->scope.data();
+
+ rproduct->name = productProps->stringValue("name");
+ QString buildDirectory = FileInfo::resolvePath(buildDirectoryRoot, rproject->id);
+
+ // insert property "buildDirectory"
+ {
+ Property p(m_engine.toScriptValue(buildDirectory));
+ productProps->properties.insert("buildDirectory", p);
+ }
+
+ rproduct->fileTags = productProps->stringListValue("type");
+ rproduct->destinationDirectory = productProps->stringValue("destination");
+ rproduct->buildDirectory = buildDirectory;
+ foreach (const Rule::Ptr &rule, globalRules)
+ rproduct->rules.insert(rule);
+ const QString lowerProductName = rproduct->name.toLower();
+ uniqueStrings.insert(lowerProductName);
+ resolvedProducts.insert(lowerProductName, rproduct);
+
+ // resolve the modules for this product
+ for (QHash<QString, Module::Ptr>::const_iterator modIt = data.product->modules.begin();
+ modIt != data.product->modules.end(); ++modIt)
+ {
+ resolveModule(rproduct, modIt.key(), modIt.value()->object);
+ }
+
+ QList<EvaluationObject *> unresolvedChildren = resolveCommonItems(data.product->children, rproduct, dummyModule);
+
+ // build the product's configuration
+ rproduct->configuration = Configuration::Ptr(new Configuration);
+ QVariantMap productCfg = evaluateAll(rproduct, data.product->scope);
+ rproduct->configuration->setValue(productCfg);
+
+ // handle the 'Product.files' property
+ {
+ QScriptValue files = data.product->scope->property("files");
+ if (files.isValid()) {
+ resolveGroup(rproduct, data.product, data.product);
+ }
+ }
+
+ foreach (EvaluationObject *child, unresolvedChildren) {
+ const uint prototypeNameHash = qHash(child->prototype);
+ if (prototypeNameHash == hashName_Group) {
+ resolveGroup(rproduct, data.product, child);
+ } else if (prototypeNameHash == hashName_ProductModule) {
+ child->scope->properties.insert("product", Property(data.product));
+ resolveProductModule(rproduct, data.product, child);
+ data.usedProductsFromProductModule += child->unknownModules;
+ }
+ }
+
+ // Apply file taggers and merge duplicate artifacts.
+ QHash<QString, SourceArtifact::Ptr> uniqueArtifacts;
+ foreach (const SourceArtifact::Ptr &artifact, rproduct->sources) {
+ if (artifact->fileTags.isEmpty()) {
+ artifact->fileTags = rproduct->fileTagsForFileName(artifact->absoluteFilePath);
+ if (!artifact->fileTags.isEmpty() && qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[LDR] adding file tags " << artifact->fileTags << " to " << FileInfo::fileName(artifact->absoluteFilePath);
+ }
+ SourceArtifact::Ptr existing = uniqueArtifacts.value(artifact->absoluteFilePath);
+ if (existing) {
+
+ // if an artifact is in the product and in a group, prefer the group configuration
+ if (existing->configuration == rproduct->configuration) {
+ existing->configuration = artifact->configuration;
+ } else if (artifact->configuration != rproduct->configuration) {
+ throw Error(QString("Artifact '%1' is in more than one group.").arg(artifact->absoluteFilePath),
+ CodeLocation(m_project->fileName));
+ }
+
+ existing->fileTags.unite(artifact->fileTags);
+ }
+ else
+ uniqueArtifacts.insert(artifact->absoluteFilePath, artifact);
+ }
+ rproduct->sources = uniqueArtifacts.values().toSet();
+
+ // fix up source artifact configurations
+ foreach (SourceArtifact::Ptr artifact, rproduct->sources)
+ if (!artifact->configuration)
+ artifact->configuration = rproduct->configuration;
+
+ rproject->products.insert(rproduct);
+ }
+
+ // Change build directory for products with the same name.
+ foreach (const QString &name, uniqueStrings) {
+ QList<ResolvedProduct::Ptr> products = resolvedProducts.values(name);
+ if (products.count() < 2)
+ continue;
+ foreach (ResolvedProduct::Ptr product, products) {
+ product->buildDirectory.append('/');
+ product->buildDirectory.append(product->fileTags.join("-"));
+ }
+ }
+
+ // Resolve inter-product dependencies.
+ if (resolveProductDependencies) {
+
+ // Collect product dependencies from ProductModules.
+ bool productDependenciesAdded;
+ do {
+ productDependenciesAdded = false;
+ foreach (ResolvedProduct::Ptr rproduct, rproject->products) {
+ ProductData &productData = products[rproduct];
+ foreach (const UnknownModule &unknownModule, productData.usedProducts) {
+ const QString &usedProductName = unknownModule.name;
+ QList<ResolvedProduct::Ptr> usedProductCandidates = resolvedProducts.values(usedProductName);
+ if (usedProductCandidates.count() < 1) {
+ if (!unknownModule.required) {
+ if (!unknownModule.failureMessage.isEmpty())
+ qbsWarning() << unknownModule.failureMessage;
+ continue;
+ }
+ throw Error(QString("Product dependency '%1' not found.").arg(usedProductName),
+ CodeLocation(m_project->fileName));
+ }
+ if (usedProductCandidates.count() > 1)
+ throw Error(QString("Product dependency '%1' is ambiguous.").arg(usedProductName),
+ CodeLocation(m_project->fileName));
+ ResolvedProduct::Ptr usedProduct = usedProductCandidates.first();
+ const ProductData &usedProductData = products.value(usedProduct);
+ bool added;
+ productData.addUsedProducts(usedProductData.usedProductsFromProductModule, &added);
+ if (added)
+ productDependenciesAdded = true;
+ }
+ }
+ } while (productDependenciesAdded);
+
+ // Resolve all inter-product dependencies.
+ foreach (ResolvedProduct::Ptr rproduct, rproject->products) {
+ foreach (const UnknownModule &unknownModule, products.value(rproduct).usedProducts) {
+ const QString &usedProductName = unknownModule.name;
+ QList<ResolvedProduct::Ptr> usedProductCandidates = resolvedProducts.values(usedProductName);
+ if (usedProductCandidates.count() < 1) {
+ if (!unknownModule.required) {
+ if (!unknownModule.failureMessage.isEmpty())
+ qbsWarning() << unknownModule.failureMessage;
+ continue;
+ }
+ throw Error(QString("Product dependency '%1' not found.").arg(usedProductName),
+ CodeLocation(m_project->fileName));
+ }
+ if (usedProductCandidates.count() > 1)
+ throw Error(QString("Product dependency '%1' is ambiguous.").arg(usedProductName),
+ CodeLocation(m_project->fileName));
+ ResolvedProduct::Ptr usedProduct = usedProductCandidates.first();
+ rproduct->uses.insert(usedProduct);
+
+ // insert the configuration of the ProductModule into the product's configuration
+ const QVariantMap productModuleConfig = m_productModules.value(usedProductName);
+ if (productModuleConfig.isEmpty())
+ continue;
+
+ QVariantMap productConfigValue = rproduct->configuration->value();
+ QVariantMap modules = productConfigValue.value("modules").toMap();
+ modules.insert(usedProductName, productModuleConfig);
+ productConfigValue.insert("modules", modules);
+ rproduct->configuration->setValue(productConfigValue);
+
+ // insert the configuration of the ProductModule into the artifact configurations
+ foreach (SourceArtifact::Ptr artifact, rproduct->sources) {
+ QVariantMap sourceArtifactConfigValue = artifact->configuration->value();
+ QVariantMap modules = sourceArtifactConfigValue.value("modules").toMap();
+ modules.insert(usedProductName, productModuleConfig);
+ sourceArtifactConfigValue.insert("modules", modules);
+ artifact->configuration->setValue(sourceArtifactConfigValue);
+ }
+ }
+ }
+ }
+
+ // Create the unaltered configuration for this project from all used modules.
+ {
+ rproject->configuration = Configuration::Ptr(new Configuration);
+ QSet<QString> seenModules;
+ ResolvedProduct::Ptr dummyProduct(new ResolvedProduct);
+ foreach (const ProductData &pd, products) {
+ foreach (Module::Ptr module, pd.product->modules) {
+ if (seenModules.contains(module->name))
+ continue;
+ seenModules.insert(module->name);
+ QVariantMap projectConfigValue = rproject->configuration->value();
+ projectConfigValue.insert(module->name, evaluateAll(dummyProduct, module->object->scope));
+ rproject->configuration->setValue(projectConfigValue);
+ }
+ }
+ }
+
+ return rproject;
+}
+
+static bool checkCondition(EvaluationObject *object)
+{
+ QScriptValue scriptValue = object->scope->property("condition");
+ if (scriptValue.isBool()) {
+ return scriptValue.toBool();
+ } else if (scriptValue.isValid() && !scriptValue.isUndefined()) {
+ const QScriptProgram &scriptProgram = object->objects.first()->bindings.value(QStringList("condition")).valueSource;
+ throw Error(QString("Invalid condition."), CodeLocation(scriptProgram.fileName(), scriptProgram.firstLineNumber()));
+ }
+ // no 'condition' property means 'the condition is true'
+ return true;
+}
+
+void Loader::resolveModule(ResolvedProduct::Ptr rproduct, const QString &moduleName, EvaluationObject *module)
+{
+ ResolvedModule::Ptr rmodule(new ResolvedModule);
+ rmodule->name = moduleName;
+ rmodule->jsImports = module->instantiatingObject()->file->jsImports;
+ rmodule->setupBuildEnvironmentScript = module->scope->verbatimValue("setupBuildEnvironment");
+ rmodule->setupRunEnvironmentScript = module->scope->verbatimValue("setupRunEnvironment");
+ QStringList additionalProductFileTags = module->scope->stringListValue("additionalProductFileTags");
+ if (!additionalProductFileTags.isEmpty()) {
+ rproduct->fileTags.append(additionalProductFileTags);
+ rproduct->fileTags = rproduct->fileTags.toSet().toList();
+ }
+ foreach (Module::Ptr m, module->modules)
+ rmodule->moduleDependencies.append(m->name);
+ rproduct->modules.append(rmodule);
+ QList<EvaluationObject *> unhandledChildren = resolveCommonItems(module->children, rproduct, rmodule);
+ foreach (EvaluationObject *child, unhandledChildren) {
+ if (child->prototype == name_Artifact) {
+ if (!checkCondition(child))
+ continue;
+ QString fileName = child->scope->stringValue("fileName");
+ if (fileName.isEmpty())
+ throw Error(QString("Source file %0 does not exist.").arg(fileName));
+ SourceArtifact::Ptr artifact;
+ foreach (SourceArtifact::Ptr a, rproduct->sources) {
+ if (a->absoluteFilePath == fileName) {
+ artifact = a;
+ break;
+ }
+ }
+ if (!artifact) {
+ artifact = SourceArtifact::Ptr(new SourceArtifact);
+ artifact->absoluteFilePath = FileInfo::resolvePath(rproduct->sourceDirectory, fileName);
+ rproduct->sources += artifact;
+ }
+ artifact->fileTags += child->scope->stringListValue("fileTags").toSet();
+ } else {
+ QString msg = "Items of type %0 not allowed in a Module.";
+ throw Error(msg.arg(child->prototype));
+ }
+ }
+}
+
+static QVariantMap evaluateModuleValues(ResolvedProduct::Ptr rproduct, EvaluationObject *product, Scope::Ptr objectScope)
+{
+ QVariantMap values;
+ QVariantMap modules;
+ for (QHash<QString, Module::Ptr>::const_iterator it = product->modules.begin();
+ it != product->modules.end(); ++it)
+ {
+ Module::Ptr module = it.value();
+ const QString name = module->name;
+ const QString id = module->id;
+ if (!id.isEmpty()) {
+ Scope::Ptr moduleScope = objectScope->properties.value(id).scope;
+ if (!moduleScope)
+ moduleScope = product->scope->properties.value(id).scope;
+ if (!moduleScope)
+ continue;
+ modules.insert(name, evaluateAll(rproduct, moduleScope));
+ } else {
+ modules.insert(name, evaluateAll(rproduct, module->object->scope));
+ }
+ }
+ values.insert(QLatin1String("modules"), modules);
+ return values;
+}
+
+/**
+ * Resolve Group {} and the files part of Product {}.
+ */
+void Loader::resolveGroup(ResolvedProduct::Ptr rproduct, EvaluationObject *product, EvaluationObject *group)
+{
+ const bool isGroup = product != group;
+
+ Configuration::Ptr configuration;
+
+ if (isGroup) {
+ clearCachedValues();
+
+ if (!checkCondition(group))
+ return;
+
+ // build configuration for this group
+ configuration = Configuration::Ptr(new Configuration);
+ configuration->setValue(evaluateModuleValues(rproduct, product, group->scope));
+ } else {
+ configuration = rproduct->configuration;
+ }
+
+ // Products can have 'files' but not 'fileTags'
+ QStringList files = group->scope->stringListValue("files");
+ if (isGroup) {
+ QString prefix = group->scope->stringValue("prefix");
+ if (!prefix.isEmpty())
+ for (int i=files.count(); --i >= 0;)
+ files[i].prepend(prefix);
+ }
+ QSet<QString> fileTags;
+ if (isGroup)
+ fileTags = group->scope->stringListValue("fileTags").toSet();
+ foreach (const QString &fileName, files) {
+ SourceArtifact::Ptr artifact(new SourceArtifact);
+ artifact->configuration = configuration;
+ artifact->absoluteFilePath = FileInfo::resolvePath(rproduct->sourceDirectory, fileName);
+ artifact->fileTags = fileTags;
+ rproduct->sources.insert(artifact);
+ }
+}
+
+void Loader::resolveProductModule(ResolvedProduct::Ptr rproduct, EvaluationObject *product, EvaluationObject *productModule)
+{
+ Q_ASSERT(!rproduct->name.isEmpty());
+
+ QVariantMap userProperties; // ### dummy
+ ScopeChain::Ptr localScopeChain(new ScopeChain(&m_engine, productModule->scope));
+ ScopeChain::Ptr moduleScopeChain(new ScopeChain(&m_engine, productModule->scope));
+ evaluateDependencies(productModule->instantiatingObject(), productModule, localScopeChain, moduleScopeChain, userProperties);
+
+ clearCachedValues();
+ QVariantMap moduleValues = evaluateModuleValues(rproduct, product, productModule->scope);
+ m_productModules.insert(rproduct->name.toLower(), moduleValues);
+}
+
+void Loader::resolveTransformer(ResolvedProduct::Ptr rproduct, EvaluationObject *trafo, ResolvedModule::Ptr module)
+{
+ if (!checkCondition(trafo))
+ return;
+
+ ResolvedTransformer::Ptr rtrafo(new ResolvedTransformer);
+ rtrafo->module = module;
+ rtrafo->jsImports = trafo->instantiatingObject()->file->jsImports;
+ rtrafo->inputs = trafo->scope->stringListValue("inputs");
+ for (int i=0; i < rtrafo->inputs.count(); ++i)
+ rtrafo->inputs[i] = FileInfo::resolvePath(rproduct->sourceDirectory, rtrafo->inputs[i]);
+ rtrafo->transform = RuleScript::Ptr(new RuleScript);
+ rtrafo->transform->script = trafo->scope->verbatimValue("prepare");
+ rtrafo->transform->location.fileName = trafo->instantiatingObject()->file->fileName;
+ rtrafo->transform->location.column = 1;
+ Configuration::Ptr outputConfiguration(new Configuration);
+ foreach (EvaluationObject *child, trafo->children) {
+ if (child->prototype != name_Artifact)
+ throw Error(QString("Transformer: wrong child type '%0'.").arg(child->prototype));
+ SourceArtifact::Ptr artifact(new SourceArtifact);
+ artifact->configuration = outputConfiguration;
+ QString fileName = child->scope->stringValue("fileName");
+ if (fileName.isEmpty())
+ throw Error("Artifact fileName must not be empty.");
+ artifact->absoluteFilePath = FileInfo::resolvePath(rproduct->buildDirectory,
+ fileName);
+ artifact->fileTags = child->scope->stringListValue("fileTags").toSet();
+ rtrafo->outputs += artifact;
+ }
+ rproduct->transformers += rtrafo;
+}
+
+static void addTransformPropertiesToRule(Rule::Ptr rule, LanguageObject *obj)
+{
+ foreach (const Binding &binding, obj->bindings) {
+ if (binding.name.length() != 1) {
+ throw Error("Binding with dots are prohibited in TransformProperties.",
+ CodeLocation(binding.valueSource.fileName(),
+ binding.valueSource.firstLineNumber()));
+ continue;
+ }
+
+ rule->transformProperties.insert(binding.name.first(), binding.valueSource);
+ }
+}
+
+/**
+ *Resolve stuff that Module and Product have in common.
+ */
+QList<EvaluationObject *> Loader::resolveCommonItems(const QList<EvaluationObject *> &objects,
+ ResolvedProduct::Ptr rproduct, ResolvedModule::Ptr module)
+{
+ QList<LanguageObject *> outerTransformProperties; // ### do we really want to allow these?
+ QList<Rule::Ptr> rules;
+
+ QList<EvaluationObject *> unhandledObjects;
+ foreach (EvaluationObject *object, objects) {
+ const uint hashPrototypeName = qHash(object->prototype);
+ if (hashPrototypeName == hashName_FileTagger) {
+ FileTagger::Ptr fileTagger(new FileTagger);
+ fileTagger->artifactExpression = object->scope->stringValue("pattern");
+ fileTagger->fileTags = object->scope->stringListValue("fileTags");
+ rproduct->fileTaggers.insert(fileTagger);
+ } else if (hashPrototypeName == hashName_Rule) {
+ Rule::Ptr rule = resolveRule(object, module);
+ rproduct->rules.insert(rule);
+ rules.append(rule);
+ } else if (hashPrototypeName == hashName_Transformer) {
+ resolveTransformer(rproduct, object, module);
+ } else if (hashPrototypeName == hashName_TransformProperties) {
+ outerTransformProperties.append(object->instantiatingObject());
+ } else if (hashPrototypeName == hashName_PropertyOptions) {
+ // Just ignore this type to allow it. It is handled elsewhere.
+ } else {
+ unhandledObjects.append(object);
+ }
+ }
+
+ // attach the outer TransformProperties to the rules
+ foreach (Rule::Ptr rule, rules) {
+ foreach (LanguageObject *tp, outerTransformProperties)
+ addTransformPropertiesToRule(rule, tp);
+ }
+
+ return unhandledObjects;
+}
+
+Rule::Ptr Loader::resolveRule(EvaluationObject *object, ResolvedModule::Ptr module)
+{
+ Rule::Ptr rule(new Rule);
+
+ LanguageObject *origObj = object->instantiatingObject();
+ Q_CHECK_PTR(origObj);
+
+ // read artifacts and TransformProperties
+ QList<RuleArtifact::Ptr> artifacts;
+ foreach (EvaluationObject *child, object->children) {
+ const uint hashChildPrototypeName = qHash(child->prototype);
+ if (hashChildPrototypeName == hashName_Artifact) {
+ RuleArtifact::Ptr artifact(new RuleArtifact);
+ artifacts.append(artifact);
+ artifact->fileScript = child->scope->verbatimValue("fileName");
+ artifact->fileTags = child->scope->stringListValue("fileTags");
+ LanguageObject *origArtifactObj = child->instantiatingObject();
+ foreach (const Binding &binding, origArtifactObj->bindings) {
+ if (binding.name.length() <= 1)
+ continue;
+ artifact->bindings.append(qMakePair(binding.name, binding.valueSource.sourceCode()));
+ }
+ } else if (hashChildPrototypeName == hashName_TransformProperties) {
+ addTransformPropertiesToRule(rule, child->instantiatingObject());
+ } else {
+ throw Error("'Rule' can only have children of type 'Artifact' or 'TransformProperties'.",
+ child->instantiatingObject()->prototypeLocation);
+ }
+ }
+
+ RuleScript::Ptr ruleScript(new RuleScript);
+ ruleScript->script = object->scope->verbatimValue("prepare");
+ ruleScript->location.fileName = object->instantiatingObject()->file->fileName;
+ ruleScript->location.column = 1;
+ {
+ Binding binding = object->instantiatingObject()->bindings.value(QStringList("prepare"));
+ ruleScript->location.line = binding.valueSource.firstLineNumber();
+ }
+
+ rule->objectId = origObj->id;
+ rule->jsImports = object->instantiatingObject()->file->jsImports;
+ rule->script = ruleScript;
+ rule->artifacts = artifacts;
+ rule->multiplex = object->scope->boolValue("multiplex", false);
+ rule->inputs = object->scope->stringListValue("inputs");
+ rule->usings = object->scope->stringListValue("usings");
+ rule->explicitlyDependsOn = object->scope->stringListValue("explicitlyDependsOn");
+ rule->module = module;
+
+ m_ruleMap.insert(rule, object);
+ return rule;
+}
+
+/// --------------------------------------------------------------------------
+
+
+template <typename T>
+static QString textOf(const QString &source, T *node)
+{
+ if (!node)
+ return QString();
+ return source.mid(node->firstSourceLocation().begin(), node->lastSourceLocation().end() - node->firstSourceLocation().begin());
+}
+
+static void bindFunction(LanguageObject *result, const QString &source, FunctionDeclaration *ast)
+{
+ Function f;
+ if (!ast->name)
+ throw Error("function decl without name");
+ f.name = ast->name->asString();
+
+ // remove the name
+ QString funcNoName = textOf(source, ast);
+ funcNoName.replace(QRegExp("^(\\s*function\\s*)\\w*"), "(\\1");
+ funcNoName.append(")");
+ f.source = QScriptProgram(funcNoName, result->file->fileName, ast->firstSourceLocation().startLine);
+ result->functions.insert(f.name, f);
+}
+
+static QStringList toStringList(UiQualifiedId *qid)
+{
+ QStringList result;
+ for (; qid; qid = qid->next) {
+ if (qid->name)
+ result.append(qid->name->asString());
+ else
+ result.append(QString()); // throw error instead?
+ }
+ return result;
+}
+
+static CodeLocation location(const QString &fileName, SourceLocation location)
+{
+ return CodeLocation(fileName, location.startLine, location.startColumn);
+}
+
+static QScriptProgram bindingProgram(const QString &fileName, const QString &source, Statement *statement)
+{
+ QString sourceCode = textOf(source, statement);
+ if (cast<Block *>(statement)) {
+ // rewrite blocks to be able to use return statements in property assignments
+ sourceCode.prepend("(function()");
+ sourceCode.append(")()");
+ }
+ return QScriptProgram(sourceCode, fileName,
+ statement->firstSourceLocation().startLine);
+}
+
+static void checkDuplicateBinding(LanguageObject *object, const QStringList &bindingName, const SourceLocation &sourceLocation)
+{
+ if (object->bindings.contains(bindingName)) {
+ QString msg("Duplicate binding for '%1'");
+ throw Error(msg.arg(bindingName.join(".")),
+ location(object->file->fileName, sourceLocation));
+ }
+}
+
+static void bindBinding(LanguageObject *result, const QString &source, UiScriptBinding *ast)
+{
+ Binding p;
+ if (!ast->qualifiedId || !ast->qualifiedId->name)
+ throw Error("script binding without name");
+ p.name = toStringList(ast->qualifiedId);
+ checkDuplicateBinding(result, p.name, ast->qualifiedId->identifierToken);
+
+ if (p.name == QStringList("id")) {
+ ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt)
+ throw Error("id: must be followed by identifier");
+ IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression);
+ if (!idExp || !idExp->name)
+ throw Error("id: must be followed by identifier");
+ result->id = idExp->name->asString();
+ return;
+ }
+
+ p.valueSource = bindingProgram(result->file->fileName, source, ast->statement);
+
+ result->bindings.insert(p.name, p);
+}
+
+static void bindBinding(LanguageObject *result, const QString &source, UiPublicMember *ast)
+{
+ Binding p;
+ if (!ast->name)
+ throw Error("public member without name");
+ p.name = QStringList(ast->name->asString());
+ checkDuplicateBinding(result, p.name, ast->identifierToken);
+
+ if (ast->statement)
+ p.valueSource = bindingProgram(result->file->fileName, source, ast->statement);
+ else
+ p.valueSource = QScriptProgram("undefined");
+
+ result->bindings.insert(p.name, p);
+}
+
+static PropertyDeclaration::Type propertyTypeFromString(const QString &typeName)
+{
+ if (typeName == "bool")
+ return PropertyDeclaration::Boolean;
+ if (typeName == "paths")
+ return PropertyDeclaration::Paths;
+ if (typeName == "string")
+ return PropertyDeclaration::String;
+ if (typeName == "var" || typeName == "variant")
+ return PropertyDeclaration::Variant;
+ return PropertyDeclaration::UnknownType;
+}
+
+static void bindPropertyDeclaration(LanguageObject *result, UiPublicMember *ast)
+{
+ PropertyDeclaration p;
+ if (!ast->name)
+ throw Error("public member without name");
+ if (!ast->memberType)
+ throw Error("public member without type");
+ if (ast->typeModifier && ast->typeModifier->asString() != QLatin1String("list"))
+ throw Error("public member with type modifier that is not 'list'");
+ if (ast->type == UiPublicMember::Signal)
+ throw Error("public member with signal type not supported");
+ p.name = ast->name->asString();
+ p.type = propertyTypeFromString(ast->memberType->asString());
+ if (ast->typeModifier && ast->typeModifier->asString() == QLatin1String("list"))
+ p.flags |= PropertyDeclaration::ListProperty;
+
+ result->propertyDeclarations.insert(p.name, p);
+}
+
+static LanguageObject *bindObject(ProjectFile::Ptr file, const QString &source, UiObjectDefinition *ast,
+ const QHash<QStringList, QString> prototypeToFile)
+{
+ LanguageObject *result = new LanguageObject(file.data());
+ result->file = file.data();
+
+// result->location = CodeLocation(
+// currentSourceFileName,
+// ast->firstSourceLocation().startLine,
+// ast->firstSourceLocation().startColumn
+// );
+
+ if (!ast->qualifiedTypeNameId || !ast->qualifiedTypeNameId->name)
+ throw Error("no prototype");
+ result->prototype = toStringList(ast->qualifiedTypeNameId);
+ result->prototypeLocation = location(file->fileName, ast->qualifiedTypeNameId->identifierToken);
+
+ // resolve prototype if possible
+ result->prototypeFileName = prototypeToFile.value(result->prototype);
+
+ if (!ast->initializer)
+ return result;
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ if (UiPublicMember *publicMember = cast<UiPublicMember *>(it->member)) {
+ bindPropertyDeclaration(result, publicMember);
+ bindBinding(result, source, publicMember);
+ } else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding *>(it->member)) {
+ bindBinding(result, source, scriptBinding);
+ } else if (UiSourceElement *sourceElement = cast<UiSourceElement *>(it->member)) {
+ FunctionDeclaration *fdecl = cast<FunctionDeclaration *>(sourceElement->sourceElement);
+ if (!fdecl)
+ continue;
+ bindFunction(result, source, fdecl);
+ } else if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(it->member)) {
+ result->children += bindObject(file, source, objDef, prototypeToFile);
+ }
+ }
+
+ return result;
+}
+
+static void collectPrototypes(const QString &path, const QString &as,
+ QHash<QStringList, QString> *prototypeToFile)
+{
+ QDirIterator dirIter(path, QStringList("*.qbs"));
+ while (dirIter.hasNext()) {
+ const QString filePath = dirIter.next();
+ const QString fileName = dirIter.fileName();
+
+ if (fileName.size() <= 4)
+ continue;
+
+ const QString componentName = fileName.left(fileName.size() - 4);
+ // ### validate componentName
+
+ if (!componentName.at(0).isUpper())
+ continue;
+
+ QStringList prototypeName;
+ if (!as.isEmpty())
+ prototypeName.append(as);
+ prototypeName.append(componentName);
+
+ prototypeToFile->insert(prototypeName, filePath);
+ }
+}
+
+static ProjectFile::Ptr bindFile(const QString &source, const QString &fileName, UiProgram *ast, QStringList searchPaths)
+{
+ ProjectFile::Ptr file(new ProjectFile);
+ file->fileName = fileName;
+ const QString path = FileInfo::path(fileName);
+
+ // maps names of known prototypes to absolute file names
+ QHash<QStringList, QString> prototypeToFile;
+
+ // files in the same directory are available as prototypes
+ collectPrototypes(path, QString(), &prototypeToFile);
+
+ QSet<QString> importAsNames;
+
+ for (QmlJS::AST::UiImportList *it = ast->imports; it; it = it->next) {
+ QmlJS::AST::UiImport *import = it->import;
+ QmlJS::NameId *iFileName = import->fileName;
+ QmlJS::NameId *importId = import->importId;
+
+ QStringList importUri;
+ bool isBase = false;
+ if (import->importUri) {
+ importUri = toStringList(import->importUri);
+ if (importUri.size() == 2
+ && importUri.first() == "qbs"
+ && importUri.last() == "base")
+ isBase = true; // ### check version!
+ }
+
+ QString as;
+ if (isBase) {
+ if (importId) {
+ // ### location
+ throw Error("Import of qbs.base must have no 'as <Name>'");
+ }
+ } else {
+ if (!importId) {
+ // ### location
+ throw Error("Imports require 'as <Name>'");
+ }
+
+ as = importId->asString();
+ if (importAsNames.contains(as)) {
+ // ### location
+ throw Error("Can't import into the same name more than once");
+ }
+ importAsNames.insert(as);
+ }
+
+ if (iFileName) {
+ QString name = FileInfo::resolvePath(path, iFileName->asString());
+
+ QFileInfo fi(name);
+ if (!fi.exists())
+ throw Error(QString("Can't find imported file %0.").arg(name),
+ CodeLocation(fileName, import->fileNameToken.startLine, import->fileNameToken.startColumn));
+ name = fi.canonicalFilePath();
+ if (fi.isDir()) {
+ collectPrototypes(name, as, &prototypeToFile);
+ } else {
+ if (name.endsWith(".js", Qt::CaseInsensitive)) {
+ file->jsImports[as].append(name);
+ } else if (name.endsWith(".qbs", Qt::CaseInsensitive)) {
+ prototypeToFile.insert(QStringList(as), name);
+ } else {
+ throw Error("Can only import .qbs and .js files",
+ CodeLocation(fileName, import->fileNameToken.startLine, import->fileNameToken.startColumn));
+ }
+ }
+ } else if (!importUri.isEmpty()) {
+ const QString importPath = importUri.join(QDir::separator());
+ bool found = false;
+ foreach (const QString &searchPath, searchPaths) {
+ const QFileInfo fi(FileInfo::resolvePath(FileInfo::resolvePath(searchPath, "imports"), importPath));
+ if (fi.isDir()) {
+ // ### versioning, qbsdir file, etc.
+ const QString &resultPath = fi.absoluteFilePath();
+ collectPrototypes(resultPath, as, &prototypeToFile);
+
+ QDirIterator dirIter(resultPath, QStringList("*.js"));
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ file->jsImports[as].append(dirIter.filePath());
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // ### location
+ throw Error(QString("import %1 not found").arg(importUri.join(".")));
+ }
+ }
+ }
+
+ UiObjectDefinition *rootDef = cast<UiObjectDefinition *>(ast->members->member);
+ if (rootDef)
+ file->root = bindObject(file, source, rootDef, prototypeToFile);
+
+ return file;
+}
+
+ProjectFile::Ptr Loader::parseFile(const QString &fileName)
+{
+ ProjectFile::Ptr result = m_parsedFiles.value(fileName);
+ if (result)
+ return result;
+
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly))
+ throw Error(QString("Couldn't open '%1'.").arg(fileName));
+
+ const QString code = QTextStream(&file).readAll();
+ QScopedPointer<QmlJS::Engine> engine(new QmlJS::Engine);
+ QScopedPointer<QmlJS::NodePool> nodePool(new QmlJS::NodePool(fileName, engine.data()));
+ QmlJS::Lexer lexer(engine.data());
+ lexer.setCode(code, 1);
+ QmlJS::Parser parser(engine.data());
+ parser.parse();
+
+ QList<QmlJS::DiagnosticMessage> parserMessages = parser.diagnosticMessages();
+ if (!parserMessages.isEmpty()) {
+ QString msgstr = "Parsing errors:\n";
+ foreach (const QmlJS::DiagnosticMessage &msg, parserMessages)
+ msgstr += Error(msg.message, fileName, msg.loc.startLine, msg.loc.startColumn).toString()
+ + QLatin1String("\n");
+ throw Error(msgstr);
+ }
+
+ result = bindFile(code, fileName, parser.ast(), m_searchPaths);
+ if (result) {
+ Q_ASSERT(!m_parsedFiles.contains(result->fileName));
+ m_parsedFiles.insert(result->fileName, result);
+ }
+ return result;
+}
+
+Loader *Loader::get(QScriptEngine *engine)
+{
+ QVariant v = engine->property(szLoaderPropertyName);
+ return static_cast<Loader*>(v.value<void*>());
+}
+
+QScriptValue Loader::js_getHostOS(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(context);
+ QString hostSystem;
+#if defined(Q_OS_WIN)
+ hostSystem = "windows";
+#elif defined(Q_OS_MAC)
+ hostSystem = "mac";
+#elif defined(Q_OS_LINUX)
+ hostSystem = "linux";
+#else
+# error unknown host platform
+#endif
+ return engine->toScriptValue(hostSystem);
+}
+
+QScriptValue Loader::js_getHostDefaultArchitecture(QScriptContext *context, QScriptEngine *engine)
+{
+ // ### TODO implement properly, do not hard-code
+ Q_UNUSED(context);
+ QString architecture;
+#if defined(Q_OS_WIN)
+ architecture = "x86";
+#elif defined(Q_OS_MAC)
+ architecture = "x86_64";
+#elif defined(Q_OS_LINUX)
+ architecture = "x86_64";
+#else
+# error unknown host platform
+#endif
+ return engine->toScriptValue(architecture);
+}
+
+QScriptValue Loader::js_configurationValue(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() < 1 || context->argumentCount() > 2) {
+ return context->throwError(QScriptContext::SyntaxError,
+ QString("configurationValue expects 1 or 2 arguments"));
+ }
+
+ Settings::Ptr settings = Loader::get(engine)->m_settings;
+ const bool defaultValueProvided = context->argumentCount() > 1;
+ const QString key = context->argument(0).toString();
+ const QString defaultValue = (defaultValueProvided ? QString() : (context->argument(1).isUndefined() ? QString() : context->argument(1).toString()));
+ QVariant v = settings->value(key, defaultValue);
+ if (!defaultValueProvided && v.isNull())
+ return context->throwError(QScriptContext::SyntaxError,
+ QString("configuration value '%1' does not exist").arg(context->argument(0).toString()));
+ return engine->toScriptValue(v);
+}
+
+EvaluationObject *Loader::resolveTopLevel(const ResolvedProject::Ptr &rproject,
+ LanguageObject *object,
+ const QString &projectFileName,
+ ProjectData *projectData,
+ QList<Rule::Ptr> *globalRules,
+ const Configuration::Ptr &userProperties,
+ const ScopeChain::Ptr &scope,
+ const ResolvedModule::Ptr &dummyModule,
+ QFutureInterface<bool> &futureInterface)
+{
+ if (qbsLogLevel(LoggerTrace))
+ qbsTrace() << "[LDR] resolve top-level " << object->file->fileName;
+ EvaluationObject *evaluationObject = new EvaluationObject(object);
+
+ const QString propertiesName = object->prototype.join(".");
+ evaluationObject->scope = Scope::create(&m_engine, propertiesName, object->file);
+
+ Scope::Ptr productProperty = Scope::create(&m_engine, name_productPropertyScope, object->file);
+ Scope::Ptr projectProperty = Scope::create(&m_engine, name_projectPropertyScope, object->file);
+ Scope::Ptr oldProductProperty(scope->findNonEmpty(name_productPropertyScope));
+ Scope::Ptr oldProjectProperty(scope->findNonEmpty(name_projectPropertyScope));
+
+ // for the 'product' and 'project' property available to the modules
+ ScopeChain::Ptr moduleScope(new ScopeChain(&m_engine));
+ moduleScope->prepend(oldProductProperty);
+ moduleScope->prepend(oldProjectProperty);
+ moduleScope->prepend(productProperty);
+ moduleScope->prepend(projectProperty);
+
+ ScopeChain::Ptr localScope(scope->clone());
+ localScope->prepend(productProperty);
+ localScope->prepend(projectProperty);
+ localScope->prepend(evaluationObject->scope);
+
+ evaluationObject->scope->properties.insert("configurationValue", Property(m_jsFunction_configurationValue));
+
+ resolveInheritance(object, evaluationObject, moduleScope, userProperties->value());
+
+ if (evaluationObject->prototype == name_Project) {
+ // if this is a nested project, set a fallback scope
+ Property outerProperty = scope->lookupProperty("project");
+ if (outerProperty.isValid() && outerProperty.scope) {
+ evaluationObject->scope->fallbackScope = outerProperty.scope;
+ } else {
+ // set the 'path' and 'filePath' properties
+ setPathAndFilePath(evaluationObject->scope, object->file->fileName);
+ }
+
+ fillEvaluationObjectBasics(localScope, object, evaluationObject);
+
+ // load referenced files
+ foreach (const QString &reference, evaluationObject->scope->stringListValue("references")) {
+
+ QString projectFileDir = FileInfo::path(projectFileName);
+ QString absReferencePath = FileInfo::resolvePath(projectFileDir, reference);
+ ProjectFile::Ptr referencedFile = parseFile(absReferencePath);
+ ScopeChain::Ptr referencedFileScope(new ScopeChain(&m_engine, buildFileContext(referencedFile.data())));
+ referencedFileScope->prepend(projectProperty);
+ resolveTopLevel(rproject,
+ referencedFile->root,
+ referencedFile->fileName,
+ projectData,
+ globalRules,
+ userProperties,
+ referencedFileScope,
+ dummyModule, futureInterface);
+ }
+
+ // load children
+ ScopeChain::Ptr childScope(scope->clone()->prepend(projectProperty));
+ foreach (LanguageObject *child, object->children)
+ resolveTopLevel(rproject,
+ child,
+ projectFileName,
+ projectData,
+ globalRules,
+ userProperties,
+ childScope,
+ dummyModule,
+ futureInterface);
+
+ return evaluationObject;
+ } else if (evaluationObject->prototype == name_Rule) {
+ fillEvaluationObject(localScope, object, evaluationObject->scope, evaluationObject, userProperties->value());
+ Rule::Ptr rule = resolveRule(evaluationObject, dummyModule);
+ globalRules->append(rule);
+
+ return evaluationObject;
+ } else if (evaluationObject->prototype != name_Product) {
+ QString msg("unknown prototype '%1' - expected Product");
+ // ### location
+ throw Error(msg.arg(evaluationObject->prototype));
+ }
+
+ // set the 'path' and 'filePath' properties
+ setPathAndFilePath(evaluationObject->scope, object->file->fileName);
+
+ ResolvedProduct::Ptr rproduct(new ResolvedProduct);
+ rproduct->qbsFile = projectFileName;
+ rproduct->sourceDirectory = QFileInfo(projectFileName).absolutePath();
+ rproduct->project = rproject.data();
+
+ ProductData productData;
+ productData.product = evaluationObject;
+
+ evaluateDependencies(object, evaluationObject, localScope, moduleScope, userProperties->value());
+ productData.usedProducts = evaluationObject->unknownModules;
+ fillEvaluationObject(localScope, object, evaluationObject->scope, evaluationObject, userProperties->value());
+
+ // check if product's name is empty and set a default value
+ Property &nameProperty = evaluationObject->scope->properties["name"];
+ if (nameProperty.value.isUndefined()) {
+ QString projectName = FileInfo::fileName(projectFileName);
+ projectName.chop(4);
+ nameProperty.value = m_engine.toScriptValue(projectName);
+ }
+
+ if (!object->id.isEmpty()) {
+ Scope::Ptr context = scope->last();
+ context->properties.insert(object->id, Property(evaluationObject));
+ }
+
+ // collect all dependent modules and put them into the product
+ QHash<QString, ProjectFile *> moduleDependencies = findModuleDependencies(evaluationObject);
+ QHashIterator<QString, ProjectFile *> it(moduleDependencies);
+ while (it.hasNext()) {
+ it.next();
+ if (productData.product->modules.contains(it.key()))
+ continue; // ### check if files equal
+ Module::Ptr module = loadModule(it.value(), QString(), it.key(), moduleScope, userProperties->value(),
+ CodeLocation(object->file->fileName));
+ if (!module) {
+ throw Error(QString("could not load module '%1' from file '%2' into product even though it was loaded into a submodule").arg(
+ it.key(), it.value()->fileName));
+ }
+ evaluationObject->modules.insert(module->name, module);
+ }
+ buildModulesProperty(evaluationObject);
+
+ // get the build variant / determine the project id
+ QString buildVariant = userProperties->value().value("qbs").toMap().value("buildVariant").toString();
+ if (rproject->id.isEmpty()) {
+ EvaluationObject *baseModule = evaluationObject->modules.value("qbs")->object;
+ if (!baseModule)
+ throw Error("base module not loaded");
+ const QString hostName = baseModule->scope->stringValue("hostOS");
+ const QString targetOS = baseModule->scope->stringValue("targetOS");
+ const QString targetName = baseModule->scope->stringValue("targetName");
+ rproject->id = buildVariant;
+ if (!targetName.isEmpty())
+ rproject->id.prepend(targetName + "-");
+ if (hostName != targetOS) {
+ QString platformName = targetOS;
+ const QString hostArchitecture = baseModule->scope->stringValue("hostArchitecture");
+ const QString targetArchitecture = baseModule->scope->stringValue("architecture");
+ if (hostArchitecture != targetArchitecture) {
+ platformName += "-";
+ platformName += targetArchitecture;
+ }
+ rproject->id.prepend(platformName + "-");
+ }
+ }
+ projectData->insert(rproduct, productData);
+ return evaluationObject;
+}
+
+ProjectFile::ProjectFile()
+ : m_destructing(false)
+{
+}
+
+ProjectFile::~ProjectFile()
+{
+ m_destructing = true;
+ qDeleteAll(m_evaluationObjects);
+ qDeleteAll(m_languageObjects);
+}
+
+void Loader::ProductData::addUsedProducts(const QList<UnknownModule> &additionalUsedProducts, bool *productsAdded)
+{
+ int oldCount = usedProducts.count();
+ QSet<QString> usedProductNames;
+ foreach (const UnknownModule &usedProduct, usedProducts)
+ usedProductNames += usedProduct.name;
+ foreach (const UnknownModule &usedProduct, additionalUsedProducts)
+ if (!usedProductNames.contains(usedProduct.name))
+ usedProducts += usedProduct;
+ *productsAdded = (oldCount != usedProducts.count());
+}
+
+} // namespace qbs
diff --git a/src/lib/language/loader.h b/src/lib/language/loader.h
new file mode 100644
index 000000000..d4f7a48a9
--- /dev/null
+++ b/src/lib/language/loader.h
@@ -0,0 +1,408 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef L2_TARGETLOADER_H
+#define L2_TARGETLOADER_H
+
+#include "language.h"
+#include <tools/settings.h>
+#include <tools/codelocation.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtCore/QFutureInterface>
+
+#include <QtScript/QScriptClass>
+#include <QtScript/QScriptEngine>
+
+#include <set>
+
+
+
+namespace qbs {
+
+class Function
+{
+public:
+ QString name;
+ QScriptProgram source;
+};
+
+class Binding
+{
+public:
+ QStringList name;
+ QScriptProgram valueSource;
+
+ bool isValid() const { return !name.isEmpty(); }
+};
+
+class PropertyDeclaration
+{
+public:
+ enum Type
+ {
+ UnknownType,
+ Boolean,
+ Paths,
+ String,
+ Variant,
+ Verbatim
+ };
+
+ enum Flag
+ {
+ DefaultFlags = 0,
+ ListProperty = 0x1,
+ PropertyNotAvailableInConfig = 0x2 // Is this property part of a project, product or file configuration?
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ PropertyDeclaration();
+ PropertyDeclaration(const QString &name, Type type, Flags flags = DefaultFlags);
+ ~PropertyDeclaration();
+
+ QString name;
+ Type type;
+ Flags flags;
+ QVariant allowedValues;
+ QString description;
+ // the initial value will be in the bindings list
+};
+
+class ProjectFile;
+
+class LanguageObject
+{
+public:
+ LanguageObject(ProjectFile *owner);
+ LanguageObject(const LanguageObject &other);
+ ~LanguageObject();
+
+ QString id;
+
+ QStringList prototype;
+ QString prototypeFileName;
+ qbs::CodeLocation prototypeLocation;
+ ProjectFile *file;
+
+ QList<LanguageObject *> children;
+ QHash<QStringList, Binding> bindings;
+ QHash<QString, Function> functions;
+ QHash<QString, PropertyDeclaration> propertyDeclarations;
+};
+
+class EvaluationObject;
+class Scope;
+
+/**
+ * Represents a qbs project file.
+ * Owns all the language objects.
+ */
+class ProjectFile
+{
+public:
+ typedef QSharedPointer<ProjectFile> Ptr;
+
+ ProjectFile();
+ ~ProjectFile();
+
+ JsImports jsImports;
+ LanguageObject *root;
+ QString fileName;
+
+ bool isValid() const { return !root->prototype.isEmpty(); }
+ bool isDestructing() const { return m_destructing; }
+
+ void registerScope(QSharedPointer<Scope> scope) { m_scopes += scope; }
+ void registerEvaluationObject(EvaluationObject *eo) { m_evaluationObjects += eo; }
+ void unregisterEvaluationObject(EvaluationObject *eo) { m_evaluationObjects.removeOne(eo); }
+ void registerLanguageObject(LanguageObject *eo) { m_languageObjects += eo; }
+ void unregisterLanguageObject(LanguageObject *eo) { m_languageObjects.removeOne(eo); }
+
+private:
+ bool m_destructing;
+ QList<QSharedPointer<Scope> > m_scopes;
+ QList<EvaluationObject *> m_evaluationObjects;
+ QList<LanguageObject *> m_languageObjects;
+};
+
+
+// evaluation objects
+
+class ScopeChain;
+class Scope;
+
+class Property
+{
+public:
+ Property() {}
+ explicit Property(QSharedPointer<Scope> scope)
+ : scope(scope)
+ {}
+ explicit Property(EvaluationObject *object);
+ explicit Property(const QScriptValue &scriptValue);
+
+ // ids, project. etc, JS imports and
+ // where properties get resolved to
+ QSharedPointer<ScopeChain> scopeChain;
+ QScriptProgram valueSource;
+ QList<Property> baseProperties;
+
+ // value once it's been evaluated
+ QScriptValue value;
+
+ // if value is a scope
+ QSharedPointer<Scope> scope;
+
+ bool isValid() const { return scopeChain || scope || value.isValid(); }
+};
+
+class ScopeChain : public QScriptClass
+{
+ Q_DISABLE_COPY(ScopeChain)
+public:
+ typedef QSharedPointer<ScopeChain> Ptr;
+
+ ScopeChain(QScriptEngine *engine, const QSharedPointer<Scope> &root = QSharedPointer<Scope>());
+ ~ScopeChain();
+
+ ScopeChain *clone() const;
+ QScriptValue value();
+ QSharedPointer<Scope> first() const;
+ QSharedPointer<Scope> last() const;
+ // returns this
+ ScopeChain *prepend(const QSharedPointer<Scope> &newTop);
+
+ QSharedPointer<Scope> findNonEmpty(const QString &name) const;
+ QSharedPointer<Scope> find(const QString &name) const;
+
+ Property lookupProperty(const QString &name) const;
+
+protected:
+ // QScriptClass interface
+ QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name,
+ QueryFlags flags, uint *id);
+ QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+ void setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &m_value);
+
+private:
+ QList<QWeakPointer<Scope> > m_scopes;
+ QScriptValue m_value;
+ QScriptValue m_globalObject;
+};
+
+class Scope : public QScriptClass
+{
+ Q_DISABLE_COPY(Scope)
+ Scope(QScriptEngine *engine, const QString &name);
+public:
+ typedef QSharedPointer<Scope> Ptr;
+ static std::set<Scope *> scopesWithEvaluatedProperties;
+
+ static Ptr create(QScriptEngine *engine, const QString &name, ProjectFile *owner);
+ ~Scope();
+
+ QString name() const;
+
+protected:
+ // QScriptClass interface
+ QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name,
+ QueryFlags flags, uint *id);
+ QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+
+public:
+ QScriptValue property(const QString &name) const;
+ bool boolValue(const QString &name, bool defaultValue = false) const;
+ QString stringValue(const QString &name) const;
+ QStringList stringListValue(const QString &name) const;
+ QString verbatimValue(const QString &name) const;
+ void dump(const QByteArray &indent) const;
+
+ QHash<QString, Property> properties;
+ QHash<QString, PropertyDeclaration> declarations;
+
+ QString m_name;
+ QWeakPointer<Scope> fallbackScope;
+ QScriptValue value;
+};
+
+class Module;
+
+class UnknownModule
+{
+public:
+ QString name;
+ bool required;
+ QString failureMessage;
+ qbs::CodeLocation dependsLocation;
+};
+
+class EvaluationObject
+{
+ Q_DISABLE_COPY(EvaluationObject)
+public:
+ EvaluationObject(LanguageObject *instantiatingObject);
+ ~EvaluationObject();
+
+ LanguageObject *instantiatingObject() const;
+ void dump(QByteArray &indent);
+
+ QString prototype;
+
+ Scope::Ptr scope;
+ QList<EvaluationObject *> children;
+ QHash<QString, QSharedPointer<Module> > modules;
+ QList<UnknownModule> unknownModules;
+
+ // the source objects that generated this object
+ // the object that triggered the instantiation is first, followed by prototypes
+ QList<LanguageObject *> objects;
+};
+
+class Module
+{
+ Q_DISABLE_COPY(Module)
+public:
+ typedef QSharedPointer<Module> Ptr;
+
+ Module();
+ ~Module();
+
+ ProjectFile *file() const;
+ void dump(QByteArray &indent);
+
+ QString id;
+ QString name;
+ qbs::CodeLocation dependsLocation;
+
+ Scope::Ptr context;
+ EvaluationObject *object;
+};
+
+class Loader
+{
+ Q_DECLARE_TR_FUNCTIONS(Loader)
+public:
+ Loader();
+ ~Loader();
+ void setSearchPaths(const QStringList &searchPaths);
+ ProjectFile::Ptr loadProject(const QString &fileName);
+ bool hasLoaded() const { return m_project; }
+ int productCount(Configuration::Ptr userProperties);
+ ResolvedProject::Ptr resolveProject(const QString &buildDirectoryRoot,
+ Configuration::Ptr userProperties,
+ QFutureInterface<bool> &futureInterface,
+ bool resolveProductDependencies = true);
+
+protected:
+ ProjectFile::Ptr parseFile(const QString &fileName);
+
+ Scope::Ptr buildFileContext(ProjectFile *file);
+ Module::Ptr loadModule(const QString &moduleId, const QString &moduleName, ScopeChain::Ptr moduleScope,
+ const QVariantMap &userProperties, const qbs::CodeLocation &dependsLocation,
+ const QStringList &extraSearchPaths = QStringList());
+ Module::Ptr loadModule(ProjectFile *file, const QString &moduleId, const QString &moduleName, ScopeChain::Ptr moduleBaseScope,
+ const QVariantMap &userProperties, const qbs::CodeLocation &dependsLocation);
+ QList<Module::Ptr> evaluateDependency(EvaluationObject *parentEObj, LanguageObject *depends,
+ ScopeChain::Ptr moduleScope,
+ const QStringList &extraSearchPaths, QList<UnknownModule> *unknownModules, const QVariantMap &userProperties);
+ void evaluateDependencies(LanguageObject *object, EvaluationObject *evaluationObject, const ScopeChain::Ptr &localScope,
+ ScopeChain::Ptr moduleScope, const QVariantMap &userProperties, bool loadBaseModule = true);
+ void evaluateImports(Scope::Ptr target, const JsImports &jsImports);
+ void evaluatePropertyOptions(LanguageObject *object);
+ void resolveInheritance(LanguageObject *object, EvaluationObject *evaluationObject,
+ ScopeChain::Ptr moduleScope = ScopeChain::Ptr(), const QVariantMap &userProperties = QVariantMap());
+ void fillEvaluationObject(const ScopeChain::Ptr &scope, LanguageObject *object, Scope::Ptr ids, EvaluationObject *evaluationObject, const QVariantMap &userProperties);
+ void fillEvaluationObjectBasics(const ScopeChain::Ptr &scope, LanguageObject *object, EvaluationObject *evaluationObject);
+ void fillEvaluationObjectForProperties(const ScopeChain::Ptr &scope, LanguageObject *object, Scope::Ptr ids, EvaluationObject *evaluationObject, const QVariantMap &userProperties);
+ void setupInternalPrototype(EvaluationObject *evaluationObject);
+ void resolveModule(ResolvedProduct::Ptr rproduct, const QString &moduleName, EvaluationObject *module);
+ void resolveGroup(ResolvedProduct::Ptr rproduct, EvaluationObject *product, EvaluationObject *group);
+ void resolveProductModule(ResolvedProduct::Ptr rproduct, EvaluationObject *product, EvaluationObject *group);
+ void resolveTransformer(ResolvedProduct::Ptr rproduct, EvaluationObject *trafo, ResolvedModule::Ptr module);
+ QList<EvaluationObject *> resolveCommonItems(const QList<EvaluationObject *> &objects,
+ ResolvedProduct::Ptr rproduct, ResolvedModule::Ptr module);
+ Rule::Ptr resolveRule(EvaluationObject *object, ResolvedModule::Ptr module);
+ void buildModulesProperty(EvaluationObject *evaluationObject);
+
+ class ProductData
+ {
+ public:
+ EvaluationObject *product;
+ QList<UnknownModule> usedProducts;
+ QList<UnknownModule> usedProductsFromProductModule;
+
+ void addUsedProducts(const QList<UnknownModule> &additionalUsedProducts, bool *productsAdded);
+ };
+ typedef QHash<ResolvedProduct::Ptr, ProductData> ProjectData;
+
+ EvaluationObject *resolveTopLevel(const ResolvedProject::Ptr &rproject,
+ LanguageObject *object,
+ const QString &projectFileName,
+ ProjectData *projectData,
+ QList<Rule::Ptr> *globalRules,
+ const Configuration::Ptr &userProperties,
+ const ScopeChain::Ptr &scope,
+ const ResolvedModule::Ptr &dummyModule,
+ QFutureInterface<bool> &futureInterface);
+
+private:
+ static Loader *get(QScriptEngine *engine);
+ static QScriptValue js_getHostOS(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_getHostDefaultArchitecture(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_configurationValue(QScriptContext *context, QScriptEngine *engine);
+
+ static QHash<QString, PropertyDeclaration> m_dependsPropertyDeclarations;
+
+ QStringList m_searchPaths;
+ QScriptEngine m_engine;
+ QScriptValue m_jsFunction_getHostOS;
+ QScriptValue m_jsFunction_getHostDefaultArchitecture;
+ QScriptValue m_jsFunction_configurationValue;
+ Settings::Ptr m_settings;
+ ProjectFile::Ptr m_project;
+ QHash<QString, ProjectFile::Ptr> m_parsedFiles;
+ QHash<QString, QScriptValue> m_jsImports;
+ QHash<Rule::Ptr, EvaluationObject *> m_ruleMap;
+ QHash<QString, QVariantMap> m_productModules;
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/lib.pro b/src/lib/lib.pro
new file mode 100644
index 000000000..28d41e097
--- /dev/null
+++ b/src/lib/lib.pro
@@ -0,0 +1,16 @@
+QT = core script
+TEMPLATE = lib
+DESTDIR = ../../lib
+TARGET = qbscore
+
+CONFIG += staticlib depend_includepath
+DEFINES += QT_CREATOR QML_BUILD_STATIC_LIB # needed for QmlJS
+
+win32:CONFIG(debug, debug|release):TARGET = $${TARGET}d
+
+include(tools/tools.pri)
+include(parser/parser.pri)
+include(buildgraph/buildgraph.pri)
+include(Qbs/Qbs.pri)
+include(language/language.pri)
+include(qtconcurrent/qtconcurrent.pri)
diff --git a/src/lib/parser/cmd.sed b/src/lib/parser/cmd.sed
new file mode 100644
index 000000000..d76372675
--- /dev/null
+++ b/src/lib/parser/cmd.sed
@@ -0,0 +1,13 @@
+s/private\/qdeclarative/qml/g
+s/qdeclarative/qml/g
+s/QDECLARATIVE/QML/g
+s/QDeclarative/Qml/g
+s/Q_DECLARATIVE_EXPORT //g
+
+# adjust pri file
+s/ \$\$PWD\/qmljsglobal_p.h/ $$PWD\/qmljsglobal_p.h \\\
+ $$PWD\/qmldirparser_p.h \\\
+ $$PWD\/qmlerror.h/
+s/ \$\$PWD\/qmljsparser.cpp/ $$PWD\/qmljsparser.cpp \\\
+ $$PWD\/qmldirparser.cpp \\\
+ $$PWD\/qmlerror.cpp/
diff --git a/src/lib/parser/gen-parser.sh b/src/lib/parser/gen-parser.sh
new file mode 100644
index 000000000..acd6a19ce
--- /dev/null
+++ b/src/lib/parser/gen-parser.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+me=$(dirname $0)
+
+for i in $QTDIR/src/declarative/qml/parser/*.{g,h,cpp,pri}; do
+ sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qdeclarativejs/qmljs/)
+done
+
+for i in $QTDIR/src/declarative/qml/qdeclarative{error.{h,cpp},dirparser{_p.h,.cpp}}; do
+ sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qdeclarative/qml/)
+done
+
+# export QmlDirParser
+perl -p -0777 -i -e 's/QT_BEGIN_NAMESPACE\n\nclass QmlError;\nclass QmlDirParser/#include "qmljsglobal_p.h"\n\nQT_BEGIN_NAMESPACE\n\nclass QmlError;\nclass QML_PARSER_EXPORT QmlDirParser/' qmldirparser_p.h
diff --git a/src/lib/parser/parser.pri b/src/lib/parser/parser.pri
new file mode 100644
index 000000000..8ce19ae18
--- /dev/null
+++ b/src/lib/parser/parser.pri
@@ -0,0 +1,23 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qmljsast_p.h \
+ $$PWD/qmljsastfwd_p.h \
+ $$PWD/qmljsastvisitor_p.h \
+ $$PWD/qmljsengine_p.h \
+ $$PWD/qmljsgrammar_p.h \
+ $$PWD/qmljslexer_p.h \
+ $$PWD/qmljsmemorypool_p.h \
+ $$PWD/qmljsnodepool_p.h \
+ $$PWD/qmljsparser_p.h \
+ $$PWD/qmljsglobal_p.h \
+ $$PWD/qmlerror.h
+
+SOURCES += \
+ $$PWD/qmljsast.cpp \
+ $$PWD/qmljsastvisitor.cpp \
+ $$PWD/qmljsengine_p.cpp \
+ $$PWD/qmljsgrammar.cpp \
+ $$PWD/qmljslexer.cpp \
+ $$PWD/qmljsparser.cpp \
+ $$PWD/qmlerror.cpp
diff --git a/src/lib/parser/qmlerror.cpp b/src/lib/parser/qmlerror.cpp
new file mode 100644
index 000000000..7c1ed5707
--- /dev/null
+++ b/src/lib/parser/qmlerror.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlerror.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QmlError
+ \since 4.7
+ \brief The QmlError class encapsulates a QML error.
+
+ QmlError includes a textual description of the error, as well
+ as location information (the file, line, and column). The toString()
+ method creates a single-line, human-readable string containing all of
+ this information, for example:
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ \endcode
+
+ You can use qDebug() or qWarning() to output errors to the console. This method
+ will attempt to open the file indicated by the error
+ and include additional contextual information.
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ y: "hello"
+ ^
+ \endcode
+
+ \sa QmlView::errors(), QmlComponent::errors()
+*/
+class QmlErrorPrivate
+{
+public:
+ QmlErrorPrivate();
+
+ QUrl url;
+ QString description;
+ int line;
+ int column;
+};
+
+QmlErrorPrivate::QmlErrorPrivate()
+: line(-1), column(-1)
+{
+}
+
+/*!
+ Creates an empty error object.
+*/
+QmlError::QmlError()
+: d(0)
+{
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+QmlError::QmlError(const QmlError &other)
+: d(0)
+{
+ *this = other;
+}
+
+/*!
+ Assigns \a other to this error object.
+*/
+QmlError &QmlError::operator=(const QmlError &other)
+{
+ if (!other.d) {
+ delete d;
+ d = 0;
+ } else {
+ if (!d) d = new QmlErrorPrivate;
+ d->url = other.d->url;
+ d->description = other.d->description;
+ d->line = other.d->line;
+ d->column = other.d->column;
+ }
+ return *this;
+}
+
+/*!
+ \internal
+*/
+QmlError::~QmlError()
+{
+ delete d; d = 0;
+}
+
+/*!
+ Returns true if this error is valid, otherwise false.
+*/
+bool QmlError::isValid() const
+{
+ return d != 0;
+}
+
+/*!
+ Returns the url for the file that caused this error.
+*/
+QUrl QmlError::url() const
+{
+ if (d) return d->url;
+ else return QUrl();
+}
+
+/*!
+ Sets the \a url for the file that caused this error.
+*/
+void QmlError::setUrl(const QUrl &url)
+{
+ if (!d) d = new QmlErrorPrivate;
+ d->url = url;
+}
+
+/*!
+ Returns the error description.
+*/
+QString QmlError::description() const
+{
+ if (d) return d->description;
+ else return QString();
+}
+
+/*!
+ Sets the error \a description.
+*/
+void QmlError::setDescription(const QString &description)
+{
+ if (!d) d = new QmlErrorPrivate;
+ d->description = description;
+}
+
+/*!
+ Returns the error line number.
+*/
+int QmlError::line() const
+{
+ if (d) return d->line;
+ else return -1;
+}
+
+/*!
+ Sets the error \a line number.
+*/
+void QmlError::setLine(int line)
+{
+ if (!d) d = new QmlErrorPrivate;
+ d->line = line;
+}
+
+/*!
+ Returns the error column number.
+*/
+int QmlError::column() const
+{
+ if (d) return d->column;
+ else return -1;
+}
+
+/*!
+ Sets the error \a column number.
+*/
+void QmlError::setColumn(int column)
+{
+ if (!d) d = new QmlErrorPrivate;
+ d->column = column;
+}
+
+/*!
+ Returns the error as a human readable string.
+*/
+QString QmlError::toString() const
+{
+ QString rv;
+ if (url().isEmpty()) {
+ rv = QLatin1String("<Unknown File>");
+ } else if (line() != -1) {
+ rv = url().toString() + QLatin1Char(':') + QString::number(line());
+ if(column() != -1)
+ rv += QLatin1Char(':') + QString::number(column());
+ } else {
+ rv = url().toString();
+ }
+
+ rv += QLatin1String(": ") + description();
+
+ return rv;
+}
+
+/*!
+ \relates QmlError
+ \fn QDebug operator<<(QDebug debug, const QmlError &error)
+
+ Outputs a human readable version of \a error to \a debug.
+*/
+
+QDebug operator<<(QDebug debug, const QmlError &error)
+{
+ debug << qPrintable(error.toString());
+
+ QUrl url = error.url();
+
+ if (error.line() > 0 && url.scheme() == QLatin1String("file")) {
+ QString file = url.toLocalFile();
+ QFile f(file);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QTextStream stream(data, QIODevice::ReadOnly);
+#ifndef QT_NO_TEXTCODEC
+ stream.setCodec("UTF-8");
+#endif
+ const QString code = stream.readAll();
+ const QStringList lines = code.split(QLatin1Char('\n'));
+
+ if (lines.count() >= error.line()) {
+ const QString &line = lines.at(error.line() - 1);
+ debug << "\n " << qPrintable(line);
+
+ if(error.column() > 0) {
+ int column = qMax(0, error.column() - 1);
+ column = qMin(column, line.length());
+
+ QByteArray ind;
+ ind.reserve(column);
+ for (int i = 0; i < column; ++i) {
+ const QChar ch = line.at(i);
+ if (ch.isSpace())
+ ind.append(ch.unicode());
+ else
+ ind.append(' ');
+ }
+ ind.append('^');
+ debug << "\n " << ind.constData();
+ }
+ }
+ }
+ }
+ return debug;
+}
+
+QT_END_NAMESPACE
diff --git a/src/lib/parser/qmlerror.h b/src/lib/parser/qmlerror.h
new file mode 100644
index 000000000..3df3edc90
--- /dev/null
+++ b/src/lib/parser/qmlerror.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLERROR_H
+#define QMLERROR_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDebug;
+class QmlErrorPrivate;
+class QmlError
+{
+public:
+ QmlError();
+ QmlError(const QmlError &);
+ QmlError &operator=(const QmlError &);
+ ~QmlError();
+
+ bool isValid() const;
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ QString description() const;
+ void setDescription(const QString &);
+ int line() const;
+ void setLine(int);
+ int column() const;
+ void setColumn(int);
+
+ QString toString() const;
+private:
+ QmlErrorPrivate *d;
+};
+
+QDebug operator<<(QDebug debug, const QmlError &error);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLERROR_H
diff --git a/src/lib/parser/qmljs.g b/src/lib/parser/qmljs.g
new file mode 100644
index 000000000..b5439a9bc
--- /dev/null
+++ b/src/lib/parser/qmljs.g
@@ -0,0 +1,3138 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+-- All rights reserved.
+-- Contact: Nokia Corporation (qt-info@nokia.com)
+--
+-- This file is part of the QtDeclarative module of the Qt Toolkit.
+--
+-- $QT_BEGIN_LICENSE:LGPL-ONLY$
+-- GNU Lesser General Public License Usage
+-- This file may be used under the terms of the GNU Lesser
+-- General Public License version 2.1 as published by the Free Software
+-- Foundation and appearing in the file LICENSE.LGPL included in the
+-- packaging of this file. Please review the following information to
+-- ensure the GNU Lesser General Public License version 2.1 requirements
+-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+--
+-- If you have questions regarding the use of this file, please contact
+-- Nokia at qt-info@nokia.com.
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser QmlJSGrammar
+%decl qmljsparser_p.h
+%impl qmljsparser.cpp
+%expect 2
+%expect-rr 2
+
+%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
+%token T_BREAK "break" T_CASE "case" T_CATCH "catch"
+%token T_COLON ":" T_COMMA ";" T_CONTINUE "continue"
+%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/"
+%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "."
+%token T_ELSE "else" T_EQ "=" T_EQ_EQ "=="
+%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for"
+%token T_FUNCTION "function" T_GE ">=" T_GT ">"
+%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>"
+%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if"
+%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{"
+%token T_LBRACKET "[" T_LE "<=" T_LPAREN "("
+%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<="
+%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--"
+%token T_NEW "new" T_NOT "!" T_NOT_EQ "!="
+%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|"
+%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+"
+%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?"
+%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
+%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")"
+%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*"
+%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal"
+%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly"
+%token T_SWITCH "switch" T_THIS "this" T_THROW "throw"
+%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof"
+%token T_VAR "var" T_VOID "void" T_WHILE "while"
+%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
+%token T_NULL "null" T_TRUE "true" T_FALSE "false"
+%token T_CONST "const"
+%token T_DEBUGGER "debugger"
+%token T_RESERVED_WORD "reserved word"
+%token T_MULTILINE_STRING_LITERAL "multiline string literal"
+%token T_COMMENT "comment"
+
+--- context keywords.
+%token T_PUBLIC "public"
+%token T_IMPORT "import"
+%token T_AS "as"
+%token T_ON "on"
+
+--- feed tokens
+%token T_FEED_UI_PROGRAM
+%token T_FEED_UI_OBJECT_MEMBER
+%token T_FEED_JS_STATEMENT
+%token T_FEED_JS_EXPRESSION
+%token T_FEED_JS_SOURCE_ELEMENT
+%token T_FEED_JS_PROGRAM
+
+%nonassoc SHIFT_THERE
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY
+%nonassoc REDUCE_HERE
+
+%start TopLevel
+
+/./****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtGui/QApplication>
+
+#include <string.h>
+
+#include "qmljsengine_p.h"
+#include "qmljslexer_p.h"
+#include "qmljsast_p.h"
+#include "qmljsnodepool_p.h"
+
+./
+
+/:/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QMLJSPARSER_P_H
+#define QMLJSPARSER_P_H
+
+#include "qmljsglobal_p.h"
+#include "qmljsgrammar_p.h"
+#include "qmljsast_p.h"
+#include "qmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Parser: protected $table
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ NameId *sval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ AST::UiSignature *UiSignature;
+ AST::UiFormalList *UiFormalList;
+ AST::UiFormal *UiFormal;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ };
+
+ double yylval;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QmlJS
+
+
+:/
+
+
+/.
+
+#include "qmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+}
+
+inline static bool automatic(Engine *driver, int token)
+{
+ return token == $table::T_RBRACE
+ || token == 0
+ || driver->lexer()->prevTerminator();
+}
+
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ qFree(sym_stack);
+ qFree(state_stack);
+ qFree(location_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->startLineNo();
+ loc.startColumn = lexer->startColumnNo();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<NameId *, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->dval();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Declarative UI
+--------------------------------------------------------------------------------------------------------
+
+TopLevel: T_FEED_UI_PROGRAM UiProgram ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_STATEMENT Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_EXPRESSION Expression ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_PROGRAM Program ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+UiProgram: UiImportListOpt UiRootMember ;
+/.
+case $rule_number: {
+ sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+./
+
+UiImportListOpt: Empty ;
+UiImportListOpt: UiImportList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+./
+
+UiImportList: UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport);
+} break;
+./
+
+UiImportList: UiImportList UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(),
+ sym(1).UiImportList, sym(2).UiImport);
+} break;
+./
+
+ImportId: MemberExpression ;
+
+UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = sym(4).sval;
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+./
+
+UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = sym(3).sval;
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+./
+
+
+UiImportHead: T_IMPORT ImportId ;
+/.
+case $rule_number: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+./
+
+Empty: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiRootMember: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMemberList UiObjectMember ;
+/.
+case $rule_number: {
+ AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(),
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+./
+
+UiArrayMemberList: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ;
+/.
+case $rule_number: {
+ AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(),
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectDefinition: UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiObjectDefinition ;
+
+UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+./
+
+UiScriptStatement: Block ;
+UiScriptStatement: EmptyStatement ;
+UiScriptStatement: ExpressionStatement ;
+UiScriptStatement: IfStatement ; --- ### do we really want if statement in a binding?
+
+UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ;
+/.
+case $rule_number:
+{
+ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiPropertyType: T_VAR ;
+/.
+case $rule_number:
+./
+UiPropertyType: T_RESERVED_WORD ;
+/.
+case $rule_number: {
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+ break;
+}
+./
+
+UiPropertyType: T_IDENTIFIER ;
+
+UiParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiParameterListOpt: UiParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+./
+
+UiParameterList: UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval);
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval);
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+./
+
+UiObjectMember: VariableStatement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+./
+
+JsIdentifier: T_IDENTIFIER;
+
+JsIdentifier: T_PROPERTY ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_SIGNAL ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_READONLY ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_READONLY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_ON ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_ON]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Expressions
+--------------------------------------------------------------------------------------------------------
+
+PrimaryExpression: T_THIS ;
+/.
+case $rule_number: {
+ AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool());
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NULL ;
+/.
+case $rule_number: {
+ AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool());
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_TRUE ;
+/.
+case $rule_number: {
+ AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool());
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_FALSE ;
+/.
+case $rule_number: {
+ AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool());
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_MULTILINE_STRING_LITERAL ;
+/.case $rule_number:./
+
+PrimaryExpression: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_EQ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+-- PrimaryExpression: T_LBRACE T_RBRACE ;
+-- /.
+-- case $rule_number: {
+-- sym(1).Node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+-- } break;
+-- ./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LPAREN Expression T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiQualifiedId: MemberExpression ;
+/.
+case $rule_number: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+./
+
+ElementList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression);
+} break;
+./
+
+ElementList: Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression);
+} break;
+./
+
+ElementList: ElementList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ElementList: ElementList T_COMMA Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool());
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: Elision T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_SIGNAL ;
+/.case $rule_number:./
+
+PropertyName: T_PROPERTY ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: ReservedIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ReservedIdentifier: T_BREAK ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CASE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CATCH ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CONTINUE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DEFAULT ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DELETE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DO ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_ELSE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FALSE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FINALLY ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FOR ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FUNCTION ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_IF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_IN ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_INSTANCEOF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_NEW ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_NULL ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_RETURN ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_SWITCH ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_THIS ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_THROW ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TRUE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TRY ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TYPEOF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_VAR ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_VOID ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_WHILE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CONST ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DEBUGGER ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_RESERVED_WORD ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_WITH ;
+/.
+case $rule_number:
+{
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+} break;
+./
+
+PropertyIdentifier: JsIdentifier ;
+PropertyIdentifier: ReservedIdentifier ;
+
+MemberExpression: PrimaryExpression ;
+MemberExpression: FunctionExpression ;
+
+MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: MemberExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+NewExpression: MemberExpression ;
+
+NewExpression: T_NEW NewExpression ;
+/.
+case $rule_number: {
+ AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ArgumentListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ArgumentListOpt: ArgumentList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+./
+
+ArgumentList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression);
+} break;
+./
+
+ArgumentList: ArgumentList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LeftHandSideExpression: NewExpression ;
+LeftHandSideExpression: CallExpression ;
+PostfixExpression: LeftHandSideExpression ;
+
+PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ;
+/.
+case $rule_number: {
+ AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ;
+/.
+case $rule_number: {
+ AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: PostfixExpression ;
+
+UnaryExpression: T_DELETE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_VOID UnaryExpression ;
+/.
+case $rule_number: {
+ AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TYPEOF UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TILDE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_NOT UnaryExpression ;
+/.
+case $rule_number: {
+ AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: UnaryExpression ;
+
+MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: MultiplicativeExpression ;
+
+AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: AdditiveExpression ;
+
+ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: ShiftExpression ;
+
+RelationalExpression: RelationalExpression T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_IN ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: ShiftExpression ;
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: RelationalExpression ;
+
+EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: RelationalExpressionNotIn ;
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpression: EqualityExpression ;
+
+BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpressionNotIn: EqualityExpressionNotIn ;
+
+BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpression: BitwiseANDExpression ;
+
+BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ;
+
+BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpression: BitwiseXORExpression ;
+
+BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ;
+
+BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpression: BitwiseORExpression ;
+
+LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ;
+
+LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpression: LogicalANDExpression ;
+
+LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpressionNotIn: LogicalANDExpressionNotIn ;
+
+LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpression: LogicalORExpression ;
+
+ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn ;
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpression: ConditionalExpression ;
+
+AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpressionNotIn: ConditionalExpressionNotIn ;
+
+AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentOperator: T_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+./
+
+AssignmentOperator: T_STAR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+./
+
+AssignmentOperator: T_DIVIDE_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+./
+
+AssignmentOperator: T_REMAINDER_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+./
+
+AssignmentOperator: T_PLUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+./
+
+AssignmentOperator: T_MINUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+./
+
+AssignmentOperator: T_LT_LT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+./
+
+AssignmentOperator: T_AND_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+./
+
+AssignmentOperator: T_XOR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+./
+
+AssignmentOperator: T_OR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+./
+
+Expression: AssignmentExpression ;
+
+Expression: Expression T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionOpt: Expression ;
+
+ExpressionNotIn: AssignmentExpressionNotIn ;
+
+ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionNotInOpt: ExpressionNotIn ;
+
+Statement: Block ;
+Statement: VariableStatement ;
+Statement: EmptyStatement ;
+Statement: ExpressionStatement ;
+Statement: IfStatement ;
+Statement: IterationStatement ;
+Statement: ContinueStatement ;
+Statement: BreakStatement ;
+Statement: ReturnStatement ;
+Statement: WithStatement ;
+Statement: LabelledStatement ;
+Statement: SwitchStatement ;
+Statement: ThrowStatement ;
+Statement: TryStatement ;
+Statement: DebuggerStatement ;
+
+
+Block: T_LBRACE StatementListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+StatementList: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement);
+} break;
+./
+
+StatementList: StatementList Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement);
+} break;
+./
+
+StatementListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+StatementListOpt: StatementList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+./
+
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(),
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationKind: T_CONST ;
+/.
+case $rule_number: {
+ sym(1).ival = T_CONST;
+} break;
+./
+
+VariableDeclarationKind: T_VAR ;
+/.
+case $rule_number: {
+ sym(1).ival = T_VAR;
+} break;
+./
+
+VariableDeclarationList: VariableDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ;
+/.
+case $rule_number: {
+ AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(),
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+./
+
+VariableDeclaration: JsIdentifier InitialiserOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Initialiser: T_EQ AssignmentExpression ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserOpt: Initialiser ;
+
+InitialiserNotIn: T_EQ AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserNotInOpt: InitialiserNotIn ;
+
+EmptyStatement: T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool());
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ExpressionStatement: Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(),
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(),
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool());
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval);
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval);
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ;
+/.
+case $rule_number: {
+ AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+CaseClauses: CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause);
+} break;
+./
+
+CaseClauses: CaseClauses CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+./
+
+CaseClausesOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+CaseClausesOpt: CaseClauses ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+./
+
+CaseClause: T_CASE Expression T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+DefaultClause: T_DEFAULT T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_SIGNAL T_COLON Statement ;
+/.case $rule_number:./
+
+LabelledStatement: T_PROPERTY T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_IDENTIFIER T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ThrowStatement: T_THROW Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ;
+/.
+case $rule_number: {
+ AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+Finally: T_FINALLY Block ;
+/.
+case $rule_number: {
+ AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+DebuggerStatement: T_DEBUGGER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool());
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (sym(2).sval)
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FormalParameterListOpt: FormalParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+./
+
+FunctionBodyOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FunctionBodyOpt: FunctionBody ;
+
+FunctionBody: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+./
+
+Program: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+./
+
+SourceElements: SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement);
+} break;
+./
+
+SourceElements: SourceElements SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement);
+} break;
+./
+
+SourceElement: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement);
+} break;
+./
+
+SourceElement: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration);
+} break;
+./
+
+IdentifierOpt: ;
+/.
+case $rule_number: {
+ sym(1).sval = 0;
+} break;
+./
+
+IdentifierOpt: JsIdentifier ;
+
+PropertyNameAndValueListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+PropertyNameAndValueListOpt: PropertyNameAndValueList ;
+
+/.
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->dval();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QmlParser", "Syntax error");
+ else
+ msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
+./
+/:
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QMLJSPARSER_P_H
+:/
diff --git a/src/lib/parser/qmljsast.cpp b/src/lib/parser/qmljsast.cpp
new file mode 100644
index 000000000..02177ef5a
--- /dev/null
+++ b/src/lib/parser/qmljsast.cpp
@@ -0,0 +1,947 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmljsast_p.h"
+
+#include "qmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS { namespace AST {
+
+void Node::accept(Visitor *visitor)
+{
+ if (visitor->preVisit(this)) {
+ accept0(visitor);
+ }
+ visitor->postVisit(this);
+}
+
+void Node::accept(Node *node, Visitor *visitor)
+{
+ if (node)
+ node->accept(visitor);
+}
+
+ExpressionNode *Node::expressionCast()
+{
+ return 0;
+}
+
+BinaryExpression *Node::binaryExpressionCast()
+{
+ return 0;
+}
+
+Statement *Node::statementCast()
+{
+ return 0;
+}
+
+UiObjectMember *Node::uiObjectMemberCast()
+{
+ return 0;
+}
+
+ExpressionNode *ExpressionNode::expressionCast()
+{
+ return this;
+}
+
+BinaryExpression *BinaryExpression::binaryExpressionCast()
+{
+ return this;
+}
+
+Statement *Statement::statementCast()
+{
+ return this;
+}
+
+UiObjectMember *UiObjectMember::uiObjectMemberCast()
+{
+ return this;
+}
+
+void NestedExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void ThisExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NullExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void TrueLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void FalseLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void RegExpLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ accept(elision, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ObjectLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(properties, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ElementList *it = this; it; it = it->next) {
+ accept(it->elision, visitor);
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void Elision::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void PropertyNameAndValueList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PropertyNameAndValueList *it = this; it; it = it->next) {
+ accept(it->name, visitor);
+ accept(it->value, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FieldMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CallExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ArgumentList *it = this; it; it = it->next) {
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DeleteExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VoidExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeOfExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryPlusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryMinusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TildeExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NotExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void BinaryExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ConditionalExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Expression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Block::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementList *it = this; it; it = it->next) {
+ accept(it->statement, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclarationList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (VariableDeclarationList *it = this; it; it = it->next) {
+ accept(it->declaration, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void EmptyStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ExpressionStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void IfStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DoWhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ContinueStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void BreakStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ReturnStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WithStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SwitchStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(block, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseBlock::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(clauses, visitor);
+ accept(defaultClause, visitor);
+ accept(moreClauses, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClauses::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (CaseClauses *it = this; it; it = it->next) {
+ accept(it->clause, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DefaultClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LabelledStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ThrowStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TryStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catchExpression, visitor);
+ accept(finallyExpression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Catch::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Finally::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FormalParameterList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionBody::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Program::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SourceElements::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SourceElements *it = this; it; it = it->next) {
+ accept(it->element, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DebuggerStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiProgram::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(imports, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSignature::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void UiFormalList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiFormalList *it = this; it; it = it->next) {
+ accept(it->formal, visitor);
+ }
+ }
+ visitor->endVisit(this);
+}
+
+void UiFormal::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+ visitor->endVisit(this);
+}
+
+void UiPublicMember::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(binding, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectDefinition::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectInitializer::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiScriptBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiObjectMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiArrayMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiQualifiedId::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImport::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(importUri, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImportList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(import, visitor);
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(sourceElement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+} } // namespace QmlJS::AST
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/lib/parser/qmljsast_p.h b/src/lib/parser/qmljsast_p.h
new file mode 100644
index 000000000..15a547df3
--- /dev/null
+++ b/src/lib/parser/qmljsast_p.h
@@ -0,0 +1,2537 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSAST_P_H
+#define QMLJSAST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsastvisitor_p.h"
+#include "qmljsglobal_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+#define QMLJS_DECLARE_AST_NODE(name) \
+ enum { K = Kind_##name };
+
+namespace QSOperator // ### rename
+{
+
+enum Op {
+ Add,
+ And,
+ InplaceAnd,
+ Assign,
+ BitAnd,
+ BitOr,
+ BitXor,
+ InplaceSub,
+ Div,
+ InplaceDiv,
+ Equal,
+ Ge,
+ Gt,
+ In,
+ InplaceAdd,
+ InstanceOf,
+ Le,
+ LShift,
+ InplaceLeftShift,
+ Lt,
+ Mod,
+ InplaceMod,
+ Mul,
+ InplaceMul,
+ NotEqual,
+ Or,
+ InplaceOr,
+ RShift,
+ InplaceRightShift,
+ StrictEqual,
+ StrictNotEqual,
+ Sub,
+ URShift,
+ InplaceURightShift,
+ InplaceXor
+};
+
+} // namespace QSOperator
+
+namespace QmlJS {
+class NameId;
+namespace AST {
+
+template <typename _T1, typename _T2>
+_T1 cast(_T2 *ast)
+{
+ if (ast && ast->kind == static_cast<_T1>(0)->K)
+ return static_cast<_T1>(ast);
+
+ return 0;
+}
+
+class QML_PARSER_EXPORT Node
+{
+public:
+ enum Kind {
+ Kind_Undefined,
+
+ Kind_ArgumentList,
+ Kind_ArrayLiteral,
+ Kind_ArrayMemberExpression,
+ Kind_BinaryExpression,
+ Kind_Block,
+ Kind_BreakStatement,
+ Kind_CallExpression,
+ Kind_CaseBlock,
+ Kind_CaseClause,
+ Kind_CaseClauses,
+ Kind_Catch,
+ Kind_ConditionalExpression,
+ Kind_ContinueStatement,
+ Kind_DebuggerStatement,
+ Kind_DefaultClause,
+ Kind_DeleteExpression,
+ Kind_DoWhileStatement,
+ Kind_ElementList,
+ Kind_Elision,
+ Kind_EmptyStatement,
+ Kind_Expression,
+ Kind_ExpressionStatement,
+ Kind_FalseLiteral,
+ Kind_FieldMemberExpression,
+ Kind_Finally,
+ Kind_ForEachStatement,
+ Kind_ForStatement,
+ Kind_FormalParameterList,
+ Kind_FunctionBody,
+ Kind_FunctionDeclaration,
+ Kind_FunctionExpression,
+ Kind_FunctionSourceElement,
+ Kind_IdentifierExpression,
+ Kind_IdentifierPropertyName,
+ Kind_IfStatement,
+ Kind_LabelledStatement,
+ Kind_LocalForEachStatement,
+ Kind_LocalForStatement,
+ Kind_NewExpression,
+ Kind_NewMemberExpression,
+ Kind_NotExpression,
+ Kind_NullExpression,
+ Kind_NumericLiteral,
+ Kind_NumericLiteralPropertyName,
+ Kind_ObjectLiteral,
+ Kind_PostDecrementExpression,
+ Kind_PostIncrementExpression,
+ Kind_PreDecrementExpression,
+ Kind_PreIncrementExpression,
+ Kind_Program,
+ Kind_PropertyName,
+ Kind_PropertyNameAndValueList,
+ Kind_RegExpLiteral,
+ Kind_ReturnStatement,
+ Kind_SourceElement,
+ Kind_SourceElements,
+ Kind_StatementList,
+ Kind_StatementSourceElement,
+ Kind_StringLiteral,
+ Kind_StringLiteralPropertyName,
+ Kind_SwitchStatement,
+ Kind_ThisExpression,
+ Kind_ThrowStatement,
+ Kind_TildeExpression,
+ Kind_TrueLiteral,
+ Kind_TryStatement,
+ Kind_TypeOfExpression,
+ Kind_UnaryMinusExpression,
+ Kind_UnaryPlusExpression,
+ Kind_VariableDeclaration,
+ Kind_VariableDeclarationList,
+ Kind_VariableStatement,
+ Kind_VoidExpression,
+ Kind_WhileStatement,
+ Kind_WithStatement,
+ Kind_NestedExpression,
+
+ Kind_UiArrayBinding,
+ Kind_UiImport,
+ Kind_UiImportList,
+ Kind_UiObjectBinding,
+ Kind_UiObjectDefinition,
+ Kind_UiObjectInitializer,
+ Kind_UiObjectMemberList,
+ Kind_UiArrayMemberList,
+ Kind_UiProgram,
+ Kind_UiParameterList,
+ Kind_UiPublicMember,
+ Kind_UiQualifiedId,
+ Kind_UiScriptBinding,
+ Kind_UiSourceElement,
+ Kind_UiFormal,
+ Kind_UiFormalList,
+ Kind_UiSignature
+ };
+
+ inline Node()
+ : kind(Kind_Undefined) {}
+
+ // NOTE: node destructors are never called,
+ // instead we block free the memory
+ // (see the NodePool class)
+ virtual ~Node() {}
+
+ virtual ExpressionNode *expressionCast();
+ virtual BinaryExpression *binaryExpressionCast();
+ virtual Statement *statementCast();
+ virtual UiObjectMember *uiObjectMemberCast();
+
+ void accept(Visitor *visitor);
+ static void accept(Node *node, Visitor *visitor);
+
+ inline static void acceptChild(Node *node, Visitor *visitor)
+ { return accept(node, visitor); } // ### remove
+
+ virtual void accept0(Visitor *visitor) = 0;
+
+// attributes
+ int kind;
+};
+
+class QML_PARSER_EXPORT ExpressionNode: public Node
+{
+public:
+ ExpressionNode() {}
+
+ virtual ExpressionNode *expressionCast();
+
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+};
+
+class QML_PARSER_EXPORT Statement: public Node
+{
+public:
+ Statement() {}
+
+ virtual Statement *statementCast();
+
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+};
+
+class QML_PARSER_EXPORT UiFormal: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiFormal)
+
+ UiFormal(NameId *name, NameId *alias = 0)
+ : name(name), alias(alias)
+ { }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ NameId *alias;
+ SourceLocation identifierToken;
+ SourceLocation asToken;
+ SourceLocation aliasToken;
+};
+
+class QML_PARSER_EXPORT UiFormalList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiFormalList)
+
+ UiFormalList(UiFormal *formal)
+ : formal(formal), next(this) {}
+
+ UiFormalList(UiFormalList *previous, UiFormal *formal)
+ : formal(formal)
+ {
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiFormalList *finish()
+ {
+ UiFormalList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiFormal *formal;
+ UiFormalList *next;
+};
+
+class QML_PARSER_EXPORT UiSignature: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiSignature)
+
+ UiSignature(UiFormalList *formals = 0)
+ : formals(formals)
+ { }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceLocation lparenToken;
+ UiFormalList *formals;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NestedExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NestedExpression)
+
+ NestedExpression(ExpressionNode *expression)
+ : expression(expression)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lparenToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ThisExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ThisExpression)
+
+ ThisExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return thisToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return thisToken; }
+
+// attributes
+ SourceLocation thisToken;
+};
+
+class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(IdentifierExpression)
+
+ IdentifierExpression(NameId *n):
+ name (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+// attributes
+ NameId *name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NullExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NullExpression)
+
+ NullExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return nullToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return nullToken; }
+
+// attributes
+ SourceLocation nullToken;
+};
+
+class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(TrueLiteral)
+
+ TrueLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return trueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return trueToken; }
+
+// attributes
+ SourceLocation trueToken;
+};
+
+class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FalseLiteral)
+
+ FalseLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return falseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return falseToken; }
+
+// attributes
+ SourceLocation falseToken;
+};
+
+class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NumericLiteral)
+
+ NumericLiteral(double v):
+ value(v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ double value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT StringLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(StringLiteral)
+
+ StringLiteral(NameId *v):
+ value (v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ NameId *value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(RegExpLiteral)
+
+ RegExpLiteral(NameId *p, int f):
+ pattern (p), flags (f) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ NameId *pattern;
+ int flags;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ArrayLiteral)
+
+ ArrayLiteral(Elision *e):
+ elements (0), elision (e)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts):
+ elements (elts), elision (0)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts, Elision *e):
+ elements (elts), elision (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbracketToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ElementList *elements;
+ Elision *elision;
+ SourceLocation lbracketToken;
+ SourceLocation commaToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ObjectLiteral)
+
+ ObjectLiteral():
+ properties (0) { kind = K; }
+
+ ObjectLiteral(PropertyNameAndValueList *plist):
+ properties (plist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ PropertyNameAndValueList *properties;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT ElementList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ElementList)
+
+ ElementList(Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr), next (this)
+ { kind = K; }
+
+ ElementList(ElementList *previous, Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ inline ElementList *finish ()
+ {
+ ElementList *front = next;
+ next = 0;
+ return front;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Elision *elision;
+ ExpressionNode *expression;
+ ElementList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Elision: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Elision)
+
+ Elision():
+ next (this) { kind = K; }
+
+ Elision(Elision *previous)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline Elision *finish ()
+ {
+ Elision *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Elision *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyNameAndValueList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PropertyNameAndValueList)
+
+ PropertyNameAndValueList(PropertyName *n, ExpressionNode *v):
+ name (n), value (v), next (this)
+ { kind = K; }
+
+ PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v):
+ name (n), value (v)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline PropertyNameAndValueList *finish ()
+ {
+ PropertyNameAndValueList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ PropertyName *name;
+ ExpressionNode *value;
+ PropertyNameAndValueList *next;
+ SourceLocation colonToken;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyName: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PropertyName)
+
+ PropertyName() { kind = K; }
+
+// attributes
+ SourceLocation propertyNameToken;
+};
+
+class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
+{
+public:
+ QMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
+
+ IdentifierPropertyName(NameId *n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *id;
+};
+
+class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
+{
+public:
+ QMLJS_DECLARE_AST_NODE(StringLiteralPropertyName)
+
+ StringLiteralPropertyName(NameId *n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *id;
+};
+
+class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NumericLiteralPropertyName)
+
+ NumericLiteralPropertyName(double n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ double id;
+};
+
+class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ArrayMemberExpression)
+
+ ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e):
+ base (b), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ExpressionNode *base;
+ ExpressionNode *expression;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FieldMemberExpression)
+
+ FieldMemberExpression(ExpressionNode *b, NameId *n):
+ base (b), name (n)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+ // attributes
+ ExpressionNode *base;
+ NameId *name;
+ SourceLocation dotToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NewMemberExpression)
+
+ NewMemberExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+ // attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation newToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NewExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NewExpression)
+
+ NewExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation newToken;
+};
+
+class QML_PARSER_EXPORT CallExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(CallExpression)
+
+ CallExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ArgumentList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ArgumentList)
+
+ ArgumentList(ExpressionNode *e):
+ expression (e), next (this)
+ { kind = K; }
+
+ ArgumentList(ArgumentList *previous, ExpressionNode *e):
+ expression (e)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline ArgumentList *finish ()
+ {
+ ArgumentList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ ExpressionNode *expression;
+ ArgumentList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PostIncrementExpression)
+
+ PostIncrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return incrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PostDecrementExpression)
+
+ PostDecrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return decrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(DeleteExpression)
+
+ DeleteExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return deleteToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation deleteToken;
+};
+
+class QML_PARSER_EXPORT VoidExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(VoidExpression)
+
+ VoidExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return voidToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation voidToken;
+};
+
+class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(TypeOfExpression)
+
+ TypeOfExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return typeofToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation typeofToken;
+};
+
+class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PreIncrementExpression)
+
+ PreIncrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return incrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(PreDecrementExpression)
+
+ PreDecrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return decrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UnaryPlusExpression)
+
+ UnaryPlusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return plusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation plusToken;
+};
+
+class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UnaryMinusExpression)
+
+ UnaryMinusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return minusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation minusToken;
+};
+
+class QML_PARSER_EXPORT TildeExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(TildeExpression)
+
+ TildeExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tildeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation tildeToken;
+};
+
+class QML_PARSER_EXPORT NotExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(NotExpression)
+
+ NotExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return notToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation notToken;
+};
+
+class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(BinaryExpression)
+
+ BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r):
+ left (l), op (o), right (r)
+ { kind = K; }
+
+ virtual BinaryExpression *binaryExpressionCast();
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ int op;
+ ExpressionNode *right;
+ SourceLocation operatorToken;
+};
+
+class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ConditionalExpression)
+
+ ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return ko->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ ExpressionNode *ok;
+ ExpressionNode *ko;
+ SourceLocation questionToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Expression)
+
+ Expression(ExpressionNode *l, ExpressionNode *r):
+ left (l), right (r) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ ExpressionNode *right;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Block: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Block)
+
+ Block(StatementList *slist):
+ statements (slist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+ // attributes
+ StatementList *statements;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT StatementList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(StatementList)
+
+ StatementList(Statement *stmt):
+ statement (stmt), next (this)
+ { kind = K; }
+
+ StatementList(StatementList *previous, Statement *stmt):
+ statement (stmt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline StatementList *finish ()
+ {
+ StatementList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Statement *statement;
+ StatementList *next;
+};
+
+class QML_PARSER_EXPORT VariableStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(VariableStatement)
+
+ VariableStatement(VariableDeclarationList *vlist):
+ declarations (vlist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declarationKindToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ VariableDeclarationList *declarations;
+ SourceLocation declarationKindToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclaration: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(VariableDeclaration)
+
+ VariableDeclaration(NameId *n, ExpressionNode *e):
+ name (n), expression (e), readOnly(false)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ ExpressionNode *expression;
+ bool readOnly;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclarationList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(VariableDeclarationList)
+
+ VariableDeclarationList(VariableDeclaration *decl):
+ declaration (decl), next (this)
+ { kind = K; }
+
+ VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl):
+ declaration (decl)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline VariableDeclarationList *finish (bool readOnly)
+ {
+ VariableDeclarationList *front = next;
+ next = 0;
+ if (readOnly) {
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next)
+ vdl->declaration->readOnly = true;
+ }
+ return front;
+ }
+
+// attributes
+ VariableDeclaration *declaration;
+ VariableDeclarationList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT EmptyStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(EmptyStatement)
+
+ EmptyStatement() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return semicolonToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ExpressionStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ExpressionStatement)
+
+ ExpressionStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT IfStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(IfStatement)
+
+ IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return ifToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (ko)
+ return ko->lastSourceLocation();
+
+ return ok->lastSourceLocation();
+ }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *ok;
+ Statement *ko;
+ SourceLocation ifToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation elseToken;
+};
+
+class QML_PARSER_EXPORT DoWhileStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(DoWhileStatement)
+
+ DoWhileStatement(Statement *stmt, ExpressionNode *e):
+ statement (stmt), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return doToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ Statement *statement;
+ ExpressionNode *expression;
+ SourceLocation doToken;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WhileStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(WhileStatement)
+
+ WhileStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return whileToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ForStatement)
+
+ ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ initialiser (i), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(LocalForStatement)
+
+ LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ declarations (vlist), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclarationList *declarations;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForEachStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ForEachStatement)
+
+ ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt):
+ initialiser (i), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForEachStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(LocalForEachStatement)
+
+ LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt):
+ declaration (v), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclaration *declaration;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ContinueStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ContinueStatement)
+
+ ContinueStatement(NameId *l = 0):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return continueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ NameId *label;
+ SourceLocation continueToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT BreakStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(BreakStatement)
+
+ BreakStatement(NameId *l = 0):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return breakToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ NameId *label;
+ SourceLocation breakToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ReturnStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ReturnStatement)
+
+ ReturnStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return returnToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation returnToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WithStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(WithStatement)
+
+ WithStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return withToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation withToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseBlock: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(CaseBlock)
+
+ CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0):
+ clauses (c), defaultClause (d), moreClauses (r)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ CaseClauses *clauses;
+ DefaultClause *defaultClause;
+ CaseClauses *moreClauses;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT SwitchStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(SwitchStatement)
+
+ SwitchStatement(ExpressionNode *e, CaseBlock *b):
+ expression (e), block (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return switchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return block->rbraceToken; }
+
+// attributes
+ ExpressionNode *expression;
+ CaseBlock *block;
+ SourceLocation switchToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseClauses: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(CaseClauses)
+
+ CaseClauses(CaseClause *c):
+ clause (c), next (this)
+ { kind = K; }
+
+ CaseClauses(CaseClauses *previous, CaseClause *c):
+ clause (c)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline CaseClauses *finish ()
+ {
+ CaseClauses *front = next;
+ next = 0;
+ return front;
+ }
+
+//attributes
+ CaseClause *clause;
+ CaseClauses *next;
+};
+
+class QML_PARSER_EXPORT CaseClause: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(CaseClause)
+
+ CaseClause(ExpressionNode *e, StatementList *slist):
+ expression (e), statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ ExpressionNode *expression;
+ StatementList *statements;
+ SourceLocation caseToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT DefaultClause: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(DefaultClause)
+
+ DefaultClause(StatementList *slist):
+ statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ StatementList *statements;
+ SourceLocation defaultToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT LabelledStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(LabelledStatement)
+
+ LabelledStatement(NameId *l, Statement *stmt):
+ label (l), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ NameId *label;
+ Statement *statement;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT ThrowStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(ThrowStatement)
+
+ ThrowStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return throwToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation throwToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT Catch: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Catch)
+
+ Catch(NameId *n, Block *stmt):
+ name (n), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ Block *statement;
+ SourceLocation catchToken;
+ SourceLocation lparenToken;
+ SourceLocation identifierToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT Finally: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Finally)
+
+ Finally(Block *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Block *statement;
+ SourceLocation finallyToken;
+};
+
+class QML_PARSER_EXPORT TryStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(TryStatement)
+
+ TryStatement(Statement *stmt, Catch *c, Finally *f):
+ statement (stmt), catchExpression (c), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Finally *f):
+ statement (stmt), catchExpression (0), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Catch *c):
+ statement (stmt), catchExpression (c), finallyExpression (0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tryToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (finallyExpression)
+ return finallyExpression->statement->rbraceToken;
+ else if (catchExpression)
+ return catchExpression->statement->rbraceToken;
+
+ return statement->lastSourceLocation();
+ }
+
+// attributes
+ Statement *statement;
+ Catch *catchExpression;
+ Finally *finallyExpression;
+ SourceLocation tryToken;
+};
+
+class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FunctionExpression)
+
+ FunctionExpression(NameId *n, FormalParameterList *f, FunctionBody *b):
+ name (n), formals (f), body (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return functionToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ NameId *name;
+ FormalParameterList *formals;
+ FunctionBody *body;
+ SourceLocation functionToken;
+ SourceLocation identifierToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FunctionDeclaration)
+
+ FunctionDeclaration(NameId *n, FormalParameterList *f, FunctionBody *b):
+ FunctionExpression(n, f, b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+};
+
+class QML_PARSER_EXPORT FormalParameterList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FormalParameterList)
+
+ FormalParameterList(NameId *n):
+ name (n), next (this)
+ { kind = K; }
+
+ FormalParameterList(FormalParameterList *previous, NameId *n):
+ name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline FormalParameterList *finish ()
+ {
+ FormalParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ NameId *name;
+ FormalParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT FunctionBody: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FunctionBody)
+
+ FunctionBody(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT Program: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(Program)
+
+ Program(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT SourceElements: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(SourceElements)
+
+ SourceElements(SourceElement *elt):
+ element (elt), next (this)
+ { kind = K; }
+
+ SourceElements(SourceElements *previous, SourceElement *elt):
+ element (elt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline SourceElements *finish ()
+ {
+ SourceElements *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ SourceElement *element;
+ SourceElements *next;
+};
+
+class QML_PARSER_EXPORT SourceElement: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(SourceElement)
+
+ inline SourceElement()
+ { kind = K; }
+};
+
+class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(FunctionSourceElement)
+
+ FunctionSourceElement(FunctionDeclaration *f):
+ declaration (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ FunctionDeclaration *declaration;
+};
+
+class QML_PARSER_EXPORT StatementSourceElement: public SourceElement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(StatementSourceElement)
+
+ StatementSourceElement(Statement *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Statement *statement;
+};
+
+class QML_PARSER_EXPORT DebuggerStatement: public Statement
+{
+public:
+ QMLJS_DECLARE_AST_NODE(DebuggerStatement)
+
+ DebuggerStatement()
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return debuggerToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation debuggerToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiProgram: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiProgram)
+
+ UiProgram(UiImportList *imports, UiObjectMemberList *members)
+ : imports(imports), members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiImportList *imports;
+ UiObjectMemberList *members;
+};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(NameId *name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, NameId *name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *next;
+ NameId *name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiImport: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiImport)
+
+ UiImport(NameId *fileName)
+ : fileName(fileName), importUri(0), importId(0)
+ { kind = K; }
+
+ UiImport(UiQualifiedId *uri)
+ : fileName(0), importUri(uri), importId(0)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return importToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *fileName;
+ UiQualifiedId *importUri;
+ NameId *importId;
+ SourceLocation importToken;
+ SourceLocation fileNameToken;
+ SourceLocation versionToken;
+ SourceLocation asToken;
+ SourceLocation importIdToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiImportList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiImportList)
+
+ UiImportList(UiImport *import)
+ : import(import),
+ next(this)
+ { kind = K; }
+
+ UiImportList(UiImportList *previous, UiImport *import)
+ : import(import)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (import) return import->firstSourceLocation();
+ else return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ for (const UiImportList *it = this; it; it = it->next)
+ if (!it->next && it->import)
+ return it->import->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+ UiImportList *finish()
+ {
+ UiImportList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiImport *import;
+ UiImportList *next;
+};
+
+class QML_PARSER_EXPORT UiObjectMember: public Node
+{
+public:
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+ virtual UiObjectMember *uiObjectMemberCast();
+};
+
+class QML_PARSER_EXPORT UiObjectMemberList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiObjectMemberList)
+
+ UiObjectMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ UiObjectMemberList *finish()
+ {
+ UiObjectMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiObjectMemberList *next;
+ UiObjectMember *member;
+};
+
+class QML_PARSER_EXPORT UiArrayMemberList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiArrayMemberList)
+
+ UiArrayMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ UiArrayMemberList *finish()
+ {
+ UiArrayMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiArrayMemberList *next;
+ UiObjectMember *member;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT UiObjectInitializer: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiObjectInitializer)
+
+ UiObjectInitializer(UiObjectMemberList *members)
+ : members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceLocation lbraceToken;
+ UiObjectMemberList *members;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT UiParameterList: public Node
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiParameterList)
+
+ UiParameterList(NameId *t, NameId *n):
+ type (t), name (n), next (this)
+ { kind = K; }
+
+ UiParameterList(UiParameterList *previous, NameId *t, NameId *n):
+ type (t), name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *) {}
+
+ inline UiParameterList *finish ()
+ {
+ UiParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ NameId *type;
+ NameId *name;
+ UiParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiPublicMember)
+
+ UiPublicMember(NameId *memberType,
+ NameId *name)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), statement(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ UiPublicMember(NameId *memberType,
+ NameId *name,
+ Statement *statement)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (defaultToken.isValid())
+ return defaultToken;
+ else if (readonlyToken.isValid())
+ return readonlyToken;
+
+ return propertyToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (binding)
+ return binding->lastSourceLocation();
+
+ return semicolonToken;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ enum { Signal, Property } type;
+ NameId *typeModifier;
+ NameId *memberType;
+ NameId *name;
+ Statement *statement; // initialized with a JS expression
+ UiObjectMember *binding; // initialized with a QML object or array.
+ bool isDefaultMember;
+ bool isReadonlyMember;
+ UiParameterList *parameters;
+ SourceLocation defaultToken;
+ SourceLocation readonlyToken;
+ SourceLocation propertyToken;
+ SourceLocation typeModifierToken;
+ SourceLocation typeToken;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiObjectDefinition)
+
+ UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedTypeNameId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+};
+
+class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiSourceElement)
+
+ UiSourceElement(Node *sourceElement)
+ : sourceElement(sourceElement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->firstSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->firstSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->lastSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Node *sourceElement;
+};
+
+class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiObjectBinding)
+
+ UiObjectBinding(UiQualifiedId *qualifiedId,
+ UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedId(qualifiedId),
+ qualifiedTypeNameId(qualifiedTypeNameId),
+ initializer(initializer),
+ hasOnToken(false)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (hasOnToken && qualifiedTypeNameId)
+ return qualifiedTypeNameId->identifierToken;
+
+ return qualifiedId->identifierToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+ SourceLocation colonToken;
+ bool hasOnToken;
+};
+
+class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiScriptBinding)
+
+ UiScriptBinding(UiQualifiedId *qualifiedId,
+ Statement *statement)
+ : qualifiedId(qualifiedId),
+ statement(statement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ Statement *statement;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember
+{
+public:
+ QMLJS_DECLARE_AST_NODE(UiArrayBinding)
+
+ UiArrayBinding(UiQualifiedId *qualifiedId,
+ UiArrayMemberList *members)
+ : qualifiedId(qualifiedId),
+ members(members)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiArrayMemberList *members;
+ SourceLocation colonToken;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+} } // namespace AST
+
+
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/lib/parser/qmljsastfwd_p.h b/src/lib/parser/qmljsastfwd_p.h
new file mode 100644
index 000000000..e8fb200b3
--- /dev/null
+++ b/src/lib/parser/qmljsastfwd_p.h
@@ -0,0 +1,180 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSAST_FWD_P_H
+#define QMLJSAST_FWD_P_H
+
+#include "qmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS { namespace AST {
+
+class SourceLocation
+{
+public:
+ SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return length != 0; }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+};
+
+class Visitor;
+class Node;
+class ExpressionNode;
+class Statement;
+class ThisExpression;
+class IdentifierExpression;
+class NullExpression;
+class TrueLiteral;
+class FalseLiteral;
+class NumericLiteral;
+class StringLiteral;
+class RegExpLiteral;
+class ArrayLiteral;
+class ObjectLiteral;
+class ElementList;
+class Elision;
+class PropertyNameAndValueList;
+class PropertyName;
+class IdentifierPropertyName;
+class StringLiteralPropertyName;
+class NumericLiteralPropertyName;
+class ArrayMemberExpression;
+class FieldMemberExpression;
+class NewMemberExpression;
+class NewExpression;
+class CallExpression;
+class ArgumentList;
+class PostIncrementExpression;
+class PostDecrementExpression;
+class DeleteExpression;
+class VoidExpression;
+class TypeOfExpression;
+class PreIncrementExpression;
+class PreDecrementExpression;
+class UnaryPlusExpression;
+class UnaryMinusExpression;
+class TildeExpression;
+class NotExpression;
+class BinaryExpression;
+class ConditionalExpression;
+class Expression; // ### rename
+class Block;
+class StatementList;
+class VariableStatement;
+class VariableDeclarationList;
+class VariableDeclaration;
+class EmptyStatement;
+class ExpressionStatement;
+class IfStatement;
+class DoWhileStatement;
+class WhileStatement;
+class ForStatement;
+class LocalForStatement;
+class ForEachStatement;
+class LocalForEachStatement;
+class ContinueStatement;
+class BreakStatement;
+class ReturnStatement;
+class WithStatement;
+class SwitchStatement;
+class CaseBlock;
+class CaseClauses;
+class CaseClause;
+class DefaultClause;
+class LabelledStatement;
+class ThrowStatement;
+class TryStatement;
+class Catch;
+class Finally;
+class FunctionDeclaration;
+class FunctionExpression;
+class FormalParameterList;
+class FunctionBody;
+class Program;
+class SourceElements;
+class SourceElement;
+class FunctionSourceElement;
+class StatementSourceElement;
+class DebuggerStatement;
+class NestedExpression;
+
+// ui elements
+class UiProgram;
+class UiImportList;
+class UiImport;
+class UiPublicMember;
+class UiObjectDefinition;
+class UiObjectInitializer;
+class UiObjectBinding;
+class UiScriptBinding;
+class UiSourceElement;
+class UiArrayBinding;
+class UiObjectMember;
+class UiObjectMemberList;
+class UiArrayMemberList;
+class UiQualifiedId;
+class UiFormalList;
+class UiFormal;
+class UiSignature;
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/lib/parser/qmljsastvisitor.cpp b/src/lib/parser/qmljsastvisitor.cpp
new file mode 100644
index 000000000..1aea4dd2a
--- /dev/null
+++ b/src/lib/parser/qmljsastvisitor.cpp
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS { namespace AST {
+
+Visitor::Visitor()
+{
+}
+
+Visitor::~Visitor()
+{
+}
+
+} } // namespace QmlJS::AST
+
+QT_QML_END_NAMESPACE
diff --git a/src/lib/parser/qmljsastvisitor_p.h b/src/lib/parser/qmljsastvisitor_p.h
new file mode 100644
index 000000000..07b072ff3
--- /dev/null
+++ b/src/lib/parser/qmljsastvisitor_p.h
@@ -0,0 +1,326 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSASTVISITOR_P_H
+#define QMLJSASTVISITOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsastfwd_p.h"
+#include "qmljsglobal_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS { namespace AST {
+
+class QML_PARSER_EXPORT Visitor
+{
+public:
+ Visitor();
+ virtual ~Visitor();
+
+ virtual bool preVisit(Node *) { return true; }
+ virtual void postVisit(Node *) {}
+
+ // Ui
+ virtual bool visit(UiProgram *) { return true; }
+ virtual bool visit(UiImportList *) { return true; }
+ virtual bool visit(UiImport *) { return true; }
+ virtual bool visit(UiPublicMember *) { return true; }
+ virtual bool visit(UiSourceElement *) { return true; }
+ virtual bool visit(UiObjectDefinition *) { return true; }
+ virtual bool visit(UiObjectInitializer *) { return true; }
+ virtual bool visit(UiObjectBinding *) { return true; }
+ virtual bool visit(UiScriptBinding *) { return true; }
+ virtual bool visit(UiArrayBinding *) { return true; }
+ virtual bool visit(UiObjectMemberList *) { return true; }
+ virtual bool visit(UiArrayMemberList *) { return true; }
+ virtual bool visit(UiQualifiedId *) { return true; }
+ virtual bool visit(UiSignature *) { return true; }
+ virtual bool visit(UiFormalList *) { return true; }
+ virtual bool visit(UiFormal *) { return true; }
+
+ virtual void endVisit(UiProgram *) {}
+ virtual void endVisit(UiImportList *) {}
+ virtual void endVisit(UiImport *) {}
+ virtual void endVisit(UiPublicMember *) {}
+ virtual void endVisit(UiSourceElement *) {}
+ virtual void endVisit(UiObjectDefinition *) {}
+ virtual void endVisit(UiObjectInitializer *) {}
+ virtual void endVisit(UiObjectBinding *) {}
+ virtual void endVisit(UiScriptBinding *) {}
+ virtual void endVisit(UiArrayBinding *) {}
+ virtual void endVisit(UiObjectMemberList *) {}
+ virtual void endVisit(UiArrayMemberList *) {}
+ virtual void endVisit(UiQualifiedId *) {}
+ virtual void endVisit(UiSignature *) {}
+ virtual void endVisit(UiFormalList *) {}
+ virtual void endVisit(UiFormal *) {}
+
+ // QmlJS
+ virtual bool visit(ThisExpression *) { return true; }
+ virtual void endVisit(ThisExpression *) {}
+
+ virtual bool visit(IdentifierExpression *) { return true; }
+ virtual void endVisit(IdentifierExpression *) {}
+
+ virtual bool visit(NullExpression *) { return true; }
+ virtual void endVisit(NullExpression *) {}
+
+ virtual bool visit(TrueLiteral *) { return true; }
+ virtual void endVisit(TrueLiteral *) {}
+
+ virtual bool visit(FalseLiteral *) { return true; }
+ virtual void endVisit(FalseLiteral *) {}
+
+ virtual bool visit(StringLiteral *) { return true; }
+ virtual void endVisit(StringLiteral *) {}
+
+ virtual bool visit(NumericLiteral *) { return true; }
+ virtual void endVisit(NumericLiteral *) {}
+
+ virtual bool visit(RegExpLiteral *) { return true; }
+ virtual void endVisit(RegExpLiteral *) {}
+
+ virtual bool visit(ArrayLiteral *) { return true; }
+ virtual void endVisit(ArrayLiteral *) {}
+
+ virtual bool visit(ObjectLiteral *) { return true; }
+ virtual void endVisit(ObjectLiteral *) {}
+
+ virtual bool visit(ElementList *) { return true; }
+ virtual void endVisit(ElementList *) {}
+
+ virtual bool visit(Elision *) { return true; }
+ virtual void endVisit(Elision *) {}
+
+ virtual bool visit(PropertyNameAndValueList *) { return true; }
+ virtual void endVisit(PropertyNameAndValueList *) {}
+
+ virtual bool visit(NestedExpression *) { return true; }
+ virtual void endVisit(NestedExpression *) {}
+
+ virtual bool visit(IdentifierPropertyName *) { return true; }
+ virtual void endVisit(IdentifierPropertyName *) {}
+
+ virtual bool visit(StringLiteralPropertyName *) { return true; }
+ virtual void endVisit(StringLiteralPropertyName *) {}
+
+ virtual bool visit(NumericLiteralPropertyName *) { return true; }
+ virtual void endVisit(NumericLiteralPropertyName *) {}
+
+ virtual bool visit(ArrayMemberExpression *) { return true; }
+ virtual void endVisit(ArrayMemberExpression *) {}
+
+ virtual bool visit(FieldMemberExpression *) { return true; }
+ virtual void endVisit(FieldMemberExpression *) {}
+
+ virtual bool visit(NewMemberExpression *) { return true; }
+ virtual void endVisit(NewMemberExpression *) {}
+
+ virtual bool visit(NewExpression *) { return true; }
+ virtual void endVisit(NewExpression *) {}
+
+ virtual bool visit(CallExpression *) { return true; }
+ virtual void endVisit(CallExpression *) {}
+
+ virtual bool visit(ArgumentList *) { return true; }
+ virtual void endVisit(ArgumentList *) {}
+
+ virtual bool visit(PostIncrementExpression *) { return true; }
+ virtual void endVisit(PostIncrementExpression *) {}
+
+ virtual bool visit(PostDecrementExpression *) { return true; }
+ virtual void endVisit(PostDecrementExpression *) {}
+
+ virtual bool visit(DeleteExpression *) { return true; }
+ virtual void endVisit(DeleteExpression *) {}
+
+ virtual bool visit(VoidExpression *) { return true; }
+ virtual void endVisit(VoidExpression *) {}
+
+ virtual bool visit(TypeOfExpression *) { return true; }
+ virtual void endVisit(TypeOfExpression *) {}
+
+ virtual bool visit(PreIncrementExpression *) { return true; }
+ virtual void endVisit(PreIncrementExpression *) {}
+
+ virtual bool visit(PreDecrementExpression *) { return true; }
+ virtual void endVisit(PreDecrementExpression *) {}
+
+ virtual bool visit(UnaryPlusExpression *) { return true; }
+ virtual void endVisit(UnaryPlusExpression *) {}
+
+ virtual bool visit(UnaryMinusExpression *) { return true; }
+ virtual void endVisit(UnaryMinusExpression *) {}
+
+ virtual bool visit(TildeExpression *) { return true; }
+ virtual void endVisit(TildeExpression *) {}
+
+ virtual bool visit(NotExpression *) { return true; }
+ virtual void endVisit(NotExpression *) {}
+
+ virtual bool visit(BinaryExpression *) { return true; }
+ virtual void endVisit(BinaryExpression *) {}
+
+ virtual bool visit(ConditionalExpression *) { return true; }
+ virtual void endVisit(ConditionalExpression *) {}
+
+ virtual bool visit(Expression *) { return true; }
+ virtual void endVisit(Expression *) {}
+
+ virtual bool visit(Block *) { return true; }
+ virtual void endVisit(Block *) {}
+
+ virtual bool visit(StatementList *) { return true; }
+ virtual void endVisit(StatementList *) {}
+
+ virtual bool visit(VariableStatement *) { return true; }
+ virtual void endVisit(VariableStatement *) {}
+
+ virtual bool visit(VariableDeclarationList *) { return true; }
+ virtual void endVisit(VariableDeclarationList *) {}
+
+ virtual bool visit(VariableDeclaration *) { return true; }
+ virtual void endVisit(VariableDeclaration *) {}
+
+ virtual bool visit(EmptyStatement *) { return true; }
+ virtual void endVisit(EmptyStatement *) {}
+
+ virtual bool visit(ExpressionStatement *) { return true; }
+ virtual void endVisit(ExpressionStatement *) {}
+
+ virtual bool visit(IfStatement *) { return true; }
+ virtual void endVisit(IfStatement *) {}
+
+ virtual bool visit(DoWhileStatement *) { return true; }
+ virtual void endVisit(DoWhileStatement *) {}
+
+ virtual bool visit(WhileStatement *) { return true; }
+ virtual void endVisit(WhileStatement *) {}
+
+ virtual bool visit(ForStatement *) { return true; }
+ virtual void endVisit(ForStatement *) {}
+
+ virtual bool visit(LocalForStatement *) { return true; }
+ virtual void endVisit(LocalForStatement *) {}
+
+ virtual bool visit(ForEachStatement *) { return true; }
+ virtual void endVisit(ForEachStatement *) {}
+
+ virtual bool visit(LocalForEachStatement *) { return true; }
+ virtual void endVisit(LocalForEachStatement *) {}
+
+ virtual bool visit(ContinueStatement *) { return true; }
+ virtual void endVisit(ContinueStatement *) {}
+
+ virtual bool visit(BreakStatement *) { return true; }
+ virtual void endVisit(BreakStatement *) {}
+
+ virtual bool visit(ReturnStatement *) { return true; }
+ virtual void endVisit(ReturnStatement *) {}
+
+ virtual bool visit(WithStatement *) { return true; }
+ virtual void endVisit(WithStatement *) {}
+
+ virtual bool visit(SwitchStatement *) { return true; }
+ virtual void endVisit(SwitchStatement *) {}
+
+ virtual bool visit(CaseBlock *) { return true; }
+ virtual void endVisit(CaseBlock *) {}
+
+ virtual bool visit(CaseClauses *) { return true; }
+ virtual void endVisit(CaseClauses *) {}
+
+ virtual bool visit(CaseClause *) { return true; }
+ virtual void endVisit(CaseClause *) {}
+
+ virtual bool visit(DefaultClause *) { return true; }
+ virtual void endVisit(DefaultClause *) {}
+
+ virtual bool visit(LabelledStatement *) { return true; }
+ virtual void endVisit(LabelledStatement *) {}
+
+ virtual bool visit(ThrowStatement *) { return true; }
+ virtual void endVisit(ThrowStatement *) {}
+
+ virtual bool visit(TryStatement *) { return true; }
+ virtual void endVisit(TryStatement *) {}
+
+ virtual bool visit(Catch *) { return true; }
+ virtual void endVisit(Catch *) {}
+
+ virtual bool visit(Finally *) { return true; }
+ virtual void endVisit(Finally *) {}
+
+ virtual bool visit(FunctionDeclaration *) { return true; }
+ virtual void endVisit(FunctionDeclaration *) {}
+
+ virtual bool visit(FunctionExpression *) { return true; }
+ virtual void endVisit(FunctionExpression *) {}
+
+ virtual bool visit(FormalParameterList *) { return true; }
+ virtual void endVisit(FormalParameterList *) {}
+
+ virtual bool visit(FunctionBody *) { return true; }
+ virtual void endVisit(FunctionBody *) {}
+
+ virtual bool visit(Program *) { return true; }
+ virtual void endVisit(Program *) {}
+
+ virtual bool visit(SourceElements *) { return true; }
+ virtual void endVisit(SourceElements *) {}
+
+ virtual bool visit(FunctionSourceElement *) { return true; }
+ virtual void endVisit(FunctionSourceElement *) {}
+
+ virtual bool visit(StatementSourceElement *) { return true; }
+ virtual void endVisit(StatementSourceElement *) {}
+
+ virtual bool visit(DebuggerStatement *) { return true; }
+ virtual void endVisit(DebuggerStatement *) {}
+};
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif // QMLJSASTVISITOR_P_H
diff --git a/src/lib/parser/qmljsengine_p.cpp b/src/lib/parser/qmljsengine_p.cpp
new file mode 100644
index 000000000..e5a35ef19
--- /dev/null
+++ b/src/lib/parser/qmljsengine_p.cpp
@@ -0,0 +1,203 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmljsengine_p.h"
+
+#include "qmljsglobal_p.h"
+#include "qmljsnodepool_p.h"
+
+#include <qnumeric.h>
+#include <QHash>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+uint qHash(const QmlJS::NameId &id)
+{ return qHash(id.asString()); }
+
+QString numberToString(double value)
+{ return QString::number(value); }
+
+int Ecma::RegExp::flagFromChar(const QChar &ch)
+{
+ static QHash<QChar, int> flagsHash;
+ if (flagsHash.isEmpty()) {
+ flagsHash[QLatin1Char('g')] = Global;
+ flagsHash[QLatin1Char('i')] = IgnoreCase;
+ flagsHash[QLatin1Char('m')] = Multiline;
+ }
+ QHash<QChar, int>::const_iterator it;
+ it = flagsHash.constFind(ch);
+ if (it == flagsHash.constEnd())
+ return 0;
+ return it.value();
+}
+
+QString Ecma::RegExp::flagsToString(int flags)
+{
+ QString result;
+ if (flags & Global)
+ result += QLatin1Char('g');
+ if (flags & IgnoreCase)
+ result += QLatin1Char('i');
+ if (flags & Multiline)
+ result += QLatin1Char('m');
+ return result;
+}
+
+NodePool::NodePool(const QString &fileName, Engine *engine)
+ : m_fileName(fileName), m_engine(engine)
+{
+ m_engine->setNodePool(this);
+}
+
+NodePool::~NodePool()
+{
+}
+
+Code *NodePool::createCompiledCode(AST::Node *, CompilationUnit &)
+{
+ Q_ASSERT(0);
+ return 0;
+}
+
+static int toDigit(char c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ return 10 + c - 'a';
+ else if ((c >= 'A') && (c <= 'Z'))
+ return 10 + c - 'A';
+ return -1;
+}
+
+double integerFromString(const char *buf, int size, int radix)
+{
+ if (size == 0)
+ return qSNaN();
+
+ double sign = 1.0;
+ int i = 0;
+ if (buf[0] == '+') {
+ ++i;
+ } else if (buf[0] == '-') {
+ sign = -1.0;
+ ++i;
+ }
+
+ if (((size-i) >= 2) && (buf[i] == '0')) {
+ if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
+ && (radix < 34)) {
+ if ((radix != 0) && (radix != 16))
+ return 0;
+ radix = 16;
+ i += 2;
+ } else {
+ if (radix == 0) {
+ radix = 8;
+ ++i;
+ }
+ }
+ } else if (radix == 0) {
+ radix = 10;
+ }
+
+ int j = i;
+ for ( ; i < size; ++i) {
+ int d = toDigit(buf[i]);
+ if ((d == -1) || (d >= radix))
+ break;
+ }
+ double result;
+ if (j == i) {
+ if (!qstrcmp(buf, "Infinity"))
+ result = qInf();
+ else
+ result = qSNaN();
+ } else {
+ result = 0;
+ double multiplier = 1;
+ for (--i ; i >= j; --i, multiplier *= radix)
+ result += toDigit(buf[i]) * multiplier;
+ }
+ result *= sign;
+ return result;
+}
+
+double integerFromString(const QString &str, int radix)
+{
+ QByteArray ba = str.trimmed().toLatin1();
+ return integerFromString(ba.constData(), ba.size(), radix);
+}
+
+
+Engine::Engine()
+ : _lexer(0), _nodePool(0)
+{ }
+
+Engine::~Engine()
+{ }
+
+QSet<NameId> Engine::literals() const
+{ return _literals; }
+
+void Engine::addComment(int pos, int len, int line, int col)
+{ if (len > 0) _comments.append(QmlJS::AST::SourceLocation(pos, len, line, col)); }
+
+QList<QmlJS::AST::SourceLocation> Engine::comments() const
+{ return _comments; }
+
+NameId *Engine::intern(const QChar *u, int s)
+{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); }
+
+QString Engine::toString(NameId *id)
+{ return id->asString(); }
+
+Lexer *Engine::lexer() const
+{ return _lexer; }
+
+void Engine::setLexer(Lexer *lexer)
+{ _lexer = lexer; }
+
+NodePool *Engine::nodePool() const
+{ return _nodePool; }
+
+void Engine::setNodePool(NodePool *nodePool)
+{ _nodePool = nodePool; }
+
+
+
+} // end of namespace QmlJS
+
+QT_QML_END_NAMESPACE
diff --git a/src/lib/parser/qmljsengine_p.h b/src/lib/parser/qmljsengine_p.h
new file mode 100644
index 000000000..1f5ee8877
--- /dev/null
+++ b/src/lib/parser/qmljsengine_p.h
@@ -0,0 +1,158 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSENGINE_P_H
+#define QMLJSENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsglobal_p.h"
+#include "qmljsastfwd_p.h"
+
+#include <QString>
+#include <QSet>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+class QML_PARSER_EXPORT NameId
+{
+ QString _text;
+
+public:
+ NameId(const QChar *u, int s)
+ : _text(u, s)
+ { }
+
+ const QString asString() const
+ { return _text; }
+
+ bool operator == (const NameId &other) const
+ { return _text == other._text; }
+
+ bool operator != (const NameId &other) const
+ { return _text != other._text; }
+
+ bool operator < (const NameId &other) const
+ { return _text < other._text; }
+};
+
+uint qHash(const QmlJS::NameId &id);
+
+} // end of namespace QmlJS
+
+namespace QmlJS {
+
+class Lexer;
+class NodePool;
+
+namespace Ecma {
+
+class QML_PARSER_EXPORT RegExp
+{
+public:
+ enum RegExpFlag {
+ Global = 0x01,
+ IgnoreCase = 0x02,
+ Multiline = 0x04
+ };
+
+public:
+ static int flagFromChar(const QChar &);
+ static QString flagsToString(int flags);
+};
+
+} // end of namespace Ecma
+
+class QML_PARSER_EXPORT DiagnosticMessage
+{
+public:
+ enum Kind { Warning, Error };
+
+ DiagnosticMessage()
+ : kind(Error) {}
+
+ DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
+ : kind(kind), loc(loc), message(message) {}
+
+ bool isWarning() const
+ { return kind == Warning; }
+
+ bool isError() const
+ { return kind == Error; }
+
+ Kind kind;
+ AST::SourceLocation loc;
+ QString message;
+};
+
+class QML_PARSER_EXPORT Engine
+{
+ Lexer *_lexer;
+ NodePool *_nodePool;
+ QSet<NameId> _literals;
+ QList<QmlJS::AST::SourceLocation> _comments;
+
+public:
+ Engine();
+ ~Engine();
+
+ QSet<NameId> literals() const;
+
+ void addComment(int pos, int len, int line, int col);
+ QList<QmlJS::AST::SourceLocation> comments() const;
+
+ NameId *intern(const QChar *u, int s);
+
+ static QString toString(NameId *id);
+
+ Lexer *lexer() const;
+ void setLexer(Lexer *lexer);
+
+ NodePool *nodePool() const;
+ void setNodePool(NodePool *nodePool);
+};
+
+} // end of namespace QmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif // QMLJSENGINE_P_H
diff --git a/src/lib/parser/qmljsglobal_p.h b/src/lib/parser/qmljsglobal_p.h
new file mode 100644
index 000000000..b492a1f5e
--- /dev/null
+++ b/src/lib/parser/qmljsglobal_p.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSGLOBAL_P_H
+#define QMLJSGLOBAL_P_H
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE
+
+# ifdef QMLJS_BUILD_DIR
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# elif QML_BUILD_STATIC_LIB
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif // QMLJS_BUILD_DIR
+
+#else // !QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
+# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
+#endif // QT_CREATOR
+
+#endif // QMLJSGLOBAL_P_H
diff --git a/src/lib/parser/qmljsgrammar.cpp b/src/lib/parser/qmljsgrammar.cpp
new file mode 100644
index 000000000..9a628c3c9
--- /dev/null
+++ b/src/lib/parser/qmljsgrammar.cpp
@@ -0,0 +1,1007 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file was generated by qlalr - DO NOT EDIT!
+#include "qmljsgrammar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+const char *const QmlJSGrammar::spell [] = {
+ "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue",
+ "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
+ "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
+ "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
+ "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
+ "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
+ ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
+ "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
+ "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public",
+ "import", "as", "on", 0, 0, 0, 0, 0, 0, 0,
+ 0};
+
+const short QmlJSGrammar::lhs [] = {
+ 101, 101, 101, 101, 101, 101, 102, 108, 108, 111,
+ 111, 113, 112, 112, 112, 112, 112, 112, 112, 112,
+ 115, 110, 109, 118, 118, 119, 119, 120, 120, 117,
+ 106, 106, 106, 106, 122, 122, 122, 122, 106, 127,
+ 127, 127, 128, 128, 129, 129, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 116, 116, 116, 116, 116, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 121, 134, 134, 134,
+ 134, 133, 133, 136, 136, 138, 138, 138, 138, 138,
+ 138, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 140, 140, 114, 114, 114, 114, 114, 143,
+ 143, 144, 144, 144, 144, 142, 142, 145, 145, 146,
+ 146, 147, 147, 147, 148, 148, 148, 148, 148, 148,
+ 148, 148, 148, 148, 149, 149, 149, 149, 150, 150,
+ 150, 151, 151, 151, 151, 152, 152, 152, 152, 152,
+ 152, 152, 153, 153, 153, 153, 153, 153, 154, 154,
+ 154, 154, 154, 155, 155, 155, 155, 155, 156, 156,
+ 157, 157, 158, 158, 159, 159, 160, 160, 161, 161,
+ 162, 162, 163, 163, 164, 164, 165, 165, 166, 166,
+ 167, 167, 137, 137, 168, 168, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 104, 104,
+ 170, 170, 171, 171, 172, 172, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 123, 184, 184, 183, 183, 131, 131, 185, 185,
+ 186, 186, 188, 188, 187, 189, 192, 190, 190, 193,
+ 191, 191, 124, 125, 125, 126, 126, 173, 173, 173,
+ 173, 173, 173, 173, 174, 174, 174, 174, 175, 175,
+ 175, 175, 176, 176, 177, 179, 194, 194, 197, 197,
+ 195, 195, 198, 196, 178, 178, 178, 180, 180, 181,
+ 181, 181, 199, 200, 182, 182, 130, 141, 204, 204,
+ 201, 201, 202, 202, 205, 107, 206, 206, 105, 105,
+ 203, 203, 135, 135, 207};
+
+const short QmlJSGrammar::rhs [] = {
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 1, 2, 2, 3, 3, 5, 5, 4, 4,
+ 2, 0, 1, 1, 2, 1, 3, 2, 3, 2,
+ 1, 5, 4, 4, 1, 1, 1, 1, 3, 1,
+ 1, 1, 0, 1, 2, 4, 6, 6, 3, 3,
+ 7, 7, 4, 4, 5, 5, 5, 6, 6, 10,
+ 6, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 3, 4, 5, 3, 4, 3, 1, 1, 2, 3,
+ 4, 1, 2, 3, 5, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 4, 3, 5, 1,
+ 2, 4, 4, 4, 3, 0, 1, 1, 3, 1,
+ 1, 1, 2, 2, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 3, 3, 3, 1, 3,
+ 3, 1, 3, 3, 3, 1, 3, 3, 3, 3,
+ 3, 3, 1, 3, 3, 3, 3, 3, 1, 3,
+ 3, 3, 3, 1, 3, 3, 3, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 5,
+ 1, 5, 1, 3, 1, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+ 0, 1, 1, 3, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 2, 0, 1, 3, 3, 1, 1,
+ 1, 3, 1, 3, 2, 2, 2, 0, 1, 2,
+ 0, 1, 1, 2, 2, 7, 5, 7, 7, 5,
+ 9, 10, 7, 8, 2, 2, 3, 3, 2, 2,
+ 3, 3, 3, 3, 5, 5, 3, 5, 1, 2,
+ 0, 1, 4, 3, 3, 3, 3, 3, 3, 3,
+ 3, 4, 5, 2, 2, 2, 8, 8, 1, 3,
+ 0, 1, 0, 1, 1, 1, 1, 2, 1, 1,
+ 0, 1, 0, 1, 2};
+
+const short QmlJSGrammar::action_default [] = {
+ 0, 0, 0, 0, 0, 0, 22, 0, 172, 239,
+ 203, 211, 207, 151, 223, 199, 3, 136, 70, 152,
+ 215, 219, 140, 169, 150, 155, 135, 189, 176, 0,
+ 77, 78, 73, 341, 64, 343, 0, 0, 0, 0,
+ 75, 0, 0, 71, 74, 68, 0, 0, 65, 67,
+ 66, 76, 69, 0, 72, 0, 0, 165, 0, 0,
+ 152, 171, 154, 153, 0, 0, 0, 167, 168, 166,
+ 170, 0, 200, 0, 0, 0, 0, 190, 0, 0,
+ 0, 0, 0, 0, 180, 0, 0, 0, 174, 175,
+ 173, 178, 182, 181, 179, 177, 192, 191, 193, 0,
+ 208, 0, 204, 0, 0, 146, 133, 145, 134, 102,
+ 103, 104, 129, 105, 130, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118, 131, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 132,
+ 0, 0, 144, 240, 147, 0, 148, 0, 149, 143,
+ 0, 236, 229, 227, 234, 235, 233, 232, 238, 231,
+ 230, 228, 237, 224, 0, 212, 0, 0, 216, 0,
+ 0, 220, 0, 0, 146, 138, 0, 137, 0, 142,
+ 156, 0, 342, 331, 332, 0, 329, 0, 330, 0,
+ 333, 247, 254, 253, 261, 249, 0, 250, 334, 0,
+ 340, 251, 252, 257, 255, 337, 335, 339, 258, 0,
+ 269, 0, 0, 0, 0, 341, 64, 0, 343, 65,
+ 241, 283, 66, 0, 0, 0, 270, 0, 0, 259,
+ 260, 0, 248, 256, 284, 285, 328, 338, 0, 299,
+ 300, 301, 302, 0, 295, 296, 297, 298, 325, 326,
+ 0, 0, 0, 0, 0, 288, 289, 245, 243, 205,
+ 213, 209, 225, 201, 246, 0, 152, 217, 221, 194,
+ 183, 0, 0, 202, 0, 0, 0, 0, 195, 0,
+ 0, 0, 0, 0, 187, 185, 188, 186, 184, 197,
+ 196, 198, 0, 210, 0, 206, 0, 244, 152, 0,
+ 226, 241, 242, 0, 241, 0, 0, 291, 0, 0,
+ 0, 293, 0, 214, 0, 0, 218, 0, 0, 222,
+ 281, 0, 273, 282, 276, 0, 280, 0, 241, 274,
+ 0, 241, 0, 0, 292, 0, 0, 0, 294, 342,
+ 331, 0, 0, 333, 0, 327, 0, 317, 0, 0,
+ 0, 287, 0, 286, 0, 344, 0, 101, 263, 266,
+ 0, 102, 269, 105, 130, 107, 108, 73, 112, 113,
+ 64, 114, 117, 71, 74, 65, 241, 66, 76, 120,
+ 69, 122, 72, 124, 125, 270, 127, 128, 132, 0,
+ 94, 0, 0, 96, 100, 98, 85, 97, 99, 0,
+ 95, 84, 264, 262, 140, 141, 146, 0, 139, 0,
+ 316, 0, 303, 304, 0, 315, 0, 0, 0, 306,
+ 311, 309, 312, 0, 0, 310, 311, 0, 307, 0,
+ 308, 265, 314, 0, 265, 313, 0, 318, 319, 0,
+ 265, 320, 321, 0, 0, 322, 0, 0, 0, 323,
+ 324, 158, 157, 0, 0, 0, 290, 0, 0, 0,
+ 305, 278, 271, 0, 279, 275, 0, 277, 267, 0,
+ 268, 272, 88, 0, 0, 92, 79, 0, 81, 90,
+ 0, 82, 91, 93, 83, 89, 80, 0, 86, 162,
+ 160, 164, 161, 159, 163, 6, 336, 4, 2, 62,
+ 87, 0, 0, 65, 67, 66, 31, 5, 0, 63,
+ 0, 42, 41, 40, 0, 0, 55, 0, 56, 35,
+ 36, 37, 38, 59, 0, 42, 0, 0, 0, 0,
+ 0, 51, 0, 52, 0, 0, 26, 0, 0, 60,
+ 27, 0, 30, 28, 24, 0, 29, 25, 0, 53,
+ 0, 54, 140, 0, 57, 61, 0, 0, 0, 0,
+ 58, 0, 49, 43, 50, 44, 0, 0, 0, 0,
+ 46, 0, 47, 48, 45, 0, 0, 140, 265, 0,
+ 0, 39, 102, 269, 105, 130, 107, 108, 73, 112,
+ 113, 64, 114, 117, 71, 74, 65, 241, 66, 76,
+ 120, 69, 122, 72, 124, 125, 270, 127, 128, 132,
+ 0, 32, 33, 0, 34, 8, 0, 10, 0, 9,
+ 0, 1, 21, 12, 0, 13, 0, 14, 0, 19,
+ 20, 0, 15, 16, 0, 17, 18, 11, 23, 7,
+ 345};
+
+const short QmlJSGrammar::goto_default [] = {
+ 7, 621, 207, 196, 205, 507, 495, 620, 639, 615,
+ 619, 617, 622, 22, 618, 18, 506, 545, 535, 542,
+ 537, 523, 191, 195, 197, 201, 526, 566, 565, 200,
+ 232, 26, 474, 473, 356, 355, 9, 354, 357, 107,
+ 17, 145, 24, 13, 144, 19, 25, 57, 23, 8,
+ 28, 27, 269, 15, 263, 10, 259, 12, 261, 11,
+ 260, 20, 267, 21, 268, 14, 262, 258, 299, 411,
+ 264, 265, 202, 193, 192, 204, 233, 203, 208, 229,
+ 230, 194, 360, 359, 231, 463, 462, 321, 322, 465,
+ 324, 464, 323, 419, 423, 426, 422, 421, 441, 442,
+ 185, 199, 181, 184, 198, 206, 0};
+
+const short QmlJSGrammar::action_index [] = {
+ 350, 1271, 2492, 2492, 2395, 999, 52, 93, 137, -101,
+ 104, 72, 66, 177, -101, 285, 80, -101, -101, 641,
+ 71, 130, 167, 178, -101, -101, -101, 431, 321, 1271,
+ -101, -101, -101, 393, -101, 2201, 2007, 1271, 1271, 1271,
+ -101, 811, 1271, -101, -101, -101, 1271, 1271, -101, -101,
+ -101, -101, -101, 1271, -101, 1271, 1271, -101, 1271, 1271,
+ 87, 188, -101, -101, 1271, 1271, 1271, -101, -101, -101,
+ 179, 1271, 263, 1271, 1271, 1271, 1271, 456, 1271, 1271,
+ 1271, 1271, 1271, 1271, 321, 1271, 1271, 1271, 128, 114,
+ 120, 193, 181, 172, 321, 321, 446, 395, 405, 1271,
+ -8, 1271, 76, 2104, 1271, 1271, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ 110, 1271, -101, -101, 68, 38, -101, 1271, -101, -101,
+ 1271, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, 1271, 32, 1271, 1271, 85, 83,
+ 1271, -101, 2104, 1271, 1271, -101, 108, -101, 53, -101,
+ -101, 64, -101, 393, 89, 62, -101, 297, -101, 63,
+ 2492, -101, -101, -101, -101, -101, 154, -101, -101, 47,
+ -101, -101, -101, -101, -101, -101, 2492, -101, -101, 461,
+ -101, 470, 74, 2395, 59, 393, 92, 67, 2686, 152,
+ 1271, -101, 65, 43, 1271, 41, -101, 39, 34, -101,
+ -101, 393, -101, -101, -101, -101, -101, -101, 86, -101,
+ -101, -101, -101, 90, -101, -101, -101, -101, -101, -101,
+ -11, 50, 1271, 103, 82, -101, -101, 1455, -101, 84,
+ 44, 5, -101, 267, 70, 33, 575, 79, 69, 471,
+ 235, 393, 1271, 275, 1271, 1271, 1271, 1271, 305, 1271,
+ 1271, 1271, 1271, 1271, 229, 201, 225, 202, 321, 355,
+ 374, 380, 1271, 35, 1271, 81, 1271, -101, 641, 1271,
+ -101, 1271, 61, 1, 1271, 29, 2395, -101, 1271, 133,
+ 2395, -101, 1271, 73, 1271, 1271, 99, 97, 1271, -101,
+ 51, 153, 60, -101, -101, 1271, -101, 393, 1271, -101,
+ 56, 1271, -25, 2395, -101, 1271, 129, 2395, -101, -35,
+ 309, -56, -31, 2492, -39, -101, 2395, -101, 1271, 245,
+ 2395, -5, 2395, -101, 6, 0, -33, -101, -101, 2395,
+ -43, 543, 7, 488, 112, 1271, 2395, -1, -27, 453,
+ 8, -18, 630, 14, 16, -101, 1365, -101, 12, -19,
+ 3, 1271, 58, -30, 1271, -2, 1271, -29, -36, 1271,
+ -101, 2298, 18, -101, -101, -101, -101, -101, -101, 1271,
+ -101, -101, -101, -101, 223, -101, 1271, -10, -101, 2395,
+ -101, 95, -101, -101, 2395, -101, 1271, 107, 20, -101,
+ 40, -101, 46, 100, 1271, -101, 55, 57, -101, 28,
+ -101, 2395, -101, 118, 2395, -101, 161, -101, -101, 126,
+ 2395, 37, -101, -12, -4, -101, 393, -34, -6, -101,
+ -101, -101, -101, 1271, 98, 2395, -101, 1271, 116, 2395,
+ -101, 19, -101, 186, -101, -101, 1271, -101, -101, 303,
+ -101, -101, -101, 119, 1638, -101, -101, 1821, -101, -101,
+ 1914, -101, -101, -101, -101, -101, -101, 123, -101, -101,
+ -101, -101, -101, -101, -101, -101, 2492, -101, -101, -101,
+ 94, -26, 819, 158, -28, 4, -101, -101, 210, -101,
+ 203, -101, -101, -101, 393, 230, -101, 1545, -101, -101,
+ -101, -101, -101, -101, 234, 2, 393, 232, 17, 393,
+ 163, -101, 10, -101, 908, 125, -101, 13, 908, -101,
+ -101, 1090, -101, -101, -101, 1181, -101, -101, 214, -101,
+ 1545, -101, 262, 9, -101, -101, 180, 318, 30, 1545,
+ -101, 238, -101, 236, -101, 26, -32, 315, 183, 288,
+ -101, 77, -101, -101, -101, 1728, 908, 291, 2589, 2007,
+ -3, -101, 443, 25, 497, 88, 1271, 2395, 24, 11,
+ 384, 36, 27, 702, 48, 49, -101, 1365, -101, 54,
+ 31, 45, 1271, 58, 15, 1271, 42, 1271, 23, 22,
+ 122, -101, -101, 21, -101, -101, 730, -101, 254, -70,
+ 908, -101, -101, 138, 393, -101, 143, -101, 134, -101,
+ -101, 268, -101, -101, 124, -101, -101, -101, -101, -101,
+ -101,
+
+ -107, 25, -75, 27, 30, 272, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -42,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 95,
+ -107, -107, -107, 31, -107, -107, 1, 37, 91, 80,
+ -107, 89, 167, -107, -107, -107, 175, 181, -107, -107,
+ -107, -107, -107, 137, -107, 130, 129, -107, 144, 152,
+ -107, -107, -107, -107, 140, 133, 149, -107, -107, -107,
+ -107, 157, -107, 182, 179, 170, 70, -107, 66, 78,
+ 55, 94, 100, 114, -107, 120, 109, 104, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 172,
+ -107, 128, -107, 122, 58, 34, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, 51, -107, -107, -107, -107, -107, 36, -107, -107,
+ 47, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, 154, -107, 158, -35, -107, -107,
+ 13, -107, 248, 42, 115, -107, -107, -107, -107, -107,
+ -107, -107, -107, 20, -107, -107, -107, 2, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 61, -107, -107, 67,
+ -107, 64, -107, 76, -107, 43, -107, -107, 57, -107,
+ 60, -107, -107, -107, 85, 69, -107, -107, -107, -107,
+ -107, -5, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, 24, -107, -107, -107, -107, 148, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, 9, 186, -107, 196, 221, 220, 212, -107, 102,
+ 98, 96, 116, 118, -107, -107, -107, -107, -107, -107,
+ -107, -107, 230, -107, 199, -107, 193, -107, -107, 211,
+ -107, 132, -107, -107, 126, -107, 14, -107, 5, -107,
+ 10, -107, 208, -107, 189, 202, -107, -107, 209, -107,
+ -107, -107, -107, -107, -107, 200, -107, 103, 121, -107,
+ -107, 168, -107, 50, -107, 54, -107, 62, -107, -107,
+ 88, -107, -107, -21, -107, -107, 184, -107, 63, -107,
+ 65, -107, 74, -107, -107, -107, -107, -107, -107, 92,
+ -107, 35, -107, 45, -107, 171, 75, -107, -107, 56,
+ -107, -107, 166, -107, -107, -107, 90, -107, -107, -107,
+ -107, 39, -107, 32, 159, -107, 178, -107, -107, -3,
+ -107, -17, -107, -107, -107, -107, -107, -107, -107, 3,
+ -107, -107, -107, -107, -107, -107, 68, -107, -107, 79,
+ -107, -107, -107, -107, 16, -107, 11, -107, -107, -107,
+ -107, -107, -8, -107, 59, -107, -41, -107, -107, -107,
+ -107, 99, -107, -107, 160, -107, -107, -107, -107, -107,
+ 93, -7, -107, -107, 77, -107, 40, -107, 46, -107,
+ -107, -107, -107, 53, -107, 83, -107, 72, -107, 71,
+ -107, -107, -107, -107, -107, -107, 48, -107, -107, 81,
+ -107, -107, -107, -107, 38, -107, -107, 173, -107, -107,
+ 33, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 86, -107, -107, -107,
+ -107, -107, 73, -107, -107, -107, -107, -107, -107, -107,
+ 22, -107, -107, -107, -10, -107, -107, 259, -107, -107,
+ -107, -107, -107, -107, -107, -107, -6, -15, -107, -2,
+ -107, -107, -107, -107, 101, -107, -107, -107, 106, -107,
+ -107, 290, -107, -107, -107, 294, -107, -107, -107, -107,
+ 318, -107, -107, -4, -107, -107, -19, -13, -107, 364,
+ -107, -107, -107, -26, -107, -107, -107, -11, -20, -12,
+ -107, -107, -107, -107, -107, 305, 278, -107, 17, 261,
+ 4, -107, 28, -107, 26, -107, 87, 19, -107, -107,
+ 23, -107, -107, 84, -107, -107, -107, 44, -107, -107,
+ -107, -107, 41, -107, 29, 125, -107, 110, -107, -107,
+ -107, -107, -107, 15, -107, -107, 12, -107, -107, 18,
+ 97, -107, -107, -107, 7, -107, -107, -107, -107, -107,
+ -107, 21, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107};
+
+const short QmlJSGrammar::action_info [] = {
+ 457, 340, 343, 440, 342, -126, -110, 453, 391, 257,
+ -121, 352, 403, 389, -129, 346, 345, 416, 348, -99,
+ 616, -118, 401, -100, 446, 399, 448, 440, 571, 440,
+ 541, -110, -129, 561, 568, 333, 466, 559, 556, 527,
+ 510, 529, 541, 346, 534, 424, 541, 257, 440, -126,
+ 408, 424, -121, 420, 541, -118, -100, 444, 457, 453,
+ 424, -99, 304, 348, 431, -123, 251, 416, 325, 141,
+ 457, 101, 414, 164, 440, 453, 147, 71, 296, 416,
+ 99, 312, 272, 430, 294, 272, 252, 164, 141, 306,
+ 170, 335, 292, 640, 301, 257, 190, 187, 149, 346,
+ 183, 312, 236, 348, 318, 71, 141, 0, 0, 172,
+ 427, 141, 0, 179, 294, 141, 141, 331, 141, 314,
+ 99, 292, 189, 315, 141, 434, 141, 477, 173, 62,
+ 538, 141, 443, 538, 0, 249, 248, 141, 573, 572,
+ 63, 141, 616, 256, 255, 101, 444, 242, 241, 249,
+ 248, 247, 246, 172, 58, 428, 413, 412, 455, 409,
+ 58, 327, 141, 254, 177, 59, 142, 418, 58, 141,
+ 532, 59, 173, 249, 248, 478, 459, 58, 611, 59,
+ 166, 539, 172, 488, 167, 636, 635, 525, 59, 337,
+ 64, 64, 103, 310, 469, 630, 629, 85, 0, 86,
+ 64, 173, 0, 174, 633, 632, 85, 0, 86, 511,
+ 87, 104, 511, 105, 328, 235, 234, 575, 85, 87,
+ 86, 550, 438, 437, 533, 531, 85, 85, 86, 86,
+ 0, 87, 511, 513, 631, 65, 65, 517, 172, 87,
+ 87, 66, 66, 541, 512, 65, 0, 470, 468, 172,
+ 85, 66, 86, 141, 85, 513, 86, 173, 513, 406,
+ 85, 511, 86, 87, 0, 511, 512, 87, 173, 512,
+ 406, 0, 0, 87, 563, 551, 549, 172, 513, 0,
+ 0, 73, 74, 0, 0, 274, 275, 0, 0, 512,
+ 0, 518, 516, 274, 275, -87, 173, 34, 174, 564,
+ 562, 626, 576, 73, 74, 350, 172, 513, 75, 76,
+ 0, 513, 276, 277, 0, 627, 625, 34, 512, 0,
+ 276, 277, 512, 0, -87, 173, 34, 174, 279, 280,
+ 75, 76, 34, 0, 48, 50, 49, 281, 34, 0,
+ 282, 0, 283, 0, 34, 624, 85, 34, 86, 0,
+ 0, 0, 0, 0, 48, 50, 49, 0, 0, 87,
+ 45, 0, 0, 48, 50, 49, 0, 0, 0, 48,
+ 50, 49, 0, 0, 0, 48, 50, 49, 279, 280,
+ 45, 48, 50, 49, 48, 50, 49, 281, 0, 45,
+ 282, 0, 283, 0, 0, 45, 0, 279, 280, 0,
+ 0, 45, 0, 279, 280, 0, 281, 45, 0, 282,
+ 45, 283, 281, 34, 0, 282, 0, 283, 78, 79,
+ -341, 0, 34, 0, 0, 0, 80, 81, 78, 79,
+ 82, 0, 83, 0, 0, 0, 80, 81, 0, 0,
+ 82, 0, 83, 6, 5, 4, 1, 3, 2, 0,
+ 48, 50, 49, 0, 78, 79, 0, 0, 0, 48,
+ 50, 49, 80, 81, 0, 0, 82, 0, 83, 78,
+ 79, 0, 34, 0, 0, 0, 45, 80, 81, 78,
+ 79, 82, 34, 83, 0, 45, 0, 80, 81, -341,
+ 34, 82, 0, 83, 279, 280, 0, 0, 0, 34,
+ 0, 0, 0, 281, 240, 239, 282, 0, 283, 48,
+ 50, 49, 0, 0, 0, 0, 0, 34, 0, 48,
+ 50, 49, 240, 239, 0, 0, 34, 48, 50, 49,
+ 0, 245, 244, 0, 0, 45, 48, 50, 49, 0,
+ 0, 0, 0, 0, 0, 45, 0, 0, 0, 245,
+ 244, 0, 0, 45, 48, 50, 49, 0, 245, 244,
+ 0, 0, 45, 48, 50, 49, 0, 0, 0, 0,
+ 0, 0, 34, 0, 0, 0, 0, 0, 151, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 152, 45,
+ 0, 0, 153, 0, 0, 0, 0, 0, 0, 0,
+ 0, 154, 0, 155, 240, 239, 308, 0, 0, 48,
+ 50, 49, 0, 0, 156, 0, 157, 62, 0, 0,
+ 0, 0, 0, 0, 158, 0, 0, 159, 63, 0,
+ 0, 0, 0, 160, 0, 45, 0, 0, 0, 161,
+ 0, 0, 30, 31, 151, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 152, 162, 0, 0, 153, 34,
+ 0, 0, 0, 35, 36, 0, 37, 154, 0, 155,
+ 0, 0, 0, 41, 0, 0, 0, 44, 0, 0,
+ 156, 0, 157, 62, 0, 0, 0, 0, 0, 0,
+ 158, 0, 0, 159, 63, 51, 48, 50, 49, 160,
+ 52, 0, 0, 0, 0, 161, 0, 0, 0, 0,
+ 0, 43, 54, 32, 30, 31, 0, 40, 0, 0,
+ 0, 162, 45, 0, 33, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 35, 36, 0, 37, 0,
+ 0, 0, 30, 31, 0, 41, 0, 0, 0, 44,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 51, 48, 50,
+ 49, 0, 52, 502, 0, 0, 0, 44, 0, 0,
+ 0, 0, 0, 43, 54, 32, 0, 0, 0, 40,
+ 0, 0, 0, 0, 45, 51, 48, 50, 49, 0,
+ 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 30, 31, 0, 0, 0, 0, 0,
+ 0, 30, 31, 33, 0, 0, 0, 0, 0, 0,
+ 34, 33, 0, 0, 35, 36, 0, 37, 34, 0,
+ 0, 0, 35, 36, 41, 37, 0, 0, 44, 0,
+ 0, 0, 502, 0, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 0, 51, 48, 50, 49, 0, 52,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 43, 54, 32, 45, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 0, 0, 0, 0, 0,
+ 0, 502, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 501,
+ 0, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 215, 0, 0, 0, 0, 0, 0, 34, 0,
+ 0, 0, 35, 36, 0, 37, 0, 0, 0, 0,
+ 0, 0, 502, 0, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 51, 503, 505, 504, 0, 52,
+ 0, 0, 0, 0, 226, 0, 0, 0, 0, 0,
+ 43, 54, 32, 210, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 501, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 215, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 0, 0, 0, 502, 0, 0, 0, 44, 0, 0,
+ 0, 0, 0, 0, 0, 543, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 503, 505, 504, 0,
+ 52, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 43, 54, 32, 210, 0, 0, 40, 0, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 501, 0, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 215, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 0, 0, 0, 502, 0, 0, 0, 44, 0,
+ 0, 0, 0, 0, 0, 0, 546, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 503, 505, 504,
+ 0, 52, 0, 0, 0, 0, 226, 0, 0, 0,
+ 0, 0, 43, 54, 32, 210, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 53, 0, 55, 0, 56, 0, 0,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, -119, 0, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 271, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 217, 0, 0, 218, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 0, 0, 221, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 483, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 486, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 53, 0, 55, 0, 56, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 217, 0,
+ 0, 578, 579, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 0, 0, 0, 0, 0, 221,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 53, 0, 55, 0, 56, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 475,
+ 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 481, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 53, 0, 55, 0, 56, 0, 0,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 483, 0, 0, 29, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
+ 0, 0, 0, 34, 0, 0, 0, 35, 36, 0,
+ 37, 0, 0, 0, 38, 0, 39, 41, 42, 0,
+ 0, 44, 0, 0, 0, 46, 0, 47, 0, 0,
+ 484, 0, 0, 0, 0, 0, 0, 0, 0, 51,
+ 48, 50, 49, 0, 52, 0, 53, 0, 55, 0,
+ 56, 0, 0, 0, 0, 43, 54, 32, 0, 0,
+ 0, 40, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 475, 0, 0, 29, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 34, 0, 0, 0,
+ 35, 36, 0, 37, 0, 0, 0, 38, 0, 39,
+ 41, 42, 0, 0, 44, 0, 0, 0, 46, 0,
+ 47, 0, 0, 476, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 48, 50, 49, 0, 52, 0, 53,
+ 0, 55, 0, 56, 0, 0, 0, 0, 43, 54,
+ 32, 0, 0, 0, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 109, 110,
+ 111, 0, 0, 113, 115, 116, 0, 0, 117, 0,
+ 118, 0, 0, 0, 120, 121, 122, 0, 0, 0,
+ 0, 0, 0, 34, 123, 124, 125, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 126, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 129, 0, 0, 0, 0, 0, 0,
+ 48, 50, 49, 130, 131, 132, 0, 134, 135, 136,
+ 137, 138, 139, 0, 0, 127, 133, 119, 112, 114,
+ 128, 0, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 109, 110, 111, 0, 0,
+ 113, 115, 116, 0, 0, 117, 0, 118, 0, 0,
+ 0, 120, 121, 122, 0, 0, 0, 0, 0, 0,
+ 393, 123, 124, 125, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 126, 0, 0, 0, 394, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 129, 0, 0, 0, 0, 0, 398, 395, 397, 0,
+ 130, 131, 132, 0, 134, 135, 136, 137, 138, 139,
+ 0, 0, 127, 133, 119, 112, 114, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 109, 110, 111, 0, 0, 113, 115, 116,
+ 0, 0, 117, 0, 118, 0, 0, 0, 120, 121,
+ 122, 0, 0, 0, 0, 0, 0, 393, 123, 124,
+ 125, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 126, 0, 0, 0, 394, 0, 0, 0, 0,
+ 0, 0, 0, 396, 0, 0, 0, 129, 0, 0,
+ 0, 0, 0, 398, 395, 397, 0, 130, 131, 132,
+ 0, 134, 135, 136, 137, 138, 139, 0, 0, 127,
+ 133, 119, 112, 114, 128, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 209,
+ 0, 0, 0, 0, 211, 0, 29, 30, 31, 213,
+ 0, 0, 0, 0, 0, 0, 214, 33, 0, 0,
+ 0, 0, 0, 0, 216, 217, 0, 0, 218, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 220, 0, 221, 0, 0, 0,
+ 51, 219, 222, 49, 223, 52, 224, 53, 225, 55,
+ 226, 56, 227, 228, 0, 0, 43, 54, 32, 210,
+ 212, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 209, 0, 0, 0,
+ 0, 211, 0, 29, 30, 31, 213, 0, 0, 0,
+ 0, 0, 0, 214, 215, 0, 0, 0, 0, 0,
+ 0, 216, 217, 0, 0, 218, 36, 0, 37, 0,
+ 0, 0, 38, 0, 39, 41, 42, 0, 0, 44,
+ 0, 0, 0, 46, 0, 47, 0, 0, 0, 0,
+ 0, 220, 0, 221, 0, 0, 0, 51, 219, 222,
+ 49, 223, 52, 224, 53, 225, 55, 226, 56, 227,
+ 228, 0, 0, 43, 54, 32, 210, 212, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 582, 110, 111, 0, 0, 584, 115,
+ 586, 30, 31, 587, 0, 118, 0, 0, 0, 120,
+ 589, 590, 0, 0, 0, 0, 0, 0, 591, 592,
+ 124, 125, 218, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 593, 42, 0, 0, 595, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 597, 0,
+ 221, 0, 0, 0, 599, 596, 598, 49, 600, 601,
+ 602, 53, 604, 605, 606, 607, 608, 609, 0, 0,
+ 594, 603, 588, 583, 585, 128, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 361, 110, 111, 0, 0, 363, 115, 365, 30, 31,
+ 366, 0, 118, 0, 0, 0, 120, 368, 369, 0,
+ 0, 0, 0, 0, 0, 370, 371, 124, 125, 218,
+ 36, 0, 37, 0, 0, 0, 38, 0, 39, 372,
+ 42, 0, 0, 374, 0, 0, 0, 46, 0, 47,
+ 0, -265, 0, 0, 0, 376, 0, 221, 0, 0,
+ 0, 378, 375, 377, 49, 379, 380, 381, 53, 383,
+ 384, 385, 386, 387, 388, 0, 0, 373, 382, 367,
+ 362, 364, 128, 40, 0, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+
+ 567, 169, 558, 570, 574, 515, 569, 557, 309, 548,
+ 461, 528, 311, 530, 417, 555, 307, 188, 415, 358,
+ 392, 250, 628, 612, 320, 623, 150, 253, 16, 637,
+ 496, 497, 498, 390, 614, 186, 634, 472, 182, 400,
+ 487, 243, 436, 238, 436, 176, 182, 302, 514, 171,
+ 238, 439, 334, 429, 439, 447, 454, 336, 339, 358,
+ 243, 140, 433, 302, 338, 237, 349, 351, 449, 482,
+ 146, 182, 148, 460, 485, 458, 353, 250, 250, 243,
+ 344, 410, 238, 163, 467, 456, 524, 143, 436, 425,
+ 237, 439, 445, 302, 402, 358, 461, 404, 0, 450,
+ 60, 358, 404, 186, 146, 92, 0, 0, 0, 407,
+ 500, 60, 0, 638, 500, 60, 84, 536, 320, 500,
+ 0, 98, 540, 60, 302, 60, 405, 490, 91, 302,
+ 0, 405, 60, 0, 180, 302, 60, 106, 489, 60,
+ 60, 60, 180, 60, 93, 60, 286, 60, 285, 60,
+ 94, 146, 284, 90, 60, 60, 178, 452, 89, 60,
+ 108, 60, 358, 60, 95, 60, 287, 471, 288, 88,
+ 60, 302, 451, 60, 60, 60, 452, 451, 60, 404,
+ 68, 432, 60, 102, 494, 60, 347, 67, 341, 60,
+ 330, 329, 61, 266, 60, 305, 69, 60, 270, 60,
+ 70, 303, 60, 60, 60, 480, 451, 0, 405, 479,
+ 72, 0, 60, 165, 491, 60, 60, 60, 180, 168,
+ 60, 97, 492, 60, 60, 452, 60, 60, 493, 100,
+ 96, 60, 0, 77, 60, 0, 270, 332, 298, 270,
+ 273, 60, 435, 270, 60, 298, 270, 298, 278, 270,
+ 270, 316, 270, 60, 298, 295, 298, 60, 270, 270,
+ 297, 270, 270, 106, 291, 60, 60, 326, 313, 317,
+ 270, 270, 290, 289, 552, 60, 319, 536, 300, 610,
+ 270, 519, 520, 521, 522, 500, 108, 175, 293, 0,
+ 0, 500, 508, 0, 0, 544, 0, 472, 613, 547,
+ 0, 499, 509, 500, 0, 0, 0, 500, 0, 0,
+ 508, 0, 0, 0, 508, 0, 0, 0, 577, 499,
+ 509, 0, 0, 499, 509, 580, 581, 519, 520, 521,
+ 522, 552, 0, 0, 0, 0, 0, 0, 553, 554,
+ 519, 520, 521, 522, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 560, 519, 520, 521, 522,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0};
+
+const short QmlJSGrammar::action_check [] = {
+ 36, 36, 33, 33, 60, 7, 7, 36, 8, 36,
+ 7, 16, 55, 7, 7, 7, 55, 36, 36, 7,
+ 90, 7, 55, 7, 36, 7, 60, 33, 60, 33,
+ 33, 7, 7, 29, 8, 60, 17, 7, 66, 37,
+ 66, 24, 33, 7, 34, 5, 33, 36, 33, 7,
+ 60, 5, 7, 33, 33, 7, 7, 20, 36, 36,
+ 5, 7, 61, 36, 7, 7, 77, 36, 17, 8,
+ 36, 79, 7, 2, 33, 36, 8, 1, 8, 36,
+ 48, 2, 1, 55, 79, 1, 36, 2, 8, 60,
+ 7, 31, 48, 0, 61, 36, 33, 8, 60, 7,
+ 36, 2, 55, 36, 7, 1, 8, -1, -1, 15,
+ 10, 8, -1, 60, 79, 8, 8, 61, 8, 50,
+ 48, 48, 60, 54, 8, 7, 8, 8, 34, 42,
+ 8, 8, 6, 8, -1, 61, 62, 8, 61, 62,
+ 53, 8, 90, 61, 62, 79, 20, 61, 62, 61,
+ 62, 61, 62, 15, 40, 55, 61, 62, 60, 7,
+ 40, 8, 8, 60, 56, 51, 56, 60, 40, 8,
+ 7, 51, 34, 61, 62, 56, 60, 40, 56, 51,
+ 50, 56, 15, 60, 54, 61, 62, 29, 51, 60,
+ 12, 12, 15, 60, 8, 61, 62, 25, -1, 27,
+ 12, 34, -1, 36, 61, 62, 25, -1, 27, 29,
+ 38, 34, 29, 36, 61, 61, 62, 7, 25, 38,
+ 27, 7, 61, 62, 61, 62, 25, 25, 27, 27,
+ -1, 38, 29, 75, 91, 57, 57, 7, 15, 38,
+ 38, 63, 63, 33, 86, 57, -1, 61, 62, 15,
+ 25, 63, 27, 8, 25, 75, 27, 34, 75, 36,
+ 25, 29, 27, 38, -1, 29, 86, 38, 34, 86,
+ 36, -1, -1, 38, 36, 61, 62, 15, 75, -1,
+ -1, 18, 19, -1, -1, 18, 19, -1, -1, 86,
+ -1, 61, 62, 18, 19, 33, 34, 29, 36, 61,
+ 62, 47, 92, 18, 19, 60, 15, 75, 45, 46,
+ -1, 75, 45, 46, -1, 61, 62, 29, 86, -1,
+ 45, 46, 86, -1, 33, 34, 29, 36, 23, 24,
+ 45, 46, 29, -1, 66, 67, 68, 32, 29, -1,
+ 35, -1, 37, -1, 29, 91, 25, 29, 27, -1,
+ -1, -1, -1, -1, 66, 67, 68, -1, -1, 38,
+ 92, -1, -1, 66, 67, 68, -1, -1, -1, 66,
+ 67, 68, -1, -1, -1, 66, 67, 68, 23, 24,
+ 92, 66, 67, 68, 66, 67, 68, 32, -1, 92,
+ 35, -1, 37, -1, -1, 92, -1, 23, 24, -1,
+ -1, 92, -1, 23, 24, -1, 32, 92, -1, 35,
+ 92, 37, 32, 29, -1, 35, -1, 37, 23, 24,
+ 36, -1, 29, -1, -1, -1, 31, 32, 23, 24,
+ 35, -1, 37, -1, -1, -1, 31, 32, -1, -1,
+ 35, -1, 37, 93, 94, 95, 96, 97, 98, -1,
+ 66, 67, 68, -1, 23, 24, -1, -1, -1, 66,
+ 67, 68, 31, 32, -1, -1, 35, -1, 37, 23,
+ 24, -1, 29, -1, -1, -1, 92, 31, 32, 23,
+ 24, 35, 29, 37, -1, 92, -1, 31, 32, 36,
+ 29, 35, -1, 37, 23, 24, -1, -1, -1, 29,
+ -1, -1, -1, 32, 61, 62, 35, -1, 37, 66,
+ 67, 68, -1, -1, -1, -1, -1, 29, -1, 66,
+ 67, 68, 61, 62, -1, -1, 29, 66, 67, 68,
+ -1, 61, 62, -1, -1, 92, 66, 67, 68, -1,
+ -1, -1, -1, -1, -1, 92, -1, -1, -1, 61,
+ 62, -1, -1, 92, 66, 67, 68, -1, 61, 62,
+ -1, -1, 92, 66, 67, 68, -1, -1, -1, -1,
+ -1, -1, 29, -1, -1, -1, -1, -1, 3, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, 13, 92,
+ -1, -1, 17, -1, -1, -1, -1, -1, -1, -1,
+ -1, 26, -1, 28, 61, 62, 31, -1, -1, 66,
+ 67, 68, -1, -1, 39, -1, 41, 42, -1, -1,
+ -1, -1, -1, -1, 49, -1, -1, 52, 53, -1,
+ -1, -1, -1, 58, -1, 92, -1, -1, -1, 64,
+ -1, -1, 12, 13, 3, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, 13, 80, -1, -1, 17, 29,
+ -1, -1, -1, 33, 34, -1, 36, 26, -1, 28,
+ -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
+ 39, -1, 41, 42, -1, -1, -1, -1, -1, -1,
+ 49, -1, -1, 52, 53, 65, 66, 67, 68, 58,
+ 70, -1, -1, -1, -1, 64, -1, -1, -1, -1,
+ -1, 81, 82, 83, 12, 13, -1, 87, -1, -1,
+ -1, 80, 92, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 12, 13, -1, 43, -1, -1, -1, 47,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, 65, 66, 67,
+ 68, -1, 70, 43, -1, -1, -1, 47, -1, -1,
+ -1, -1, -1, 81, 82, 83, -1, -1, -1, 87,
+ -1, -1, -1, -1, 92, 65, 66, 67, 68, -1,
+ 70, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 12, 13, -1, -1, -1, -1, -1,
+ -1, 12, 13, 22, -1, -1, -1, -1, -1, -1,
+ 29, 22, -1, -1, 33, 34, -1, 36, 29, -1,
+ -1, -1, 33, 34, 43, 36, -1, -1, 47, -1,
+ -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ 81, 82, 83, 92, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
+ -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 10,
+ -1, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, -1,
+ -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, -1, -1, -1, 75, -1, -1, -1, -1, -1,
+ 81, 82, 83, 84, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, -1, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
+ -1, -1, -1, -1, -1, 55, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, -1, -1, -1, 75, -1, -1, -1, -1,
+ -1, 81, 82, 83, 84, -1, -1, 87, -1, -1,
+ -1, -1, 92, -1, -1, -1, -1, -1, -1, -1,
+ -1, 10, -1, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
+ -1, -1, -1, -1, -1, -1, 55, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, -1, -1, -1, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, 84, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, 72, -1, 74, -1, 76, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, 7, -1, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ 75, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, 61, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 8, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, 56, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, 30, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, 61,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 8,
+ -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, 56, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, 72, -1, 74, -1, 76, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, 8, -1, -1, 11, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
+ -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
+ 56, -1, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
+ 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, 87, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, 8, -1, -1, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, 72,
+ -1, 74, -1, 76, -1, -1, -1, -1, 81, 82,
+ 83, -1, -1, -1, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, 4, 5,
+ 6, -1, -1, 9, 10, 11, -1, -1, 14, -1,
+ 16, -1, -1, -1, 20, 21, 22, -1, -1, -1,
+ -1, -1, -1, 29, 30, 31, 32, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 43, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 59, -1, -1, -1, -1, -1, -1,
+ 66, 67, 68, 69, 70, 71, -1, 73, 74, 75,
+ 76, 77, 78, -1, -1, 81, 82, 83, 84, 85,
+ 86, -1, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, 5, 6, -1, -1,
+ 9, 10, 11, -1, -1, 14, -1, 16, -1, -1,
+ -1, 20, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 59, -1, -1, -1, -1, -1, 65, 66, 67, -1,
+ 69, 70, 71, -1, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, 86, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 4, 5, 6, -1, -1, 9, 10, 11,
+ -1, -1, 14, -1, 16, -1, -1, -1, 20, 21,
+ 22, -1, -1, -1, -1, -1, -1, 29, 30, 31,
+ 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, -1, -1, 55, -1, -1, -1, 59, -1, -1,
+ -1, -1, -1, 65, 66, 67, -1, 69, 70, 71,
+ -1, 73, 74, 75, 76, 77, 78, -1, -1, 81,
+ 82, 83, 84, 85, 86, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ -1, -1, -1, -1, 9, -1, 11, 12, 13, 14,
+ -1, -1, -1, -1, -1, -1, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, 59, -1, 61, -1, -1, -1,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 4, -1, -1, -1,
+ -1, 9, -1, 11, 12, 13, 14, -1, -1, -1,
+ -1, -1, -1, 21, 22, -1, -1, -1, -1, -1,
+ -1, 29, 30, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, 59, -1, 61, -1, -1, -1, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, -1, -1, 81, 82, 83, 84, 85, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, 5, 6, -1, -1, 9, 10,
+ 11, 12, 13, 14, -1, 16, -1, -1, -1, 20,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ 31, 32, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, 59, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, 86, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ 4, 5, 6, -1, -1, 9, 10, 11, 12, 13,
+ 14, -1, 16, -1, -1, -1, 20, 21, 22, -1,
+ -1, -1, -1, -1, -1, 29, 30, 31, 32, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, 55, -1, -1, -1, 59, -1, 61, -1, -1,
+ -1, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, -1, -1, 81, 82, 83,
+ 84, 85, 86, 87, -1, -1, -1, -1, 92, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+
+ 26, 36, 15, 15, 15, 15, 26, 26, 3, 15,
+ 15, 26, 2, 15, 3, 19, 2, 15, 2, 2,
+ 37, 2, 15, 19, 15, 13, 68, 3, 3, 11,
+ 105, 4, 2, 36, 19, 15, 15, 36, 15, 36,
+ 3, 15, 3, 15, 3, 3, 15, 3, 26, 36,
+ 15, 22, 2, 94, 22, 15, 3, 3, 15, 2,
+ 15, 3, 3, 3, 2, 4, 3, 2, 22, 36,
+ 36, 15, 36, 2, 36, 3, 2, 2, 2, 15,
+ 101, 2, 15, 36, 36, 2, 13, 36, 3, 97,
+ 4, 22, 99, 3, 2, 2, 15, 13, -1, 22,
+ 45, 2, 13, 15, 36, 50, -1, -1, -1, 41,
+ 13, 45, -1, 16, 13, 45, 50, 16, 15, 13,
+ -1, 51, 16, 45, 3, 45, 42, 47, 50, 3,
+ -1, 42, 45, -1, 47, 3, 45, 15, 47, 45,
+ 45, 45, 47, 45, 50, 45, 50, 45, 50, 45,
+ 50, 36, 50, 49, 45, 45, 41, 47, 49, 45,
+ 38, 45, 2, 45, 50, 45, 50, 86, 50, 49,
+ 45, 3, 47, 45, 45, 45, 47, 47, 45, 13,
+ 47, 82, 45, 55, 47, 45, 2, 47, 100, 45,
+ 69, 88, 48, 45, 45, 69, 47, 45, 50, 45,
+ 48, 69, 45, 45, 45, 32, 47, -1, 42, 36,
+ 53, -1, 45, 59, 47, 45, 45, 45, 47, 61,
+ 45, 51, 47, 45, 45, 47, 45, 45, 47, 57,
+ 51, 45, -1, 51, 45, -1, 50, 69, 45, 50,
+ 54, 45, 82, 50, 45, 45, 50, 45, 52, 50,
+ 50, 62, 50, 45, 45, 56, 45, 45, 50, 50,
+ 67, 50, 50, 15, 52, 45, 45, 67, 60, 67,
+ 50, 50, 52, 52, 13, 45, 67, 16, 67, 18,
+ 50, 22, 23, 24, 25, 13, 38, 39, 58, -1,
+ -1, 13, 20, -1, -1, 5, -1, 36, 20, 5,
+ -1, 29, 30, 13, -1, -1, -1, 13, -1, -1,
+ 20, -1, -1, -1, 20, -1, -1, -1, 13, 29,
+ 30, -1, -1, 29, 30, 20, 21, 22, 23, 24,
+ 25, 13, -1, -1, -1, -1, -1, -1, 20, 21,
+ 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 21, 22, 23, 24, 25,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1};
+
+QT_END_NAMESPACE
diff --git a/src/lib/parser/qmljsgrammar_p.h b/src/lib/parser/qmljsgrammar_p.h
new file mode 100644
index 000000000..25e266fd5
--- /dev/null
+++ b/src/lib/parser/qmljsgrammar_p.h
@@ -0,0 +1,201 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef QMLJSGRAMMAR_P_H
+#define QMLJSGRAMMAR_P_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlJSGrammar
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ REDUCE_HERE = 100,
+ SHIFT_THERE = 99,
+ T_AND = 1,
+ T_AND_AND = 2,
+ T_AND_EQ = 3,
+ T_AS = 91,
+ T_AUTOMATIC_SEMICOLON = 62,
+ T_BREAK = 4,
+ T_CASE = 5,
+ T_CATCH = 6,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_COMMENT = 88,
+ T_CONST = 84,
+ T_CONTINUE = 9,
+ T_DEBUGGER = 85,
+ T_DEFAULT = 10,
+ T_DELETE = 11,
+ T_DIVIDE_ = 12,
+ T_DIVIDE_EQ = 13,
+ T_DO = 14,
+ T_DOT = 15,
+ T_ELSE = 16,
+ T_EQ = 17,
+ T_EQ_EQ = 18,
+ T_EQ_EQ_EQ = 19,
+ T_FALSE = 83,
+ T_FEED_JS_EXPRESSION = 96,
+ T_FEED_JS_PROGRAM = 98,
+ T_FEED_JS_SOURCE_ELEMENT = 97,
+ T_FEED_JS_STATEMENT = 95,
+ T_FEED_UI_OBJECT_MEMBER = 94,
+ T_FEED_UI_PROGRAM = 93,
+ T_FINALLY = 20,
+ T_FOR = 21,
+ T_FUNCTION = 22,
+ T_GE = 23,
+ T_GT = 24,
+ T_GT_GT = 25,
+ T_GT_GT_EQ = 26,
+ T_GT_GT_GT = 27,
+ T_GT_GT_GT_EQ = 28,
+ T_IDENTIFIER = 29,
+ T_IF = 30,
+ T_IMPORT = 90,
+ T_IN = 31,
+ T_INSTANCEOF = 32,
+ T_LBRACE = 33,
+ T_LBRACKET = 34,
+ T_LE = 35,
+ T_LPAREN = 36,
+ T_LT = 37,
+ T_LT_LT = 38,
+ T_LT_LT_EQ = 39,
+ T_MINUS = 40,
+ T_MINUS_EQ = 41,
+ T_MINUS_MINUS = 42,
+ T_MULTILINE_STRING_LITERAL = 87,
+ T_NEW = 43,
+ T_NOT = 44,
+ T_NOT_EQ = 45,
+ T_NOT_EQ_EQ = 46,
+ T_NULL = 81,
+ T_NUMERIC_LITERAL = 47,
+ T_ON = 92,
+ T_OR = 48,
+ T_OR_EQ = 49,
+ T_OR_OR = 50,
+ T_PLUS = 51,
+ T_PLUS_EQ = 52,
+ T_PLUS_PLUS = 53,
+ T_PROPERTY = 66,
+ T_PUBLIC = 89,
+ T_QUESTION = 54,
+ T_RBRACE = 55,
+ T_RBRACKET = 56,
+ T_READONLY = 68,
+ T_REMAINDER = 57,
+ T_REMAINDER_EQ = 58,
+ T_RESERVED_WORD = 86,
+ T_RETURN = 59,
+ T_RPAREN = 60,
+ T_SEMICOLON = 61,
+ T_SIGNAL = 67,
+ T_STAR = 63,
+ T_STAR_EQ = 64,
+ T_STRING_LITERAL = 65,
+ T_SWITCH = 69,
+ T_THIS = 70,
+ T_THROW = 71,
+ T_TILDE = 72,
+ T_TRUE = 82,
+ T_TRY = 73,
+ T_TYPEOF = 74,
+ T_VAR = 75,
+ T_VOID = 76,
+ T_WHILE = 77,
+ T_WITH = 78,
+ T_XOR = 79,
+ T_XOR_EQ = 80,
+
+ ACCEPT_STATE = 640,
+ RULE_COUNT = 345,
+ STATE_COUNT = 641,
+ TERMINAL_COUNT = 101,
+ NON_TERMINAL_COUNT = 107,
+
+ GOTO_INDEX_OFFSET = 641,
+ GOTO_INFO_OFFSET = 2787,
+ GOTO_CHECK_OFFSET = 2787
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+QT_END_NAMESPACE
+#endif // QMLJSGRAMMAR_P_H
+
diff --git a/src/lib/parser/qmljslexer.cpp b/src/lib/parser/qmljslexer.cpp
new file mode 100644
index 000000000..a6b17c7a4
--- /dev/null
+++ b/src/lib/parser/qmljslexer.cpp
@@ -0,0 +1,1249 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "qmljslexer_p.h"
+
+#include "qmljsglobal_p.h"
+#include "qmljsengine_p.h"
+#include "qmljsgrammar_p.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+QT_END_NAMESPACE
+
+QT_QML_BEGIN_NAMESPACE
+
+#define shiftWindowsLineBreak() \
+ do { \
+ if (((current == '\r') && (next1 == '\n')) \
+ || ((current == '\n') && (next1 == '\r'))) { \
+ shift(1); \
+ } \
+ } \
+ while (0)
+
+namespace QmlJS {
+extern double integerFromString(const char *buf, int size, int radix);
+}
+
+using namespace QmlJS;
+
+Lexer::Lexer(Engine *eng, bool tokenizeComments)
+ : driver(eng),
+ yylineno(0),
+ done(false),
+ size8(128), size16(128),
+ pos8(0), pos16(0),
+ terminator(false),
+ restrKeyword(false),
+ delimited(false),
+ stackToken(-1),
+ state(Start),
+ pos(0),
+ code(0), length(0),
+ yycolumn(0),
+ startpos(0),
+ startlineno(0), startcolumn(0),
+ bol(true),
+ current(0), next1(0), next2(0), next3(0),
+ err(NoError),
+ wantRx(false),
+ check_reserved(true),
+ parenthesesState(IgnoreParentheses),
+ parenthesesCount(0),
+ prohibitAutomaticSemicolon(false),
+ tokenizeComments(tokenizeComments)
+{
+ if (driver) driver->setLexer(this);
+ // allocate space for read buffers
+ buffer8 = new char[size8];
+ buffer16 = new QChar[size16];
+ pattern = 0;
+ flags = 0;
+
+}
+
+Lexer::~Lexer()
+{
+ delete [] buffer8;
+ delete [] buffer16;
+}
+
+void Lexer::setCode(const QString &c, int lineno)
+{
+ errmsg.clear();
+ yylineno = lineno;
+ yycolumn = 1;
+ restrKeyword = false;
+ delimited = false;
+ stackToken = -1;
+ pos = 0;
+ code = c.unicode();
+ length = c.length();
+ bol = true;
+
+ // read first characters
+ current = (length > 0) ? code[0].unicode() : 0;
+ next1 = (length > 1) ? code[1].unicode() : 0;
+ next2 = (length > 2) ? code[2].unicode() : 0;
+ next3 = (length > 3) ? code[3].unicode() : 0;
+}
+
+void Lexer::shift(uint p)
+{
+ while (p--) {
+ ++pos;
+ ++yycolumn;
+ current = next1;
+ next1 = next2;
+ next2 = next3;
+ next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
+ }
+}
+
+void Lexer::setDone(State s)
+{
+ state = s;
+ done = true;
+}
+
+int Lexer::findReservedWord(const QChar *c, int size) const
+{
+ switch (size) {
+ case 2: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o'))
+ return QmlJSGrammar::T_DO;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f'))
+ return QmlJSGrammar::T_IF;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n'))
+ return QmlJSGrammar::T_IN;
+ else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s'))
+ return QmlJSGrammar::T_AS;
+ else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n'))
+ return QmlJSGrammar::T_ON;
+ } break;
+
+ case 3: {
+ if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r'))
+ return QmlJSGrammar::T_FOR;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w'))
+ return QmlJSGrammar::T_NEW;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y'))
+ return QmlJSGrammar::T_TRY;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r'))
+ return QmlJSGrammar::T_VAR;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 4: {
+ if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
+ return QmlJSGrammar::T_CASE;
+ else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
+ return QmlJSGrammar::T_ELSE;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s'))
+ return QmlJSGrammar::T_THIS;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d'))
+ return QmlJSGrammar::T_VOID;
+ else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h'))
+ return QmlJSGrammar::T_WITH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e'))
+ return QmlJSGrammar::T_TRUE;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l'))
+ return QmlJSGrammar::T_NULL;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 5: {
+ if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('k'))
+ return QmlJSGrammar::T_BREAK;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('h'))
+ return QmlJSGrammar::T_CATCH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('w'))
+ return QmlJSGrammar::T_THROW;
+ else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e'))
+ return QmlJSGrammar::T_WHILE;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('t'))
+ return QmlJSGrammar::T_CONST;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('e'))
+ return QmlJSGrammar::T_FALSE;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r')
+ && c[4] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('r'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('l'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('s'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 6: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e'))
+ return QmlJSGrammar::T_DELETE;
+ else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n'))
+ return QmlJSGrammar::T_RETURN;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h'))
+ return QmlJSGrammar::T_SWITCH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f'))
+ return QmlJSGrammar::T_TYPEOF;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QmlJSGrammar::T_IMPORT;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l'))
+ return QmlJSGrammar::T_SIGNAL;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b')
+ && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
+ return QmlJSGrammar::T_PUBLIC;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i')
+ && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 7: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l')
+ && c[6] == QLatin1Char('t'))
+ return QmlJSGrammar::T_DEFAULT;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l')
+ && c[6] == QLatin1Char('y'))
+ return QmlJSGrammar::T_FINALLY;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a')
+ && c[6] == QLatin1Char('n'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d')
+ && c[6] == QLatin1Char('s'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g')
+ && c[6] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t')
+ && c[6] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 8: {
+ if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e'))
+ return QmlJSGrammar::T_CONTINUE;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n'))
+ return QmlJSGrammar::T_FUNCTION;
+ else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u')
+ && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r'))
+ return QmlJSGrammar::T_DEBUGGER;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r')
+ && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y'))
+ return QmlJSGrammar::T_PROPERTY;
+ else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d')
+ && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y'))
+ return QmlJSGrammar::T_READONLY;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a')
+ && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 9: {
+ if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f')
+ && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c')
+ && c[8] == QLatin1Char('e'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n')
+ && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('t'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c')
+ && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e')
+ && c[8] == QLatin1Char('d'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 10: {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e')
+ && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f'))
+ return QmlJSGrammar::T_INSTANCEOF;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 12: {
+ if (check_reserved) {
+ if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r')
+ && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z')
+ && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d'))
+ return QmlJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ } // switch
+
+ return -1;
+}
+
+int Lexer::lex()
+{
+ int token = 0;
+ state = Start;
+ ushort stringType = 0; // either single or double quotes
+ bool multiLineString = false;
+ pos8 = pos16 = 0;
+ done = false;
+ terminator = false;
+
+ // did we push a token on the stack previously ?
+ // (after an automatic semicolon insertion)
+ if (stackToken >= 0) {
+ setDone(Other);
+ token = stackToken;
+ stackToken = -1;
+ }
+
+ bool identifierWithEscapedUnicode = false;
+
+ while (!done) {
+ switch (state) {
+ case Start:
+ if (isWhiteSpace()) {
+ // do nothing
+ } else if (current == '/' && next1 == '/') {
+ recordStartPos();
+ shift(1);
+ state = InSingleLineComment;
+ } else if (current == '/' && next1 == '*') {
+ recordStartPos();
+ shift(1);
+ state = InMultiLineComment;
+ } else if (current == 0) {
+ syncProhibitAutomaticSemicolon();
+ if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
+ // automatic semicolon insertion if program incomplete
+ token = QmlJSGrammar::T_SEMICOLON;
+ stackToken = 0;
+ setDone(Other);
+ } else {
+ setDone(Eof);
+ }
+ } else if (isLineTerminator()) {
+ if (restrKeyword) {
+ // automatic semicolon insertion
+ recordStartPos();
+ token = QmlJSGrammar::T_SEMICOLON;
+ setDone(Other);
+ } else {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ bol = true;
+ terminator = true;
+ syncProhibitAutomaticSemicolon();
+ }
+ } else if (current == '"' || current == '\'') {
+ recordStartPos();
+ state = InString;
+ multiLineString = false;
+ stringType = current;
+ } else if (current == '\\' && next1 == 'u') {
+ identifierWithEscapedUnicode = true;
+ recordStartPos();
+
+ shift(2); // skip the unicode escape prefix `\u'
+
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ state = InIdentifier;
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
+ break;
+ }
+
+ } else if (isIdentLetter(current)) {
+ identifierWithEscapedUnicode = false;
+ recordStartPos();
+ record16(current);
+ state = InIdentifier;
+ } else if (current == '0') {
+ recordStartPos();
+ record8(current);
+ state = InNum0;
+ } else if (isDecimalDigit(current)) {
+ recordStartPos();
+ record8(current);
+ state = InNum;
+ } else if (current == '.' && isDecimalDigit(next1)) {
+ recordStartPos();
+ record8(current);
+ state = InDecimal;
+ } else {
+ recordStartPos();
+ token = matchPunctuator(current, next1, next2, next3);
+ if (token != -1) {
+ if (terminator && !delimited && !prohibitAutomaticSemicolon
+ && (token == QmlJSGrammar::T_PLUS_PLUS
+ || token == QmlJSGrammar::T_MINUS_MINUS)) {
+ // automatic semicolon insertion
+ stackToken = token;
+ token = QmlJSGrammar::T_SEMICOLON;
+ }
+ setDone(Other);
+ }
+ else {
+ setDone(Bad);
+ err = IllegalCharacter;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal character");
+ }
+ }
+ break;
+ case InString:
+ if (current == stringType) {
+ shift(1);
+ setDone(String);
+ } else if (isLineTerminator()) {
+ multiLineString = true;
+ record16(current);
+ } else if (current == 0 || isLineTerminator()) {
+ setDone(Bad);
+ err = UnclosedStringLiteral;
+ errmsg = QCoreApplication::translate("QmlParser", "Unclosed string at end of line");
+ } else if (current == '\\') {
+ state = InEscapeSequence;
+ } else {
+ record16(current);
+ }
+ break;
+ // Escape Sequences inside of strings
+ case InEscapeSequence:
+ if (isOctalDigit(current)) {
+ if (current >= '0' && current <= '3' &&
+ isOctalDigit(next1) && isOctalDigit(next2)) {
+ record16(convertOctal(current, next1, next2));
+ shift(2);
+ state = InString;
+ } else if (isOctalDigit(current) &&
+ isOctalDigit(next1)) {
+ record16(convertOctal('0', current, next1));
+ shift(1);
+ state = InString;
+ } else if (isOctalDigit(current)) {
+ record16(convertOctal('0', '0', current));
+ state = InString;
+ } else {
+ setDone(Bad);
+ err = IllegalEscapeSequence;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal escape sequence");
+ }
+ } else if (current == 'x')
+ state = InHexEscape;
+ else if (current == 'u')
+ state = InUnicodeEscape;
+ else {
+ if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ bol = true;
+ } else {
+ record16(singleEscape(current));
+ }
+ state = InString;
+ }
+ break;
+ case InHexEscape:
+ if (isHexDigit(current) && isHexDigit(next1)) {
+ state = InString;
+ record16(QLatin1Char(convertHex(current, next1)));
+ shift(1);
+ } else if (current == stringType) {
+ record16(QLatin1Char('x'));
+ shift(1);
+ setDone(String);
+ } else {
+ record16(QLatin1Char('x'));
+ record16(current);
+ state = InString;
+ }
+ break;
+ case InUnicodeEscape:
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ state = InString;
+ } else if (current == stringType) {
+ record16(QLatin1Char('u'));
+ shift(1);
+ setDone(String);
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
+ }
+ break;
+ case InSingleLineComment:
+ if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ terminator = true;
+ bol = true;
+ if (restrKeyword) {
+ token = QmlJSGrammar::T_SEMICOLON;
+ setDone(Other);
+ } else
+ state = Start;
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ } else if (current == 0) {
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ setDone(Eof);
+ }
+
+ break;
+ case InMultiLineComment:
+ if (current == 0) {
+ setDone(Bad);
+ err = UnclosedComment;
+ errmsg = QCoreApplication::translate("QmlParser", "Unclosed comment at end of file");
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ } else if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ } else if (current == '*' && next1 == '/') {
+ state = Start;
+ shift(1);
+ if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2);
+ }
+
+ break;
+ case InIdentifier:
+ if (isIdentLetter(current) || isDecimalDigit(current)) {
+ record16(current);
+ break;
+ } else if (current == '\\' && next1 == 'u') {
+ identifierWithEscapedUnicode = true;
+ shift(2); // skip the unicode escape prefix `\u'
+
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ break;
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
+ break;
+ }
+ }
+ setDone(Identifier);
+ break;
+ case InNum0:
+ if (current == 'x' || current == 'X') {
+ record8(current);
+ state = InHex;
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else if (isOctalDigit(current)) {
+ record8(current);
+ state = InOctal;
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InHex:
+ if (isHexDigit(current))
+ record8(current);
+ else
+ setDone(Hex);
+ break;
+ case InOctal:
+ if (isOctalDigit(current)) {
+ record8(current);
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else {
+ setDone(Octal);
+ }
+ break;
+ case InNum:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InDecimal:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InExponentIndicator:
+ if (current == '+' || current == '-') {
+ record8(current);
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InExponent;
+ } else {
+ setDone(Bad);
+ err = IllegalExponentIndicator;
+ errmsg = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number");
+ }
+ break;
+ case InExponent:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else {
+ setDone(Number);
+ }
+ break;
+ default:
+ Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
+ }
+
+ // move on to the next character
+ if (!done)
+ shift(1);
+ if (state != Start && state != InSingleLineComment)
+ bol = false;
+ }
+
+ // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
+ if ((state == Number || state == Octal || state == Hex)
+ && isIdentLetter(current)) {
+ state = Bad;
+ err = IllegalIdentifier;
+ errmsg = QCoreApplication::translate("QmlParser", "Identifier cannot start with numeric literal");
+ }
+
+ // terminate string
+ buffer8[pos8] = '\0';
+
+ double dval = 0;
+ if (state == Number) {
+ dval = qstrtod(buffer8, 0, 0);
+ } else if (state == Hex) { // scan hex numbers
+ dval = integerFromString(buffer8, pos8, 16);
+ state = Number;
+ } else if (state == Octal) { // scan octal number
+ dval = integerFromString(buffer8, pos8, 8);
+ state = Number;
+ }
+
+ restrKeyword = false;
+ delimited = false;
+
+ switch (parenthesesState) {
+ case IgnoreParentheses:
+ break;
+ case CountParentheses:
+ if (token == QmlJSGrammar::T_RPAREN) {
+ --parenthesesCount;
+ if (parenthesesCount == 0)
+ parenthesesState = BalancedParentheses;
+ } else if (token == QmlJSGrammar::T_LPAREN) {
+ ++parenthesesCount;
+ }
+ break;
+ case BalancedParentheses:
+ parenthesesState = IgnoreParentheses;
+ break;
+ }
+
+ switch (state) {
+ case Eof:
+ return 0;
+ case Other:
+ if (token == QmlJSGrammar::T_RBRACE || token == QmlJSGrammar::T_SEMICOLON)
+ delimited = true;
+ return token;
+ case Identifier:
+ token = -1;
+ if (! identifierWithEscapedUnicode)
+ token = findReservedWord(buffer16, pos16);
+
+ if (token < 0) {
+ /* TODO: close leak on parse error. same holds true for String */
+ if (driver)
+ qsyylval.ustr = driver->intern(buffer16, pos16);
+ else
+ qsyylval.ustr = 0;
+ return QmlJSGrammar::T_IDENTIFIER;
+ }
+ if (token == QmlJSGrammar::T_CONTINUE || token == QmlJSGrammar::T_BREAK
+ || token == QmlJSGrammar::T_RETURN || token == QmlJSGrammar::T_THROW) {
+ restrKeyword = true;
+ } else if (token == QmlJSGrammar::T_IF || token == QmlJSGrammar::T_FOR
+ || token == QmlJSGrammar::T_WHILE || token == QmlJSGrammar::T_WITH) {
+ parenthesesState = CountParentheses;
+ parenthesesCount = 0;
+ } else if (token == QmlJSGrammar::T_DO) {
+ parenthesesState = BalancedParentheses;
+ }
+ return token;
+ case String:
+ if (driver)
+ qsyylval.ustr = driver->intern(buffer16, pos16);
+ else
+ qsyylval.ustr = 0;
+ return multiLineString?QmlJSGrammar::T_MULTILINE_STRING_LITERAL:QmlJSGrammar::T_STRING_LITERAL;
+ case Number:
+ qsyylval.dval = dval;
+ return QmlJSGrammar::T_NUMERIC_LITERAL;
+ case Bad:
+ return -1;
+ default:
+ Q_ASSERT(!"unhandled numeration value in switch");
+ return -1;
+ }
+}
+
+bool Lexer::isWhiteSpace() const
+{
+ return (current == ' ' || current == '\t' ||
+ current == 0x0b || current == 0x0c);
+}
+
+bool Lexer::isLineTerminator() const
+{
+ return (current == '\n' || current == '\r');
+}
+
+bool Lexer::isIdentLetter(ushort c)
+{
+ // ASCII-biased, since all reserved words are ASCII, aand hence the
+ // bulk of content to be parsed.
+ if ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || c == '$'
+ || c == '_')
+ return true;
+ if (c < 128)
+ return false;
+ return QChar(c).isLetterOrNumber();
+}
+
+bool Lexer::isDecimalDigit(ushort c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+bool Lexer::isHexDigit(ushort c) const
+{
+ return ((c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F'));
+}
+
+bool Lexer::isOctalDigit(ushort c) const
+{
+ return (c >= '0' && c <= '7');
+}
+
+int Lexer::matchPunctuator(ushort c1, ushort c2,
+ ushort c3, ushort c4)
+{
+ if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
+ shift(4);
+ return QmlJSGrammar::T_GT_GT_GT_EQ;
+ } else if (c1 == '=' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return QmlJSGrammar::T_EQ_EQ_EQ;
+ } else if (c1 == '!' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return QmlJSGrammar::T_NOT_EQ_EQ;
+ } else if (c1 == '>' && c2 == '>' && c3 == '>') {
+ shift(3);
+ return QmlJSGrammar::T_GT_GT_GT;
+ } else if (c1 == '<' && c2 == '<' && c3 == '=') {
+ shift(3);
+ return QmlJSGrammar::T_LT_LT_EQ;
+ } else if (c1 == '>' && c2 == '>' && c3 == '=') {
+ shift(3);
+ return QmlJSGrammar::T_GT_GT_EQ;
+ } else if (c1 == '<' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_LE;
+ } else if (c1 == '>' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_GE;
+ } else if (c1 == '!' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_NOT_EQ;
+ } else if (c1 == '+' && c2 == '+') {
+ shift(2);
+ return QmlJSGrammar::T_PLUS_PLUS;
+ } else if (c1 == '-' && c2 == '-') {
+ shift(2);
+ return QmlJSGrammar::T_MINUS_MINUS;
+ } else if (c1 == '=' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_EQ_EQ;
+ } else if (c1 == '+' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_PLUS_EQ;
+ } else if (c1 == '-' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_MINUS_EQ;
+ } else if (c1 == '*' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_STAR_EQ;
+ } else if (c1 == '/' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_DIVIDE_EQ;
+ } else if (c1 == '&' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_AND_EQ;
+ } else if (c1 == '^' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_XOR_EQ;
+ } else if (c1 == '%' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_REMAINDER_EQ;
+ } else if (c1 == '|' && c2 == '=') {
+ shift(2);
+ return QmlJSGrammar::T_OR_EQ;
+ } else if (c1 == '<' && c2 == '<') {
+ shift(2);
+ return QmlJSGrammar::T_LT_LT;
+ } else if (c1 == '>' && c2 == '>') {
+ shift(2);
+ return QmlJSGrammar::T_GT_GT;
+ } else if (c1 == '&' && c2 == '&') {
+ shift(2);
+ return QmlJSGrammar::T_AND_AND;
+ } else if (c1 == '|' && c2 == '|') {
+ shift(2);
+ return QmlJSGrammar::T_OR_OR;
+ }
+
+ switch(c1) {
+ case '=': shift(1); return QmlJSGrammar::T_EQ;
+ case '>': shift(1); return QmlJSGrammar::T_GT;
+ case '<': shift(1); return QmlJSGrammar::T_LT;
+ case ',': shift(1); return QmlJSGrammar::T_COMMA;
+ case '!': shift(1); return QmlJSGrammar::T_NOT;
+ case '~': shift(1); return QmlJSGrammar::T_TILDE;
+ case '?': shift(1); return QmlJSGrammar::T_QUESTION;
+ case ':': shift(1); return QmlJSGrammar::T_COLON;
+ case '.': shift(1); return QmlJSGrammar::T_DOT;
+ case '+': shift(1); return QmlJSGrammar::T_PLUS;
+ case '-': shift(1); return QmlJSGrammar::T_MINUS;
+ case '*': shift(1); return QmlJSGrammar::T_STAR;
+ case '/': shift(1); return QmlJSGrammar::T_DIVIDE_;
+ case '&': shift(1); return QmlJSGrammar::T_AND;
+ case '|': shift(1); return QmlJSGrammar::T_OR;
+ case '^': shift(1); return QmlJSGrammar::T_XOR;
+ case '%': shift(1); return QmlJSGrammar::T_REMAINDER;
+ case '(': shift(1); return QmlJSGrammar::T_LPAREN;
+ case ')': shift(1); return QmlJSGrammar::T_RPAREN;
+ case '{': shift(1); return QmlJSGrammar::T_LBRACE;
+ case '}': shift(1); return QmlJSGrammar::T_RBRACE;
+ case '[': shift(1); return QmlJSGrammar::T_LBRACKET;
+ case ']': shift(1); return QmlJSGrammar::T_RBRACKET;
+ case ';': shift(1); return QmlJSGrammar::T_SEMICOLON;
+
+ default: return -1;
+ }
+}
+
+ushort Lexer::singleEscape(ushort c) const
+{
+ switch(c) {
+ case 'b':
+ return 0x08;
+ case 't':
+ return 0x09;
+ case 'n':
+ return 0x0A;
+ case 'v':
+ return 0x0B;
+ case 'f':
+ return 0x0C;
+ case 'r':
+ return 0x0D;
+ case '"':
+ return 0x22;
+ case '\'':
+ return 0x27;
+ case '\\':
+ return 0x5C;
+ default:
+ return c;
+ }
+}
+
+ushort Lexer::convertOctal(ushort c1, ushort c2,
+ ushort c3) const
+{
+ return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
+}
+
+unsigned char Lexer::convertHex(ushort c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+unsigned char Lexer::convertHex(ushort c1, ushort c2)
+{
+ return ((convertHex(c1) << 4) + convertHex(c2));
+}
+
+QChar Lexer::convertUnicode(ushort c1, ushort c2,
+ ushort c3, ushort c4)
+{
+ return QChar((convertHex(c3) << 4) + convertHex(c4),
+ (convertHex(c1) << 4) + convertHex(c2));
+}
+
+void Lexer::record8(ushort c)
+{
+ Q_ASSERT(c <= 0xff);
+
+ // enlarge buffer if full
+ if (pos8 >= size8 - 1) {
+ char *tmp = new char[2 * size8];
+ memcpy(tmp, buffer8, size8 * sizeof(char));
+ delete [] buffer8;
+ buffer8 = tmp;
+ size8 *= 2;
+ }
+
+ buffer8[pos8++] = (char) c;
+}
+
+void Lexer::record16(QChar c)
+{
+ // enlarge buffer if full
+ if (pos16 >= size16 - 1) {
+ QChar *tmp = new QChar[2 * size16];
+ memcpy(tmp, buffer16, size16 * sizeof(QChar));
+ delete [] buffer16;
+ buffer16 = tmp;
+ size16 *= 2;
+ }
+
+ buffer16[pos16++] = c;
+}
+
+void Lexer::recordStartPos()
+{
+ startpos = pos;
+ startlineno = yylineno;
+ startcolumn = yycolumn;
+}
+
+bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
+{
+ pos16 = 0;
+ pattern = 0;
+
+ if (prefix == EqualPrefix)
+ record16(QLatin1Char('='));
+
+ while (true) {
+ switch (current) {
+
+ case 0: // eof
+ case '\n': case '\r': // line terminator
+ errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal");
+ return false;
+
+ case '/':
+ shift(1);
+
+ if (driver) // create the pattern
+ pattern = driver->intern(buffer16, pos16);
+
+ // scan the flags
+ pos16 = 0;
+ flags = 0;
+ while (isIdentLetter(current)) {
+ int flag = Ecma::RegExp::flagFromChar(current);
+ if (flag == 0) {
+ errmsg = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(current));
+ return false;
+ }
+ flags |= flag;
+ record16(current);
+ shift(1);
+ }
+ return true;
+
+ case '\\':
+ // regular expression backslash sequence
+ record16(current);
+ shift(1);
+
+ if (! current || isLineTerminator()) {
+ errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ record16(current);
+ shift(1);
+ break;
+
+ case '[':
+ // regular expression class
+ record16(current);
+ shift(1);
+
+ while (current && ! isLineTerminator()) {
+ if (current == ']')
+ break;
+ else if (current == '\\') {
+ // regular expression backslash sequence
+ record16(current);
+ shift(1);
+
+ if (! current || isLineTerminator()) {
+ errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ record16(current);
+ shift(1);
+ } else {
+ record16(current);
+ shift(1);
+ }
+ }
+
+ if (current != ']') {
+ errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression class");
+ return false;
+ }
+
+ record16(current);
+ shift(1); // skip ]
+ break;
+
+ default:
+ record16(current);
+ shift(1);
+ } // switch
+ } // while
+
+ return false;
+}
+
+void Lexer::syncProhibitAutomaticSemicolon()
+{
+ if (parenthesesState == BalancedParentheses) {
+ // we have seen something like "if (foo)", which means we should
+ // never insert an automatic semicolon at this point, since it would
+ // then be expanded into an empty statement (ECMA-262 7.9.1)
+ prohibitAutomaticSemicolon = true;
+ parenthesesState = IgnoreParentheses;
+ } else {
+ prohibitAutomaticSemicolon = false;
+ }
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/lib/parser/qmljslexer_p.h b/src/lib/parser/qmljslexer_p.h
new file mode 100644
index 000000000..8d94c0240
--- /dev/null
+++ b/src/lib/parser/qmljslexer_p.h
@@ -0,0 +1,240 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSLEXER_P_H
+#define QMLJSLEXER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsglobal_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Lexer
+{
+public:
+ Lexer(Engine *eng, bool tokenizeComments = false);
+ ~Lexer();
+
+ void setCode(const QString &c, int lineno);
+ int lex();
+
+ int currentLineNo() const { return yylineno; }
+ int currentColumnNo() const { return yycolumn; }
+
+ int tokenOffset() const { return startpos; }
+ int tokenLength() const { return pos - startpos; }
+
+ int startLineNo() const { return startlineno; }
+ int startColumnNo() const { return startcolumn; }
+
+ int endLineNo() const { return currentLineNo(); }
+ int endColumnNo() const
+ { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; }
+
+ bool prevTerminator() const { return terminator; }
+
+ enum State { Start,
+ Identifier,
+ InIdentifier,
+ InSingleLineComment,
+ InMultiLineComment,
+ InNum,
+ InNum0,
+ InHex,
+ InOctal,
+ InDecimal,
+ InExponentIndicator,
+ InExponent,
+ Hex,
+ Octal,
+ Number,
+ String,
+ Eof,
+ InString,
+ InEscapeSequence,
+ InHexEscape,
+ InUnicodeEscape,
+ Other,
+ Bad };
+
+ enum Error {
+ NoError,
+ IllegalCharacter,
+ UnclosedStringLiteral,
+ IllegalEscapeSequence,
+ IllegalUnicodeEscapeSequence,
+ UnclosedComment,
+ IllegalExponentIndicator,
+ IllegalIdentifier
+ };
+
+ enum ParenthesesState {
+ IgnoreParentheses,
+ CountParentheses,
+ BalancedParentheses
+ };
+
+ enum RegExpBodyPrefix {
+ NoPrefix,
+ EqualPrefix
+ };
+
+ bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
+
+ NameId *pattern;
+ int flags;
+
+ State lexerState() const
+ { return state; }
+
+ QString errorMessage() const
+ { return errmsg; }
+ void setErrorMessage(const QString &err)
+ { errmsg = err; }
+ void setErrorMessage(const char *err)
+ { setErrorMessage(QString::fromLatin1(err)); }
+
+ Error error() const
+ { return err; }
+ void clearError()
+ { err = NoError; }
+
+private:
+ Engine *driver;
+ int yylineno;
+ bool done;
+ char *buffer8;
+ QChar *buffer16;
+ uint size8, size16;
+ uint pos8, pos16;
+ bool terminator;
+ bool restrKeyword;
+ // encountered delimiter like "'" and "}" on last run
+ bool delimited;
+ int stackToken;
+
+ State state;
+ void setDone(State s);
+ uint pos;
+ void shift(uint p);
+ int lookupKeyword(const char *);
+
+ bool isWhiteSpace() const;
+ bool isLineTerminator() const;
+ bool isHexDigit(ushort c) const;
+ bool isOctalDigit(ushort c) const;
+
+ int matchPunctuator(ushort c1, ushort c2,
+ ushort c3, ushort c4);
+ ushort singleEscape(ushort c) const;
+ ushort convertOctal(ushort c1, ushort c2,
+ ushort c3) const;
+public:
+ static unsigned char convertHex(ushort c1);
+ static unsigned char convertHex(ushort c1, ushort c2);
+ static QChar convertUnicode(ushort c1, ushort c2,
+ ushort c3, ushort c4);
+ static bool isIdentLetter(ushort c);
+ static bool isDecimalDigit(ushort c);
+
+ inline int ival() const { return qsyylval.ival; }
+ inline double dval() const { return qsyylval.dval; }
+ inline NameId *ustr() const { return qsyylval.ustr; }
+
+ const QChar *characterBuffer() const { return buffer16; }
+ int characterCount() const { return pos16; }
+
+private:
+ void record8(ushort c);
+ void record16(QChar c);
+ void recordStartPos();
+
+ int findReservedWord(const QChar *buffer, int size) const;
+
+ void syncProhibitAutomaticSemicolon();
+
+ const QChar *code;
+ uint length;
+ int yycolumn;
+ int startpos;
+ int startlineno;
+ int startcolumn;
+ int bol; // begin of line
+
+ union {
+ int ival;
+ double dval;
+ NameId *ustr;
+ } qsyylval;
+
+ // current and following unicode characters
+ ushort current, next1, next2, next3;
+
+ struct keyword {
+ const char *name;
+ int token;
+ };
+
+ QString errmsg;
+ Error err;
+
+ bool wantRx;
+ bool check_reserved;
+
+ ParenthesesState parenthesesState;
+ int parenthesesCount;
+ bool prohibitAutomaticSemicolon;
+ bool tokenizeComments;
+};
+
+} // namespace QmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/lib/parser/qmljsmemorypool_p.h b/src/lib/parser/qmljsmemorypool_p.h
new file mode 100644
index 000000000..458069282
--- /dev/null
+++ b/src/lib/parser/qmljsmemorypool_p.h
@@ -0,0 +1,124 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSMEMORYPOOL_P_H
+#define QMLJSMEMORYPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+
+#include <string.h>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+class QML_PARSER_EXPORT MemoryPool : public QSharedData
+{
+public:
+ enum { maxBlockCount = -1 };
+ enum { defaultBlockSize = 1 << 12 };
+
+ MemoryPool() {
+ m_blockIndex = maxBlockCount;
+ m_currentIndex = 0;
+ m_storage = 0;
+ m_currentBlock = 0;
+ m_currentBlockSize = 0;
+ }
+
+ virtual ~MemoryPool() {
+ for (int index = 0; index < m_blockIndex + 1; ++index)
+ qFree(m_storage[index]);
+
+ qFree(m_storage);
+ }
+
+ char *allocate(int bytes) {
+ bytes += (8 - bytes) & 7; // ensure multiple of 8 bytes (maintain alignment)
+ if (m_currentBlock == 0 || m_currentBlockSize < m_currentIndex + bytes) {
+ ++m_blockIndex;
+ m_currentBlockSize = defaultBlockSize << m_blockIndex;
+
+ m_storage = reinterpret_cast<char**>(qRealloc(m_storage, sizeof(char*) * (1 + m_blockIndex)));
+ m_currentBlock = m_storage[m_blockIndex] = reinterpret_cast<char*>(qMalloc(m_currentBlockSize));
+ ::memset(m_currentBlock, 0, m_currentBlockSize);
+
+ m_currentIndex = (8 - quintptr(m_currentBlock)) & 7; // ensure first chunk is 64-bit aligned
+ Q_ASSERT(m_currentIndex + bytes <= m_currentBlockSize);
+ }
+
+ char *p = reinterpret_cast<char *>
+ (m_currentBlock + m_currentIndex);
+
+ m_currentIndex += bytes;
+
+ return p;
+ }
+
+ int bytesAllocated() const {
+ int bytes = 0;
+ for (int index = 0; index < m_blockIndex; ++index)
+ bytes += (defaultBlockSize << index);
+ bytes += m_currentIndex;
+ return bytes;
+ }
+
+private:
+ int m_blockIndex;
+ int m_currentIndex;
+ char *m_currentBlock;
+ int m_currentBlockSize;
+ char **m_storage;
+
+private:
+ Q_DISABLE_COPY(MemoryPool)
+};
+
+} // namespace QmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/lib/parser/qmljsnodepool_p.h b/src/lib/parser/qmljsnodepool_p.h
new file mode 100644
index 000000000..83144dc32
--- /dev/null
+++ b/src/lib/parser/qmljsnodepool_p.h
@@ -0,0 +1,130 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLJSNODEPOOL_P_H
+#define QMLJSNODEPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmljsglobal_p.h"
+#include "qmljsmemorypool_p.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+namespace AST {
+class Node;
+} // namespace AST
+
+class Code;
+class CompilationUnit;
+class Engine;
+
+template <typename NodeType>
+inline NodeType *makeAstNode(MemoryPool *storage)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType();
+ return node;
+}
+
+template <typename NodeType, typename Arg1>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2, typename Arg3>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3, arg4);
+ return node;
+}
+
+class QML_PARSER_EXPORT NodePool : public MemoryPool
+{
+public:
+ NodePool(const QString &fileName, Engine *engine);
+ virtual ~NodePool();
+
+ Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation);
+
+ inline QString fileName() const { return m_fileName; }
+ inline Engine *engine() const { return m_engine; }
+#ifndef J_SCRIPT_NO_EVENT_NOTIFY
+ inline qint64 id() const { return m_id; }
+#endif
+
+private:
+ QHash<AST::Node*, Code*> m_codeCache;
+ QString m_fileName;
+ Engine *m_engine;
+#ifndef J_SCRIPT_NO_EVENT_NOTIFY
+ qint64 m_id;
+#endif
+
+private:
+ Q_DISABLE_COPY(NodePool)
+};
+
+} // namespace QmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/lib/parser/qmljsparser.cpp b/src/lib/parser/qmljsparser.cpp
new file mode 100644
index 000000000..ca34b527c
--- /dev/null
+++ b/src/lib/parser/qmljsparser.cpp
@@ -0,0 +1,1893 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtGui/QApplication>
+
+#include <string.h>
+
+#include "qmljsengine_p.h"
+#include "qmljslexer_p.h"
+#include "qmljsast_p.h"
+#include "qmljsnodepool_p.h"
+
+
+
+#include "qmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+}
+
+inline static bool automatic(Engine *driver, int token)
+{
+ return token == QmlJSGrammar::T_RBRACE
+ || token == 0
+ || driver->lexer()->prevTerminator();
+}
+
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ qFree(sym_stack);
+ qFree(state_stack);
+ qFree(location_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->startLineNo();
+ loc.startColumn = lexer->startColumnNo();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<NameId *, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->dval();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+
+case 0: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 1: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 2: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 3: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 4: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 5: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 6: {
+ sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+
+case 8: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+
+case 9: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport);
+} break;
+
+case 10: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(),
+ sym(1).UiImportList, sym(2).UiImport);
+} break;
+
+case 13: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+
+case 15: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+
+case 17: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = sym(4).sval;
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+
+case 19: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = sym(3).sval;
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+
+case 20: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+
+case 21: {
+ sym(1).Node = 0;
+} break;
+
+case 22: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 23: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 24: {
+ AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(),
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+
+case 25: {
+ sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 26: {
+ AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(),
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 27: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 28: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 29: {
+ AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+
+case 31: {
+ AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 32: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 33: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+
+case 38:
+{
+ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 39:
+
+case 40: {
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+ break;
+}
+
+case 42: {
+ sym(1).Node = 0;
+} break;
+
+case 43: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+
+case 44: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 45: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 47: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 49: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 51: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 53: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 55: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 56: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 57: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 58: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 59: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval);
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 60: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval);
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 61: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+
+case 62: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+
+case 64: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 65: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 66: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_READONLY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 67: {
+ QString s = QLatin1String(QmlJSGrammar::spell[T_ON]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 68: {
+ AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool());
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 69: {
+ AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 70: {
+ AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool());
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 71: {
+ AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool());
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 72: {
+ AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool());
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 73: {
+ AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 74:
+case 75: {
+ AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 76: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 77: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 78: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 79: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 80: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 81: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 82: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 83: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 84: {
+ AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 85: {
+ AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 86: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+
+case 87: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression);
+} break;
+
+case 88: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression);
+} break;
+
+case 89: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 90: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 91: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool());
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 92: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 93: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 94: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 95: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 96:
+case 97: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 98: {
+ AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 99: {
+ AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 100: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 101:
+
+case 102:
+
+case 103:
+
+case 104:
+
+case 105:
+
+case 106:
+
+case 107:
+
+case 108:
+
+case 109:
+
+case 110:
+
+case 111:
+
+case 112:
+
+case 113:
+
+case 114:
+
+case 115:
+
+case 116:
+
+case 117:
+
+case 118:
+
+case 119:
+
+case 120:
+
+case 121:
+
+case 122:
+
+case 123:
+
+case 124:
+
+case 125:
+
+case 126:
+
+case 127:
+
+case 128:
+
+case 129:
+
+case 130:
+
+case 131:
+{
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+} break;
+
+case 136: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 137: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 138: {
+ AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 140: {
+ AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 141: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 142: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 143: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 144: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 145: {
+ sym(1).Node = 0;
+} break;
+
+case 146: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+
+case 147: {
+ sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression);
+} break;
+
+case 148: {
+ AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 152: {
+ AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 153: {
+ AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 155: {
+ AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 156: {
+ AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 157: {
+ AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 158: {
+ AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 159: {
+ AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 160: {
+ AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 161: {
+ AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 162: {
+ AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 163: {
+ AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 165: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 166: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 167: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 169: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 170: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 172: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 173: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 174: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 176: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 177: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 178: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 179: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 180: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 181: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 183: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 184: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 185: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 186: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 187: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 189: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 190: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 191: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 192: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 194: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 195: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 196: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 197: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 199: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 201: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 203: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 205: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 207: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 209: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 211: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 213: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 215: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 217: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 219: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 221: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 223: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 225: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 226: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+
+case 227: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+
+case 228: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+
+case 229: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+
+case 230: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+
+case 231: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+
+case 232: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+
+case 233: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+
+case 234: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+
+case 235: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+
+case 236: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+
+case 237: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+
+case 239: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 240: {
+ sym(1).Node = 0;
+} break;
+
+case 243: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 244: {
+ sym(1).Node = 0;
+} break;
+
+case 261: {
+ AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 262: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement);
+} break;
+
+case 263: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement);
+} break;
+
+case 264: {
+ sym(1).Node = 0;
+} break;
+
+case 265: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+
+case 267: {
+ AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(),
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 268: {
+ sym(1).ival = T_CONST;
+} break;
+
+case 269: {
+ sym(1).ival = T_VAR;
+} break;
+
+case 270: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+
+case 271: {
+ AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(),
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 272: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+
+case 273: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+
+case 274: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 275: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 276: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 277: {
+ sym(1).Node = 0;
+} break;
+
+case 279: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 280: {
+ sym(1).Node = 0;
+} break;
+
+case 282: {
+ AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool());
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 284: {
+ AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 285: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 286: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 288: {
+ AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 289: {
+ AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 290: {
+ AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 291: {
+ AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(),
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+
+case 292: {
+ AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 293: {
+ AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(),
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 295: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool());
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 297: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval);
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 299: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 301: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval);
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 303: {
+ AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 304: {
+ AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 305: {
+ AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 306: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 307: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 308: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause);
+} break;
+
+case 309: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+
+case 310: {
+ sym(1).Node = 0;
+} break;
+
+case 311: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+
+case 312: {
+ AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 313: {
+ AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+case 314:
+case 315: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 316: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 318: {
+ AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 319: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 320: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 321: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 322: {
+ AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 323: {
+ AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 325: {
+ AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool());
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 326: {
+ AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 327: {
+ AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (sym(2).sval)
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 328: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 329: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 330: {
+ sym(1).Node = 0;
+} break;
+
+case 331: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+
+case 332: {
+ sym(1).Node = 0;
+} break;
+
+case 334: {
+ sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+
+case 335: {
+ sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+
+case 336: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement);
+} break;
+
+case 337: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement);
+} break;
+
+case 338: {
+ sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement);
+} break;
+
+case 339: {
+ sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration);
+} break;
+
+case 340: {
+ sym(1).sval = 0;
+} break;
+
+case 342: {
+ sym(1).Node = 0;
+} break;
+
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->dval();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QmlParser", "Syntax error");
+ else
+ msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/lib/parser/qmljsparser_p.h b/src/lib/parser/qmljsparser_p.h
new file mode 100644
index 000000000..16973a2ad
--- /dev/null
+++ b/src/lib/parser/qmljsparser_p.h
@@ -0,0 +1,237 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build System
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QMLJSPARSER_P_H
+#define QMLJSPARSER_P_H
+
+#include "qmljsglobal_p.h"
+#include "qmljsgrammar_p.h"
+#include "qmljsast_p.h"
+#include "qmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QmlJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Parser: protected QmlJSGrammar
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ NameId *sval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ AST::UiSignature *UiSignature;
+ AST::UiFormalList *UiFormalList;
+ AST::UiFormal *UiFormal;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ };
+
+ double yylval;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QmlJS
+
+
+
+#define J_SCRIPT_REGEXPLITERAL_RULE1 76
+
+#define J_SCRIPT_REGEXPLITERAL_RULE2 77
+
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QMLJSPARSER_P_H
diff --git a/src/lib/qtconcurrent/QtConcurrentTools b/src/lib/qtconcurrent/QtConcurrentTools
new file mode 100644
index 000000000..f6084a528
--- /dev/null
+++ b/src/lib/qtconcurrent/QtConcurrentTools
@@ -0,0 +1,39 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "qtconcurrent/multitask.h"
+#include "qtconcurrent/runextensions.h"
diff --git a/src/lib/qtconcurrent/multitask.h b/src/lib/qtconcurrent/multitask.h
new file mode 100644
index 000000000..1b223a596
--- /dev/null
+++ b/src/lib/qtconcurrent/multitask.h
@@ -0,0 +1,202 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef MULTITASK_H
+#define MULTITASK_H
+
+#include "qtconcurrent_global.h"
+#include "runextensions.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QEventLoop>
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QThreadPool>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+class QTCONCURRENT_EXPORT MultiTaskBase : public QObject, public QRunnable
+{
+ Q_OBJECT
+protected slots:
+ virtual void cancelSelf() = 0;
+ virtual void setFinished() = 0;
+ virtual void setProgressRange(int min, int max) = 0;
+ virtual void setProgressValue(int value) = 0;
+ virtual void setProgressText(QString value) = 0;
+};
+
+template <typename Class, typename R>
+class MultiTask : public MultiTaskBase
+{
+public:
+ MultiTask(void (Class::*fn)(QFutureInterface<R> &), const QList<Class *> &objects)
+ : fn(fn),
+ objects(objects)
+ {
+ maxProgress = 100*objects.size();
+ }
+
+ QFuture<R> future()
+ {
+ futureInterface.reportStarted();
+ return futureInterface.future();
+ }
+
+ void run()
+ {
+ QThreadPool::globalInstance()->releaseThread();
+ futureInterface.setProgressRange(0, maxProgress);
+ foreach (Class *object, objects) {
+ QFutureWatcher<R> *watcher = new QFutureWatcher<R>();
+ watchers.insert(object, watcher);
+ finished.insert(watcher, false);
+ connect(watcher, SIGNAL(finished()), this, SLOT(setFinished()));
+ connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(setProgressRange(int,int)));
+ connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int)));
+ connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(setProgressText(QString)));
+ watcher->setFuture(QtConcurrent::run(fn, object));
+ }
+ selfWatcher = new QFutureWatcher<R>();
+ connect(selfWatcher, SIGNAL(canceled()), this, SLOT(cancelSelf()));
+ selfWatcher->setFuture(futureInterface.future());
+ loop = new QEventLoop;
+ loop->exec();
+ futureInterface.reportFinished();
+ QThreadPool::globalInstance()->reserveThread();
+ qDeleteAll(watchers);
+ delete selfWatcher;
+ delete loop;
+ }
+protected:
+ void cancelSelf()
+ {
+ foreach (QFutureWatcher<R> *watcher, watchers)
+ watcher->future().cancel();
+ }
+
+ void setFinished()
+ {
+ updateProgress();
+ QFutureWatcher<R> *watcher = static_cast<QFutureWatcher<R> *>(sender());
+ if (finished.contains(watcher))
+ finished[watcher] = true;
+ bool allFinished = true;
+ foreach (bool isFinished, finished) {
+ if (!isFinished) {
+ allFinished = false;
+ break;
+ }
+ }
+ if (allFinished)
+ loop->quit();
+ }
+
+ void setProgressRange(int min, int max)
+ {
+ Q_UNUSED(min)
+ Q_UNUSED(max)
+ updateProgress();
+ }
+
+ void setProgressValue(int value)
+ {
+ Q_UNUSED(value)
+ updateProgress();
+ }
+
+ void setProgressText(QString value)
+ {
+ Q_UNUSED(value)
+ updateProgressText();
+ }
+private:
+ void updateProgress()
+ {
+ int progressSum = 0;
+ foreach (QFutureWatcher<R> *watcher, watchers) {
+ if (watcher->progressMinimum() == watcher->progressMaximum()) {
+ if (watcher->future().isFinished() && !watcher->future().isCanceled())
+ progressSum += 100;
+ } else {
+ progressSum += 100*(watcher->progressValue()-watcher->progressMinimum())/(watcher->progressMaximum()-watcher->progressMinimum());
+ }
+ }
+ futureInterface.setProgressValue(progressSum);
+ }
+
+ void updateProgressText()
+ {
+ QString text;
+ foreach (QFutureWatcher<R> *watcher, watchers) {
+ if (!watcher->progressText().isEmpty())
+ text += watcher->progressText() + "\n";
+ }
+ text = text.trimmed();
+ futureInterface.setProgressValueAndText(futureInterface.progressValue(), text);
+ }
+
+ QFutureInterface<R> futureInterface;
+ void (Class::*fn)(QFutureInterface<R> &);
+ QList<Class *> objects;
+
+ QFutureWatcher<R> *selfWatcher;
+ QMap<Class *, QFutureWatcher<R> *> watchers;
+ QMap<QFutureWatcher<R> *, bool> finished;
+ QEventLoop *loop;
+ int maxProgress;
+};
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), const QList<Class *> &objects, int priority = 0)
+{
+ MultiTask<Class, T> *task = new MultiTask<Class, T>(fn, objects);
+ QFuture<T> future = task->future();
+ QThreadPool::globalInstance()->start(task, priority);
+ return future;
+}
+
+} // namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif // MULTITASK_H
diff --git a/src/lib/qtconcurrent/qtconcurrent.pri b/src/lib/qtconcurrent/qtconcurrent.pri
new file mode 100644
index 000000000..5aebdb6af
--- /dev/null
+++ b/src/lib/qtconcurrent/qtconcurrent.pri
@@ -0,0 +1,6 @@
+DEFINES += BUILD_QTCONCURRENT
+
+HEADERS += \
+ $$PWD/qtconcurrent_global.h \
+ $$PWD/multitask.h \
+ $$PWD/runextensions.h
diff --git a/src/lib/qtconcurrent/qtconcurrent_global.h b/src/lib/qtconcurrent/qtconcurrent_global.h
new file mode 100644
index 000000000..1e89819be
--- /dev/null
+++ b/src/lib/qtconcurrent/qtconcurrent_global.h
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QTCONCURRENT_GLOBAL_H
+#define QTCONCURRENT_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(BUILD_QTCONCURRENT)
+# define QTCONCURRENT_EXPORT Q_DECL_EXPORT
+#else
+# define QTCONCURRENT_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QTCONCURRENT_GLOBAL_H
diff --git a/src/lib/qtconcurrent/runextensions.h b/src/lib/qtconcurrent/runextensions.h
new file mode 100644
index 000000000..32bb74c13
--- /dev/null
+++ b/src/lib/qtconcurrent/runextensions.h
@@ -0,0 +1,431 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QTCONCURRENT_RUNEX_H
+#define QTCONCURRENT_RUNEX_H
+
+#include <qrunnable.h>
+#include <qfutureinterface.h>
+#include <qthreadpool.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+template <typename T, typename FunctionPointer>
+class StoredInterfaceFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &))
+ : fn(fn) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+
+};
+template <typename T, typename FunctionPointer, typename Class>
+class StoredInterfaceMemberFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+ : fn(fn), object(object) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+
+};
+
+template <typename T, typename FunctionPointer, typename Arg1>
+class StoredInterfaceFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+ : fn(fn), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1>
+class StoredInterfaceMemberFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, const Arg1 &arg1)
+ : fn(fn), object(object), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2>
+class StoredInterfaceFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2>
+class StoredInterfaceMemberFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceMemberFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceMemberFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceMemberFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+
+template <typename T>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &))
+{
+ return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start();
+}
+template <typename T, typename Arg1>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+{
+ return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start();
+}
+template <typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start();
+}
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start();
+}
+
+template <typename Class, typename T, typename Arg1>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1)
+{
+ return (new StoredInterfaceMemberFunctionCall1<T, void (Class::*)(QFutureInterface<T> &, Arg1), Class, Arg1>(fn, object, arg1))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceMemberFunctionCall2<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceMemberFunctionCall3<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceMemberFunctionCall4<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceMemberFunctionCall5<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start();
+}
+} // namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif // QTCONCURRENT_RUNEX_H
diff --git a/src/lib/tools/codelocation.h b/src/lib/tools/codelocation.h
new file mode 100644
index 000000000..d1ebeff86
--- /dev/null
+++ b/src/lib/tools/codelocation.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef SOURCELOCATION_H
+#define SOURCELOCATION_H
+
+#include <QtCore/QString>
+#include <QtCore/QDataStream>
+
+namespace qbs {
+
+struct CodeLocation
+{
+ CodeLocation()
+ : line(0), column(0)
+ {}
+
+ CodeLocation(const QString &aFileName, int aLine = 0, int aColumn = 0)
+ : fileName(aFileName),
+ line(aLine),
+ column(aColumn)
+ {}
+
+ bool isValid() const
+ {
+ return !fileName.isEmpty();
+ }
+
+ bool operator != (const CodeLocation &rhs) const
+ {
+ return fileName != rhs.fileName || line != rhs.line || column != rhs.column;
+ }
+
+ QString fileName;
+ int line;
+ int column;
+};
+
+} // namespace qbs
+
+inline QDataStream &operator<< (QDataStream &s, const qbs::CodeLocation &o)
+{
+ s << o.fileName;
+ s << o.line;
+ s << o.column;
+ return s;
+}
+
+inline QDataStream &operator>> (QDataStream &s, qbs::CodeLocation &o)
+{
+ s >> o.fileName;
+ s >> o.line;
+ s >> o.column;
+ return s;
+}
+
+#endif // SOURCELOCATION_H
diff --git a/src/lib/tools/coloredoutput.cpp b/src/lib/tools/coloredoutput.cpp
new file mode 100644
index 000000000..8039c21ef
--- /dev/null
+++ b/src/lib/tools/coloredoutput.cpp
@@ -0,0 +1,103 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "coloredoutput.h"
+#include <qglobal.h>
+#ifdef Q_OS_WIN32
+# include <qt_windows.h>
+#endif
+
+#include <cstdarg>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+namespace qbs {
+
+void printfColored(TextColor color, const char *str, va_list vl)
+{
+ fprintfColored(color, stdout, str, vl);
+}
+
+void printfColored(TextColor color, const char *str, ...)
+{
+ va_list vl;
+ va_start(vl, str);
+ printfColored(color, str, vl);
+ va_end(vl);
+}
+
+void fprintfColored(TextColor color, FILE *file, const char *str, va_list vl)
+{
+#if defined(Q_OS_UNIX)
+ if (color != TextColorDefault && isatty(fileno(stdout))) {
+ unsigned char bright = (color & TextColorBright) >> 3;
+ fprintf(file, "\033[%d;%dm", bright, 30 + (color & ~TextColorBright));
+ vfprintf(file, str, vl);
+ fprintf(stdout, "\033[0m");
+ fprintf(stderr, "\033[0m");
+ } else
+#elif defined(Q_OS_WIN32)
+ HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ if (color != TextColorDefault
+ && hStdout != INVALID_HANDLE_VALUE
+ && GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
+ {
+ WORD bgrColor = ((color & 1) << 2) | (color & 2) | ((color & 4) >> 2); // BGR instead of RGB.
+ if (color & TextColorBright)
+ bgrColor += FOREGROUND_INTENSITY;
+ SetConsoleTextAttribute(hStdout, (csbiInfo.wAttributes & 0xf0) | bgrColor);
+ vfprintf(file, str, vl);
+ SetConsoleTextAttribute(hStdout, csbiInfo.wAttributes);
+ } else
+#endif
+ {
+ vfprintf(file, str, vl);
+ }
+}
+
+void fprintfColored(TextColor color, FILE *file, const char *str, ...)
+{
+ va_list vl;
+ va_start(vl, str);
+ fprintfColored(color, file, str, vl);
+ va_end(vl);
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/coloredoutput.h b/src/lib/tools/coloredoutput.h
new file mode 100644
index 000000000..65385aa87
--- /dev/null
+++ b/src/lib/tools/coloredoutput.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef COLOREDOUTPUT_H
+#define COLOREDOUTPUT_H
+
+#include <cstdio>
+
+namespace qbs {
+
+// http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+enum TextColor {
+ TextColorDefault = -1,
+ TextColorBlack = 0,
+ TextColorDarkRed = 1,
+ TextColorDarkGreen = 2,
+ TextColorDarkBlue = 4,
+ TextColorDarkCyan = TextColorDarkGreen | TextColorDarkBlue,
+ TextColorDarkMagenta = TextColorDarkRed | TextColorDarkBlue,
+ TextColorDarkYellow = TextColorDarkRed | TextColorDarkGreen,
+ TextColorGray = 7,
+ TextColorBright = 8,
+ TextColorRed = TextColorDarkRed | TextColorBright,
+ TextColorGreen = TextColorDarkGreen | TextColorBright,
+ TextColorBlue = TextColorDarkBlue | TextColorBright,
+ TextColorCyan = TextColorDarkCyan | TextColorBright,
+ TextColorMagenta = TextColorDarkMagenta | TextColorBright,
+ TextColorYellow = TextColorDarkYellow | TextColorBright,
+ TextColorWhite = TextColorGray | TextColorBright
+};
+
+void printfColored(TextColor color, const char *str, va_list vl);
+void printfColored(TextColor color, const char *str, ...);
+void fprintfColored(TextColor color, FILE *file, const char *str, va_list vl);
+void fprintfColored(TextColor color, FILE *file, const char *str, ...);
+
+} // namespace qbs
+
+#endif // COLOREDOUTPUT_H
diff --git a/src/lib/tools/error.cpp b/src/lib/tools/error.cpp
new file mode 100644
index 000000000..39e5113f4
--- /dev/null
+++ b/src/lib/tools/error.cpp
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "error.h"
+
+#include <QtCore/QDir>
+
+namespace qbs {
+
+QString Error::toString() const
+{
+ QString str;
+ if (!file.isEmpty()) {
+ str = QDir::toNativeSeparators(file);
+ QString lineAndColumn;
+ if (line > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+$"))))
+ lineAndColumn += QLatin1Char(':') + QString::number(line);
+ if (column > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+:[0-9]+$"))))
+ lineAndColumn += QLatin1Char(':') + QString::number(column);
+ str += lineAndColumn;
+ str += QLatin1Char(' ') + description;
+ } else {
+ str = description;
+ }
+ return str;
+}
+
+void Error::clear()
+{
+ description.clear();
+ file.clear();
+ line = 0;
+ column = 0;
+}
+
+}
diff --git a/src/lib/tools/error.h b/src/lib/tools/error.h
new file mode 100644
index 000000000..0a05e1534
--- /dev/null
+++ b/src/lib/tools/error.h
@@ -0,0 +1,90 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QBS_ERR
+#define QBS_ERR
+
+#include "codelocation.h"
+
+namespace qbs {
+
+class Error
+{
+public:
+ Error()
+ : line(0), column(0)
+ {}
+
+ Error(const Error &rhs)
+ : description(rhs.description)
+ , file(rhs.file)
+ , line(rhs.line)
+ , column(rhs.column)
+ {}
+
+ Error(const QString &_description,
+ const QString &_file = QString(),
+ int _line = 0, int _column = 0)
+ : description(_description)
+ , file(_file)
+ , line(_line)
+ , column(_column)
+ {
+ }
+
+ Error(const QString &_description, const CodeLocation &location)
+ : description(_description)
+ , file(location.fileName)
+ , line(location.line)
+ , column(location.column)
+ {
+ }
+
+ QString toString() const;
+ void clear();
+
+ QString description;
+ QString file;
+ int line, column;
+};
+
+} // namespace qbs
+
+#define QBS_TESTLIB_CATCH catch (qbs::Error &e) { \
+ QFAIL(qPrintable(QString(QLatin1String("\n%1\n")).arg(e.toString())));}
+
+#endif
diff --git a/src/lib/tools/fakeconcurrent.h b/src/lib/tools/fakeconcurrent.h
new file mode 100644
index 000000000..8505903aa
--- /dev/null
+++ b/src/lib/tools/fakeconcurrent.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef FAKECONCURRENT_H
+#define FAKECONCURRENT_H
+
+#include <qtconcurrent/runextensions.h>
+
+namespace qbs {
+namespace FakeConcurrent {
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface);
+ return result;
+}
+
+template <typename Class, typename T, typename Arg1>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, const Arg1 &arg1)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface, arg1);
+ return result;
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface, arg1, arg2);
+ return result;
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ return result;
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ return result;
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ QFuture<T> result;
+ QFutureInterface<T> futureInterface;
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ return result;
+}
+
+} // namespace FakeConcurrent
+} // namespace qbs
+
+#endif // FAKECONCURRENT_H
diff --git a/src/lib/tools/fileinfo.cpp b/src/lib/tools/fileinfo.cpp
new file mode 100644
index 000000000..3dba942e0
--- /dev/null
+++ b/src/lib/tools/fileinfo.cpp
@@ -0,0 +1,247 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "fileinfo.h"
+#include <QtCore/QCoreApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QDebug>
+#include <cassert>
+
+
+#ifdef Q_OS_UNIX
+#include <sys/stat.h>
+#endif
+
+namespace qbs {
+
+QString FileInfo::fileName(const QString &fp)
+{
+ int last = fp.lastIndexOf('/');
+ if (last < 0)
+ return fp;
+ return fp.mid(last + 1);
+}
+
+QString FileInfo::baseName(const QString &fp)
+{
+ QString fn = fileName(fp);
+ int dot = fn.indexOf('.');
+ if (dot < 0)
+ return fp;
+ return fn.mid(0, dot);
+}
+
+QString FileInfo::completeBaseName(const QString &fp)
+{
+ QString fn = fileName(fp);
+ int dot = fn.lastIndexOf('.');
+ if (dot < 0)
+ return fp;
+ return fn.mid(0, dot);
+}
+
+QString FileInfo::path(const QString &fp)
+{
+ if (fp.isEmpty())
+ return QString();
+ if (fp.at(fp.size() - 1) == '/')
+ return fp;
+ int last = fp.lastIndexOf('/');
+ if (last < 0)
+ return ".";
+ return QDir::cleanPath(fp.mid(0, last));
+}
+
+bool FileInfo::exists(const QString &fp)
+{
+ return FileInfo(fp).exists();
+}
+
+// from creator/src/shared/proparser/ioutils.cpp
+bool FileInfo::isAbsolute(const QString &path)
+{
+ if (path.startsWith(QLatin1Char('/')))
+ return true;
+#ifdef Q_OS_WIN
+ if (path.startsWith(QLatin1Char('\\')))
+ return true;
+ // Unlike QFileInfo, this won't accept a relative path with a drive letter.
+ // Such paths result in a royal mess anyway ...
+ if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
+ && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\')))
+ return true;
+#endif
+ return false;
+}
+
+QString FileInfo::resolvePath(const QString &base, const QString &rel)
+{
+ if (isAbsolute(rel))
+ return rel;
+ if (rel == QLatin1String("."))
+ return base;
+
+ QString r = base;
+ if (!r.endsWith('/')) {
+ r.append('/');
+ }
+ r.append(rel);
+
+ return r;
+}
+
+bool FileInfo::globMatches(const QString &pattern, const QString &subject)
+{
+ // ### the QRegExp wildcard matcher is slow!
+ //QRegExp rex(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
+ //return rex.exactMatch(subject);
+ return subject.endsWith(pattern.mid(1), Qt::CaseInsensitive);
+}
+
+static QString resolveSymlinks(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ while (fi.isSymLink())
+ fi.setFile(fi.symLinkTarget());
+ return fi.absoluteFilePath();
+}
+
+#if defined(Q_OS_WIN)
+
+#include <qt_windows.h>
+
+#define z(x) reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA*>(const_cast<FileInfo::InternalStatType*>(&x))
+
+template<bool> struct CompileTimeAssert;
+template<> struct CompileTimeAssert<true> {};
+
+FileInfo::FileInfo(const QString &fileName)
+{
+ static CompileTimeAssert<
+ sizeof(FileInfo::InternalStatType) == sizeof(WIN32_FILE_ATTRIBUTE_DATA)
+ > internal_type_has_wrong_size;
+ if (!GetFileAttributesEx(reinterpret_cast<const WCHAR*>(fileName.utf16()),
+ GetFileExInfoStandard, &m_stat))
+ {
+ z(m_stat)->dwFileAttributes = INVALID_FILE_ATTRIBUTES;
+ }
+}
+
+bool FileInfo::exists() const
+{
+ return z(m_stat)->dwFileAttributes != INVALID_FILE_ATTRIBUTES;
+}
+
+FileTime FileInfo::lastModified() const
+{
+ return FileTime(*reinterpret_cast<const FileTime::InternalType*>(
+ &z(m_stat)->ftLastWriteTime));
+}
+
+QString applicationDirPath()
+{
+ static const QString appDirPath = FileInfo::path(resolveSymlinks(QCoreApplication::applicationFilePath()));
+ return appDirPath;
+}
+
+#elif defined(Q_OS_UNIX)
+
+FileInfo::FileInfo(const QString &fileName)
+{
+ if (stat(fileName.toLocal8Bit(), &m_stat) == -1)
+ m_stat.st_mtime = 0;
+}
+
+bool FileInfo::exists() const
+{
+ return m_stat.st_mtime != 0;
+}
+
+FileTime FileInfo::lastModified() const
+{
+ return m_stat.st_mtime;
+}
+
+QString applicationDirPath()
+{
+ return QCoreApplication::applicationDirPath();
+}
+
+#endif
+
+// adapted from qtc/plugins/vcsbase/cleandialog.cpp
+static bool removeFileRecursion(const QFileInfo &f, QString *errorMessage)
+{
+ if (!f.exists())
+ return true;
+ if (f.isDir()) {
+ const QDir dir(f.absoluteFilePath());
+ foreach(const QFileInfo &fi, dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Hidden))
+ removeFileRecursion(fi, errorMessage);
+ QDir parent = f.absoluteDir();
+ if (!parent.rmdir(f.fileName())) {
+ errorMessage->append(FileInfo::tr("The directory %1 could not be deleted.").
+ arg(QDir::toNativeSeparators(f.absoluteFilePath())));
+ return false;
+ }
+ } else if (!QFile::remove(f.absoluteFilePath())) {
+ if (!errorMessage->isEmpty())
+ errorMessage->append(QLatin1Char('\n'));
+ errorMessage->append(FileInfo::tr("The file %1 could not be deleted.").
+ arg(QDir::toNativeSeparators(f.absoluteFilePath())));
+ return false;
+ }
+ return true;
+}
+
+bool removeDirectoryWithContents(const QString &path, QString *errorMessage)
+{
+ QFileInfo f(path);
+ if (f.exists() && !f.isDir()) {
+ *errorMessage = FileInfo::tr("%1 is not a directory.").arg(QDir::toNativeSeparators(path));
+ return false;
+ }
+ return removeFileRecursion(f, errorMessage);
+}
+
+QString qbsRootPath()
+{
+ return QDir::cleanPath(applicationDirPath() + QLatin1String("/../"));
+}
+
+}
diff --git a/src/lib/tools/fileinfo.h b/src/lib/tools/fileinfo.h
new file mode 100644
index 000000000..e345f5f16
--- /dev/null
+++ b/src/lib/tools/fileinfo.h
@@ -0,0 +1,90 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef FILEINFO_H
+#define FILEINFO_H
+
+#include "filetime.h"
+
+#if defined(Q_OS_UNIX)
+#include <sys/stat.h>
+#endif
+
+#include <QtCore/QString>
+#include <QtCore/QCoreApplication> // for Q_DECLARE_TR_FUNCTIONS
+
+namespace qbs {
+
+class FileInfo
+{
+ Q_DECLARE_TR_FUNCTIONS(qbs::FileInfo)
+public:
+ FileInfo(const QString &fileName);
+
+ bool exists() const;
+ FileTime lastModified() const;
+
+ static QString fileName(const QString &fp);
+ static QString baseName(const QString &fp);
+ static QString completeBaseName(const QString &fp);
+ static QString path(const QString &fp);
+ static bool exists(const QString &fp);
+ static bool isAbsolute(const QString &fp);
+ static QString resolvePath(const QString &base, const QString &rel);
+ static bool globMatches(const QString &pattern, const QString &subject);
+
+private:
+#if defined(Q_OS_WIN)
+ struct InternalStatType
+ {
+ quint8 z[36];
+ };
+#elif defined(Q_OS_UNIX)
+ typedef struct stat InternalStatType;
+#else
+# error unknown platform
+#endif
+ InternalStatType m_stat;
+};
+
+QString applicationDirPath();
+QString qbsRootPath();
+bool removeDirectoryWithContents(const QString &path, QString *errorMessage);
+
+}
+
+#endif
diff --git a/src/lib/tools/filetime.h b/src/lib/tools/filetime.h
new file mode 100644
index 000000000..0b49c2e18
--- /dev/null
+++ b/src/lib/tools/filetime.h
@@ -0,0 +1,128 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef FILETIME_H
+#define FILETIME_H
+
+#include <QtCore/QDataStream>
+#include <QtCore/QDebug>
+
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#endif
+
+namespace qbs {
+
+class FileTime
+{
+public:
+#if defined(Q_OS_UNIX)
+ typedef time_t InternalType;
+#elif defined(Q_OS_WIN)
+ typedef quint64 InternalType;
+#else
+# error unknown platform
+#endif
+
+ FileTime();
+ FileTime(const InternalType &ft)
+ : m_fileTime(ft)
+ { }
+
+ bool operator < (const FileTime &rhs) const;
+ bool operator > (const FileTime &rhs) const;
+ bool operator <= (const FileTime &rhs) const;
+ bool operator >= (const FileTime &rhs) const;
+ bool operator == (const FileTime &rhs) const;
+
+ void clear();
+ bool isValid() const;
+ QString toString() const;
+
+ static FileTime currentTime();
+
+ friend class FileInfo;
+ InternalType m_fileTime;
+};
+
+inline bool FileTime::operator > (const FileTime &rhs) const
+{
+ return rhs < *this;
+}
+
+inline bool FileTime::operator <= (const FileTime &rhs) const
+{
+ return operator < (rhs) || operator == (rhs);
+}
+
+inline bool FileTime::operator >= (const FileTime &rhs) const
+{
+ return operator > (rhs) || operator == (rhs);
+}
+
+inline bool FileTime::operator == (const FileTime &rhs) const
+{
+ return m_fileTime == rhs.m_fileTime;
+}
+
+} // namespace qbs
+
+QT_BEGIN_NAMESPACE
+
+inline QDataStream& operator>>(QDataStream &stream, qbs::FileTime &ft)
+{
+ quint64 u;
+ stream >> u;
+ ft.m_fileTime = u;
+ return stream;
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const qbs::FileTime &ft)
+{
+ stream << (quint64)ft.m_fileTime;
+ return stream;
+}
+
+inline QDebug operator<<(QDebug dbg, const qbs::FileTime &t)
+{
+ dbg.nospace() << t.toString();
+ return dbg.space();
+}
+
+QT_END_NAMESPACE
+
+#endif // FILETIME_H
diff --git a/src/lib/tools/filetime_unix.cpp b/src/lib/tools/filetime_unix.cpp
new file mode 100644
index 000000000..2d4560d4b
--- /dev/null
+++ b/src/lib/tools/filetime_unix.cpp
@@ -0,0 +1,78 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "filetime.h"
+
+#include <QtCore/QString>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <time.h>
+
+namespace qbs {
+
+FileTime::FileTime()
+ : m_fileTime(0)
+{
+}
+
+bool FileTime::operator < (const FileTime &rhs) const
+{
+ return m_fileTime < rhs.m_fileTime;
+}
+
+void FileTime::clear()
+{
+ m_fileTime = 0;
+}
+
+bool FileTime::isValid() const
+{
+ return m_fileTime != 0;
+}
+
+FileTime FileTime::currentTime()
+{
+ return time(0);
+}
+
+QString FileTime::toString() const
+{
+ QDateTime dt;
+ dt.setTime_t(m_fileTime);
+ return dt.toString();
+}
+}
diff --git a/src/lib/tools/filetime_win.cpp b/src/lib/tools/filetime_win.cpp
new file mode 100644
index 000000000..8313dbbee
--- /dev/null
+++ b/src/lib/tools/filetime_win.cpp
@@ -0,0 +1,104 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "filetime.h"
+
+#include <QtCore/QString>
+#include <qt_windows.h>
+#ifdef Q_CC_MSVC
+#include <strsafe.h>
+#endif // Q_CC_MSVC
+
+template<bool> struct CompileTimeAssert;
+template<> struct CompileTimeAssert<true> {};
+static CompileTimeAssert<sizeof(qbs::FileTime::InternalType) == sizeof(FILETIME)> internal_type_has_wrong_size;
+
+namespace qbs {
+
+FileTime::FileTime()
+ : m_fileTime(0)
+{
+}
+
+bool FileTime::operator < (const FileTime &rhs) const
+{
+ const FILETIME *const t1 = reinterpret_cast<const FILETIME *>(&m_fileTime);
+ const FILETIME *const t2 = reinterpret_cast<const FILETIME *>(&rhs.m_fileTime);
+ return CompareFileTime(t1, t2) < 0;
+}
+
+void FileTime::clear()
+{
+ m_fileTime = 0;
+}
+
+bool FileTime::isValid() const
+{
+ return m_fileTime != 0;
+}
+
+FileTime FileTime::currentTime()
+{
+ FileTime result;
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime);
+ SystemTimeToFileTime(&st, ft);
+ return result;
+}
+
+QString FileTime::toString() const
+{
+ const FILETIME *const ft = reinterpret_cast<const FILETIME *>(&m_fileTime);
+ SYSTEMTIME stUTC, stLocal;
+ FileTimeToSystemTime(ft, &stUTC);
+ SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
+#ifdef Q_CC_MSVC
+ WCHAR szString[512];
+ HRESULT hr = StringCchPrintf(szString, sizeof(szString) / sizeof(WCHAR),
+ L"%02d.%02d.%d %02d:%02d:%02d",
+ stLocal.wDay, stLocal.wMonth, stLocal.wYear,
+ stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
+ return SUCCEEDED(hr) ? QString::fromUtf16(szString) : QString();
+#else // Q_CC_MSVC
+ const QString result = QString("%1.%2.%3 %4:%5:%6")
+ .arg(stLocal.wDay, 2, 10, QLatin1Char('0')).arg(stLocal.wMonth, 2, 10, QLatin1Char('0')).arg(stLocal.wYear)
+ .arg(stLocal.wHour, 2, 10, QLatin1Char('0')).arg(stLocal.wMinute, 2, 10, QLatin1Char('0')).arg(stLocal.wSecond, 2, 10, QLatin1Char('0'));
+ return result;
+#endif // Q_CC_MSVC
+}
+}
diff --git a/src/lib/tools/logger.cpp b/src/lib/tools/logger.cpp
new file mode 100644
index 000000000..977abf113
--- /dev/null
+++ b/src/lib/tools/logger.cpp
@@ -0,0 +1,325 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#if defined(_MSC_VER) && _MSC_VER > 0
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "logger.h"
+#include "logsink.h"
+
+#include <cstdarg>
+#include <stdio.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QByteArray>
+#include <QtCore/QMutex>
+#include <QtCore/QVariant>
+
+
+namespace qbs {
+
+Logger &Logger::instance()
+{
+ static Logger instance;
+ return instance;
+}
+
+Logger::Logger()
+ : m_logSink(0)
+ , m_level(LoggerInfo)
+{
+}
+
+Logger::~Logger()
+{
+ delete m_logSink;
+}
+
+void Logger::setLogSink(ILogSink *logSink)
+{
+ m_logSink = logSink;
+}
+
+void Logger::sendProcessOutput(const ProcessOutput &processOutput)
+{
+ if (!m_logSink)
+ return;
+
+ m_logSink->processOutput(processOutput);
+}
+
+void Logger::setLevel(int level)
+{
+ m_level = static_cast<LoggerLevel>(qMin(level, int(LoggerMaxLevel)));
+}
+
+void Logger::setLevel(LoggerLevel level)
+{
+ m_level = level;
+}
+
+void Logger::print(LoggerLevel l, const LogMessage &message)
+{
+ if (!m_logSink)
+ return;
+ m_logSink->outputLogMessage(l, message);
+}
+
+LogWriter::LogWriter(LoggerLevel level)
+ : m_level(level)
+{}
+
+LogWriter::LogWriter(const LogWriter &other)
+ : m_level(other.m_level)
+ , m_logMessage(other.m_logMessage)
+{
+ other.m_logMessage.data.clear();
+}
+
+LogWriter::~LogWriter()
+{
+ if (!m_logMessage.data.isEmpty())
+ Logger::instance().print(m_level, m_logMessage);
+}
+
+const LogWriter &LogWriter::operator=(const LogWriter &other)
+{
+ m_level = other.m_level;
+ m_logMessage = other.m_logMessage;
+ other.m_logMessage.data.clear();
+
+ return *this;
+}
+
+void LogWriter::write(const char c)
+{
+ if (Logger::instance().level() >= m_level)
+ m_logMessage.data.append(c);
+}
+
+void LogWriter::write(const char *str)
+{
+ if (Logger::instance().level() >= m_level)
+ m_logMessage.data.append(str);
+}
+
+} // namespace qbs
+
+
+using namespace qbs;
+
+Q_GLOBAL_STATIC(QMutex, logMutex)
+Q_GLOBAL_STATIC(QByteArray, logByteArray)
+
+static void qbsLog_impl(LoggerLevel logLevel, const char *str, va_list vl)
+{
+ Logger &logger = Logger::instance();
+ if (logger.level() < logLevel)
+ return;
+ logMutex()->lock();
+ if (logByteArray()->isEmpty())
+ logByteArray()->resize(1024 * 1024);
+ vsnprintf(logByteArray()->data(), logByteArray()->size(), str, vl);
+ LogMessage msg;
+ msg.data = *logByteArray();
+ logMutex()->unlock();
+ logger.print(logLevel, msg);
+}
+
+void qbsLog(LoggerLevel logLevel, const char *str, ...)
+{
+ va_list vl;
+ va_start(vl, str);
+ qbsLog_impl(logLevel, str, vl);
+ va_end(vl);
+}
+
+#define DEFINE_QBS_LOG_FUNCTION(LogLevel) \
+ void qbs##LogLevel(const char *str, ...) \
+ { \
+ const LoggerLevel level = Logger##LogLevel; \
+ Logger &logger = Logger::instance(); \
+ if (logger.level() >= level) { \
+ va_list vl; \
+ va_start(vl, str); \
+ qbsLog_impl(level, str, vl); \
+ va_end(vl); \
+ } \
+ } \
+
+DEFINE_QBS_LOG_FUNCTION(Fatal)
+DEFINE_QBS_LOG_FUNCTION(Error)
+DEFINE_QBS_LOG_FUNCTION(Warning)
+DEFINE_QBS_LOG_FUNCTION(Info)
+DEFINE_QBS_LOG_FUNCTION(Debug)
+DEFINE_QBS_LOG_FUNCTION(Trace)
+
+LogWriter qbsLog(LoggerLevel level)
+{
+ return LogWriter(level);
+}
+
+LogWriter qbsFatal()
+{
+ return LogWriter(LoggerFatal);
+}
+
+LogWriter qbsError()
+{
+ return LogWriter(LoggerError);
+}
+
+LogWriter qbsWarning()
+{
+ return LogWriter(LoggerWarning);
+}
+
+LogWriter qbsInfo()
+{
+ return LogWriter(LoggerInfo);
+}
+
+LogWriter qbsDebug()
+{
+ return LogWriter(LoggerDebug);
+}
+
+LogWriter qbsTrace()
+{
+ return LogWriter(LoggerTrace);
+}
+
+LogWriter operator<<(LogWriter w, const char *str)
+{
+ w.write(str);
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, const QByteArray &byteArray)
+{
+ w.write(byteArray.data());
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, const QString &str)
+{
+ w.write(qPrintable(str));
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, const QStringList &strList)
+{
+ for (int i = 0; i < strList.size(); ++i) {
+ w << strList.at(i);
+ if (i != strList.size() - 1)
+ w.write(", ");
+ }
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, const QSet<QString> &strSet)
+{
+ bool firstLoop = true;
+ w.write('(');
+ foreach (const QString &str, strSet) {
+ if (firstLoop)
+ firstLoop = false;
+ else
+ w.write(", ");
+ w.write(qPrintable(str));
+ }
+ w.write(')');
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, const QVariant &variant)
+{
+ QString str = variant.typeName() + QLatin1String("(");
+ if (variant.type() == QVariant::List) {
+ bool firstLoop = true;
+ foreach (const QVariant &item, variant.toList()) {
+ str += item.toString();
+ if (firstLoop)
+ firstLoop = false;
+ else
+ str += QLatin1String(", ");
+ }
+ } else {
+ str += variant.toString();
+ }
+ str += QLatin1String(")");
+ w.write(qPrintable(str));
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, int n)
+{
+ return w << QString::number(n);
+}
+
+LogWriter operator<<(LogWriter w, qint64 n)
+{
+ return w << QString::number(n);
+}
+
+LogWriter operator<<(LogWriter w, bool b)
+{
+ return w << (b ? "true" : "false");
+}
+
+LogWriter operator<<(LogWriter w, LogOutputChannel channel)
+{
+ w.setOutputChannel(channel);
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, LogModifier modifier)
+{
+ switch (modifier) {
+ case DontPrintLogLevel:
+ w.setPrintLogLevel(false);
+ break;
+ }
+ return w;
+}
+
+LogWriter operator<<(LogWriter w, TextColor color)
+{
+ w.setTextColor(color);
+ return w;
+}
diff --git a/src/lib/tools/logger.h b/src/lib/tools/logger.h
new file mode 100644
index 000000000..ca482b742
--- /dev/null
+++ b/src/lib/tools/logger.h
@@ -0,0 +1,138 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef LOGGER_H
+#define LOGGER_H
+
+#include <Qbs/globals.h>
+
+#include <Qbs/ilogsink.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QVariant;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class Logger
+{
+public:
+ static Logger &instance();
+
+ void setLevel(int level);
+ void setLevel(LoggerLevel level);
+ LoggerLevel level() const { return m_level; }
+ void print(LoggerLevel l, const LogMessage &message);
+
+ ~Logger();
+
+ void setLogSink(ILogSink *logSink);
+ void sendProcessOutput(const Qbs::ProcessOutput &processOutput);
+
+protected:
+ Logger();
+
+private:
+ ILogSink *m_logSink;
+ LoggerLevel m_level;
+};
+
+class LogWriter
+{
+public:
+ LogWriter(LoggerLevel level);
+
+ // log writer has move semantics and the last instance of
+ // a << chain prints the accumulated data
+ LogWriter(const LogWriter &other);
+ ~LogWriter();
+ const LogWriter &operator=(const LogWriter &other);
+
+ void write(const char c);
+ void write(const char *str);
+ void setOutputChannel(LogOutputChannel channel) { m_logMessage.outputChannel = channel; }
+ void setPrintLogLevel(bool b) { m_logMessage.printLogLevel = b; }
+ void setTextColor(TextColor color) { m_logMessage.textColor = color; }
+ const Qbs::LogMessage &logMessage() const { return m_logMessage; }
+
+private:
+ LoggerLevel m_level;
+ mutable Qbs::LogMessage m_logMessage;
+};
+
+enum LogModifier
+{
+ DontPrintLogLevel
+};
+
+} // namespace qbs
+
+inline bool qbsLogLevel(qbs::LoggerLevel l) { return qbs::Logger::instance().level() >= l; }
+void qbsLog(qbs::LoggerLevel logLevel, const char *str, ...);
+void qbsFatal(const char *str, ...);
+void qbsError(const char *str, ...);
+void qbsWarning(const char *str, ...);
+void qbsInfo(const char *str, ...);
+void qbsDebug(const char *str, ...);
+void qbsTrace(const char *str, ...);
+
+qbs::LogWriter qbsLog(qbs::LoggerLevel level);
+qbs::LogWriter qbsFatal();
+qbs::LogWriter qbsError();
+qbs::LogWriter qbsWarning();
+qbs::LogWriter qbsInfo();
+qbs::LogWriter qbsDebug();
+qbs::LogWriter qbsTrace();
+
+qbs::LogWriter operator<<(qbs::LogWriter w, const char *str);
+qbs::LogWriter operator<<(qbs::LogWriter w, const QByteArray &byteArray);
+qbs::LogWriter operator<<(qbs::LogWriter w, const QString &str);
+qbs::LogWriter operator<<(qbs::LogWriter w, const QStringList &strList);
+qbs::LogWriter operator<<(qbs::LogWriter w, const QSet<QString> &strSet);
+qbs::LogWriter operator<<(qbs::LogWriter w, const QVariant &variant);
+qbs::LogWriter operator<<(qbs::LogWriter w, int n);
+qbs::LogWriter operator<<(qbs::LogWriter w, qint64 n);
+qbs::LogWriter operator<<(qbs::LogWriter w, bool b);
+qbs::LogWriter operator<<(qbs::LogWriter w, qbs::LogOutputChannel);
+qbs::LogWriter operator<<(qbs::LogWriter w, qbs::LogModifier);
+qbs::LogWriter operator<<(qbs::LogWriter w, qbs::TextColor);
+
+#endif // LOGGER_H
diff --git a/src/lib/tools/logsink.cpp b/src/lib/tools/logsink.cpp
new file mode 100644
index 000000000..a9a4cc064
--- /dev/null
+++ b/src/lib/tools/logsink.cpp
@@ -0,0 +1,81 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "logsink.h"
+#include "logger.h"
+#include "coloredoutput.h"
+
+#include <qhash.h>
+#include <stdio.h>
+
+namespace qbs {
+
+void ConsolePrintLogSink::outputLogMessage(LoggerLevel level, const LogMessage &message)
+{
+ FILE *file = stdout;
+ if (message.outputChannel == LogOutputStdErr)
+ file = stderr;
+
+ if (message.printLogLevel) {
+ switch (level) {
+ case LoggerFatal:
+ fprintfColored(TextColorRed, file, "FATAL ERROR: ");
+ break;
+ case LoggerError:
+ fprintfColored(TextColorRed, file, "ERROR: ");
+ break;
+ case LoggerWarning:
+ fprintfColored(TextColorYellow, file, "WARNING: ");
+ break;
+ case LoggerInfo:
+ fprintf(file, "INFO: ");
+ break;
+ case LoggerDebug:
+ fprintf(file, "DEBUG: ");
+ break;
+ case LoggerTrace:
+ fprintf(file, "TRACE: ");
+ break;
+ }
+ }
+ if (message.textColor == TextColorDefault || !m_coloredOutputEnabled)
+ fprintf(file, "%s\n", message.data.data());
+ else
+ fprintfColored(message.textColor, file, "%s\n", message.data.data());
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/logsink.h b/src/lib/tools/logsink.h
new file mode 100644
index 000000000..f9db7cfb7
--- /dev/null
+++ b/src/lib/tools/logsink.h
@@ -0,0 +1,60 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef LOGSINK_H
+#define LOGSINK_H
+
+#include "logger.h"
+#include <Qbs/ilogsink.h>
+
+namespace qbs {
+
+class ConsolePrintLogSink : public Qbs::ILogSink
+{
+public:
+ void setColoredOutputEnabled(bool enabled) { m_coloredOutputEnabled = enabled; }
+
+protected:
+ virtual void outputLogMessage(LoggerLevel level, const LogMessage &message);
+
+private:
+ bool m_coloredOutputEnabled;
+};
+
+} // namespace qbs
+
+#endif // LOGSINK_H
diff --git a/src/lib/tools/options.cpp b/src/lib/tools/options.cpp
new file mode 100644
index 000000000..02ef521bc
--- /dev/null
+++ b/src/lib/tools/options.cpp
@@ -0,0 +1,450 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "options.h"
+
+#include <tools/error.h>
+#include <tools/fileinfo.h>
+#include <tools/logger.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QThread>
+#include <tools/platform.h>
+
+namespace qbs {
+
+CommandLineOptions::CommandLineOptions()
+ : m_command(BuildCommand)
+ , m_dumpGraph(false)
+ , m_gephi (false)
+ , m_help (false)
+ , m_clean (false)
+ , m_keepGoing(false)
+ , m_jobs(QThread::idealThreadCount())
+{
+ m_settings = Settings::create();
+}
+
+void CommandLineOptions::printHelp()
+{
+ fputs("usage: qbs [command] [options]\n"
+ "\ncommands:\n"
+ " build [variant] [property:value]\n"
+ " build project (default command)\n"
+ " clean ........... remove all generated files\n"
+ " shell ........... open a shell\n"
+ " run target [variant] [property:value] -- <args>\n"
+ " run the specified target\n"
+ " config\n"
+ " set, get, or get all project/global options\n"
+ "\ngeneral options:\n"
+ " -h -? --help .... this help\n"
+ " -d .............. dump graph\n"
+ " -f <file> ....... specify .qbp project file\n"
+ " -v .............. verbose (add up to 5 v to increase verbosity level)\n"
+ "\nbuild options:\n"
+ " -j <n> .......... use <n> jobs (default is nr of cores)\n"
+ " -k .............. keep going (ignore errors)\n"
+ " -n .............. dry run\n"
+ " --changed-files file [file 2] ... [file n]\n"
+ " .............. specify a list of out of date files\n"
+ " --products ProductName [product name 2] ... [product name n]\n"
+ " .............. specify a list of products to build\n"
+ "\ngraph options:\n"
+ " -g .............. show generation graph\n"
+ , stderr);
+}
+
+/**
+ * Finds automatically the project file (.qbs) in the search directory.
+ * If there's more than one project file found then this function returns false.
+ * A project file can explicitely be given by the -f option.
+ */
+bool CommandLineOptions::readCommandLineArguments(const QStringList &args)
+{
+ m_projectFileName.clear();
+ m_dryRun = false;
+ bool firstPositionalEaten = false;
+ bool runArgMode = false;
+ int verbosity = 0;
+
+ const int argc = args.size();
+ for (int i = 0; i < argc; ++i) {
+ QString arg = args.at(i);
+ if (runArgMode) {
+ m_runArgs.append(arg);
+ continue;
+ }
+ if (arg == "--") {
+ runArgMode = true;
+ continue;
+ }
+
+ // --- no dash
+ if (arg.at(0) != '-' || arg.length() < 2) {
+ if (arg == QLatin1String("build")) {
+ m_command = BuildCommand;
+ } else if (arg == QLatin1String("config")) {
+ m_command = ConfigCommand;
+ m_configureArgs = args.mid(i + 1);
+ break;
+ } else if (arg == QLatin1String("clean")) {
+ m_command = CleanCommand;
+ } else if (arg == QLatin1String("shell")) {
+ m_command = StartShellCommand;
+ } else if (arg == QLatin1String("run")) {
+ m_command = RunCommand;
+ } else if (m_command == RunCommand && !firstPositionalEaten) {
+ m_runTargetName = arg;
+ firstPositionalEaten = true;
+ } else {
+ m_positional.append(arg);
+ }
+
+ // --- two dashes
+ } else if (arg.at(1) == '-') {
+
+ arg = arg.remove(0, 2).toLower();
+ QString *targetString = 0;
+ QStringList *targetStringList = 0;
+
+ if (arg == QLatin1String("help")) {
+ m_help = true;
+ } else if (arg == "changed-files" && m_command == BuildCommand) {
+ QStringList changedFiles;
+ for (++i; i < argc && !args.at(i).startsWith('-'); ++i)
+ changedFiles += args.at(i);
+ if (changedFiles.isEmpty()) {
+ qbsError("--changed-files expects one or more file names.");
+ return false;
+ }
+ m_changedFiles = changedFiles;
+ --i;
+ continue;
+ } else if (arg == "products" && (m_command == BuildCommand || m_command == CleanCommand)) {
+ QStringList productNames;
+ for (++i; i < argc && !args.at(i).startsWith('-'); ++i)
+ productNames += args.at(i);
+ if (productNames.isEmpty()) {
+ qbsError("--products expects one or more product names.");
+ return false;
+ }
+ m_selectedProductNames = productNames;
+ --i;
+ continue;
+ } else {
+ QString err = QLatin1String("Parameter '%1' is unknown.");
+ qbsError(qPrintable(err.arg(QLatin1String("--") + arg)));
+ return false;
+ }
+
+ QString stringValue;
+ if (targetString || targetStringList) {
+ // string value expected
+ if (++i >= argc) {
+ QString err = QLatin1String("String value expected after parameter '%1'.");
+ qbsError(qPrintable(err.arg(QLatin1String("--") + arg)));
+ return false;
+ }
+ stringValue = args.at(i);
+ }
+
+ if (targetString)
+ *targetString = stringValue;
+ else if (targetStringList)
+ targetStringList->append(stringValue);
+
+ // --- one dash
+ } else {
+ int k = 1;
+ switch (arg.at(1).toLower().unicode()) {
+ case '?':
+ case 'h':
+ m_help = true;
+ break;
+ case 'j':
+ if (arg.length() > 2) {
+ const QByteArray str(arg.mid(2).toAscii());
+ char *endStr = 0;
+ m_jobs = strtoul(str.data(), &endStr, 10);
+ k += endStr - str.data();
+ } else if (++i < argc) {
+ m_jobs = args.at(i).toInt();
+ }
+ if (m_jobs < 1)
+ return false;
+ break;
+ case 'v':
+ verbosity = 1;
+ while (k < arg.length() - 1 && arg.at(k + 1).toLower().unicode() == 'v') {
+ verbosity++;
+ k++;
+ }
+ break;
+ case 'd':
+ m_dumpGraph = true;
+ break;
+ case 'f':
+ if (arg.length() > 2) {
+ m_projectFileName = arg.mid(2);
+ k += m_projectFileName.length();
+ } else if (++i < argc) {
+ m_projectFileName = args.at(i);
+ }
+ m_projectFileName = QDir::fromNativeSeparators(m_projectFileName);
+ break;
+ case 'g':
+ m_gephi = true;
+ break;
+ case 'k':
+ m_keepGoing = true;
+ break;
+ case 'n':
+ m_dryRun = true;
+ break;
+ default:
+ qbsError(qPrintable(QString("Unknown option '%1'.").arg(arg.at(1))));
+ return false;
+ }
+ if (k < arg.length() - 1) { // Trailing characters?
+ qbsError(qPrintable(QString("Invalid option '%1'.").arg(arg)));
+ return false;
+ }
+ }
+ }
+
+ if (verbosity)
+ Logger::instance().setLevel(verbosity);
+
+ // automatically detect the project file name
+ if (m_projectFileName.isEmpty())
+ m_projectFileName = guessProjectFileName();
+
+ // make the project file name absolute
+ if (!m_projectFileName.isEmpty() && !FileInfo::isAbsolute(m_projectFileName)) {
+ m_projectFileName = FileInfo::resolvePath(QDir::currentPath(), m_projectFileName);
+ }
+
+ // eventually load defaults from configs
+ if (m_searchPaths.isEmpty())
+ m_searchPaths = configurationValue("paths/cubes", QVariant()).toStringList();
+ m_pluginPaths = configurationValue("paths/plugins", QVariant()).toStringList();
+
+ // fixup some defaults
+ if (m_searchPaths.isEmpty())
+ m_searchPaths.append(qbsRootPath() + "/share/qbs/");
+ if (m_pluginPaths.isEmpty())
+ m_pluginPaths.append(qbsRootPath() + "/plugins/");
+
+ return true;
+}
+
+static void showConfigUsage()
+{
+ puts("usage: qbs config [options]\n"
+ "\n"
+ "Config file location:\n"
+ " --global choose global configuration file\n"
+ " --local choose local configuration file (default)\n"
+ "\n"
+ "Actions:\n"
+ " --list list all variables\n"
+ " --unset remove variable with given name\n");
+}
+
+void CommandLineOptions::loadLocalProjectSettings(bool throwExceptionOnFailure)
+{
+ if (m_settings->hasProjectSettings())
+ return;
+ if (throwExceptionOnFailure && m_projectFileName.isEmpty())
+ throw Error("Can't find a project file in the current directory. Local configuration not available.");
+ m_settings->loadProjectSettings(m_projectFileName);
+}
+
+void CommandLineOptions::configure()
+{
+ enum ConfigCommand { CfgSet, CfgUnset, CfgList };
+ ConfigCommand cmd = CfgSet;
+ Settings::Scope scope = Settings::Local;
+ bool scopeSet = false;
+
+ QStringList args = m_configureArgs;
+ m_configureArgs.clear();
+ if (args.isEmpty()) {
+ showConfigUsage();
+ return;
+ }
+
+ while (!args.isEmpty() && args.first().startsWith("--")) {
+ QString arg = args.takeFirst();
+ arg.remove(0, 2);
+ if (arg == "list") {
+ cmd = CfgList;
+ } else if (arg == "unset") {
+ cmd = CfgUnset;
+ } else if (arg == "global") {
+ scope = Settings::Global;
+ scopeSet = true;
+ } else if (arg == "local") {
+ scope = Settings::Local;
+ scopeSet = true;
+ } else {
+ throw Error("Unknown option for config command.");
+ }
+ }
+
+ switch (cmd) {
+ case CfgList:
+ if (scopeSet) {
+ if (scope == Settings::Local)
+ loadLocalProjectSettings(true);
+ printSettings(scope);
+ } else {
+ loadLocalProjectSettings(false);
+ printSettings(Settings::Local);
+ printSettings(Settings::Global);
+ }
+ break;
+ case CfgSet:
+ if (scope == Settings::Local)
+ loadLocalProjectSettings(true);
+ if (args.count() > 2)
+ throw Error("Too many arguments for setting a configuration value.");
+ if (args.count() == 0) {
+ showConfigUsage();
+ } else if (args.count() < 2) {
+ puts(qPrintable(m_settings->value(scope, args.at(0)).toString()));
+ } else {
+ m_settings->setValue(scope, args.at(0), args.at(1));
+ }
+ break;
+ case CfgUnset:
+ if (scope == Settings::Local)
+ loadLocalProjectSettings(true);
+ if (args.isEmpty())
+ throw Error("unset what?");
+ foreach (const QString &arg, args)
+ m_settings->remove(scope, arg);
+ break;
+ }
+}
+
+QVariant CommandLineOptions::configurationValue(const QString &key, const QVariant &defaultValue)
+{
+ return m_settings->value(key, defaultValue);
+}
+
+template <typename S, typename T>
+QMap<S,T> &inhaleValues(QMap<S,T> &dst, const QMap<S,T> &src)
+{
+ for (typename QMap<S,T>::const_iterator it=src.constBegin();
+ it != src.constEnd(); ++it)
+ {
+ dst.insert(it.key(), it.value());
+ }
+ return dst;
+}
+
+QList<QVariantMap> CommandLineOptions::buildConfigurations() const
+{
+ QList<QVariantMap> ret;
+ QVariantMap globalSet;
+ QVariantMap currentSet;
+ QString currentName;
+ foreach (const QString &arg, positional()) {
+ int idx = arg.indexOf(':');
+ if (idx < 0) {
+ if (currentName.isEmpty()) {
+ globalSet = currentSet;
+ } else {
+ QVariantMap map = globalSet;
+ inhaleValues(map, currentSet);
+ if (!map.contains("buildVariant"))
+ map["buildVariant"] = currentName;
+ ret.append(map);
+ }
+ currentSet.clear();
+ currentName = arg;
+ } else {
+ currentSet.insert(arg.left(idx), arg.mid(idx + 1));
+ }
+ }
+
+ if (currentName.isEmpty())
+ currentName = m_settings->value("defaults/buildvariant", "debug").toString();
+ QVariantMap map = globalSet;
+ inhaleValues(map, currentSet);
+ if (!map.contains("buildVariant"))
+ map["buildVariant"] = currentName;
+ ret.append(map);
+ return ret;
+}
+
+void CommandLineOptions::printSettings(Settings::Scope scope)
+{
+ if (scope == Settings::Global)
+ printf("global variables:\n");
+ else
+ printf("local variables:\n");
+ foreach (const QString &key, m_settings->allKeys(scope))
+ printf("%s = %s\n", qPrintable(key),
+ qPrintable(m_settings->value(scope, key).toString()));
+}
+
+QString CommandLineOptions::guessProjectFileName()
+{
+ QDir searchDir = QDir::current();
+ for (;;) {
+ QStringList projectFiles = searchDir.entryList(QStringList() << "*.qbp", QDir::Files);
+ if (projectFiles.count() == 1) {
+ QDir::setCurrent(searchDir.path());
+ return searchDir.absoluteFilePath(projectFiles.first());
+ } else if (projectFiles.count() > 1) {
+ QString str = QLatin1String("Multiple project files found in '%1'.\n"
+ "Please specify the correct project file using the -f option.");
+ qbsError(qPrintable(str.arg(QDir::toNativeSeparators(searchDir.absolutePath()))));
+ return QString();
+ }
+ if (!searchDir.cdUp())
+ break;
+ }
+ return QString();
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/options.h b/src/lib/tools/options.h
new file mode 100644
index 000000000..fa78a3202
--- /dev/null
+++ b/src/lib/tools/options.h
@@ -0,0 +1,113 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include <tools/settings.h>
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include <QtCore/QVariant>
+
+namespace qbs {
+/**
+ * Command line options for qbs command line tools.
+ * ### TODO: move to qbs application.
+ */
+class CommandLineOptions
+{
+public:
+ CommandLineOptions();
+
+ enum Command {
+ BuildCommand,
+ CleanCommand,
+ ConfigCommand,
+ StartShellCommand,
+ RunCommand
+ };
+
+ static void printHelp();
+ Command command() const { return m_command;}
+ bool readCommandLineArguments(const QStringList &args);
+ void configure();
+ const QString &runTargetName() const { return m_runTargetName; }
+ const QString &projectFileName() const { return m_projectFileName; }
+ const QStringList &searchPaths() const { return m_searchPaths; }
+ const QStringList &pluginPaths() const { return m_pluginPaths; }
+ const QStringList &positional() const { return m_positional; }
+ const QStringList &runArgs() const { return m_runArgs; }
+ const QStringList &changedFiles() const { return m_changedFiles; }
+ const QStringList &selectedProductNames() const { return m_selectedProductNames; }
+ bool isDumpGraphSet() const { return m_dumpGraph; }
+ bool isGephiSet() const { return m_gephi; }
+ bool isDryRunSet() const { return m_dryRun; }
+ bool isHelpSet() const { return m_help; }
+ bool isCleanSet() const { return m_clean; }
+ bool isKeepGoingSet() const { return m_keepGoing; }
+ int jobs() const { return m_jobs; }
+ Settings::Ptr settings() const { return m_settings; }
+ QVariant configurationValue(const QString &key, const QVariant &defaultValue = QVariant());
+ QList<QVariantMap> buildConfigurations() const;
+
+private:
+ void loadLocalProjectSettings(bool throwExceptionOnFailure);
+ void printSettings(Settings::Scope scope);
+ QString guessProjectFileName();
+
+private:
+ Settings::Ptr m_settings;
+ Command m_command;
+ QString m_runTargetName;
+ QString m_projectFileName;
+ QStringList m_searchPaths;
+ QStringList m_pluginPaths;
+ QStringList m_positional;
+ QStringList m_runArgs;
+ QStringList m_configureArgs;
+ QStringList m_changedFiles;
+ QStringList m_selectedProductNames;
+ bool m_dumpGraph;
+ bool m_gephi;
+ bool m_dryRun;
+ bool m_help;
+ bool m_clean;
+ bool m_keepGoing;
+ int m_jobs;
+};
+}
+#endif // OPTIONS_H
diff --git a/src/lib/tools/persistence.cpp b/src/lib/tools/persistence.cpp
new file mode 100644
index 000000000..52a441eeb
--- /dev/null
+++ b/src/lib/tools/persistence.cpp
@@ -0,0 +1,227 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "persistence.h"
+#include "fileinfo.h"
+#include <QtCore/QDir>
+#include <stdio.h>
+
+namespace qbs {
+
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE0_0_1__1";
+
+PersistentPool::PersistentPool()
+{
+}
+
+PersistentPool::~PersistentPool()
+{
+}
+
+bool PersistentPool::load(const QString &filePath, const LoadMode loadMode)
+{
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly))
+ return false;
+ QDataStream s(&file);
+
+ QByteArray magic;
+ s >> magic;
+ if (magic != QBS_PERSISTENCE_MAGIC) {
+ file.close();
+ file.remove();
+ return false;
+ }
+
+ s >> m_headData.projectConfig;
+ if (loadMode == LoadHeadData)
+ return true;
+
+ s >> m_stringStorage;
+ m_inverseStringStorage.reserve(m_stringStorage.count());
+ for (int i = m_stringStorage.count(); --i >= 0;)
+ m_inverseStringStorage.insert(m_stringStorage.at(i), i);
+
+ s >> m_storage;
+ m_loadedRaw.reserve(m_storage.count());
+ m_loaded.reserve(m_storage.count());
+ return true;
+}
+
+bool PersistentPool::store(const QString &filePath)
+{
+ QString dirPath = FileInfo::path(filePath);
+ if (!FileInfo::exists(dirPath))
+ if (!QDir().mkpath(dirPath))
+ return false;
+
+ if (QFile::exists(filePath) && !QFile::remove(filePath))
+ return false;
+ Q_ASSERT(!QFile::exists(filePath));
+ QFile file(filePath);
+ if (!file.open(QFile::WriteOnly))
+ return false;
+
+ QDataStream s(&file);
+ s << QByteArray(QBS_PERSISTENCE_MAGIC);
+ s << m_headData.projectConfig;
+ s << m_stringStorage;
+ s << m_storage;
+ return true;
+}
+
+PersistentObjectId PersistentPool::store(PersistentObject *object)
+{
+ if (!object)
+ return 0;
+ PersistentObjectId id = m_storageIndices.value(object, -1);
+ if (id < 0) {
+ PersistentObjectData data;
+ id = qMax(m_storage.count(), m_maxReservedId + 1);
+ m_storageIndices.insert(object, id);
+ m_storage.resize(id + 1);
+ m_storage[id] = data;
+ object->store(*this, data);
+ m_storage[id] = data;
+ }
+ return id;
+}
+
+void PersistentPool::clear()
+{
+ m_loaded.clear();
+ m_storage.clear();
+ m_storageIndices.clear();
+ m_stringStorage.clear();
+ m_inverseStringStorage.clear();
+}
+
+PersistentObjectData PersistentPool::getData(PersistentObjectId id) const
+{
+ return m_storage.at(id);
+}
+
+void PersistentPool::setData(PersistentObjectId id, PersistentObjectData data)
+{
+ Q_ASSERT(id <= m_maxReservedId);
+ if (id >= m_storage.count())
+ m_storage.resize(id + 1);
+ m_storage[id] = data;
+}
+
+int PersistentPool::storeString(const QString &t)
+{
+ if (t.isEmpty())
+ return 0;
+ int id = m_inverseStringStorage.value(t, -1);
+ if (id < 0) {
+ id = m_stringStorage.count();
+ m_inverseStringStorage.insert(t, id);
+ m_stringStorage.append(t);
+ }
+ return id;
+}
+
+QString PersistentPool::loadString(int id)
+{
+ if (id == 0)
+ return QString();
+
+ if (id < 0 || id >= m_stringStorage.count())
+ throw Error(QString("storage error: no string id %1 stored.").arg(id));
+
+ return m_stringStorage.at(id);
+}
+
+QString PersistentPool::idLoadString(QDataStream &s)
+{
+ int id;
+ s >> id;
+ return loadString(id);
+}
+
+QList<int> PersistentPool::storeStringSet(const QSet<QString> &t)
+{
+ QList<int> r;
+ r.reserve(t.count());
+ foreach (const QString &s, t)
+ r += storeString(s);
+ return r;
+}
+
+QSet<QString> PersistentPool::loadStringSet(const QList<int> &ids)
+{
+ QSet<QString> r;
+ r.reserve(ids.count());
+ foreach (int id, ids)
+ r.insert(loadString(id));
+ return r;
+}
+
+QSet<QString> PersistentPool::idLoadStringSet(QDataStream &s)
+{
+ QList<int> list;
+ s >> list;
+ return loadStringSet(list);
+}
+
+QList<int> PersistentPool::storeStringList(const QStringList &t)
+{
+ QList<int> r;
+ r.reserve(t.count());
+ foreach (const QString &s, t)
+ r += storeString(s);
+ return r;
+}
+
+QStringList PersistentPool::loadStringList(const QList<int> &ids)
+{
+ QStringList result;
+ result.reserve(ids.count());
+ foreach (const int &id, ids)
+ result.append(loadString(id));
+ return result;
+}
+
+QStringList PersistentPool::idLoadStringList(QDataStream &s)
+{
+ QList<int> list;
+ s >> list;
+ return loadStringList(list);
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/persistence.h b/src/lib/tools/persistence.h
new file mode 100644
index 000000000..fa9536622
--- /dev/null
+++ b/src/lib/tools/persistence.h
@@ -0,0 +1,237 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QBS_PERSISTENCE
+#define QBS_PERSISTENCE
+
+#include <QtCore/QString>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFile>
+#include <QtCore/QDataStream>
+#include <QtCore/QMap>
+#include <QtCore/QVariantMap>
+#include <QtCore/QDebug>
+#include <tools/error.h>
+
+namespace qbs {
+
+typedef int PersistentObjectId;
+typedef QByteArray PersistentObjectData;
+class PersistentPool;
+
+class PersistentObject
+{
+public:
+ virtual ~PersistentObject() {}
+ virtual void load(PersistentPool &/*pool*/, PersistentObjectData &/*data*/) {}
+ virtual void store(PersistentPool &/*pool*/, PersistentObjectData &/*data*/) const {}
+};
+
+class PersistentPool
+{
+public:
+ PersistentPool();
+ ~PersistentPool();
+
+ struct HeadData
+ {
+ QVariantMap projectConfig;
+ };
+
+ enum LoadMode
+ {
+ LoadHeadData, LoadAll
+ };
+
+ bool load(const QString &filePath, const LoadMode loadMode = LoadAll);
+ bool store(const QString &filePath);
+ void clear();
+
+ template <typename T>
+ inline T *idLoad(QDataStream &s)
+ {
+ PersistentObjectId id;
+ s >> id;
+ return loadRaw<T>(id);
+ }
+
+ template <class T>
+ inline T *loadRaw(PersistentObjectId id)
+ {
+ if (id == 0)
+ return 0;
+
+ PersistentObject *obj = 0;
+ if (id < m_loadedRaw.count()) {
+ obj = m_loadedRaw.value(id);
+ } else {
+ int i = m_loadedRaw.count();
+ m_loadedRaw.resize(id + 1);
+ for (; i < m_loadedRaw.count(); ++i)
+ m_loadedRaw[i] = 0;
+ }
+ if (!obj) {
+ if (id >= m_storage.count())
+ throw Error(QString("storage error: no id %1 stored.").arg(id).arg(m_storage.count()));
+ PersistentObjectData data = m_storage.at(id);
+ obj = new T;
+ m_loadedRaw[id] = obj;
+ obj->load(*this, data);
+ }
+
+ return static_cast<T*>(obj);
+ }
+
+ template <class T>
+ inline typename T::Ptr idLoadS(QDataStream &s)
+ {
+ PersistentObjectId id;
+ s >> id;
+ return load<T>(id);
+ }
+
+ template <class T>
+ inline QSharedPointer<T> load(PersistentObjectId id)
+ {
+ if (id == 0)
+ return QSharedPointer<T>();
+
+ QSharedPointer<PersistentObject> obj;
+ if (id < m_loaded.count())
+ obj = m_loaded.value(id);
+ else
+ m_loaded.resize(id + 1);
+ if (!obj) {
+ if (id >= m_storage.count())
+ throw Error(QString("storage error: no id %1 stored. I have that many: %2").arg(id).arg(m_storage.count()));
+
+ PersistentObjectData data = m_storage.at(id);
+ T *t = new T;
+ obj = QSharedPointer<PersistentObject>(t);
+ m_loaded[id] = obj;
+ obj->load(*this, data);
+ }
+
+ return obj.staticCast<T>();
+ }
+
+ PersistentObject *load(PersistentObjectId);
+
+ template <class T>
+ PersistentObjectId store(QSharedPointer<T> ptr)
+ {
+ return store(ptr.data());
+ }
+
+ PersistentObjectId store(PersistentObject *object);
+
+ int storeString(const QString &t);
+ QString loadString(int id);
+ QString idLoadString(QDataStream &s);
+
+ QList<int> storeStringSet(const QSet<QString> &t);
+ QSet<QString> loadStringSet(const QList<int> &id);
+ QSet<QString> idLoadStringSet(QDataStream &s);
+
+ QList<int> storeStringList(const QStringList &t);
+ QStringList loadStringList(const QList<int> &ids);
+ QStringList idLoadStringList(QDataStream &s);
+
+ PersistentObjectData getData(PersistentObjectId) const;
+ void setData(PersistentObjectId, PersistentObjectData);
+
+ const HeadData &headData() const { return m_headData; }
+ void setHeadData(const HeadData &hd) { m_headData = hd; }
+
+private:
+ static const int m_maxReservedId = 0;
+ HeadData m_headData;
+ QVector<PersistentObject *> m_loadedRaw;
+ QVector<QSharedPointer<PersistentObject> > m_loaded;
+ QVector<PersistentObjectData> m_storage;
+ QHash<PersistentObject *, int> m_storageIndices;
+
+ QVector<QString> m_stringStorage;
+ QHash<QString, int> m_inverseStringStorage;
+};
+
+template<typename T> struct RemovePointer { typedef T Type; };
+template<typename T> struct RemovePointer<T*> { typedef T Type; };
+
+template <typename T>
+void loadContainerS(T &container, QDataStream &s, qbs::PersistentPool &pool)
+{
+ int count;
+ s >> count;
+ container.clear();
+ container.reserve(count);
+ for (int i = count; --i >= 0;)
+ container += pool.idLoadS<typename T::value_type::Type>(s);
+}
+
+template <typename T>
+void loadContainer(T &container, QDataStream &s, qbs::PersistentPool &pool)
+{
+ int count;
+ s >> count;
+ container.clear();
+ container.reserve(count);
+ for (int i = count; --i >= 0;)
+ container += pool.idLoad<typename RemovePointer<typename T::value_type>::Type>(s);
+}
+
+template <typename T>
+void storeContainer(T &container, QDataStream &s, qbs::PersistentPool &pool)
+{
+ s << container.count();
+ typename T::const_iterator it = container.constBegin();
+ const typename T::const_iterator itEnd = container.constEnd();
+ for (; it != itEnd; ++it)
+ s << pool.store(*it);
+}
+
+template <typename T>
+void storeHashContainer(T &container, QDataStream &s, qbs::PersistentPool &pool)
+{
+ s << container.count();
+ foreach (const typename T::mapped_type &item, container)
+ s << pool.store(item);
+}
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/tools/platform.cpp b/src/lib/tools/platform.cpp
new file mode 100644
index 000000000..5ca25dc87
--- /dev/null
+++ b/src/lib/tools/platform.cpp
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "platform.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QSettings>
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#include <Shlobj.h>
+#endif
+
+namespace qbs {
+
+Platform::Platform(const QString &_name, const QString& configpath)
+ : name(_name)
+ , settings(configpath + "/setup.ini", QSettings::IniFormat)
+{
+}
+
+QHash<QString, Platform::Ptr> Platform::platforms()
+{
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
+ QString localSettingsPath = QDir::homePath() + "/.config/Nokia/qbs/platforms/";
+#elif defined(Q_OS_WIN)
+ QString localSettingsPath;
+ wchar_t wszPath[MAX_PATH];
+ if (SHGetSpecialFolderPath(NULL, wszPath, CSIDL_APPDATA, TRUE))
+ localSettingsPath = QString::fromUtf16(wszPath) + "/qbs/platforms";
+#else
+#error port me!
+#endif
+ QHash<QString, Platform::Ptr> targets;
+ QDirIterator i(localSettingsPath, QDir::Dirs | QDir::NoDotAndDotDot);
+ while (i.hasNext()) {
+ i.next();
+ Platform *t = new Platform(i.fileName(), i.filePath());
+ targets.insert(t->name, Platform::Ptr(t));
+ }
+ return targets;
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/platform.h b/src/lib/tools/platform.h
new file mode 100644
index 000000000..fd70a59d0
--- /dev/null
+++ b/src/lib/tools/platform.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef QBS_PLATFORM_H
+#define QBS_PLATFORM_H
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QTextStream>
+#include <QtCore/QSettings>
+
+namespace qbs {
+
+class Platform
+{
+public:
+ typedef QSharedPointer<Platform> Ptr;
+ Platform(const QString &name, const QString& configpath);
+ QString name;
+ QSettings settings;
+ static QHash<QString, Platform::Ptr> platforms();
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/tools/runenvironment.cpp b/src/lib/tools/runenvironment.cpp
new file mode 100644
index 000000000..70d5dcc83
--- /dev/null
+++ b/src/lib/tools/runenvironment.cpp
@@ -0,0 +1,134 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "runenvironment.h"
+#include <tools/settings.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QProcess>
+#include <QtScript/QScriptEngine>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+namespace qbs {
+
+RunEnvironment::RunEnvironment(ResolvedProduct::Ptr product)
+ : m_product(product)
+{
+}
+
+int RunEnvironment::runShell()
+{
+ try {
+ QScriptEngine engine;
+ m_product->setupBuildEnvironment(&engine, QProcessEnvironment::systemEnvironment());
+ } catch (Error &e) {
+ fprintf(stderr, "%s", qPrintable(e.toString()));
+ return 1;
+ }
+
+ QString productId = m_product->project->id + '/' + m_product->name;
+ printf("Starting shell for target '%s'.\n", qPrintable(productId));
+#ifdef Q_OS_UNIX
+ Settings::Ptr settings = Settings::create();
+ QByteArray shellProcess = settings->value("shell", "/bin/sh").toString().toLocal8Bit();
+ QByteArray prompt = "PS1=qbs " + productId.toLocal8Bit() + " $ ";
+
+ QStringList senv = m_product->buildEnvironment.toStringList();
+
+ char *argv[2];
+ argv[0] = shellProcess.data();
+ argv[1] = 0;
+ char **env = new char *[senv.count() + 1];
+ int i = 0;
+ foreach (const QString &s, senv){
+ QByteArray b = s.toLocal8Bit();
+ if (b.startsWith("PS1")) {
+ b = prompt;
+ }
+ env[i] = (char*)malloc(b.size() + 1);
+ memcpy(env[i], b.data(), b.size());
+ env[i][b.size()] = 0;
+ ++i;
+ }
+ env[i] = 0;
+ execve(argv[0], argv, env);
+ qDebug("executing the shell failed");
+ return 890;
+#else
+ foreach (const QString &s, m_product->buildEnvironment.toStringList()) {
+ int idx = s.indexOf(QLatin1Char('='));
+ qputenv(s.left(idx).toLocal8Bit(), s.mid(idx + 1, s.length() - idx - 1).toLocal8Bit());
+ }
+ QByteArray shellProcess = qgetenv("COMSPEC");
+ if (shellProcess.isEmpty())
+ shellProcess = "cmd";
+ shellProcess.append(" /k prompt [qbs] " + qgetenv("PROMPT"));
+ return system(shellProcess);
+#endif
+}
+
+int RunEnvironment::runTarget(const QString &targetBin, const QStringList &arguments)
+{
+ if (!QFileInfo(targetBin).isExecutable()) {
+ fprintf(stderr, "File '%s' is not an executable.\n", qPrintable(targetBin));
+ return 1;
+ }
+
+ try {
+ QScriptEngine engine;
+ m_product->setupRunEnvironment(&engine, QProcessEnvironment::systemEnvironment());
+ } catch (Error &e) {
+ fprintf(stderr, "%s", qPrintable(e.toString()));
+ return 1;
+ }
+
+ printf("Starting target '%s'.\n", qPrintable(QDir::toNativeSeparators(targetBin)));
+ QProcess proc;
+ proc.setProcessEnvironment(m_product->runEnvironment);
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ proc.start(targetBin, arguments);
+ proc.waitForFinished(-1);
+ return proc.exitCode();
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/runenvironment.h b/src/lib/tools/runenvironment.h
new file mode 100644
index 000000000..cc2567e06
--- /dev/null
+++ b/src/lib/tools/runenvironment.h
@@ -0,0 +1,60 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef RUNENVIRONMENT_H
+#define RUNENVIRONMENT_H
+
+#include <QString>
+#include <language/language.h>
+
+namespace qbs {
+
+class RunEnvironment
+{
+public:
+ RunEnvironment(qbs::ResolvedProduct::Ptr product);
+
+ int runShell();
+ int runTarget(const QString &targetBin, const QStringList &arguments);
+
+private:
+ qbs::ResolvedProduct::Ptr m_product;
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/tools/scannerpluginmanager.cpp b/src/lib/tools/scannerpluginmanager.cpp
new file mode 100644
index 000000000..38afb84d3
--- /dev/null
+++ b/src/lib/tools/scannerpluginmanager.cpp
@@ -0,0 +1,113 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "scannerpluginmanager.h"
+#include "logger.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDirIterator>
+#include <QtCore/QLibrary>
+
+namespace qbs {
+ScannerPluginManager *ScannerPluginManager::instance()
+{
+ static ScannerPluginManager *i = new ScannerPluginManager;
+ return i;
+}
+
+ScannerPluginManager::ScannerPluginManager()
+{
+}
+
+QList<ScannerPlugin *> ScannerPluginManager::scannersForFileTag(const QString &fileTag)
+{
+ return instance()->m_scannerPlugins.value(fileTag);
+}
+
+void ScannerPluginManager::loadPlugins(const QStringList &pluginPaths)
+{
+ QStringList filters;
+#if defined(Q_OS_WIN)
+ QString sharedLibSuffix = ".dll";
+#elif defined(Q_OS_DARWIN)
+ QString sharedLibSuffix = ".dylib";
+#else
+ QString sharedLibSuffix = ".so";
+#endif
+ filters << "*" + sharedLibSuffix;
+
+ foreach (const QString &pluginPath, pluginPaths) {
+ qbsTrace("pluginmanager: loading plugins from '%s'.", qPrintable(QDir::toNativeSeparators(pluginPath)));
+ QDirIterator it(pluginPath, filters, QDir::Files);
+ while (it.hasNext()) {
+ const QString fileName = it.next();
+ QScopedPointer<QLibrary> lib(new QLibrary(fileName));
+ if (!lib->load()) {
+ qbsWarning("pluginmanager: couldn't load '%s'.",
+ qPrintable(QDir::toNativeSeparators(fileName)));
+ continue;
+ }
+
+ getScanners_f getScanners = reinterpret_cast<getScanners_f>(lib->resolve("getScanners"));
+ if (!getScanners) {
+ qbsWarning("pluginmanager: couldn't resolve symbol in '%s'.",
+ qPrintable(QDir::toNativeSeparators(fileName)));
+ continue;
+ }
+
+ ScannerPlugin **plugins = getScanners();
+ if (plugins == 0) {
+ qbsWarning("pluginmanager: no scanners returned from '%s'.",
+ qPrintable(QDir::toNativeSeparators(fileName)));
+ continue;
+ }
+
+ qbsTrace("pluginmanager: scanner plugin '%s' loaded.",
+ qPrintable(QDir::toNativeSeparators(fileName)));
+
+ int i = 0;
+ while (plugins[i] != 0) {
+ m_scannerPlugins[QString::fromLocal8Bit(plugins[i]->fileTag)] += plugins[i];
+ ++i;
+ }
+ m_libs.append(lib.take());
+ }
+ }
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/scannerpluginmanager.h b/src/lib/tools/scannerpluginmanager.h
new file mode 100644
index 000000000..0a2b1e5de
--- /dev/null
+++ b/src/lib/tools/scannerpluginmanager.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef PLUGINS_H
+#define PLUGINS_H
+
+#include <QtCore/QString>
+#include <QtCore/QMap>
+#include <plugins/scanner/scanner.h>
+
+QT_BEGIN_NAMESPACE
+class QLibrary;
+QT_END_NAMESPACE
+
+namespace qbs {
+class ScannerPluginManager
+{
+public:
+ static ScannerPluginManager *instance();
+ static QList<ScannerPlugin *> scannersForFileTag(const QString &fileTag);
+ void loadPlugins(const QStringList &paths);
+
+private:
+ ScannerPluginManager();
+
+private:
+ QList<QLibrary *> m_libs;
+ QMap<QString, QList<ScannerPlugin*> > m_scannerPlugins;
+};
+
+} // namespace qbs
+
+#endif
diff --git a/src/lib/tools/scripttools.cpp b/src/lib/tools/scripttools.cpp
new file mode 100644
index 000000000..e2fe36ea9
--- /dev/null
+++ b/src/lib/tools/scripttools.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "scripttools.h"
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValueIterator>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QDataStream &operator<< (QDataStream &s, const QScriptProgram &script)
+{
+ s << script.sourceCode()
+ << script.fileName()
+ << script.firstLineNumber();
+ return s;
+}
+
+QDataStream &operator>> (QDataStream &s, QScriptProgram &script)
+{
+ QString fileName, sourceCode;
+ int lineNumber;
+ s >> sourceCode
+ >> fileName
+ >> lineNumber;
+ script = QScriptProgram(sourceCode, fileName, lineNumber);
+ return s;
+}
+
+QT_END_NAMESPACE
+
+namespace qbs {
+
+static const bool debugJSImports = false;
+
+void addJSImport(QScriptEngine *engine,
+ const QScriptValue &targetObject,
+ const QString &id)
+{
+ if (debugJSImports)
+ qDebug() << "addJSImport (cached): " << id;
+ engine->globalObject().setProperty(id, targetObject);
+}
+
+QScriptValue addJSImport(QScriptEngine *engine,
+ const QScriptProgram &program,
+ const QString &id)
+{
+ if (debugJSImports)
+ qDebug() << "addJSImport: " << id;
+ QScriptValue targetObject = engine->globalObject().property(id);
+ QScriptValue result = addJSImport(engine, program, targetObject);
+ engine->globalObject().setProperty(id, targetObject);
+ return result;
+}
+
+QScriptValue addJSImport(QScriptEngine *engine,
+ const QScriptProgram &program,
+ QScriptValue &targetObject)
+{
+ engine->pushContext();
+ QScriptValue result = engine->evaluate(program);
+ QScriptValue activationObject = engine->currentContext()->activationObject();
+ engine->popContext();
+ if (result.isError())
+ return result;
+
+ if (targetObject.isValid() && !targetObject.isUndefined()) {
+ // try to merge imports with the same target into the same object
+ // it is necessary for library imports that have multiple js files
+ QScriptValueIterator it(activationObject);
+ while (it.hasNext()) {
+ it.next();
+ if (debugJSImports)
+ qDebug() << "mergeJSImport copying property" << it.name();
+ targetObject.setProperty(it.name(), it.value());
+ }
+ } else {
+ targetObject = activationObject;
+ }
+ return result;
+}
+
+void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value)
+{
+ if (name.length() == 1) {
+ cfg.insert(name.first(), value);
+ } else {
+ QVariant &subCfg = cfg[name.first()];
+ QVariantMap subCfgMap = subCfg.toMap();
+ setConfigProperty(subCfgMap, name.mid(1), value);
+ subCfg = subCfgMap;
+ }
+}
+
+QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name)
+{
+ if (name.length() == 1) {
+ return cfg.value(name.first());
+ } else {
+ return getConfigProperty(cfg.value(name.first()).toMap(), name.mid(1));
+ }
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/scripttools.h b/src/lib/tools/scripttools.h
new file mode 100644
index 000000000..bdb218f95
--- /dev/null
+++ b/src/lib/tools/scripttools.h
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef SCRIPTTOOLS_H
+#define SCRIPTTOOLS_H
+
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtCore/QVariantMap>
+#include <QtScript/QScriptProgram>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptEngine>
+
+QT_BEGIN_NAMESPACE
+
+QDataStream &operator<< (QDataStream &s, const QScriptProgram &script);
+QDataStream &operator>> (QDataStream &s, QScriptProgram &script);
+
+QT_END_NAMESPACE
+
+
+namespace qbs {
+
+template <typename C>
+QScriptValue toScriptValue(QScriptEngine *scriptEngine, const C &container)
+{
+ QScriptValue v = scriptEngine->newArray(container.count());
+ int i = 0;
+ foreach (const typename C::value_type &item, container)
+ v.setProperty(i++, scriptEngine->toScriptValue(item));
+ return v;
+}
+
+void addJSImport(QScriptEngine *engine,
+ const QScriptValue &targetObject,
+ const QString &id);
+QScriptValue addJSImport(QScriptEngine *engine,
+ const QScriptProgram &program,
+ const QString &id);
+QScriptValue addJSImport(QScriptEngine *engine,
+ const QScriptProgram &program,
+ QScriptValue &targetObject);
+
+void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value);
+QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name);
+
+} // namespace qbs
+
+#endif // SCRIPTTOOLS_H
diff --git a/src/lib/tools/settings.cpp b/src/lib/tools/settings.cpp
new file mode 100644
index 000000000..290b66478
--- /dev/null
+++ b/src/lib/tools/settings.cpp
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "settings.h"
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QStringList>
+#include <algorithm>
+
+namespace qbs {
+
+Settings::Settings()
+ : m_globalSettings(0),
+ m_localSettings(0)
+{
+ m_globalSettings = new QSettings(QSettings::UserScope,
+ QLatin1String("Nokia"),
+ QLatin1String("qbs"));
+}
+
+Settings::~Settings()
+{
+ delete m_globalSettings;
+ delete m_localSettings;
+}
+
+void Settings::loadProjectSettings(const QString &projectFileName)
+{
+ delete m_localSettings;
+ m_localSettings = new QSettings(QFileInfo(projectFileName).path()
+ + "/.qbs/config", QSettings::IniFormat);
+}
+
+QVariant Settings::value(const QString &key, const QVariant &defaultValue) const
+{
+ if (m_localSettings && m_localSettings->contains(key))
+ return m_localSettings->value(key, defaultValue);
+ return m_globalSettings->value(key, defaultValue);
+}
+
+QVariant Settings::value(Scope scope, const QString &key, const QVariant &defaultValue) const
+{
+ QSettings *s = (scope == Global ? m_globalSettings : m_localSettings);
+ return s ? s->value(key, defaultValue) : defaultValue;
+}
+
+QStringList Settings::allKeys() const
+{
+ QStringList keys;
+ if (m_localSettings)
+ keys = m_localSettings->allKeys();
+ keys.append(m_globalSettings->allKeys());
+ keys.sort();
+ std::unique(keys.begin(), keys.end());
+ return keys;
+}
+
+QStringList Settings::allKeys(Scope scope) const
+{
+ QSettings *s = (scope == Global ? m_globalSettings : m_localSettings);
+ return s ? s->allKeys() : QStringList();
+}
+
+void Settings::setValue(const QString &key, const QVariant &value)
+{
+ setValue(Global, key, value);
+}
+
+void Settings::setValue(Scope scope, const QString &key, const QVariant &value)
+{
+ QSettings *s = (scope == Global ? m_globalSettings : m_localSettings);
+ Q_CHECK_PTR(s);
+ s->setValue(key, value);
+}
+
+void Settings::remove(Settings::Scope scope, const QString &key)
+{
+ QSettings *s = (scope == Global ? m_globalSettings : m_localSettings);
+ if (s)
+ s->remove(key);
+}
+
+} // namespace qbs
diff --git a/src/lib/tools/settings.h b/src/lib/tools/settings.h
new file mode 100644
index 000000000..c2d33d534
--- /dev/null
+++ b/src/lib/tools/settings.h
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace qbs {
+
+class Settings
+{
+public:
+ ~Settings();
+
+ typedef QSharedPointer<Settings> Ptr;
+ static Ptr create() { return Ptr(new Settings); }
+
+ enum Scope
+ {
+ Local, Global
+ };
+
+ void loadProjectSettings(const QString &projectFileName);
+ bool hasProjectSettings() const { return m_localSettings; }
+ QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+ QVariant value(Scope scope, const QString &key, const QVariant &defaultValue = QVariant()) const;
+ QStringList allKeys() const;
+ QStringList allKeys(Scope scope) const;
+ void setValue(const QString &key, const QVariant &value);
+ void setValue(Scope scope, const QString &key, const QVariant &value);
+ void remove(Scope scope, const QString &key);
+
+protected:
+ Settings();
+
+protected:
+ QSettings *m_globalSettings;
+ QSettings *m_localSettings;
+};
+
+}
+
+#endif // SETTINGS_H
diff --git a/src/lib/tools/tools.pri b/src/lib/tools/tools.pri
new file mode 100644
index 000000000..71268117c
--- /dev/null
+++ b/src/lib/tools/tools.pri
@@ -0,0 +1,40 @@
+INCLUDEPATH += $$PWD $$PWD/.. $$PWD/../.. $$PWD/../../..
+
+HEADERS += \
+ $$PWD/codelocation.h \
+ $$PWD/error.h \
+ $$PWD/fileinfo.h \
+ $$PWD/filetime.h \
+ $$PWD/logger.h \
+ $$PWD/logsink.h \
+ $$PWD/options.h \
+ $$PWD/persistence.h \
+ $$PWD/platform.h \
+ $$PWD/scannerpluginmanager.h \
+ $$PWD/runenvironment.h \
+ $$PWD/scripttools.h \
+ $$PWD/settings.h \
+ $$PWD/coloredoutput.h \
+ $$PWD/fakeconcurrent.h
+
+SOURCES += \
+ $$PWD/error.cpp \
+ $$PWD/fileinfo.cpp \
+ $$PWD/logger.cpp \
+ $$PWD/logsink.cpp \
+ $$PWD/options.cpp \
+ $$PWD/persistence.cpp \
+ $$PWD/platform.cpp \
+ $$PWD/scannerpluginmanager.cpp \
+ $$PWD/runenvironment.cpp \
+ $$PWD/scripttools.cpp \
+ $$PWD/settings.cpp \
+ $$PWD/coloredoutput.cpp
+
+win32 {
+ SOURCES += $$PWD/filetime_win.cpp
+}
+
+unix {
+ SOURCES += $$PWD/filetime_unix.cpp
+}
diff --git a/src/lib/use.pri b/src/lib/use.pri
new file mode 100644
index 000000000..d69ea6a7f
--- /dev/null
+++ b/src/lib/use.pri
@@ -0,0 +1,43 @@
+isEmpty(QBSLIBDIR) {
+ QBSLIBDIR = $$OUT_PWD/../../../lib
+}
+
+QT += script
+
+unix {
+ LIBS += -L$$QBSLIBDIR -lqbscore
+ POST_TARGETDEPS += $$QBSLIBDIR/libqbscore.a
+}
+
+win32 {
+ CONFIG(debug, debug|release) {
+ QBSCORELIB = qbscored
+ }
+ CONFIG(release, debug|release) {
+ QBSCORELIB = qbscore
+ }
+ win32-msvc* {
+ LIBS += /LIBPATH:$$QBSLIBDIR
+ QBSCORELIB = $${QBSCORELIB}.lib
+ } else {
+ LIBS += -L$${QBSLIBDIR}
+ QBSCORELIB = lib$${QBSCORELIB}
+ }
+ QBSLIBS += $$QBSCORELIB
+ LIBS += Shell32.lib $$QBSLIBS
+ for(x, QBSLIBS): POST_TARGETDEPS+=$$QBSLIBDIR/$$x
+}
+
+INCLUDEPATH += \
+ $$PWD \
+ $$PWD/..
+
+
+
+DEPENDPATH += \
+ $$PWD/buildgraph\
+ $$PWD/Qbs\
+ $$PWD/l2\
+ $$PWD/parser\
+ $$PWD/tools\
+ $$INCLUDEPATH
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
new file mode 100644
index 000000000..d6a7e6d5b
--- /dev/null
+++ b/src/plugins/plugins.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = scanner script
diff --git a/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h b/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h
new file mode 100644
index 000000000..4b8b1f1d1
--- /dev/null
+++ b/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h
@@ -0,0 +1,151 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+#define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+
+#include <cstdlib>
+#include <cstddef>
+
+#ifndef CPLUSPLUS_WITHOUT_QT
+# include <QtCore/qglobal.h>
+
+//# if defined(CPLUSPLUS_BUILD_LIB)
+//# define CPLUSPLUS_EXPORT Q_DECL_EXPORT
+//# elif defined(CPLUSPLUS_BUILD_STATIC_LIB)
+//# define CPLUSPLUS_EXPORT
+//# else
+//# define CPLUSPLUS_EXPORT Q_DECL_IMPORT
+//# endif
+//#else
+# define CPLUSPLUS_EXPORT
+#endif
+
+namespace CPlusPlus {
+
+class TranslationUnit;
+class Control;
+class MemoryPool;
+class DiagnosticClient;
+
+class Identifier;
+class Literal;
+class StringLiteral;
+class NumericLiteral;
+
+class SymbolTable;
+
+// names
+class NameVisitor;
+class Name;
+class Identifier;
+class TemplateNameId;
+class DestructorNameId;
+class OperatorNameId;
+class ConversionNameId;
+class QualifiedNameId;
+class SelectorNameId;
+
+// types
+class TypeMatcher;
+class FullySpecifiedType;
+class TypeVisitor;
+class Type;
+class UndefinedType;
+class VoidType;
+class IntegerType;
+class FloatType;
+class PointerToMemberType;
+class PointerType;
+class ReferenceType;
+class ArrayType;
+class NamedType;
+
+// symbols
+class SymbolVisitor;
+class Symbol;
+class Scope;
+class UsingNamespaceDirective;
+class UsingDeclaration;
+class Declaration;
+class Argument;
+class TypenameArgument;
+class Function;
+class Namespace;
+class NamespaceAlias;
+class Template;
+class BaseClass;
+class Block;
+class Class;
+class Enum;
+class ForwardClassDeclaration;
+
+class Token;
+
+// Objective-C symbols
+class ObjCBaseClass;
+class ObjCBaseProtocol;
+class ObjCClass;
+class ObjCForwardClassDeclaration;
+class ObjCProtocol;
+class ObjCForwardProtocolDeclaration;
+class ObjCMethod;
+class ObjCPropertyDeclaration;
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
diff --git a/src/plugins/scanner/cpp/Lexer.cpp b/src/plugins/scanner/cpp/Lexer.cpp
new file mode 100644
index 000000000..6d6f22e18
--- /dev/null
+++ b/src/plugins/scanner/cpp/Lexer.cpp
@@ -0,0 +1,669 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Lexer.h"
+#include <cctype>
+
+using namespace CPlusPlus;
+
+Lexer::Lexer(const char *firstChar, const char *lastChar)
+ : _state(State_Default),
+ _flags(0),
+ _currentLine(1)
+{
+ setSource(firstChar, lastChar);
+}
+
+Lexer::~Lexer()
+{ }
+
+void Lexer::setSource(const char *firstChar, const char *lastChar)
+{
+ _firstChar = firstChar;
+ _lastChar = lastChar;
+ _currentChar = _firstChar - 1;
+ _tokenStart = _currentChar;
+ _yychar = '\n';
+}
+
+void Lexer::setStartWithNewline(bool enabled)
+{
+ if (enabled)
+ _yychar = '\n';
+ else
+ _yychar = ' ';
+}
+
+int Lexer::state() const
+{ return _state; }
+
+void Lexer::setState(int state)
+{ _state = state; }
+
+bool Lexer::qtMocRunEnabled() const
+{ return f._qtMocRunEnabled; }
+
+void Lexer::setQtMocRunEnabled(bool onoff)
+{ f._qtMocRunEnabled = onoff; }
+
+bool Lexer::cxx0xEnabled() const
+{ return f._cxx0xEnabled; }
+
+void Lexer::setCxxOxEnabled(bool onoff)
+{ f._cxx0xEnabled = onoff; }
+
+bool Lexer::objCEnabled() const
+{ return f._objCEnabled; }
+
+void Lexer::setObjCEnabled(bool onoff)
+{ f._objCEnabled = onoff; }
+
+bool Lexer::isIncremental() const
+{ return f._isIncremental; }
+
+void Lexer::setIncremental(bool isIncremental)
+{ f._isIncremental = isIncremental; }
+
+bool Lexer::scanCommentTokens() const
+{ return f._scanCommentTokens; }
+
+void Lexer::setScanCommentTokens(bool onoff)
+{ f._scanCommentTokens = onoff; }
+
+void Lexer::setScanAngleStringLiteralTokens(bool onoff)
+{ f._scanAngleStringLiteralTokens = onoff; }
+
+void Lexer::pushLineStartOffset()
+{
+ ++_currentLine;
+}
+
+unsigned Lexer::tokenOffset() const
+{ return _tokenStart - _firstChar; }
+
+unsigned Lexer::tokenLength() const
+{ return _currentChar - _tokenStart; }
+
+const char *Lexer::tokenBegin() const
+{ return _tokenStart; }
+
+const char *Lexer::tokenEnd() const
+{ return _currentChar; }
+
+unsigned Lexer::currentLine() const
+{ return _currentLine; }
+
+void Lexer::scan(Token *tok)
+{
+ tok->reset();
+ scan_helper(tok);
+ tok->f.length = _currentChar - _tokenStart;
+}
+
+void Lexer::scan_helper(Token *tok)
+{
+ _Lagain:
+ while (_yychar && std::isspace(_yychar)) {
+ if (_yychar == '\n') {
+ tok->f.joined = false;
+ tok->f.newline = true;
+ } else {
+ tok->f.whitespace = true;
+ }
+ yyinp();
+ }
+
+ tok->lineno = _currentLine;
+ _tokenStart = _currentChar;
+ tok->offset = _currentChar - _firstChar;
+
+ if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) {
+ const int originalState = _state;
+
+ if (! _yychar) {
+ tok->f.kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ while (_yychar) {
+ if (_yychar != '*')
+ yyinp();
+ else {
+ yyinp();
+ if (_yychar == '/') {
+ yyinp();
+ _state = State_Default;
+ break;
+ }
+ }
+ }
+
+ if (! f._scanCommentTokens)
+ goto _Lagain;
+
+ else if (originalState == State_MultiLineComment)
+ tok->f.kind = T_COMMENT;
+ else
+ tok->f.kind = T_DOXY_COMMENT;
+ return; // done
+ }
+
+ if (! _yychar) {
+ tok->f.kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ unsigned char ch = _yychar;
+ yyinp();
+
+ switch (ch) {
+ case '\\':
+ while (_yychar != '\n' && std::isspace(_yychar))
+ yyinp();
+ // ### assert(! _yychar || _yychar == '\n');
+ if (_yychar == '\n') {
+ tok->f.joined = true;
+ tok->f.newline = false;
+ yyinp();
+ }
+ goto _Lagain;
+
+ case '"': case '\'': {
+ const char quote = ch;
+
+ tok->f.kind = quote == '"'
+ ? T_STRING_LITERAL
+ : T_CHAR_LITERAL;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar == '\n')
+ break;
+ else if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ if (_yychar == quote)
+ yyinp();
+ } break;
+
+ case '{':
+ tok->f.kind = T_LBRACE;
+ break;
+
+ case '}':
+ tok->f.kind = T_RBRACE;
+ break;
+
+ case '[':
+ tok->f.kind = T_LBRACKET;
+ break;
+
+ case ']':
+ tok->f.kind = T_RBRACKET;
+ break;
+
+ case '#':
+ if (_yychar == '#') {
+ tok->f.kind = T_POUND_POUND;
+ yyinp();
+ } else {
+ tok->f.kind = T_POUND;
+ }
+ break;
+
+ case '(':
+ tok->f.kind = T_LPAREN;
+ break;
+
+ case ')':
+ tok->f.kind = T_RPAREN;
+ break;
+
+ case ';':
+ tok->f.kind = T_SEMICOLON;
+ break;
+
+ case ':':
+ if (_yychar == ':') {
+ yyinp();
+ tok->f.kind = T_COLON_COLON;
+ } else {
+ tok->f.kind = T_COLON;
+ }
+ break;
+
+ case '.':
+ if (_yychar == '*') {
+ yyinp();
+ tok->f.kind = T_DOT_STAR;
+ } else if (_yychar == '.') {
+ yyinp();
+ // ### assert(_yychar);
+ if (_yychar == '.') {
+ yyinp();
+ tok->f.kind = T_DOT_DOT_DOT;
+ } else {
+ tok->f.kind = T_ERROR;
+ }
+ } else if (std::isdigit(_yychar)) {
+ do {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ } while (_yychar);
+ tok->f.kind = T_NUMERIC_LITERAL;
+ } else {
+ tok->f.kind = T_DOT;
+ }
+ break;
+
+ case '?':
+ tok->f.kind = T_QUESTION;
+ break;
+
+ case '+':
+ if (_yychar == '+') {
+ yyinp();
+ tok->f.kind = T_PLUS_PLUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_PLUS_EQUAL;
+ } else {
+ tok->f.kind = T_PLUS;
+ }
+ break;
+
+ case '-':
+ if (_yychar == '-') {
+ yyinp();
+ tok->f.kind = T_MINUS_MINUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_MINUS_EQUAL;
+ } else if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '*') {
+ yyinp();
+ tok->f.kind = T_ARROW_STAR;
+ } else {
+ tok->f.kind = T_ARROW;
+ }
+ } else {
+ tok->f.kind = T_MINUS;
+ }
+ break;
+
+ case '*':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_STAR_EQUAL;
+ } else {
+ tok->f.kind = T_STAR;
+ }
+ break;
+
+ case '/':
+ if (_yychar == '/') {
+ yyinp();
+
+ bool doxy = false;
+
+ if (_yychar == '/' || _yychar == '!') {
+ yyinp();
+
+ if (_yychar == '<')
+ yyinp();
+
+ if (_yychar != '\n' && std::isspace(_yychar))
+ doxy = true;
+ }
+
+ while (_yychar && _yychar != '\n')
+ yyinp();
+
+ if (! f._scanCommentTokens)
+ goto _Lagain;
+
+ tok->f.kind = doxy ? T_CPP_DOXY_COMMENT : T_CPP_COMMENT;
+
+ } else if (_yychar == '*') {
+ yyinp();
+
+ bool doxy = false;
+
+ if (_yychar == '*' || _yychar == '!') {
+ const char ch = _yychar;
+
+ yyinp();
+
+ if (ch == '*' && _yychar == '/')
+ goto _Ldone;
+
+ if (_yychar == '<')
+ yyinp();
+
+ if (! _yychar || std::isspace(_yychar))
+ doxy = true;
+ }
+
+ while (_yychar) {
+ if (_yychar != '*') {
+ yyinp();
+ } else {
+ yyinp();
+ if (_yychar == '/')
+ break;
+ }
+ }
+
+ _Ldone:
+ if (_yychar)
+ yyinp();
+ else
+ _state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment;
+
+ if (! f._scanCommentTokens)
+ goto _Lagain;
+
+ tok->f.kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
+
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_SLASH_EQUAL;
+ } else {
+ tok->f.kind = T_SLASH;
+ }
+ break;
+
+ case '%':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_PERCENT_EQUAL;
+ } else {
+ tok->f.kind = T_PERCENT;
+ }
+ break;
+
+ case '^':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_CARET_EQUAL;
+ } else {
+ tok->f.kind = T_CARET;
+ }
+ break;
+
+ case '&':
+ if (_yychar == '&') {
+ yyinp();
+ tok->f.kind = T_AMPER_AMPER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_AMPER_EQUAL;
+ } else {
+ tok->f.kind = T_AMPER;
+ }
+ break;
+
+ case '|':
+ if (_yychar == '|') {
+ yyinp();
+ tok->f.kind = T_PIPE_PIPE;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_PIPE_EQUAL;
+ } else {
+ tok->f.kind = T_PIPE;
+ }
+ break;
+
+ case '~':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_TILDE_EQUAL;
+ } else {
+ tok->f.kind = T_TILDE;
+ }
+ break;
+
+ case '!':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_EXCLAIM_EQUAL;
+ } else {
+ tok->f.kind = T_EXCLAIM;
+ }
+ break;
+
+ case '=':
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_EQUAL_EQUAL;
+ } else {
+ tok->f.kind = T_EQUAL;
+ }
+ break;
+
+ case '<':
+ if (f._scanAngleStringLiteralTokens) {
+ const char *yytext = _currentChar;
+ while (_yychar && _yychar != '>')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ // ### assert(_yychar == '>');
+ if (_yychar == '>')
+ yyinp();
+ tok->f.kind = T_ANGLE_STRING_LITERAL;
+ } else if (_yychar == '<') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_LESS_LESS_EQUAL;
+ } else
+ tok->f.kind = T_LESS_LESS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_LESS_EQUAL;
+ } else {
+ tok->f.kind = T_LESS;
+ }
+ break;
+
+ case '>':
+ if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_GREATER_GREATER_EQUAL;
+ } else
+ tok->f.kind = T_LESS_LESS;
+ tok->f.kind = T_GREATER_GREATER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->f.kind = T_GREATER_EQUAL;
+ } else {
+ tok->f.kind = T_GREATER;
+ }
+ break;
+
+ case ',':
+ tok->f.kind = T_COMMA;
+ break;
+
+ default: {
+ if (f._objCEnabled) {
+ if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') {
+ const char *yytext = _currentChar;
+
+ do {
+ yyinp();
+ if (! (isalnum(_yychar) || _yychar == '_' || _yychar == '$'))
+ break;
+ } while (_yychar);
+
+ const int yylen = _currentChar - yytext;
+ //tok->f.kind = classifyObjCAtKeyword(yytext, yylen); /// ### FIXME
+ break;
+ } else if (ch == '@' && _yychar == '"') {
+ // objc @string literals
+ ch = _yychar;
+ yyinp();
+ tok->f.kind = T_AT_STRING_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != '"') {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == '"');
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == '"')
+ yyinp();
+
+ break;
+ }
+ }
+
+ if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
+ // wide char/string literals
+ ch = _yychar;
+ yyinp();
+
+ const char quote = ch;
+
+ tok->f.kind = quote == '"'
+ ? T_WIDE_STRING_LITERAL
+ : T_WIDE_CHAR_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == quote)
+ yyinp();
+
+ } else if (std::isalpha(ch) || ch == '_' || ch == '$') {
+ const char *yytext = _currentChar - 1;
+ while (std::isalnum(_yychar) || _yychar == '_' || _yychar == '$')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ tok->f.kind = T_IDENTIFIER;
+ break;
+ } else if (std::isdigit(ch)) {
+ const char *yytext = _currentChar - 1;
+ while (_yychar) {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ }
+ int yylen = _currentChar - yytext;
+ tok->f.kind = T_NUMERIC_LITERAL;
+ break;
+ } else {
+ tok->f.kind = T_ERROR;
+ break;
+ }
+ } // default
+
+ } // switch
+}
+
+
diff --git a/src/plugins/scanner/cpp/Lexer.h b/src/plugins/scanner/cpp/Lexer.h
new file mode 100644
index 000000000..e697bad9a
--- /dev/null
+++ b/src/plugins/scanner/cpp/Lexer.h
@@ -0,0 +1,162 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LEXER_H
+#define CPLUSPLUS_LEXER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Token.h"
+
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT Lexer
+{
+ Lexer(const Lexer &other);
+ void operator =(const Lexer &other);
+
+public:
+ enum State {
+ State_Default,
+ State_MultiLineComment,
+ State_MultiLineDoxyComment
+ };
+
+ Lexer(const char *firstChar, const char *lastChar);
+ ~Lexer();
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ bool cxx0xEnabled() const;
+ void setCxxOxEnabled(bool onoff);
+
+ bool objCEnabled() const;
+ void setObjCEnabled(bool onoff);
+
+ void scan(Token *tok);
+
+ inline void operator()(Token *tok)
+ { scan(tok); }
+
+ unsigned tokenOffset() const;
+ unsigned tokenLength() const;
+ const char *tokenBegin() const;
+ const char *tokenEnd() const;
+ unsigned currentLine() const;
+
+ bool scanCommentTokens() const;
+ void setScanCommentTokens(bool onoff);
+
+ bool scanAngleStringLiteralTokens() const;
+ void setScanAngleStringLiteralTokens(bool onoff);
+
+ void setStartWithNewline(bool enabled);
+
+ int state() const;
+ void setState(int state);
+
+ bool isIncremental() const;
+ void setIncremental(bool isIncremental);
+
+private:
+ void scan_helper(Token *tok);
+ void setSource(const char *firstChar, const char *lastChar);
+ static int classify(const char *string, int length, bool q, bool cxx0x);
+ static int classifyObjCAtKeyword(const char *s, int n);
+ static int classifyOperator(const char *string, int length);
+
+ inline void yyinp()
+ {
+ if (++_currentChar == _lastChar)
+ _yychar = 0;
+ else {
+ _yychar = *_currentChar;
+ if (_yychar == '\n')
+ pushLineStartOffset();
+ }
+ }
+
+ void pushLineStartOffset();
+
+private:
+ struct Flags {
+ unsigned _isIncremental: 1;
+ unsigned _scanCommentTokens: 1;
+ unsigned _scanAngleStringLiteralTokens: 1;
+ unsigned _qtMocRunEnabled: 1;
+ unsigned _cxx0xEnabled: 1;
+ unsigned _objCEnabled: 1;
+ };
+
+ const char *_firstChar;
+ const char *_currentChar;
+ const char *_lastChar;
+ const char *_tokenStart;
+ unsigned char _yychar;
+ int _state;
+ union {
+ unsigned _flags;
+ Flags f;
+ };
+ unsigned _currentLine;
+};
+
+} // end of namespace CPlusPlus
+
+
+#endif // CPLUSPLUS_LEXER_H
diff --git a/src/plugins/scanner/cpp/Token.cpp b/src/plugins/scanner/cpp/Token.cpp
new file mode 100644
index 000000000..066e3c469
--- /dev/null
+++ b/src/plugins/scanner/cpp/Token.cpp
@@ -0,0 +1,154 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Token.h"
+#ifndef CPLUSPLUS_NO_PARSER
+# include "Literals.h"
+#endif
+
+using namespace CPlusPlus;
+
+static const char *token_names[] = {
+ (""), ("<error>"),
+
+ ("<C++ comment>"), ("<C++ doxy comment>"),
+ ("<comment>"), ("<doxy comment>"),
+
+ ("<identifier>"), ("<numeric literal>"), ("<char literal>"),
+ ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),
+ ("<@string literal>"), ("<angle string literal>"),
+
+ ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"),
+ (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"),
+ ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="),
+ ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"),
+ ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"),
+ ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
+
+ ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"),
+ ("class"), ("const"), ("const_cast"), ("continue"), ("default"),
+ ("delete"), ("do"), ("double"), ("dynamic_cast"), ("else"), ("enum"),
+ ("explicit"), ("export"), ("extern"), ("false"), ("float"), ("for"),
+ ("friend"), ("goto"), ("if"), ("inline"), ("int"), ("long"),
+ ("mutable"), ("namespace"), ("new"), ("operator"), ("private"),
+ ("protected"), ("public"), ("register"), ("reinterpret_cast"),
+ ("return"), ("short"), ("signed"), ("sizeof"), ("static"),
+ ("static_cast"), ("struct"), ("switch"), ("template"), ("this"),
+ ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"),
+ ("union"), ("unsigned"), ("using"), ("virtual"), ("void"),
+ ("volatile"), ("wchar_t"), ("while"),
+
+ // gnu
+ ("__attribute__"), ("__typeof__"),
+
+ // objc @keywords
+ ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"),
+ ("@encode"), ("@end"), ("@finally"), ("@implementation"), ("@interface"),
+ ("@not_keyword"), ("@optional"), ("@package"), ("@private"), ("@property"),
+ ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"),
+ ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"),
+
+ // Qt keywords
+ ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"),
+ ("Q_FOREACH"), ("Q_D"), ("Q_Q"),
+ ("Q_INVOKABLE"), ("Q_PROPERTY"), ("Q_INTERFACES"), ("Q_ENUMS"), ("Q_FLAGS"),
+ ("Q_PRIVATE_SLOT"), ("Q_DECLARE_INTERFACE"), ("Q_OBJECT"), ("Q_GADGET"),
+
+};
+
+Token::Token() :
+ flags(0), offset(0), ptr(0)
+{
+}
+
+Token::~Token()
+{
+}
+
+void Token::reset()
+{
+ flags = 0;
+ offset = 0;
+ ptr = 0;
+}
+
+const char *Token::name(int kind)
+{ return token_names[kind]; }
+
+#ifndef CPLUSPLUS_NO_PARSER
+const char *Token::spell() const
+{
+ switch (f.kind) {
+ case T_IDENTIFIER:
+ return identifier->chars();
+
+ case T_NUMERIC_LITERAL:
+ case T_CHAR_LITERAL:
+ case T_STRING_LITERAL:
+ case T_AT_STRING_LITERAL:
+ case T_ANGLE_STRING_LITERAL:
+ case T_WIDE_CHAR_LITERAL:
+ case T_WIDE_STRING_LITERAL:
+ return literal->chars();
+
+ default:
+ return token_names[f.kind];
+ } // switch
+}
+#endif
+
+
diff --git a/src/plugins/scanner/cpp/Token.h b/src/plugins/scanner/cpp/Token.h
new file mode 100644
index 000000000..140af2f42
--- /dev/null
+++ b/src/plugins/scanner/cpp/Token.h
@@ -0,0 +1,371 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TOKEN_H
+#define CPLUSPLUS_TOKEN_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+namespace CPlusPlus {
+
+enum Kind {
+ T_EOF_SYMBOL = 0,
+ T_ERROR,
+
+ T_CPP_COMMENT,
+ T_CPP_DOXY_COMMENT,
+ T_COMMENT,
+ T_DOXY_COMMENT,
+ T_IDENTIFIER,
+
+ T_FIRST_LITERAL,
+ T_NUMERIC_LITERAL = T_FIRST_LITERAL,
+ T_CHAR_LITERAL,
+ T_WIDE_CHAR_LITERAL,
+ T_STRING_LITERAL,
+ T_WIDE_STRING_LITERAL,
+ T_AT_STRING_LITERAL,
+ T_ANGLE_STRING_LITERAL,
+ T_LAST_LITERAL = T_ANGLE_STRING_LITERAL,
+
+ T_FIRST_OPERATOR,
+ T_AMPER = T_FIRST_OPERATOR,
+ T_AMPER_AMPER,
+ T_AMPER_EQUAL,
+ T_ARROW,
+ T_ARROW_STAR,
+ T_CARET,
+ T_CARET_EQUAL,
+ T_COLON,
+ T_COLON_COLON,
+ T_COMMA,
+ T_SLASH,
+ T_SLASH_EQUAL,
+ T_DOT,
+ T_DOT_DOT_DOT,
+ T_DOT_STAR,
+ T_EQUAL,
+ T_EQUAL_EQUAL,
+ T_EXCLAIM,
+ T_EXCLAIM_EQUAL,
+ T_GREATER,
+ T_GREATER_EQUAL,
+ T_GREATER_GREATER,
+ T_GREATER_GREATER_EQUAL,
+ T_LBRACE,
+ T_LBRACKET,
+ T_LESS,
+ T_LESS_EQUAL,
+ T_LESS_LESS,
+ T_LESS_LESS_EQUAL,
+ T_LPAREN,
+ T_MINUS,
+ T_MINUS_EQUAL,
+ T_MINUS_MINUS,
+ T_PERCENT,
+ T_PERCENT_EQUAL,
+ T_PIPE,
+ T_PIPE_EQUAL,
+ T_PIPE_PIPE,
+ T_PLUS,
+ T_PLUS_EQUAL,
+ T_PLUS_PLUS,
+ T_POUND,
+ T_POUND_POUND,
+ T_QUESTION,
+ T_RBRACE,
+ T_RBRACKET,
+ T_RPAREN,
+ T_SEMICOLON,
+ T_STAR,
+ T_STAR_EQUAL,
+ T_TILDE,
+ T_TILDE_EQUAL,
+ T_LAST_OPERATOR = T_TILDE_EQUAL,
+
+ T_FIRST_KEYWORD,
+ T_ASM = T_FIRST_KEYWORD,
+ T_AUTO,
+ T_BOOL,
+ T_BREAK,
+ T_CASE,
+ T_CATCH,
+ T_CHAR,
+ T_CLASS,
+ T_CONST,
+ T_CONST_CAST,
+ T_CONTINUE,
+ T_DEFAULT,
+ T_DELETE,
+ T_DO,
+ T_DOUBLE,
+ T_DYNAMIC_CAST,
+ T_ELSE,
+ T_ENUM,
+ T_EXPLICIT,
+ T_EXPORT,
+ T_EXTERN,
+ T_FALSE,
+ T_FLOAT,
+ T_FOR,
+ T_FRIEND,
+ T_GOTO,
+ T_IF,
+ T_INLINE,
+ T_INT,
+ T_LONG,
+ T_MUTABLE,
+ T_NAMESPACE,
+ T_NEW,
+ T_OPERATOR,
+ T_PRIVATE,
+ T_PROTECTED,
+ T_PUBLIC,
+ T_REGISTER,
+ T_REINTERPRET_CAST,
+ T_RETURN,
+ T_SHORT,
+ T_SIGNED,
+ T_SIZEOF,
+ T_STATIC,
+ T_STATIC_CAST,
+ T_STRUCT,
+ T_SWITCH,
+ T_TEMPLATE,
+ T_THIS,
+ T_THROW,
+ T_TRUE,
+ T_TRY,
+ T_TYPEDEF,
+ T_TYPEID,
+ T_TYPENAME,
+ T_UNION,
+ T_UNSIGNED,
+ T_USING,
+ T_VIRTUAL,
+ T_VOID,
+ T_VOLATILE,
+ T_WCHAR_T,
+ T_WHILE,
+
+ T___ATTRIBUTE__,
+ T___TYPEOF__,
+
+ // obj c++ @ keywords
+ T_FIRST_OBJC_AT_KEYWORD,
+
+ T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD,
+ T_AT_CLASS,
+ T_AT_COMPATIBILITY_ALIAS,
+ T_AT_DEFS,
+ T_AT_DYNAMIC,
+ T_AT_ENCODE,
+ T_AT_END,
+ T_AT_FINALLY,
+ T_AT_IMPLEMENTATION,
+ T_AT_INTERFACE,
+ T_AT_NOT_KEYWORD,
+ T_AT_OPTIONAL,
+ T_AT_PACKAGE,
+ T_AT_PRIVATE,
+ T_AT_PROPERTY,
+ T_AT_PROTECTED,
+ T_AT_PROTOCOL,
+ T_AT_PUBLIC,
+ T_AT_REQUIRED,
+ T_AT_SELECTOR,
+ T_AT_SYNCHRONIZED,
+ T_AT_SYNTHESIZE,
+ T_AT_THROW,
+ T_AT_TRY,
+
+ T_LAST_OBJC_AT_KEYWORD = T_AT_TRY,
+
+ T_FIRST_QT_KEYWORD,
+
+ // Qt keywords
+ T_SIGNAL = T_FIRST_QT_KEYWORD,
+ T_SLOT,
+ T_Q_SIGNAL,
+ T_Q_SLOT,
+ T_Q_SIGNALS,
+ T_Q_SLOTS,
+ T_Q_FOREACH,
+ T_Q_D,
+ T_Q_Q,
+ T_Q_INVOKABLE,
+ T_Q_PROPERTY,
+ T_Q_INTERFACES,
+ T_Q_ENUMS,
+ T_Q_FLAGS,
+ T_Q_PRIVATE_SLOT,
+ T_Q_DECLARE_INTERFACE,
+ T_Q_OBJECT,
+ T_Q_GADGET,
+ T_LAST_KEYWORD = T_Q_GADGET,
+
+ // aliases
+ T_OR = T_PIPE_PIPE,
+ T_AND = T_AMPER_AMPER,
+ T_NOT = T_EXCLAIM,
+ T_XOR = T_CARET,
+ T_BITOR = T_PIPE,
+ T_COMPL = T_TILDE,
+ T_OR_EQ = T_PIPE_EQUAL,
+ T_AND_EQ = T_AMPER_EQUAL,
+ T_BITAND = T_AMPER,
+ T_NOT_EQ = T_EXCLAIM_EQUAL,
+ T_XOR_EQ = T_CARET_EQUAL,
+
+ T___ASM = T_ASM,
+ T___ASM__ = T_ASM,
+
+ T_TYPEOF = T___TYPEOF__,
+ T___TYPEOF = T___TYPEOF__,
+
+ T___INLINE = T_INLINE,
+ T___INLINE__ = T_INLINE,
+
+ T___CONST = T_CONST,
+ T___CONST__ = T_CONST,
+
+ T___VOLATILE = T_VOLATILE,
+ T___VOLATILE__ = T_VOLATILE,
+
+ T___ATTRIBUTE = T___ATTRIBUTE__
+};
+
+class CPLUSPLUS_EXPORT Token
+{
+public:
+ Token();
+ ~Token();
+
+ inline bool is(unsigned k) const { return f.kind == k; }
+ inline bool isNot(unsigned k) const { return f.kind != k; }
+#ifndef CPLUSPLUS_NO_PARSER
+ const char *spell() const;
+#endif
+ void reset();
+
+ inline unsigned kind() const { return f.kind; }
+ inline bool newline() const { return f.newline; }
+ inline bool whitespace() const { return f.whitespace; }
+ inline bool joined() const { return f.joined; }
+ inline bool expanded() const { return f.expanded; }
+ inline bool generated() const { return f.generated; }
+ inline unsigned length() const { return f.length; }
+
+ inline unsigned begin() const
+ { return offset; }
+
+ inline unsigned end() const
+ { return offset + f.length; }
+
+ inline bool isLiteral() const
+ { return f.kind >= T_FIRST_LITERAL && f.kind <= T_LAST_LITERAL; }
+
+ inline bool isOperator() const
+ { return f.kind >= T_FIRST_OPERATOR && f.kind <= T_LAST_OPERATOR; }
+
+ inline bool isKeyword() const
+ { return f.kind >= T_FIRST_KEYWORD && f.kind < T_FIRST_QT_KEYWORD; }
+
+ inline bool isComment() const
+ { return f.kind == T_COMMENT || f.kind == T_DOXY_COMMENT ||
+ f.kind == T_CPP_COMMENT || f.kind == T_CPP_DOXY_COMMENT; }
+
+ inline bool isObjCAtKeyword() const
+ { return f.kind >= T_FIRST_OBJC_AT_KEYWORD && f.kind <= T_LAST_OBJC_AT_KEYWORD; }
+
+ static const char *name(int kind);
+
+public:
+ struct Flags {
+ unsigned kind : 8;
+ unsigned newline : 1;
+ unsigned whitespace : 1;
+ unsigned joined : 1;
+ unsigned expanded : 1;
+ unsigned generated : 1;
+ unsigned pad : 3;
+ unsigned length : 16;
+ };
+ union {
+ unsigned flags;
+ Flags f;
+ };
+
+ unsigned offset;
+
+ union {
+ void *ptr;
+#ifndef CPLUSPLUS_NO_PARSER
+ const Literal *literal;
+ const NumericLiteral *number;
+ const StringLiteral *string;
+ const Identifier *identifier;
+#endif
+ unsigned close_brace;
+ unsigned lineno;
+ };
+};
+
+} // end of namespace CPlusPlus
+
+
+#endif // CPLUSPLUS_TOKEN_H
diff --git a/src/plugins/scanner/cpp/cpp.cpp b/src/plugins/scanner/cpp/cpp.cpp
new file mode 100644
index 000000000..3fde5b6cc
--- /dev/null
+++ b/src/plugins/scanner/cpp/cpp.cpp
@@ -0,0 +1,281 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "../scanner.h"
+#include "cpp_global.h"
+#include <Lexer.h>
+
+using namespace CPlusPlus;
+
+#ifdef Q_OS_UNIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <QtCore/QFile>
+#endif
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QString>
+
+struct ScanResult
+{
+ char *fileName;
+ unsigned int size;
+ int flags;
+};
+
+struct Opaq
+{
+ enum FileType
+ {
+ FT_UNKNOWN, FT_HPP, FT_CPP
+ };
+
+ Opaq()
+ :
+#ifdef Q_OS_UNIX
+ fd(0),
+ mapl(0),
+#endif
+ fileContent(0),
+ fileType(FT_UNKNOWN),
+ hasQObjectMacro(false),
+ currentResultIndex(0)
+ {}
+
+ ~Opaq()
+ {
+#ifdef Q_OS_UNIX
+ if (fileContent)
+ munmap(fileContent, mapl);
+ if (fd)
+ close(fd);
+#endif
+ }
+
+#ifdef Q_OS_WIN
+ QFile file;
+#endif
+#ifdef Q_OS_UNIX
+ int fd;
+ size_t mapl;
+#endif
+
+ QString fileName;
+ char *fileContent;
+ FileType fileType;
+ QList<ScanResult> includedFiles;
+ bool hasQObjectMacro;
+ int currentResultIndex;
+};
+
+static void scanCppFile(void *opaq, Lexer &yylex, bool scanForFileTags)
+{
+ static const size_t lengthOfIncludeLiteral = strlen("include");
+ Opaq *opaque = static_cast<Opaq *>(opaq);
+ Token tk;
+ ScanResult scanResult;
+
+ yylex(&tk);
+
+ while (tk.isNot(T_EOF_SYMBOL)) {
+ if (tk.newline() && tk.is(T_POUND)) {
+ yylex(&tk);
+
+ if (!scanForFileTags && !tk.newline() && tk.is(T_IDENTIFIER)) {
+ if (tk.length() >= lengthOfIncludeLiteral
+ && (strncmp(opaque->fileContent + tk.begin(), "include", lengthOfIncludeLiteral) == 0))
+ {
+ yylex.setScanAngleStringLiteralTokens(true);
+ yylex(&tk);
+ yylex.setScanAngleStringLiteralTokens(false);
+
+ if (!tk.newline() && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))) {
+ scanResult.size = tk.length() - 2;
+ if (tk.is(T_STRING_LITERAL))
+ scanResult.flags = SC_LOCAL_INCLUDE_FLAG;
+ else
+ scanResult.flags = SC_GLOBAL_INCLUDE_FLAG;
+ scanResult.fileName = opaque->fileContent + tk.begin() + 1;
+ opaque->includedFiles.append(scanResult);
+ }
+ }
+ }
+ } else if (tk.is(T_IDENTIFIER) && !opaque->hasQObjectMacro) {
+ if (scanForFileTags
+ && tk.length() == 8
+ && opaque->fileContent[tk.begin()] == 'Q'
+ && opaque->fileContent[tk.begin() + 1] == '_'
+ && (strncmp(opaque->fileContent + tk.begin() + 2, "OBJECT", 6) == 0
+ || strncmp(opaque->fileContent + tk.begin() + 2, "GADGET", 6) == 0))
+ {
+ opaque->hasQObjectMacro = true;
+ break;
+ }
+ }
+ yylex(&tk);
+ }
+}
+
+static void *openScanner(const unsigned short *filePath, char **fileTags, int numFileTags)
+{
+ QScopedPointer<Opaq> opaque(new Opaq);
+ opaque->fileName = QString::fromUtf16(filePath);
+
+ size_t mapl = 0;
+#ifdef Q_OS_UNIX
+ QString filePathS = opaque->fileName;
+
+ opaque->fd = open(qPrintable(filePathS), O_RDONLY);
+ if (opaque->fd == -1) {
+ opaque->fd = 0;
+ return 0;
+ }
+
+ struct stat s;
+ int r = fstat(opaque->fd, &s);
+ if (r != 0)
+ return 0;
+ mapl = s.st_size;
+ opaque->mapl = mapl;
+
+ void *vmap = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, opaque->fd, 0);
+ if (vmap == MAP_FAILED)
+ return 0;
+#else
+ opaque->file.setFileName(opaque->fileName);
+ if (!opaque->file.open(QFile::ReadOnly))
+ return 0;
+
+ uchar *vmap = opaque->file.map(0, opaque->file.size());
+ mapl = opaque->file.size();
+#endif
+ if (!vmap)
+ return 0;
+
+ for (int i=0; i < numFileTags; ++i) {
+ const char *fileTag = fileTags[i];
+ if (strncmp("cpp", fileTag, 3) == 0)
+ opaque->fileType = Opaq::FT_CPP;
+ else if (strncmp("hpp", fileTag, 3) == 0)
+ opaque->fileType = Opaq::FT_HPP;
+ }
+
+ opaque->fileContent = reinterpret_cast<char *>(vmap);
+ Lexer lex(opaque->fileContent, opaque->fileContent + mapl);
+ const bool scanForFileTags = fileTags && numFileTags;
+ scanCppFile(opaque.data(), lex, scanForFileTags);
+ return static_cast<void *>(opaque.take());
+}
+
+static void closeScanner(void *ptr)
+{
+ Opaq *opaque = static_cast<Opaq *>(ptr);
+ delete opaque;
+}
+
+static const char *next(void *opaq, int *size, int *flags)
+{
+ Opaq *opaque = static_cast<Opaq*>(opaq);
+ if (opaque->currentResultIndex < opaque->includedFiles.count()) {
+ const ScanResult &result = opaque->includedFiles.at(opaque->currentResultIndex);
+ ++opaque->currentResultIndex;
+ *size = result.size;
+ *flags = result.flags;
+ return result.fileName;
+ }
+ *size = 0;
+ *flags = 0;
+ return 0;
+}
+
+static const char **additionalFileTags(void *opaq, int *size)
+{
+ static const char *thMocCpp[] = { "moc_cpp" };
+ static const char *thMocHpp[] = { "moc_hpp" };
+
+ Opaq *opaque = static_cast<Opaq*>(opaq);
+ if (opaque->hasQObjectMacro) {
+ *size = 1;
+ switch (opaque->fileType) {
+ case Opaq::FT_CPP:
+ return thMocCpp;
+ case Opaq::FT_HPP:
+ return thMocHpp;
+ default:
+ break;
+ }
+ }
+ *size = 0;
+ return 0;
+}
+
+extern "C" {
+
+ScannerPlugin hppScanner =
+{
+ "include_scanner",
+ "hpp",
+ openScanner,
+ closeScanner,
+ next,
+ additionalFileTags
+};
+
+ScannerPlugin cppScanner =
+{
+ "include_scanner",
+ "cpp",
+ openScanner,
+ closeScanner,
+ next,
+ additionalFileTags
+};
+
+ScannerPlugin *theScanners[3] = {&hppScanner, &cppScanner, NULL};
+
+CPPSCANNER_EXPORT ScannerPlugin **getScanners()
+{
+ return theScanners;
+}
+
+} // extern "C"
diff --git a/src/plugins/scanner/cpp/cpp.pro b/src/plugins/scanner/cpp/cpp.pro
new file mode 100644
index 000000000..e5d4d8381
--- /dev/null
+++ b/src/plugins/scanner/cpp/cpp.pro
@@ -0,0 +1,15 @@
+DEFINES += CPLUSPLUS_NO_PARSER
+
+DESTDIR= ../../../../plugins/
+TEMPLATE = lib
+TARGET = qbs_cpp_scanner
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT = core
+
+unix: CONFIG += plugin
+
+HEADERS += CPlusPlusForwardDeclarations.h Lexer.h Token.h ../scanner.h \
+ cpp_global.h
+SOURCES += cpp.cpp Lexer.cpp Token.cpp
diff --git a/src/plugins/scanner/cpp/cpp_global.h b/src/plugins/scanner/cpp/cpp_global.h
new file mode 100644
index 000000000..1e57911dd
--- /dev/null
+++ b/src/plugins/scanner/cpp/cpp_global.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef CPP_GLOBAL_H
+#define CPP_GLOBAL_H
+
+#if defined(WIN32) || defined(_WIN32)
+#define CPPSCANNER_EXPORT __declspec(dllexport)
+#else
+#define CPPSCANNER_EXPORT
+#endif
+
+#endif // CPP_GLOBAL_H
diff --git a/src/plugins/scanner/qt/qt.cpp b/src/plugins/scanner/qt/qt.cpp
new file mode 100644
index 000000000..66d59e59a
--- /dev/null
+++ b/src/plugins/scanner/qt/qt.cpp
@@ -0,0 +1,227 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#if defined(WIN32) || defined(_WIN32)
+#define SCANNER_EXPORT __declspec(dllexport)
+#else
+#define SCANNER_EXPORT
+#endif
+
+#include "../scanner.h"
+
+#include <QtCore/qglobal.h>
+
+#ifdef Q_OS_UNIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <QtCore/QFile>
+#endif
+
+#include <QtCore/QString>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QScopedPointer>
+
+
+#include <QDebug>
+
+struct Opaq
+{
+#ifdef Q_OS_UNIX
+ int fd;
+ int mapl;
+#else
+ QFile *file;
+#endif
+
+ char *map;
+ QXmlStreamReader *xml;
+ QByteArray current;
+ Opaq()
+#ifdef Q_OS_UNIX
+ : fd (0),
+#else
+ : file(0),
+#endif
+ map(0),
+ xml(0)
+ {}
+
+ ~Opaq()
+ {
+#ifdef Q_OS_UNIX
+ if (map)
+ munmap (map, mapl);
+ if (fd)
+ close (fd);
+#else
+ delete file;
+#endif
+ delete xml;
+ }
+};
+
+static void *openScanner(const unsigned short *filePath, char **fileTags, int numFileTags)
+{
+ Q_UNUSED(fileTags);
+ Q_UNUSED(numFileTags);
+ QScopedPointer<Opaq> opaque(new Opaq);
+
+#ifdef Q_OS_UNIX
+ QString filePathS = QString::fromUtf16(filePath);
+ opaque->fd = open(qPrintable(filePathS), O_RDONLY);
+ if (opaque->fd == -1) {
+ opaque->fd = 0;
+ return 0;
+ }
+
+ struct stat s;
+ int r = fstat(opaque->fd, &s);
+ if (r != 0)
+ return 0;
+ opaque->mapl = s.st_size;
+
+ void *map = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, opaque->fd, 0);
+ if (map == 0)
+ return 0;
+#else
+ opaque->file = new QFile(QString::fromUtf16(filePath));
+ if (!opaque->file->open(QFile::ReadOnly))
+ return 0;
+
+ uchar *map = opaque->file->map(0, opaque->file->size());
+ if (!map)
+ return 0;
+#endif
+
+ opaque->map = reinterpret_cast<char *>(map);
+ opaque->xml = new QXmlStreamReader(opaque->map);
+
+ return static_cast<void *>(opaque.take());
+}
+
+static void closeScanner(void *ptr)
+{
+ Opaq *opaque = static_cast<Opaq *>(ptr);
+ delete opaque;
+}
+
+static const char *nextUi(void *opaq, int *size, int *flags)
+{
+ Opaq *o= static_cast<Opaq *>(opaq);
+ while (!o->xml->atEnd()) {
+ o->xml->readNext();
+ switch (o->xml->tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if ( o->xml->name() == "include") {
+ o->current = o->xml->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toUtf8();
+ *flags = SC_GLOBAL_INCLUDE_FLAG;
+ *size = o->current.size();
+ return o->current.data();
+ }
+ break;
+ case QXmlStreamReader::EndDocument:
+ return 0;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static const char *nextQrc(void *opaq, int *size, int *flags)
+{
+ Opaq *o= static_cast<Opaq *>(opaq);
+ while (!o->xml->atEnd()) {
+ o->xml->readNext();
+ switch (o->xml->tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if ( o->xml->name() == "file") {
+ o->current = o->xml->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toUtf8();
+ *flags = SC_LOCAL_INCLUDE_FLAG;
+ *size = o->current.size();
+ return o->current.data();
+ }
+ break;
+ case QXmlStreamReader::EndDocument:
+ return 0;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static const char **additionalFileTags(void *, int *size)
+{
+ *size = 0;
+ return 0;
+}
+
+extern "C" {
+
+ScannerPlugin uiScanner =
+{
+ "qt_ui_scanner",
+ "ui",
+ openScanner,
+ closeScanner,
+ nextUi,
+ additionalFileTags
+};
+
+ScannerPlugin qrcScanner =
+{
+ "qt_qrc_scanner",
+ "qrc",
+ openScanner,
+ closeScanner,
+ nextQrc,
+ additionalFileTags
+};
+
+ScannerPlugin *theScanners[3] = {&uiScanner, &qrcScanner, NULL};
+
+SCANNER_EXPORT ScannerPlugin **getScanners()
+{
+ return theScanners;
+}
+
+} // extern "C"
diff --git a/src/plugins/scanner/qt/qt.pro b/src/plugins/scanner/qt/qt.pro
new file mode 100644
index 000000000..c825e9d15
--- /dev/null
+++ b/src/plugins/scanner/qt/qt.pro
@@ -0,0 +1,12 @@
+DESTDIR= ../../../../plugins
+TEMPLATE = lib
+TARGET = qbs_qt_scanner
+DEPENDPATH += .
+INCLUDEPATH += .
+
+Qt = core xml
+
+unix: CONFIG += plugin
+
+HEADERS += ../scanner.h
+SOURCES += qt.cpp
diff --git a/src/plugins/scanner/scanner.h b/src/plugins/scanner/scanner.h
new file mode 100644
index 000000000..402112d8e
--- /dev/null
+++ b/src/plugins/scanner/scanner.h
@@ -0,0 +1,93 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SC_LOCAL_INCLUDE_FLAG 0x1
+#define SC_GLOBAL_INCLUDE_FLAG 0x2
+
+/**
+ * Open a file that's going to be scanned.
+ * The file path encoding is UTF-16 on all platforms.
+ *
+ * If the scanner is used for more than one type hint (e.g. C++ header / source)
+ * the scanner can read the parameter fileTag which file type it is going to scan.
+ *
+ * Returns a scanner handle.
+ */
+typedef void *(*scanOpen_f) (const unsigned short *filePath, char **fileTags, int numFileTags);
+
+/**
+ * Closes the given scanner handle.
+ */
+typedef void (*scanClose_f) (void *opaq);
+
+/**
+ * Return the next result (filename) of the scan.
+ */
+typedef const char *(*scanNext_f) (void *opaq, int *size, int *flags);
+
+/**
+ * Returns a list of type hints for the scanned file.
+ * May return null.
+ *
+ * Example: if a C++ header file contains Q_OBJECT,
+ * the type hint 'moc_hpp' is returned.
+ */
+typedef const char** (*scanAdditionalFileTags_f) (void *opaq, int *size);
+
+struct ScannerPlugin
+{
+ const char *name;
+ const char *fileTag;
+ scanOpen_f open;
+ scanClose_f close;
+ scanNext_f next;
+ scanAdditionalFileTags_f additionalFileTags;
+};
+
+typedef ScannerPlugin **(*getScanners_f)();
+
+#ifdef __cplusplus
+}
+#endif
+#endif // SCANNER_H
diff --git a/src/plugins/scanner/scanner.pro b/src/plugins/scanner/scanner.pro
new file mode 100644
index 000000000..68acae7da
--- /dev/null
+++ b/src/plugins/scanner/scanner.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = cpp qt
+
diff --git a/src/plugins/script/file/file.cpp b/src/plugins/script/file/file.cpp
new file mode 100644
index 000000000..247d46056
--- /dev/null
+++ b/src/plugins/script/file/file.cpp
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "file.h"
+
+#include <tools/fileinfo.h>
+
+#include <QtCore/QDebug>
+#include <QtScript/QScriptEngine>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+void File::init(QScriptValue &extensionObject, QScriptEngine *engine)
+{
+ QScriptValue fileObj = engine->newQObject(new File, QScriptEngine::ScriptOwnership);
+ fileObj.setProperty("copy", engine->newFunction(File::js_copy));
+ fileObj.setProperty("exists", engine->newFunction(File::js_exists));
+ fileObj.setProperty("remove", engine->newFunction(File::js_remove));
+ extensionObject.setProperty("File", fileObj);
+}
+
+QScriptValue File::js_copy(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (context->argumentCount() < 2) {
+ return context->throwError(QScriptContext::SyntaxError,
+ tr("copy expects 2 arguments"));
+ }
+ return QFile::copy(context->argument(0).toString(), context->argument(1).toString());
+}
+
+QScriptValue File::js_exists(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (context->argumentCount() < 1) {
+ return context->throwError(QScriptContext::SyntaxError,
+ tr("exist expects 1 argument"));
+ }
+ return qbs::FileInfo::exists(context->argument(0).toString());
+}
+
+QScriptValue File::js_remove(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (context->argumentCount() < 1) {
+ return context->throwError(QScriptContext::SyntaxError,
+ tr("remove expects 1 argument"));
+ }
+ QString fileName = context->argument(0).toString();
+#ifdef Q_OS_UNIX
+ return unlink(fileName.toLocal8Bit().data()) == 0;
+#else
+ return QFile::remove(fileName);
+#endif
+}
diff --git a/src/plugins/script/file/file.h b/src/plugins/script/file/file.h
new file mode 100644
index 000000000..0e4126718
--- /dev/null
+++ b/src/plugins/script/file/file.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef FILE_H
+
+#include <QtCore/QMetaType>
+#include <QtCore/QObject>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtScript/QScriptable>
+#include <QtScript/QScriptValue>
+
+class File : public QObject, public QScriptable
+{
+Q_OBJECT
+public:
+ static void init(QScriptValue &extensionObject, QScriptEngine *engine);
+
+private:
+ static QScriptValue js_copy(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_exists(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_remove(QScriptContext *context, QScriptEngine *engine);
+};
+
+#endif // FILE_H
diff --git a/src/plugins/script/file/file.pro b/src/plugins/script/file/file.pro
new file mode 100644
index 000000000..eded5fdbc
--- /dev/null
+++ b/src/plugins/script/file/file.pro
@@ -0,0 +1,20 @@
+DESTDIR= ../../../../plugins/script/
+TEMPLATE = lib
+TARGET = qtscript_fileapi
+DEPENDPATH += .
+INCLUDEPATH += . ../../../lib/
+
+QT = core script
+
+unix: CONFIG += plugin
+
+HEADERS += \
+ file.h \
+ ../../../lib/tools/fileinfo.h \
+ textfile.h
+
+SOURCES += \
+ plugin.cpp \
+ file.cpp \
+ ../../../lib/tools/fileinfo.cpp \
+ textfile.cpp
diff --git a/src/plugins/script/file/plugin.cpp b/src/plugins/script/file/plugin.cpp
new file mode 100644
index 000000000..c493145a3
--- /dev/null
+++ b/src/plugins/script/file/plugin.cpp
@@ -0,0 +1,75 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "file.h"
+#include "textfile.h"
+
+#include <QtScript/QScriptExtensionPlugin>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptEngine>
+
+void qtscript_initialize_com_nokia_qbs_fileapi_bindings(QScriptValue &);
+
+class com_nokia_qbs_fileapi_ScriptPlugin : public QScriptExtensionPlugin
+{
+public:
+ QStringList keys() const;
+ void initialize(const QString &key, QScriptEngine *engine);
+};
+
+QStringList com_nokia_qbs_fileapi_ScriptPlugin::keys() const
+{
+ QStringList list;
+ list << QLatin1String("qbs");
+ list << QLatin1String("qbs.fileapi");
+ return list;
+}
+
+void com_nokia_qbs_fileapi_ScriptPlugin::initialize(const QString &key, QScriptEngine *engine)
+{
+ if (key == QLatin1String("qbs")) {
+ } else if (key == QLatin1String("qbs.fileapi")) {
+ QScriptValue extensionObject = engine->globalObject();
+ File::init(extensionObject, engine);
+ TextFile::init(extensionObject, engine);
+ } else {
+ Q_ASSERT_X(false, "qbs.fileapi::initialize", qPrintable(key));
+ }
+}
+
+Q_EXPORT_STATIC_PLUGIN(com_nokia_qbs_fileapi_ScriptPlugin)
+Q_EXPORT_PLUGIN2(qtscript_com_nokia_qbs_fileapi, com_nokia_qbs_fileapi_ScriptPlugin)
diff --git a/src/plugins/script/file/textfile.cpp b/src/plugins/script/file/textfile.cpp
new file mode 100644
index 000000000..91817799e
--- /dev/null
+++ b/src/plugins/script/file/textfile.cpp
@@ -0,0 +1,186 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "textfile.h"
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
+
+void TextFile::init(QScriptValue &extensionObject, QScriptEngine *engine)
+{
+ QScriptValue obj = engine->newQMetaObject(&TextFile::staticMetaObject, engine->newFunction(&TextFile::ctor));
+ extensionObject.setProperty("TextFile", obj);
+}
+
+QScriptValue TextFile::ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ TextFile *t;
+ switch (context->argumentCount()) {
+ case 1:
+ t = new TextFile(context,
+ context->argument(0).toString());
+ break;
+ case 2:
+ t = new TextFile(context,
+ context->argument(0).toString(),
+ static_cast<OpenMode>(context->argument(1).toInt32())
+ );
+ break;
+ case 3:
+ t = new TextFile(context,
+ context->argument(0).toString(),
+ static_cast<OpenMode>(context->argument(1).toInt32()),
+ context->argument(2).toString()
+ );
+ break;
+ default:
+ return context->throwError("TextFile(QString file, OpenMode mode = ReadOnly, QString codec = QLatin1String(\"UTF8\"))");
+ }
+
+ QScriptValue obj = engine->newQObject(t, QScriptEngine::ScriptOwnership);
+// obj.setProperty("d", engine->newQObject(new FileImplementation(t),
+// QScriptEngine::QScriptEngine::QtOwnership));
+ return obj;
+}
+
+TextFile::~TextFile()
+{
+ delete qstream;
+ delete qfile;
+}
+
+TextFile::TextFile(QScriptContext *context, QString file, OpenMode mode, QString codec)
+{
+ Q_UNUSED(codec)
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = this;
+
+ t->qfile = new QFile(file);
+ QIODevice::OpenMode m = QIODevice::ReadOnly;
+ if (mode == ReadWrite) {
+ m = QIODevice::ReadWrite;
+ } else if (mode == ReadOnly) {
+ m = QIODevice::ReadOnly;
+ } else if (mode == WriteOnly) {
+ m = QIODevice::WriteOnly;
+ }
+ if (!t->qfile->open(m)) {
+ delete t->qfile;
+ t->qfile = 0;
+ context->throwError(QString::fromLatin1("unable to open '%1'")
+ .arg(file)
+ );
+ }
+
+ t->qstream = new QTextStream(t->qfile);
+}
+
+void TextFile::close()
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (t->qfile)
+ t->qfile->close();
+ delete t->qfile;
+ t->qfile = 0;
+ delete t->qstream;
+ t->qstream = 0;
+}
+
+void TextFile::setCodec(QString codec)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ t->qstream->setCodec(qPrintable(codec));
+}
+
+QString TextFile::readLine()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qfile)
+ return QString();
+ return t->qstream->readLine();
+}
+
+QString TextFile::readAll()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qfile)
+ return QString();
+ return t->qstream->readAll();
+}
+
+bool TextFile::eof()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return true;
+ return t->qstream->atEnd();
+}
+
+void TextFile::truncate()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ t->qfile->resize(0);
+ t->qstream->reset();
+}
+
+void TextFile::write(QString str)
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ (*t->qstream) << str;
+}
+
+void TextFile::writeLine(QString str)
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ (*t->qstream) << str;
+#ifdef Q_OS_WINDOWS
+ (*t->qstream) <<"\r\n";
+#else
+ (*t->qstream) <<"\n";
+#endif
+}
diff --git a/src/plugins/script/file/textfile.h b/src/plugins/script/file/textfile.h
new file mode 100644
index 000000000..3ac722311
--- /dev/null
+++ b/src/plugins/script/file/textfile.h
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef TEXTFILE_H
+#define TEXTFILE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtScript/QScriptable>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QTextStream;
+QT_END_NAMESPACE
+
+class TextFile : public QObject, public QScriptable
+{
+ Q_OBJECT
+ Q_ENUMS(OpenMode)
+public:
+ static void init(QScriptValue &extensionObject, QScriptEngine *engine);
+
+ enum OpenMode { ReadOnly, WriteOnly, ReadWrite };
+ static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine);
+ TextFile(QScriptContext *context, QString file, OpenMode mode = ReadOnly, QString codec = QLatin1String("UTF8"));
+ ~TextFile();
+ Q_INVOKABLE void close();
+ Q_INVOKABLE void setCodec(QString codec);
+ Q_INVOKABLE QString readLine();
+ Q_INVOKABLE QString readAll();
+ Q_INVOKABLE bool eof();
+ Q_INVOKABLE void truncate();
+ Q_INVOKABLE void write(QString);
+ Q_INVOKABLE void writeLine(QString);
+private:
+ QFile *qfile;
+ QTextStream *qstream;
+};
+
+Q_DECLARE_METATYPE(TextFile *);
+
+#endif // TEXTFILE_H
diff --git a/src/plugins/script/script.pro b/src/plugins/script/script.pro
new file mode 100644
index 000000000..702ca17ef
--- /dev/null
+++ b/src/plugins/script/script.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = file
diff --git a/static.pro b/static.pro
new file mode 100644
index 000000000..35168f08a
--- /dev/null
+++ b/static.pro
@@ -0,0 +1,70 @@
+TEMPLATE = app
+TARGET = phony_target
+CONFIG -= qt separate_debug_info gdb_dwarf_index
+QT =
+LIBS =
+macx:CONFIG -= app_bundle
+
+isEmpty(vcproj) {
+ QMAKE_LINK = @: IGNORE THIS LINE
+ OBJECTS_DIR =
+ win32:CONFIG -= embed_manifest_exe
+} else {
+ CONFIG += console
+ PHONY_DEPS = .
+ phony_src.input = PHONY_DEPS
+ phony_src.output = phony.c
+ phony_src.variable_out = GENERATED_SOURCES
+ phony_src.commands = echo int main() { return 0; } > phony.c
+ phony_src.name = CREATE phony.c
+ phony_src.CONFIG += combine
+ QMAKE_EXTRA_COMPILERS += phony_src
+}
+
+DATA_DIRS = share/qbs/imports share/qbs/modules
+win32:DATA_FILES = bin/ibmsvc.xml bin/ibqbs.bat
+
+defineReplace(cleanPath) {
+ win32:1 ~= s|\\\\|/|g
+ contains(1, ^/.*):pfx = /
+ else:pfx =
+ segs = $$split(1, /)
+ out =
+ for(seg, segs) {
+ equals(seg, ..):out = $$member(out, 0, -2)
+ else:!equals(seg, .):out += $$seg
+ }
+ return($$join(out, /, $$pfx))
+}
+
+# For use in custom compilers which just copy files
+win32:i_flag = i
+defineReplace(stripSrcDir) {
+ win32 {
+ !contains(1, ^.:.*):1 = $$OUT_PWD/$$1
+ } else {
+ !contains(1, ^/.*):1 = $$OUT_PWD/$$1
+ }
+ out = $$cleanPath($$1)
+ out ~= s|^$$re_escape($$PWD/)||$$i_flag
+ return($$out)
+}
+
+!isEqual(PWD, $$OUT_PWD) {
+ for(data_dir, DATA_DIRS) {
+ files = $$files($$PWD/$$data_dir/*, true)
+ win32:files ~= s|\\\\|/|g
+ for(file, files):!exists($$file/*):FILES += $$file
+ }
+ FILES += $$DATA_FILES
+
+ OTHER_FILES += $$FILES
+ copy2build.input = FILES
+ copy2build.output = ${QMAKE_FUNC_FILE_IN_stripSrcDir}
+ isEmpty(vcproj):copy2build.variable_out = PRE_TARGETDEPS
+ win32:copy2build.commands = $$QMAKE_COPY \"${QMAKE_FILE_IN}\" \"${QMAKE_FILE_OUT}\"
+ unix:copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ copy2build.name = COPY ${QMAKE_FILE_IN}
+ copy2build.CONFIG += no_link
+ QMAKE_EXTRA_COMPILERS += copy2build
+}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 000000000..8291acce4
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,8 @@
+TEMPLATE=subdirs
+SUBDIRS=\
+ options\
+ tools\
+ blackbox
+
+# dependencyFinder\
+
diff --git a/tests/auto/blackbox/blackbox.pro b/tests/auto/blackbox/blackbox.pro
new file mode 100644
index 000000000..40d1a5dea
--- /dev/null
+++ b/tests/auto/blackbox/blackbox.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+TARGET = testBlackbox
+DEPENDPATH += .
+DESTDIR = ../../../bin/
+INCLUDEPATH += . ../../../src/lib/
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+QT = core script testlib
+
+include(../../../src/lib/use.pri)
+
+SOURCES += \
+ tst_blackbox.cpp
+
diff --git a/tests/auto/blackbox/testdata/buildproperties_source/bp_source.qbp b/tests/auto/blackbox/testdata/buildproperties_source/bp_source.qbp
new file mode 100644
index 000000000..0d6cb5741
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildproperties_source/bp_source.qbp
@@ -0,0 +1,16 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "HelloWorld"
+
+ Depends { name: 'cpp' }
+
+ Group {
+ cpp.defines: ['WORLD="BANANA"']
+ files : [ "main.cpp" ]
+ }
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/buildproperties_source/main.cpp b/tests/auto/blackbox/testdata/buildproperties_source/main.cpp
new file mode 100644
index 000000000..fbae63cf0
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildproperties_source/main.cpp
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#ifndef WORLD
+# error WORLD is not defined
+#endif
+
+int main()
+{
+ puts("Hello " WORLD "!");
+}
diff --git a/tests/auto/blackbox/testdata/moc_h/bla.cpp b/tests/auto/blackbox/testdata/moc_h/bla.cpp
new file mode 100644
index 000000000..9045af23d
--- /dev/null
+++ b/tests/auto/blackbox/testdata/moc_h/bla.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "bla.h"
+
+int main()
+{
+ MyObject obj;
+ obj.setObjectName("I am the object!");
+}
diff --git a/tests/auto/blackbox/testdata/moc_h/bla_noqobject.h b/tests/auto/blackbox/testdata/moc_h/bla_noqobject.h
new file mode 100644
index 000000000..54e7cbd8f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/moc_h/bla_noqobject.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QObject>
+
+class MyObject : public QObject
+{
+};
+
diff --git a/tests/auto/blackbox/testdata/moc_h/bla_qobject.h b/tests/auto/blackbox/testdata/moc_h/bla_qobject.h
new file mode 100644
index 000000000..4f58ed10a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/moc_h/bla_qobject.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QObject>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+};
+
diff --git a/tests/auto/blackbox/testdata/moc_h/i.qbp b/tests/auto/blackbox/testdata/moc_h/i.qbp
new file mode 100644
index 000000000..0e103ecd9
--- /dev/null
+++ b/tests/auto/blackbox/testdata/moc_h/i.qbp
@@ -0,0 +1,18 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "i"
+
+ Depends {
+ name: "Qt.core"
+ }
+
+ files: [
+ "bla.cpp",
+ "bla.h"
+ ]
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/qrc/bla.cpp b/tests/auto/blackbox/testdata/qrc/bla.cpp
new file mode 100644
index 000000000..cbb85fa03
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qrc/bla.cpp
@@ -0,0 +1,42 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+int main()
+{
+ return 3;
+}
+
diff --git a/tests/auto/blackbox/testdata/qrc/bla.qrc b/tests/auto/blackbox/testdata/qrc/bla.qrc
new file mode 100644
index 000000000..46c93847e
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qrc/bla.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>stuff.txt</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/blackbox/testdata/qrc/i.qbp b/tests/auto/blackbox/testdata/qrc/i.qbp
new file mode 100644
index 000000000..11b9d1be3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qrc/i.qbp
@@ -0,0 +1,19 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "i"
+
+ Depends {
+ name: "Qt.core"
+ }
+
+ files: [
+ "bla.cpp",
+ "bla.qrc",
+ "stuff.txt"
+ ]
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/qrc/stuff.txt b/tests/auto/blackbox/testdata/qrc/stuff.txt
new file mode 100644
index 000000000..78f0d32c6
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qrc/stuff.txt
@@ -0,0 +1 @@
+a resource file
diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp b/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp
new file mode 100644
index 000000000..749b6c2d1
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "narf.h"
+#include "zort.h"
+#include <cstdio>
+
+int main(int argc, char **argv)
+{
+ printf("Hello World!\n");
+ Narf narf;
+ narf.shout();
+ Zort zort;
+ zort.shout();
+ return 0;
+}
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/project.qbp b/tests/auto/blackbox/testdata/trackAddFile/after/project.qbp
new file mode 100644
index 000000000..2e3a56102
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/after/project.qbp
@@ -0,0 +1,15 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ name: 'someapp'
+ type: 'application'
+ Depends { name: 'cpp' }
+ files: [
+ "main.cpp",
+ "narf.h", "narf.cpp",
+ "zort.h", "zort.cpp"
+ ]
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp b/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp
new file mode 100644
index 000000000..336ff5fda
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "zort.h"
+#include <cstdio>
+
+void Zort::shout()
+{
+ printf("ZORT!\n");
+}
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/zort.h b/tests/auto/blackbox/testdata/trackAddFile/after/zort.h
new file mode 100644
index 000000000..b94b70e27
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/after/zort.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef ZORT_H
+#define ZORT_H
+
+class Zort
+{
+public:
+ void shout();
+};
+
+#endif
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp b/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp
new file mode 100644
index 000000000..2fec2b365
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "narf.h"
+#include <cstdio>
+
+int main(int argc, char **argv)
+{
+ printf("Hello World!\n");
+ Narf narf;
+ narf.shout();
+ return 0;
+}
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp b/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp
new file mode 100644
index 000000000..5c04c9d7c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "narf.h"
+#include <cstdio>
+
+void Narf::shout()
+{
+ printf("NARF!\n");
+}
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/narf.h b/tests/auto/blackbox/testdata/trackAddFile/before/narf.h
new file mode 100644
index 000000000..afc73511f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/before/narf.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef NARF_H
+#define NARF_H
+
+class Narf
+{
+public:
+ void shout();
+};
+
+#endif
+
diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/project.qbp b/tests/auto/blackbox/testdata/trackAddFile/before/project.qbp
new file mode 100644
index 000000000..222788b6a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackAddFile/before/project.qbp
@@ -0,0 +1,11 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ name: 'someapp'
+ type: 'application'
+ Depends { name: 'cpp' }
+ files: [ "main.cpp", "narf.h", "narf.cpp" ]
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp b/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp
new file mode 100644
index 000000000..fb5a86b9c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include <cstdio>
+
+int foo();
+
+int main(int argc, char **argv)
+{
+ printf("there's %d foo here\n", foo());
+ return 0;
+}
+
diff --git a/tests/auto/blackbox/testdata/trackFileTags/after/project.qbp b/tests/auto/blackbox/testdata/trackFileTags/after/project.qbp
new file mode 100644
index 000000000..453658e98
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackFileTags/after/project.qbp
@@ -0,0 +1,51 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ name: 'someapp'
+ type: 'application'
+ Depends { name: 'cpp' }
+ Group {
+ files: [ "main.cpp" ]
+ fileTags: [ "foosource", "cpp" ]
+ }
+ }
+
+ Rule {
+ inputs: ["foosource"]
+ Artifact {
+ fileName: input.baseName + ".foo"
+ fileTags: ["foo"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = "var file = new TextFile(output.fileName, TextFile.WriteOnly);";
+ cmd.sourceCode += "file.truncate();"
+ cmd.sourceCode += "file.write(\"There's nothing to see here!\");"
+ cmd.sourceCode += "file.close();"
+ cmd.description = "generating something";
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["foo"]
+ Artifact {
+ fileName: input.baseName + "_foo.cpp"
+ fileTags: ["cpp"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = "var file = new TextFile(output.fileName, TextFile.WriteOnly);";
+ cmd.sourceCode += "file.truncate();";
+ cmd.sourceCode += "file.write(\"// There's nothing to see here!\\n\");";
+ cmd.sourceCode += "file.write(\"int foo() { return 15; }\\n\");";
+ cmd.sourceCode += "file.close();";
+ cmd.description = "generating something";
+ return cmd;
+ }
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp b/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp
new file mode 100644
index 000000000..fe6c86168
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include <cstdio>
+
+int main(int argc, char **argv)
+{
+ printf("there's no foo here\n");
+ return 0;
+}
+
diff --git a/tests/auto/blackbox/testdata/trackFileTags/before/project.qbp b/tests/auto/blackbox/testdata/trackFileTags/before/project.qbp
new file mode 100644
index 000000000..50400f157
--- /dev/null
+++ b/tests/auto/blackbox/testdata/trackFileTags/before/project.qbp
@@ -0,0 +1,51 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ name: 'someapp'
+ type: 'application'
+ Depends { name: 'cpp' }
+ Group {
+ files: [ "main.cpp" ]
+ fileTags: [ "cpp" ]
+ }
+ }
+
+ Rule {
+ inputs: ["foosource"]
+ Artifact {
+ fileName: input.baseName + ".foo"
+ fileTags: ["foo"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = "var file = new TextFile(output.fileName, TextFile.WriteOnly);";
+ cmd.sourceCode += "file.truncate();"
+ cmd.sourceCode += "file.write(\"There's nothing to see here!\");"
+ cmd.sourceCode += "file.close();"
+ cmd.description = "generating something";
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["foo"]
+ Artifact {
+ fileName: input.baseName + "_foo.cpp"
+ fileTags: ["cpp"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.sourceCode = "var file = new TextFile(output.fileName, TextFile.WriteOnly);";
+ cmd.sourceCode += "file.truncate();";
+ cmd.sourceCode += "file.write(\"// There's nothing to see here!\\n\");";
+ cmd.sourceCode += "file.write(\"int foo() { return 15; }\\n\");";
+ cmd.sourceCode += "file.close();";
+ cmd.description = "generating something";
+ return cmd;
+ }
+ }
+}
+
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
new file mode 100644
index 000000000..9bf6b7d87
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -0,0 +1,395 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QProcess>
+#include <QtCore/QFile>
+#include <QtCore/QCoreApplication>
+#include <QtTest/QtTest>
+
+#ifdef Q_OS_LINUX
+#include <unistd.h>
+#endif
+
+class TestBlackbox : public QObject
+{
+ Q_OBJECT
+ const QString testDataDir;
+ const QString testSourceDir;
+ const QString executableSuffix;
+ const QString objectSuffix;
+public:
+ TestBlackbox()
+ : testDataDir(QCoreApplication::applicationDirPath() + "/testdata"),
+ testSourceDir(QDir::cleanPath(SRCDIR "/testdata")),
+ #ifdef Q_OS_WIN
+ executableSuffix(QLatin1String(".exe")),
+ #else
+ executableSuffix(QLatin1String("")),
+ #endif
+ #ifdef Q_OS_WIN
+ objectSuffix(QLatin1String(".obj"))
+ #else
+ objectSuffix(QLatin1String(".o"))
+ #endif
+ {
+ }
+
+protected:
+
+ int runQbs(QStringList arguments = QStringList(), bool showOutput = false)
+ {
+ QString cmdLine = QCoreApplication::applicationDirPath() + "/qbs";
+ foreach (const QString &str, arguments)
+ cmdLine += QLatin1String(" \"") + str + QLatin1Char('"');
+
+ int r;
+ if (showOutput) {
+ r = system(cmdLine.toLatin1());
+ } else {
+ QProcess process;
+ process.start(cmdLine);
+ process.waitForStarted();
+ process.waitForFinished();
+ r = process.exitCode();
+ }
+ return r;
+ }
+
+ /*!
+ Recursive copy from directory to another.
+ Note that this updates the file stamps on Linux but not on Windows.
+ */
+ void ccp(const QString &from, const QString &to)
+ {
+ QDirIterator it(from, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
+ while (it.hasNext()) {
+ it.next();
+ QDir().mkpath(to + "/" + it.fileName());
+ ccp(from + "/" + it.fileName(), to + "/" + it.fileName());
+ }
+
+ QDirIterator it2(from, QDir::Files| QDir::NoDotAndDotDot | QDir::Hidden);
+ while (it2.hasNext()) {
+ it2.next();
+ const QString dstFilePath = to + "/" + it2.fileName();
+ if (QFile::exists(dstFilePath))
+ QFile::remove(dstFilePath);
+ QFile(from + "/" + it2.fileName()).copy(dstFilePath);
+ }
+ }
+
+ void rmDirR(const QString &dir)
+ {
+ QDirIterator it(dir, QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden);
+ while (it.hasNext()) {
+ QFile(it.next()).remove();
+ }
+
+ QDirIterator it2(dir, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
+ while (it2.hasNext()) {
+ rmDirR(it2.next());
+ }
+ QDir().rmdir(dir);
+ }
+
+ void touch(const QString &fn)
+ {
+ QFile f(fn);
+ int s = f.size();
+ if (!f.open(QFile::ReadWrite))
+ qFatal("cannot open file %s", qPrintable(fn));
+ f.resize(s+1);
+ f.resize(s);
+ }
+
+public slots:
+ void init()
+ {
+ rmDirR(testDataDir);
+ QDir().mkpath(testDataDir);
+ ccp(testSourceDir, testDataDir);
+ }
+
+ void cleanup()
+ {
+// rmDirR(testDataDir);
+ }
+
+private slots:
+ void build_project_data()
+ {
+ QTest::addColumn<QString>("projectSubDir");
+ QTest::addColumn<QString>("productFileName");
+ QTest::newRow("BPs in Sources")
+ << QString("buildproperties_source")
+ << QString("build/debug/HelloWorld");
+ }
+
+ void build_project()
+ {
+ QFETCH(QString, projectSubDir);
+ QFETCH(QString, productFileName);
+ if (!projectSubDir.startsWith('/'))
+ projectSubDir.prepend('/');
+ QDir::setCurrent(testDataDir + projectSubDir);
+ qDebug() << "currentdir set" << testDataDir + projectSubDir;
+ qDebug() << "currentdir" << QDir::currentPath();
+ productFileName.append(executableSuffix);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(QFile::exists(productFileName));
+ QVERIFY(QFile::remove(productFileName));
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(QFile::exists(productFileName));
+ }
+
+ void track_qrc()
+ {
+ QDir::setCurrent(testDataDir + "/qrc");
+ QCOMPARE(runQbs(), 0);
+ QString fileName = "build/debug/i" + executableSuffix;
+ QVERIFY(QFile(fileName).exists());
+ QDateTime dt = QFileInfo(fileName).lastModified();
+ QTest::qSleep(2020);
+ {
+ QFile f("stuff.txt");
+ f.remove();
+ QVERIFY(f.open(QFile::WriteOnly));
+ f.write("bla");
+ f.close();
+ }
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(QFile(fileName).exists());
+ QVERIFY(dt < QFileInfo(fileName).lastModified());
+ }
+
+ void track_qobject_change()
+ {
+ QDir::setCurrent(testDataDir + "/moc_h");
+ QFile("bla.h").remove();
+ QVERIFY(QFile("bla_qobject.h").copy("bla.h"));
+ touch("bla.h");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(QFile("build/debug/i" + executableSuffix).exists());
+ QString moc_bla_objectFileName = "build/debug/.obj/i/GeneratedFiles/i/moc_bla" + objectSuffix;
+ QVERIFY(QFile(moc_bla_objectFileName).exists());
+
+ QTest::qSleep(1000);
+ QFile("bla.h").remove();
+ QVERIFY(QFile("bla_noqobject.h").copy("bla.h"));
+ touch("bla.h");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(QFile("build/debug/i" + executableSuffix).exists());
+ QVERIFY(!QFile(moc_bla_objectFileName).exists());
+ }
+
+ void trackAddFile()
+ {
+ QProcess process;
+ QList<QByteArray> output;
+ QDir::setCurrent(testDataDir + "/trackAddFile");
+ if (QFile::exists("work"))
+ rmDirR("work");
+ QDir().mkdir("work");
+ ccp("before", "work");
+ QDir::setCurrent(testDataDir + "/trackAddFile/work");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!");
+ QString unchangedObjectFile = "build/debug/someapp/narf" + objectSuffix;
+ QDateTime unchangedObjectFileTime1 = QFileInfo(unchangedObjectFile).lastModified();
+
+ QTest::qWait(1000); // for file systems with low resolution timestamps
+ ccp("../after", ".");
+ touch("project.qbp");
+ touch("main.cpp");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "ZORT!");
+
+ // the object file of the untouched source should not have changed
+ QDateTime unchangedObjectFileTime2 = QFileInfo(unchangedObjectFile).lastModified();
+ QCOMPARE(unchangedObjectFileTime1, unchangedObjectFileTime2);
+ }
+
+ void trackRemoveFile()
+ {
+ QProcess process;
+ QList<QByteArray> output;
+ QDir::setCurrent(testDataDir + "/trackAddFile");
+ if (QFile::exists("work"))
+ rmDirR("work");
+ QDir().mkdir("work");
+ ccp("before", "work");
+ ccp("after", "work");
+ QDir::setCurrent(testDataDir + "/trackAddFile/work");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "ZORT!");
+ QString unchangedObjectFile = "build/debug/someapp/narf" + objectSuffix;
+ QDateTime unchangedObjectFileTime1 = QFileInfo(unchangedObjectFile).lastModified();
+
+ QTest::qWait(1000); // for file systems with low resolution timestamps
+ QFile::remove("project.qbp");
+ QFile::remove("main.cpp");
+ ccp("../before/project.qbp", ".");
+ ccp("../before/main.cpp", ".");
+ QFile::copy("../before/project.qbp", "project.qbp");
+ QFile::copy("../before/main.cpp", "main.cpp");
+ QVERIFY(QFile::remove("zort.h"));
+ QVERIFY(QFile::remove("zort.cpp"));
+ touch("main.cpp");
+ touch("project.qbp");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!");
+ QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!");
+
+ // the object file of the untouched source should not have changed
+ QDateTime unchangedObjectFileTime2 = QFileInfo(unchangedObjectFile).lastModified();
+ QCOMPARE(unchangedObjectFileTime1, unchangedObjectFileTime2);
+
+ // the object file for the removed cpp file should have vanished too
+ QCOMPARE(QFile::exists("build/debug/someapp/zort" + objectSuffix), false);
+ }
+
+ void trackAddFileTag()
+ {
+ QProcess process;
+ QList<QByteArray> output;
+ QDir::setCurrent(testDataDir + "/trackFileTags");
+ if (QFile::exists("work"))
+ rmDirR("work");
+ QDir().mkdir("work");
+ ccp("before", "work");
+ QDir::setCurrent(testDataDir + "/trackFileTags/work");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "there's no foo here");
+
+ QTest::qWait(1000); // for file systems with low resolution timestamps
+ ccp("../after", ".");
+ touch("main.cpp");
+ touch("project.qbp");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "there's 15 foo here");
+ }
+
+ void trackRemoveFileTag()
+ {
+ QProcess process;
+ QList<QByteArray> output;
+ QDir::setCurrent(testDataDir + "/trackFileTags");
+ if (QFile::exists("work"))
+ rmDirR("work");
+ QDir().mkdir("work");
+ ccp("after", "work");
+ QDir::setCurrent(testDataDir + "/trackFileTags/work");
+ QCOMPARE(runQbs(), 0);
+
+ // check if the artifacts are here that will become stale in the 2nd step
+ QCOMPARE(QFile::exists("build/debug/.obj/someapp/main_foo" + objectSuffix), true);
+ QCOMPARE(QFile::exists("build/debug/main_foo.cpp"), true);
+ QCOMPARE(QFile::exists("build/debug/main.foo"), true);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "there's 15 foo here");
+
+ QTest::qWait(1000); // for file systems with low resolution timestamps
+ ccp("../before", ".");
+ touch("main.cpp");
+ touch("project.qbp");
+ QCOMPARE(runQbs(), 0);
+
+ process.start("build/debug/someapp");
+ QVERIFY(process.waitForStarted());
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+ output = process.readAllStandardOutput().split('\n');
+ QCOMPARE(output.takeFirst().trimmed().constData(), "there's no foo here");
+
+ // check if stale artifacts have been removed
+ QCOMPARE(QFile::exists("build/debug/someapp/main_foo" + objectSuffix), false);
+ QCOMPARE(QFile::exists("build/debug/someapp/main_foo.cpp"), false);
+ QCOMPARE(QFile::exists("build/debug/someapp/main.foo"), false);
+ }
+
+};
+
+QTEST_MAIN(TestBlackbox)
+
+#include "tst_blackbox.moc"
diff --git a/tests/auto/dependencyFinder/dependencyFinder.pro b/tests/auto/dependencyFinder/dependencyFinder.pro
new file mode 100644
index 000000000..7ecd2cbe4
--- /dev/null
+++ b/tests/auto/dependencyFinder/dependencyFinder.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET = testDependencyFinder
+DEPENDPATH += .
+INCLUDEPATH += . ../../../src/lib/
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+QT = core script testlib
+
+SOURCES += \
+ tst_dependencyFinder.cpp
diff --git a/tests/auto/dependencyFinder/order_basic1.qbs b/tests/auto/dependencyFinder/order_basic1.qbs
new file mode 100644
index 000000000..5a8529b80
--- /dev/null
+++ b/tests/auto/dependencyFinder/order_basic1.qbs
@@ -0,0 +1,4 @@
+Project {
+ foo: bar
+ bar: 2
+}
diff --git a/tests/auto/dependencyFinder/order_basic2.qbs b/tests/auto/dependencyFinder/order_basic2.qbs
new file mode 100644
index 000000000..8c0979870
--- /dev/null
+++ b/tests/auto/dependencyFinder/order_basic2.qbs
@@ -0,0 +1,5 @@
+Project {
+ bar: car
+ foo: bar
+ car: 1
+}
diff --git a/tests/auto/dependencyFinder/order_complex1.qbs b/tests/auto/dependencyFinder/order_complex1.qbs
new file mode 100644
index 000000000..aba10cacf
--- /dev/null
+++ b/tests/auto/dependencyFinder/order_complex1.qbs
@@ -0,0 +1,8 @@
+Project {
+ bar: car + foo + def
+ foo: def
+ car: foo + abc + blub
+ abc: foo + blub
+ def: 12 + blub
+ blub: 24
+}
diff --git a/tests/auto/dependencyFinder/order_nodeps.qbs b/tests/auto/dependencyFinder/order_nodeps.qbs
new file mode 100644
index 000000000..54cecaf19
--- /dev/null
+++ b/tests/auto/dependencyFinder/order_nodeps.qbs
@@ -0,0 +1,4 @@
+Project {
+ foo: 1
+ bar: 2
+}
diff --git a/tests/auto/dependencyFinder/test1.qbs b/tests/auto/dependencyFinder/test1.qbs
new file mode 100644
index 000000000..dd0e11325
--- /dev/null
+++ b/tests/auto/dependencyFinder/test1.qbs
@@ -0,0 +1,16 @@
+Module {
+ includePaths: foo + abc.def
+ foo: bar
+
+ car: {
+ var x = 12
+ x = 13
+ var aaa = function aa(x1, x2) {
+ function bbb() { bbb() }
+ x = x1 + x2 + x2.def
+ aa(x1, x2)
+ bbb();
+ }
+ return aaa(x, includePaths)
+ }
+}
diff --git a/tests/auto/dependencyFinder/tst_dependencyFinder.cpp b/tests/auto/dependencyFinder/tst_dependencyFinder.cpp
new file mode 100644
index 000000000..9c2ac693e
--- /dev/null
+++ b/tests/auto/dependencyFinder/tst_dependencyFinder.cpp
@@ -0,0 +1,569 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptProgram>
+
+using namespace QmlJS::AST;
+
+class Function
+{
+public:
+ QString name;
+ QString code;
+};
+
+class Property
+{
+public:
+ QString name;
+ QString code;
+ QList<QStringList> dependencies;
+ QList<QStringList> sideEffects;
+};
+
+class Object
+{
+public:
+ QString prototype;
+ QList<Object> objects;
+ QHash<QString, Property> properties;
+ QHash<QString, Function> functions;
+};
+
+template <typename T>
+static QString textOf(const QString &source, T *node)
+{
+ return source.mid(node->firstSourceLocation().begin(), node->lastSourceLocation().end() - node->firstSourceLocation().begin());
+}
+
+static QList<QStringList> stripLocals(const QList<QStringList> &deps, const QStringList &locals)
+{
+ QList<QStringList> result;
+ foreach (const QStringList &dep, deps) {
+ if (!locals.contains(dep.first()))
+ result.append(dep);
+ }
+ return result;
+}
+
+// run on a statement/expression to find its deps and side effect targets
+class DependencyFinder : protected QmlJS::AST::Visitor
+{
+public:
+ DependencyFinder();
+
+ void operator()(Node *node)
+ {
+ m_deps.clear();
+ m_sideEffects.clear();
+ m_locals.clear();
+ Node::accept(node, this);
+ m_deps = stripLocals(m_deps, m_locals);
+ m_sideEffects = stripLocals(m_sideEffects, m_locals);
+ }
+
+ QList<QStringList> dependencies() const
+ {
+ return m_deps;
+ }
+
+ QList<QStringList> sideEffects() const
+ {
+ return m_sideEffects;
+ }
+
+protected:
+ using Visitor::visit;
+
+ // local vars, not external deps
+ bool visit(VariableDeclaration *ast);
+ bool visit(FunctionDeclaration *ast);
+ bool visit(FunctionExpression *ast);
+
+ // deps
+ bool visit(IdentifierExpression *ast);
+ bool visit(FieldMemberExpression *ast);
+ bool visit(ArrayMemberExpression *ast);
+
+ // side effects
+ bool visit(BinaryExpression *ast);
+ bool visit(PreIncrementExpression *ast);
+ bool visit(PostIncrementExpression *ast);
+ bool visit(PreDecrementExpression *ast);
+ bool visit(PostDecrementExpression *ast);
+
+ void sideEffectOn(ExpressionNode *ast);
+
+private:
+ QList<QSOperator::Op> m_assigningOps;
+
+ QStringList m_locals;
+ QList<QStringList> m_deps;
+ QList<QStringList> m_sideEffects;
+};
+
+DependencyFinder::DependencyFinder()
+{
+ m_assigningOps << QSOperator::Assign
+ << QSOperator::InplaceAnd
+ << QSOperator::InplaceSub
+ << QSOperator::InplaceDiv
+ << QSOperator::InplaceAdd
+ << QSOperator::InplaceLeftShift
+ << QSOperator::InplaceMod
+ << QSOperator::InplaceMul
+ << QSOperator::InplaceOr
+ << QSOperator::InplaceRightShift
+ << QSOperator::InplaceURightShift
+ << QSOperator::InplaceXor;
+}
+
+bool DependencyFinder::visit(VariableDeclaration *ast)
+{
+ if (ast->name)
+ m_locals.append(ast->name->asString());
+ return true;
+}
+
+bool DependencyFinder::visit(FunctionDeclaration *ast)
+{
+ if (ast->name)
+ m_locals.append(ast->name->asString());
+ return visit(static_cast<FunctionExpression *>(ast));
+}
+
+bool DependencyFinder::visit(FunctionExpression *ast)
+{
+ const QStringList outerLocals = m_locals;
+ m_locals.clear();
+ m_locals += QLatin1String("arguments");
+ if (ast->name)
+ m_locals += ast->name->asString();
+ for (FormalParameterList *it = ast->formals; it; it = it->next) {
+ if (it->name)
+ m_locals += it->name->asString();
+ }
+
+ const QList<QStringList> outerDeps = m_deps;
+ const QList<QStringList> outerSideEffects = m_sideEffects;
+ m_deps.clear();
+ m_sideEffects.clear();
+
+ Node::accept(ast->body, this);
+
+ m_deps = stripLocals(m_deps, m_locals);
+ m_deps += outerDeps;
+
+ m_sideEffects = stripLocals(m_sideEffects, m_locals);
+ m_sideEffects += outerSideEffects;
+
+ m_locals = outerLocals;
+ return false;
+}
+
+bool DependencyFinder::visit(IdentifierExpression *ast)
+{
+ if (ast->name)
+ m_deps += QStringList() << ast->name->asString();
+ return true;
+}
+
+class GetMemberAccess : protected Visitor
+{
+ QStringList m_result;
+
+public:
+ // gets the longest static member access, i.e.
+ // foo.bar["abc"] -> foo,bar,abc
+ // foo.bar[aaa].def -> foo.bar
+ QStringList operator()(ExpressionNode *ast)
+ {
+ m_result.clear();
+ Node::accept(ast, this);
+ return m_result;
+ }
+
+protected:
+ bool preVisit(Node *ast)
+ {
+ if (cast<FieldMemberExpression *>(ast)
+ || cast<ArrayMemberExpression *>(ast)
+ || cast<IdentifierExpression *>(ast))
+ return true;
+ m_result.clear();
+ return false;
+ }
+
+ bool visit(FieldMemberExpression *ast)
+ {
+ if (ast->name) {
+ m_result.prepend(ast->name->asString());
+ return true;
+ }
+ m_result.clear();
+ return true;
+ }
+
+ bool visit(ArrayMemberExpression *ast)
+ {
+ if (StringLiteral *string = cast<StringLiteral *>(ast->expression)) {
+ m_result.prepend(string->value->asString());
+ return true;
+ }
+ m_result.clear();
+ return true;
+ }
+
+ bool visit(IdentifierExpression *ast)
+ {
+ if (ast->name) {
+ m_result.prepend(ast->name->asString());
+ return true;
+ }
+ m_result.clear();
+ return true;
+ }
+};
+
+bool DependencyFinder::visit(FieldMemberExpression *ast)
+{
+ const QStringList dep = GetMemberAccess()(ast);
+ if (!dep.isEmpty())
+ m_deps += dep;
+ return false;
+}
+
+bool DependencyFinder::visit(ArrayMemberExpression *ast)
+{
+ const QStringList dep = GetMemberAccess()(ast);
+ if (!dep.isEmpty())
+ m_deps += dep;
+ return false;
+}
+
+void DependencyFinder::sideEffectOn(ExpressionNode *ast)
+{
+ QStringList assignee = GetMemberAccess()(ast);
+ if (!assignee.isEmpty())
+ m_sideEffects += assignee;
+ // ### does this catch everything?
+}
+
+bool DependencyFinder::visit(BinaryExpression *ast)
+{
+ if (!m_assigningOps.contains(static_cast<QSOperator::Op>(ast->op)))
+ return true;
+
+ sideEffectOn(ast->left);
+
+ // need to collect dependencies regardless, consider a = b = c = d
+ return true;
+}
+
+bool DependencyFinder::visit(PreDecrementExpression *ast)
+{
+ sideEffectOn(ast->expression);
+ return true;
+}
+
+bool DependencyFinder::visit(PostDecrementExpression *ast)
+{
+ sideEffectOn(ast->base);
+ return true;
+}
+
+bool DependencyFinder::visit(PreIncrementExpression *ast)
+{
+ sideEffectOn(ast->expression);
+ return true;
+}
+
+bool DependencyFinder::visit(PostIncrementExpression *ast)
+{
+ sideEffectOn(ast->base);
+ return true;
+}
+
+static QHash<QString, Function> bindFunctions(const QString &source, UiObjectInitializer *ast)
+{
+ QHash<QString, Function> result;
+ for (UiObjectMemberList *it = ast->members; it; it = it->next) {
+ UiSourceElement *sourceElement = cast<UiSourceElement *>(it->member);
+ if (!sourceElement)
+ continue;
+ FunctionDeclaration *fdecl = cast<FunctionDeclaration *>(sourceElement->sourceElement);
+ if (!fdecl)
+ continue;
+
+ Function f;
+ if (!fdecl->name)
+ throw Exception("function decl without name");
+ f.name = fdecl->name->asString();
+ f.code = textOf(source, fdecl);
+ result.insert(f.name, f);
+ }
+ return result;
+}
+
+static QHash<QString, Property> bindProperties(const QString &source, UiObjectInitializer *ast)
+{
+ QHash<QString, Property> result;
+ for (UiObjectMemberList *it = ast->members; it; it = it->next) {
+ if (UiScriptBinding *scriptBinding = cast<UiScriptBinding *>(it->member)) {
+ Property p;
+ if (!scriptBinding->qualifiedId || !scriptBinding->qualifiedId->name || scriptBinding->qualifiedId->next)
+ throw Exception("script binding without name or name with dots");
+ p.name = scriptBinding->qualifiedId->name->asString();
+ p.code = textOf(source, scriptBinding->statement);
+ DependencyFinder finder;
+ finder(scriptBinding->statement);
+ p.dependencies = finder.dependencies();
+ p.sideEffects = finder.sideEffects();
+ result.insert(p.name, p);
+ }
+ }
+ return result;
+}
+
+static Object bindObject(const QString &source, UiObjectDefinition *ast);
+
+static QList<Object> bindObjects(const QString &source, UiObjectInitializer *ast)
+{
+ QList<Object> result;
+ for (UiObjectMemberList *it = ast->members; it; it = it->next) {
+ if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(it->member)) {
+ result += bindObject(source, objDef);
+ }
+ }
+ return result;
+}
+
+static Object bindObject(const QString &source, UiObjectDefinition *ast)
+{
+ Object result;
+
+ if (!ast->qualifiedTypeNameId || !ast->qualifiedTypeNameId->name || ast->qualifiedTypeNameId->next)
+ throw Exception("no prototype or prototype with dots");
+ result.prototype = ast->qualifiedTypeNameId->name->asString();
+
+ result.functions = bindFunctions(source, ast->initializer);
+ result.properties = bindProperties(source, ast->initializer);
+ result.objects = bindObjects(source, ast->initializer);
+
+ return result;
+}
+
+
+class Loader
+{
+public:
+ Object readFile(const QString &fileName)
+ {
+ Object emptyReturn;
+
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Couldn't open" << fileName;
+ return emptyReturn;
+ }
+
+ const QString code = QTextStream(&file).readAll();
+ QScopedPointer<QmlJS::Engine> engine(new QmlJS::Engine);
+ QScopedPointer<QmlJS::NodePool> nodePool(new QmlJS::NodePool(fileName, engine.data()));
+ QmlJS::Lexer lexer(engine.data());
+ lexer.setCode(code, 1);
+ QmlJS::Parser parser(engine.data());
+ parser.parse();
+ QList<QmlJS::DiagnosticMessage> parserMessages = parser.diagnosticMessages();
+ if (!parserMessages.isEmpty()) {
+ foreach (const QmlJS::DiagnosticMessage &msg, parserMessages)
+ qWarning() << fileName << ":" << msg.loc.startLine << ": " << msg.message;
+ return emptyReturn;
+ }
+
+ // extract dependencies without resolving them
+ UiObjectDefinition *rootDef = cast<UiObjectDefinition *>(parser.ast()->members->member);
+ if (!rootDef)
+ return emptyReturn;
+ return bindObject(code, rootDef);
+ }
+};
+
+class TestDepFinder : public QObject
+{
+ Q_OBJECT
+private slots:
+ void test1();
+ void evaluationOrder_data();
+ void evaluationOrder();
+};
+
+void TestDepFinder::test1()
+{
+ Loader loader;
+ Object object = loader.readFile(SRCDIR "test1.qbs");
+ QCOMPARE(object.properties.size(), 3);
+
+ Property includePaths = object.properties.value("includePaths");
+ QCOMPARE(includePaths.dependencies.size(), 2);
+ QCOMPARE(includePaths.dependencies.at(0), QStringList() << "foo");
+ QCOMPARE(includePaths.dependencies.at(1), QStringList() << "abc" << "def");
+ QVERIFY(includePaths.sideEffects.isEmpty());
+
+ Property foo = object.properties.value("foo");
+ QCOMPARE(foo.dependencies.size(), 1);
+ QCOMPARE(foo.dependencies.at(0), QStringList() << "bar");
+ QVERIFY(foo.sideEffects.isEmpty());
+
+ Property car = object.properties.value("car");
+ QCOMPARE(car.dependencies.size(), 1);
+ QCOMPARE(car.dependencies.at(0), QStringList() << "includePaths");
+ QVERIFY(car.sideEffects.isEmpty());
+}
+
+class ResolvedProperty
+{
+public:
+ typedef QSharedPointer<ResolvedProperty> Ptr;
+ const Object *object;
+ const Property *property;
+ QList<ResolvedProperty::Ptr> dependencies;
+};
+
+static QList<ResolvedProperty::Ptr> resolveProperties(const Object &object)
+{
+ QHash<QString, ResolvedProperty::Ptr> result;
+
+ // build initial resolved property list
+ foreach (const Property &property, object.properties) {
+ ResolvedProperty::Ptr resolvedProperty(new ResolvedProperty);
+ resolvedProperty->object = &object;
+ resolvedProperty->property = &property;
+ result.insert(property.name, resolvedProperty);
+ }
+
+ // add dependency links
+ QHashIterator<QString, ResolvedProperty::Ptr> it(result);
+ while (it.hasNext()) {
+ it.next();
+ ResolvedProperty::Ptr resolvedProperty = it.value();
+ foreach (const QStringList &dependency, resolvedProperty->property->dependencies) {
+ ResolvedProperty::Ptr rDepProp = result.value(dependency.first());
+ // ### TODO This needs serious extension:
+ // ### check globals (QScriptEngine), object.functions, parent objects?
+ if (!rDepProp) {
+ throw Exception(QString("property %1 has dependency on nonexistent property %2").arg(
+ it.key(), dependency.first()));
+ }
+ resolvedProperty->dependencies += rDepProp;
+ }
+ }
+
+ return result.values();
+}
+
+static void resolveDependencies(const ResolvedProperty::Ptr &property,
+ QList<ResolvedProperty::Ptr> *target,
+ QSet<ResolvedProperty::Ptr> *done,
+ QSet<ResolvedProperty::Ptr> *parents)
+{
+ if (done->contains(property))
+ return;
+ parents->insert(property);
+ foreach (const ResolvedProperty::Ptr &dep, property->dependencies) {
+ if (parents->contains(dep))
+ throw Exception("dependency cycle");
+ resolveDependencies(dep, target, done, parents);
+ }
+ target->append(property);
+ done->insert(property);
+ parents->remove(property);
+}
+
+static QList<ResolvedProperty::Ptr> sortForEvaluation(const QList<ResolvedProperty::Ptr> &input)
+{
+ QList<ResolvedProperty::Ptr> result;
+ QSet<ResolvedProperty::Ptr> done;
+ QSet<ResolvedProperty::Ptr> parents;
+
+ foreach (const ResolvedProperty::Ptr &property, input) {
+ resolveDependencies(property, &result, &done, &parents);
+ }
+
+ return result;
+}
+
+void TestDepFinder::evaluationOrder_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QStringList>("expectedOrder");
+ QTest::newRow("no dependencies")
+ << QString(SRCDIR "order_nodeps.qbs")
+ << (QStringList() << "foo" << "bar");
+ QTest::newRow("basic1")
+ << QString(SRCDIR "order_basic1.qbs")
+ << (QStringList() << "bar" << "foo");
+ QTest::newRow("basic2")
+ << QString(SRCDIR "order_basic2.qbs")
+ << (QStringList() << "car" << "bar" << "foo");
+ QTest::newRow("complex1")
+ << QString(SRCDIR "order_complex1.qbs")
+ << (QStringList() << "blub" << "def" << "foo" << "abc" << "car" << "bar");
+}
+
+void TestDepFinder::evaluationOrder()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QStringList, expectedOrder);
+
+ Loader loader;
+ Object object = loader.readFile(fileName);
+ QCOMPARE(object.properties.size(), expectedOrder.size());
+
+ QList<ResolvedProperty::Ptr> resolvedProperties = resolveProperties(object);
+ QList<ResolvedProperty::Ptr> evaluationOrder = sortForEvaluation(resolvedProperties);
+
+ for (int i = 0; i < evaluationOrder.size(); ++i) {
+ QCOMPARE(evaluationOrder[i]->property->name, expectedOrder[i]);
+ }
+}
+
+QTEST_MAIN(TestDepFinder)
+
+#include "tst_dependencyFinder.moc"
diff --git a/tests/auto/options/app.xml b/tests/auto/options/app.xml
new file mode 100644
index 000000000..7d4099f72
--- /dev/null
+++ b/tests/auto/options/app.xml
@@ -0,0 +1,5 @@
+<Project name='brickapp' >
+ <Product name='brick'>
+ <Using package="bricklib" />
+ </Product>
+</Project>
diff --git a/tests/auto/options/options.pro b/tests/auto/options/options.pro
new file mode 100644
index 000000000..384af7f40
--- /dev/null
+++ b/tests/auto/options/options.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+TARGET = testOptions
+DEPENDPATH += .
+INCLUDEPATH += . ../../../src/lib/
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+QT = core testlib
+
+include(../../../src/lib/use.pri)
+
+SOURCES += \
+ tst_options.cpp
diff --git a/tests/auto/options/tst_options.cpp b/tests/auto/options/tst_options.cpp
new file mode 100644
index 000000000..66ab824d7
--- /dev/null
+++ b/tests/auto/options/tst_options.cpp
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <tools/options.h>
+#include <tools/logger.h>
+#include <QtTest/QtTest>
+
+class TestOptions : public QObject
+{
+ Q_OBJECT
+private slots:
+
+ void test()
+ {
+ QStringList args;
+ args.append("-vvvk");
+ qbs::CommandLineOptions options;
+ options.readCommandLineArguments(args);
+ QCOMPARE(qbs::Logger::instance().level(), qbs::LoggerTrace);
+ QCOMPARE(options.command(), qbs::CommandLineOptions::BuildCommand);
+ QVERIFY(options.isKeepGoingSet());
+ }
+};
+
+QTEST_APPLESS_MAIN(TestOptions)
+
+#include "tst_options.moc"
diff --git a/tests/auto/tools/tools.pro b/tests/auto/tools/tools.pro
new file mode 100644
index 000000000..27cb2cbe9
--- /dev/null
+++ b/tests/auto/tools/tools.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+TARGET = testTools
+DEPENDPATH += .
+INCLUDEPATH += . ../../../src/lib/
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+QT = core testlib
+
+include(../../../src/lib/use.pri)
+
+SOURCES += \
+ tst_tools.cpp
diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp
new file mode 100644
index 000000000..b528ed82b
--- /dev/null
+++ b/tests/auto/tools/tst_tools.cpp
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <tools/fileinfo.h>
+#include <QtTest/QtTest>
+
+class TestFileInfo : public QObject
+{
+ Q_OBJECT
+private slots:
+
+ void testFileInfo()
+ {
+ QCOMPARE(qbs::FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
+ QCOMPARE(qbs::FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
+ QCOMPARE(qbs::FileInfo::path("abc"), QString("."));
+ QCOMPARE(qbs::FileInfo::path("/abc/lol"), QString("/abc"));
+ QVERIFY(!qbs::FileInfo::isAbsolute("bla/lol"));
+ QVERIFY(qbs::FileInfo::isAbsolute("/bla/lol"));
+#ifdef Q_OS_WIN
+ QVERIFY(qbs::FileInfo::isAbsolute("C:\\bla\\lol"));
+#endif
+ QCOMPARE(qbs::FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
+
+ }
+};
+
+QTEST_APPLESS_MAIN(TestFileInfo)
+
+#include "tst_tools.moc"
diff --git a/tests/manual/application/foo.c b/tests/manual/application/foo.c
new file mode 100644
index 000000000..2a0b103fd
--- /dev/null
+++ b/tests/manual/application/foo.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int some_c_function(int x)
+{
+ printf("Some C function has been called. (arg: %d)\n", x);
+ return 123;
+}
+
+
diff --git a/tests/manual/application/main.cpp b/tests/manual/application/main.cpp
new file mode 100644
index 000000000..5e4c65017
--- /dev/null
+++ b/tests/manual/application/main.cpp
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <cstdio>
+#include "object1.h"
+#include "object2.h"
+
+extern void someCustomFeature();
+extern "C" int some_c_function(int);
+
+class Object3 : public QObject
+{
+ Q_OBJECT
+};
+
+int main()
+{
+ Object1 obj1;
+ Object2 obj2;
+ Object3 obj3;
+ printf("Hello World\n");
+ someCustomFeature();
+ some_c_function(156);
+}
+
+#include "main.moc"
+
diff --git a/tests/manual/application/main_dbg.cpp b/tests/manual/application/main_dbg.cpp
new file mode 100644
index 000000000..d7578047d
--- /dev/null
+++ b/tests/manual/application/main_dbg.cpp
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <cstdio>
+#include "object1.h"
+#include "object2.h"
+
+extern void someCustomFeature();
+extern "C" int some_c_function(int);
+
+class Object3 : public QObject
+{
+ Q_OBJECT
+};
+
+int main()
+{
+ Object1 obj1;
+ Object2 obj2;
+ Object3 obj3;
+ printf("Hello World (debug version)\n");
+ someCustomFeature();
+ some_c_function(156);
+}
+
+#include "main_dbg.moc"
+
diff --git a/tests/manual/application/object1.cpp b/tests/manual/application/object1.cpp
new file mode 100644
index 000000000..85a5dea2c
--- /dev/null
+++ b/tests/manual/application/object1.cpp
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "object1.h"
+
+Object1::Object1(QObject *parent)
+ : QObject(parent)
+{}
+
diff --git a/tests/manual/application/object1.h b/tests/manual/application/object1.h
new file mode 100644
index 000000000..5acd76240
--- /dev/null
+++ b/tests/manual/application/object1.h
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef OBJECT1_H
+#define OBJECT1_H
+#include <QObject>
+
+class Object1 : public QObject
+{
+ Q_OBJECT
+public:
+ Object1(QObject *parent = 0);
+};
+
+#endif
+
diff --git a/tests/manual/application/object2.cpp b/tests/manual/application/object2.cpp
new file mode 100644
index 000000000..d67c3a838
--- /dev/null
+++ b/tests/manual/application/object2.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "object2.h"
+
+Object2::Object2(QObject *parent)
+ : QObject(parent)
+{}
+
+
+#include "moc_object2.cpp"
+
diff --git a/tests/manual/application/object2.h b/tests/manual/application/object2.h
new file mode 100644
index 000000000..41fd9f29b
--- /dev/null
+++ b/tests/manual/application/object2.h
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef OBJECT2_H
+#define OBJECT2_H
+#include <QtCore/QObject>
+
+class Object2 : public QObject
+{
+ Q_OBJECT
+public:
+ Object2(QObject *parent = 0);
+};
+
+#endif
+
diff --git a/tests/manual/application/somecustomfeature.cpp b/tests/manual/application/somecustomfeature.cpp
new file mode 100644
index 000000000..6a1972ac3
--- /dev/null
+++ b/tests/manual/application/somecustomfeature.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <cstdio>
+
+void someCustomFeature()
+{
+ printf("void someCustomFeature() called\n");
+}
+
diff --git a/tests/manual/application/test.qbp b/tests/manual/application/test.qbp
new file mode 100644
index 000000000..4e993bedf
--- /dev/null
+++ b/tests/manual/application/test.qbp
@@ -0,0 +1,43 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "QtHelloWorld"
+
+ Depends {
+ name: "Qt"
+ submodules: ["gui"]
+ }
+
+ property bool someCustomFeature: true
+
+ Group {
+ condition: qbs.debugInformation === false
+ files : [ "main.cpp" ]
+ }
+
+ Group {
+ condition: qbs.debugInformation === true
+ files : [ "main_dbg.cpp" ]
+ }
+
+ files : [
+ "object1.h",
+ "object1.cpp",
+ "object2.cpp",
+ "foo.c"
+ ]
+
+ Group {
+ files: [ "object2.h" ]
+ fileTags: [ "hpp" ]
+ }
+
+ Group {
+ condition: someCustomFeature == true
+ files: [ "somecustomfeature.cpp" ]
+ }
+ }
+}
+
diff --git a/tests/manual/baseProperties/Bar.qbs b/tests/manual/baseProperties/Bar.qbs
new file mode 100644
index 000000000..c25541dc4
--- /dev/null
+++ b/tests/manual/baseProperties/Bar.qbs
@@ -0,0 +1,6 @@
+import qbs.base 1.0
+
+Product {
+ Depends { name: "cpp" }
+ cpp.defines: ["FROM_BAR"]
+}
diff --git a/tests/manual/baseProperties/Foo.qbs b/tests/manual/baseProperties/Foo.qbs
new file mode 100644
index 000000000..d3da538dd
--- /dev/null
+++ b/tests/manual/baseProperties/Foo.qbs
@@ -0,0 +1,7 @@
+import qbs.base 1.0
+
+Bar {
+ type: "application"
+ cpp.defines: base.concat(["FROM_FOO"])
+}
+
diff --git a/tests/manual/baseProperties/main.cpp b/tests/manual/baseProperties/main.cpp
new file mode 100644
index 000000000..c791c18e1
--- /dev/null
+++ b/tests/manual/baseProperties/main.cpp
@@ -0,0 +1,51 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef FROM_FOO
+#error FROM_FOO missing!
+#endif
+#ifndef FROM_BAR
+#error FROM_BAR missing!
+#endif
+#ifndef FROM_PRJ
+#error FROM_PRJ missing!
+#endif
+
+int main()
+{
+ return 0;
+}
+
diff --git a/tests/manual/baseProperties/prj.qbp b/tests/manual/baseProperties/prj.qbp
new file mode 100644
index 000000000..e7800da69
--- /dev/null
+++ b/tests/manual/baseProperties/prj.qbp
@@ -0,0 +1,9 @@
+import qbs.base 1.0
+
+Project {
+ Foo {
+ cpp.defines: base.concat(["FROM_PRJ"]);
+ files: "main.cpp"
+ }
+}
+
diff --git a/tests/manual/codegen/codegen.qbp b/tests/manual/codegen/codegen.qbp
new file mode 100644
index 000000000..e1f7be3d4
--- /dev/null
+++ b/tests/manual/codegen/codegen.qbp
@@ -0,0 +1,42 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+
+Project {
+ property string name: 'codegen'
+
+ Product {
+ type: 'application'
+ name: project.name
+ Group {
+ files: 'foo.txt'
+ fileTags: ['text']
+ }
+ Depends { name: 'cpp' }
+ }
+
+ Rule {
+ inputs: ['text']
+ Artifact {
+ fileTags: ['cpp']
+ fileName: input.baseName + '.cpp'
+ }
+ prepare: {
+ var code = 'int main(int, char **) { return 0; }'
+ var args = ['echo ' + code + '>' + output.fileName]
+ var cmd
+ if (product.modules.qbs.targetOS == 'windows') {
+ cmd = new Command('c:/Windows/System32/cmd.exe', ['/C'].concat(args));
+ } else {
+ args[0] = args[0].replace(/\(/g, '\\(')
+ args[0] = args[0].replace(/\)/g, '\\)')
+ args[0] = args[0].replace(/;/g, '\\;')
+ cmd = new Command('/bin/sh', ['-c'].concat(args))
+ }
+ cmd.description = 'generate\t' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'codegen';
+ return cmd;
+ }
+ }
+
+}
+
diff --git a/tests/manual/codegen/foo.txt b/tests/manual/codegen/foo.txt
new file mode 100644
index 000000000..557db03de
--- /dev/null
+++ b/tests/manual/codegen/foo.txt
@@ -0,0 +1 @@
+Hello World
diff --git a/tests/manual/collidingmice/collidingmice.qbp b/tests/manual/collidingmice/collidingmice.qbp
new file mode 100644
index 000000000..b6b875ed1
--- /dev/null
+++ b/tests/manual/collidingmice/collidingmice.qbp
@@ -0,0 +1,18 @@
+import qbs.base 1.0
+
+Project {
+ Application {
+ name : "CollidingMice"
+ destination: "bin"
+
+ Depends { name: "Qt.gui" }
+
+ files : [
+ "main.cpp",
+ "mouse.cpp",
+ "mouse.h",
+ "mice.qrc"
+ ]
+ }
+}
+
diff --git a/tests/manual/collidingmice/images/cheese.jpg b/tests/manual/collidingmice/images/cheese.jpg
new file mode 100644
index 000000000..dea5795fd
--- /dev/null
+++ b/tests/manual/collidingmice/images/cheese.jpg
Binary files differ
diff --git a/tests/manual/collidingmice/main.cpp b/tests/manual/collidingmice/main.cpp
new file mode 100644
index 000000000..714b6fecf
--- /dev/null
+++ b/tests/manual/collidingmice/main.cpp
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "mouse.h"
+
+#include <QtGui>
+
+#include <math.h>
+
+static const int MouseCount = 7;
+
+//! [0]
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
+//! [0]
+
+//! [1]
+ QGraphicsScene scene;
+ scene.setSceneRect(-300, -300, 600, 600);
+//! [1] //! [2]
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+//! [2]
+
+//! [3]
+ for (int i = 0; i < MouseCount; ++i) {
+ Mouse *mouse = new Mouse;
+ mouse->setPos(::sin((i * 6.28) / MouseCount) * 200,
+ ::cos((i * 6.28) / MouseCount) * 200);
+ scene.addItem(mouse);
+ }
+//! [3]
+
+//! [4]
+ QGraphicsView view(&scene);
+ view.setRenderHint(QPainter::Antialiasing);
+ view.setBackgroundBrush(QPixmap(":/images/cheese.jpg"));
+//! [4] //! [5]
+ view.setCacheMode(QGraphicsView::CacheBackground);
+ view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+ view.setDragMode(QGraphicsView::ScrollHandDrag);
+//! [5] //! [6]
+ view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice"));
+ view.resize(400, 300);
+ view.show();
+
+ QTimer timer;
+ QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
+ timer.start(1000 / 33);
+
+ return app.exec();
+}
+//! [6]
diff --git a/tests/manual/collidingmice/mice.qrc b/tests/manual/collidingmice/mice.qrc
new file mode 100644
index 000000000..accdb4d0a
--- /dev/null
+++ b/tests/manual/collidingmice/mice.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/" >
+ <file>images/cheese.jpg</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/collidingmice/mouse.cpp b/tests/manual/collidingmice/mouse.cpp
new file mode 100644
index 000000000..f14627ad1
--- /dev/null
+++ b/tests/manual/collidingmice/mouse.cpp
@@ -0,0 +1,197 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "mouse.h"
+
+#include <QGraphicsScene>
+#include <QPainter>
+#include <QStyleOption>
+
+#include <math.h>
+
+static const double Pi = 3.14159265358979323846264338327950288419717;
+static double TwoPi = 2.0 * Pi;
+
+static qreal normalizeAngle(qreal angle)
+{
+ while (angle < 0)
+ angle += TwoPi;
+ while (angle > TwoPi)
+ angle -= TwoPi;
+ return angle;
+}
+
+//! [0]
+Mouse::Mouse()
+ : angle(0), speed(0), mouseEyeDirection(0),
+ color(qrand() % 256, qrand() % 256, qrand() % 256)
+{
+ setRotation(qrand() % (360 * 16));
+}
+//! [0]
+
+//! [1]
+QRectF Mouse::boundingRect() const
+{
+ qreal adjust = 0.5;
+ return QRectF(-18 - adjust, -22 - adjust,
+ 36 + adjust, 60 + adjust);
+}
+//! [1]
+
+//! [2]
+QPainterPath Mouse::shape() const
+{
+ QPainterPath path;
+ path.addRect(-10, -20, 20, 40);
+ return path;
+}
+//! [2]
+
+//! [3]
+void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ // Body
+ painter->setBrush(color);
+ painter->drawEllipse(-10, -20, 20, 40);
+
+ // Eyes
+ painter->setBrush(Qt::white);
+ painter->drawEllipse(-10, -17, 8, 8);
+ painter->drawEllipse(2, -17, 8, 8);
+
+ // Nose
+ painter->setBrush(Qt::black);
+ painter->drawEllipse(QRectF(-2, -22, 4, 4));
+
+ // Pupils
+ painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4));
+ painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4));
+
+ // Ears
+ painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red);
+ painter->drawEllipse(-17, -12, 16, 16);
+ painter->drawEllipse(1, -12, 16, 16);
+
+ // Tail
+ QPainterPath path(QPointF(0, 20));
+ path.cubicTo(-5, 22, -5, 22, 0, 25);
+ path.cubicTo(5, 27, 5, 32, 0, 30);
+ path.cubicTo(-5, 32, -5, 42, 0, 35);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawPath(path);
+}
+//! [3]
+
+//! [4]
+void Mouse::advance(int step)
+{
+ if (!step)
+ return;
+//! [4]
+ // Don't move too far away
+//! [5]
+ QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0));
+ if (lineToCenter.length() > 150) {
+ qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length());
+ if (lineToCenter.dy() < 0)
+ angleToCenter = TwoPi - angleToCenter;
+ angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2);
+
+ if (angleToCenter < Pi && angleToCenter > Pi / 4) {
+ // Rotate left
+ angle += (angle < -Pi / 2) ? 0.25 : -0.25;
+ } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) {
+ // Rotate right
+ angle += (angle < Pi / 2) ? 0.25 : -0.25;
+ }
+ } else if (::sin(angle) < 0) {
+ angle += 0.25;
+ } else if (::sin(angle) > 0) {
+ angle -= 0.25;
+//! [5] //! [6]
+ }
+//! [6]
+
+ // Try not to crash with any other mice
+//! [7]
+ QList<QGraphicsItem *> dangerMice = scene()->items(QPolygonF()
+ << mapToScene(0, 0)
+ << mapToScene(-30, -50)
+ << mapToScene(30, -50));
+ foreach (QGraphicsItem *item, dangerMice) {
+ if (item == this)
+ continue;
+
+ QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0));
+ qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length());
+ if (lineToMouse.dy() < 0)
+ angleToMouse = TwoPi - angleToMouse;
+ angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2);
+
+ if (angleToMouse >= 0 && angleToMouse < Pi / 2) {
+ // Rotate right
+ angle += 0.5;
+ } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) {
+ // Rotate left
+ angle -= 0.5;
+//! [7] //! [8]
+ }
+//! [8] //! [9]
+ }
+//! [9]
+
+ // Add some random movement
+//! [10]
+ if (dangerMice.size() > 1 && (qrand() % 10) == 0) {
+ if (qrand() % 1)
+ angle += (qrand() % 100) / 500.0;
+ else
+ angle -= (qrand() % 100) / 500.0;
+ }
+//! [10]
+
+//! [11]
+ speed += (-50 + qrand() % 100) / 100.0;
+
+ qreal dx = ::sin(angle) * 10;
+ mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5;
+
+ setRotation(rotation() + dx);
+ setPos(mapToParent(0, -(3 + sin(speed) * 3)));
+}
+//! [11]
diff --git a/tests/manual/collidingmice/mouse.h b/tests/manual/collidingmice/mouse.h
new file mode 100644
index 000000000..f06a626d8
--- /dev/null
+++ b/tests/manual/collidingmice/mouse.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef MOUSE_H
+#define MOUSE_H
+
+#include <QGraphicsItem>
+
+//! [0]
+class Mouse : public QGraphicsItem
+{
+public:
+ Mouse();
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget);
+
+protected:
+ void advance(int step);
+
+private:
+ qreal angle;
+ qreal speed;
+ qreal mouseEyeDirection;
+ QColor color;
+};
+//! [0]
+
+#endif
diff --git a/tests/manual/hello/hello.qbp b/tests/manual/hello/hello.qbp
new file mode 100644
index 000000000..d73a6fdb8
--- /dev/null
+++ b/tests/manual/hello/hello.qbp
@@ -0,0 +1,24 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ Depends { name: 'cpp' }
+
+ type: 'application'
+ name: 'HelloWorld'
+
+ cpp.defines: ['SOMETHING']
+ //cpp.applicationLinker.debugInformation: false
+
+ Group {
+ cpp.defines: outer.concat(['HAVE_MAIN_CPP', cpp.debugInformation ? '_DEBUG' : '_RELEASE'])
+ prefix: "src/"
+ files: [
+ 'main.cpp',
+ 'foo.h',
+ 'foo.cpp'
+ ]
+ }
+ }
+}
+
diff --git a/tests/manual/hello/src/foo.cpp b/tests/manual/hello/src/foo.cpp
new file mode 100644
index 000000000..6d2828af9
--- /dev/null
+++ b/tests/manual/hello/src/foo.cpp
@@ -0,0 +1,5 @@
+int someUsefulFunction()
+{
+ return 156;
+}
+
diff --git a/tests/manual/hello/src/foo.h b/tests/manual/hello/src/foo.h
new file mode 100644
index 000000000..1e4fd7b94
--- /dev/null
+++ b/tests/manual/hello/src/foo.h
@@ -0,0 +1,7 @@
+#ifndef FOO_H
+#define FOO_H
+
+int someUsefulFunction();
+
+#endif
+
diff --git a/tests/manual/hello/src/main.cpp b/tests/manual/hello/src/main.cpp
new file mode 100644
index 000000000..c08389c00
--- /dev/null
+++ b/tests/manual/hello/src/main.cpp
@@ -0,0 +1,17 @@
+#include "foo.h"
+#include <stdio.h>
+
+#ifndef HAVE_MAIN_CPP
+# error missing define HAVE_MAIN_CPP
+#endif
+
+int main()
+{
+ someUsefulFunction();
+#ifdef _DEBUG
+ puts("Hello World! (debug version)");
+#else
+ puts("Hello World! (release version)");
+#endif
+}
+
diff --git a/tests/manual/inheritModuleSearchPath/Foo.qbs b/tests/manual/inheritModuleSearchPath/Foo.qbs
new file mode 100644
index 000000000..d52dabbc9
--- /dev/null
+++ b/tests/manual/inheritModuleSearchPath/Foo.qbs
@@ -0,0 +1,7 @@
+import qbs.base 1.0
+
+Product {
+ type: "application"
+ Depends { name: 'bli' }
+}
+
diff --git a/tests/manual/inheritModuleSearchPath/main.cpp b/tests/manual/inheritModuleSearchPath/main.cpp
new file mode 100644
index 000000000..7382cd2dd
--- /dev/null
+++ b/tests/manual/inheritModuleSearchPath/main.cpp
@@ -0,0 +1,9 @@
+#ifndef HAVE_BLI
+#error HAVE_BLI missing!
+#endif
+
+int main()
+{
+ return 0;
+}
+
diff --git a/tests/manual/inheritModuleSearchPath/prj.qbp b/tests/manual/inheritModuleSearchPath/prj.qbp
new file mode 100644
index 000000000..8f72cf5be
--- /dev/null
+++ b/tests/manual/inheritModuleSearchPath/prj.qbp
@@ -0,0 +1,10 @@
+import qbs.base 1.0
+
+Project {
+ moduleSearchPaths: "subdir"
+// moduleSearchPaths: ["subdir"]
+ Foo {
+ files: "main.cpp"
+ }
+}
+
diff --git a/tests/manual/inheritModuleSearchPath/subdir/bli/m.qbs b/tests/manual/inheritModuleSearchPath/subdir/bli/m.qbs
new file mode 100644
index 000000000..e33dab9a7
--- /dev/null
+++ b/tests/manual/inheritModuleSearchPath/subdir/bli/m.qbs
@@ -0,0 +1,7 @@
+import qbs.base 1.0
+
+Module {
+ Depends {name : "cpp" }
+ cpp.defines: ["HAVE_BLI"]
+}
+
diff --git a/tests/manual/lib_samesource/lib.qbp b/tests/manual/lib_samesource/lib.qbp
new file mode 100644
index 000000000..36ecb4d19
--- /dev/null
+++ b/tests/manual/lib_samesource/lib.qbp
@@ -0,0 +1,22 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name : "HelloWorld"
+ Depends { name: 'cpp' }
+ Group {
+ files : [ "main.cpp" ]
+ }
+ }
+
+ Product {
+ type: "staticlibrary"
+ name : "HelloWorld"
+ Depends { name: 'cpp' }
+ Group {
+ files : [ "main.cpp" ]
+ }
+ }
+}
+
diff --git a/tests/manual/lib_samesource/main.cpp b/tests/manual/lib_samesource/main.cpp
new file mode 100644
index 000000000..f45acac3b
--- /dev/null
+++ b/tests/manual/lib_samesource/main.cpp
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+int main()
+{
+ puts("Hello WOrld!");
+}
diff --git a/tests/manual/lib_subdir/app/app.qbs b/tests/manual/lib_subdir/app/app.qbs
new file mode 100644
index 000000000..4f7e959c5
--- /dev/null
+++ b/tests/manual/lib_subdir/app/app.qbs
@@ -0,0 +1,10 @@
+import qbs.base 1.0
+
+Product {
+ type: "application"
+ name : "HelloWorld"
+ files : [ "main.cpp" ]
+ Depends { name: "cpp" }
+ Depends { name: "lol" }
+}
+
diff --git a/tests/manual/lib_subdir/app/main.cpp b/tests/manual/lib_subdir/app/main.cpp
new file mode 100644
index 000000000..3e1f2fd27
--- /dev/null
+++ b/tests/manual/lib_subdir/app/main.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+int bla();
+int main()
+{
+ return bla();
+}
diff --git a/tests/manual/lib_subdir/lib/lib.cpp b/tests/manual/lib_subdir/lib/lib.cpp
new file mode 100644
index 000000000..f7d886a31
--- /dev/null
+++ b/tests/manual/lib_subdir/lib/lib.cpp
@@ -0,0 +1,48 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#ifndef CRUCIAL_DEFINE
+# error CRUCIAL_DEFINE not defined
+#endif
+
+int bla()
+{
+ puts("Hello WOrld!");
+ return 2;
+}
diff --git a/tests/manual/lib_subdir/lib/lib.qbs b/tests/manual/lib_subdir/lib/lib.qbs
new file mode 100644
index 000000000..22ef0535d
--- /dev/null
+++ b/tests/manual/lib_subdir/lib/lib.qbs
@@ -0,0 +1,10 @@
+import qbs.base 1.0
+
+Product {
+ type: "staticlibrary"
+ name: "lol"
+ files: [ "lib.cpp" ]
+ cpp.defines: ['CRUCIAL_DEFINE']
+ Depends { name: 'cpp' }
+}
+
diff --git a/tests/manual/lib_subdir/lib_subdir.qbp b/tests/manual/lib_subdir/lib_subdir.qbp
new file mode 100644
index 000000000..71afd646f
--- /dev/null
+++ b/tests/manual/lib_subdir/lib_subdir.qbp
@@ -0,0 +1,8 @@
+import qbs.base 1.0
+Project {
+ references: [
+ "app/app.qbs",
+ "lib/lib.qbs"
+ ]
+}
+
diff --git a/tests/manual/link_dynamiclib/lib1.cpp b/tests/manual/link_dynamiclib/lib1.cpp
new file mode 100644
index 000000000..7e2632c02
--- /dev/null
+++ b/tests/manual/link_dynamiclib/lib1.cpp
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+IMPORT void lib2_hello();
+
+EXPORT int lib1_hello()
+{
+ puts("lib1 says hello!");
+ lib2_hello();
+ return 0;
+}
diff --git a/tests/manual/link_dynamiclib/lib2.cpp b/tests/manual/link_dynamiclib/lib2.cpp
new file mode 100644
index 000000000..8aaa4fb70
--- /dev/null
+++ b/tests/manual/link_dynamiclib/lib2.cpp
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+IMPORT void lib3_hello();
+
+EXPORT void lib2_hello()
+{
+ puts("lib2 says hello!");
+ lib3_hello();
+}
+
diff --git a/tests/manual/link_dynamiclib/lib3.cpp b/tests/manual/link_dynamiclib/lib3.cpp
new file mode 100644
index 000000000..a4ac4885d
--- /dev/null
+++ b/tests/manual/link_dynamiclib/lib3.cpp
@@ -0,0 +1,58 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+EXPORT void lib3_hello()
+{
+ puts("lib3 says hello!");
+}
+
+EXPORT char* lib3_greeting()
+{
+ static char greeting[] = "hello";
+ return greeting;
+}
+
diff --git a/tests/manual/link_dynamiclib/link_dynamiclib.qbp b/tests/manual/link_dynamiclib/link_dynamiclib.qbp
new file mode 100644
index 000000000..51172835a
--- /dev/null
+++ b/tests/manual/link_dynamiclib/link_dynamiclib.qbp
@@ -0,0 +1,43 @@
+import qbs.base 1.0
+
+Project {
+ Application {
+ name : "HelloWorld"
+ destination: "bin"
+ Group {
+ files : [ "main.cpp" ]
+ }
+ Depends { name: "cpp" }
+ Depends { name: "lib1" }
+ }
+
+ DynamicLibrary {
+ name : "lib1"
+ destination: "bin"
+ Group {
+ files : [ "lib1.cpp" ]
+ }
+ Depends { name: "cpp" }
+ Depends { name: "lib2" }
+ }
+
+ DynamicLibrary {
+ name : "lib2"
+ destination: "bin"
+ Group {
+ files : [ "lib2.cpp" ]
+ }
+ Depends { name: "cpp" }
+ Depends { name: "lib3" }
+ }
+
+ DynamicLibrary {
+ name : "lib3"
+ destination: "bin"
+ Group {
+ files : [ "lib3.cpp" ]
+ }
+ Depends { name: "cpp" }
+ }
+}
+
diff --git a/tests/manual/link_dynamiclib/main.cpp b/tests/manual/link_dynamiclib/main.cpp
new file mode 100644
index 000000000..c904e7088
--- /dev/null
+++ b/tests/manual/link_dynamiclib/main.cpp
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+IMPORT int lib1_hello();
+
+int main()
+{
+ puts("application says hello!");
+ return lib1_hello();
+}
+
diff --git a/tests/manual/link_staticlib/helper/helper.cpp b/tests/manual/link_staticlib/helper/helper.cpp
new file mode 100644
index 000000000..796c1ef2a
--- /dev/null
+++ b/tests/manual/link_staticlib/helper/helper.cpp
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#include "helper.h"
+
+int getSomeNumber()
+{
+ return 156;
+}
+
diff --git a/tests/manual/link_staticlib/helper/helper.h b/tests/manual/link_staticlib/helper/helper.h
new file mode 100644
index 000000000..6cb075a1c
--- /dev/null
+++ b/tests/manual/link_staticlib/helper/helper.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+#ifndef HELPER_H
+#define HELPER_H
+
+extern int getSomeNumber();
+
+#endif
+
diff --git a/tests/manual/link_staticlib/link_staticlib.qbp b/tests/manual/link_staticlib/link_staticlib.qbp
new file mode 100644
index 000000000..a86b50f8d
--- /dev/null
+++ b/tests/manual/link_staticlib/link_staticlib.qbp
@@ -0,0 +1,30 @@
+import qbs.base 1.0
+
+Project {
+ Application {
+ name: "HelloWorld"
+ files : [ "main.cpp" ]
+ Depends { name: "cpp" }
+ Depends { name: "mystaticlib" }
+ }
+
+ StaticLibrary {
+ name : "mystaticlib"
+ files : [ "mystaticlib.cpp" ]
+ Depends { name: "cpp" }
+ Depends { name: "helperlib" }
+ }
+
+ StaticLibrary {
+ name : "helperlib"
+ files : [
+ "helper/helper.h",
+ "helper/helper.cpp"
+ ]
+ Depends { name: "cpp" }
+ ProductModule {
+ cpp.includePaths: ['helper']
+ }
+ }
+}
+
diff --git a/tests/manual/link_staticlib/main.cpp b/tests/manual/link_staticlib/main.cpp
new file mode 100644
index 000000000..fbef6bd79
--- /dev/null
+++ b/tests/manual/link_staticlib/main.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+int bla();
+
+int main()
+{
+ return bla();
+}
+
diff --git a/tests/manual/link_staticlib/mystaticlib.cpp b/tests/manual/link_staticlib/mystaticlib.cpp
new file mode 100644
index 000000000..9c035f22d
--- /dev/null
+++ b/tests/manual/link_staticlib/mystaticlib.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+#include <helper.h>
+
+int bla()
+{
+ int n = getSomeNumber();
+ printf("Hello World! The magic number is %d.", n);
+ return n;
+}
diff --git a/tests/manual/link_staticlib/mystaticlibhelper.cpp b/tests/manual/link_staticlib/mystaticlibhelper.cpp
new file mode 100644
index 000000000..76a6a38e9
--- /dev/null
+++ b/tests/manual/link_staticlib/mystaticlibhelper.cpp
@@ -0,0 +1,5 @@
+int helper_function()
+{
+ return 156;
+}
+
diff --git a/tests/manual/localDeployment/localDeployment.qbp b/tests/manual/localDeployment/localDeployment.qbp
new file mode 100644
index 000000000..1909d14d0
--- /dev/null
+++ b/tests/manual/localDeployment/localDeployment.qbp
@@ -0,0 +1,20 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: ["application", "installed_content"]
+ name: "HelloWorld"
+ destination: "bin"
+
+ Depends { name: "Qt.core"}
+
+ files: [ "main.cpp" ]
+
+ Group {
+ qbs.installDir: "share"
+ files: ['main.cpp']
+ fileTags: ["install"]
+ }
+ }
+}
+
diff --git a/tests/manual/localDeployment/main.cpp b/tests/manual/localDeployment/main.cpp
new file mode 100644
index 000000000..267f645bf
--- /dev/null
+++ b/tests/manual/localDeployment/main.cpp
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <QFile>
+#include <QCoreApplication>
+#include <QDebug>
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QFile f(app.applicationDirPath() + "/../share/main.cpp");
+ f.open(QFile::ReadOnly);
+ qDebug() << f.readAll();
+}
+
diff --git a/tests/manual/moc_cpp/bla.cpp b/tests/manual/moc_cpp/bla.cpp
new file mode 100644
index 000000000..26185684a
--- /dev/null
+++ b/tests/manual/moc_cpp/bla.cpp
@@ -0,0 +1,15 @@
+#include <QObject>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+};
+
+int main()
+{
+ MyObject obj;
+ return 0;
+}
+
+#include "bla.moc"
+
diff --git a/tests/manual/moc_cpp/moc_cpp.qbp b/tests/manual/moc_cpp/moc_cpp.qbp
new file mode 100644
index 000000000..dd8ddf603
--- /dev/null
+++ b/tests/manual/moc_cpp/moc_cpp.qbp
@@ -0,0 +1,14 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "moc_cpp"
+
+ Depends {
+ name: "Qt.core"
+ }
+
+ files: ["bla.cpp"]
+ }
+}
diff --git a/tests/manual/moc_hpp/moc_hpp.qbp b/tests/manual/moc_hpp/moc_hpp.qbp
new file mode 100644
index 000000000..a730c93e8
--- /dev/null
+++ b/tests/manual/moc_hpp/moc_hpp.qbp
@@ -0,0 +1,16 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "moc_hpp"
+
+ Depends { name: "qt.core" }
+
+ files : [
+ "object.h",
+ "object.cpp"
+ ]
+ }
+}
+
diff --git a/tests/manual/moc_hpp/object.cpp b/tests/manual/moc_hpp/object.cpp
new file mode 100644
index 000000000..8c091c58c
--- /dev/null
+++ b/tests/manual/moc_hpp/object.cpp
@@ -0,0 +1,13 @@
+#include "object.h"
+#include <cstdio>
+
+Object::Object(QObject *parent)
+ : QObject(parent)
+{}
+
+int main()
+{
+ Object obj;
+ printf("Hello World\n");
+}
+
diff --git a/tests/manual/moc_hpp/object.h b/tests/manual/moc_hpp/object.h
new file mode 100644
index 000000000..7d8f59c6c
--- /dev/null
+++ b/tests/manual/moc_hpp/object.h
@@ -0,0 +1,13 @@
+#ifndef OBJECT_H
+#define OBJECT_H
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ Object(QObject *parent = 0);
+};
+
+#endif
+
diff --git a/tests/manual/moc_hpp_included/moc_hpp_included.qbp b/tests/manual/moc_hpp_included/moc_hpp_included.qbp
new file mode 100644
index 000000000..1cdfb7fad
--- /dev/null
+++ b/tests/manual/moc_hpp_included/moc_hpp_included.qbp
@@ -0,0 +1,18 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "moc_hpp_included"
+
+ Depends { name: "qt.core" }
+
+ files : [ "object.cpp" ]
+
+ Group {
+ files : [ "object.h" ]
+ fileTags: [ "hpp" ]
+ }
+ }
+}
+
diff --git a/tests/manual/moc_hpp_included/object.cpp b/tests/manual/moc_hpp_included/object.cpp
new file mode 100644
index 000000000..ef0b32417
--- /dev/null
+++ b/tests/manual/moc_hpp_included/object.cpp
@@ -0,0 +1,15 @@
+#include "object.h"
+
+Object::Object(QObject *parent)
+ : QObject(parent)
+{}
+
+#include "moc_object.cpp"
+#include <cstdio>
+
+int main()
+{
+ Object obj;
+ printf("Hello World\n");
+}
+
diff --git a/tests/manual/moc_hpp_included/object.h b/tests/manual/moc_hpp_included/object.h
new file mode 100644
index 000000000..7d8f59c6c
--- /dev/null
+++ b/tests/manual/moc_hpp_included/object.h
@@ -0,0 +1,13 @@
+#ifndef OBJECT_H
+#define OBJECT_H
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ Object(QObject *parent = 0);
+};
+
+#endif
+
diff --git a/tests/manual/pch/main.cpp b/tests/manual/pch/main.cpp
new file mode 100644
index 000000000..83d04ea54
--- /dev/null
+++ b/tests/manual/pch/main.cpp
@@ -0,0 +1,27 @@
+#include "myobject.h"
+#include <algorithm>
+#include <iostream>
+#include <list>
+
+using namespace std;
+
+int main(int argc, char **argv)
+{
+ MyObject obj;
+ list<int> lst;
+ lst.push_back(1);
+ lst.push_back(2);
+ lst.push_back(3);
+ lst.push_back(4);
+ lst.push_back(5);
+ lst.push_back(6);
+ lst.push_back(7);
+ lst.push_back(8);
+ lst.push_back(9);
+ reverse(lst.begin(), lst.end());
+ for (list<int>::iterator it=lst.begin(); it != lst.end(); ++it)
+ cout << *it << ", ";
+ cout << endl;
+ return 0;
+}
+
diff --git a/tests/manual/pch/myobject.cpp b/tests/manual/pch/myobject.cpp
new file mode 100644
index 000000000..9f3f93740
--- /dev/null
+++ b/tests/manual/pch/myobject.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+#include "myobject.h"
+
+MyObject::MyObject()
+{
+ std::cout << "MyObject::MyObject()\n";
+}
+
+MyObject::~MyObject()
+{
+ std::cout << "MyObject::~MyObject()" << std::endl;
+}
+
diff --git a/tests/manual/pch/myobject.h b/tests/manual/pch/myobject.h
new file mode 100644
index 000000000..17dfd48c8
--- /dev/null
+++ b/tests/manual/pch/myobject.h
@@ -0,0 +1,12 @@
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+class MyObject
+{
+public:
+ MyObject();
+ ~MyObject();
+};
+
+#endif
+
diff --git a/tests/manual/pch/pch.qbp b/tests/manual/pch/pch.qbp
new file mode 100644
index 000000000..664d134e6
--- /dev/null
+++ b/tests/manual/pch/pch.qbp
@@ -0,0 +1,13 @@
+import qbs.base 1.0
+
+Product {
+ type: "application"
+ name: "pch"
+ files: ["stable.h",
+ "myobject.h",
+ "main.cpp",
+ "myobject.cpp"]
+ Depends { name: "cpp" }
+ cpp.precompiledHeader: "stable.h"
+}
+
diff --git a/tests/manual/pch/stable.h b/tests/manual/pch/stable.h
new file mode 100644
index 000000000..93ce3cb29
--- /dev/null
+++ b/tests/manual/pch/stable.h
@@ -0,0 +1,9 @@
+/* Add C includes here */
+
+#if defined __cplusplus
+/* Add C++ includes here */
+
+# include <iostream>
+# include <algorithm>
+#endif
+
diff --git a/tests/manual/productmoduledeps/lib1.cpp b/tests/manual/productmoduledeps/lib1.cpp
new file mode 100644
index 000000000..5322022b3
--- /dev/null
+++ b/tests/manual/productmoduledeps/lib1.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+EXPORT int lib1_hello()
+{
+ puts("lib1 says hello!");
+ return 0;
+}
diff --git a/tests/manual/productmoduledeps/main.cpp b/tests/manual/productmoduledeps/main.cpp
new file mode 100644
index 000000000..c904e7088
--- /dev/null
+++ b/tests/manual/productmoduledeps/main.cpp
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+IMPORT int lib1_hello();
+
+int main()
+{
+ puts("application says hello!");
+ return lib1_hello();
+}
+
diff --git a/tests/manual/productmoduledeps/productmoduledeps.qbp b/tests/manual/productmoduledeps/productmoduledeps.qbp
new file mode 100644
index 000000000..5e065f6b5
--- /dev/null
+++ b/tests/manual/productmoduledeps/productmoduledeps.qbp
@@ -0,0 +1,47 @@
+import qbs.base 1.0
+
+Project {
+ Application {
+ name : "HelloWorld"
+ destination: "bin"
+ Group {
+ files : [ "main.cpp" ]
+ }
+ Depends { name: "cpp" }
+ Depends { name: 'dummy' }
+ }
+
+ Product {
+ name: 'dummy'
+ type: 'installed_content'
+ Group {
+ files: 'main.cpp'
+ fileTags: 'install'
+ }
+ ProductModule {
+ Depends { name: 'dummy2' }
+ }
+ }
+
+ Product {
+ name: 'dummy2'
+ type: 'installed_content'
+ Group {
+ files: 'lib1.cpp'
+ fileTags: 'install'
+ }
+ ProductModule {
+ Depends { name: 'lib1' }
+ }
+ }
+
+ DynamicLibrary {
+ name : "lib1"
+ destination: "bin"
+ Group {
+ files : [ "lib1.cpp" ]
+ }
+ Depends { name: "cpp" }
+ }
+}
+
diff --git a/tests/manual/proper quoting/main.cpp b/tests/manual/proper quoting/main.cpp
new file mode 100644
index 000000000..7efbf23ee
--- /dev/null
+++ b/tests/manual/proper quoting/main.cpp
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#define __stringify__(x) #x
+#define stringify(x) __stringify__(x)
+
+int bla();
+
+int main()
+{
+ printf(DEFINE"\n");
+ printf(DEFINEWITHSPACE"\n");
+ printf(DEFINEWITHTAB"\n");
+ printf(DEFINEWITHBACKSLASH"\n");
+ printf(stringify(DEFINEWITHBACKSLASHRAW)"\n");
+
+ return bla();
+}
+
diff --git a/tests/manual/proper quoting/my static lib helper.cpp b/tests/manual/proper quoting/my static lib helper.cpp
new file mode 100644
index 000000000..76a6a38e9
--- /dev/null
+++ b/tests/manual/proper quoting/my static lib helper.cpp
@@ -0,0 +1,5 @@
+int helper_function()
+{
+ return 156;
+}
+
diff --git a/tests/manual/proper quoting/my static lib.cpp b/tests/manual/proper quoting/my static lib.cpp
new file mode 100644
index 000000000..7134e431b
--- /dev/null
+++ b/tests/manual/proper quoting/my static lib.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+#include <some helper.h>
+
+int bla()
+{
+ int n = getSomeNumber();
+ printf("Hello World! The magic number is %d.", n);
+ return n;
+}
diff --git a/tests/manual/proper quoting/proper quoting.qbp b/tests/manual/proper quoting/proper quoting.qbp
new file mode 100644
index 000000000..f56f78071
--- /dev/null
+++ b/tests/manual/proper quoting/proper quoting.qbp
@@ -0,0 +1,42 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "Hello World"
+ files : [ "main.cpp" ]
+ Depends { name: "cpp" }
+ Depends { name: "my static lib" }
+ cpp.defines: [
+ 'DEFINE="whitespaceless"',
+ 'DEFINEWITHSPACE="contains space"',
+ 'DEFINEWITHTAB="contains\ttab"',
+ 'DEFINEWITHBACKSLASH="backslash\\\\"',
+ 'DEFINEWITHBACKSLASHRAW=backslash\\\\'
+ ]
+// cpp.responseFileThreshold: 0
+ }
+
+ Product {
+ type: "staticlibrary"
+ name : "my static lib"
+ files : [ "my static lib.cpp" ]
+ Depends { name: "cpp" }
+ Depends { name: "helper lib" }
+// cpp.responseFileThreshold: 0
+ }
+
+ Product {
+ type: "staticlibrary"
+ name : "helper lib"
+ files : [
+ "some helper/some helper.h",
+ "some helper/some helper.cpp"
+ ]
+ Depends { name: "cpp" }
+ ProductModule {
+ cpp.includePaths: ['some helper']
+ }
+// cpp.responseFileThreshold: 0
+ }
+}
diff --git a/tests/manual/proper quoting/some helper/some helper.cpp b/tests/manual/proper quoting/some helper/some helper.cpp
new file mode 100644
index 000000000..99ac58019
--- /dev/null
+++ b/tests/manual/proper quoting/some helper/some helper.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "some helper.h"
+
+int getSomeNumber()
+{
+ return 156;
+}
+
diff --git a/tests/manual/proper quoting/some helper/some helper.h b/tests/manual/proper quoting/some helper/some helper.h
new file mode 100644
index 000000000..75560e6af
--- /dev/null
+++ b/tests/manual/proper quoting/some helper/some helper.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#ifndef HELPER_H
+#define HELPER_H
+
+extern int getSomeNumber();
+
+#endif
+
diff --git a/tests/manual/propertiesblocks/hello.qbp b/tests/manual/propertiesblocks/hello.qbp
new file mode 100644
index 000000000..de08cbbec
--- /dev/null
+++ b/tests/manual/propertiesblocks/hello.qbp
@@ -0,0 +1,28 @@
+import qbs.base 1.0
+
+Product {
+ Depends { name: 'cpp' }
+
+ Properties {
+ condition: true
+ type: 'application'
+ name: 'HelloWorld'
+ }
+
+ Properties {
+ condition: name == 'HelloWorld'
+ cpp.defines: ['SOMETHING']
+ }
+
+ Properties {
+ condition: qbs.targetOS == "weird"
+ cpp.staticLibraries: "abc"
+ }
+
+ Group {
+ cpp.defines: outer.concat(['HAVE_MAIN_CPP', cpp.debugInformation ? '_DEBUG' : '_RELEASE'])
+ files: ['main.cpp']
+ }
+}
+
+
diff --git a/tests/manual/propertiesblocks/main.cpp b/tests/manual/propertiesblocks/main.cpp
new file mode 100644
index 000000000..4d2b5fa6c
--- /dev/null
+++ b/tests/manual/propertiesblocks/main.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <stdio.h>
+
+#ifndef HAVE_MAIN_CPP
+# error missing define HAVE_MAIN_CPP
+#endif
+
+int main()
+{
+#ifdef _DEBUG
+ puts("Hello World! (debug version)");
+#else
+ puts("Hello World! (release version)");
+#endif
+}
+
diff --git a/tests/manual/qrc2/bla.cpp b/tests/manual/qrc2/bla.cpp
new file mode 100644
index 000000000..e1c0d42bc
--- /dev/null
+++ b/tests/manual/qrc2/bla.cpp
@@ -0,0 +1,40 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+int main(){
+ return 3;
+}
diff --git a/tests/manual/qrc2/bla.qrc b/tests/manual/qrc2/bla.qrc
new file mode 100644
index 000000000..f0a7168f5
--- /dev/null
+++ b/tests/manual/qrc2/bla.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/bla">
+ <file>stuff.txt</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/qrc2/foo.qrc b/tests/manual/qrc2/foo.qrc
new file mode 100644
index 000000000..a8acfc34a
--- /dev/null
+++ b/tests/manual/qrc2/foo.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/foo">
+ <file>stuff.txt</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/qrc2/i.qbp b/tests/manual/qrc2/i.qbp
new file mode 100644
index 000000000..5f89b9f82
--- /dev/null
+++ b/tests/manual/qrc2/i.qbp
@@ -0,0 +1,19 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "i"
+
+ Depends {
+ name: "Qt.core"
+ }
+
+ files: [
+ "bla.cpp",
+ "bla.qrc",
+ "foo.qrc",
+ "stuff.txt"
+ ]
+ }
+}
diff --git a/tests/manual/qrc2/stuff.txt b/tests/manual/qrc2/stuff.txt
new file mode 100644
index 000000000..78f0d32c6
--- /dev/null
+++ b/tests/manual/qrc2/stuff.txt
@@ -0,0 +1 @@
+a resource file
diff --git a/tests/manual/symhello/hello.qbp b/tests/manual/symhello/hello.qbp
new file mode 100644
index 000000000..7e9944a15
--- /dev/null
+++ b/tests/manual/symhello/hello.qbp
@@ -0,0 +1,10 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ name : "HelloWorld"
+ type: "application"
+ files : [ "main.cpp" ]
+ }
+}
+
diff --git a/tests/manual/symhello/main.cpp b/tests/manual/symhello/main.cpp
new file mode 100644
index 000000000..8e1873a2a
--- /dev/null
+++ b/tests/manual/symhello/main.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <e32std.h>
+#include <e32debug.h>
+
+TInt E32Main()
+{
+ RDebug::Print(_L("Hello!"));
+ return 0;
+}
+
diff --git a/tests/manual/transformers/main.cpp b/tests/manual/transformers/main.cpp
new file mode 100644
index 000000000..5df553831
--- /dev/null
+++ b/tests/manual/transformers/main.cpp
@@ -0,0 +1,77 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+bool displayTextFile(const string &dirPath, const string &fileName)
+{
+ string fullPath = dirPath + fileName;
+ ifstream istream(fullPath.c_str());
+ if (!istream.is_open()) {
+ cout << "Cannot open " << fileName << endl;
+ return false;
+ }
+ cout << "---" << fileName << "---" << endl;
+ char buf[256];
+ unsigned int i = 1;
+ while (istream.good()) {
+ istream.getline(buf, sizeof(buf));
+ cout << i++ << ": " << buf << endl;
+ }
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ string appPath(argv[0]);
+ size_t i = appPath.find_last_of('/');
+ if (i == string::npos)
+ i = appPath.find_last_of('\\');
+ if (i != string::npos)
+ appPath.resize(i + 1);
+ if (!displayTextFile(appPath, "foo.txt"))
+ return 1;
+ if (!displayTextFile(appPath, "bar.txt"))
+ return 2;
+ cout << "-------------" << endl;
+ return 0;
+}
+
diff --git a/tests/manual/transformers/transformers.qbp b/tests/manual/transformers/transformers.qbp
new file mode 100644
index 000000000..12cd3579f
--- /dev/null
+++ b/tests/manual/transformers/transformers.qbp
@@ -0,0 +1,53 @@
+import qbs.base 1.0
+import qbs.fileinfo 1.0 as FileInfo
+
+Project {
+ Product {
+ name: "HelloWorld"
+ type: "application"
+ files: ["main.cpp"]
+
+ Depends { name: "cpp" }
+
+ Transformer {
+ // no inputs -> just a generator
+ Artifact {
+ fileName: "foo.txt"
+ fileTags: "text"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating foo.txt";
+ cmd.highlight = "linker";
+ cmd.sourceCode = "File.remove(output.fileName);\n";
+ cmd.sourceCode += "var f = new TextFile(output.fileName, TextFile.WriteOnly);\n"
+ cmd.sourceCode += "f.write(\"Dear Sir/Madam,\\n\\n\");\n";
+ cmd.sourceCode += "f.write(\"this is a generated file.\\n\\n\\n\");\n";
+ cmd.sourceCode += "f.write(\"Best Regards and Mellow Greetings,\\nYour Build Tool.\\n\");\n";
+ cmd.sourceCode += "f.close();";
+ return cmd;
+ }
+ }
+
+ Transformer {
+ inputs: ["main.cpp"] // will be taken from the source dir
+ Artifact {
+ fileName: "bar.txt"
+ fileTags: "text"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating bar.txt";
+ cmd.highlight = "linker";
+ cmd.sourceCode = "File.remove(output.fileName);\n";
+ cmd.sourceCode += "var f = new TextFile(output.fileName, TextFile.WriteOnly)\n";
+ cmd.sourceCode += "f.write(\"Dear Sir/Madam,\\n\\n\");\n";
+ cmd.sourceCode += "f.write(\"this file was generated from \" + input.fileName + \".\\n\\n\\n\");\n";
+ cmd.sourceCode += "f.write(\"Best Regards and Mellow Greetings,\\nYour Build Tool.\\n\");";
+ cmd.sourceCode += "f.close();";
+ return cmd;
+ }
+ }
+ }
+}
+
diff --git a/tests/manual/uic/bla.cpp b/tests/manual/uic/bla.cpp
new file mode 100644
index 000000000..b56070dc2
--- /dev/null
+++ b/tests/manual/uic/bla.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "bla.h"
+
+int main()
+{
+ Ui::MainWindow mainWindow;
+}
+
diff --git a/tests/manual/uic/bla.h b/tests/manual/uic/bla.h
new file mode 100644
index 000000000..8c8a45878
--- /dev/null
+++ b/tests/manual/uic/bla.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "ui.h"
diff --git a/tests/manual/uic/ui.h b/tests/manual/uic/ui.h
new file mode 100644
index 000000000..e2dfa0eb6
--- /dev/null
+++ b/tests/manual/uic/ui.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+**
+** This file is part of the Qt Build Suite
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file.
+** Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**************************************************************************/
+
+#include "ui_ui.h"
diff --git a/tests/manual/uic/ui.ui b/tests/manual/uic/ui.ui
new file mode 100644
index 000000000..b07f62d05
--- /dev/null
+++ b/tests/manual/uic/ui.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget"/>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>25</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/manual/uic/uic.qbp b/tests/manual/uic/uic.qbp
new file mode 100644
index 000000000..1c10dca76
--- /dev/null
+++ b/tests/manual/uic/uic.qbp
@@ -0,0 +1,17 @@
+import qbs.base 1.0
+
+Project {
+ Product {
+ type: "application"
+ name: "ui"
+
+ Depends { name: "Qt.gui"}
+
+ files: [
+ "bla.cpp",
+ "bla.h",
+ "ui.ui",
+ "ui.h"
+ ]
+ }
+}
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 000000000..cef82e9c7
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = auto
+