From b855240b782395f94315f43ea3e7e182299fac48 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Thu, 16 Feb 2012 14:43:03 +1000 Subject: Rename QDeclarative symbols to QQuick and QQml Symbols beginning with QDeclarative are already exported by the quick1 module. Users can apply the bin/rename-qtdeclarative-symbols.sh script to modify client code using the previous names of the renamed symbols. Task-number: QTBUG-23737 Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66 Reviewed-by: Martin Jones --- src/qml/qml/ftw/ftw.pri | 29 + src/qml/qml/ftw/qbitfield_p.h | 165 + src/qml/qml/ftw/qdeletewatcher_p.h | 113 + src/qml/qml/ftw/qfastmetabuilder.cpp | 369 +++ src/qml/qml/ftw/qfastmetabuilder_p.h | 206 ++ src/qml/qml/ftw/qfieldlist_p.h | 426 +++ src/qml/qml/ftw/qfinitestack_p.h | 186 ++ src/qml/qml/ftw/qflagpointer_p.h | 338 ++ src/qml/qml/ftw/qhashedstring.cpp | 490 +++ src/qml/qml/ftw/qhashedstring_p.h | 1418 +++++++++ src/qml/qml/ftw/qhashfield_p.h | 120 + src/qml/qml/ftw/qintrusivelist.cpp | 179 ++ src/qml/qml/ftw/qintrusivelist_p.h | 274 ++ src/qml/qml/ftw/qlazilyallocated_p.h | 146 + src/qml/qml/ftw/qpodvector_p.h | 173 + src/qml/qml/ftw/qpointervaluepair_p.h | 196 ++ src/qml/qml/ftw/qqmlpool.cpp | 92 + src/qml/qml/ftw/qqmlpool_p.h | 278 ++ src/qml/qml/ftw/qqmlrefcount_p.h | 192 ++ src/qml/qml/ftw/qqmlthread.cpp | 359 +++ src/qml/qml/ftw/qqmlthread_p.h | 318 ++ src/qml/qml/ftw/qqmltrace.cpp | 154 + src/qml/qml/ftw/qqmltrace_p.h | 294 ++ src/qml/qml/ftw/qrecursionwatcher_p.h | 105 + src/qml/qml/ftw/qrecyclepool_p.h | 220 ++ src/qml/qml/parser/parser.pri | 19 + src/qml/qml/parser/qqmljs.g | 3016 ++++++++++++++++++ src/qml/qml/parser/qqmljsast.cpp | 931 ++++++ src/qml/qml/parser/qqmljsast_p.h | 2640 +++++++++++++++ src/qml/qml/parser/qqmljsastfwd_p.h | 186 ++ src/qml/qml/parser/qqmljsastvisitor.cpp | 58 + src/qml/qml/parser/qqmljsastvisitor_p.h | 329 ++ src/qml/qml/parser/qqmljsengine_p.cpp | 161 + src/qml/qml/parser/qqmljsengine_p.h | 126 + src/qml/qml/parser/qqmljsglobal_p.h | 69 + src/qml/qml/parser/qqmljsgrammar.cpp | 1013 ++++++ src/qml/qml/parser/qqmljsgrammar_p.h | 211 ++ src/qml/qml/parser/qqmljskeywords_p.h | 860 +++++ src/qml/qml/parser/qqmljslexer.cpp | 1166 +++++++ src/qml/qml/parser/qqmljslexer_p.h | 248 ++ src/qml/qml/parser/qqmljsmemorypool_p.h | 173 + src/qml/qml/parser/qqmljsparser.cpp | 1812 +++++++++++ src/qml/qml/parser/qqmljsparser_p.h | 248 ++ src/qml/qml/qlistmodelinterface.cpp | 104 + src/qml/qml/qlistmodelinterface_p.h | 83 + src/qml/qml/qml.pri | 125 + src/qml/qml/qqml.h | 451 +++ src/qml/qml/qqmlaccessors.cpp | 127 + src/qml/qml/qqmlaccessors_p.h | 166 + src/qml/qml/qqmlbinding.cpp | 551 ++++ src/qml/qml/qqmlbinding_p.h | 219 ++ src/qml/qml/qqmlbinding_p_p.h | 89 + src/qml/qml/qqmlboundsignal.cpp | 300 ++ src/qml/qml/qqmlboundsignal_p.h | 103 + src/qml/qml/qqmlcleanup.cpp | 118 + src/qml/qml/qqmlcleanup_p.h | 87 + src/qml/qml/qqmlcompileddata.cpp | 261 ++ src/qml/qml/qqmlcompiler.cpp | 3882 +++++++++++++++++++++++ src/qml/qml/qqmlcompiler_p.h | 466 +++ src/qml/qml/qqmlcomponent.cpp | 1350 ++++++++ src/qml/qml/qqmlcomponent.h | 138 + src/qml/qml/qqmlcomponent_p.h | 129 + src/qml/qml/qqmlcomponentattached_p.h | 85 + src/qml/qml/qqmlcontext.cpp | 811 +++++ src/qml/qml/qqmlcontext.h | 113 + src/qml/qml/qqmlcontext_p.h | 334 ++ src/qml/qml/qqmlcustomparser.cpp | 319 ++ src/qml/qml/qqmlcustomparser_p.h | 168 + src/qml/qml/qqmlcustomparser_p_p.h | 89 + src/qml/qml/qqmldata_p.h | 207 ++ src/qml/qml/qqmldirparser.cpp | 298 ++ src/qml/qml/qqmldirparser_p.h | 166 + src/qml/qml/qqmlengine.cpp | 1854 +++++++++++ src/qml/qml/qqmlengine.h | 138 + src/qml/qml/qqmlengine_p.h | 522 +++ src/qml/qml/qqmlerror.cpp | 285 ++ src/qml/qml/qqmlerror.h | 87 + src/qml/qml/qqmlexpression.cpp | 982 ++++++ src/qml/qml/qqmlexpression.h | 121 + src/qml/qml/qqmlexpression_p.h | 406 +++ src/qml/qml/qqmlextensioninterface.h | 76 + src/qml/qml/qqmlextensionplugin.cpp | 171 + src/qml/qml/qqmlextensionplugin.h | 77 + src/qml/qml/qqmlglobal_p.h | 129 + src/qml/qml/qqmlguard_p.h | 218 ++ src/qml/qml/qqmlimageprovider.cpp | 334 ++ src/qml/qml/qqmlimageprovider.h | 96 + src/qml/qml/qqmlimport.cpp | 1183 +++++++ src/qml/qml/qqmlimport_p.h | 157 + src/qml/qml/qqmlincubator.cpp | 696 ++++ src/qml/qml/qqmlincubator.h | 129 + src/qml/qml/qqmlincubator_p.h | 106 + src/qml/qml/qqmlinfo.cpp | 192 ++ src/qml/qml/qqmlinfo.h | 103 + src/qml/qml/qqmlinstruction.cpp | 278 ++ src/qml/qml/qqmlinstruction_p.h | 558 ++++ src/qml/qml/qqmlintegercache.cpp | 82 + src/qml/qml/qqmlintegercache_p.h | 97 + src/qml/qml/qqmllist.cpp | 417 +++ src/qml/qml/qqmllist.h | 151 + src/qml/qml/qqmllist_p.h | 85 + src/qml/qml/qqmllocale.cpp | 1123 +++++++ src/qml/qml/qqmllocale_p.h | 135 + src/qml/qml/qqmlmetatype.cpp | 1359 ++++++++ src/qml/qml/qqmlmetatype_p.h | 268 ++ src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp | 103 + src/qml/qml/qqmlnetworkaccessmanagerfactory.h | 66 + src/qml/qml/qqmlnotifier.cpp | 115 + src/qml/qml/qqmlnotifier_p.h | 206 ++ src/qml/qml/qqmlnullablevalue_p_p.h | 81 + src/qml/qml/qqmlopenmetaobject.cpp | 387 +++ src/qml/qml/qqmlopenmetaobject_p.h | 130 + src/qml/qml/qqmlparserstatus.cpp | 107 + src/qml/qml/qqmlparserstatus.h | 75 + src/qml/qml/qqmlprivate.h | 265 ++ src/qml/qml/qqmlproperty.cpp | 1917 +++++++++++ src/qml/qml/qqmlproperty.h | 143 + src/qml/qml/qqmlproperty_p.h | 171 + src/qml/qml/qqmlpropertycache.cpp | 889 ++++++ src/qml/qml/qqmlpropertycache_p.h | 383 +++ src/qml/qml/qqmlpropertyvalueinterceptor.cpp | 79 + src/qml/qml/qqmlpropertyvalueinterceptor_p.h | 74 + src/qml/qml/qqmlpropertyvaluesource.cpp | 76 + src/qml/qml/qqmlpropertyvaluesource.h | 67 + src/qml/qml/qqmlproxymetaobject.cpp | 124 + src/qml/qml/qqmlproxymetaobject_p.h | 99 + src/qml/qml/qqmlrewrite.cpp | 441 +++ src/qml/qml/qqmlrewrite_p.h | 149 + src/qml/qml/qqmlscript.cpp | 1700 ++++++++++ src/qml/qml/qqmlscript_p.h | 533 ++++ src/qml/qml/qqmlscriptstring.cpp | 157 + src/qml/qml/qqmlscriptstring.h | 90 + src/qml/qml/qqmlscriptstring_p.h | 64 + src/qml/qml/qqmlstringconverters.cpp | 311 ++ src/qml/qml/qqmlstringconverters_p.h | 93 + src/qml/qml/qqmltypeloader.cpp | 1928 +++++++++++ src/qml/qml/qqmltypeloader_p.h | 435 +++ src/qml/qml/qqmltypenamecache.cpp | 127 + src/qml/qml/qqmltypenamecache_p.h | 187 ++ src/qml/qml/qqmltypenotavailable.cpp | 53 + src/qml/qml/qqmltypenotavailable_p.h | 64 + src/qml/qml/qqmlvaluetype.cpp | 868 +++++ src/qml/qml/qqmlvaluetype_p.h | 635 ++++ src/qml/qml/qqmlvme.cpp | 1370 ++++++++ src/qml/qml/qqmlvme_p.h | 240 ++ src/qml/qml/qqmlvmemetaobject.cpp | 1110 +++++++ src/qml/qml/qqmlvmemetaobject_p.h | 221 ++ src/qml/qml/qqmlwatcher.cpp | 188 ++ src/qml/qml/qqmlwatcher_p.h | 94 + src/qml/qml/qqmlxmlhttprequest.cpp | 1797 +++++++++++ src/qml/qml/qqmlxmlhttprequest_p.h | 73 + src/qml/qml/qquickapplication.cpp | 124 + src/qml/qml/qquickapplication_p.h | 87 + src/qml/qml/qquicklistmodel.cpp | 2467 ++++++++++++++ src/qml/qml/qquicklistmodel_p.h | 199 ++ src/qml/qml/qquicklistmodel_p_p.h | 378 +++ src/qml/qml/qquicklistmodelworkeragent.cpp | 246 ++ src/qml/qml/qquicklistmodelworkeragent_p.h | 161 + src/qml/qml/qquickworkerscript.cpp | 730 +++++ src/qml/qml/qquickworkerscript_p.h | 130 + src/qml/qml/rewriter/rewriter.pri | 2 + src/qml/qml/rewriter/textwriter.cpp | 217 ++ src/qml/qml/rewriter/textwriter_p.h | 101 + src/qml/qml/v4/qv4bindings.cpp | 1538 +++++++++ src/qml/qml/v4/qv4bindings_p.h | 153 + src/qml/qml/v4/qv4compiler.cpp | 1399 ++++++++ src/qml/qml/v4/qv4compiler_p.h | 105 + src/qml/qml/v4/qv4compiler_p_p.h | 245 ++ src/qml/qml/v4/qv4instruction.cpp | 412 +++ src/qml/qml/v4/qv4instruction_p.h | 432 +++ src/qml/qml/v4/qv4ir.cpp | 882 +++++ src/qml/qml/v4/qv4ir_p.h | 604 ++++ src/qml/qml/v4/qv4irbuilder.cpp | 1303 ++++++++ src/qml/qml/v4/qv4irbuilder_p.h | 240 ++ src/qml/qml/v4/qv4program_p.h | 122 + src/qml/qml/v4/v4.pri | 15 + src/qml/qml/v8/notes.txt | 4 + src/qml/qml/v8/qjsconverter_impl_p.h | 268 ++ src/qml/qml/v8/qjsconverter_p.h | 93 + src/qml/qml/v8/qjsengine.cpp | 476 +++ src/qml/qml/v8/qjsengine.h | 141 + src/qml/qml/v8/qjsengine_p.h | 57 + src/qml/qml/v8/qjsvalue.cpp | 856 +++++ src/qml/qml/v8/qjsvalue.h | 143 + src/qml/qml/v8/qjsvalue_impl_p.h | 977 ++++++ src/qml/qml/v8/qjsvalue_p.h | 195 ++ src/qml/qml/v8/qjsvalueiterator.cpp | 157 + src/qml/qml/v8/qjsvalueiterator.h | 63 + src/qml/qml/v8/qjsvalueiterator_impl_p.h | 121 + src/qml/qml/v8/qjsvalueiterator_p.h | 68 + src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 1320 ++++++++ src/qml/qml/v8/qqmlbuiltinfunctions_p.h | 110 + src/qml/qml/v8/qscript_impl_p.h | 43 + src/qml/qml/v8/qscriptisolate_p.h | 71 + src/qml/qml/v8/qscriptoriginalglobalobject_p.h | 159 + src/qml/qml/v8/qscriptshareddata_p.h | 151 + src/qml/qml/v8/qscripttools_p.h | 68 + src/qml/qml/v8/qv8_p.h | 42 + src/qml/qml/v8/qv8bindings.cpp | 285 ++ src/qml/qml/v8/qv8bindings_p.h | 148 + src/qml/qml/v8/qv8contextwrapper.cpp | 455 +++ src/qml/qml/v8/qv8contextwrapper_p.h | 120 + src/qml/qml/v8/qv8debug_p.h | 42 + src/qml/qml/v8/qv8domerrors.cpp | 73 + src/qml/qml/v8/qv8domerrors_p.h | 94 + src/qml/qml/v8/qv8engine.cpp | 1598 ++++++++++ src/qml/qml/v8/qv8engine_impl_p.h | 155 + src/qml/qml/v8/qv8engine_p.h | 631 ++++ src/qml/qml/v8/qv8include.cpp | 244 ++ src/qml/qml/v8/qv8include_p.h | 113 + src/qml/qml/v8/qv8listwrapper.cpp | 194 ++ src/qml/qml/v8/qv8listwrapper_p.h | 97 + src/qml/qml/v8/qv8profiler_p.h | 42 + src/qml/qml/v8/qv8qobjectwrapper.cpp | 2113 ++++++++++++ src/qml/qml/v8/qv8qobjectwrapper_p.h | 159 + src/qml/qml/v8/qv8sequencewrapper.cpp | 264 ++ src/qml/qml/v8/qv8sequencewrapper_p.h | 106 + src/qml/qml/v8/qv8sequencewrapper_p_p.h | 503 +++ src/qml/qml/v8/qv8sqlerrors.cpp | 64 + src/qml/qml/v8/qv8sqlerrors_p.h | 77 + src/qml/qml/v8/qv8stringwrapper.cpp | 78 + src/qml/qml/v8/qv8stringwrapper_p.h | 78 + src/qml/qml/v8/qv8typewrapper.cpp | 314 ++ src/qml/qml/v8/qv8typewrapper_p.h | 94 + src/qml/qml/v8/qv8valuetypewrapper.cpp | 387 +++ src/qml/qml/v8/qv8valuetypewrapper_p.h | 104 + src/qml/qml/v8/qv8variantresource_p.h | 81 + src/qml/qml/v8/qv8variantwrapper.cpp | 279 ++ src/qml/qml/v8/qv8variantwrapper_p.h | 110 + src/qml/qml/v8/qv8worker.cpp | 392 +++ src/qml/qml/v8/qv8worker_p.h | 75 + src/qml/qml/v8/script.pri | 21 + src/qml/qml/v8/v8.pri | 45 + 233 files changed, 90055 insertions(+) create mode 100644 src/qml/qml/ftw/ftw.pri create mode 100644 src/qml/qml/ftw/qbitfield_p.h create mode 100644 src/qml/qml/ftw/qdeletewatcher_p.h create mode 100644 src/qml/qml/ftw/qfastmetabuilder.cpp create mode 100644 src/qml/qml/ftw/qfastmetabuilder_p.h create mode 100644 src/qml/qml/ftw/qfieldlist_p.h create mode 100644 src/qml/qml/ftw/qfinitestack_p.h create mode 100644 src/qml/qml/ftw/qflagpointer_p.h create mode 100644 src/qml/qml/ftw/qhashedstring.cpp create mode 100644 src/qml/qml/ftw/qhashedstring_p.h create mode 100644 src/qml/qml/ftw/qhashfield_p.h create mode 100644 src/qml/qml/ftw/qintrusivelist.cpp create mode 100644 src/qml/qml/ftw/qintrusivelist_p.h create mode 100644 src/qml/qml/ftw/qlazilyallocated_p.h create mode 100644 src/qml/qml/ftw/qpodvector_p.h create mode 100644 src/qml/qml/ftw/qpointervaluepair_p.h create mode 100644 src/qml/qml/ftw/qqmlpool.cpp create mode 100644 src/qml/qml/ftw/qqmlpool_p.h create mode 100644 src/qml/qml/ftw/qqmlrefcount_p.h create mode 100644 src/qml/qml/ftw/qqmlthread.cpp create mode 100644 src/qml/qml/ftw/qqmlthread_p.h create mode 100644 src/qml/qml/ftw/qqmltrace.cpp create mode 100644 src/qml/qml/ftw/qqmltrace_p.h create mode 100644 src/qml/qml/ftw/qrecursionwatcher_p.h create mode 100644 src/qml/qml/ftw/qrecyclepool_p.h create mode 100644 src/qml/qml/parser/parser.pri create mode 100644 src/qml/qml/parser/qqmljs.g create mode 100644 src/qml/qml/parser/qqmljsast.cpp create mode 100644 src/qml/qml/parser/qqmljsast_p.h create mode 100644 src/qml/qml/parser/qqmljsastfwd_p.h create mode 100644 src/qml/qml/parser/qqmljsastvisitor.cpp create mode 100644 src/qml/qml/parser/qqmljsastvisitor_p.h create mode 100644 src/qml/qml/parser/qqmljsengine_p.cpp create mode 100644 src/qml/qml/parser/qqmljsengine_p.h create mode 100644 src/qml/qml/parser/qqmljsglobal_p.h create mode 100644 src/qml/qml/parser/qqmljsgrammar.cpp create mode 100644 src/qml/qml/parser/qqmljsgrammar_p.h create mode 100644 src/qml/qml/parser/qqmljskeywords_p.h create mode 100644 src/qml/qml/parser/qqmljslexer.cpp create mode 100644 src/qml/qml/parser/qqmljslexer_p.h create mode 100644 src/qml/qml/parser/qqmljsmemorypool_p.h create mode 100644 src/qml/qml/parser/qqmljsparser.cpp create mode 100644 src/qml/qml/parser/qqmljsparser_p.h create mode 100644 src/qml/qml/qlistmodelinterface.cpp create mode 100644 src/qml/qml/qlistmodelinterface_p.h create mode 100644 src/qml/qml/qml.pri create mode 100644 src/qml/qml/qqml.h create mode 100644 src/qml/qml/qqmlaccessors.cpp create mode 100644 src/qml/qml/qqmlaccessors_p.h create mode 100644 src/qml/qml/qqmlbinding.cpp create mode 100644 src/qml/qml/qqmlbinding_p.h create mode 100644 src/qml/qml/qqmlbinding_p_p.h create mode 100644 src/qml/qml/qqmlboundsignal.cpp create mode 100644 src/qml/qml/qqmlboundsignal_p.h create mode 100644 src/qml/qml/qqmlcleanup.cpp create mode 100644 src/qml/qml/qqmlcleanup_p.h create mode 100644 src/qml/qml/qqmlcompileddata.cpp create mode 100644 src/qml/qml/qqmlcompiler.cpp create mode 100644 src/qml/qml/qqmlcompiler_p.h create mode 100644 src/qml/qml/qqmlcomponent.cpp create mode 100644 src/qml/qml/qqmlcomponent.h create mode 100644 src/qml/qml/qqmlcomponent_p.h create mode 100644 src/qml/qml/qqmlcomponentattached_p.h create mode 100644 src/qml/qml/qqmlcontext.cpp create mode 100644 src/qml/qml/qqmlcontext.h create mode 100644 src/qml/qml/qqmlcontext_p.h create mode 100644 src/qml/qml/qqmlcustomparser.cpp create mode 100644 src/qml/qml/qqmlcustomparser_p.h create mode 100644 src/qml/qml/qqmlcustomparser_p_p.h create mode 100644 src/qml/qml/qqmldata_p.h create mode 100644 src/qml/qml/qqmldirparser.cpp create mode 100644 src/qml/qml/qqmldirparser_p.h create mode 100644 src/qml/qml/qqmlengine.cpp create mode 100644 src/qml/qml/qqmlengine.h create mode 100644 src/qml/qml/qqmlengine_p.h create mode 100644 src/qml/qml/qqmlerror.cpp create mode 100644 src/qml/qml/qqmlerror.h create mode 100644 src/qml/qml/qqmlexpression.cpp create mode 100644 src/qml/qml/qqmlexpression.h create mode 100644 src/qml/qml/qqmlexpression_p.h create mode 100644 src/qml/qml/qqmlextensioninterface.h create mode 100644 src/qml/qml/qqmlextensionplugin.cpp create mode 100644 src/qml/qml/qqmlextensionplugin.h create mode 100644 src/qml/qml/qqmlglobal_p.h create mode 100644 src/qml/qml/qqmlguard_p.h create mode 100644 src/qml/qml/qqmlimageprovider.cpp create mode 100644 src/qml/qml/qqmlimageprovider.h create mode 100644 src/qml/qml/qqmlimport.cpp create mode 100644 src/qml/qml/qqmlimport_p.h create mode 100644 src/qml/qml/qqmlincubator.cpp create mode 100644 src/qml/qml/qqmlincubator.h create mode 100644 src/qml/qml/qqmlincubator_p.h create mode 100644 src/qml/qml/qqmlinfo.cpp create mode 100644 src/qml/qml/qqmlinfo.h create mode 100644 src/qml/qml/qqmlinstruction.cpp create mode 100644 src/qml/qml/qqmlinstruction_p.h create mode 100644 src/qml/qml/qqmlintegercache.cpp create mode 100644 src/qml/qml/qqmlintegercache_p.h create mode 100644 src/qml/qml/qqmllist.cpp create mode 100644 src/qml/qml/qqmllist.h create mode 100644 src/qml/qml/qqmllist_p.h create mode 100644 src/qml/qml/qqmllocale.cpp create mode 100644 src/qml/qml/qqmllocale_p.h create mode 100644 src/qml/qml/qqmlmetatype.cpp create mode 100644 src/qml/qml/qqmlmetatype_p.h create mode 100644 src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp create mode 100644 src/qml/qml/qqmlnetworkaccessmanagerfactory.h create mode 100644 src/qml/qml/qqmlnotifier.cpp create mode 100644 src/qml/qml/qqmlnotifier_p.h create mode 100644 src/qml/qml/qqmlnullablevalue_p_p.h create mode 100644 src/qml/qml/qqmlopenmetaobject.cpp create mode 100644 src/qml/qml/qqmlopenmetaobject_p.h create mode 100644 src/qml/qml/qqmlparserstatus.cpp create mode 100644 src/qml/qml/qqmlparserstatus.h create mode 100644 src/qml/qml/qqmlprivate.h create mode 100644 src/qml/qml/qqmlproperty.cpp create mode 100644 src/qml/qml/qqmlproperty.h create mode 100644 src/qml/qml/qqmlproperty_p.h create mode 100644 src/qml/qml/qqmlpropertycache.cpp create mode 100644 src/qml/qml/qqmlpropertycache_p.h create mode 100644 src/qml/qml/qqmlpropertyvalueinterceptor.cpp create mode 100644 src/qml/qml/qqmlpropertyvalueinterceptor_p.h create mode 100644 src/qml/qml/qqmlpropertyvaluesource.cpp create mode 100644 src/qml/qml/qqmlpropertyvaluesource.h create mode 100644 src/qml/qml/qqmlproxymetaobject.cpp create mode 100644 src/qml/qml/qqmlproxymetaobject_p.h create mode 100644 src/qml/qml/qqmlrewrite.cpp create mode 100644 src/qml/qml/qqmlrewrite_p.h create mode 100644 src/qml/qml/qqmlscript.cpp create mode 100644 src/qml/qml/qqmlscript_p.h create mode 100644 src/qml/qml/qqmlscriptstring.cpp create mode 100644 src/qml/qml/qqmlscriptstring.h create mode 100644 src/qml/qml/qqmlscriptstring_p.h create mode 100644 src/qml/qml/qqmlstringconverters.cpp create mode 100644 src/qml/qml/qqmlstringconverters_p.h create mode 100644 src/qml/qml/qqmltypeloader.cpp create mode 100644 src/qml/qml/qqmltypeloader_p.h create mode 100644 src/qml/qml/qqmltypenamecache.cpp create mode 100644 src/qml/qml/qqmltypenamecache_p.h create mode 100644 src/qml/qml/qqmltypenotavailable.cpp create mode 100644 src/qml/qml/qqmltypenotavailable_p.h create mode 100644 src/qml/qml/qqmlvaluetype.cpp create mode 100644 src/qml/qml/qqmlvaluetype_p.h create mode 100644 src/qml/qml/qqmlvme.cpp create mode 100644 src/qml/qml/qqmlvme_p.h create mode 100644 src/qml/qml/qqmlvmemetaobject.cpp create mode 100644 src/qml/qml/qqmlvmemetaobject_p.h create mode 100644 src/qml/qml/qqmlwatcher.cpp create mode 100644 src/qml/qml/qqmlwatcher_p.h create mode 100644 src/qml/qml/qqmlxmlhttprequest.cpp create mode 100644 src/qml/qml/qqmlxmlhttprequest_p.h create mode 100644 src/qml/qml/qquickapplication.cpp create mode 100644 src/qml/qml/qquickapplication_p.h create mode 100644 src/qml/qml/qquicklistmodel.cpp create mode 100644 src/qml/qml/qquicklistmodel_p.h create mode 100644 src/qml/qml/qquicklistmodel_p_p.h create mode 100644 src/qml/qml/qquicklistmodelworkeragent.cpp create mode 100644 src/qml/qml/qquicklistmodelworkeragent_p.h create mode 100644 src/qml/qml/qquickworkerscript.cpp create mode 100644 src/qml/qml/qquickworkerscript_p.h create mode 100644 src/qml/qml/rewriter/rewriter.pri create mode 100644 src/qml/qml/rewriter/textwriter.cpp create mode 100644 src/qml/qml/rewriter/textwriter_p.h create mode 100644 src/qml/qml/v4/qv4bindings.cpp create mode 100644 src/qml/qml/v4/qv4bindings_p.h create mode 100644 src/qml/qml/v4/qv4compiler.cpp create mode 100644 src/qml/qml/v4/qv4compiler_p.h create mode 100644 src/qml/qml/v4/qv4compiler_p_p.h create mode 100644 src/qml/qml/v4/qv4instruction.cpp create mode 100644 src/qml/qml/v4/qv4instruction_p.h create mode 100644 src/qml/qml/v4/qv4ir.cpp create mode 100644 src/qml/qml/v4/qv4ir_p.h create mode 100644 src/qml/qml/v4/qv4irbuilder.cpp create mode 100644 src/qml/qml/v4/qv4irbuilder_p.h create mode 100644 src/qml/qml/v4/qv4program_p.h create mode 100644 src/qml/qml/v4/v4.pri create mode 100644 src/qml/qml/v8/notes.txt create mode 100644 src/qml/qml/v8/qjsconverter_impl_p.h create mode 100644 src/qml/qml/v8/qjsconverter_p.h create mode 100644 src/qml/qml/v8/qjsengine.cpp create mode 100644 src/qml/qml/v8/qjsengine.h create mode 100644 src/qml/qml/v8/qjsengine_p.h create mode 100644 src/qml/qml/v8/qjsvalue.cpp create mode 100644 src/qml/qml/v8/qjsvalue.h create mode 100644 src/qml/qml/v8/qjsvalue_impl_p.h create mode 100644 src/qml/qml/v8/qjsvalue_p.h create mode 100644 src/qml/qml/v8/qjsvalueiterator.cpp create mode 100644 src/qml/qml/v8/qjsvalueiterator.h create mode 100644 src/qml/qml/v8/qjsvalueiterator_impl_p.h create mode 100644 src/qml/qml/v8/qjsvalueiterator_p.h create mode 100644 src/qml/qml/v8/qqmlbuiltinfunctions.cpp create mode 100644 src/qml/qml/v8/qqmlbuiltinfunctions_p.h create mode 100644 src/qml/qml/v8/qscript_impl_p.h create mode 100644 src/qml/qml/v8/qscriptisolate_p.h create mode 100644 src/qml/qml/v8/qscriptoriginalglobalobject_p.h create mode 100644 src/qml/qml/v8/qscriptshareddata_p.h create mode 100644 src/qml/qml/v8/qscripttools_p.h create mode 100644 src/qml/qml/v8/qv8_p.h create mode 100644 src/qml/qml/v8/qv8bindings.cpp create mode 100644 src/qml/qml/v8/qv8bindings_p.h create mode 100644 src/qml/qml/v8/qv8contextwrapper.cpp create mode 100644 src/qml/qml/v8/qv8contextwrapper_p.h create mode 100644 src/qml/qml/v8/qv8debug_p.h create mode 100644 src/qml/qml/v8/qv8domerrors.cpp create mode 100644 src/qml/qml/v8/qv8domerrors_p.h create mode 100644 src/qml/qml/v8/qv8engine.cpp create mode 100644 src/qml/qml/v8/qv8engine_impl_p.h create mode 100644 src/qml/qml/v8/qv8engine_p.h create mode 100644 src/qml/qml/v8/qv8include.cpp create mode 100644 src/qml/qml/v8/qv8include_p.h create mode 100644 src/qml/qml/v8/qv8listwrapper.cpp create mode 100644 src/qml/qml/v8/qv8listwrapper_p.h create mode 100644 src/qml/qml/v8/qv8profiler_p.h create mode 100644 src/qml/qml/v8/qv8qobjectwrapper.cpp create mode 100644 src/qml/qml/v8/qv8qobjectwrapper_p.h create mode 100644 src/qml/qml/v8/qv8sequencewrapper.cpp create mode 100644 src/qml/qml/v8/qv8sequencewrapper_p.h create mode 100644 src/qml/qml/v8/qv8sequencewrapper_p_p.h create mode 100644 src/qml/qml/v8/qv8sqlerrors.cpp create mode 100644 src/qml/qml/v8/qv8sqlerrors_p.h create mode 100644 src/qml/qml/v8/qv8stringwrapper.cpp create mode 100644 src/qml/qml/v8/qv8stringwrapper_p.h create mode 100644 src/qml/qml/v8/qv8typewrapper.cpp create mode 100644 src/qml/qml/v8/qv8typewrapper_p.h create mode 100644 src/qml/qml/v8/qv8valuetypewrapper.cpp create mode 100644 src/qml/qml/v8/qv8valuetypewrapper_p.h create mode 100644 src/qml/qml/v8/qv8variantresource_p.h create mode 100644 src/qml/qml/v8/qv8variantwrapper.cpp create mode 100644 src/qml/qml/v8/qv8variantwrapper_p.h create mode 100644 src/qml/qml/v8/qv8worker.cpp create mode 100644 src/qml/qml/v8/qv8worker_p.h create mode 100644 src/qml/qml/v8/script.pri create mode 100644 src/qml/qml/v8/v8.pri (limited to 'src/qml/qml') diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri new file mode 100644 index 0000000000..f2fec4e2dd --- /dev/null +++ b/src/qml/qml/ftw/ftw.pri @@ -0,0 +1,29 @@ +HEADERS += \ + $$PWD/qbitfield_p.h \ + $$PWD/qintrusivelist_p.h \ + $$PWD/qpodvector_p.h \ + $$PWD/qhashedstring_p.h \ + $$PWD/qqmlrefcount_p.h \ + $$PWD/qqmlpool_p.h \ + $$PWD/qfieldlist_p.h \ + $$PWD/qfastmetabuilder_p.h \ + $$PWD/qhashfield_p.h \ + $$PWD/qqmlthread_p.h \ + $$PWD/qfinitestack_p.h \ + $$PWD/qrecursionwatcher_p.h \ + $$PWD/qdeletewatcher_p.h \ + $$PWD/qrecyclepool_p.h \ + $$PWD/qflagpointer_p.h \ + $$PWD/qqmltrace_p.h \ + $$PWD/qpointervaluepair_p.h \ + $$PWD/qlazilyallocated_p.h \ + +SOURCES += \ + $$PWD/qintrusivelist.cpp \ + $$PWD/qhashedstring.cpp \ + $$PWD/qqmlpool.cpp \ + $$PWD/qfastmetabuilder.cpp \ + $$PWD/qqmlthread.cpp \ + $$PWD/qqmltrace.cpp \ + +contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h new file mode 100644 index 0000000000..75f80dd896 --- /dev/null +++ b/src/qml/qml/ftw/qbitfield_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBITFIELD_P_H +#define QBITFIELD_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 + +QT_BEGIN_NAMESPACE + +class QBitField +{ +public: + inline QBitField(); + inline QBitField(const quint32 *, int bits); + inline QBitField(const QBitField &); + inline ~QBitField(); + + inline QBitField &operator=(const QBitField &); + + inline quint32 size() const; + inline QBitField united(const QBitField &); + inline bool testBit(int) const; + +private: + quint32 bits:31; + quint32 *ownData; + const quint32 *data; +}; + +QBitField::QBitField() +: bits(0), ownData(0), data(0) +{ +} + +QBitField::QBitField(const quint32 *bitData, int bitCount) +: bits((quint32)bitCount), ownData(0), data(bitData) +{ +} + +QBitField::QBitField(const QBitField &other) +: bits(other.bits), ownData(other.ownData), data(other.data) +{ + if (ownData) + ++(*ownData); +} + +QBitField::~QBitField() +{ + if (ownData) + if(0 == --(*ownData)) delete [] ownData; +} + +QBitField &QBitField::operator=(const QBitField &other) +{ + if (other.data == data) + return *this; + + if (ownData) + if(0 == --(*ownData)) delete [] ownData; + + bits = other.bits; + ownData = other.ownData; + data = other.data; + + if (ownData) + ++(*ownData); + + return *this; +} + +inline quint32 QBitField::size() const +{ + return bits; +} + +QBitField QBitField::united(const QBitField &o) +{ + if (o.bits == 0) { + return *this; + } else if (bits == 0) { + return o; + } else { + int max = (bits > o.bits)?bits:o.bits; + int length = (max + 31) / 32; + QBitField rv; + rv.bits = max; + rv.ownData = new quint32[length + 1]; + *(rv.ownData) = 1; + rv.data = rv.ownData + 1; + if (bits > o.bits) { + ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= o.data[ii]; + } else { + ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= data[ii]; + } + return rv; + } +} + +bool QBitField::testBit(int b) const +{ + Q_ASSERT(b >= 0); + if ((quint32)b < bits) { + return data[b / 32] & (1 << (b % 32)); + } else { + return false; + } +} + +QT_END_NAMESPACE + +#endif // QBITFIELD_P_H diff --git a/src/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/ftw/qdeletewatcher_p.h new file mode 100644 index 0000000000..9f7b100429 --- /dev/null +++ b/src/qml/qml/ftw/qdeletewatcher_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDELETEWATCHER_P_H +#define QDELETEWATCHER_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 + +QT_BEGIN_NAMESPACE + +class QDeleteWatchable +{ +public: + inline QDeleteWatchable(); + inline ~QDeleteWatchable(); +private: + friend class QDeleteWatcher; + bool *_w; +}; + +class QDeleteWatcher { +public: + inline QDeleteWatcher(QDeleteWatchable *data); + inline ~QDeleteWatcher(); + inline bool wasDeleted() const; +private: + void *operator new(size_t); + bool *_w; + bool _s; + QDeleteWatchable *m_d; +}; + +QDeleteWatchable::QDeleteWatchable() +: _w(0) +{ +} + +QDeleteWatchable::~QDeleteWatchable() +{ + if (_w) *_w = true; +} + +QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data) +: _s(false), m_d(data) +{ + if (!m_d->_w) + m_d->_w = &_s; + _w = m_d->_w; +} + +QDeleteWatcher::~QDeleteWatcher() +{ + if (false == *_w && &_s == m_d->_w) + m_d->_w = 0; +} + +bool QDeleteWatcher::wasDeleted() const +{ + return *_w; +} + +QT_END_NAMESPACE + +#endif // QDELETEWATCHER_P_H diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp new file mode 100644 index 0000000000..9663c1e944 --- /dev/null +++ b/src/qml/qml/ftw/qfastmetabuilder.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfastmetabuilder_p.h" + +#include + +QT_BEGIN_NAMESPACE + +struct QFastMetaBuilderHeader +{ + int fieldCount; +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; //since revision 2 + int flags; //since revision 3 + int signalCount; //since revision 4 +}; + +enum MetaObjectFlag { + DynamicMetaObject = 0x01 +}; + +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Constant = 0x00000400, + Final = 0x00000800, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Revisioned = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40, + MethodRevisioned = 0x80 +}; + +#define FMBHEADER_FIELD_COUNT 1 + +#define HEADER_FIELD_COUNT 14 +#define CLASSINFO_FIELD_COUNT 2 +#define METHOD_FIELD_COUNT 5 +#define PROPERTY_FIELD_COUNT 3 +#define PROPERTY_NOTIFY_FIELD_COUNT 1 + +static inline uint *fieldPointer(QByteArray &data) +{ return reinterpret_cast(data.data()) + FMBHEADER_FIELD_COUNT; } + +static inline const uint *fieldPointer(const QByteArray &data) +{ return reinterpret_cast(data.constData()) + FMBHEADER_FIELD_COUNT; } + +static inline QMetaObjectPrivate *priv(QByteArray &data) +{ return reinterpret_cast(fieldPointer(data)); } + +static inline const QMetaObjectPrivate *priv(const QByteArray &data) +{ return reinterpret_cast(fieldPointer(data)); } + +static inline QFastMetaBuilderHeader *header(QByteArray &data) +{ return reinterpret_cast(data.data()); } + +static inline const QFastMetaBuilderHeader *header(const QByteArray &data) +{ return reinterpret_cast(data.constData()); } + +QFastMetaBuilder::QFastMetaBuilder() +: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0) +{ +} + +QFastMetaBuilder::~QFastMetaBuilder() +{ +} + +QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount) +{ + Q_ASSERT(m_data.isEmpty()); + Q_ASSERT(classNameLength > 0); + Q_ASSERT(propertyCount >= 0); + Q_ASSERT(methodCount >= 0); + Q_ASSERT(signalCount >= 0); + Q_ASSERT(classInfoCount >= 0); + + int fieldCount = FMBHEADER_FIELD_COUNT + + HEADER_FIELD_COUNT + + propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) + + methodCount * (METHOD_FIELD_COUNT) + + signalCount * (METHOD_FIELD_COUNT) + + classInfoCount * CLASSINFO_FIELD_COUNT; + + m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1); + m_stringData = m_data.data() + m_data.size() - classNameLength - 1; + m_stringDataLength = classNameLength + 1; + m_stringDataAllocated = classNameLength + 1; + m_stringData[classNameLength] = 0; + m_zeroPtr = classNameLength; + + header(m_data)->fieldCount = fieldCount; + + QMetaObjectPrivate *p = priv(m_data); + + int dataIndex = HEADER_FIELD_COUNT; + + p->revision = 4; + p->className = 0; + + // Class infos + p->classInfoCount = classInfoCount; + if (p->classInfoCount) { + p->classInfoData = dataIndex; + dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT; + } else { + p->classInfoData = 0; + } + + // Methods + p->methodCount = methodCount + signalCount; + if (p->methodCount) { + p->methodData = dataIndex; + dataIndex += p->methodCount * METHOD_FIELD_COUNT; + } else { + p->methodData = 0; + } + p->signalCount = signalCount; + + // Properties + p->propertyCount = propertyCount; + if (p->propertyCount) { + p->propertyData = dataIndex; + dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT); + } else { + p->propertyData = 0; + } + + // Flags + p->flags = DynamicMetaObject; // Always dynamic + + // Enums and constructors not supported + p->enumeratorCount = 0; + p->enumeratorData = 0; + p->constructorCount = 0; + p->constructorData = 0; + + StringRef className; + className._b = this; + className._o = 0; + className._l = classNameLength; + return className; +} + +// Allocate a string of \a length. \a length should *not* include the null terminator. +QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length) +{ + Q_ASSERT(length > 0); + + StringRef sr; + sr._b = this; + sr._o = m_stringDataLength; + sr._l = length; + + m_stringDataLength += length + 1 /* for null terminator */; + + return sr; +} + +void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!key.isEmpty() && !value.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->classInfoCount); + + uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT; + // classinfo: key, value + ptr[0] = key.offset(); ptr[1] = value.offset(); +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = mtype << 24; + ptr[2] |= flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = mtype << 24; + ptr[2] |= flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QFastMetaBuilder::PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForSignal(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSignal; +} + +void QFastMetaBuilder::setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForMethod(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSlot; +} + +int QFastMetaBuilder::metaObjectIndexForSignal(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(index < priv(m_data)->signalCount); + return index; +} + +int QFastMetaBuilder::metaObjectIndexForMethod(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + + const QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < (p->methodCount - p->signalCount)); + return index + p->signalCount; +} + +void QFastMetaBuilder::allocateStringData() +{ + if (m_stringDataAllocated < m_stringDataLength) { + m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated); + m_stringDataAllocated = m_stringDataLength; + m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); + } +} + +void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) +{ + output->d.superdata = parent; + output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint); + output->d.data = fieldPointer(data); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h new file mode 100644 index 0000000000..c1f6a3de5c --- /dev/null +++ b/src/qml/qml/ftw/qfastmetabuilder_p.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFASTMETABUILDER_P_H +#define QFASTMETABUILDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +struct QMetaObject; +class QFastMetaBuilder +{ +public: + QFastMetaBuilder(); + ~QFastMetaBuilder(); + + struct StringRef { + public: + inline StringRef(); + inline StringRef(const StringRef &); + inline StringRef &operator=(const StringRef &); + + inline void load(const QHashedStringRef &); + inline void load(const QByteArray &); + inline void load(const char *); + + inline bool isEmpty() const; + inline QFastMetaBuilder *builder() const; + inline int offset() const; + inline char *data(); + inline int length() const; + private: + friend class QFastMetaBuilder; + + QFastMetaBuilder *_b; + int _o; + int _l; + }; + StringRef newString(int length); + + // Returns class name + StringRef init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount); + + void setClassInfo(int index, const StringRef &key, const StringRef &value); + + enum PropertyFlag { + None = 0x00000000, + Writable = 0x00000002, + Resettable = 0x00000004, + Constant = 0x00000400, + Final = 0x00000800 + }; + // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + PropertyFlag flags, int notifySignal = -1); + void setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + void setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + + int metaObjectIndexForSignal(int) const; + int metaObjectIndexForMethod(int) const; + + QByteArray toData() const { return m_data; } + static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &); +private: + friend struct StringRef; + + QByteArray m_data; + int m_zeroPtr; + + void allocateStringData(); + char *m_stringData; + int m_stringDataLength; + int m_stringDataAllocated; +}; + +QFastMetaBuilder::StringRef::StringRef() +: _b(0), _o(0), _l(0) +{ +} + +QFastMetaBuilder::StringRef::StringRef(const StringRef &o) +: _b(o._b), _o(o._o), _l(o._l) +{ +} + +QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o) +{ + _b = o._b; + _o = o._o; + _l = o._l; + return *this; +} + +bool QFastMetaBuilder::StringRef::isEmpty() const +{ + return _l == 0; +} + +QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const +{ + return _b; +} + +int QFastMetaBuilder::StringRef::offset() const +{ + return _o; +} + +char *QFastMetaBuilder::StringRef::data() +{ + Q_ASSERT(_b); + if (_b->m_stringDataLength != _b->m_stringDataAllocated) + _b->allocateStringData(); + return _b->m_stringData + _o; +} + +int QFastMetaBuilder::StringRef::length() const +{ + return _l; +} + +void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str) +{ + Q_ASSERT(str.utf8length() == _l); + str.writeUtf8(data()); + *(data() + _l) = 0; +} + +void QFastMetaBuilder::StringRef::load(const QByteArray &str) +{ + Q_ASSERT(str.length() == _l); + strcpy(data(), str.constData()); +} + +void QFastMetaBuilder::StringRef::load(const char *str) +{ + Q_ASSERT(strlen(str) == (uint)_l); + strcpy(data(), str); +} + +QT_END_NAMESPACE + +#endif // QFASTMETABUILDER_P_H + diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h new file mode 100644 index 0000000000..da5074b3cd --- /dev/null +++ b/src/qml/qml/ftw/qfieldlist_p.h @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFIELDLIST_P_H +#define QFIELDLIST_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 + +#include + +// QForwardFieldList is a super simple linked list that can only prepend +template +class QForwardFieldList +{ +public: + inline QForwardFieldList(); + inline N *first() const; + inline N *takeFirst(); + + inline void prepend(N *); + + inline bool isEmpty() const; + inline bool isOne() const; + inline bool isMany() const; + + static inline N *next(N *v); + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline bool flag2() const; + inline void setFlag2(); + inline void clearFlag2(); + inline void setFlag2Value(bool); +private: + QFlagPointer _first; +}; + +// QFieldList is a simple linked list, that can append and prepend and also +// maintains a count +template +class QFieldList +{ +public: + inline QFieldList(); + inline N *first() const; + inline N *takeFirst(); + + inline void append(N *); + inline void prepend(N *); + + inline bool isEmpty() const; + inline bool isOne() const; + inline bool isMany() const; + inline int count() const; + + inline void append(QFieldList &); + inline void prepend(QFieldList &); + inline void insertAfter(N *, QFieldList &); + + inline void copyAndClear(QFieldList &); + inline void copyAndClearAppend(QForwardFieldList &); + inline void copyAndClearPrepend(QForwardFieldList &); + + static inline N *next(N *v); + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); +private: + N *_first; + N *_last; + quint32 _flag:1; + quint32 _count:31; +}; + +template +QForwardFieldList::QForwardFieldList() +{ +} + +template +N *QForwardFieldList::first() const +{ + return *_first; +} + +template +N *QForwardFieldList::takeFirst() +{ + N *value = *_first; + if (value) { + _first = next(value); + value->*nextMember = 0; + } + return value; +} + +template +void QForwardFieldList::prepend(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + v->*nextMember = *_first; + _first = v; +} + +template +bool QForwardFieldList::isEmpty() const +{ + return _first.isNull(); +} + +template +bool QForwardFieldList::isOne() const +{ + return *_first && _first->*nextMember == 0; +} + +template +bool QForwardFieldList::isMany() const +{ + return *_first && _first->*nextMember != 0; +} + +template +N *QForwardFieldList::next(N *v) +{ + Q_ASSERT(v); + return v->*nextMember; +} + +template +bool QForwardFieldList::flag() const +{ + return _first.flag(); +} + +template +void QForwardFieldList::setFlag() +{ + _first.setFlag(); +} + +template +void QForwardFieldList::clearFlag() +{ + _first.clearFlag(); +} + +template +void QForwardFieldList::setFlagValue(bool v) +{ + _first.setFlagValue(v); +} + +template +bool QForwardFieldList::flag2() const +{ + return _first.flag2(); +} + +template +void QForwardFieldList::setFlag2() +{ + _first.setFlag2(); +} + +template +void QForwardFieldList::clearFlag2() +{ + _first.clearFlag2(); +} + +template +void QForwardFieldList::setFlag2Value(bool v) +{ + _first.setFlag2Value(v); +} + +template +QFieldList::QFieldList() +: _first(0), _last(0), _flag(0), _count(0) +{ +} + +template +N *QFieldList::first() const +{ + return _first; +} + +template +N *QFieldList::takeFirst() +{ + N *value = _first; + if (value) { + _first = next(value); + if (_last == value) { + Q_ASSERT(_first == 0); + _last = 0; + } + value->*nextMember = 0; + --_count; + } + return value; +} + +template +void QFieldList::append(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + if (isEmpty()) { + _first = v; + _last = v; + } else { + _last->*nextMember = v; + _last = v; + } + ++_count; +} + +template +void QFieldList::prepend(N *v) +{ + Q_ASSERT(v->*nextMember == 0); + if (isEmpty()) { + _first = v; + _last = v; + } else { + v->*nextMember = _first; + _first = v; + } + ++_count; +} + +template +bool QFieldList::isEmpty() const +{ + return _count == 0; +} + +template +bool QFieldList::isOne() const +{ + return _count == 1; +} + +template +bool QFieldList::isMany() const +{ + return _count > 1; +} + +template +int QFieldList::count() const +{ + return _count; +} + +template +N *QFieldList::next(N *v) +{ + Q_ASSERT(v); + return v->*nextMember; +} + +template +void QFieldList::append(QFieldList &o) +{ + if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + _last->*nextMember = o._first; + _last = o._last; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template +void QFieldList::prepend(QFieldList &o) +{ + if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + o._last->*nextMember = _first; + _first = o._first; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template +void QFieldList::insertAfter(N *after, QFieldList &o) +{ + if (after == 0) { + prepend(o); + } else if (after == _last) { + append(o); + } else if (!o.isEmpty()) { + if (isEmpty()) { + _first = o._first; + _last = o._last; + _count = o._count; + } else { + o._last->*nextMember = after->*nextMember; + after->*nextMember = o._first; + _count += o._count; + } + o._first = o._last = 0; o._count = 0; + } +} + +template +void QFieldList::copyAndClear(QFieldList &o) +{ + _first = o._first; + _last = o._last; + _count = o._count; + o._first = o._last = 0; + o._count = 0; +} + +template +void QFieldList::copyAndClearAppend(QForwardFieldList &o) +{ + _first = 0; + _last = 0; + _count = 0; + while (N *n = o.takeFirst()) append(n); +} + +template +void QFieldList::copyAndClearPrepend(QForwardFieldList &o) +{ + _first = 0; + _last = 0; + _count = 0; + while (N *n = o.takeFirst()) prepend(n); +} + +template +bool QFieldList::flag() const +{ + return _flag; +} + +template +void QFieldList::setFlag() +{ + _flag = true; +} + +template +void QFieldList::clearFlag() +{ + _flag = false; +} + +template +void QFieldList::setFlagValue(bool v) +{ + _flag = v; +} + +#endif // QFIELDLIST_P_H diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h new file mode 100644 index 0000000000..c5a9fbaedb --- /dev/null +++ b/src/qml/qml/ftw/qfinitestack_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFINITESTACK_P_H +#define QFINITESTACK_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 + +QT_BEGIN_NAMESPACE + +template +struct QFiniteStack { + inline QFiniteStack(); + inline ~QFiniteStack(); + + inline void deallocate(); + inline void allocate(int size); + + inline bool isEmpty() const; + inline const T &top() const; + inline T &top(); + inline void push(const T &o); + inline T pop(); + inline int count() const; + inline const T &at(int index) const; + inline T &operator[](int index); +private: + T *_array; + int _alloc; + int _size; +}; + +template +QFiniteStack::QFiniteStack() +: _array(0), _alloc(0), _size(0) +{ +} + +template +QFiniteStack::~QFiniteStack() +{ + deallocate(); +} + +template +bool QFiniteStack::isEmpty() const +{ + return _size == 0; +} + +template +const T &QFiniteStack::top() const +{ + return _array[_size - 1]; +} + +template +T &QFiniteStack::top() +{ + return _array[_size - 1]; +} + +template +void QFiniteStack::push(const T &o) +{ + if (QTypeInfo::isComplex) { + new (_array + _size++) T(o); + } else { + _array[_size++] = o; + } +} + +template +T QFiniteStack::pop() +{ + --_size; + + if (QTypeInfo::isComplex) { + T rv = _array[_size]; + (_array + _size)->~T(); + return rv; + } else { + return _array[_size]; + } +} + +template +int QFiniteStack::count() const +{ + return _size; +} + +template +const T &QFiniteStack::at(int index) const +{ + return _array[index]; +} + +template +T &QFiniteStack::operator[](int index) +{ + return _array[index]; +} + +template +void QFiniteStack::allocate(int size) +{ + Q_ASSERT(_array == 0); + Q_ASSERT(_alloc == 0); + Q_ASSERT(_size == 0); + + if (!size) return; + + _array = (T *)qMalloc(size * sizeof(T)); + _alloc = size; +} + +template +void QFiniteStack::deallocate() +{ + if (QTypeInfo::isComplex) { + T *i = _array + _size; + while (i != _array) + (--i)->~T(); + } + + qFree(_array); + + _array = 0; + _alloc = 0; + _size = 0; +} + +QT_END_NAMESPACE + +#endif // QFINITESTACK_P_H + diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h new file mode 100644 index 0000000000..a4b20d9e2a --- /dev/null +++ b/src/qml/qml/ftw/qflagpointer_p.h @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFLAGPOINTER_P_H +#define QFLAGPOINTER_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 + +QT_BEGIN_NAMESPACE + +template +class QFlagPointer { +public: + inline QFlagPointer(); + inline QFlagPointer(T *); + inline QFlagPointer(const QFlagPointer &o); + + inline bool isNull() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline bool flag2() const; + inline void setFlag2(); + inline void clearFlag2(); + inline void setFlag2Value(bool); + + inline QFlagPointer &operator=(const QFlagPointer &o); + inline QFlagPointer &operator=(T *); + + inline T *operator->() const; + inline T *operator*() const; + +private: + quintptr ptr_value; + + static const quintptr FlagBit = 0x1; + static const quintptr Flag2Bit = 0x2; + static const quintptr FlagsMask = FlagBit | Flag2Bit; +}; + +template +class QBiPointer { +public: + inline QBiPointer(); + inline QBiPointer(T *); + inline QBiPointer(T2 *); + inline QBiPointer(const QBiPointer &o); + + inline bool isNull() const; + inline bool isT1() const; + inline bool isT2() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline QBiPointer &operator=(const QBiPointer &o); + inline QBiPointer &operator=(T *); + inline QBiPointer &operator=(T2 *); + + inline T *asT1() const; + inline T2 *asT2() const; + +private: + quintptr ptr_value; + + static const quintptr FlagBit = 0x1; + static const quintptr Flag2Bit = 0x2; + static const quintptr FlagsMask = FlagBit | Flag2Bit; +}; + +template +QFlagPointer::QFlagPointer() +: ptr_value(0) +{ +} + +template +QFlagPointer::QFlagPointer(T *v) +: ptr_value(quintptr(v)) +{ + Q_ASSERT((ptr_value & FlagsMask) == 0); +} + +template +QFlagPointer::QFlagPointer(const QFlagPointer &o) +: ptr_value(o.ptr_value) +{ +} + +template +bool QFlagPointer::isNull() const +{ + return 0 == (ptr_value & (~FlagsMask)); +} + +template +bool QFlagPointer::flag() const +{ + return ptr_value & FlagBit; +} + +template +void QFlagPointer::setFlag() +{ + ptr_value |= FlagBit; +} + +template +void QFlagPointer::clearFlag() +{ + ptr_value &= ~FlagBit; +} + +template +void QFlagPointer::setFlagValue(bool v) +{ + if (v) setFlag(); + else clearFlag(); +} + +template +bool QFlagPointer::flag2() const +{ + return ptr_value & Flag2Bit; +} + +template +void QFlagPointer::setFlag2() +{ + ptr_value|= Flag2Bit; +} + +template +void QFlagPointer::clearFlag2() +{ + ptr_value &= ~Flag2Bit; +} + +template +void QFlagPointer::setFlag2Value(bool v) +{ + if (v) setFlag2(); + else clearFlag2(); +} + +template +QFlagPointer &QFlagPointer::operator=(const QFlagPointer &o) +{ + ptr_value = o.ptr_value; + return *this; +} + +template +QFlagPointer &QFlagPointer::operator=(T *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagsMask); + return *this; +} + +template +T *QFlagPointer::operator->() const +{ + return (T *)(ptr_value & ~FlagsMask); +} + +template +T *QFlagPointer::operator*() const +{ + return (T *)(ptr_value & ~FlagsMask); +} + +template +QBiPointer::QBiPointer() +: ptr_value(0) +{ +} + +template +QBiPointer::QBiPointer(T *v) +: ptr_value(quintptr(v)) +{ + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template +QBiPointer::QBiPointer(T2 *v) +: ptr_value(quintptr(v) | Flag2Bit) +{ + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template +QBiPointer::QBiPointer(const QBiPointer &o) +: ptr_value(o.ptr_value) +{ +} + +template +bool QBiPointer::isNull() const +{ + return 0 == (ptr_value & (~FlagsMask)); +} + +template +bool QBiPointer::isT1() const +{ + return !(ptr_value & Flag2Bit); +} + +template +bool QBiPointer::isT2() const +{ + return ptr_value & Flag2Bit; +} + +template +bool QBiPointer::flag() const +{ + return ptr_value & FlagBit; +} + +template +void QBiPointer::setFlag() +{ + ptr_value |= FlagBit; +} + +template +void QBiPointer::clearFlag() +{ + ptr_value &= ~FlagBit; +} + +template +void QBiPointer::setFlagValue(bool v) +{ + if (v) setFlag(); + else clearFlag(); +} + +template +QBiPointer &QBiPointer::operator=(const QBiPointer &o) +{ + ptr_value = o.ptr_value; + return *this; +} + +template +QBiPointer &QBiPointer::operator=(T *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit); + return *this; +} + +template +QBiPointer &QBiPointer::operator=(T2 *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit; + return *this; +} + +template +T *QBiPointer::asT1() const +{ + Q_ASSERT(isT1()); + return (T *)(ptr_value & ~FlagsMask); +} + +template +T2 *QBiPointer::asT2() const +{ + Q_ASSERT(isT2()); + return (T2 *)(ptr_value & ~FlagsMask); +} + +QT_END_NAMESPACE + +#endif // QFLAGPOINTER_P_H diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp new file mode 100644 index 0000000000..1f09d50ed3 --- /dev/null +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -0,0 +1,490 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhashedstring_p.h" + +// This is a reimplementation of V8's string hash algorithm. It is significantly +// faster to do it here than call into V8, but it adds the maintainence burden of +// ensuring that the two hashes are identical. We Q_ASSERT() that the two return +// the same value. If these asserts start to fail, the hash code needs to be +// synced with V8. +namespace String { + static const int kMaxArrayIndexSize = 10; + static const int kMaxHashCalcLength = 16383; + static const int kNofHashBitFields = 2; + static const int kHashShift = kNofHashBitFields; + static const int kIsNotArrayIndexMask = 1 << 1; + static const int kArrayIndexValueBits = 24; + static const int kArrayIndexHashLengthShift = kArrayIndexValueBits + kNofHashBitFields; + static const int kMaxCachedArrayIndexLength = 7; +}; + +template +uint32_t calculateHash(const schar* chars, int length) { + if (length > String::kMaxHashCalcLength) { + // V8 trivial hash + return (length << String::kHashShift) | String::kIsNotArrayIndexMask; + } + + uint32_t raw_running_hash = 0; + uint32_t array_index = 0; + bool is_array_index = (0 < length && length <= String::kMaxArrayIndexSize); + bool is_first_char = true; + + int ii = 0; + for (;is_array_index && ii < length; ++ii) { + quint32 c = *chars++; + + raw_running_hash += c; + raw_running_hash += (raw_running_hash << 10); + raw_running_hash ^= (raw_running_hash >> 6); + + if (c < '0' || c > '9') { + is_array_index = false; + } else { + int d = c - '0'; + if (is_first_char) { + is_first_char = false; + if (c == '0' && length > 1) { + is_array_index = false; + continue; + } + } + if (array_index > 429496729U - ((d + 2) >> 3)) { + is_array_index = false; + } else { + array_index = array_index * 10 + d; + } + } + } + + for (;ii < length; ++ii) { + raw_running_hash += *chars++; + raw_running_hash += (raw_running_hash << 10); + raw_running_hash ^= (raw_running_hash >> 6); + } + + if (is_array_index) { + array_index <<= String::kHashShift; + array_index |= length << String::kArrayIndexHashLengthShift; + return array_index; + } else { + raw_running_hash += (raw_running_hash << 3); + raw_running_hash ^= (raw_running_hash >> 11); + raw_running_hash += (raw_running_hash << 15); + if (raw_running_hash == 0) { + raw_running_hash = 27; + } + + return (raw_running_hash << String::kHashShift) | String::kIsNotArrayIndexMask; + } +} + +inline quint32 stringHash(const QChar* data, int length) +{ + quint32 rv = calculateHash((quint16*)data, length) >> String::kHashShift; + Q_ASSERT(rv == v8::String::ComputeHash((uint16_t*)data, length)); + return rv; +} + +inline quint32 stringHash(const char *data, int length) +{ + quint32 rv = calculateHash((quint8*)data, length) >> String::kHashShift; + Q_ASSERT(rv == v8::String::ComputeHash((char *)data, length)); + return rv; +} + +void QHashedString::computeHash() const +{ + m_hash = stringHash(constData(), length()); +} + +void QHashedStringRef::computeHash() const +{ + m_hash = stringHash(m_data, m_length); +} + +void QHashedCStringRef::computeHash() const +{ + m_hash = stringHash(m_data, m_length); +} + +/* + A QHash has initially around pow(2, MinNumBits) buckets. For + example, if MinNumBits is 4, it has 17 buckets. +*/ +const int MinNumBits = 4; + +/* + The prime_deltas array is a table of selected prime values, even + though it doesn't look like one. The primes we are using are 1, + 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate + surrounding of a power of two. + + The primeForNumBits() function returns the prime associated to a + power of two. For example, primeForNumBits(8) returns 257. +*/ + +static const uchar prime_deltas[] = { + 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, + 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 +}; + +static inline int primeForNumBits(int numBits) +{ + return (1 << numBits) + prime_deltas[numBits]; +} + +void QStringHashData::rehashToSize(int size, IteratorData first, + IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip) +{ + short bits = qMax(MinNumBits, (int)numBits); + while (primeForNumBits(bits) < size) bits++; + + if (bits > numBits) + rehashToBits(bits, first, Iterate, skip); +} + +void QStringHashData::rehashToBits(short bits, IteratorData first, + IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip) +{ + numBits = qMax(MinNumBits, (int)bits); + + int nb = primeForNumBits(numBits); + if (nb == numBuckets && buckets) + return; + + numBuckets = nb; + +#ifdef QSTRINGHASH_LINK_DEBUG + if (linkCount) + qFatal("QStringHash: Illegal attempt to rehash a linked hash."); +#endif + + delete [] buckets; + buckets = new QStringHashNode *[numBuckets]; + ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets); + + IteratorData nodeList = first; + while (nodeList.n) { + if (nodeList.n != skip) { + int bucket = nodeList.n->hash % numBuckets; + nodeList.n->next = buckets[bucket]; + buckets[bucket] = nodeList.n; + } + + nodeList = Iterate(nodeList); + } +} + +// Copy of QString's qMemCompare +bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + const quint16 *a = (const quint16 *)lhs; + const quint16 *b = (const quint16 *)rhs; + + if (a == b || !length) + return true; + + register union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = a; + sb.w = b; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + register const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + register const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} + +// Unicode stuff +static inline bool isUnicodeNonCharacter(uint ucs4) +{ + // Unicode has a couple of "non-characters" that one can use internally, + // but are not allowed to be used for text interchange. + // + // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF, + // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and + // U+FDEF (inclusive) + + return (ucs4 & 0xfffe) == 0xfffe + || (ucs4 - 0xfdd0U) < 16; +} + +static int utf8LengthFromUtf16(const QChar *uc, int len) +{ + int length = 0; + + int surrogate_high = -1; + + const QChar *ch = uc; + int invalid = 0; + + const QChar *end = ch + len; + while (ch < end) { + uint u = ch->unicode(); + if (surrogate_high >= 0) { + if (u >= 0xdc00 && u < 0xe000) { + u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000; + surrogate_high = -1; + } else { + // high surrogate without low + ++ch; + ++invalid; + surrogate_high = -1; + continue; + } + } else if (u >= 0xdc00 && u < 0xe000) { + // low surrogate without high + ++ch; + ++invalid; + continue; + } else if (u >= 0xd800 && u < 0xdc00) { + surrogate_high = u; + ++ch; + continue; + } + + if (u < 0x80) { + ++length; + } else { + if (u < 0x0800) { + ++length; + } else { + // is it one of the Unicode non-characters? + if (isUnicodeNonCharacter(u)) { + ++length; + ++ch; + ++invalid; + continue; + } + + if (u > 0xffff) { + ++length; + ++length; + } else { + ++length; + } + ++length; + } + ++length; + } + ++ch; + } + + return length; +} + +// Writes the utf8 version of uc to output. uc is of length len. +// There must be at least utf8LengthFromUtf16(uc, len) bytes in output. +// A null terminator is not written. +static void utf8FromUtf16(char *output, const QChar *uc, int len) +{ + uchar replacement = '?'; + int surrogate_high = -1; + + uchar* cursor = (uchar*)output; + const QChar *ch = uc; + int invalid = 0; + + const QChar *end = ch + len; + while (ch < end) { + uint u = ch->unicode(); + if (surrogate_high >= 0) { + if (u >= 0xdc00 && u < 0xe000) { + u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000; + surrogate_high = -1; + } else { + // high surrogate without low + *cursor = replacement; + ++ch; + ++invalid; + surrogate_high = -1; + continue; + } + } else if (u >= 0xdc00 && u < 0xe000) { + // low surrogate without high + *cursor = replacement; + ++ch; + ++invalid; + continue; + } else if (u >= 0xd800 && u < 0xdc00) { + surrogate_high = u; + ++ch; + continue; + } + + if (u < 0x80) { + *cursor++ = (uchar)u; + } else { + if (u < 0x0800) { + *cursor++ = 0xc0 | ((uchar) (u >> 6)); + } else { + // is it one of the Unicode non-characters? + if (isUnicodeNonCharacter(u)) { + *cursor++ = replacement; + ++ch; + ++invalid; + continue; + } + + if (u > 0xffff) { + *cursor++ = 0xf0 | ((uchar) (u >> 18)); + *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f); + } else { + *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f); + } + *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f); + } + *cursor++ = 0x80 | ((uchar) (u&0x3f)); + } + ++ch; + } +} + +void QHashedStringRef::computeUtf8Length() const +{ + if (m_length) + m_utf8length = utf8LengthFromUtf16(m_data, m_length); + else + m_utf8length = 0; +} + +QHashedStringRef QHashedStringRef::mid(int offset, int length) const +{ + Q_ASSERT(offset < m_length); + return QHashedStringRef(m_data + offset, + (length == -1 || (offset + length) > m_length)?(m_length - offset):length); +} + +bool QHashedStringRef::endsWith(const QString &s) const +{ + return s.length() < m_length && + QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length()); +} + +bool QHashedStringRef::startsWith(const QString &s) const +{ + return s.length() < m_length && + QHashedString::compare(s.constData(), m_data, s.length()); +} + +QString QHashedStringRef::toString() const +{ + if (m_length == 0) + return QString(); + return QString(m_data, m_length); +} + +QByteArray QHashedStringRef::toUtf8() const +{ + if (m_length == 0) + return QByteArray(); + + QByteArray result; + result.resize(utf8length()); + writeUtf8(result.data()); + return result; +} + +void QHashedStringRef::writeUtf8(char *output) const +{ + if (m_length) { + int ulen = utf8length(); + if (ulen == m_length) { + // Must be a latin1 string + uchar *o = (uchar *)output; + const QChar *c = m_data; + while (ulen--) + *o++ = (uchar)((*c++).unicode()); + } else { + utf8FromUtf16(output, m_data, m_length); + } + } +} + +QString QHashedCStringRef::toUtf16() const +{ + if (m_length == 0) + return QString(); + + QString rv; + rv.resize(m_length); + writeUtf16((uint16_t*)rv.data()); + return rv; +} + diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h new file mode 100644 index 0000000000..f575285ff6 --- /dev/null +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -0,0 +1,1418 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHASHEDSTRING_P_H +#define QHASHEDSTRING_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 +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +// Enable this to debug hash linking assumptions. +// #define QSTRINGHASH_LINK_DEBUG + +class QHashedStringRef; +class Q_AUTOTEST_EXPORT QHashedString : public QString +{ +public: + inline QHashedString(); + inline QHashedString(const QString &string); + inline QHashedString(const QString &string, quint32); + inline QHashedString(const QHashedString &string); + + inline QHashedString &operator=(const QHashedString &string); + inline bool operator==(const QHashedString &string) const; + inline bool operator==(const QHashedStringRef &string) const; + + inline quint32 hash() const; + inline quint32 existingHash() const; + + static inline bool isUpper(const QChar &); + + static bool compare(const QChar *lhs, const QChar *rhs, int length); + static inline bool compare(const QChar *lhs, const char *rhs, int length); + static inline bool compare(const char *lhs, const char *rhs, int length); +private: + friend class QHashedStringRef; + friend class QStringHashNode; + + void computeHash() const; + mutable quint32 m_hash; +}; + +class Q_AUTOTEST_EXPORT QHashedV8String +{ +public: + inline QHashedV8String(); + explicit inline QHashedV8String(v8::Handle); + inline QHashedV8String(const QHashedV8String &string); + inline QHashedV8String &operator=(const QHashedV8String &other); + + inline bool operator==(const QHashedV8String &string); + + inline quint32 hash() const; + inline int length() const; + inline quint32 symbolId() const; + + inline v8::Handle string() const; + + inline QString toString() const; + +private: + v8::String::CompleteHashData m_hash; + v8::Handle m_string; +}; + +class QHashedCStringRef; +class Q_AUTOTEST_EXPORT QHashedStringRef +{ +public: + inline QHashedStringRef(); + inline QHashedStringRef(const QString &); + inline QHashedStringRef(const QStringRef &); + inline QHashedStringRef(const QChar *, int); + inline QHashedStringRef(const QChar *, int, quint32); + inline QHashedStringRef(const QHashedString &); + inline QHashedStringRef(const QHashedStringRef &); + inline QHashedStringRef &operator=(const QHashedStringRef &); + + inline bool operator==(const QString &string) const; + inline bool operator==(const QHashedString &string) const; + inline bool operator==(const QHashedStringRef &string) const; + inline bool operator==(const QHashedCStringRef &string) const; + inline bool operator!=(const QString &string) const; + inline bool operator!=(const QHashedString &string) const; + inline bool operator!=(const QHashedStringRef &string) const; + inline bool operator!=(const QHashedCStringRef &string) const; + + inline quint32 hash() const; + + inline const QChar &at(int) const; + inline const QChar *constData() const; + bool startsWith(const QString &) const; + bool endsWith(const QString &) const; + QHashedStringRef mid(int, int) const; + + inline bool isEmpty() const; + inline int length() const; + inline bool startsWithUpper() const; + + QString toString() const; + + inline int utf8length() const; + QByteArray toUtf8() const; + void writeUtf8(char *) const; +private: + friend class QHashedString; + + void computeHash() const; + void computeUtf8Length() const; + + const QChar *m_data; + int m_length; + mutable int m_utf8length; + mutable quint32 m_hash; +}; + +class Q_AUTOTEST_EXPORT QHashedCStringRef +{ +public: + inline QHashedCStringRef(); + inline QHashedCStringRef(const char *, int); + inline QHashedCStringRef(const char *, int, quint32); + inline QHashedCStringRef(const QHashedCStringRef &); + + inline quint32 hash() const; + + inline const char *constData() const; + inline int length() const; + + QString toUtf16() const; + inline int utf16length() const; + inline void writeUtf16(QChar *) const; + inline void writeUtf16(uint16_t *) const; +private: + friend class QHashedStringRef; + + void computeHash() const; + + const char *m_data; + int m_length; + mutable quint32 m_hash; +}; + +class QStringHashData; +class Q_AUTOTEST_EXPORT QStringHashNode +{ +public: + QStringHashNode() + : length(0), hash(0), symbolId(0), ckey(0) + { + } + + QStringHashNode(const QHashedString &key) + : length(key.length()), hash(key.hash()), symbolId(0) + { + strData = const_cast(key).data_ptr(); + setQString(true); + strData->ref.ref(); + } + + QStringHashNode(const QHashedCStringRef &key) + : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData()) + { + } + + QStringHashNode(const QStringHashNode &o) + : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey) + { + setQString(o.isQString()); + if (isQString()) { strData->ref.ref(); } + } + + ~QStringHashNode() + { + if (isQString()) { if (!strData->ref.deref()) free(strData); } + } + + QFlagPointer next; + + qint32 length; + quint32 hash; + quint32 symbolId; + + union { + const char *ckey; + QStringData *strData; + }; + + bool isQString() const { return next.flag(); } + void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); } + + inline char *cStrData() const { return (char *)ckey; } + inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); } + + inline bool equals(v8::Handle string) { + return isQString()?string->Equals(utf16Data(), length): + string->Equals(cStrData(), length); + } + + inline bool symbolEquals(const QHashedV8String &string) { + Q_ASSERT(string.symbolId() != 0); + return length == string.length() && hash == string.hash() && + (string.symbolId() == symbolId || equals(string.string())); + } + + inline bool equals(const QHashedV8String &string) { + return length == string.length() && hash == string.hash() && + equals(string.string()); + } + + inline bool equals(const QHashedStringRef &string) { + return length == string.length() && + hash == string.hash() && + (isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length): + QHashedString::compare(string.constData(), cStrData(), length)); + } + + inline bool equals(const QHashedCStringRef &string) { + return length == string.length() && + hash == string.hash() && + (isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length): + QHashedString::compare(string.constData(), cStrData(), length)); + } +}; + +class Q_AUTOTEST_EXPORT QStringHashData +{ +public: + QStringHashData() + : buckets(0), numBuckets(0), size(0), numBits(0) +#ifdef QSTRINGHASH_LINK_DEBUG + , linkCount(0) +#endif + {} + + QStringHashNode **buckets; + int numBuckets; + int size; + short numBits; +#ifdef QSTRINGHASH_LINK_DEBUG + int linkCount; +#endif + + struct IteratorData { + IteratorData() : n(0), p(0) {} + QStringHashNode *n; + void *p; + }; + void rehashToBits(short, IteratorData, IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip = 0); + void rehashToSize(int, IteratorData, IteratorData (*Iterate)(const IteratorData &), + QStringHashNode *skip = 0); + +private: + QStringHashData(const QStringHashData &); + QStringHashData &operator=(const QStringHashData &); +}; + +template +class QStringHash +{ +public: + struct Node : public QStringHashNode { + Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {} + Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {} + Node(const Node &o) : QStringHashNode(o), value(o.value) {} + Node() {} + T value; + }; + struct NewedNode : public Node { + NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(0) {} + NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(0) {} + NewedNode(const Node &o) : Node(o), nextNewed(0) {} + NewedNode *nextNewed; + }; + struct ReservedNodePool + { + ReservedNodePool() : count(0), used(0), nodes(0) {} + ~ReservedNodePool() { delete [] nodes; } + int count; + int used; + Node *nodes; + }; + + QStringHashData data; + NewedNode *newedNodes; + ReservedNodePool *nodePool; + const QStringHash *link; + + inline Node *findNode(const QString &) const; + inline Node *findNode(const QHashedString &) const; + inline Node *findNode(const QHashedStringRef &) const; + inline Node *findNode(const QHashedCStringRef &) const; + inline Node *findNode(const QHashedV8String &) const; + inline Node *findSymbolNode(const QHashedV8String &) const; + inline Node *createNode(const Node &o); + inline Node *createNode(const QHashedString &, const T &); + inline Node *createNode(const QHashedCStringRef &, const T &); + + inline Node *takeNode(const QHashedString &key, const T &value); + inline Node *takeNode(const QHashedCStringRef &key, const T &value); + inline Node *takeNode(const Node &o); + + inline void copy(const QStringHash &); + + inline QStringHashData::IteratorData iterateFirst() const; + static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &); + +public: + inline QStringHash(); + inline QStringHash(const QStringHash &); + inline ~QStringHash(); + + QStringHash &operator=(const QStringHash &); + + void copyAndReserve(const QStringHash &other, int additionalReserve); + void linkAndReserve(const QStringHash &other, int additionalReserve); + + inline bool isEmpty() const; + inline void clear(); + inline int count() const; + + inline int numBuckets() const; + inline bool isLinked() const; + + class ConstIterator { + public: + inline ConstIterator(); + inline ConstIterator(const QStringHashData::IteratorData &); + + inline ConstIterator &operator++(); + + inline bool operator==(const ConstIterator &o) const; + inline bool operator!=(const ConstIterator &o) const; + + inline QHashedString key() const; + inline const T &value() const; + inline const T &operator*() const; + + inline Node *node() const; + private: + QStringHashData::IteratorData d; + }; + + inline void insert(const QString &, const T &); + inline void insert(const QHashedString &, const T &); + inline void insert(const QHashedStringRef &, const T &); + inline void insert(const QHashedCStringRef &, const T &); + inline void insert(const ConstIterator &); + + inline T *value(const QString &) const; + inline T *value(const QHashedString &) const; + inline T *value(const QHashedStringRef &) const; + inline T *value(const QHashedV8String &) const; + inline T *value(const QHashedCStringRef &) const; + inline T *value(const ConstIterator &) const; + + inline bool contains(const QString &) const; + inline bool contains(const QHashedString &) const; + inline bool contains(const QHashedStringRef &) const; + inline bool contains(const QHashedCStringRef &) const; + inline bool contains(const ConstIterator &) const; + + inline T &operator[](const QString &); + inline T &operator[](const QHashedString &); + inline T &operator[](const QHashedStringRef &); + inline T &operator[](const QHashedCStringRef &); + + inline ConstIterator begin() const; + inline ConstIterator end() const; + + inline void reserve(int); +}; + +template +QStringHash::QStringHash() +: newedNodes(0), nodePool(0), link(0) +{ +} + +template +QStringHash::QStringHash(const QStringHash &other) +: newedNodes(0), nodePool(0), link(0) +{ + data.numBits = other.data.numBits; + data.size = other.data.size; + reserve(other.count()); + copy(other); +} + +template +QStringHash &QStringHash::operator=(const QStringHash &other) +{ + if (&other == this) + return *this; + + clear(); + + data.numBits = other.data.numBits; + data.size = other.data.size; + reserve(other.count()); + copy(other); + + return *this; +} + +template +void QStringHash::copyAndReserve(const QStringHash &other, int additionalReserve) +{ + clear(); + data.numBits = other.data.numBits; + reserve(other.count() + additionalReserve); + copy(other); +} + +template +void QStringHash::linkAndReserve(const QStringHash &other, int additionalReserve) +{ + clear(); + + if (other.count()) { + data.size = other.data.size; + data.rehashToSize(other.count() + additionalReserve, iterateFirst(), iterateNext); + + if (data.numBuckets == other.data.numBuckets) { + nodePool = new ReservedNodePool; + nodePool->count = additionalReserve; + nodePool->used = 0; + nodePool->nodes = new Node[additionalReserve]; + +#ifdef QSTRINGHASH_LINK_DEBUG + data.linkCount++; + const_cast&>(other).data.linkCount++; +#endif + + for (int ii = 0; ii < data.numBuckets; ++ii) { + data.buckets[ii] = 0; + Node *n = (Node *)other.data.buckets[ii]; + data.buckets[ii] = n; + } + + link = &other; + return; + } + + data.size = 0; + } + + data.numBits = other.data.numBits; + reserve(other.count() + additionalReserve); + copy(other); +} + +template +QStringHash::~QStringHash() +{ + clear(); +} + +template +void QStringHash::clear() +{ +#ifdef QSTRINGHASH_LINK_DEBUG + if (link) { + data.linkCount--; + const_cast *>(link)->data.linkCount--; + } + + if (data.linkCount) + qFatal("QStringHash: Illegal attempt to clear a linked hash."); +#endif + + // Delete the individually allocated nodes + NewedNode *n = newedNodes; + while (n) { + NewedNode *c = n; + n = c->nextNewed; + delete c; + } + // Delete the pool allocated nodes + if (nodePool) delete nodePool; + delete [] data.buckets; + + data.buckets = 0; + data.numBuckets = 0; + data.numBits = 0; + data.size = 0; + + newedNodes = 0; + nodePool = 0; + link = 0; +} + +template +bool QStringHash::isEmpty() const +{ + return data.size== 0; +} + +template +int QStringHash::count() const +{ + return data.size; +} + +template +int QStringHash::numBuckets() const +{ + return data.numBuckets; +} + +template +bool QStringHash::isLinked() const +{ + return link != 0; +} + +template +typename QStringHash::Node *QStringHash::takeNode(const QHashedString &key, const T &value) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = key.length(); + rv->hash = key.hash(); + rv->strData = const_cast(key).data_ptr(); + rv->strData->ref.ref(); + rv->setQString(true); + rv->value = value; + return rv; + } else { + NewedNode *rv = new NewedNode(key, value); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template +typename QStringHash::Node *QStringHash::takeNode(const QHashedCStringRef &key, const T &value) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = key.length(); + rv->hash = key.hash(); + rv->ckey = key.constData(); + rv->value = value; + return rv; + } else { + NewedNode *rv = new NewedNode(key, value); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template +typename QStringHash::Node *QStringHash::takeNode(const Node &o) +{ + if (nodePool && nodePool->used != nodePool->count) { + Node *rv = nodePool->nodes + nodePool->used++; + rv->length = o.length; + rv->hash = o.hash; + if (o.isQString()) { + rv->strData = o.strData; + rv->strData->ref.ref(); + rv->setQString(true); + } else { + rv->ckey = o.ckey; + } + rv->symbolId = o.symbolId; + rv->value = o.value; + return rv; + } else { + NewedNode *rv = new NewedNode(o); + rv->nextNewed = newedNodes; + newedNodes = rv; + return rv; + } +} + +template +void QStringHash::copy(const QStringHash &other) +{ + Q_ASSERT(data.size == 0); + + data.size = other.data.size; + + // Ensure buckets array is created + data.rehashToBits(data.numBits, iterateFirst(), iterateNext); + + if (other.link) { + for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) { + Node *o = iter.node(); + Node *n = o->isQString()?findNode(QHashedStringRef((QChar *)o->strData->data(), o->length, o->hash)): + findNode(QHashedCStringRef(o->ckey, o->length, o->hash)); + if (!n) { + Node *mynode = takeNode(*o); + int bucket = mynode->hash % data.numBuckets; + mynode->next = data.buckets[bucket]; + data.buckets[bucket] = mynode; + } + } + } else { + for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) { + Node *o = iter.node(); + Node *mynode = takeNode(*o); + int bucket = mynode->hash % data.numBuckets; + mynode->next = data.buckets[bucket]; + data.buckets[bucket] = mynode; + } + } +} + +template +QStringHashData::IteratorData +QStringHash::iterateNext(const QStringHashData::IteratorData &d) +{ + QStringHash *This = (QStringHash *)d.p; + Node *node = (Node *)d.n; + + if (This->nodePool && node >= This->nodePool->nodes && + node < (This->nodePool->nodes + This->nodePool->used)) { + node--; + if (node < This->nodePool->nodes) + node = 0; + } else { + NewedNode *nn = (NewedNode *)node; + node = nn->nextNewed; + + if (node == 0 && This->nodePool && This->nodePool->used) + node = This->nodePool->nodes + This->nodePool->used - 1; + } + + if (node == 0 && This->link) + return This->link->iterateFirst(); + + QStringHashData::IteratorData rv; + rv.n = node; + rv.p = d.p; + return rv; +} + +template +QStringHashData::IteratorData QStringHash::iterateFirst() const +{ + Node *n = 0; + if (newedNodes) + n = newedNodes; + else if (nodePool && nodePool->used) + n = nodePool->nodes + nodePool->used - 1; + + if (n == 0 && link) + return link->iterateFirst(); + + QStringHashData::IteratorData rv; + rv.n = n; + rv.p = const_cast *>(this); + return rv; +} + +template +typename QStringHash::Node *QStringHash::createNode(const Node &o) +{ + Node *n = takeNode(o); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = n->hash % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template +typename QStringHash::Node *QStringHash::createNode(const QHashedString &key, const T &value) +{ + Node *n = takeNode(key, value); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = key.hash() % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template +typename QStringHash::Node *QStringHash::createNode(const QHashedCStringRef &key, const T &value) +{ + Node *n = takeNode(key, value); + + if (data.size >= data.numBuckets) + data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n); + + int bucket = key.hash() % data.numBuckets; + n->next = data.buckets[bucket]; + data.buckets[bucket] = n; + + data.size++; + + return n; +} + +template +void QStringHash::insert(const QString &key, const T &value) +{ + QHashedStringRef ch(key); + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(QHashedString(key, ch.hash()), value); +} + +template +void QStringHash::insert(const QHashedString &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template +void QStringHash::insert(const QHashedStringRef &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template +void QStringHash::insert(const QHashedCStringRef &key, const T &value) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + Node *n = link?0:findNode(key); + if (n) n->value = value; + else createNode(key, value); +} + +template +void QStringHash::insert(const ConstIterator &key) +{ + // If this is a linked hash, we can't rely on owning the node, so we always + // create a new one. + if (key.node()->isQString()) { + QHashedStringRef str((QChar *)key.node()->strData->data(), key.node()->length, + key.node()->hash); + + Node *n = link?0:findNode(str); + if (n) n->value = key.node()->value; + else createNode(*key.node()); + } else { + QHashedCStringRef str(key.node()->ckey, key.node()->length, key.node()->hash); + + Node *n = link?0:findNode(str); + if (n) n->value = key.node()->value; + else createNode(str, key.node()->value); + } +} + +template +typename QStringHash::Node *QStringHash::findNode(const QString &string) const +{ + return findNode(QHashedStringRef(string)); +} + +template +typename QStringHash::Node *QStringHash::findNode(const QHashedString &string) const +{ + return findNode(QHashedStringRef(string.constData(), string.length(), string.hash())); +} + +template +typename QStringHash::Node *QStringHash::findNode(const QHashedStringRef &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template +typename QStringHash::Node *QStringHash::findNode(const QHashedCStringRef &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template +typename QStringHash::Node *QStringHash::findNode(const QHashedV8String &string) const +{ + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->equals(string)) + node = (*node->next); + + return (Node *)node; +} + +template +typename QStringHash::Node *QStringHash::findSymbolNode(const QHashedV8String &string) const +{ + Q_ASSERT(string.symbolId() != 0); + + QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0; + while (node && !node->symbolEquals(string)) + node = (*node->next); + + if (node) + node->symbolId = string.symbolId(); + + return (Node *)node; +} + +template +T *QStringHash::value(const QString &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template +T *QStringHash::value(const QHashedString &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template +T *QStringHash::value(const QHashedStringRef &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template +T *QStringHash::value(const QHashedCStringRef &key) const +{ + Node *n = findNode(key); + return n?&n->value:0; +} + +template +T *QStringHash::value(const ConstIterator &iter) const +{ + Node *n = iter.node(); + if (n->isQString()) + return value(QHashedStringRef((QChar *)n->strData->data(), n->length, n->hash)); + else + return value(QHashedCStringRef(n->ckey, n->length, n->hash)); +} + +template +T *QStringHash::value(const QHashedV8String &string) const +{ + Node *n = string.symbolId()?findSymbolNode(string):findNode(string); + return n?&n->value:0; +} + +template +bool QStringHash::contains(const QString &s) const +{ + return 0 != value(s); +} + +template +bool QStringHash::contains(const QHashedString &s) const +{ + return 0 != value(s); +} + +template +bool QStringHash::contains(const QHashedStringRef &s) const +{ + return 0 != value(s); +} + +template +bool QStringHash::contains(const QHashedCStringRef &s) const +{ + return 0 != value(s); +} + +template +bool QStringHash::contains(const ConstIterator &s) const +{ + return 0 != value(s); +} + +template +T &QStringHash::operator[](const QString &key) +{ + QHashedStringRef cs(key); + Node *n = findNode(cs); + if (n) return n->value; + else return createNode(QHashedString(key, cs.hash()), T())->value; +} + +template +T &QStringHash::operator[](const QHashedString &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template +T &QStringHash::operator[](const QHashedStringRef &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template +T &QStringHash::operator[](const QHashedCStringRef &key) +{ + Node *n = findNode(key); + if (n) return n->value; + else return createNode(key, T())->value; +} + +template +void QStringHash::reserve(int n) +{ + if (nodePool || 0 == n) + return; + + nodePool = new ReservedNodePool; + nodePool->count = n; + nodePool->used = 0; + nodePool->nodes = new Node[n]; + + data.rehashToSize(n, iterateFirst(), iterateNext); +} + +template +QStringHash::ConstIterator::ConstIterator() +{ +} + +template +QStringHash::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d) +: d(d) +{ +} + +template +typename QStringHash::ConstIterator &QStringHash::ConstIterator::operator++() +{ + d = QStringHash::iterateNext(d); + return *this; +} + +template +bool QStringHash::ConstIterator::operator==(const ConstIterator &o) const +{ + return d.n == o.d.n; +} + +template +bool QStringHash::ConstIterator::operator!=(const ConstIterator &o) const +{ + return d.n != o.d.n; +} + +template +QHashedString QStringHash::ConstIterator::key() const +{ + Node *n = (Node *)d.n; + if (n->isQString()) { + return QHashedString(QString((QChar *)n->strData->data(), n->length), n->hash); + } else { + return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash); + } +} +template +const T &QStringHash::ConstIterator::value() const +{ + Node *n = (Node *)d.n; + return n->value; +} + +template +const T &QStringHash::ConstIterator::operator*() const +{ + Node *n = (Node *)d.n; + return n->value; +} + +template +typename QStringHash::Node *QStringHash::ConstIterator::node() const +{ + Node *n = (Node *)d.n; + return n; +} + +template +typename QStringHash::ConstIterator QStringHash::begin() const +{ + return ConstIterator(iterateFirst()); +} + +template +typename QStringHash::ConstIterator QStringHash::end() const +{ + return ConstIterator(); +} + +inline uint qHash(const QHashedString &string) +{ + return uint(string.hash()); +} + +inline uint qHash(const QHashedStringRef &string) +{ + return uint(string.hash()); +} + +QHashedString::QHashedString() +: QString(), m_hash(0) +{ +} + +QHashedString::QHashedString(const QString &string) +: QString(string), m_hash(0) +{ +} + +QHashedString::QHashedString(const QString &string, quint32 hash) +: QString(string), m_hash(hash) +{ +} + +QHashedString::QHashedString(const QHashedString &string) +: QString(string), m_hash(string.m_hash) +{ +} + +QHashedString &QHashedString::operator=(const QHashedString &string) +{ + static_cast(*this) = string; + m_hash = string.m_hash; + return *this; +} + +bool QHashedString::operator==(const QHashedString &string) const +{ + return (string.m_hash == m_hash || !string.m_hash || !m_hash) && + static_cast(*this) == static_cast(string); +} + +bool QHashedString::operator==(const QHashedStringRef &string) const +{ + return length() == string.m_length && + (string.m_hash == m_hash || !string.m_hash || !m_hash) && + QHashedString::compare(constData(), string.m_data, string.m_length); +} + +quint32 QHashedString::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +quint32 QHashedString::existingHash() const +{ + return m_hash; +} + +bool QHashedString::isUpper(const QChar &qc) +{ + ushort c = qc.unicode(); + // Optimize for _, a-z and A-Z. + return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) && + ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase)); +} + +QHashedV8String::QHashedV8String() +{ +} + +QHashedV8String::QHashedV8String(v8::Handle string) +: m_hash(string->CompleteHash()), m_string(string) +{ + Q_ASSERT(!m_string.IsEmpty()); +} + +QHashedV8String::QHashedV8String(const QHashedV8String &string) +: m_hash(string.m_hash), m_string(string.m_string) +{ +} + +QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other) +{ + m_hash = other.m_hash; + m_string = other.m_string; + return *this; +} + +bool QHashedV8String::operator==(const QHashedV8String &string) +{ + return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length && + m_string.IsEmpty() == m_string.IsEmpty() && + (m_string.IsEmpty() || m_string->StrictEquals(string.m_string)); +} + +quint32 QHashedV8String::hash() const +{ + return m_hash.hash; +} + +int QHashedV8String::length() const +{ + return m_hash.length; +} + +quint32 QHashedV8String::symbolId() const +{ + return m_hash.symbol_id; +} + +v8::Handle QHashedV8String::string() const +{ + return m_string; +} + +QString QHashedV8String::toString() const +{ + QString result; + result.reserve(m_hash.length); + + for (int i = 0; i < m_hash.length; ++i) + result.append(m_string->GetCharacter(i)); + + return result; +} + +QHashedStringRef::QHashedStringRef() +: m_data(0), m_length(0), m_utf8length(-1), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QString &str) +: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QStringRef &str) +: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QChar *data, int length) +: m_data(data), m_length(length), m_utf8length(0), m_hash(0) +{ +} + +QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash) +: m_data(data), m_length(length), m_utf8length(0), m_hash(hash) +{ +} + +QHashedStringRef::QHashedStringRef(const QHashedString &string) +: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash) +{ +} + +QHashedStringRef::QHashedStringRef(const QHashedStringRef &string) +: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length), + m_hash(string.m_hash) +{ +} + +QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o) +{ + m_data = o.m_data; + m_length = o.m_length; + m_utf8length = o.m_utf8length; + m_hash = o.m_hash; + return *this; +} + +bool QHashedStringRef::operator==(const QString &string) const +{ + return m_length == string.length() && + QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedString &string) const +{ + return m_length == string.length() && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedStringRef &string) const +{ + return m_length == string.m_length && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(string.m_data, m_data, m_length); +} + +bool QHashedStringRef::operator==(const QHashedCStringRef &string) const +{ + return m_length == string.m_length && + (m_hash == string.m_hash || !m_hash || !string.m_hash) && + QHashedString::compare(m_data, string.m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QString &string) const +{ + return m_length != string.length() || + !QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedString &string) const +{ + return m_length != string.length() || + (m_hash != string.m_hash && m_hash && string.m_hash) || + !QHashedString::compare(string.constData(), m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedStringRef &string) const +{ + return m_length != string.m_length || + (m_hash != string.m_hash && m_hash && string.m_hash) || + QHashedString::compare(string.m_data, m_data, m_length); +} + +bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const +{ + return m_length != string.m_length || + (m_hash != string.m_hash && m_hash && string.m_hash) || + QHashedString::compare(m_data, string.m_data, m_length); +} + +const QChar &QHashedStringRef::at(int index) const +{ + Q_ASSERT(index < m_length); + return m_data[index]; +} + +const QChar *QHashedStringRef::constData() const +{ + return m_data; +} + +bool QHashedStringRef::isEmpty() const +{ + return m_length == 0; +} + +int QHashedStringRef::length() const +{ + return m_length; +} + +int QHashedStringRef::utf8length() const +{ + if (m_utf8length < m_length) + computeUtf8Length(); + return m_utf8length; +} + +bool QHashedStringRef::startsWithUpper() const +{ + if (m_length < 1) return false; + return QHashedString::isUpper(m_data[0]); +} + +quint32 QHashedStringRef::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +QHashedCStringRef::QHashedCStringRef() +: m_data(0), m_length(0), m_hash(0) +{ +} + +QHashedCStringRef::QHashedCStringRef(const char *data, int length) +: m_data(data), m_length(length), m_hash(0) +{ +} + +QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash) +: m_data(data), m_length(length), m_hash(hash) +{ +} + +QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o) +: m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash) +{ +} + +quint32 QHashedCStringRef::hash() const +{ + if (!m_hash) computeHash(); + return m_hash; +} + +const char *QHashedCStringRef::constData() const +{ + return m_data; +} + +int QHashedCStringRef::length() const +{ + return m_length; +} + +int QHashedCStringRef::utf16length() const +{ + return m_length; +} + +void QHashedCStringRef::writeUtf16(QChar *output) const +{ + writeUtf16((uint16_t *)output); +} + +void QHashedCStringRef::writeUtf16(uint16_t *output) const +{ + int l = m_length; + const char *d = m_data; + while (l--) + *output++ = *d++; +} + +bool QHashedString::compare(const QChar *lhs, const char *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + const quint16 *l = (const quint16*)lhs; + while (length--) + if (*l++ != *rhs++) return false; + return true; +} + +bool QHashedString::compare(const char *lhs, const char *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + return 0 == ::memcmp(lhs, rhs, length); +} + +QT_END_NAMESPACE + +#endif // QHASHEDSTRING_P_H diff --git a/src/qml/qml/ftw/qhashfield_p.h b/src/qml/qml/ftw/qhashfield_p.h new file mode 100644 index 0000000000..46df9a176c --- /dev/null +++ b/src/qml/qml/ftw/qhashfield_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHASHFIELD_P_H +#define QHASHFIELD_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 + +QT_BEGIN_NAMESPACE + +// QHashField can be used for doing coarse grained set testing, in +// cases where you do not expect the set to contain the item. For +// example where you would write: +// QSet strings; +// for (int ii = 0; ii < mystrings.count(); ++ii) { +// if (strings.contains(mystrings.at(ii))) +// qFatal("Duplication!"); +// strings.insert(mystrings); +// } +// You may write: +// QHashField strings; +// for (int ii = 0; ii < mystrings.count(); ++ii) { +// if (strings.testAndSet(qHash(mystrings.at(ii)))) { +// // The string *might* be duplicated +// for (int jj = 0; jj < ii; ++jj) { +// if (mystrings.at(ii) == mystrings.at(jj)) +// qFatal("Duplication!"); +// } +// } +// } +// For small lists of things, where the hash is cheap to calculate +// and you don't expect duplication this will be much faster. +class QHashField { +public: + inline QHashField(); + + inline void clear(); + + inline bool test(quint32 hash); + inline bool testAndSet(quint32 hash); +private: + quint32 m_field; +}; + +QHashField::QHashField() +: m_field(0) +{ +} + +void QHashField::clear() +{ + m_field = 0; +} + +bool QHashField::test(quint32 hash) +{ + return m_field & (1 << (hash % 31)); +} + +bool QHashField::testAndSet(quint32 hash) +{ + quint32 mask = 1 << (hash % 31); + bool rv = m_field & mask; + m_field |= mask; + return rv; +} + +QT_END_NAMESPACE + +#endif // QHASHFIELD_P_H diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp new file mode 100644 index 0000000000..5a1624f1f4 --- /dev/null +++ b/src/qml/qml/ftw/qintrusivelist.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qintrusivelist_p.h" + +/*! +\class QIntrusiveList +\brief The QIntrusiveList class is a template class that provides a list of objects using static storage. +\internal + +QIntrusiveList creates a linked list of objects. Adding and removing objects from the +QIntrusiveList is a constant time operation and is very quick. The list performs no memory +allocations, but does require the objects being added to the list to contain a QIntrusiveListNode +instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's +other list classes. + +As QIntrusiveList uses storage inside the objects in the list, each object can only be in one +list at a time. Objects are inserted by the insert() method. If the object is already +in a list (including the one it is being inserted into) it is first removed, and then inserted +at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an +insert() the inserted object becomes the list's first() object. + +\code +struct MyObject { + MyObject(int value) : value(value) {} + + int value; + QIntrusiveListNode node; +}; +typedef QIntrusiveList MyObjectList; + +void foo() { + MyObjectList list; + + MyObject m0(0); + MyObject m1(1); + MyObject m2(2); + + list.insert(&m0); + list.insert(&m1); + list.insert(&m2); + + // QIntrusiveList is LIFO, so will print: 2... 1... 0... + for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) { + qWarning() << iter->value; + } +} +\endcode +*/ + + +/*! +\fn QIntrusiveList::QIntrusiveList(); + +Construct an empty list. +*/ + +/*! +\fn QIntrusiveList::~QIntrusiveList(); + +Destroy the list. All entries are removed. +*/ + +/*! +\fn void QIntrusiveList::insert(N *object); + +Insert \a object into the list. If \a object is a member of this, or another list, it will be +removed and inserted at the head of this list. +*/ + +/*! +\fn void QIntrusiveList::remove(N *object); + +Remove \a object from the list. \a object must not be null. +*/ + +/*! +\fn bool QIntrusiveList::contains(N *object) const + +Returns true if the list contains \a object; otherwise returns false. +*/ + +/*! +\fn N *QIntrusiveList::first() const + +Returns the first entry in this list, or null if the list is empty. +*/ + +/*! +\fn N *QIntrusiveList::next(N *current) + +Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null. +*/ + +/*! +\fn iterator QIntrusiveList::begin() + +Returns an STL-style interator pointing to the first item in the list. + +\sa end() +*/ + +/*! +\fn iterator QIntrusiveList::end() + +Returns an STL-style iterator pointing to the imaginary item after the last item in the list. + +\sa begin() +*/ + +/*! +iterator &QInplacelist::iterator::erase() + +Remove the current object from the list, and return an iterator to the next element. +*/ + + +/*! +\fn QIntrusiveListNode::QIntrusiveListNode() + +Create a QIntrusiveListNode. +*/ + +/*! +\fn QIntrusiveListNode::~QIntrusiveListNode() + +Destroy the QIntrusiveListNode. If the node is in a list, it is removed. +*/ + +/*! +\fn void QIntrusiveListNode::remove() + +If in a list, remove this node otherwise do nothing. +*/ + +/*! +\fn bool QIntrusiveListNode::isInList() const + +Returns true if this node is in a list, false otherwise. +*/ + diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h new file mode 100644 index 0000000000..489b02d656 --- /dev/null +++ b/src/qml/qml/ftw/qintrusivelist_p.h @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QINTRUSIVELIST_P_H +#define QINTRUSIVELIST_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 + +QT_BEGIN_NAMESPACE + +class QIntrusiveListNode; +template +class QIntrusiveList +{ +public: + inline QIntrusiveList(); + inline ~QIntrusiveList(); + + inline bool isEmpty() const; + inline void insert(N *n); + inline void remove(N *n); + inline bool contains(N *) const; + + class iterator { + public: + inline iterator(); + inline iterator(N *value); + + inline N *operator*() const; + inline N *operator->() const; + inline bool operator==(const iterator &other) const; + inline bool operator!=(const iterator &other) const; + inline iterator &operator++(); + + inline iterator &erase(); + + private: + N *_value; + }; + typedef iterator Iterator; + + inline N *first() const; + static inline N *next(N *current); + + inline iterator begin(); + inline iterator end(); + +private: + static inline N *nodeToN(QIntrusiveListNode *node); + + QIntrusiveListNode *__first; +}; + +class QIntrusiveListNode +{ +public: + inline QIntrusiveListNode(); + inline ~QIntrusiveListNode(); + + inline void remove(); + inline bool isInList() const; + + QIntrusiveListNode *_next; + QIntrusiveListNode**_prev; +}; + +template +QIntrusiveList::iterator::iterator() +: _value(0) +{ +} + +template +QIntrusiveList::iterator::iterator(N *value) +: _value(value) +{ +} + +template +N *QIntrusiveList::iterator::operator*() const +{ + return _value; +} + +template +N *QIntrusiveList::iterator::operator->() const +{ + return _value; +} + +template +bool QIntrusiveList::iterator::operator==(const iterator &other) const +{ + return other._value == _value; +} + +template +bool QIntrusiveList::iterator::operator!=(const iterator &other) const +{ + return other._value != _value; +} + +template +typename QIntrusiveList::iterator &QIntrusiveList::iterator::operator++() +{ + _value = QIntrusiveList::next(_value); + return *this; +} + +template +typename QIntrusiveList::iterator &QIntrusiveList::iterator::erase() +{ + N *old = _value; + _value = QIntrusiveList::next(_value); + (old->*member).remove(); + return *this; +} + +template +QIntrusiveList::QIntrusiveList() +: __first(0) +{ +} + +template +QIntrusiveList::~QIntrusiveList() +{ + while (__first) __first->remove(); +} + +template +bool QIntrusiveList::isEmpty() const +{ + return __first == 0; +} + +template +void QIntrusiveList::insert(N *n) +{ + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); + + nnode->_next = __first; + if (nnode->_next) nnode->_next->_prev = &nnode->_next; + __first = nnode; + nnode->_prev = &__first; +} + +template +void QIntrusiveList::remove(N *n) +{ + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); +} + +template +bool QIntrusiveList::contains(N *n) const +{ + QIntrusiveListNode *nnode = __first; + while (nnode) { + if (nodeToN(nnode) == n) + return true; + nnode = nnode->_next; + } + return false; +} + +template +N *QIntrusiveList::first() const +{ + return __first?nodeToN(__first):0; +} + +template +N *QIntrusiveList::next(N *current) +{ + QIntrusiveListNode *nextnode = (current->*member)._next; + N *nextstruct = nextnode?nodeToN(nextnode):0; + return nextstruct; +} + +template +typename QIntrusiveList::iterator QIntrusiveList::begin() +{ + return __first?iterator(nodeToN(__first)):iterator(); +} + +template +typename QIntrusiveList::iterator QIntrusiveList::end() +{ + return iterator(); +} + +template +N *QIntrusiveList::nodeToN(QIntrusiveListNode *node) +{ + return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0)); +} + +QIntrusiveListNode::QIntrusiveListNode() +: _next(0), _prev(0) +{ +} + +QIntrusiveListNode::~QIntrusiveListNode() +{ + remove(); +} + +void QIntrusiveListNode::remove() +{ + if (_prev) *_prev = _next; + if (_next) _next->_prev = _prev; + _prev = 0; + _next = 0; +} + +bool QIntrusiveListNode::isInList() const +{ + return _prev != 0; +} + +QT_END_NAMESPACE + +#endif // QINTRUSIVELIST_P_H diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h new file mode 100644 index 0000000000..960d84d5e7 --- /dev/null +++ b/src/qml/qml/ftw/qlazilyallocated_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAZILYALLOCATED_P_H +#define QLAZILYALLOCATED_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 + +#include + +QT_BEGIN_NAMESPACE + +template +class QLazilyAllocated { +public: + inline QLazilyAllocated(); + inline ~QLazilyAllocated(); + + inline bool isAllocated() const; + + inline T *operator->() const; + + inline T &value(); + inline const T &value() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); +private: + mutable QFlagPointer d; +}; + +template +QLazilyAllocated::QLazilyAllocated() +{ +} + +template +QLazilyAllocated::~QLazilyAllocated() +{ + delete *d; +} + +template +bool QLazilyAllocated::isAllocated() const +{ + return !d.isNull(); +} + +template +T &QLazilyAllocated::value() +{ + if (d.isNull()) d = new T; + return *(*d); +} + +template +const T &QLazilyAllocated::value() const +{ + if (d.isNull()) d = new T; + return *(*d); +} + +template +T *QLazilyAllocated::operator->() const +{ + return *d; +} + +template +bool QLazilyAllocated::flag() const +{ + return d.flag(); +} + +template +void QLazilyAllocated::setFlag() +{ + d.setFlag(); +} + +template +void QLazilyAllocated::clearFlag() +{ + d.clearFlag(); +} + +template +void QLazilyAllocated::setFlagValue(bool v) +{ + d.setFlagValue(v); +} + +QT_END_NAMESPACE + +#endif // QLAZILYALLOCATED_P_H diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h new file mode 100644 index 0000000000..c96692667a --- /dev/null +++ b/src/qml/qml/ftw/qpodvector_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPODVECTOR_P_H +#define QPODVECTOR_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 +#include + +QT_BEGIN_NAMESPACE + +template +class QPODVector +{ +public: + QPODVector() + : m_count(0), m_capacity(0), m_data(0) {} + ~QPODVector() { if (m_data) ::free(m_data); } + + const T &at(int idx) const { + return m_data[idx]; + } + + T &operator[](int idx) { + return m_data[idx]; + } + + void clear() { + m_count = 0; + } + + void prepend(const T &v) { + insert(0, v); + } + + void append(const T &v) { + insert(m_count, v); + } + + void insert(int idx, const T &v) { + if (m_count == m_capacity) { + m_capacity += Increment; + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T)); + m_count++; + m_data[idx] = v; + } + + void reserve(int count) { + if (count >= m_capacity) { + m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1); + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + } + + void insertBlank(int idx, int count) { + int newSize = m_count + count; + reserve(newSize); + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + count, m_data + idx, + moveCount * sizeof(T)); + m_count = newSize; + } + + void remove(int idx, int count = 1) { + int moveCount = m_count - (idx + count); + if (moveCount) + ::memmove(m_data + idx, m_data + idx + count, + moveCount * sizeof(T)); + m_count -= count; + } + + void removeOne(const T &v) { + int idx = 0; + while (idx < m_count) { + if (m_data[idx] == v) { + remove(idx); + return; + } + ++idx; + } + } + + int find(const T &v) { + for (int idx = 0; idx < m_count; ++idx) + if (m_data[idx] == v) + return idx; + return -1; + } + + bool contains(const T &v) { + return find(v) != -1; + } + + int count() const { + return m_count; + } + + void copyAndClear(QPODVector &other) { + if (other.m_data) ::free(other.m_data); + other.m_count = m_count; + other.m_capacity = m_capacity; + other.m_data = m_data; + m_count = 0; + m_capacity = 0; + m_data = 0; + } + + QPODVector &operator<<(const T &v) { append(v); return *this; } +private: + QPODVector(const QPODVector &); + QPODVector &operator=(const QPODVector &); + int m_count; + int m_capacity; + T *m_data; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h new file mode 100644 index 0000000000..7b0caf49bc --- /dev/null +++ b/src/qml/qml/ftw/qpointervaluepair_p.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPOINTERVALUEPAIR_P_H +#define QPOINTERVALUEPAIR_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 +#include + +QT_BEGIN_NAMESPACE + +// QPointerValuePair is intended to help reduce the memory consumption of a class. +// In the common case, QPointerValuePair behaves like a pointer. In this mode, it +// consumes the same memory as a regular pointer. +// Additionally, QPointerValuePair can store an arbitrary value type in *addition* +// to the pointer. In this case, it uses slightly more memory than the pointer and +// value type combined. +// Consequently, this class is most useful in cases where a pointer is always stored +// and a value type is rarely stored. +template +class QPointerValuePair { +public: + inline QPointerValuePair(); + inline QPointerValuePair(P *); + inline ~QPointerValuePair(); + + inline bool isNull() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline QPointerValuePair &operator=(P *); + + inline P *operator->() const; + inline P *operator*() const; + + inline bool hasValue() const; + inline V &value(); + inline const V *constValue() const; + +private: + struct Value { P *pointer; V value; }; + QBiPointer d; +}; + +template +QPointerValuePair::QPointerValuePair() +{ +} + +template +QPointerValuePair::QPointerValuePair(P *p) +: d(p) +{ +} + +template +QPointerValuePair::~QPointerValuePair() +{ + if (d.isT2()) delete d.asT2(); +} + +template +bool QPointerValuePair::isNull() const +{ + if (d.isT1()) return 0 == d.asT1(); + else return d.asT2()->pointer == 0; +} + +template +bool QPointerValuePair::flag() const +{ + return d.flag(); +} + +template +void QPointerValuePair::setFlag() +{ + d.setFlag(); +} + +template +void QPointerValuePair::clearFlag() +{ + d.clearFlag(); +} + +template +void QPointerValuePair::setFlagValue(bool v) +{ + d.setFlagValue(v); +} + +template +QPointerValuePair &QPointerValuePair::operator=(P *o) +{ + if (d.isT1()) d = o; + else d.asT2()->pointer = o; + return *this; +} + +template +P *QPointerValuePair::operator->() const +{ + if (d.isT1()) return d.asT1(); + else return d.asT2()->pointer; +} + +template +P *QPointerValuePair::operator*() const +{ + if (d.isT1()) return d.asT1(); + else return d.asT2()->pointer; +} + +template +bool QPointerValuePair::hasValue() const +{ + return d.isT2(); +} + +template +V &QPointerValuePair::value() +{ + if (d.isT1()) { + P *p = d.asT1(); + Value *value = new Value; + value->pointer = p; + d = value; + } + + return d.asT2()->value; +} + +// Will return null if hasValue() == false +template +const V *QPointerValuePair::constValue() const +{ + if (d.isT2()) return &d.asT2()->value; + else return 0; +} + +QT_END_NAMESPACE + +#endif // QPOINTERVALUEPAIR_P_H diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp new file mode 100644 index 0000000000..6fd11d4b1e --- /dev/null +++ b/src/qml/qml/ftw/qqmlpool.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlpool_p.h" + +// #define POOL_DEBUG + +QT_BEGIN_NAMESPACE + +void QQmlPool::newpage() +{ +#ifdef POOL_DEBUG + qWarning("QQmlPool: Allocating page"); +#endif + + Page *page = (Page *)malloc(sizeof(Page)); + page->header.next = _page; + page->header.free = page->memory; + _page = page; +} + +void QQmlPool::clear() +{ +#ifdef POOL_DEBUG + int count = 0; +#endif + + Class *c = _classList; + while (c) { + Class *n = c->_next; + c->_destroy(c); +#ifdef POOL_DEBUG + ++count; +#endif + c = n; + } + +#ifdef POOL_DEBUG + qWarning("QQmlPool: Destroyed %d objects", count); +#endif + + Page *p = _page; + while (p) { + Page *n = p->header.next; + free(p); + p = n; + } + + _classList = 0; + _page = 0; +} + + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h new file mode 100644 index 0000000000..e4fa03ce34 --- /dev/null +++ b/src/qml/qml/ftw/qqmlpool_p.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLPOOL_P_H +#define QQMLPOOL_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 +#include +#include + +QT_BEGIN_NAMESPACE + +// Exported for QtQuick1 +class Q_QML_EXPORT QQmlPool +{ +public: + // The class has a destructor that needs to be called + class Class { + public: + inline QQmlPool *pool() const; + + private: + void *operator new(size_t); + void *operator new(size_t, void *m) { return m; } + friend class QQmlPool; + + QQmlPool *_pool; + Class *_next; + void (*_destroy)(Class *); + }; + + // The class is plain old data and no destructor needs to + // be called + class POD { + public: + inline QQmlPool *pool() const; + + private: + void *operator new(size_t); + void *operator new(size_t, void *m) { return m; } + friend class QQmlPool; + + QQmlPool *_pool; + }; + + inline QQmlPool(); + inline ~QQmlPool(); + + void clear(); + + template + inline T *New(); + template + inline T *NewRaw(); + template + inline T *NewRawArray(int length); + + inline QString *NewString(const QString &); + inline QByteArray *NewByteArray(const QByteArray &); + inline QUrl *NewUrl(const QUrl &); + + template + struct List { + List() : m_length(0), m_data(0) {} + List(const List &o) : m_length(o.m_length), m_data(o.m_data) {} + List &operator=(const List &o) { + m_length = o.m_length; + m_data = o.m_data; + return *this; + } + + int count() const { + return m_length; + } + int length() const { + return m_length; + } + const T &at(int index) const { + Q_ASSERT(index < m_length); + return m_data[index]; + }; + T &operator[](int index) { + Q_ASSERT(index < m_length); + return m_data[index]; + }; + private: + friend class QQmlPool; + List(T *d, int l) : m_length(l), m_data(d) {} + int m_length; + T *m_data; + }; + + template + inline List NewRawList(int length); + +private: + struct StringClass : public QString, public Class { + }; + struct ByteArrayClass : public QByteArray, public Class { + }; + struct UrlClass : public QUrl, public Class { + }; + + inline void *allocate(int size); + void newpage(); + + template + inline void initialize(POD *); + template + inline void initialize(Class *); + template + static void destroy(Class *c); + + struct Page { + struct Header { + Page *next; + char *free; + } header; + + static const int pageSize = 4 * 4096 - sizeof(Header); + + char memory[pageSize]; + }; + + Page *_page; + Class *_classList; +}; + +QQmlPool::QQmlPool() +: _page(0), _classList(0) +{ +} + +QQmlPool::~QQmlPool() +{ + clear(); +} + +template +T *QQmlPool::New() +{ + T *rv = new (allocate(sizeof(T))) T; + initialize(rv); + rv->_pool = this; + return rv; +} + +template +T *QQmlPool::NewRaw() +{ + return (T*)allocate(sizeof(T)); +} + +template +T *QQmlPool::NewRawArray(int length) +{ + return (T*)allocate(length * sizeof(T)); +} + +template +QQmlPool::List QQmlPool::NewRawList(int length) +{ + return List(NewRawArray(length), length); +} + +QString *QQmlPool::NewString(const QString &s) +{ + QString *rv = New(); + *rv = s; + return rv; +} + +QByteArray *QQmlPool::NewByteArray(const QByteArray &s) +{ + QByteArray *rv = New(); + *rv = s; + return rv; +} + +QUrl *QQmlPool::NewUrl(const QUrl &s) +{ + QUrl *rv = New(); + *rv = s; + return rv; +} + +void *QQmlPool::allocate(int size) +{ + if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize)) + newpage(); + + void *rv = _page->header.free; + _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment; + return rv; +} + +template +void QQmlPool::initialize(QQmlPool::POD *) +{ +} + +template +void QQmlPool::initialize(QQmlPool::Class *c) +{ + c->_next = _classList; + c->_destroy = &destroy; + _classList = c; +} + +template +void QQmlPool::destroy(Class *c) +{ + static_cast(c)->~T(); +} + +QQmlPool *QQmlPool::Class::pool() const +{ + return _pool; +} + +QQmlPool *QQmlPool::POD::pool() const +{ + return _pool; +} + +QT_END_NAMESPACE + +#endif // QQMLPOOL_P_H + diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h new file mode 100644 index 0000000000..497f4ecc0f --- /dev/null +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLREFCOUNT_P_H +#define QQMLREFCOUNT_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 +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QQmlRefCount +{ +public: + inline QQmlRefCount(); + inline virtual ~QQmlRefCount(); + inline void addref(); + inline void release(); + +protected: + inline virtual void destroy(); + +private: + QAtomicInt refCount; +}; + +template +class QQmlRefPointer +{ +public: + inline QQmlRefPointer(); + inline QQmlRefPointer(T *); + inline QQmlRefPointer(const QQmlRefPointer &); + inline ~QQmlRefPointer(); + + inline QQmlRefPointer &operator=(const QQmlRefPointer &o); + inline QQmlRefPointer &operator=(T *); + + inline bool isNull() const { return !o; } + + inline T* operator->() const { return o; } + inline T& operator*() const { return *o; } + inline operator T*() const { return o; } + inline T* data() const { return o; } + + inline QQmlRefPointer &take(T *); + +private: + T *o; +}; + +QQmlRefCount::QQmlRefCount() +: refCount(1) +{ +} + +QQmlRefCount::~QQmlRefCount() +{ + Q_ASSERT(refCount.load() == 0); +} + +void QQmlRefCount::addref() +{ + Q_ASSERT(refCount.load() > 0); + refCount.ref(); +} + +void QQmlRefCount::release() +{ + Q_ASSERT(refCount.load() > 0); + if (!refCount.deref()) + destroy(); +} + +void QQmlRefCount::destroy() +{ + delete this; +} + +template +QQmlRefPointer::QQmlRefPointer() +: o(0) +{ +} + +template +QQmlRefPointer::QQmlRefPointer(T *o) +: o(o) +{ + if (o) o->addref(); +} + +template +QQmlRefPointer::QQmlRefPointer(const QQmlRefPointer &other) +: o(other.o) +{ + if (o) o->addref(); +} + +template +QQmlRefPointer::~QQmlRefPointer() +{ + if (o) o->release(); +} + +template +QQmlRefPointer &QQmlRefPointer::operator=(const QQmlRefPointer &other) +{ + if (other.o) other.o->addref(); + if (o) o->release(); + o = other.o; + return *this; +} + +template +QQmlRefPointer &QQmlRefPointer::operator=(T *other) +{ + if (other) other->addref(); + if (o) o->release(); + o = other; + return *this; +} + +/*! +Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership +of the callers reference of other. +*/ +template +QQmlRefPointer &QQmlRefPointer::take(T *other) +{ + if (o) o->release(); + o = other; + return *this; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQMLREFCOUNT_P_H diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp new file mode 100644 index 0000000000..423012b934 --- /dev/null +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlthread_p.h" + +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlThreadPrivate : public QThread +{ +public: + QQmlThreadPrivate(QQmlThread *); + QQmlThread *q; + + virtual void run(); + + inline void lock() { _mutex.lock(); } + inline void unlock() { _mutex.unlock(); } + inline void wait() { _wait.wait(&_mutex); } + inline void wakeOne() { _wait.wakeOne(); } + inline void wakeAll() { _wait.wakeAll(); } + + quint32 m_threadProcessing:1; // Set when the thread is processing messages + quint32 m_mainProcessing:1; // Set when the main thread is processing messages + quint32 m_shutdown:1; // Set by main thread to request a shutdown + quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty + + typedef QFieldList MessageList; + MessageList threadList; + MessageList mainList; + + QQmlThread::Message *mainSync; + + void triggerMainEvent(); + void triggerThreadEvent(); + + void mainEvent(); + void threadEvent(); + +protected: + virtual bool event(QEvent *); + +private: + struct MainObject : public QObject { + MainObject(QQmlThreadPrivate *p); + virtual bool event(QEvent *e); + QQmlThreadPrivate *p; + }; + MainObject m_mainObject; + + QMutex _mutex; + QWaitCondition _wait; +}; + +QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p) +: p(p) +{ +} + +// Trigger mainEvent in main thread. Must be called from thread. +void QQmlThreadPrivate::triggerMainEvent() +{ + Q_ASSERT(q->isThisThread()); + QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); +} + +// Trigger even in thread. Must be called from main thread. +void QQmlThreadPrivate::triggerThreadEvent() +{ + Q_ASSERT(!q->isThisThread()); + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); +} + +bool QQmlThreadPrivate::MainObject::event(QEvent *e) +{ + if (e->type() == QEvent::User) + p->mainEvent(); + return QObject::event(e); +} + +QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q) +: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false), + m_mainThreadWaiting(false), mainSync(0), m_mainObject(this) +{ +} + +bool QQmlThreadPrivate::event(QEvent *e) +{ + if (e->type() == QEvent::User) + threadEvent(); + return QThread::event(e); +} + +void QQmlThreadPrivate::run() +{ + lock(); + + wakeOne(); + + unlock(); + + q->startupThread(); + exec(); +} + +void QQmlThreadPrivate::mainEvent() +{ + lock(); + + m_mainProcessing = true; + + while (!mainList.isEmpty() || mainSync) { + bool isSync = mainSync != 0; + QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst(); + unlock(); + + message->call(q); + delete message; + + lock(); + + if (isSync) { + mainSync = 0; + wakeOne(); + } + } + + m_mainProcessing = false; + + unlock(); +} + +void QQmlThreadPrivate::threadEvent() +{ + lock(); + + if (m_shutdown) { + quit(); + wakeOne(); + unlock(); + q->shutdownThread(); + } else { + m_threadProcessing = true; + + while (!threadList.isEmpty()) { + QQmlThread::Message *message = threadList.first(); + + unlock(); + + message->call(q); + + lock(); + + delete threadList.takeFirst(); + } + + wakeOne(); + + m_threadProcessing = false; + + unlock(); + } +} + +QQmlThread::QQmlThread() +: d(new QQmlThreadPrivate(this)) +{ + d->lock(); + d->start(); + d->wait(); + d->unlock(); + d->moveToThread(d); + +} + +QQmlThread::~QQmlThread() +{ + delete d; +} + +void QQmlThread::shutdown() +{ + d->lock(); + Q_ASSERT(!d->m_shutdown); + d->m_shutdown = true; + if (d->threadList.isEmpty() && d->m_threadProcessing == false) + d->triggerThreadEvent(); + d->wait(); + d->unlock(); + d->QThread::wait(); +} + +void QQmlThread::lock() +{ + d->lock(); +} + +void QQmlThread::unlock() +{ + d->unlock(); +} + +void QQmlThread::wakeOne() +{ + d->wakeOne(); +} + +void QQmlThread::wakeAll() +{ + d->wakeAll(); +} + +void QQmlThread::wait() +{ + d->wait(); +} + +bool QQmlThread::isThisThread() const +{ + return QThread::currentThread() == d; +} + +QThread *QQmlThread::thread() const +{ + return const_cast(static_cast(d)); +} + +// Called when the thread starts. Do startup stuff in here. +void QQmlThread::startupThread() +{ +} + +// Called when the thread shuts down. Do cleanup in here. +void QQmlThread::shutdownThread() +{ +} + +void QQmlThread::internalCallMethodInThread(Message *message) +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + bool wasEmpty = d->threadList.isEmpty(); + d->threadList.append(message); + if (wasEmpty && d->m_threadProcessing == false) + d->triggerThreadEvent(); + + d->m_mainThreadWaiting = true; + + do { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } while (d->mainSync || !d->threadList.isEmpty()); + + d->m_mainThreadWaiting = false; + d->unlock(); +} + +void QQmlThread::internalCallMethodInMain(Message *message) +{ + Q_ASSERT(isThisThread()); + + d->lock(); + + Q_ASSERT(d->mainSync == 0); + d->mainSync = message; + + if (d->m_mainThreadWaiting) { + d->wakeOne(); + } else if (d->m_mainProcessing) { + // Do nothing - it is already looping + } else { + d->triggerMainEvent(); + } + + while (d->mainSync && !d->m_shutdown) + d->wait(); + + d->unlock(); +} + +void QQmlThread::internalPostMethodToThread(Message *message) +{ + Q_ASSERT(!isThisThread()); + d->lock(); + bool wasEmpty = d->threadList.isEmpty(); + d->threadList.append(message); + if (wasEmpty && d->m_threadProcessing == false) + d->triggerThreadEvent(); + d->unlock(); +} + +void QQmlThread::internalPostMethodToMain(Message *message) +{ + Q_ASSERT(isThisThread()); + d->lock(); + bool wasEmpty = d->mainList.isEmpty(); + d->mainList.append(message); + if (wasEmpty && d->m_mainProcessing == false) + d->triggerMainEvent(); + d->unlock(); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h new file mode 100644 index 0000000000..8a0ec6ceaa --- /dev/null +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLTHREAD_P_H +#define QQMLTHREAD_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 + +#include + +QT_BEGIN_NAMESPACE + +class QThread; + +class QQmlThreadPrivate; +class QQmlThread +{ +public: + QQmlThread(); + virtual ~QQmlThread(); + void shutdown(); + + void lock(); + void unlock(); + void wakeOne(); + void wakeAll(); + void wait(); + + QThread *thread() const; + bool isThisThread() const; + + // Synchronously invoke a method in the thread + template + inline void callMethodInThread(void (O::*Member)()); + template + inline void callMethodInThread(void (O::*Member)(V), const T &); + template + inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &); + + // Synchronously invoke a method in the main thread. If the main thread is + // blocked in a callMethodInThread() call, the call is made from within that + // call. + template + inline void callMethodInMain(void (O::*Member)()); + template + inline void callMethodInMain(void (O::*Member)(V), const T &); + template + inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &); + + // Asynchronously invoke a method in the thread. + template + inline void postMethodToThread(void (O::*Member)()); + template + inline void postMethodToThread(void (O::*Member)(V), const T &); + template + inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &); + + // Asynchronously invoke a method in the main thread. + template + inline void postMethodToMain(void (O::*Member)()); + template + inline void postMethodToMain(void (O::*Member)(V), const T &); + template + inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + +protected: + virtual void startupThread(); + virtual void shutdownThread(); + +private: + friend class QQmlThreadPrivate; + + struct Message { + Message() : next(0) {} + virtual ~Message() {} + Message *next; + virtual void call(QQmlThread *) = 0; + }; + void internalCallMethodInThread(Message *); + void internalCallMethodInMain(Message *); + void internalPostMethodToThread(Message *); + void internalPostMethodToMain(Message *); + QQmlThreadPrivate *d; +}; + +template +void QQmlThread::callMethodInThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(); + } + }; + internalCallMethodInThread(new I(Member)); +} + +template +void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg); + } + }; + internalCallMethodInThread(new I(Member, arg)); +} + +template +void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInThread(new I(Member, arg, arg2)); +} + +template +void QQmlThread::callMethodInMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(); + } + }; + internalCallMethodInMain(new I(Member)); +} + +template +void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg); + } + }; + internalCallMethodInMain(new I(Member, arg)); +} + +template +void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg, arg2); + } + }; + internalCallMethodInMain(new I(Member, arg, arg2)); +} + +template +void QQmlThread::postMethodToThread(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(); + } + }; + internalPostMethodToThread(new I(Member)); +} + +template +void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg); + } + }; + internalPostMethodToThread(new I(Member, arg)); +} + +template +void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToThread(new I(Member, arg, arg2)); +} + +template +void QQmlThread::postMethodToMain(void (O::*Member)()) +{ + struct I : public Message { + void (O::*Member)(); + I(void (O::*Member)()) : Member(Member) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(); + } + }; + internalPostMethodToMain(new I(Member)); +} + +template +void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg) +{ + struct I : public Message { + void (O::*Member)(V); + T arg; + I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg); + } + }; + internalPostMethodToMain(new I(Member, arg)); +} + +template +void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +{ + struct I : public Message { + void (O::*Member)(V, V2); + T arg; + T2 arg2; + I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + virtual void call(QQmlThread *thread) { + O *me = static_cast(thread); + (me->*Member)(arg, arg2); + } + }; + internalPostMethodToMain(new I(Member, arg, arg2)); +} + +QT_END_NAMESPACE + +#endif // QQMLTHREAD_P_H diff --git a/src/qml/qml/ftw/qqmltrace.cpp b/src/qml/qml/ftw/qqmltrace.cpp new file mode 100644 index 0000000000..e044dc654f --- /dev/null +++ b/src/qml/qml/ftw/qqmltrace.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmltrace_p.h" + +#ifdef QML_ENABLE_TRACE +#include +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QML_ENABLE_TRACE + +QQmlTrace::Pool QQmlTrace::logPool; +QQmlTrace::Entry *QQmlTrace::first = 0; +QQmlTrace::Entry *QQmlTrace::last = 0; + +static qint64 toNsecs(QQmlTrace::TimeType time) +{ +#ifdef Q_OS_MAC + static mach_timebase_info_data_t info = {0,0}; + if (info.denom == 0) + mach_timebase_info(&info); + return time * info.numer / info.denom; +#else + qint64 rv = time.tv_sec * 1000000000 + time.tv_nsec; + return rv; +#endif +} + +QQmlTrace::Pool::Pool() +{ + first = New(); + last = first; +} + +QQmlTrace::Pool::~Pool() +{ + char buffer[128]; + sprintf(buffer, "qml.%d.log", ::getpid()); + FILE *out = fopen(buffer, "w"); + if (!out) { + fprintf (stderr, "QML Log: Could not open %s\n", buffer); + return; + } else { + fprintf (stderr, "QML Log: Writing log to %s\n", buffer); + } + + QQmlTrace::Entry *cur = QQmlTrace::first; + QByteArray indent; + int depth = -1; + + qint64 firstTime = -1; + + while (cur) { + + switch (cur->type) { + case QQmlTrace::Entry::RangeStart: { + RangeStart *rs = static_cast(cur); + + qint64 nsecs = toNsecs(rs->time); + + if (firstTime == -1) + firstTime = nsecs; + + nsecs -= firstTime; + + depth++; + indent = QByteArray(depth * 4, ' '); + fprintf(out, "%s%s @%lld (%lld ns)\n", indent.constData(), + rs->description, nsecs, toNsecs(rs->end->time) - nsecs - firstTime); + } break; + case QQmlTrace::Entry::RangeEnd: + depth--; + indent = QByteArray(depth * 4, ' '); + break; + case QQmlTrace::Entry::Detail: + fprintf(out, "%s %s\n", indent.constData(), + static_cast(cur)->description); + break; + case QQmlTrace::Entry::IntDetail: + fprintf(out, "%s %s: %d\n", indent.constData(), + static_cast(cur)->description, + static_cast(cur)->value); + break; + case QQmlTrace::Entry::StringDetail: { + QByteArray vLatin1 = static_cast(cur)->value->toLatin1(); + fprintf(out, "%s %s: %s\n", indent.constData(), + static_cast(cur)->description, + vLatin1.constData()); + } break; + case QQmlTrace::Entry::UrlDetail: { + QByteArray vLatin1 = static_cast(cur)->value->toString().toLatin1(); + fprintf(out, "%s %s: %s\n", indent.constData(), + static_cast(cur)->description, + vLatin1.constData()); + } break; + case QQmlTrace::Entry::Event: { + Event *ev = static_cast(cur); + qint64 nsecs = toNsecs(ev->time) - firstTime; + fprintf(out, "%s + %s @%lld +%lld ns\n", indent.constData(), + ev->description, nsecs, nsecs - (toNsecs(ev->start->time) - firstTime)); + } break; + case QQmlTrace::Entry::Null: + default: + break; + } + cur = cur->next; + } + fclose(out); +} + +#endif + +QT_END_NAMESPACE + diff --git a/src/qml/qml/ftw/qqmltrace_p.h b/src/qml/qml/ftw/qqmltrace_p.h new file mode 100644 index 0000000000..965baff3a3 --- /dev/null +++ b/src/qml/qml/ftw/qqmltrace_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLTRACE_P_H +#define QQMLTRACE_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 +#include + +// #define QML_ENABLE_TRACE + +#if defined(QML_ENABLE_TRACE) && defined(Q_OS_MAC) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QUrl; +class QQmlTrace +{ +public: + inline QQmlTrace(const char *desc); + inline ~QQmlTrace(); + + inline void addDetail(const char *); + inline void addDetail(const char *, int); + inline void addDetail(const char *, const QString &); + inline void addDetail(const char *, const QUrl &); + + inline void event(const char *desc); + +#ifdef QML_ENABLE_TRACE + +#ifdef Q_OS_MAC + typedef uint64_t TimeType; +#else + typedef timespec TimeType; +#endif + + struct Entry : public QQmlPool::POD { + enum Type { Null, RangeStart, RangeEnd, Detail, IntDetail, StringDetail, UrlDetail, Event }; + inline Entry(); + inline Entry(Type); + Type type; + Entry *next; + }; + struct RangeEnd : public Entry { + inline RangeEnd(); + TimeType time; + }; + struct RangeStart : public Entry { + inline RangeStart(); + const char *description; + TimeType time; + QQmlTrace::RangeEnd *end; + }; + struct Detail : public Entry { + inline Detail(); + inline Detail(Type t); + const char *description; + }; + struct IntDetail : public Detail { + inline IntDetail(); + int value; + }; + struct StringDetail : public Detail { + inline StringDetail(); + QString *value; + }; + struct UrlDetail : public Detail { + inline UrlDetail(); + QUrl *value; + }; + struct Event : public Entry { + inline Event(); + const char *description; + TimeType time; + QQmlTrace::RangeStart *start; + }; + + struct Pool : public QQmlPool { + Pool(); + ~Pool(); + }; + + static Pool logPool; + static Entry *first; + static Entry *last; + +private: + RangeStart *start; + + static TimeType gettime() { +#ifdef Q_OS_MAC + return mach_absolute_time(); +#else + TimeType ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts; +#endif + } +#endif +}; + +#ifdef QML_ENABLE_TRACE +QQmlTrace::Entry::Entry() +: type(Null), next(0) +{ +} + +QQmlTrace::Entry::Entry(Type type) +: type(type), next(0) +{ + QQmlTrace::last->next = this; + QQmlTrace::last = this; +} + +QQmlTrace::RangeEnd::RangeEnd() +: QQmlTrace::Entry(QQmlTrace::Entry::RangeEnd), + time(gettime()) +{ +} + +QQmlTrace::RangeStart::RangeStart() +: QQmlTrace::Entry(QQmlTrace::Entry::RangeStart), + description(0), time(gettime()) +{ +} + +QQmlTrace::Detail::Detail() +: QQmlTrace::Entry(QQmlTrace::Entry::Detail), + description(0) +{ +} + +QQmlTrace::Detail::Detail(Type type) +: QQmlTrace::Entry(type), description(0) +{ +} + +QQmlTrace::IntDetail::IntDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::IntDetail), + value(0) +{ +} + +QQmlTrace::StringDetail::StringDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::StringDetail), + value(0) +{ +} + +QQmlTrace::UrlDetail::UrlDetail() +: QQmlTrace::Detail(QQmlTrace::Entry::UrlDetail), + value(0) +{ +} + +QQmlTrace::Event::Event() +: QQmlTrace::Entry(QQmlTrace::Entry::Event), + description(0), time(gettime()), start(0) +{ +} +#endif + +QQmlTrace::QQmlTrace(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + RangeStart *e = logPool.New(); + e->description = desc; + e->end = 0; + start = e; +#else + Q_UNUSED(desc); +#endif +} + +QQmlTrace::~QQmlTrace() +{ +#ifdef QML_ENABLE_TRACE + RangeEnd *e = logPool.New(); + start->end = e; +#endif +} + +void QQmlTrace::addDetail(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + Detail *e = logPool.New(); + e->description = desc; +#else + Q_UNUSED(desc); +#endif +} + +void QQmlTrace::addDetail(const char *desc, int v) +{ +#ifdef QML_ENABLE_TRACE + IntDetail *e = logPool.New(); + e->description = desc; + e->value = v; +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::addDetail(const char *desc, const QString &v) +{ +#ifdef QML_ENABLE_TRACE + StringDetail *e = logPool.New(); + e->description = desc; + e->value = logPool.NewString(v); +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::addDetail(const char *desc, const QUrl &v) +{ +#ifdef QML_ENABLE_TRACE + UrlDetail *e = logPool.New(); + e->description = desc; + e->value = logPool.NewUrl(v); +#else + Q_UNUSED(desc); + Q_UNUSED(v); +#endif +} + +void QQmlTrace::event(const char *desc) +{ +#ifdef QML_ENABLE_TRACE + Event *e = logPool.New(); + e->start = start; + e->description = desc; +#else + Q_UNUSED(desc); +#endif +} + +QT_END_NAMESPACE + +#endif // QQMLTRACE_P_H diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h new file mode 100644 index 0000000000..16886edf12 --- /dev/null +++ b/src/qml/qml/ftw/qrecursionwatcher_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRECURSIONWATCHER_P_H +#define QRECURSIONWATCHER_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 + +QT_BEGIN_NAMESPACE + +class QRecursionNode; +class QRecursionNode { +public: + inline QRecursionNode(); + bool *_r; +}; + +template +class QRecursionWatcher { +public: + inline QRecursionWatcher(T *); + inline ~QRecursionWatcher(); + inline bool hasRecursed() const; +private: + T *_t; + bool _r; +}; + +QRecursionNode::QRecursionNode() +: _r(0) +{ +} + +template +QRecursionWatcher::QRecursionWatcher(T *t) +: _t(t), _r(false) +{ + if ((_t->*Node)._r) *(_t->*Node)._r = true; + (_t->*Node)._r = &_r; +} + +template +QRecursionWatcher::~QRecursionWatcher() +{ + if ((_t->*Node)._r == &_r) (_t->*Node)._r = 0; +} + +template +bool QRecursionWatcher::hasRecursed() const +{ + return _r; +} + +QT_END_NAMESPACE + +#endif // QRECURSIONWATCHER_P_H diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h new file mode 100644 index 0000000000..8d0f060ab3 --- /dev/null +++ b/src/qml/qml/ftw/qrecyclepool_p.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRECYCLEPOOL_P_H +#define QRECYCLEPOOL_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. +// + +QT_BEGIN_NAMESPACE + +#define QRECYCLEPOOLCOOKIE 0x33218ADF + +template +class QRecyclePoolPrivate +{ +public: + QRecyclePoolPrivate() + : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE), + currentPage(0), nextAllocated(0) + { + } + + bool recyclePoolHold; + int outstandingItems; + quint32 cookie; + + struct PoolType : public T { + union { + QRecyclePoolPrivate *pool; + PoolType *nextAllocated; + }; + }; + + struct Page { + Page *nextPage; + unsigned int free; + union { + char array[Step * sizeof(PoolType)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; + }; + + Page *currentPage; + PoolType *nextAllocated; + + inline T *allocate(); + static inline void dispose(T *); + inline void releaseIfPossible(); +}; + +template +class QRecyclePool +{ +public: + inline QRecyclePool(); + inline ~QRecyclePool(); + + inline T *New(); + template + inline T *New(const T1 &); + template + inline T *New(T1 &); + + static inline void Delete(T *); + +private: + QRecyclePoolPrivate *d; +}; + +template +QRecyclePool::QRecyclePool() +: d(new QRecyclePoolPrivate()) +{ +} + +template +QRecyclePool::~QRecyclePool() +{ + d->recyclePoolHold = false; + d->releaseIfPossible(); +} + +template +T *QRecyclePool::New() +{ + T *rv = d->allocate(); + new (rv) T; + return rv; +} + +template +template +T *QRecyclePool::New(const T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template +template +T *QRecyclePool::New(T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template +void QRecyclePool::Delete(T *t) +{ + t->~T(); + QRecyclePoolPrivate::dispose(t); +} + +template +void QRecyclePoolPrivate::releaseIfPossible() +{ + if (recyclePoolHold || outstandingItems) + return; + + Page *p = currentPage; + while (p) { + Page *n = p->nextPage; + qFree(p); + p = n; + } + + delete this; +} + +template +T *QRecyclePoolPrivate::allocate() +{ + PoolType *rv = 0; + if (nextAllocated) { + rv = nextAllocated; + nextAllocated = rv->nextAllocated; + } else if (currentPage && currentPage->free) { + rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType)); + currentPage->free--; + } else { + Page *p = (Page *)qMalloc(sizeof(Page)); + p->nextPage = currentPage; + p->free = Step; + currentPage = p; + + rv = (PoolType *)currentPage->array; + currentPage->free--; + } + + rv->pool = this; + ++outstandingItems; + return rv; +} + +template +void QRecyclePoolPrivate::dispose(T *t) +{ + PoolType *pt = static_cast(t); + Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE); + + QRecyclePoolPrivate *This = pt->pool; + pt->nextAllocated = This->nextAllocated; + This->nextAllocated = pt; + --This->outstandingItems; + This->releaseIfPossible(); +} + +QT_END_NAMESPACE + +#endif // QRECYCLEPOOL_P_H diff --git a/src/qml/qml/parser/parser.pri b/src/qml/qml/parser/parser.pri new file mode 100644 index 0000000000..6be85ba85a --- /dev/null +++ b/src/qml/qml/parser/parser.pri @@ -0,0 +1,19 @@ +HEADERS += \ + $$PWD/qqmljsast_p.h \ + $$PWD/qqmljsastfwd_p.h \ + $$PWD/qqmljsastvisitor_p.h \ + $$PWD/qqmljsengine_p.h \ + $$PWD/qqmljsgrammar_p.h \ + $$PWD/qqmljslexer_p.h \ + $$PWD/qqmljsmemorypool_p.h \ + $$PWD/qqmljsparser_p.h \ + $$PWD/qqmljsglobal_p.h \ + $$PWD/qqmljskeywords_p.h + +SOURCES += \ + $$PWD/qqmljsast.cpp \ + $$PWD/qqmljsastvisitor.cpp \ + $$PWD/qqmljsengine_p.cpp \ + $$PWD/qqmljsgrammar.cpp \ + $$PWD/qqmljslexer.cpp \ + $$PWD/qqmljsparser.cpp diff --git a/src/qml/qml/parser/qqmljs.g b/src/qml/qml/parser/qqmljs.g new file mode 100644 index 0000000000..746fcb24df --- /dev/null +++ b/src/qml/qml/parser/qqmljs.g @@ -0,0 +1,3016 @@ +---------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +-- Contact: http://www.qt-project.org/ +-- +-- This file is part of the QtQml 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 +-- us via http://www.qt-project.org/. +-- +-- $QT_END_LICENSE$ +-- +---------------------------------------------------------------------------- + +%parser QQmlJSGrammar +%decl qqmljsparser_p.h +%impl qdeclarativejsparser.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" + +%token T_ERROR + +--- 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). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include "qqmljsengine_p.h" +#include "qqmljslexer_p.h" +#include "qqmljsast_p.h" +#include "qqmljsmemorypool_p.h" + +./ + +/:/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $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 QDECLARATIVEJSPARSER_P_H +#define QDECLARATIVEJSPARSER_P_H + +#include "qqmljsglobal_p.h" +#include "qqmljsgrammar_p.h" +#include "qqmljsast_p.h" +#include "qqmljsengine_p.h" + +#include +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +class Engine; + +class QML_PARSER_EXPORT Parser: protected $table +{ +public: + union Value { + int ival; + double dval; + 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; + }; + +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(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 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 QStringRef &stringRef(int index) + { return string_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; + MemoryPool *pool; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + QStringRef *string_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + QStringRef spell; + }; + + double yylval; + QStringRef yytokenspell; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList diagnostic_messages; +}; + +} // end of namespace QQmlJS + + +:/ + + +/. + +#include "qqmljsparser_p.h" +#include + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QQmlJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); + string_stack = reinterpret_cast (realloc(string_stack, stack_size * sizeof(QStringRef))); +} + +Parser::Parser(Engine *engine): + driver(engine), + pool(engine->pool()), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + string_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + free(sym_stack); + free(state_stack); + free(location_stack); + free(string_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->tokenStartLine(); + loc.startColumn = lexer->tokenStartColumn(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray nameIds; + QVarLengthArray locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast(it)) { + AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = new (pool) AST::UiQualifiedId(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->tokenValue(); + yytokenspell = lexer->tokenSpell(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yytokenspell = first_token->spell; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + stringRef(1) = yytokenspell; + 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 = new (pool) AST::UiProgram(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 = new (pool) AST::UiImportList(sym(1).UiImport); +} break; +./ + +UiImportList: UiImportList UiImport ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::UiImportList(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 = stringRef(4); + 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 = stringRef(3); + sym(1).UiImport->semicolonToken = loc(4); +} break; +./ + + +UiImportHead: T_IMPORT ImportId ; +/. +case $rule_number: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast(sym(2).Expression)) { + node = new (pool) AST::UiImport(importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + node = new (pool) AST::UiImport(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 = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMember ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMemberList UiObjectMember ; +/. +case $rule_number: { + AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList( + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; +./ + +UiArrayMemberList: UiObjectDefinition ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember); +} break; +./ + +UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ; +/. +case $rule_number: { + AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList( + 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 = new (pool) AST::UiObjectInitializer((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 = new (pool) AST::UiObjectInitializer(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 = new (pool) AST::UiObjectDefinition(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 = new (pool) AST::UiArrayBinding( + 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 = new (pool) AST::UiObjectBinding( + 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 = new (pool) AST::UiObjectBinding( + 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 ; +UiScriptStatement: WithStatement ; +UiScriptStatement: SwitchStatement ; +UiScriptStatement: TryStatement ; + +UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ; +/. +case $rule_number: +{ + AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding( + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiPropertyType: T_VAR ; +UiPropertyType: T_RESERVED_WORD ; +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 = new (pool) AST::UiParameterList(stringRef(1), stringRef(2)); + node->propertyTypeToken = loc(1); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ; +/. +case $rule_number: { + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4)); + 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 = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); + 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 = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); + 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 = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); + node->typeModifier = stringRef(2); + 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 = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); + 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 = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); + 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 = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3), + 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 = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), + 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 = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), + 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 = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); + node->typeModifier = stringRef(2); + 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 = new (pool) AST::UiQualifiedId(stringRef(6)); + propertyName->identifierToken = loc(6); + propertyName->next = 0; + + AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding( + 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 = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3)); + propertyName->identifierToken = loc(3); + propertyName->next = 0; + + AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( + 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 = new (pool) AST::UiSourceElement(sym(1).Node); +} break; +./ + +UiObjectMember: VariableStatement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); +} break; +./ + +JsIdentifier: T_IDENTIFIER; + +JsIdentifier: T_PROPERTY ; +JsIdentifier: T_SIGNAL ; +JsIdentifier: T_READONLY ; +JsIdentifier: T_ON ; + +-------------------------------------------------------------------------------------------------------- +-- Expressions +-------------------------------------------------------------------------------------------------------- + +PrimaryExpression: T_THIS ; +/. +case $rule_number: { + AST::ThisExpression *node = new (pool) AST::ThisExpression(); + node->thisToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: JsIdentifier ; +/. +case $rule_number: { + AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1)); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NULL ; +/. +case $rule_number: { + AST::NullExpression *node = new (pool) AST::NullExpression(); + node->nullToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_TRUE ; +/. +case $rule_number: { + AST::TrueLiteral *node = new (pool) AST::TrueLiteral(); + node->trueToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_FALSE ; +/. +case $rule_number: { + AST::FalseLiteral *node = new (pool) AST::FalseLiteral(); + node->falseToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteral *node = new (pool) AST::NumericLiteral(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 = new (pool) AST::StringLiteral(stringRef(1)); + 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(); + yylloc = loc(1); // adjust the location of the current token + + AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( + driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); + 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(); + yylloc = loc(1); // adjust the location of the current token + + AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( + driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((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 = new (pool) AST::ArrayLiteral(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 = new (pool) AST::ArrayLiteral(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 = new (pool) AST::ArrayLiteral(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 = new (pool) AST::ArrayLiteral(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 = new (pool) AST::ObjectLiteral(); +-- } break; +-- ./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; +/. +case $rule_number: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = new (pool) AST::ObjectLiteral( + sym(2).PropertyNameAndValueList->finish ()); + else + node = new (pool) AST::ObjectLiteral(); + 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 = new (pool) AST::ObjectLiteral( + 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 = new (pool) AST::NestedExpression(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(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 = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); +} break; +./ + +ElementList: Elision AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression); +} break; +./ + +ElementList: ElementList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ElementList *node = new (pool) AST::ElementList(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 = new (pool) AST::ElementList(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 = new (pool) AST::Elision(); + node->commaToken = loc(1); + sym(1).Node = node; +} break; +./ + +Elision: Elision T_COMMA ; +/. +case $rule_number: { + AST::Elision *node = new (pool) AST::Elision(sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList( + 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 = new (pool) AST::PropertyNameAndValueList( + 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 = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_SIGNAL ; +/.case $rule_number:./ + +PropertyName: T_PROPERTY ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_STRING_LITERAL ; +/. +case $rule_number: { + AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: ReservedIdentifier ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +ReservedIdentifier: T_BREAK ; +ReservedIdentifier: T_CASE ; +ReservedIdentifier: T_CATCH ; +ReservedIdentifier: T_CONTINUE ; +ReservedIdentifier: T_DEFAULT ; +ReservedIdentifier: T_DELETE ; +ReservedIdentifier: T_DO ; +ReservedIdentifier: T_ELSE ; +ReservedIdentifier: T_FALSE ; +ReservedIdentifier: T_FINALLY ; +ReservedIdentifier: T_FOR ; +ReservedIdentifier: T_FUNCTION ; +ReservedIdentifier: T_IF ; +ReservedIdentifier: T_IN ; +ReservedIdentifier: T_INSTANCEOF ; +ReservedIdentifier: T_NEW ; +ReservedIdentifier: T_NULL ; +ReservedIdentifier: T_RETURN ; +ReservedIdentifier: T_SWITCH ; +ReservedIdentifier: T_THIS ; +ReservedIdentifier: T_THROW ; +ReservedIdentifier: T_TRUE ; +ReservedIdentifier: T_TRY ; +ReservedIdentifier: T_TYPEOF ; +ReservedIdentifier: T_VAR ; +ReservedIdentifier: T_VOID ; +ReservedIdentifier: T_WHILE ; +ReservedIdentifier: T_CONST ; +ReservedIdentifier: T_DEBUGGER ; +ReservedIdentifier: T_RESERVED_WORD ; +ReservedIdentifier: T_WITH ; + +PropertyIdentifier: JsIdentifier ; +PropertyIdentifier: ReservedIdentifier ; + +MemberExpression: PrimaryExpression ; +MemberExpression: FunctionExpression ; + +MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(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 = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + 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 = new (pool) AST::NewMemberExpression(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 = new (pool) AST::NewExpression(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 = new (pool) AST::CallExpression(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 = new (pool) AST::CallExpression(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 = new (pool) AST::ArrayMemberExpression(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 = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + 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 = new (pool) AST::ArgumentList(sym(1).Expression); +} break; +./ + +ArgumentList: ArgumentList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ArgumentList *node = new (pool) AST::ArgumentList(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 = new (pool) AST::PostIncrementExpression(sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; +/. +case $rule_number: { + AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +UnaryExpression: PostfixExpression ; + +UnaryExpression: T_DELETE UnaryExpression ; +/. +case $rule_number: { + AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_VOID UnaryExpression ; +/. +case $rule_number: { + AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TYPEOF UnaryExpression ; +/. +case $rule_number: { + AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TILDE UnaryExpression ; +/. +case $rule_number: { + AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_NOT UnaryExpression ; +/. +case $rule_number: { + AST::NotExpression *node = new (pool) AST::NotExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::ConditionalExpression(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 = new (pool) AST::ConditionalExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::BinaryExpression(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 = new (pool) AST::Expression(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 = new (pool) AST::Expression(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 = new (pool) AST::Block(sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +StatementList: Statement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); +} break; +./ + +StatementList: StatementList Statement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::StatementList(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 = new (pool) AST::VariableStatement( + 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 = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; +/. +case $rule_number: { + AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList( + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; +./ + +VariableDeclaration: JsIdentifier InitialiserOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), 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 = new (pool) AST::EmptyStatement(); + 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 = new (pool) AST::ExpressionStatement(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 = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(6); + sym(1).Node = node; +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::IfStatement *node = new (pool) AST::IfStatement(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 = new (pool) AST::DoWhileStatement(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 = new (pool) AST::WhileStatement(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 = new (pool) AST::ForStatement(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 = new (pool) AST::LocalForStatement( + 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 = new (pool) AST::ForEachStatement(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 = new (pool) AST::LocalForEachStatement( + 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 = new (pool) AST::ContinueStatement(); + 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 = new (pool) AST::ContinueStatement(stringRef(2)); + 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 = new (pool) AST::BreakStatement(QStringRef()); + 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 = new (pool) AST::BreakStatement(stringRef(2)); + 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 = new (pool) AST::ReturnStatement(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 = new (pool) AST::WithStatement(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 = new (pool) AST::SwitchStatement(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 = new (pool) AST::CaseBlock(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 = new (pool) AST::CaseBlock(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 = new (pool) AST::CaseClauses(sym(1).CaseClause); +} break; +./ + +CaseClauses: CaseClauses CaseClause ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::CaseClauses(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 = new (pool) AST::CaseClause(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 = new (pool) AST::DefaultClause(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 = new (pool) AST::LabelledStatement(stringRef(1), 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 = new (pool) AST::LabelledStatement(stringRef(1), 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 = new (pool) AST::ThrowStatement(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 = new (pool) AST::TryStatement(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 = new (pool) AST::TryStatement(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 = new (pool) AST::TryStatement(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 = new (pool) AST::Catch(stringRef(3), 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 = new (pool) AST::Finally(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 = new (pool) AST::DebuggerStatement(); + 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 = new (pool) AST::FunctionDeclaration(stringRef(2), 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 = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (! stringRef(2).isNull()) + 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 = new (pool) AST::FormalParameterList(stringRef(1)); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +FormalParameterList: FormalParameterList T_COMMA JsIdentifier ; +/. +case $rule_number: { + AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); + 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 = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); +} break; +./ + +Program: Empty ; + +Program: SourceElements ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); +} break; +./ + +SourceElements: SourceElement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); +} break; +./ + +SourceElements: SourceElements SourceElement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); +} break; +./ + +SourceElement: Statement ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); +} break; +./ + +SourceElement: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); +} break; +./ + +IdentifierOpt: ; +/. +case $rule_number: { + stringRef(1) = QStringRef(); +} 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) && lexer->canInsertAutomaticSemicolon(yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.spell = yytokenspell; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QQmlParser", "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].spell = yytokenspell; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->tokenValue(); + token_buffer[1].spell = yytokenspell = lexer->tokenSpell(); + 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("QQmlParser", "Syntax error"); + else + msg = qApp->translate("QQmlParser", "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("QQmlParser", "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("QQmlParser", "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("QQmlParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + +./ +/: +QT_QML_END_NAMESPACE + + + +#endif // QDECLARATIVEJSPARSER_P_H +:/ diff --git a/src/qml/qml/parser/qqmljsast.cpp b/src/qml/qml/parser/qqmljsast.cpp new file mode 100644 index 0000000000..d0b984fc9e --- /dev/null +++ b/src/qml/qml/parser/qqmljsast.cpp @@ -0,0 +1,931 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmljsast_p.h" + +#include "qqmljsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { 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 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 QQmlJS::AST + +QT_QML_END_NAMESPACE + + diff --git a/src/qml/qml/parser/qqmljsast_p.h b/src/qml/qml/parser/qqmljsast_p.h new file mode 100644 index 0000000000..f85eb4ca5f --- /dev/null +++ b/src/qml/qml/parser/qqmljsast_p.h @@ -0,0 +1,2640 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSAST_P_H +#define QQMLJSAST_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 "qqmljsastvisitor_p.h" +#include "qqmljsglobal_p.h" +#include "qqmljsmemorypool_p.h" + +#include + +QT_QML_BEGIN_NAMESPACE + +#define QQMLJS_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 QQmlJS { + +namespace AST { + +template +_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 Managed +{ +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 + }; + + 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; + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; + +// attributes + int kind; +}; + +class QML_PARSER_EXPORT ExpressionNode: public Node +{ +public: + ExpressionNode() {} + + virtual ExpressionNode *expressionCast(); +}; + +class QML_PARSER_EXPORT Statement: public Node +{ +public: + Statement() {} + + virtual Statement *statementCast(); +}; + +class QML_PARSER_EXPORT NestedExpression: public ExpressionNode +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(IdentifierExpression) + + IdentifierExpression(const QStringRef &n): + name (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return identifierToken; } + +// attributes + QStringRef name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NullExpression: public ExpressionNode +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(StringLiteral) + + StringLiteral(const QStringRef &v): + value (v) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + QStringRef value; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode +{ +public: + QQMLJS_DECLARE_AST_NODE(RegExpLiteral) + + RegExpLiteral(const QStringRef &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: + QStringRef pattern; + int flags; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode +{ +public: + QQMLJS_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: + QQMLJS_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 Elision: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return commaToken; } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : commaToken; } + + inline Elision *finish () + { + Elision *front = next; + next = 0; + return front; + } + +// attributes + Elision *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT ElementList: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { + if (elision) + return elision->firstSourceLocation(); + return expression->firstSourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (next) + return next->lastSourceLocation(); + return expression->lastSourceLocation(); + } + +// attributes + Elision *elision; + ExpressionNode *expression; + ElementList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PropertyName: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(PropertyName) + + PropertyName() { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return propertyNameToken; } + + virtual SourceLocation lastSourceLocation() const + { return propertyNameToken; } + +// attributes + SourceLocation propertyNameToken; +}; + +class QML_PARSER_EXPORT PropertyNameAndValueList: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return name->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { + if (next) + return next->lastSourceLocation(); + return value->lastSourceLocation(); + } + + 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 IdentifierPropertyName: public PropertyName +{ +public: + QQMLJS_DECLARE_AST_NODE(IdentifierPropertyName) + + IdentifierPropertyName(const QStringRef &n): + id (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + QStringRef id; +}; + +class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName +{ +public: + QQMLJS_DECLARE_AST_NODE(StringLiteralPropertyName) + + StringLiteralPropertyName(const QStringRef &n): + id (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + QStringRef id; +}; + +class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(FieldMemberExpression) + + FieldMemberExpression(ExpressionNode *b, const QStringRef &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; + QStringRef name; + SourceLocation dotToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return expression->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { + if (next) + return next->lastSourceLocation(); + return expression->lastSourceLocation(); + } + + 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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return statement->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : statement->lastSourceLocation(); } + + inline StatementList *finish () + { + StatementList *front = next; + next = 0; + return front; + } + +// attributes + Statement *statement; + StatementList *next; +}; + +class QML_PARSER_EXPORT VariableStatement: public Statement +{ +public: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(VariableDeclaration) + + VariableDeclaration(const QStringRef &n, ExpressionNode *e): + name (n), expression (e), readOnly(false) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression ? expression->lastSourceLocation() : identifierToken; } + +// attributes + QStringRef name; + ExpressionNode *expression; + bool readOnly; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT VariableDeclarationList: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return declaration->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { + if (next) + return next->lastSourceLocation(); + return declaration->lastSourceLocation(); + } + + 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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(ContinueStatement) + + ContinueStatement(const QStringRef &l = QStringRef()): + label (l) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return continueToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + QStringRef label; + SourceLocation continueToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT BreakStatement: public Statement +{ +public: + QQMLJS_DECLARE_AST_NODE(BreakStatement) + + BreakStatement(const QStringRef &l): + label (l) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return breakToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + // attributes + QStringRef label; + SourceLocation breakToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT ReturnStatement: public Statement +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + CaseClauses *clauses; + DefaultClause *defaultClause; + CaseClauses *moreClauses; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT SwitchStatement: public Statement +{ +public: + QQMLJS_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 CaseClause: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(CaseClause) + + CaseClause(ExpressionNode *e, StatementList *slist): + expression (e), statements (slist) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return caseToken; } + + virtual SourceLocation lastSourceLocation() const + { return statements ? statements->lastSourceLocation() : colonToken; } + +// attributes + ExpressionNode *expression; + StatementList *statements; + SourceLocation caseToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT CaseClauses: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return clause->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : clause->lastSourceLocation(); } + + inline CaseClauses *finish () + { + CaseClauses *front = next; + next = 0; + return front; + } + +//attributes + CaseClause *clause; + CaseClauses *next; +}; + +class QML_PARSER_EXPORT DefaultClause: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(DefaultClause) + + DefaultClause(StatementList *slist): + statements (slist) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return defaultToken; } + + virtual SourceLocation lastSourceLocation() const + { return statements ? statements->lastSourceLocation() : colonToken; } + +// attributes + StatementList *statements; + SourceLocation defaultToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT LabelledStatement: public Statement +{ +public: + QQMLJS_DECLARE_AST_NODE(LabelledStatement) + + LabelledStatement(const QStringRef &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 + QStringRef label; + Statement *statement; + SourceLocation identifierToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT ThrowStatement: public Statement +{ +public: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(Catch) + + Catch(const QStringRef &n, Block *stmt): + name (n), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return catchToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + QStringRef name; + Block *statement; + SourceLocation catchToken; + SourceLocation lparenToken; + SourceLocation identifierToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT Finally: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(Finally) + + Finally(Block *stmt): + statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return finallyToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement ? statement->lastSourceLocation() : finallyToken; } + +// attributes + Block *statement; + SourceLocation finallyToken; +}; + +class QML_PARSER_EXPORT TryStatement: public Statement +{ +public: + QQMLJS_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: + QQMLJS_DECLARE_AST_NODE(FunctionExpression) + + FunctionExpression(const QStringRef &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 + QStringRef 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: + QQMLJS_DECLARE_AST_NODE(FunctionDeclaration) + + FunctionDeclaration(const QStringRef &n, FormalParameterList *f, FunctionBody *b): + FunctionExpression(n, f, b) + { kind = K; } + + virtual void accept0(Visitor *visitor); +}; + +class QML_PARSER_EXPORT FormalParameterList: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(FormalParameterList) + + FormalParameterList(const QStringRef &n): + name (n), next (this) + { kind = K; } + + FormalParameterList(FormalParameterList *previous, const QStringRef &n): + name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : identifierToken; } + + inline FormalParameterList *finish () + { + FormalParameterList *front = next; + next = 0; + return front; + } + +// attributes + QStringRef name; + FormalParameterList *next; + SourceLocation commaToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT SourceElement: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(SourceElement) + + inline SourceElement() + { kind = K; } +}; + +class QML_PARSER_EXPORT SourceElements: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return element->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : element->lastSourceLocation(); } + + inline SourceElements *finish () + { + SourceElements *front = next; + next = 0; + return front; + } + +// attributes + SourceElement *element; + SourceElements *next; +}; + +class QML_PARSER_EXPORT FunctionBody: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(FunctionBody) + + FunctionBody(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return elements ? elements->firstSourceLocation() : SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return elements ? elements->lastSourceLocation() : SourceLocation(); } + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT Program: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(Program) + + Program(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return elements ? elements->firstSourceLocation() : SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return elements ? elements->lastSourceLocation() : SourceLocation(); } + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement +{ +public: + QQMLJS_DECLARE_AST_NODE(FunctionSourceElement) + + FunctionSourceElement(FunctionDeclaration *f): + declaration (f) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return declaration->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return declaration->lastSourceLocation(); } + +// attributes + FunctionDeclaration *declaration; +}; + +class QML_PARSER_EXPORT StatementSourceElement: public SourceElement +{ +public: + QQMLJS_DECLARE_AST_NODE(StatementSourceElement) + + StatementSourceElement(Statement *stmt): + statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return statement->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + Statement *statement; +}; + +class QML_PARSER_EXPORT DebuggerStatement: public Statement +{ +public: + QQMLJS_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 UiQualifiedId: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiQualifiedId) + + UiQualifiedId(const QStringRef &name) + : next(this), name(name) + { kind = K; } + + UiQualifiedId(UiQualifiedId *previous, const QStringRef &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); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : identifierToken; } + +// attributes + UiQualifiedId *next; + QStringRef name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiImport: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiImport) + + UiImport(const QStringRef &fileName) + : fileName(fileName), importUri(0) + { kind = K; } + + UiImport(UiQualifiedId *uri) + : importUri(uri) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return importToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + QStringRef fileName; + UiQualifiedId *importUri; + QStringRef importId; + SourceLocation importToken; + SourceLocation fileNameToken; + SourceLocation versionToken; + SourceLocation asToken; + SourceLocation importIdToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiImportList: public Node +{ +public: + QQMLJS_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; + } + + UiImportList *finish() + { + UiImportList *head = next; + next = 0; + return head; + } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return import->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : import->lastSourceLocation(); } + +// 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: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return member->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : member->lastSourceLocation(); } + + UiObjectMemberList *finish() + { + UiObjectMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiObjectMemberList *next; + UiObjectMember *member; +}; + +class QML_PARSER_EXPORT UiProgram: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiProgram) + + UiProgram(UiImportList *imports, UiObjectMemberList *members) + : imports(imports), members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { + if (imports) + return imports->firstSourceLocation(); + else if (members) + return members->firstSourceLocation(); + return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (members) + return members->lastSourceLocation(); + else if (imports) + return imports->lastSourceLocation(); + return SourceLocation(); + } + +// attributes + UiImportList *imports; + UiObjectMemberList *members; +}; + +class QML_PARSER_EXPORT UiArrayMemberList: public Node +{ +public: + QQMLJS_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); + + virtual SourceLocation firstSourceLocation() const + { return member->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : member->lastSourceLocation(); } + + UiArrayMemberList *finish() + { + UiArrayMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiArrayMemberList *next; + UiObjectMember *member; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT UiObjectInitializer: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiObjectInitializer) + + UiObjectInitializer(UiObjectMemberList *members) + : members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + SourceLocation lbraceToken; + UiObjectMemberList *members; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT UiParameterList: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiParameterList) + + UiParameterList(const QStringRef &t, const QStringRef &n): + type (t), name (n), next (this) + { kind = K; } + + UiParameterList(UiParameterList *previous, const QStringRef &t, const QStringRef &n): + type (t), name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *) {} + + virtual SourceLocation firstSourceLocation() const + { return propertyTypeToken; } + + virtual SourceLocation lastSourceLocation() const + { return next ? next->lastSourceLocation() : identifierToken; } + + inline UiParameterList *finish () + { + UiParameterList *front = next; + next = 0; + return front; + } + +// attributes + QStringRef type; + QStringRef name; + UiParameterList *next; + SourceLocation commaToken; + SourceLocation propertyTypeToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember +{ +public: + QQMLJS_DECLARE_AST_NODE(UiPublicMember) + + UiPublicMember(const QStringRef &memberType, + const QStringRef &name) + : type(Property), memberType(memberType), name(name), statement(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + UiPublicMember(const QStringRef &memberType, + const QStringRef &name, + Statement *statement) + : type(Property), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + 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(); + if (statement) + return statement->lastSourceLocation(); + + return semicolonToken; + } + +// attributes + enum { Signal, Property } type; + QStringRef typeModifier; + QStringRef memberType; + QStringRef 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: + QQMLJS_DECLARE_AST_NODE(UiObjectDefinition) + + UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return qualifiedTypeNameId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return initializer->rbraceToken; } + +// attributes + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; +}; + +class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember +{ +public: + QQMLJS_DECLARE_AST_NODE(UiSourceElement) + + UiSourceElement(Node *sourceElement) + : sourceElement(sourceElement) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast(sourceElement)) + return funDecl->firstSourceLocation(); + else if (VariableStatement *varStmt = cast(sourceElement)) + return varStmt->firstSourceLocation(); + + return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast(sourceElement)) + return funDecl->lastSourceLocation(); + else if (VariableStatement *varStmt = cast(sourceElement)) + return varStmt->lastSourceLocation(); + + return SourceLocation(); + } + + virtual void accept0(Visitor *visitor); + + +// attributes + Node *sourceElement; +}; + +class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember +{ +public: + QQMLJS_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: + QQMLJS_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: + QQMLJS_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/qml/qml/parser/qqmljsastfwd_p.h b/src/qml/qml/parser/qqmljsastfwd_p.h new file mode 100644 index 0000000000..dec1cbc599 --- /dev/null +++ b/src/qml/qml/parser/qqmljsastfwd_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSAST_FWD_P_H +#define QQMLJSAST_FWD_P_H + +#include "qqmljsglobal_p.h" + +#include + +// +// 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 QQmlJS { 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; + +} } // namespace AST + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/qml/qml/parser/qqmljsastvisitor.cpp b/src/qml/qml/parser/qqmljsastvisitor.cpp new file mode 100644 index 0000000000..2d854dc735 --- /dev/null +++ b/src/qml/qml/parser/qqmljsastvisitor.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmljsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { namespace AST { + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +} } // namespace QQmlJS::AST + +QT_QML_END_NAMESPACE diff --git a/src/qml/qml/parser/qqmljsastvisitor_p.h b/src/qml/qml/parser/qqmljsastvisitor_p.h new file mode 100644 index 0000000000..991580309d --- /dev/null +++ b/src/qml/qml/parser/qqmljsastvisitor_p.h @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSASTVISITOR_P_H +#define QQMLJSASTVISITOR_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 "qqmljsastfwd_p.h" +#include "qqmljsglobal_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { 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 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 *) {} + + // QQmlJS + 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 // QQMLJSASTVISITOR_P_H diff --git a/src/qml/qml/parser/qqmljsengine_p.cpp b/src/qml/qml/parser/qqmljsengine_p.cpp new file mode 100644 index 0000000000..459ba8d7dc --- /dev/null +++ b/src/qml/qml/parser/qqmljsengine_p.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmljsengine_p.h" +#include "qqmljsglobal_p.h" + +#include +#include +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +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) +{ } + +Engine::~Engine() +{ } + +void Engine::setCode(const QString &code) +{ _code = code; } + +void Engine::addComment(int pos, int len, int line, int col) +{ if (len > 0) _comments.append(QQmlJS::AST::SourceLocation(pos, len, line, col)); } + +QList Engine::comments() const +{ return _comments; } + +Lexer *Engine::lexer() const +{ return _lexer; } + +void Engine::setLexer(Lexer *lexer) +{ _lexer = lexer; } + +MemoryPool *Engine::pool() +{ return &_pool; } + +QStringRef Engine::newStringRef(const QString &text) +{ + const int pos = _extraCode.length(); + _extraCode += text; + return _extraCode.midRef(pos, text.length()); +} + +QStringRef Engine::newStringRef(const QChar *chars, int size) +{ return newStringRef(QString(chars, size)); } + +} // end of namespace QQmlJS + +QT_QML_END_NAMESPACE diff --git a/src/qml/qml/parser/qqmljsengine_p.h b/src/qml/qml/parser/qqmljsengine_p.h new file mode 100644 index 0000000000..3cb78de4eb --- /dev/null +++ b/src/qml/qml/parser/qqmljsengine_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSENGINE_P_H +#define QQMLJSENGINE_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 "qqmljsglobal_p.h" +#include "qqmljsastfwd_p.h" +#include "qqmljsmemorypool_p.h" + +#include +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +class Lexer; +class MemoryPool; + +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; + MemoryPool _pool; + QList _comments; + QString _extraCode; + QString _code; + +public: + Engine(); + ~Engine(); + + void setCode(const QString &code); + + void addComment(int pos, int len, int line, int col); + QList comments() const; + + Lexer *lexer() const; + void setLexer(Lexer *lexer); + + MemoryPool *pool(); + + inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); } + + QStringRef newStringRef(const QString &s); + QStringRef newStringRef(const QChar *chars, int size); +}; + +double integerFromString(const char *buf, int size, int radix); + +} // end of namespace QQmlJS + +QT_QML_END_NAMESPACE + +#endif // QQMLJSENGINE_P_H diff --git a/src/qml/qml/parser/qqmljsglobal_p.h b/src/qml/qml/parser/qqmljsglobal_p.h new file mode 100644 index 0000000000..81c90310ad --- /dev/null +++ b/src/qml/qml/parser/qqmljsglobal_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQMLJSGLOBAL_P_H +#define QQMLJSGLOBAL_P_H + +#include + +#ifdef QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE + +# ifdef QDECLARATIVEJS_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 // QQMLJS_BUILD_DIR + +#else // !QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE QT_END_NAMESPACE +# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) + // QmlDevTools is a static library +# define QML_PARSER_EXPORT +# else +# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT +# endif +#endif // QT_CREATOR + +#endif // QQMLJSGLOBAL_P_H diff --git a/src/qml/qml/parser/qqmljsgrammar.cpp b/src/qml/qml/parser/qqmljsgrammar.cpp new file mode 100644 index 0000000000..f69f809ee3 --- /dev/null +++ b/src/qml/qml/parser/qqmljsgrammar.cpp @@ -0,0 +1,1013 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! +#include "qqmljsgrammar_p.h" + +QT_BEGIN_NAMESPACE + +const char *const QQmlJSGrammar::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, 0}; + +const short QQmlJSGrammar::lhs [] = { + 102, 102, 102, 102, 102, 102, 103, 109, 109, 112, + 112, 114, 113, 113, 113, 113, 113, 113, 113, 113, + 116, 111, 110, 119, 119, 120, 120, 121, 121, 118, + 107, 107, 107, 107, 123, 123, 123, 123, 123, 123, + 123, 107, 131, 131, 131, 132, 132, 133, 133, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 117, 117, 117, 117, + 117, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 122, + 138, 138, 138, 138, 137, 137, 140, 140, 142, 142, + 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 144, 144, 115, 115, 115, + 115, 115, 147, 147, 148, 148, 148, 148, 146, 146, + 149, 149, 150, 150, 151, 151, 151, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 153, 153, 153, + 153, 154, 154, 154, 155, 155, 155, 155, 156, 156, + 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, + 157, 158, 158, 158, 158, 158, 159, 159, 159, 159, + 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, + 164, 165, 165, 166, 166, 167, 167, 168, 168, 169, + 169, 170, 170, 171, 171, 141, 141, 172, 172, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 105, 105, 174, 174, 175, 175, 176, 176, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 124, 185, 185, 184, 184, 135, + 135, 186, 186, 187, 187, 189, 189, 188, 190, 193, + 191, 191, 194, 192, 192, 125, 126, 126, 127, 127, + 177, 177, 177, 177, 177, 177, 177, 178, 178, 178, + 178, 179, 179, 179, 179, 180, 180, 128, 129, 195, + 195, 198, 198, 196, 196, 199, 197, 181, 181, 181, + 182, 182, 130, 130, 130, 200, 201, 183, 183, 134, + 145, 205, 205, 202, 202, 203, 203, 206, 108, 108, + 207, 207, 106, 106, 204, 204, 139, 139, 208}; + +const short QQmlJSGrammar::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, 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, + 1, 2, 1, 1, 0, 1, 0, 1, 2}; + +const short QQmlJSGrammar::action_default [] = { + 0, 0, 22, 0, 0, 0, 22, 0, 175, 242, + 206, 214, 210, 154, 226, 202, 3, 139, 73, 155, + 218, 222, 143, 172, 153, 158, 138, 192, 179, 0, + 80, 81, 76, 345, 67, 347, 0, 0, 0, 0, + 78, 0, 0, 74, 77, 71, 0, 0, 68, 70, + 69, 79, 72, 0, 75, 0, 0, 168, 0, 0, + 155, 174, 157, 156, 0, 0, 0, 170, 171, 169, + 173, 0, 203, 0, 0, 0, 0, 193, 0, 0, + 0, 0, 0, 0, 183, 0, 0, 0, 177, 178, + 176, 181, 185, 184, 182, 180, 195, 194, 196, 0, + 211, 0, 207, 0, 0, 149, 136, 148, 137, 105, + 106, 107, 132, 108, 133, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 134, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 135, + 0, 0, 147, 243, 150, 0, 151, 0, 152, 146, + 0, 239, 232, 230, 237, 238, 236, 235, 241, 234, + 233, 231, 240, 227, 0, 215, 0, 0, 219, 0, + 0, 223, 0, 0, 149, 141, 0, 140, 0, 145, + 159, 0, 346, 334, 335, 0, 332, 0, 333, 0, + 336, 250, 257, 256, 264, 252, 0, 253, 337, 0, + 344, 254, 255, 260, 258, 341, 338, 343, 261, 0, + 272, 0, 0, 0, 0, 345, 67, 0, 347, 68, + 244, 286, 69, 0, 0, 0, 273, 0, 0, 262, + 263, 0, 251, 259, 287, 288, 331, 342, 0, 302, + 303, 304, 305, 0, 298, 299, 300, 301, 328, 329, + 0, 0, 0, 0, 0, 291, 292, 248, 246, 208, + 216, 212, 228, 204, 249, 0, 155, 220, 224, 197, + 186, 0, 0, 205, 0, 0, 0, 0, 198, 0, + 0, 0, 0, 0, 190, 188, 191, 189, 187, 200, + 199, 201, 0, 213, 0, 209, 0, 247, 155, 0, + 229, 244, 245, 0, 244, 0, 0, 294, 0, 0, + 0, 296, 0, 217, 0, 0, 221, 0, 0, 225, + 284, 0, 276, 285, 279, 0, 283, 0, 244, 277, + 0, 244, 0, 0, 295, 0, 0, 0, 297, 346, + 334, 0, 0, 336, 0, 330, 0, 320, 0, 0, + 0, 290, 0, 289, 0, 348, 0, 104, 266, 269, + 0, 105, 272, 108, 133, 110, 111, 76, 115, 116, + 67, 117, 120, 74, 77, 68, 244, 69, 79, 123, + 72, 125, 75, 127, 128, 273, 130, 131, 135, 0, + 97, 0, 0, 99, 103, 101, 88, 100, 102, 0, + 98, 87, 267, 265, 143, 144, 149, 0, 142, 0, + 319, 0, 306, 307, 0, 318, 0, 0, 0, 309, + 314, 312, 315, 0, 0, 313, 314, 0, 310, 0, + 311, 268, 317, 0, 268, 316, 0, 321, 322, 0, + 268, 323, 324, 0, 0, 325, 0, 0, 0, 326, + 327, 161, 160, 0, 0, 0, 293, 0, 0, 0, + 308, 281, 274, 0, 282, 278, 0, 280, 270, 0, + 271, 275, 91, 0, 0, 95, 82, 0, 84, 93, + 0, 85, 94, 96, 86, 92, 83, 0, 89, 165, + 163, 167, 164, 162, 166, 339, 6, 340, 4, 2, + 65, 90, 0, 0, 68, 70, 69, 31, 5, 0, + 66, 0, 45, 44, 43, 0, 0, 58, 0, 59, + 35, 36, 37, 38, 40, 41, 62, 39, 0, 45, + 0, 0, 0, 0, 0, 54, 0, 55, 0, 0, + 26, 0, 0, 63, 27, 0, 30, 28, 24, 0, + 29, 25, 0, 56, 0, 57, 143, 0, 60, 64, + 0, 0, 0, 0, 61, 0, 52, 46, 53, 47, + 0, 0, 0, 0, 49, 0, 50, 51, 48, 0, + 0, 143, 268, 0, 0, 42, 105, 272, 108, 133, + 110, 111, 76, 115, 116, 67, 117, 120, 74, 77, + 68, 244, 69, 79, 123, 72, 125, 75, 127, 128, + 273, 130, 131, 135, 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, 349}; + +const short QQmlJSGrammar::goto_default [] = { + 7, 625, 207, 196, 205, 508, 496, 624, 643, 495, + 623, 621, 626, 22, 622, 18, 507, 549, 539, 546, + 541, 526, 191, 195, 197, 201, 233, 208, 230, 530, + 570, 569, 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, 203, + 229, 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 QQmlJSGrammar::action_index [] = { + 404, 1275, 2411, 2411, 2509, 1000, 68, 92, 90, -102, + 88, 62, 60, 256, -102, 298, 86, -102, -102, 638, + 83, 134, 172, 219, -102, -102, -102, 454, 194, 1275, + -102, -102, -102, 381, -102, 2215, 1555, 1275, 1275, 1275, + -102, 790, 1275, -102, -102, -102, 1275, 1275, -102, -102, + -102, -102, -102, 1275, -102, 1275, 1275, -102, 1275, 1275, + 102, 217, -102, -102, 1275, 1275, 1275, -102, -102, -102, + 204, 1275, 304, 1275, 1275, 1275, 1275, 539, 1275, 1275, + 1275, 1275, 1275, 1275, 308, 1275, 1275, 1275, 103, 131, + 135, 308, 210, 225, 216, 308, 444, 390, 434, 1275, + 82, 1275, 100, 2117, 1275, 1275, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + 139, 1275, -102, -102, 91, 10, -102, 1275, -102, -102, + 1275, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, 1275, 26, 1275, 1275, 69, 66, + 1275, -102, 2117, 1275, 1275, -102, 97, -102, 44, -102, + -102, 67, -102, 297, 78, 24, -102, 291, -102, 36, + 2411, -102, -102, -102, -102, -102, 234, -102, -102, 12, + -102, -102, -102, -102, -102, -102, 2411, -102, -102, 464, + -102, 461, 115, 2509, 42, 381, 58, 46, 2705, 70, + 1275, -102, 74, 57, 1275, 65, -102, 59, 61, -102, + -102, 367, -102, -102, -102, -102, -102, -102, 106, -102, + -102, -102, -102, 87, -102, -102, -102, -102, -102, -102, + 56, 55, 1275, 99, 84, -102, -102, 1461, -102, 75, + 48, 52, -102, 306, 72, 53, 579, 77, 110, 370, + 230, 381, 1275, 286, 1275, 1275, 1275, 1275, 380, 1275, + 1275, 1275, 1275, 1275, 184, 169, 166, 190, 198, 460, + 363, 353, 1275, 50, 1275, 63, 1275, -102, 638, 1275, + -102, 1275, 64, 39, 1275, 30, 2509, -102, 1275, 173, + 2509, -102, 1275, 79, 1275, 1275, 81, 80, 1275, -102, + 71, 149, 32, -102, -102, 1275, -102, 381, 1275, -102, + 73, 1275, 76, 2509, -102, 1275, 142, 2509, -102, -16, + 381, -42, -12, 2411, -39, -102, 2509, -102, 1275, 154, + 2509, 14, 2509, -102, 20, 16, -32, -102, -102, 2509, + -51, 519, -4, 511, 136, 1275, 2509, -2, -35, 395, + -1, -27, 908, 4, 6, -102, 1370, -102, 0, -36, + 27, 1275, 47, 22, 1275, 45, 1275, 21, 17, 1275, + -102, 2313, 144, -102, -102, -102, -102, -102, -102, 1275, + -102, -102, -102, -102, 274, -102, 1275, -21, -102, 2509, + -102, 138, -102, -102, 2509, -102, 1275, 132, 5, -102, + 40, -102, 41, 101, 1275, -102, 38, 34, -102, -38, + -102, 2509, -102, 105, 2509, -102, 245, -102, -102, 96, + 2509, 11, -102, -7, -11, -102, 352, 8, 18, -102, + -102, -102, -102, 1275, 129, 2509, -102, 1275, 130, 2509, + -102, 49, -102, 226, -102, -102, 1275, -102, -102, 362, + -102, -102, -102, 107, 1837, -102, -102, 1649, -102, -102, + 1743, -102, -102, -102, -102, -102, -102, 114, -102, -102, + -102, -102, -102, -102, -102, -102, -102, 2411, -102, -102, + -102, 94, 9, 818, 189, -10, 31, -102, -102, 223, + -102, 191, -102, -102, -102, 300, 178, -102, 1928, -102, + -102, -102, -102, -102, -102, -102, -102, -102, 257, -25, + 381, 195, -22, 305, 240, -102, -6, -102, 818, 127, + -102, -18, 818, -102, -102, 1184, -102, -102, -102, 1092, + -102, -102, 237, -102, 1928, -102, 294, -8, -102, -102, + 176, 381, 19, 1928, -102, 165, -102, 174, -102, 2, + -52, 381, 183, 381, -102, 117, -102, -102, -102, 2019, + 880, 285, 2607, 1555, 3, -102, 522, 35, 453, 108, + 1275, 2509, 51, 23, 475, 54, -17, 700, 7, 43, + -102, 1370, -102, 28, -3, 33, 1275, 37, 15, 1275, + 25, 1275, 1, 13, 124, -102, -102, 29, -102, -102, + 728, -102, 250, -43, 627, -102, -102, 231, 372, -102, + 222, -102, 111, -102, -102, 381, -102, -102, 104, -102, + -102, -102, -102, -102, -102, + + -107, 9, -103, 2, 5, 266, 1, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -39, + -107, -107, -107, -107, -107, -107, -107, -107, -107, 86, + -107, -107, -107, 8, -107, -107, -22, 19, 71, 174, + -107, 186, 171, -107, -107, -107, 184, 178, -107, -107, + -107, -107, -107, 144, -107, 124, 150, -107, 165, 161, + -107, -107, -107, -107, 156, 160, 157, -107, -107, -107, + -107, 147, -107, 142, 135, 179, 166, -107, 177, 170, + 117, 72, 134, 92, -107, 75, 94, 66, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, 181, + -107, 106, -107, 143, 78, 55, -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, -5, -107, -107, -107, -107, -107, 54, -107, -107, + 51, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, 114, -107, 113, 38, -107, -107, + 41, -107, 231, 63, 112, -107, -107, -107, -107, -107, + -107, -107, -107, 30, -107, -107, -107, 52, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, 36, -107, -107, 45, + -107, 42, -107, 40, -107, 80, -107, -107, 77, -107, + 88, -107, -107, -107, 83, 74, -107, -107, -107, -107, + -107, -10, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, 23, -107, -107, -107, -107, 100, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, 4, 223, -107, 230, 236, 222, 205, -107, 127, + 125, 115, 96, 102, -107, -107, -107, -107, -107, -107, + -107, -107, 234, -107, 215, -107, 199, -107, -107, 197, + -107, 190, -107, -107, 163, -107, 90, -107, 0, -107, + -1, -107, 203, -107, 189, 211, -107, -107, 195, -107, + -107, -107, -107, -107, -107, 191, -107, 98, 119, -107, + -107, 95, -107, 81, -107, 79, -107, 82, -107, -107, + 101, -107, -107, -16, -107, -107, 53, -107, 46, -107, + 57, -107, 59, -107, -107, -107, -107, -107, -107, 35, + -107, 33, -107, 39, -107, 89, 67, -107, -107, 58, + -107, -107, 84, -107, -107, -107, 73, -107, -107, -107, + -107, 65, -107, 43, 93, -107, 109, -107, -107, 49, + -107, 47, -107, -107, -107, -107, -107, -107, -107, 50, + -107, -107, -107, -107, -107, -107, 108, -107, -107, 61, + -107, -107, -107, -107, 62, -107, 68, -107, -107, -107, + -107, -107, -23, -107, 69, -107, -19, -107, -107, -107, + -107, 97, -107, -107, 99, -107, -107, -107, -107, -107, + 60, -61, -107, -107, 34, -107, 37, -107, 29, -107, + -107, -107, -107, 32, -107, 76, -107, 44, -107, 56, + -107, -107, -107, -107, -107, -107, 31, -107, -107, 116, + -107, -107, -107, -107, -6, -107, -107, 70, -107, -107, + 64, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, 193, -107, -107, + -107, -107, -107, 7, -107, -107, -107, -107, -107, -107, + -107, -20, -107, -107, -107, -7, -107, -107, 290, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -2, -25, -107, -15, -107, -107, -107, -107, 172, -107, + -107, -107, 287, -107, -107, 288, -107, -107, -107, 291, + -107, -107, -107, -107, 336, -107, -107, 20, -107, -107, + 15, 3, -107, 304, -107, -107, -107, 24, -107, -107, + -107, 28, 21, 26, -107, -107, -107, -107, -107, 320, + 104, -107, 13, 381, -3, -107, 6, -107, 10, -107, + 167, 22, -107, -107, 12, -107, -107, 87, -107, -107, + -107, 25, -107, -107, -107, -107, 11, -107, 14, 85, + -107, 121, -107, -107, -107, -107, -107, 27, -107, -107, + 17, -107, -107, 18, 91, -107, -107, -107, 16, -107, + -107, -107, -107, -107, -107, -4, -107, -107, -107, -107, + -107, -107, -107, -107, -107}; + +const short QQmlJSGrammar::action_info [] = { + 416, 257, 533, -132, 403, -113, 346, -102, 575, 348, + 572, -121, 531, -103, -121, 545, 345, 430, 342, 348, + 340, 343, 440, 401, 391, 545, 563, 389, 538, 446, + 352, 444, -129, 416, -124, -102, 545, 453, 420, 408, + -124, 431, -132, 424, -126, 424, 424, 620, 440, 457, + -103, 440, -129, 457, -126, 440, 560, 453, -113, 257, + 565, 346, 545, 335, 272, 346, 466, 236, 448, 190, + 149, 164, 141, 170, 99, 511, 272, 409, 257, 312, + 296, 414, 348, 312, 189, 164, 187, 318, 325, 71, + 306, 252, 644, 416, 141, 453, 292, 457, 440, 147, + 304, 71, 443, 183, 179, 141, 0, 141, 0, 172, + 99, 427, 434, 141, 301, 477, 444, 0, 0, 0, + 0, 0, 141, 0, 0, 0, 0, 292, 173, 294, + 58, 294, 542, 251, 331, 542, 333, 141, 141, 101, + 141, 59, 0, 58, 62, 256, 255, 141, 247, 246, + 141, 399, 0, 177, 59, 63, 428, 327, 620, 254, + 314, 101, 141, 478, 315, 640, 639, 242, 241, 249, + 248, 58, 634, 633, 488, 58, 249, 248, 577, 576, + 615, 141, 59, 543, 166, 518, 59, 172, 167, 455, + 459, 85, 418, 86, 85, 142, 86, 249, 248, 413, + 412, 567, 337, 512, 87, 512, 173, 87, 174, 85, + 328, 86, 512, 0, 350, 85, 64, 86, 529, 85, + 512, 86, 87, 85, 512, 86, 568, 566, 87, 64, + 579, 64, 87, 310, 469, 85, 87, 86, 0, 519, + 517, 85, 141, 86, 554, 0, 172, 536, 87, 514, + 85, 514, 86, 141, 87, 85, 545, 86, 514, 0, + 513, 65, 513, 87, 514, 173, 514, 66, 87, 513, + 514, 103, 172, 0, 65, 513, 65, 513, 0, 0, + 66, 513, 66, 637, 636, 0, 0, 470, 468, 172, + 104, 173, 105, 406, 0, 235, 234, 630, 555, 553, + 172, 537, 535, 0, 274, 275, 438, 437, 173, 172, + 406, 631, 629, 635, 0, 580, 73, 74, -90, 173, + 34, 174, 73, 74, 274, 275, 34, -90, 173, 34, + 174, 276, 277, 85, 34, 86, 0, 0, 0, 0, + 0, 628, 0, 75, 76, 0, 87, 0, 0, 75, + 76, 276, 277, 0, 0, 0, 0, 48, 50, 49, + 0, 0, 0, 48, 50, 49, 48, 50, 49, 0, + 0, 48, 50, 49, 0, 0, 279, 280, 0, 0, + 0, 34, 0, 45, 0, 281, 279, 280, 282, 45, + 283, 34, 45, 279, 280, 281, 34, 45, 282, 0, + 283, 34, 281, 279, 280, 282, 0, 283, 0, 0, + 34, 0, 281, 78, 79, 282, 0, 283, 48, 50, + 49, 80, 81, 0, 34, 82, 0, 83, 48, 50, + 49, -345, 0, 48, 50, 49, 0, 0, 48, 50, + 49, 0, 0, 0, 45, 0, 0, 48, 50, 49, + 0, 0, 0, 0, 45, 0, 0, 78, 79, 45, + 0, 48, 50, 49, 45, 80, 81, 78, 79, 82, + 0, 83, 0, 45, 0, 80, 81, 78, 79, 82, + 0, 83, 34, 279, 280, 80, 81, 45, 0, 82, + 34, 83, 281, 34, 0, 282, 0, 283, 6, 5, + 4, 1, 3, 2, 34, 0, 0, 0, 0, 0, + 0, -345, 0, 0, 245, 244, 0, 0, 0, 48, + 50, 49, 245, 244, 0, 240, 239, 48, 50, 49, + 48, 50, 49, 0, 0, 0, 0, 0, 0, 0, + 34, 48, 50, 49, 0, 45, 0, 0, 34, 0, + 0, 34, 0, 45, 0, 0, 45, 0, 0, 0, + 0, 0, 78, 79, 0, 0, 0, 45, 0, 0, + 80, 81, 245, 244, 82, 0, 83, 48, 50, 49, + 240, 239, 151, 240, 239, 48, 50, 49, 48, 50, + 49, 0, 152, 0, 0, 0, 153, 0, 0, 0, + 0, 0, 0, 45, 0, 154, 0, 155, 0, 0, + 308, 45, 0, 0, 45, 0, 0, 0, 156, 0, + 157, 62, 0, 0, 0, 0, 0, 0, 158, 0, + 0, 159, 63, 0, 0, 0, 0, 160, 0, 30, + 31, 151, 0, 161, 0, 0, 0, 0, 0, 33, + 0, 152, 0, 0, 0, 153, 34, 0, 0, 162, + 35, 36, 0, 37, 154, 0, 155, 0, 0, 0, + 503, 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, 0, 30, 31, 40, 0, 0, 0, 162, 45, + 0, 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, 503, 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, 30, 31, 0, 0, 0, 0, 0, 43, + 54, 32, 33, 0, 0, 40, 0, 0, 0, 34, + 45, 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, 503, 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, 30, 31, 0, 0, 0, 0, 0, 43, + 54, 32, 33, 0, 0, 40, 0, 0, 0, 34, + 45, 0, 0, 35, 36, 0, 37, 0, 0, 0, + 30, 31, 0, 503, 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, 41, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 502, 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, 503, 0, 0, 0, 44, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 51, 504, 506, 505, 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, 0, 502, 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, 503, 0, 0, 0, 44, + 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 51, 504, 506, + 505, 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, 0, 502, 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, 503, 0, 0, + 0, 44, 0, 0, 0, 0, 0, 0, 0, 547, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, + 504, 506, 505, 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, 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, 0, -122, 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, 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, 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, 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, + 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, 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, 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, 223, 52, 0, + 53, 225, 55, 0, 56, 0, 228, 0, 0, 43, + 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, + 45, 0, 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, 582, 583, 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, 223, 52, + 0, 53, 225, 55, 0, 56, 0, 228, 0, 0, + 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, + 0, 45, 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, 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, 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, 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, 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, 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, + 0, 586, 110, 111, 0, 0, 588, 115, 590, 30, + 31, 591, 0, 118, 0, 0, 0, 120, 593, 594, + 0, 0, 0, 0, 0, 0, 595, 596, 124, 125, + 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, + 597, 42, 0, 0, 599, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 601, 0, 221, 0, + 0, 0, 603, 600, 602, 49, 604, 605, 606, 53, + 608, 609, 610, 611, 612, 613, 0, 0, 598, 607, + 592, 587, 589, 128, 40, 0, 0, 0, 0, 45, + 0, 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, + -268, 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, 0, + + 534, 311, 497, 309, 532, 461, 498, 499, 516, 515, + 619, 638, 16, 552, 436, 358, 616, 472, 562, 320, + 528, 238, 487, 182, 250, 243, 253, 182, 302, 641, + 627, 632, 150, 485, 143, 454, 439, 402, 445, 559, + 237, 574, 250, 578, 561, 186, 618, 458, 238, 349, + 573, 449, 447, 571, 243, 347, 450, 243, 460, 351, + 238, 353, 358, 410, 415, 439, 176, 188, 436, 250, + 467, 417, 433, 182, 425, 429, 302, 169, 456, 358, + 171, 140, 336, 334, 338, 344, 436, 392, 390, 400, + 163, 302, 307, 148, 146, 339, 439, 404, 302, 358, + 404, 358, 0, 482, 501, 480, 0, 642, 0, 479, + 0, 0, 0, 320, 60, 0, 186, 501, 90, 60, + 60, 489, 302, 60, 617, 93, 0, 88, 0, 405, + 0, 461, 405, 60, 60, 451, 180, 60, 0, 180, + 60, 60, 60, 451, 60, 95, 89, 146, 266, 287, + 60, 146, 407, 270, 60, 288, 178, 60, 106, 452, + 0, 60, 60, 60, 102, 60, 302, 332, 286, 60, + 92, 452, 60, 60, 451, 60, 165, 168, 285, 432, + 284, 435, 60, 60, 108, 501, 329, 94, 540, 96, + 60, 330, 60, 302, 494, 60, 77, 237, 60, 404, + 452, 341, 471, 72, 60, 60, 67, 69, 60, 60, + 68, 0, 70, 60, 60, 60, 61, 180, 60, 60, + 98, 491, 60, 91, 490, 60, 60, 60, 493, 60, + 84, 405, 60, 97, 492, 305, 0, 60, 0, 298, + 0, 100, 270, 298, 270, 298, 106, 298, 270, 0, + 270, 60, 270, 60, 316, 0, 270, 0, 270, 298, + 291, 326, 303, 60, 270, 319, 313, 300, 270, 297, + 60, 60, 108, 175, 295, 270, 270, 290, 60, 501, + 273, 317, 60, 270, 60, 278, 509, 270, 0, 270, + 0, 289, 0, 548, 0, 293, 551, 0, 500, 510, + 501, 501, 0, 544, 501, 0, 0, 0, 509, 0, + 0, 509, 520, 521, 522, 523, 527, 524, 525, 0, + 500, 510, 0, 500, 510, 564, 520, 521, 522, 523, + 527, 524, 525, 581, 0, 0, 0, 0, 0, 0, + 584, 585, 520, 521, 522, 523, 527, 524, 525, 556, + 0, 0, 0, 0, 0, 0, 557, 558, 520, 521, + 522, 523, 527, 524, 525, 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, 556, 0, 0, 540, 0, 614, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 472, 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 QQmlJSGrammar::action_check [] = { + 36, 36, 24, 7, 55, 7, 7, 7, 60, 36, + 8, 7, 37, 7, 7, 33, 55, 55, 60, 36, + 36, 33, 33, 55, 8, 33, 7, 7, 34, 36, + 16, 20, 7, 36, 7, 7, 33, 36, 33, 60, + 7, 7, 7, 5, 7, 5, 5, 90, 33, 36, + 7, 33, 7, 36, 7, 33, 66, 36, 7, 36, + 29, 7, 33, 31, 1, 7, 17, 55, 60, 33, + 60, 2, 8, 7, 48, 66, 1, 7, 36, 2, + 8, 7, 36, 2, 60, 2, 8, 7, 17, 1, + 60, 36, 0, 36, 8, 36, 48, 36, 33, 8, + 61, 1, 6, 36, 60, 8, -1, 8, -1, 15, + 48, 10, 7, 8, 61, 8, 20, -1, -1, -1, + -1, -1, 8, -1, -1, -1, -1, 48, 34, 79, + 40, 79, 8, 77, 61, 8, 60, 8, 8, 79, + 8, 51, -1, 40, 42, 61, 62, 8, 61, 62, + 8, 7, -1, 56, 51, 53, 55, 8, 90, 60, + 50, 79, 8, 56, 54, 61, 62, 61, 62, 61, + 62, 40, 61, 62, 60, 40, 61, 62, 61, 62, + 56, 8, 51, 56, 50, 7, 51, 15, 54, 60, + 60, 25, 60, 27, 25, 56, 27, 61, 62, 61, + 62, 36, 60, 29, 38, 29, 34, 38, 36, 25, + 61, 27, 29, -1, 60, 25, 12, 27, 29, 25, + 29, 27, 38, 25, 29, 27, 61, 62, 38, 12, + 7, 12, 38, 60, 8, 25, 38, 27, -1, 61, + 62, 25, 8, 27, 7, -1, 15, 7, 38, 75, + 25, 75, 27, 8, 38, 25, 33, 27, 75, -1, + 86, 57, 86, 38, 75, 34, 75, 63, 38, 86, + 75, 15, 15, -1, 57, 86, 57, 86, -1, -1, + 63, 86, 63, 61, 62, -1, -1, 61, 62, 15, + 34, 34, 36, 36, -1, 61, 62, 47, 61, 62, + 15, 61, 62, -1, 18, 19, 61, 62, 34, 15, + 36, 61, 62, 91, -1, 92, 18, 19, 33, 34, + 29, 36, 18, 19, 18, 19, 29, 33, 34, 29, + 36, 45, 46, 25, 29, 27, -1, -1, -1, -1, + -1, 91, -1, 45, 46, -1, 38, -1, -1, 45, + 46, 45, 46, -1, -1, -1, -1, 66, 67, 68, + -1, -1, -1, 66, 67, 68, 66, 67, 68, -1, + -1, 66, 67, 68, -1, -1, 23, 24, -1, -1, + -1, 29, -1, 92, -1, 32, 23, 24, 35, 92, + 37, 29, 92, 23, 24, 32, 29, 92, 35, -1, + 37, 29, 32, 23, 24, 35, -1, 37, -1, -1, + 29, -1, 32, 23, 24, 35, -1, 37, 66, 67, + 68, 31, 32, -1, 29, 35, -1, 37, 66, 67, + 68, 36, -1, 66, 67, 68, -1, -1, 66, 67, + 68, -1, -1, -1, 92, -1, -1, 66, 67, 68, + -1, -1, -1, -1, 92, -1, -1, 23, 24, 92, + -1, 66, 67, 68, 92, 31, 32, 23, 24, 35, + -1, 37, -1, 92, -1, 31, 32, 23, 24, 35, + -1, 37, 29, 23, 24, 31, 32, 92, -1, 35, + 29, 37, 32, 29, -1, 35, -1, 37, 94, 95, + 96, 97, 98, 99, 29, -1, -1, -1, -1, -1, + -1, 36, -1, -1, 61, 62, -1, -1, -1, 66, + 67, 68, 61, 62, -1, 61, 62, 66, 67, 68, + 66, 67, 68, -1, -1, -1, -1, -1, -1, -1, + 29, 66, 67, 68, -1, 92, -1, -1, 29, -1, + -1, 29, -1, 92, -1, -1, 92, -1, -1, -1, + -1, -1, 23, 24, -1, -1, -1, 92, -1, -1, + 31, 32, 61, 62, 35, -1, 37, 66, 67, 68, + 61, 62, 3, 61, 62, 66, 67, 68, 66, 67, + 68, -1, 13, -1, -1, -1, 17, -1, -1, -1, + -1, -1, -1, 92, -1, 26, -1, 28, -1, -1, + 31, 92, -1, -1, 92, -1, -1, -1, 39, -1, + 41, 42, -1, -1, -1, -1, -1, -1, 49, -1, + -1, 52, 53, -1, -1, -1, -1, 58, -1, 12, + 13, 3, -1, 64, -1, -1, -1, -1, -1, 22, + -1, 13, -1, -1, -1, 17, 29, -1, -1, 80, + 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, -1, 12, 13, 87, -1, -1, -1, 80, 92, + -1, -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, 12, 13, -1, -1, -1, -1, -1, 81, + 82, 83, 22, -1, -1, 87, -1, -1, -1, 29, + 92, -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, 12, 13, -1, -1, -1, -1, -1, 81, + 82, 83, 22, -1, -1, 87, -1, -1, -1, 29, + 92, -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, -1, -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, -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, -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, -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, -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, -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, -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, -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, + -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, -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, -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, 69, 70, -1, + 72, 73, 74, -1, 76, -1, 78, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, + 92, -1, -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, 69, 70, + -1, 72, 73, 74, -1, 76, -1, 78, -1, -1, + 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, + -1, 92, -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, -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, -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, -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, -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, -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, + -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, -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, -1, + + 15, 2, 105, 3, 29, 15, 4, 2, 15, 29, + 9, 15, 3, 15, 3, 2, 19, 39, 15, 15, + 13, 15, 3, 15, 2, 15, 3, 15, 3, 11, + 13, 15, 71, 39, 39, 3, 22, 2, 99, 19, + 4, 15, 2, 15, 29, 15, 19, 3, 15, 3, + 29, 22, 15, 29, 15, 2, 22, 15, 2, 2, + 15, 2, 2, 2, 2, 22, 3, 15, 3, 2, + 39, 3, 3, 15, 97, 94, 3, 39, 2, 2, + 39, 3, 3, 2, 2, 101, 3, 40, 39, 39, + 39, 3, 2, 39, 39, 15, 22, 13, 3, 2, + 13, 2, -1, 39, 13, 35, -1, 16, -1, 39, + -1, -1, -1, 15, 48, -1, 15, 13, 52, 48, + 48, 50, 3, 48, 20, 53, -1, 52, -1, 45, + -1, 15, 45, 48, 48, 50, 50, 48, -1, 50, + 48, 48, 48, 50, 48, 53, 52, 39, 48, 53, + 48, 39, 44, 53, 48, 53, 44, 48, 15, 50, + -1, 48, 48, 48, 58, 48, 3, 72, 53, 48, + 53, 50, 48, 48, 50, 48, 62, 64, 53, 82, + 53, 82, 48, 48, 41, 13, 88, 53, 16, 54, + 48, 72, 48, 3, 50, 48, 54, 4, 48, 13, + 50, 100, 86, 56, 48, 48, 50, 50, 48, 48, + 50, -1, 51, 48, 48, 48, 51, 50, 48, 48, + 54, 50, 48, 53, 50, 48, 48, 48, 50, 48, + 53, 45, 48, 54, 50, 72, -1, 48, -1, 48, + -1, 60, 53, 48, 53, 48, 15, 48, 53, -1, + 53, 48, 53, 48, 65, -1, 53, -1, 53, 48, + 55, 70, 72, 48, 53, 70, 63, 70, 53, 70, + 48, 48, 41, 42, 59, 53, 53, 55, 48, 13, + 57, 70, 48, 53, 48, 55, 20, 53, -1, 53, + -1, 55, -1, 5, -1, 61, 5, -1, 32, 33, + 13, 13, -1, 16, 13, -1, -1, -1, 20, -1, + -1, 20, 22, 23, 24, 25, 26, 27, 28, -1, + 32, 33, -1, 32, 33, 21, 22, 23, 24, 25, + 26, 27, 28, 13, -1, -1, -1, -1, -1, -1, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 13, + -1, -1, -1, -1, -1, -1, 20, 21, 22, 23, + 24, 25, 26, 27, 28, -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, 13, -1, -1, 16, -1, 18, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 39, -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/qml/qml/parser/qqmljsgrammar_p.h b/src/qml/qml/parser/qqmljsgrammar_p.h new file mode 100644 index 0000000000..455391a862 --- /dev/null +++ b/src/qml/qml/parser/qqmljsgrammar_p.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// 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 QQMLJSGRAMMAR_P_H +#define QQMLJSGRAMMAR_P_H + +#include + +QT_BEGIN_NAMESPACE + +class QQmlJSGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + REDUCE_HERE = 101, + SHIFT_THERE = 100, + 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_ERROR = 93, + T_FALSE = 83, + T_FEED_JS_EXPRESSION = 97, + T_FEED_JS_PROGRAM = 99, + T_FEED_JS_SOURCE_ELEMENT = 98, + T_FEED_JS_STATEMENT = 96, + T_FEED_UI_OBJECT_MEMBER = 95, + T_FEED_UI_PROGRAM = 94, + 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 = 644, + RULE_COUNT = 349, + STATE_COUNT = 645, + TERMINAL_COUNT = 102, + NON_TERMINAL_COUNT = 107, + + GOTO_INDEX_OFFSET = 645, + GOTO_INFO_OFFSET = 2807, + GOTO_CHECK_OFFSET = 2807 + }; + + 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 // QQMLJSGRAMMAR_P_H + diff --git a/src/qml/qml/parser/qqmljskeywords_p.h b/src/qml/qml/parser/qqmljskeywords_p.h new file mode 100644 index 0000000000..bbcc4855a3 --- /dev/null +++ b/src/qml/qml/parser/qqmljskeywords_p.h @@ -0,0 +1,860 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSKEYWORDS_P_H +#define QQMLJSKEYWORDS_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. +// + +static inline int classify2(const QChar *s, bool qmlMode) { + if (s[0].unicode() == 'a') { + if (s[1].unicode() == 's') { + return qmlMode ? Lexer::T_AS : Lexer::T_RESERVED_WORD; + } + } + else if (s[0].unicode() == 'd') { + if (s[1].unicode() == 'o') { + return Lexer::T_DO; + } + } + else if (s[0].unicode() == 'i') { + if (s[1].unicode() == 'f') { + return Lexer::T_IF; + } + else if (s[1].unicode() == 'n') { + return Lexer::T_IN; + } + } + else if (qmlMode && s[0].unicode() == 'o') { + if (s[1].unicode() == 'n') { + return Lexer::T_ON; + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify3(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'f') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'r') { + return Lexer::T_FOR; + } + } + } + else if (s[0].unicode() == 'i') { + if (s[1].unicode() == 'n') { + if (s[2].unicode() == 't') { + return Lexer::T_INT; + } + } + } + else if (s[0].unicode() == 'n') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 'w') { + return Lexer::T_NEW; + } + } + } + else if (s[0].unicode() == 't') { + if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'y') { + return Lexer::T_TRY; + } + } + } + else if (s[0].unicode() == 'v') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 'r') { + return Lexer::T_VAR; + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify4(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'b') { + if (s[1].unicode() == 'y') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'e') { + return Lexer::T_BYTE; + } + } + } + } + else if (s[0].unicode() == 'c') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 's') { + if (s[3].unicode() == 'e') { + return Lexer::T_CASE; + } + } + } + else if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'a') { + if (s[3].unicode() == 'r') { + return Lexer::T_CHAR; + } + } + } + } + else if (s[0].unicode() == 'e') { + if (s[1].unicode() == 'l') { + if (s[2].unicode() == 's') { + if (s[3].unicode() == 'e') { + return Lexer::T_ELSE; + } + } + } + else if (s[1].unicode() == 'n') { + if (s[2].unicode() == 'u') { + if (s[3].unicode() == 'm') { + return Lexer::T_ENUM; + } + } + } + } + else if (s[0].unicode() == 'g') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'o') { + return Lexer::T_GOTO; + } + } + } + } + else if (s[0].unicode() == 'l') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 'g') { + return Lexer::T_LONG; + } + } + } + } + else if (s[0].unicode() == 'n') { + if (s[1].unicode() == 'u') { + if (s[2].unicode() == 'l') { + if (s[3].unicode() == 'l') { + return Lexer::T_NULL; + } + } + } + } + else if (s[0].unicode() == 't') { + if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'i') { + if (s[3].unicode() == 's') { + return Lexer::T_THIS; + } + } + } + else if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'u') { + if (s[3].unicode() == 'e') { + return Lexer::T_TRUE; + } + } + } + } + else if (s[0].unicode() == 'v') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'i') { + if (s[3].unicode() == 'd') { + return Lexer::T_VOID; + } + } + } + } + else if (s[0].unicode() == 'w') { + if (s[1].unicode() == 'i') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'h') { + return Lexer::T_WITH; + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify5(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'b') { + if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'e') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 'k') { + return Lexer::T_BREAK; + } + } + } + } + } + else if (s[0].unicode() == 'c') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'c') { + if (s[4].unicode() == 'h') { + return Lexer::T_CATCH; + } + } + } + } + else if (s[1].unicode() == 'l') { + if (s[2].unicode() == 'a') { + if (s[3].unicode() == 's') { + if (s[4].unicode() == 's') { + return Lexer::T_CLASS; + } + } + } + } + else if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 's') { + if (s[4].unicode() == 't') { + return Lexer::T_CONST; + } + } + } + } + } + else if (s[0].unicode() == 'f') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 'l') { + if (s[3].unicode() == 's') { + if (s[4].unicode() == 'e') { + return Lexer::T_FALSE; + } + } + } + } + else if (s[1].unicode() == 'i') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 'l') { + return Lexer::T_FINAL; + } + } + } + } + else if (s[1].unicode() == 'l') { + if (s[2].unicode() == 'o') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 't') { + return Lexer::T_FLOAT; + } + } + } + } + } + else if (s[0].unicode() == 's') { + if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'o') { + if (s[3].unicode() == 'r') { + if (s[4].unicode() == 't') { + return Lexer::T_SHORT; + } + } + } + } + else if (s[1].unicode() == 'u') { + if (s[2].unicode() == 'p') { + if (s[3].unicode() == 'e') { + if (s[4].unicode() == 'r') { + return Lexer::T_SUPER; + } + } + } + } + } + else if (s[0].unicode() == 't') { + if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'r') { + if (s[3].unicode() == 'o') { + if (s[4].unicode() == 'w') { + return Lexer::T_THROW; + } + } + } + } + } + else if (s[0].unicode() == 'w') { + if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'i') { + if (s[3].unicode() == 'l') { + if (s[4].unicode() == 'e') { + return Lexer::T_WHILE; + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify6(const QChar *s, bool qmlMode) { + if (s[0].unicode() == 'd') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 'l') { + if (s[3].unicode() == 'e') { + if (s[4].unicode() == 't') { + if (s[5].unicode() == 'e') { + return Lexer::T_DELETE; + } + } + } + } + } + else if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'u') { + if (s[3].unicode() == 'b') { + if (s[4].unicode() == 'l') { + if (s[5].unicode() == 'e') { + return Lexer::T_DOUBLE; + } + } + } + } + } + } + else if (s[0].unicode() == 'e') { + if (s[1].unicode() == 'x') { + if (s[2].unicode() == 'p') { + if (s[3].unicode() == 'o') { + if (s[4].unicode() == 'r') { + if (s[5].unicode() == 't') { + return Lexer::T_EXPORT; + } + } + } + } + } + } + else if (s[0].unicode() == 'i') { + if (s[1].unicode() == 'm') { + if (s[2].unicode() == 'p') { + if (s[3].unicode() == 'o') { + if (s[4].unicode() == 'r') { + if (s[5].unicode() == 't') { + return qmlMode ? Lexer::T_IMPORT : Lexer::T_RESERVED_WORD; + } + } + } + } + } + } + else if (s[0].unicode() == 'n') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'i') { + if (s[4].unicode() == 'v') { + if (s[5].unicode() == 'e') { + return Lexer::T_NATIVE; + } + } + } + } + } + } + else if (s[0].unicode() == 'p') { + if (s[1].unicode() == 'u') { + if (s[2].unicode() == 'b') { + if (s[3].unicode() == 'l') { + if (s[4].unicode() == 'i') { + if (s[5].unicode() == 'c') { + return qmlMode ? Lexer::T_PUBLIC : Lexer::T_RESERVED_WORD; + } + } + } + } + } + } + else if (s[0].unicode() == 'r') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'u') { + if (s[4].unicode() == 'r') { + if (s[5].unicode() == 'n') { + return Lexer::T_RETURN; + } + } + } + } + } + } + else if (s[0].unicode() == 's') { + if (qmlMode && s[1].unicode() == 'i') { + if (s[2].unicode() == 'g') { + if (s[3].unicode() == 'n') { + if (s[4].unicode() == 'a') { + if (s[5].unicode() == 'l') { + return Lexer::T_SIGNAL; + } + } + } + } + } + else if (s[1].unicode() == 't') { + if (s[2].unicode() == 'a') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'i') { + if (s[5].unicode() == 'c') { + return Lexer::T_STATIC; + } + } + } + } + } + else if (s[1].unicode() == 'w') { + if (s[2].unicode() == 'i') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'c') { + if (s[5].unicode() == 'h') { + return Lexer::T_SWITCH; + } + } + } + } + } + } + else if (s[0].unicode() == 't') { + if (s[1].unicode() == 'h') { + if (s[2].unicode() == 'r') { + if (s[3].unicode() == 'o') { + if (s[4].unicode() == 'w') { + if (s[5].unicode() == 's') { + return Lexer::T_THROWS; + } + } + } + } + } + else if (s[1].unicode() == 'y') { + if (s[2].unicode() == 'p') { + if (s[3].unicode() == 'e') { + if (s[4].unicode() == 'o') { + if (s[5].unicode() == 'f') { + return Lexer::T_TYPEOF; + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify7(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'b') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'o') { + if (s[3].unicode() == 'l') { + if (s[4].unicode() == 'e') { + if (s[5].unicode() == 'a') { + if (s[6].unicode() == 'n') { + return Lexer::T_BOOLEAN; + } + } + } + } + } + } + } + else if (s[0].unicode() == 'd') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 'f') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 'u') { + if (s[5].unicode() == 'l') { + if (s[6].unicode() == 't') { + return Lexer::T_DEFAULT; + } + } + } + } + } + } + } + else if (s[0].unicode() == 'e') { + if (s[1].unicode() == 'x') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'e') { + if (s[4].unicode() == 'n') { + if (s[5].unicode() == 'd') { + if (s[6].unicode() == 's') { + return Lexer::T_EXTENDS; + } + } + } + } + } + } + } + else if (s[0].unicode() == 'f') { + if (s[1].unicode() == 'i') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 'l') { + if (s[5].unicode() == 'l') { + if (s[6].unicode() == 'y') { + return Lexer::T_FINALLY; + } + } + } + } + } + } + } + else if (s[0].unicode() == 'p') { + if (s[1].unicode() == 'a') { + if (s[2].unicode() == 'c') { + if (s[3].unicode() == 'k') { + if (s[4].unicode() == 'a') { + if (s[5].unicode() == 'g') { + if (s[6].unicode() == 'e') { + return Lexer::T_PACKAGE; + } + } + } + } + } + } + else if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'i') { + if (s[3].unicode() == 'v') { + if (s[4].unicode() == 'a') { + if (s[5].unicode() == 't') { + if (s[6].unicode() == 'e') { + return Lexer::T_PRIVATE; + } + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify8(const QChar *s, bool qmlMode) { + if (s[0].unicode() == 'a') { + if (s[1].unicode() == 'b') { + if (s[2].unicode() == 's') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'r') { + if (s[5].unicode() == 'a') { + if (s[6].unicode() == 'c') { + if (s[7].unicode() == 't') { + return Lexer::T_ABSTRACT; + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 'c') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'i') { + if (s[5].unicode() == 'n') { + if (s[6].unicode() == 'u') { + if (s[7].unicode() == 'e') { + return Lexer::T_CONTINUE; + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 'd') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 'b') { + if (s[3].unicode() == 'u') { + if (s[4].unicode() == 'g') { + if (s[5].unicode() == 'g') { + if (s[6].unicode() == 'e') { + if (s[7].unicode() == 'r') { + return Lexer::T_DEBUGGER; + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 'f') { + if (s[1].unicode() == 'u') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 'c') { + if (s[4].unicode() == 't') { + if (s[5].unicode() == 'i') { + if (s[6].unicode() == 'o') { + if (s[7].unicode() == 'n') { + return Lexer::T_FUNCTION; + } + } + } + } + } + } + } + } + else if (qmlMode && s[0].unicode() == 'p') { + if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'o') { + if (s[3].unicode() == 'p') { + if (s[4].unicode() == 'e') { + if (s[5].unicode() == 'r') { + if (s[6].unicode() == 't') { + if (s[7].unicode() == 'y') { + return Lexer::T_PROPERTY; + } + } + } + } + } + } + } + } + else if (qmlMode && s[0].unicode() == 'r') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 'a') { + if (s[3].unicode() == 'd') { + if (s[4].unicode() == 'o') { + if (s[5].unicode() == 'n') { + if (s[6].unicode() == 'l') { + if (s[7].unicode() == 'y') { + return Lexer::T_READONLY; + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 'v') { + if (s[1].unicode() == 'o') { + if (s[2].unicode() == 'l') { + if (s[3].unicode() == 'a') { + if (s[4].unicode() == 't') { + if (s[5].unicode() == 'i') { + if (s[6].unicode() == 'l') { + if (s[7].unicode() == 'e') { + return Lexer::T_VOLATILE; + } + } + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify9(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'i') { + if (s[1].unicode() == 'n') { + if (s[2].unicode() == 't') { + if (s[3].unicode() == 'e') { + if (s[4].unicode() == 'r') { + if (s[5].unicode() == 'f') { + if (s[6].unicode() == 'a') { + if (s[7].unicode() == 'c') { + if (s[8].unicode() == 'e') { + return Lexer::T_INTERFACE; + } + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 'p') { + if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'o') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'e') { + if (s[5].unicode() == 'c') { + if (s[6].unicode() == 't') { + if (s[7].unicode() == 'e') { + if (s[8].unicode() == 'd') { + return Lexer::T_PROTECTED; + } + } + } + } + } + } + } + } + } + else if (s[0].unicode() == 't') { + if (s[1].unicode() == 'r') { + if (s[2].unicode() == 'a') { + if (s[3].unicode() == 'n') { + if (s[4].unicode() == 's') { + if (s[5].unicode() == 'i') { + if (s[6].unicode() == 'e') { + if (s[7].unicode() == 'n') { + if (s[8].unicode() == 't') { + return Lexer::T_TRANSIENT; + } + } + } + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify10(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 'i') { + if (s[1].unicode() == 'm') { + if (s[2].unicode() == 'p') { + if (s[3].unicode() == 'l') { + if (s[4].unicode() == 'e') { + if (s[5].unicode() == 'm') { + if (s[6].unicode() == 'e') { + if (s[7].unicode() == 'n') { + if (s[8].unicode() == 't') { + if (s[9].unicode() == 's') { + return Lexer::T_IMPLEMENTS; + } + } + } + } + } + } + } + } + } + else if (s[1].unicode() == 'n') { + if (s[2].unicode() == 's') { + if (s[3].unicode() == 't') { + if (s[4].unicode() == 'a') { + if (s[5].unicode() == 'n') { + if (s[6].unicode() == 'c') { + if (s[7].unicode() == 'e') { + if (s[8].unicode() == 'o') { + if (s[9].unicode() == 'f') { + return Lexer::T_INSTANCEOF; + } + } + } + } + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +static inline int classify12(const QChar *s, bool /*qmlMode*/) { + if (s[0].unicode() == 's') { + if (s[1].unicode() == 'y') { + if (s[2].unicode() == 'n') { + if (s[3].unicode() == 'c') { + if (s[4].unicode() == 'h') { + if (s[5].unicode() == 'r') { + if (s[6].unicode() == 'o') { + if (s[7].unicode() == 'n') { + if (s[8].unicode() == 'i') { + if (s[9].unicode() == 'z') { + if (s[10].unicode() == 'e') { + if (s[11].unicode() == 'd') { + return Lexer::T_SYNCHRONIZED; + } + } + } + } + } + } + } + } + } + } + } + } + return Lexer::T_IDENTIFIER; +} + +int Lexer::classify(const QChar *s, int n, bool qmlMode) { + switch (n) { + case 2: return classify2(s, qmlMode); + case 3: return classify3(s, qmlMode); + case 4: return classify4(s, qmlMode); + case 5: return classify5(s, qmlMode); + case 6: return classify6(s, qmlMode); + case 7: return classify7(s, qmlMode); + case 8: return classify8(s, qmlMode); + case 9: return classify9(s, qmlMode); + case 10: return classify10(s, qmlMode); + case 12: return classify12(s, qmlMode); + default: return Lexer::T_IDENTIFIER; + } // switch +} + +#endif // QQMLJSKEYWORDS_P_H diff --git a/src/qml/qml/parser/qqmljslexer.cpp b/src/qml/qml/parser/qqmljslexer.cpp new file mode 100644 index 0000000000..c34fc81163 --- /dev/null +++ b/src/qml/qml/parser/qqmljslexer.cpp @@ -0,0 +1,1166 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmljslexer_p.h" +#include "qqmljsengine_p.h" +#include "qqmljsmemorypool_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE +Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); +QT_END_NAMESPACE + +using namespace QQmlJS; + +static int regExpFlagFromChar(const QChar &ch) +{ + switch (ch.unicode()) { + case 'g': return Lexer::RegExp_Global; + case 'i': return Lexer::RegExp_IgnoreCase; + case 'm': return Lexer::RegExp_Multiline; + } + return 0; +} + +static unsigned char 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); +} + +static QChar convertHex(QChar c1, QChar c2) +{ + return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode())); +} + +static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4) +{ + return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()), + (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode())); +} + +Lexer::Lexer(Engine *engine) + : _engine(engine) + , _codePtr(0) + , _lastLinePtr(0) + , _tokenLinePtr(0) + , _tokenStartPtr(0) + , _char(QLatin1Char('\n')) + , _errorCode(NoError) + , _currentLineNumber(0) + , _tokenValue(0) + , _parenthesesState(IgnoreParentheses) + , _parenthesesCount(0) + , _stackToken(-1) + , _patternFlags(0) + , _tokenKind(0) + , _tokenLength(0) + , _tokenLine(0) + , _validTokenText(false) + , _prohibitAutomaticSemicolon(false) + , _restrictedKeyword(false) + , _terminator(false) + , _followsClosingBrace(false) + , _delimited(true) + , _qmlMode(true) +{ + if (engine) + engine->setLexer(this); +} + +bool Lexer::qmlMode() const +{ + return _qmlMode; +} + +QString Lexer::code() const +{ + return _code; +} + +void Lexer::setCode(const QString &code, int lineno, bool qmlMode) +{ + if (_engine) + _engine->setCode(code); + + _qmlMode = qmlMode; + _code = code; + _tokenText.clear(); + _tokenText.reserve(1024); + _errorMessage.clear(); + _tokenSpell = QStringRef(); + + _codePtr = code.unicode(); + _lastLinePtr = _codePtr; + _tokenLinePtr = _codePtr; + _tokenStartPtr = _codePtr; + + _char = QLatin1Char('\n'); + _errorCode = NoError; + + _currentLineNumber = lineno; + _tokenValue = 0; + + // parentheses state + _parenthesesState = IgnoreParentheses; + _parenthesesCount = 0; + + _stackToken = -1; + + _patternFlags = 0; + _tokenLength = 0; + _tokenLine = lineno; + + _validTokenText = false; + _prohibitAutomaticSemicolon = false; + _restrictedKeyword = false; + _terminator = false; + _followsClosingBrace = false; + _delimited = true; +} + +void Lexer::scanChar() +{ + _char = *_codePtr++; + + if (_char == QLatin1Char('\n')) { + _lastLinePtr = _codePtr; // points to the first character after the newline + ++_currentLineNumber; + } +} + +int Lexer::lex() +{ + const int previousTokenKind = _tokenKind; + + _tokenSpell = QStringRef(); + _tokenKind = scanToken(); + _tokenLength = _codePtr - _tokenStartPtr - 1; + + _delimited = false; + _restrictedKeyword = false; + _followsClosingBrace = (previousTokenKind == T_RBRACE); + + // update the flags + switch (_tokenKind) { + case T_LBRACE: + case T_SEMICOLON: + case T_COLON: + _delimited = true; + break; + + case T_IF: + case T_FOR: + case T_WHILE: + case T_WITH: + _parenthesesState = CountParentheses; + _parenthesesCount = 0; + break; + + case T_DO: + _parenthesesState = BalancedParentheses; + break; + + case T_CONTINUE: + case T_BREAK: + case T_RETURN: + case T_THROW: + _restrictedKeyword = true; + break; + } // switch + + // update the parentheses state + switch (_parenthesesState) { + case IgnoreParentheses: + break; + + case CountParentheses: + if (_tokenKind == T_RPAREN) { + --_parenthesesCount; + if (_parenthesesCount == 0) + _parenthesesState = BalancedParentheses; + } else if (_tokenKind == T_LPAREN) { + ++_parenthesesCount; + } + break; + + case BalancedParentheses: + _parenthesesState = IgnoreParentheses; + break; + } // switch + + return _tokenKind; +} + +bool Lexer::isUnicodeEscapeSequence(const QChar *chars) +{ + if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3])) + return true; + + return false; +} + +QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok) +{ + if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) { + scanChar(); // skip u + + const QChar c1 = _char; + scanChar(); + + const QChar c2 = _char; + scanChar(); + + const QChar c3 = _char; + scanChar(); + + const QChar c4 = _char; + scanChar(); + + if (ok) + *ok = true; + + return convertUnicode(c1, c2, c3, c4); + } + + *ok = false; + return QChar(); +} + +int Lexer::scanToken() +{ + if (_stackToken != -1) { + int tk = _stackToken; + _stackToken = -1; + return tk; + } + + _terminator = false; + +again: + _validTokenText = false; + _tokenLinePtr = _lastLinePtr; + + while (_char.isSpace()) { + if (_char == QLatin1Char('\n')) { + _tokenLinePtr = _codePtr; + + if (_restrictedKeyword) { + // automatic semicolon insertion + _tokenLine = _currentLineNumber; + _tokenStartPtr = _codePtr - 1; // ### TODO: insert it before the optional \r sequence. + return T_SEMICOLON; + } else { + _terminator = true; + syncProhibitAutomaticSemicolon(); + } + } + + scanChar(); + } + + _tokenStartPtr = _codePtr - 1; + _tokenLine = _currentLineNumber; + + if (_char.isNull()) + return EOF_SYMBOL; + + const QChar ch = _char; + scanChar(); + + switch (ch.unicode()) { + case '~': return T_TILDE; + case '}': return T_RBRACE; + + case '|': + if (_char == QLatin1Char('|')) { + scanChar(); + return T_OR_OR; + } else if (_char == QLatin1Char('=')) { + scanChar(); + return T_OR_EQ; + } + return T_OR; + + case '{': return T_LBRACE; + + case '^': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_XOR_EQ; + } + return T_XOR; + + case ']': return T_RBRACKET; + case '[': return T_LBRACKET; + case '?': return T_QUESTION; + + case '>': + if (_char == QLatin1Char('>')) { + scanChar(); + if (_char == QLatin1Char('>')) { + scanChar(); + if (_char == QLatin1Char('=')) { + scanChar(); + return T_GT_GT_GT_EQ; + } + return T_GT_GT_GT; + } else if (_char == QLatin1Char('=')) { + scanChar(); + return T_GT_GT_EQ; + } + return T_GT_GT; + } else if (_char == QLatin1Char('=')) { + scanChar(); + return T_GE; + } + return T_GT; + + case '=': + if (_char == QLatin1Char('=')) { + scanChar(); + if (_char == QLatin1Char('=')) { + scanChar(); + return T_EQ_EQ_EQ; + } + return T_EQ_EQ; + } + return T_EQ; + + case '<': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_LE; + } else if (_char == QLatin1Char('<')) { + scanChar(); + if (_char == QLatin1Char('=')) { + scanChar(); + return T_LT_LT_EQ; + } + return T_LT_LT; + } + return T_LT; + + case ';': return T_SEMICOLON; + case ':': return T_COLON; + + case '/': + if (_char == QLatin1Char('*')) { + scanChar(); + while (!_char.isNull()) { + if (_char == QLatin1Char('*')) { + scanChar(); + if (_char == QLatin1Char('/')) { + scanChar(); + + if (_engine) { + _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4, + tokenStartLine(), tokenStartColumn() + 2); + } + + goto again; + } + } else { + scanChar(); + } + } + } else if (_char == QLatin1Char('/')) { + while (!_char.isNull() && _char != QLatin1Char('\n')) { + scanChar(); + } + if (_engine) { + _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2, + tokenStartLine(), tokenStartColumn() + 2); + } + goto again; + } if (_char == QLatin1Char('=')) { + scanChar(); + return T_DIVIDE_EQ; + } + return T_DIVIDE_; + + case '.': + if (_char.isDigit()) { + QVarLengthArray chars; + + chars.append(ch.unicode()); // append the `.' + + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } + + if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { + if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && + _codePtr[1].isDigit())) { + + chars.append(_char.unicode()); + scanChar(); // consume `e' + + if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { + chars.append(_char.unicode()); + scanChar(); // consume the sign + } + + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } + } + } + + chars.append('\0'); + + const char *begin = chars.constData(); + const char *end = 0; + bool ok = false; + + _tokenValue = qstrtod(begin, &end, &ok); + + if (end - begin != chars.size() - 1) { + _errorCode = IllegalExponentIndicator; + _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number"); + return T_ERROR; + } + + return T_NUMERIC_LITERAL; + } + return T_DOT; + + case '-': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_MINUS_EQ; + } else if (_char == QLatin1Char('-')) { + scanChar(); + + if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) { + _stackToken = T_MINUS_MINUS; + return T_SEMICOLON; + } + + return T_MINUS_MINUS; + } + return T_MINUS; + + case ',': return T_COMMA; + + case '+': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_PLUS_EQ; + } else if (_char == QLatin1Char('+')) { + scanChar(); + + if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) { + _stackToken = T_PLUS_PLUS; + return T_SEMICOLON; + } + + return T_PLUS_PLUS; + } + return T_PLUS; + + case '*': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_STAR_EQ; + } + return T_STAR; + + case ')': return T_RPAREN; + case '(': return T_LPAREN; + + case '&': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_AND_EQ; + } else if (_char == QLatin1Char('&')) { + scanChar(); + return T_AND_AND; + } + return T_AND; + + case '%': + if (_char == QLatin1Char('=')) { + scanChar(); + return T_REMAINDER_EQ; + } + return T_REMAINDER; + + case '!': + if (_char == QLatin1Char('=')) { + scanChar(); + if (_char == QLatin1Char('=')) { + scanChar(); + return T_NOT_EQ_EQ; + } + return T_NOT_EQ; + } + return T_NOT; + + case '\'': + case '"': { + const QChar quote = ch; + bool multilineStringLiteral = false; + + const QChar *startCode = _codePtr; + + if (_engine) { + while (!_char.isNull()) { + if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) { + break; + } else if (_char == quote) { + _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode); + scanChar(); + + return T_STRING_LITERAL; + } + scanChar(); + } + } + + _validTokenText = true; + _tokenText.resize(0); + startCode--; + while (startCode != _codePtr - 1) + _tokenText += *startCode++; + + while (! _char.isNull()) { + if (_char == QLatin1Char('\n')) { + multilineStringLiteral = true; + _tokenText += _char; + scanChar(); + } else if (_char == quote) { + scanChar(); + + if (_engine) + _tokenSpell = _engine->newStringRef(_tokenText); + + return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL; + } else if (_char == QLatin1Char('\\')) { + scanChar(); + + QChar u; + bool ok = false; + + switch (_char.unicode()) { + // unicode escape sequence + case 'u': + u = decodeUnicodeEscapeCharacter(&ok); + if (! ok) + u = _char; + break; + + // hex escape sequence + case 'x': + case 'X': + if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) { + scanChar(); + + const QChar c1 = _char; + scanChar(); + + const QChar c2 = _char; + scanChar(); + + u = convertHex(c1, c2); + } else { + u = _char; + } + break; + + // single character escape sequence + case '\\': u = QLatin1Char('\\'); scanChar(); break; + case '\'': u = QLatin1Char('\''); scanChar(); break; + case '\"': u = QLatin1Char('\"'); scanChar(); break; + case 'b': u = QLatin1Char('\b'); scanChar(); break; + case 'f': u = QLatin1Char('\f'); scanChar(); break; + case 'n': u = QLatin1Char('\n'); scanChar(); break; + case 'r': u = QLatin1Char('\r'); scanChar(); break; + case 't': u = QLatin1Char('\t'); scanChar(); break; + case 'v': u = QLatin1Char('\v'); scanChar(); break; + + case '0': + if (! _codePtr[1].isDigit()) { + scanChar(); + u = QLatin1Char('\0'); + } else { + // ### parse deprecated octal escape sequence ? + u = _char; + } + break; + + case '\r': + while (_char == QLatin1Char('\r')) + scanChar(); + + if (_char == QLatin1Char('\n')) { + u = _char; + scanChar(); + } else { + u = QLatin1Char('\n'); + } + + break; + + case '\n': + u = _char; + scanChar(); + break; + + default: + // non escape character + u = _char; + scanChar(); + } + + _tokenText += u; + } else { + _tokenText += _char; + scanChar(); + } + } + + _errorCode = UnclosedStringLiteral; + _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line"); + return T_ERROR; + } + + default: + if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) { + bool identifierWithEscapeChars = false; + if (ch == QLatin1Char('\\')) { + identifierWithEscapeChars = true; + _tokenText.resize(0); + bool ok = false; + _tokenText += decodeUnicodeEscapeCharacter(&ok); + _validTokenText = true; + if (! ok) { + _errorCode = IllegalUnicodeEscapeSequence; + _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence"); + return T_ERROR; + } + } + while (true) { + if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) { + if (identifierWithEscapeChars) + _tokenText += _char; + + scanChar(); + } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) { + if (! identifierWithEscapeChars) { + identifierWithEscapeChars = true; + _tokenText.resize(0); + _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1); + _validTokenText = true; + } + + scanChar(); // skip '\\' + bool ok = false; + _tokenText += decodeUnicodeEscapeCharacter(&ok); + if (! ok) { + _errorCode = IllegalUnicodeEscapeSequence; + _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence"); + return T_ERROR; + } + } else { + _tokenLength = _codePtr - _tokenStartPtr - 1; + + int kind = T_IDENTIFIER; + + if (! identifierWithEscapeChars) + kind = classify(_tokenStartPtr, _tokenLength, _qmlMode); + + if (_engine) { + if (kind == T_IDENTIFIER && identifierWithEscapeChars) + _tokenSpell = _engine->newStringRef(_tokenText); + else + _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength); + } + + return kind; + } + } + } else if (ch.isDigit()) { + if (ch != QLatin1Char('0')) { + double integer = ch.unicode() - '0'; + + QChar n = _char; + const QChar *code = _codePtr; + while (n.isDigit()) { + integer = integer * 10 + (n.unicode() - '0'); + n = *code++; + } + + if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) { + if (code != _codePtr) { + _codePtr = code - 1; + scanChar(); + } + _tokenValue = integer; + return T_NUMERIC_LITERAL; + } + } + + QVarLengthArray chars; + chars.append(ch.unicode()); + + if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) { + // parse hex integer literal + + chars.append(_char.unicode()); + scanChar(); // consume `x' + + while (isHexDigit(_char)) { + chars.append(_char.unicode()); + scanChar(); + } + + _tokenValue = integerFromString(chars.constData(), chars.size(), 16); + return T_NUMERIC_LITERAL; + } + + // decimal integer literal + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); // consume the digit + } + + if (_char == QLatin1Char('.')) { + chars.append(_char.unicode()); + scanChar(); // consume `.' + + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } + + if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { + if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && + _codePtr[1].isDigit())) { + + chars.append(_char.unicode()); + scanChar(); // consume `e' + + if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { + chars.append(_char.unicode()); + scanChar(); // consume the sign + } + + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } + } + } + } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { + if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && + _codePtr[1].isDigit())) { + + chars.append(_char.unicode()); + scanChar(); // consume `e' + + if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { + chars.append(_char.unicode()); + scanChar(); // consume the sign + } + + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } + } + } + + chars.append('\0'); + + const char *begin = chars.constData(); + const char *end = 0; + bool ok = false; + + _tokenValue = qstrtod(begin, &end, &ok); + + if (end - begin != chars.size() - 1) { + _errorCode = IllegalExponentIndicator; + _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number"); + return T_ERROR; + } + + return T_NUMERIC_LITERAL; + } + + break; + } + + return T_ERROR; +} + +bool Lexer::scanRegExp(RegExpBodyPrefix prefix) +{ + _tokenText.resize(0); + _validTokenText = true; + _patternFlags = 0; + + if (prefix == EqualPrefix) + _tokenText += QLatin1Char('='); + + while (true) { + switch (_char.unicode()) { + case 0: // eof + case '\n': case '\r': // line terminator + _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression literal"); + return false; + + case '/': + scanChar(); + + // scan the flags + _patternFlags = 0; + while (isIdentLetter(_char)) { + int flag = regExpFlagFromChar(_char); + if (flag == 0) { + _errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'") + .arg(QChar(_char)); + return false; + } + _patternFlags |= flag; + scanChar(); + } + + _tokenLength = _codePtr - _tokenStartPtr - 1; + return true; + + case '\\': + // regular expression backslash sequence + _tokenText += _char; + scanChar(); + + if (_char.isNull() || isLineTerminator()) { + _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence"); + return false; + } + + _tokenText += _char; + scanChar(); + break; + + case '[': + // regular expression class + _tokenText += _char; + scanChar(); + + while (! _char.isNull() && ! isLineTerminator()) { + if (_char == QLatin1Char(']')) + break; + else if (_char == QLatin1Char('\\')) { + // regular expression backslash sequence + _tokenText += _char; + scanChar(); + + if (_char.isNull() || isLineTerminator()) { + _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence"); + return false; + } + + _tokenText += _char; + scanChar(); + } else { + _tokenText += _char; + scanChar(); + } + } + + if (_char != QLatin1Char(']')) { + _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression class"); + return false; + } + + _tokenText += _char; + scanChar(); // skip ] + break; + + default: + _tokenText += _char; + scanChar(); + } // switch + } // while + + return false; +} + +bool Lexer::isLineTerminator() const +{ + return (_char == QLatin1Char('\n') || _char == QLatin1Char('\r')); +} + +bool Lexer::isIdentLetter(QChar ch) +{ + // ASCII-biased, since all reserved words are ASCII, aand hence the + // bulk of content to be parsed. + if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) + || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')) + || ch == QLatin1Char('$') + || ch == QLatin1Char('_')) + return true; + if (ch.unicode() < 128) + return false; + return ch.isLetterOrNumber(); +} + +bool Lexer::isDecimalDigit(ushort c) +{ + return (c >= '0' && c <= '9'); +} + +bool Lexer::isHexDigit(QChar c) +{ + return ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) + || (c >= QLatin1Char('a') && c <= QLatin1Char('f')) + || (c >= QLatin1Char('A') && c <= QLatin1Char('F'))); +} + +bool Lexer::isOctalDigit(ushort c) +{ + return (c >= '0' && c <= '7'); +} + +int Lexer::tokenKind() const +{ + return _tokenKind; +} + +int Lexer::tokenOffset() const +{ + return _tokenStartPtr - _code.unicode(); +} + +int Lexer::tokenLength() const +{ + return _tokenLength; +} + +int Lexer::tokenStartLine() const +{ + return _tokenLine; +} + +int Lexer::tokenStartColumn() const +{ + return _tokenStartPtr - _tokenLinePtr + 1; +} + +int Lexer::tokenEndLine() const +{ + return _currentLineNumber; +} + +int Lexer::tokenEndColumn() const +{ + return _codePtr - _lastLinePtr; +} + +QStringRef Lexer::tokenSpell() const +{ + return _tokenSpell; +} + +double Lexer::tokenValue() const +{ + return _tokenValue; +} + +QString Lexer::tokenText() const +{ + if (_validTokenText) + return _tokenText; + + if (_tokenKind == T_STRING_LITERAL) + return QString(_tokenStartPtr + 1, _tokenLength - 2); + + return QString(_tokenStartPtr, _tokenLength); +} + +Lexer::Error Lexer::errorCode() const +{ + return _errorCode; +} + +QString Lexer::errorMessage() const +{ + return _errorMessage; +} + +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; + } +} + +bool Lexer::prevTerminator() const +{ + return _terminator; +} + +bool Lexer::followsClosingBrace() const +{ + return _followsClosingBrace; +} + +bool Lexer::canInsertAutomaticSemicolon(int token) const +{ + return token == T_RBRACE + || token == EOF_SYMBOL + || _terminator + || _followsClosingBrace; +} + +bool Lexer::scanDirectives(Directives *directives) +{ + if (_qmlMode) { + // the directives are a Javascript-only extension. + return false; + } + + lex(); // fetch the first token + + if (_tokenKind != T_DOT) + return true; + + do { + lex(); // skip T_DOT + + const int lineNumber = tokenStartLine(); + + if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD)) + return false; // expected a valid QML/JS directive + + const QString directiveName = tokenText(); + + if (! (directiveName == QLatin1String("pragma") || + directiveName == QLatin1String("import"))) + return false; // not a valid directive name + + // it must be a pragma or an import directive. + if (directiveName == QLatin1String("pragma")) { + // .pragma library + if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library"))) + return false; // expected `library + + // we found a .pragma library directive + directives->pragmaLibrary(); + + } else { + Q_ASSERT(directiveName == QLatin1String("import")); + lex(); // skip .import + + QString pathOrUri; + QString version; + bool fileImport = false; // file or uri import + + if (_tokenKind == T_STRING_LITERAL) { + // .import T_STRING_LITERAL as T_IDENTIFIER + + fileImport = true; + pathOrUri = tokenText(); + + } else if (_tokenKind == T_IDENTIFIER) { + // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER + + pathOrUri = tokenText(); + + lex(); // skip the first T_IDENTIFIER + for (; _tokenKind == T_DOT; lex()) { + if (lex() != T_IDENTIFIER) + return false; + + pathOrUri += QLatin1Char('.'); + pathOrUri += tokenText(); + } + + if (_tokenKind != T_NUMERIC_LITERAL) + return false; // expected the module version number + + version = tokenText(); + } + + // + // recognize the mandatory `as' followed by the module name + // + if (! (lex() == T_RESERVED_WORD && tokenText() == QLatin1String("as"))) + return false; // expected `as' + + if (lex() != T_IDENTIFIER) + return false; // expected module name + + const QString module = tokenText(); + + if (fileImport) + directives->importFile(pathOrUri, module); + else + directives->importModule(pathOrUri, version, module); + } + + if (tokenStartLine() != lineNumber) + return false; // the directives cannot span over multiple lines + + // fetch the first token after the .pragma/.import directive + lex(); + } while (_tokenKind == T_DOT); + + return true; +} + +#include "qqmljskeywords_p.h" diff --git a/src/qml/qml/parser/qqmljslexer_p.h b/src/qml/qml/parser/qqmljslexer_p.h new file mode 100644 index 0000000000..6b51852f5f --- /dev/null +++ b/src/qml/qml/parser/qqmljslexer_p.h @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSLEXER_P_H +#define QQMLJSLEXER_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 "qqmljsglobal_p.h" +#include "qqmljsgrammar_p.h" +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +class Engine; + +class QML_PARSER_EXPORT Directives { +public: + virtual ~Directives() {} + + virtual void pragmaLibrary() + { + } + + virtual void importFile(const QString &jsfile, const QString &module) + { + Q_UNUSED(jsfile); + Q_UNUSED(module); + } + + virtual void importModule(const QString &uri, const QString &version, const QString &module) + { + Q_UNUSED(uri); + Q_UNUSED(version); + Q_UNUSED(module); + } +}; + +class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar +{ +public: + enum { + T_ABSTRACT = T_RESERVED_WORD, + T_BOOLEAN = T_RESERVED_WORD, + T_BYTE = T_RESERVED_WORD, + T_CHAR = T_RESERVED_WORD, + T_CLASS = T_RESERVED_WORD, + T_DOUBLE = T_RESERVED_WORD, + T_ENUM = T_RESERVED_WORD, + T_EXPORT = T_RESERVED_WORD, + T_EXTENDS = T_RESERVED_WORD, + T_FINAL = T_RESERVED_WORD, + T_FLOAT = T_RESERVED_WORD, + T_GOTO = T_RESERVED_WORD, + T_IMPLEMENTS = T_RESERVED_WORD, + T_INT = T_RESERVED_WORD, + T_INTERFACE = T_RESERVED_WORD, + T_LET = T_RESERVED_WORD, + T_LONG = T_RESERVED_WORD, + T_NATIVE = T_RESERVED_WORD, + T_PACKAGE = T_RESERVED_WORD, + T_PRIVATE = T_RESERVED_WORD, + T_PROTECTED = T_RESERVED_WORD, + T_SHORT = T_RESERVED_WORD, + T_STATIC = T_RESERVED_WORD, + T_SUPER = T_RESERVED_WORD, + T_SYNCHRONIZED = T_RESERVED_WORD, + T_THROWS = T_RESERVED_WORD, + T_TRANSIENT = T_RESERVED_WORD, + T_VOLATILE = T_RESERVED_WORD, + T_YIELD = T_RESERVED_WORD + }; + + enum Error { + NoError, + IllegalCharacter, + UnclosedStringLiteral, + IllegalEscapeSequence, + IllegalUnicodeEscapeSequence, + UnclosedComment, + IllegalExponentIndicator, + IllegalIdentifier + }; + + enum RegExpBodyPrefix { + NoPrefix, + EqualPrefix + }; + + enum RegExpFlag { + RegExp_Global = 0x01, + RegExp_IgnoreCase = 0x02, + RegExp_Multiline = 0x04 + }; + +public: + Lexer(Engine *engine); + + bool qmlMode() const; + + QString code() const; + void setCode(const QString &code, int lineno, bool qmlMode = true); + + int lex(); + + bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); + bool scanDirectives(Directives *directives); + + int regExpFlags() const { return _patternFlags; } + QString regExpPattern() const { return _tokenText; } + + int tokenKind() const; + int tokenOffset() const; + int tokenLength() const; + + int tokenStartLine() const; + int tokenStartColumn() const; + + int tokenEndLine() const; + int tokenEndColumn() const; + + QStringRef tokenSpell() const; + double tokenValue() const; + QString tokenText() const; + + Error errorCode() const; + QString errorMessage() const; + + bool prevTerminator() const; + bool followsClosingBrace() const; + bool canInsertAutomaticSemicolon(int token) const; + + enum ParenthesesState { + IgnoreParentheses, + CountParentheses, + BalancedParentheses + }; + +protected: + int classify(const QChar *s, int n, bool qmlMode); + +private: + inline void scanChar(); + int scanToken(); + + bool isLineTerminator() const; + static bool isIdentLetter(QChar c); + static bool isDecimalDigit(ushort c); + static bool isHexDigit(QChar c); + static bool isOctalDigit(ushort c); + static bool isUnicodeEscapeSequence(const QChar *chars); + + void syncProhibitAutomaticSemicolon(); + QChar decodeUnicodeEscapeCharacter(bool *ok); + +private: + Engine *_engine; + + QString _code; + QString _tokenText; + QString _errorMessage; + QStringRef _tokenSpell; + + const QChar *_codePtr; + const QChar *_lastLinePtr; + const QChar *_tokenLinePtr; + const QChar *_tokenStartPtr; + + QChar _char; + Error _errorCode; + + int _currentLineNumber; + double _tokenValue; + + // parentheses state + ParenthesesState _parenthesesState; + int _parenthesesCount; + + int _stackToken; + + int _patternFlags; + int _tokenKind; + int _tokenLength; + int _tokenLine; + + bool _validTokenText; + bool _prohibitAutomaticSemicolon; + bool _restrictedKeyword; + bool _terminator; + bool _followsClosingBrace; + bool _delimited; + bool _qmlMode; +}; + +} // end of namespace QQmlJS + +QT_QML_END_NAMESPACE + +#endif // LEXER_H diff --git a/src/qml/qml/parser/qqmljsmemorypool_p.h b/src/qml/qml/parser/qqmljsmemorypool_p.h new file mode 100644 index 0000000000..fd52fd25e4 --- /dev/null +++ b/src/qml/qml/parser/qqmljsmemorypool_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLJSMEMORYPOOL_P_H +#define QQMLJSMEMORYPOOL_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 "qqmljsglobal_p.h" + +#include +#include +#include + +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +class QML_PARSER_EXPORT MemoryPool : public QSharedData +{ + MemoryPool(const MemoryPool &other); + void operator =(const MemoryPool &other); + +public: + MemoryPool() + : _blocks(0), + _allocatedBlocks(0), + _blockCount(-1), + _ptr(0), + _end(0) + { } + + ~MemoryPool() + { + if (_blocks) { + for (int i = 0; i < _allocatedBlocks; ++i) { + if (char *b = _blocks[i]) + qFree(b); + } + + qFree(_blocks); + } + } + + inline void *allocate(size_t size) + { + size = (size + 7) & ~7; + if (_ptr && (_ptr + size < _end)) { + void *addr = _ptr; + _ptr += size; + return addr; + } + return allocate_helper(size); + } + + void reset() + { + _blockCount = -1; + _ptr = _end = 0; + } + +private: + void *allocate_helper(size_t size) + { + Q_ASSERT(size < BLOCK_SIZE); + + if (++_blockCount == _allocatedBlocks) { + if (! _allocatedBlocks) + _allocatedBlocks = DEFAULT_BLOCK_COUNT; + else + _allocatedBlocks *= 2; + + _blocks = (char **) qRealloc(_blocks, sizeof(char *) * _allocatedBlocks); + + for (int index = _blockCount; index < _allocatedBlocks; ++index) + _blocks[index] = 0; + } + + char *&block = _blocks[_blockCount]; + + if (! block) + block = (char *) qMalloc(BLOCK_SIZE); + + _ptr = block; + _end = _ptr + BLOCK_SIZE; + + void *addr = _ptr; + _ptr += size; + return addr; + } + +private: + char **_blocks; + int _allocatedBlocks; + int _blockCount; + char *_ptr; + char *_end; + + enum + { + BLOCK_SIZE = 8 * 1024, + DEFAULT_BLOCK_COUNT = 8 + }; +}; + +class QML_PARSER_EXPORT Managed +{ + Managed(const Managed &other); + void operator = (const Managed &other); + +public: + Managed() {} + ~Managed() {} + + void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); } + void operator delete(void *) {} + void operator delete(void *, MemoryPool *) {} +}; + +} // namespace QQmlJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/qml/qml/parser/qqmljsparser.cpp b/src/qml/qml/parser/qqmljsparser.cpp new file mode 100644 index 0000000000..bc89b2ac84 --- /dev/null +++ b/src/qml/qml/parser/qqmljsparser.cpp @@ -0,0 +1,1812 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include "qqmljsengine_p.h" +#include "qqmljslexer_p.h" +#include "qqmljsast_p.h" +#include "qqmljsmemorypool_p.h" + + + +#include "qqmljsparser_p.h" +#include + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QQmlJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); + string_stack = reinterpret_cast (realloc(string_stack, stack_size * sizeof(QStringRef))); +} + +Parser::Parser(Engine *engine): + driver(engine), + pool(engine->pool()), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + string_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + free(sym_stack); + free(state_stack); + free(location_stack); + free(string_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->tokenStartLine(); + loc.startColumn = lexer->tokenStartColumn(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray nameIds; + QVarLengthArray locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast(it)) { + AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = new (pool) AST::UiQualifiedId(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->tokenValue(); + yytokenspell = lexer->tokenSpell(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yytokenspell = first_token->spell; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + stringRef(1) = yytokenspell; + 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 = new (pool) AST::UiProgram(sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; + +case 8: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; + +case 9: { + sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport); +} break; + +case 10: { + sym(1).Node = new (pool) AST::UiImportList(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 = stringRef(4); + 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 = stringRef(3); + sym(1).UiImport->semicolonToken = loc(4); +} break; + +case 20: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast(sym(2).Expression)) { + node = new (pool) AST::UiImport(importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + node = new (pool) AST::UiImport(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 = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); +} break; + +case 23: { + sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); +} break; + +case 24: { + AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList( + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; + +case 25: { + sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember); +} break; + +case 26: { + AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList( + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 27: { + AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0); + node->lbraceToken = loc(1); + node->rbraceToken = loc(2); + sym(1).Node = node; +} break; + +case 28: { + AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 29: { + AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; + +case 31: { + AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding( + 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 = new (pool) AST::UiObjectBinding( + sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 33: { + AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding( + sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + node->hasOnToken = true; + sym(1).Node = node; +} break; + +case 41: +{ + AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding( + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 45: { + sym(1).Node = 0; +} break; + +case 46: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; + +case 47: { + AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2)); + node->propertyTypeToken = loc(1); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; + +case 48: { + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4)); + node->commaToken = loc(2); + node->identifierToken = loc(4); + sym(1).Node = node; +} break; + +case 50: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); + 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 52: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); + 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 54: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); + node->typeModifier = stringRef(2); + 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 56: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); + sym(1).Node = node; +} break; + +case 58: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); + 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 59: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3), + 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 60: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), + 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 61: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), + 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 62: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); + node->typeModifier = stringRef(2); + 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 = new (pool) AST::UiQualifiedId(stringRef(6)); + propertyName->identifierToken = loc(6); + propertyName->next = 0; + + AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding( + 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 63: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3)); + propertyName->identifierToken = loc(3); + propertyName->next = 0; + + AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( + propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer); + binding->colonToken = loc(4); + + node->binding = binding; + + sym(1).Node = node; +} break; + +case 64: { + sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); +} break; + +case 65: { + sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); +} break; + +case 71: { + AST::ThisExpression *node = new (pool) AST::ThisExpression(); + node->thisToken = loc(1); + sym(1).Node = node; +} break; + +case 72: { + AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1)); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 73: { + AST::NullExpression *node = new (pool) AST::NullExpression(); + node->nullToken = loc(1); + sym(1).Node = node; +} break; + +case 74: { + AST::TrueLiteral *node = new (pool) AST::TrueLiteral(); + node->trueToken = loc(1); + sym(1).Node = node; +} break; + +case 75: { + AST::FalseLiteral *node = new (pool) AST::FalseLiteral(); + node->falseToken = loc(1); + sym(1).Node = node; +} break; + +case 76: { + AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +case 77: +case 78: { + AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1)); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 79: { + 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(); + yylloc = loc(1); // adjust the location of the current token + + AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( + driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 80: { + 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(); + yylloc = loc(1); // adjust the location of the current token + + AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( + driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 81: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; + +case 82: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 83: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 84: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(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 85: { + AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(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 86: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = new (pool) AST::ObjectLiteral( + sym(2).PropertyNameAndValueList->finish ()); + else + node = new (pool) AST::ObjectLiteral(); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 87: { + AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral( + sym(2).PropertyNameAndValueList->finish ()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(4); + sym(1).Node = node; +} break; + +case 88: { + AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression); + node->lparenToken = loc(1); + node->rparenToken = loc(3); + sym(1).Node = node; +} break; + +case 89: { + if (AST::ArrayMemberExpression *mem = AST::cast(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 90: { + sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); +} break; + +case 91: { + sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression); +} break; + +case 92: { + AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 93: { + AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 94: { + AST::Elision *node = new (pool) AST::Elision(); + node->commaToken = loc(1); + sym(1).Node = node; +} break; + +case 95: { + AST::Elision *node = new (pool) AST::Elision(sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 96: { + AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList( + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 97: { + AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList( + sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + node->commaToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 98: { + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +case 99: +case 100: { + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 101: { + AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 102: { + AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 103: { + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 139: { + AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 140: { + AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 141: { + AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList); + node->newToken = loc(1); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + sym(1).Node = node; +} break; + +case 143: { + AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; + +case 144: { + AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 145: { + AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 146: { + AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 147: { + AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 148: { + sym(1).Node = 0; +} break; + +case 149: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; + +case 150: { + sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression); +} break; + +case 151: { + AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 155: { + AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; + +case 156: { + AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; + +case 158: { + AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; + +case 159: { + AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; + +case 160: { + AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; + +case 161: { + AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; + +case 162: { + AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; + +case 163: { + AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; + +case 164: { + AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; + +case 165: { + AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; + +case 166: { + AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; + +case 168: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Mul, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 169: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Div, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 170: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Mod, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 172: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Add, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 173: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Sub, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 175: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::LShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 176: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::RShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 177: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::URShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 179: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 180: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 181: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 182: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 183: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 184: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::In, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 186: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 187: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 188: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 189: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 190: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 192: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 193: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 194: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 195: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 197: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 198: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 199: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 200: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 202: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 204: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 206: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 208: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 210: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 212: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 214: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 216: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 218: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 220: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 222: { + AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 224: { + AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 226: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 228: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 229: { + sym(1).ival = QSOperator::Assign; +} break; + +case 230: { + sym(1).ival = QSOperator::InplaceMul; +} break; + +case 231: { + sym(1).ival = QSOperator::InplaceDiv; +} break; + +case 232: { + sym(1).ival = QSOperator::InplaceMod; +} break; + +case 233: { + sym(1).ival = QSOperator::InplaceAdd; +} break; + +case 234: { + sym(1).ival = QSOperator::InplaceSub; +} break; + +case 235: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; + +case 236: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; + +case 237: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; + +case 238: { + sym(1).ival = QSOperator::InplaceAnd; +} break; + +case 239: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 240: { + sym(1).ival = QSOperator::InplaceOr; +} break; + +case 242: { + AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 243: { + sym(1).Node = 0; +} break; + +case 246: { + AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 247: { + sym(1).Node = 0; +} break; + +case 264: { + AST::Block *node = new (pool) AST::Block(sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 265: { + sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); +} break; + +case 266: { + sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement); +} break; + +case 267: { + sym(1).Node = 0; +} break; + +case 268: { + sym(1).Node = sym(1).StatementList->finish (); +} break; + +case 270: { + AST::VariableStatement *node = new (pool) AST::VariableStatement( + sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + node->declarationKindToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 271: { + sym(1).ival = T_CONST; +} break; + +case 272: { + sym(1).ival = T_VAR; +} break; + +case 273: { + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); +} break; + +case 274: { + AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList( + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 275: { + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); +} break; + +case 276: { + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; + +case 277: { + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 278: { + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 279: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 280: { + sym(1).Node = 0; +} break; + +case 282: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 283: { + sym(1).Node = 0; +} break; + +case 285: { + AST::EmptyStatement *node = new (pool) AST::EmptyStatement(); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; + +case 287: { + AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 288: { + AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(6); + sym(1).Node = node; +} break; + +case 289: { + AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 291: { + AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(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 292: { + AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement); + node->whileToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 293: { + AST::ForStatement *node = new (pool) AST::ForStatement(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 294: { + AST::LocalForStatement *node = new (pool) AST::LocalForStatement( + 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 295: { + AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(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 296: { + AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement( + 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 298: { + AST::ContinueStatement *node = new (pool) AST::ContinueStatement(); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 300: { + AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2)); + node->continueToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 302: { + AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 304: { + AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2)); + node->breakToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 306: { + AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression); + node->returnToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 307: { + AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement); + node->withToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 308: { + AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock); + node->switchToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 309: { + AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 310: { + AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(5); + sym(1).Node = node; +} break; + +case 311: { + sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause); +} break; + +case 312: { + sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause); +} break; + +case 313: { + sym(1).Node = 0; +} break; + +case 314: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; + +case 315: { + AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList); + node->caseToken = loc(1); + node->colonToken = loc(3); + sym(1).Node = node; +} break; + +case 316: { + AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList); + node->defaultToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +case 317: +case 318: { + AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 319: { + AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 321: { + AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression); + node->throwToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 322: { + AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 323: { + AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 324: { + AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 325: { + AST::Catch *node = new (pool) AST::Catch(stringRef(3), 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 326: { + AST::Finally *node = new (pool) AST::Finally(sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; + +case 328: { + AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement(); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 329: { + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), 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 330: { + AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (! stringRef(2).isNull()) + 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 331: { + AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1)); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 332: { + AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); + node->commaToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 333: { + sym(1).Node = 0; +} break; + +case 334: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; + +case 335: { + sym(1).Node = 0; +} break; + +case 337: { + sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); +} break; + +case 339: { + sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); +} break; + +case 340: { + sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); +} break; + +case 341: { + sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); +} break; + +case 342: { + sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); +} break; + +case 343: { + sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); +} break; + +case 344: { + stringRef(1) = QStringRef(); +} break; + +case 346: { + 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) && lexer->canInsertAutomaticSemicolon(yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.spell = yytokenspell; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QQmlParser", "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].spell = yytokenspell; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->tokenValue(); + token_buffer[1].spell = yytokenspell = lexer->tokenSpell(); + 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("QQmlParser", "Syntax error"); + else + msg = qApp->translate("QQmlParser", "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("QQmlParser", "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("QQmlParser", "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("QQmlParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + diff --git a/src/qml/qml/parser/qqmljsparser_p.h b/src/qml/qml/parser/qqmljsparser_p.h new file mode 100644 index 0000000000..ad532c32c7 --- /dev/null +++ b/src/qml/qml/parser/qqmljsparser_p.h @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $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 QQMLJSPARSER_P_H +#define QQMLJSPARSER_P_H + +#include "qqmljsglobal_p.h" +#include "qqmljsgrammar_p.h" +#include "qqmljsast_p.h" +#include "qqmljsengine_p.h" + +#include +#include + +QT_QML_BEGIN_NAMESPACE + +namespace QQmlJS { + +class Engine; + +class QML_PARSER_EXPORT Parser: protected QQmlJSGrammar +{ +public: + union Value { + int ival; + double dval; + 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; + }; + +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(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 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 QStringRef &stringRef(int index) + { return string_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; + MemoryPool *pool; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + QStringRef *string_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + QStringRef spell; + }; + + double yylval; + QStringRef yytokenspell; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList diagnostic_messages; +}; + +} // end of namespace QQmlJS + + + +#define J_SCRIPT_REGEXPLITERAL_RULE1 79 + +#define J_SCRIPT_REGEXPLITERAL_RULE2 80 + +QT_QML_END_NAMESPACE + + + +#endif // QQMLJSPARSER_P_H diff --git a/src/qml/qml/qlistmodelinterface.cpp b/src/qml/qml/qlistmodelinterface.cpp new file mode 100644 index 0000000000..3ea0d3f155 --- /dev/null +++ b/src/qml/qml/qlistmodelinterface.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtDeclaractive module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlistmodelinterface_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QListModelInterface + \brief The QListModelInterface class can be subclassed to provide C++ models to QQuickGraphics Views + + This class is comprised primarily of pure virtual functions which + you must implement in a subclass. You can then use the subclass + as a model for a QQuickGraphics view, such as a QQuickListView. +*/ + +/*! \fn QListModelInterface::QListModelInterface(QObject *parent) + Constructs a QListModelInterface with the specified \a parent. +*/ + + /*! \fn QListModelInterface::QListModelInterface(QObjectPrivate &dd, QObject *parent) + + \internal + */ + +/*! \fn QListModelInterface::~QListModelInterface() + The destructor is virtual. + */ + +/*! \fn int QListModelInterface::count() const + Returns the number of data entries in the model. +*/ + +/*! \fn QVariant QListModelInterface::data(int index, int role) const + Returns the data at the given \a index for the specified \a roles. +*/ + +/*! \fn QList QListModelInterface::roles() const + Returns the list of roles for which the list model interface + provides data. +*/ + +/*! \fn QString QListModelInterface::toString(int role) const + Returns a string description of the specified \a role. +*/ + +/*! \fn void QListModelInterface::itemsInserted(int index, int count) + Emit this signal when \a count items are inserted at \a index. + */ + +/*! \fn void QListModelInterface::itemsRemoved(int index, int count) + Emit this signal when \a count items are removed at \a index. + */ + +/*! \fn void QListModelInterface::itemsMoved(int from, int to, int count) + Emit this signal when \a count items are moved from index \a from + to index \a to. + */ + +/*! \fn void QListModelInterface::itemsChanged(int index, int count, const QList &roles) + Emit this signal when \a count items at \a index have had their + \a roles changed. + */ + +QT_END_NAMESPACE diff --git a/src/qml/qml/qlistmodelinterface_p.h b/src/qml/qml/qlistmodelinterface_p.h new file mode 100644 index 0000000000..c644ce88e6 --- /dev/null +++ b/src/qml/qml/qlistmodelinterface_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLISTMODELINTERFACE_H +#define QLISTMODELINTERFACE_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class Q_QML_PRIVATE_EXPORT QListModelInterface : public QObject +{ + Q_OBJECT + public: + QListModelInterface(QObject *parent = 0) : QObject(parent) {} + virtual ~QListModelInterface() {} + + virtual int count() const = 0; + virtual QVariant data(int index, int role) const = 0; + + virtual QList roles() const = 0; + virtual QString toString(int role) const = 0; + + Q_SIGNALS: + void itemsInserted(int index, int count); + void itemsRemoved(int index, int count); + void itemsMoved(int from, int to, int count); + void itemsChanged(int index, int count, const QList &roles); + + protected: + QListModelInterface(QObjectPrivate &dd, QObject *parent) + : QObject(dd, parent) {} +}; + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif //QTREEMODELINTERFACE_H diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri new file mode 100644 index 0000000000..0ce7c7ed5c --- /dev/null +++ b/src/qml/qml/qml.pri @@ -0,0 +1,125 @@ +SOURCES += \ + $$PWD/qquickapplication.cpp \ + $$PWD/qqmlinstruction.cpp \ + $$PWD/qquicklistmodel.cpp \ + $$PWD/qquicklistmodelworkeragent.cpp \ + $$PWD/qqmlopenmetaobject.cpp \ + $$PWD/qqmlvmemetaobject.cpp \ + $$PWD/qqmlengine.cpp \ + $$PWD/qqmlexpression.cpp \ + $$PWD/qqmlbinding.cpp \ + $$PWD/qqmlproperty.cpp \ + $$PWD/qqmlcomponent.cpp \ + $$PWD/qqmlincubator.cpp \ + $$PWD/qqmlcontext.cpp \ + $$PWD/qqmlcustomparser.cpp \ + $$PWD/qqmlpropertyvaluesource.cpp \ + $$PWD/qqmlpropertyvalueinterceptor.cpp \ + $$PWD/qqmlproxymetaobject.cpp \ + $$PWD/qqmlvme.cpp \ + $$PWD/qqmlcompiler.cpp \ + $$PWD/qqmlcompileddata.cpp \ + $$PWD/qqmlboundsignal.cpp \ + $$PWD/qqmlmetatype.cpp \ + $$PWD/qqmlstringconverters.cpp \ + $$PWD/qqmlparserstatus.cpp \ + $$PWD/qqmltypeloader.cpp \ + $$PWD/qqmlinfo.cpp \ + $$PWD/qqmlerror.cpp \ + $$PWD/qqmlscript.cpp \ + $$PWD/qqmlrewrite.cpp \ + $$PWD/qqmlvaluetype.cpp \ + $$PWD/qqmlaccessors.cpp \ + $$PWD/qqmlxmlhttprequest.cpp \ + $$PWD/qqmlwatcher.cpp \ + $$PWD/qqmlcleanup.cpp \ + $$PWD/qqmlpropertycache.cpp \ + $$PWD/qqmlnotifier.cpp \ + $$PWD/qqmlintegercache.cpp \ + $$PWD/qqmltypenotavailable.cpp \ + $$PWD/qqmltypenamecache.cpp \ + $$PWD/qqmlscriptstring.cpp \ + $$PWD/qquickworkerscript.cpp \ + $$PWD/qqmlimageprovider.cpp \ + $$PWD/qqmlnetworkaccessmanagerfactory.cpp \ + $$PWD/qqmldirparser.cpp \ + $$PWD/qqmlextensionplugin.cpp \ + $$PWD/qqmlimport.cpp \ + $$PWD/qqmllist.cpp \ + $$PWD/qqmllocale.cpp \ + $$PWD/qlistmodelinterface.cpp + +HEADERS += \ + $$PWD/qqmlglobal_p.h \ + $$PWD/qqmlinstruction_p.h \ + $$PWD/qquicklistmodel_p.h\ + $$PWD/qquicklistmodel_p_p.h\ + $$PWD/qquicklistmodelworkeragent_p.h \ + $$PWD/qqmlopenmetaobject_p.h \ + $$PWD/qqmlvmemetaobject_p.h \ + $$PWD/qqml.h \ + $$PWD/qquickapplication_p.h \ + $$PWD/qqmlbinding_p.h \ + $$PWD/qqmlbinding_p_p.h \ + $$PWD/qqmlproperty.h \ + $$PWD/qqmlcomponent.h \ + $$PWD/qqmlcomponent_p.h \ + $$PWD/qqmlincubator.h \ + $$PWD/qqmlincubator_p.h \ + $$PWD/qqmlcustomparser_p.h \ + $$PWD/qqmlcustomparser_p_p.h \ + $$PWD/qqmlpropertyvaluesource.h \ + $$PWD/qqmlpropertyvalueinterceptor_p.h \ + $$PWD/qqmlboundsignal_p.h \ + $$PWD/qqmlparserstatus.h \ + $$PWD/qqmlproxymetaobject_p.h \ + $$PWD/qqmlvme_p.h \ + $$PWD/qqmlcompiler_p.h \ + $$PWD/qqmlengine_p.h \ + $$PWD/qqmlexpression_p.h \ + $$PWD/qqmlprivate.h \ + $$PWD/qqmlmetatype_p.h \ + $$PWD/qqmlengine.h \ + $$PWD/qqmlcontext.h \ + $$PWD/qqmlexpression.h \ + $$PWD/qqmlstringconverters_p.h \ + $$PWD/qqmlinfo.h \ + $$PWD/qqmlproperty_p.h \ + $$PWD/qqmlcontext_p.h \ + $$PWD/qqmltypeloader_p.h \ + $$PWD/qqmllist.h \ + $$PWD/qqmllist_p.h \ + $$PWD/qqmldata_p.h \ + $$PWD/qqmlerror.h \ + $$PWD/qqmlscript_p.h \ + $$PWD/qqmlrewrite_p.h \ + $$PWD/qqmlvaluetype_p.h \ + $$PWD/qqmlaccessors_p.h \ + $$PWD/qqmlxmlhttprequest_p.h \ + $$PWD/qqmlwatcher_p.h \ + $$PWD/qqmlcleanup_p.h \ + $$PWD/qqmlpropertycache_p.h \ + $$PWD/qqmlnotifier_p.h \ + $$PWD/qqmlintegercache_p.h \ + $$PWD/qqmltypenotavailable_p.h \ + $$PWD/qqmltypenamecache_p.h \ + $$PWD/qqmlscriptstring.h \ + $$PWD/qquickworkerscript_p.h \ + $$PWD/qqmlguard_p.h \ + $$PWD/qqmlimageprovider.h \ + $$PWD/qqmlnetworkaccessmanagerfactory.h \ + $$PWD/qqmldirparser_p.h \ + $$PWD/qqmlextensioninterface.h \ + $$PWD/qqmlimport_p.h \ + $$PWD/qqmlextensionplugin.h \ + $$PWD/qqmlnullablevalue_p_p.h \ + $$PWD/qqmlscriptstring_p.h \ + $$PWD/qqmllocale_p.h \ + $$PWD/qlistmodelinterface_p.h \ + $$PWD/qqmlcomponentattached_p.h + +include(parser/parser.pri) +include(rewriter/rewriter.pri) +include(ftw/ftw.pri) +include(v4/v4.pri) +include(v8/v8.pri) diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h new file mode 100644 index 0000000000..32da2c616e --- /dev/null +++ b/src/qml/qml/qqml.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQML_H +#define QQML_H + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +#define QML_VERSION 0x020000 +#define QML_VERSION_STR "2.0" + +#define QML_DECLARE_TYPE(TYPE) \ + Q_DECLARE_METATYPE(TYPE *) \ + Q_DECLARE_METATYPE(QQmlListProperty) + +#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \ + Q_DECLARE_METATYPE(QQmlListProperty) + +#define QML_DECLARE_INTERFACE(INTERFACE) \ + QML_DECLARE_TYPE(INTERFACE) + +#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \ + QML_DECLARE_TYPE_HASMETATYPE(INTERFACE) + +enum { /* TYPEINFO flags */ + QML_HAS_ATTACHED_PROPERTIES = 0x01 +}; + +#define QML_DECLARE_TYPEINFO(TYPE, FLAGS) \ +QT_BEGIN_NAMESPACE \ +template <> \ +class QQmlTypeInfo \ +{ \ +public: \ + enum { \ + hasAttachedProperties = (((FLAGS) & QML_HAS_ATTACHED_PROPERTIES) == QML_HAS_ATTACHED_PROPERTIES) \ + }; \ +}; \ +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + + +class QQmlPropertyValueInterceptor; + +template +int qmlRegisterType() +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + 0, 0, + QString(), + + 0, 0, 0, 0, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message); + +template +int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + 0, 0, + reason, + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +template +int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QQmlPrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +template +int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 1, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QQmlPrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +template +int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 1, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QQmlPrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, 0, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + + +template +int qmlRegisterExtendedType() +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + 0, 0, + QString(), + + 0, 0, 0, 0, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + QQmlPrivate::createParent, &E::staticMetaObject, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +template +int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, + const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc(); + const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject(); + if (!attached) { + attached = QQmlPrivate::attachedPropertiesFunc(); + attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject(); + } + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QQmlPrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + attached, + attachedMetaObject, + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + QQmlPrivate::createParent, &E::staticMetaObject, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +template +int qmlRegisterInterface(const char *typeName) +{ + QByteArray name(typeName); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterInterface qmlInterface = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + + qobject_interface_iid() + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); +} + +template +int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, + const char *qmlName, QQmlCustomParser *parser) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QQmlListProperty<" + name + ">"); + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QQmlPrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QQmlPrivate::attachedPropertiesFunc(), + QQmlPrivate::attachedPropertiesMetaObject(), + + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + QQmlPrivate::StaticCastSelector::cast(), + + 0, 0, + + parser, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + +class QQmlContext; +class QQmlEngine; +class QJSValue; +class QJSEngine; +Q_QML_EXPORT void qmlExecuteDeferred(QObject *); +Q_QML_EXPORT QQmlContext *qmlContext(const QObject *); +Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *); +Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); +Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *, const QMetaObject *, bool create); + +template +QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) +{ + static int idx = -1; + return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create); +} + +// For the use of QtQuick1 module +Q_QML_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor); + +inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, + QJSValue (*callback)(QQmlEngine *, QJSEngine *)) +{ + QQmlPrivate::RegisterModuleApi api = { + 0, + + uri, versionMajor, versionMinor, + + callback, 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); +} + +inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, + QObject *(*callback)(QQmlEngine *, QJSEngine *)) +{ + QQmlPrivate::RegisterModuleApi api = { + 0, + + uri, versionMajor, versionMinor, + + 0, callback + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); +} + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QObject) +Q_DECLARE_METATYPE(QVariant) + +QT_END_HEADER + +#endif // QQML_H diff --git a/src/qml/qml/qqmlaccessors.cpp b/src/qml/qml/qqmlaccessors.cpp new file mode 100644 index 0000000000..ceb4f44789 --- /dev/null +++ b/src/qml/qml/qqmlaccessors.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlaccessors_p.h" + +#include "qqmldata_p.h" +#include "qqmlnotifier_p.h" + +QT_BEGIN_NAMESPACE + +struct AccessorProperties { + AccessorProperties(); + + QReadWriteLock lock; + QHash properties; +}; + +Q_GLOBAL_STATIC(AccessorProperties, accessorProperties) + +QML_PRIVATE_ACCESSOR(QObject, QString, objectName, objectName) + +static void QObject_objectNameNotifier(QObject *object, intptr_t, QQmlNotifier **notifier) +{ + *notifier = QQmlData::get(object, true)->objectNameNotifier(); +} + +static QQmlAccessors QObject_objectName = { QObject_objectNameRead, + QObject_objectNameNotifier }; + +QML_DECLARE_PROPERTIES(QObject) { + { QML_PROPERTY_NAME(objectName), 0, &QObject_objectName } +}; + +static void buildNameMask(QQmlAccessorProperties::Properties &properties) +{ + quint32 mask = 0; + + for (int ii = 0; ii < properties.count; ++ii) { + Q_ASSERT(strlen(properties.properties[ii].name) == properties.properties[ii].nameLength); + Q_ASSERT(properties.properties[ii].nameLength > 0); + + mask |= (1 << qMin(31U, properties.properties[ii].nameLength - 1)); + } + + properties.nameMask = mask; +} + +AccessorProperties::AccessorProperties() +{ + // Pre-seed QObject::objectName accessor + typedef QQmlAccessorProperties::Properties P; + properties.insert(&QObject::staticMetaObject, + P(qqml_accessor_properties_QObject, + sizeof(qqml_accessor_properties_QObject) / + sizeof(QQmlAccessorProperties::Property))); +} + +QQmlAccessorProperties::Properties::Properties(Property *properties, int count) +: count(count), properties(properties) +{ + buildNameMask(*this); +} + +QQmlAccessorProperties::Properties +QQmlAccessorProperties::properties(const QMetaObject *mo) +{ + AccessorProperties *This = accessorProperties(); + + QReadLocker lock(&This->lock); + return This->properties.value(mo); +} + +void QQmlAccessorProperties::registerProperties(const QMetaObject *mo, int count, + Property *props) +{ + Q_ASSERT(count > 0); + + Properties properties(props, count); + + AccessorProperties *This = accessorProperties(); + + QWriteLocker lock(&This->lock); + + Q_ASSERT(!This->properties.contains(mo) || This->properties.value(mo) == properties); + + This->properties.insert(mo, properties); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h new file mode 100644 index 0000000000..a603bede9f --- /dev/null +++ b/src/qml/qml/qqmlaccessors_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLACCESSORS_P_H +#define QQMLACCESSORS_P_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QObject; +class QQmlNotifier; + +// QML "accessor properties" allow V4 and V8 to bypass Qt's meta system to read and, more +// importantly, subscribe to properties directly. Any property that is primarily read +// from bindings is a candidate for inclusion as an accessor property. +// +// To define accessor properties, use the QML_DECLARE_PROPERTIES() and QML_DEFINE_PROPERTIES() +// macros. The QML_DECLARE_PROPERTIES() macro is used to specify the properties, and the +// QML_DEFINE_PROPERTIES() macro to register the properties with the +// QQmlAccessorProperties singleton. +// +// A class with accessor properties must also add the Q_CLASSINFO("qt_HasQmlAccessors", "true") +// tag to its declaration. This is essential for QML to maintain internal consistency, +// and forgetting to do so will probably cause your application to qFatal() with a +// helpful reminder of this requirement. +// +// It is important that QML_DEFINE_PROPERTIES() has been called before QML ever sees +// the type with the accessor properties. As QML_DEFINE_PROPERTIES() is idempotent, it is +// recommended to call it in the type's constructor as well as when the type is registered +// as a QML element (if it ever is). QML_DEFINE_PROPERTIES() is a very cheap operation +// if registration has already occurred. + +#define QML_DECLARE_PROPERTIES(type) \ + static volatile bool qqml_accessor_properties_isregistered_ ## type = false; \ + static QQmlAccessorProperties::Property qqml_accessor_properties_ ## type[] = + +#define QML_DEFINE_PROPERTIES(type) \ + do { \ + if (!qqml_accessor_properties_isregistered_ ## type) { \ + int count = sizeof(qqml_accessor_properties_ ## type) / \ + sizeof(QQmlAccessorProperties::Property); \ + QQmlAccessorProperties::registerProperties(&type::staticMetaObject, count, \ + qqml_accessor_properties_ ## type);\ + qqml_accessor_properties_isregistered_ ## type = true; \ + } \ + } while (false); + +#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \ + static void clazz ## _ ## name ## Read(QObject *o, intptr_t, void *rv) \ + { \ + clazz ## Private *d = clazz ## Private::get(static_cast(o)); \ + *static_cast(rv) = d->variable; \ + } + +#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1 + +class QQmlAccessors +{ +public: + void (*read)(QObject *object, intptr_t property, void *output); + void (*notifier)(QObject *object, intptr_t property, QQmlNotifier **notifier); +}; + +namespace QQmlAccessorProperties { + struct Property { + const char *name; + unsigned int nameLength; + intptr_t data; + QQmlAccessors *accessors; + }; + + struct Properties { + inline Properties(); + Properties(Property *, int); + + bool operator==(const Properties &o) const { + return count == o.count && properties == o.properties; + } + + inline Property *property(const char *name); + + int count; + Property *properties; + quint32 nameMask; + }; + + Properties properties(const QMetaObject *); + void Q_QML_EXPORT registerProperties(const QMetaObject *, int, Property *); +}; + +QQmlAccessorProperties::Property * +QQmlAccessorProperties::Properties::property(const char *name) +{ + if (count == 0) + return 0; + + unsigned int length = strlen(name); + + Q_ASSERT(length); + + if (nameMask & (1 << qMin(31U, length - 1))) { + + for (int ii = 0; ii < count; ++ii) { + if (properties[ii].nameLength == length && 0 == qstrcmp(name, properties[ii].name)) + return &properties[ii]; + } + + } + + return 0; +} + +QQmlAccessorProperties::Properties::Properties() +: count(0), properties(0), nameMask(0) +{ +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQMLACCESSORS_P_H diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp new file mode 100644 index 0000000000..a19644fb3e --- /dev/null +++ b/src/qml/qml/qqmlbinding.cpp @@ -0,0 +1,551 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlbinding_p.h" +#include "qqmlbinding_p_p.h" + +#include "qqml.h" +#include "qqmlcontext.h" +#include "qqmlinfo.h" +#include "qqmlcompiler_p.h" +#include "qqmldata_p.h" +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QQmlAbstractBinding::QQmlAbstractBinding() +: m_prevBinding(0), m_nextBinding(0) +{ +} + +QQmlAbstractBinding::~QQmlAbstractBinding() +{ + Q_ASSERT(m_prevBinding == 0); + Q_ASSERT(*m_mePtr == 0); +} + +/*! +Destroy the binding. Use this instead of calling delete. + +Bindings are free to implement their own memory management, so the delete operator is not +necessarily safe. The default implementation clears the binding, removes it from the object +and calls delete. +*/ +void QQmlAbstractBinding::destroy() +{ + removeFromObject(); + clear(); + + delete this; +} + +/*! +Add this binding to \a object. + +This transfers ownership of the binding to the object, marks the object's property as +being bound. + +However, it does not enable the binding itself or call update() on it. +*/ +void QQmlAbstractBinding::addToObject() +{ + Q_ASSERT(!m_prevBinding); + + QObject *obj = object(); + Q_ASSERT(obj); + + int index = propertyIndex(); + + QQmlData *data = QQmlData::get(obj, true); + + if (index & 0xFF000000) { + // Value type + + int coreIndex = index & 0xFFFFFF; + + // Find the value type proxy (if there is one) + QQmlValueTypeProxyBinding *proxy = 0; + if (data->hasBindingBit(coreIndex)) { + QQmlAbstractBinding *b = data->bindings; + while (b && b->propertyIndex() != coreIndex) + b = b->m_nextBinding; + Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy); + proxy = static_cast(b); + } + + if (!proxy) { + proxy = new QQmlValueTypeProxyBinding(obj, coreIndex); + + Q_ASSERT(proxy->propertyIndex() == coreIndex); + Q_ASSERT(proxy->object() == obj); + + proxy->addToObject(); + } + + m_nextBinding = proxy->m_bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &proxy->m_bindings; + proxy->m_bindings = this; + + } else { + m_nextBinding = data->bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &data->bindings; + data->bindings = this; + + data->setBindingBit(obj, index); + } +} + +/*! +Remove the binding from the object. +*/ +void QQmlAbstractBinding::removeFromObject() +{ + if (m_prevBinding) { + int index = propertyIndex(); + + *m_prevBinding = m_nextBinding; + if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding; + m_prevBinding = 0; + m_nextBinding = 0; + + if (index & 0xFF000000) { + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing until it is removed by a write, a binding change or it is reused + // to hold more sub-bindings. + } else if (QObject *obj = object()) { + QQmlData *data = QQmlData::get(obj, false); + if (data) data->clearBindingBit(index); + } + } +} + +static void bindingDummyDeleter(QQmlAbstractBinding *) +{ +} + +QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer() +{ + if (m_mePtr.value().isNull()) + m_mePtr.value() = QSharedPointer(this, bindingDummyDeleter); + + return m_mePtr.value().toWeakRef(); +} + +void QQmlAbstractBinding::clear() +{ + if (!m_mePtr.isNull()) { + **m_mePtr = 0; + m_mePtr = 0; + } +} + +void QQmlAbstractBinding::retargetBinding(QObject *, int) +{ + qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding."); +} + +QString QQmlAbstractBinding::expression() const +{ + return QLatin1String(""); +} + +void QQmlAbstractBinding::setEnabled(bool enabled, QQmlPropertyPrivate::WriteFlags flags) +{ + if (enabled) update(flags); +} + +QQmlBinding::Identifier QQmlBinding::Invalid = -1; + +void QQmlBindingPrivate::refresh() +{ + Q_Q(QQmlBinding); + q->update(); +} + +QQmlBindingPrivate::QQmlBindingPrivate() +: updating(false), enabled(false), target(), targetProperty(0) +{ +} + +QQmlBindingPrivate::~QQmlBindingPrivate() +{ +} + +QQmlBinding * +QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt, + const QString &url, int lineNumber, QObject *parent) +{ + if (id < 0) + return 0; + + QQmlContextData *ctxtdata = QQmlContextData::get(ctxt); + + QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine()); + QQmlCompiledData *cdata = 0; + QQmlTypeData *typeData = 0; + if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { + typeData = engine->typeLoader.get(ctxtdata->url); + cdata = typeData->compiledData(); + } + QQmlBinding *rv = cdata ? new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0, parent) : 0; + if (cdata) + cdata->release(); + if (typeData) + typeData->release(); + return rv; +} + +QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt, + QObject *parent) +: QQmlExpression(QQmlContextData::get(ctxt), obj, str, *new QQmlBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt, + QObject *parent) +: QQmlExpression(ctxt, obj, str, *new QQmlBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj, + QQmlContextData *ctxt, + const QString &url, int lineNumber, int columnNumber, + QObject *parent) +: QQmlExpression(ctxt, obj, str, isRewritten, url, lineNumber, columnNumber, *new QQmlBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +/*! + \internal + + To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle. + For example: + v8::Handle function; + new QQmlBinding(&function, scope, ctxt); + */ +QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt, + QObject *parent) +: QQmlExpression(ctxt, obj, functionPtr, *new QQmlBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QQmlBinding::~QQmlBinding() +{ +} + +void QQmlBinding::setTarget(const QQmlProperty &prop) +{ + Q_D(QQmlBinding); + d->property = prop; + d->target = d->property.object(); + d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex(); + + update(); +} + +void QQmlBinding::setTarget(QObject *object, + const QQmlPropertyData &core, + QQmlContextData *ctxt) +{ + Q_D(QQmlBinding); + d->property = QQmlPropertyPrivate::restore(object, core, ctxt); + d->target = d->property.object(); + d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex(); + + update(); +} + +QQmlProperty QQmlBinding::property() const +{ + Q_D(const QQmlBinding); + return d->property; +} + +void QQmlBinding::setEvaluateFlags(EvaluateFlags flags) +{ + Q_D(QQmlBinding); + d->setRequiresThisObject(flags & RequiresThisObject); +} + +QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const +{ + Q_D(const QQmlBinding); + return d->requiresThisObject()?RequiresThisObject:None; +} + +void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) +{ + Q_D(QQmlBinding); + + if (!d->enabled || !d->context() || !d->context()->isValid()) + return; + + QQmlTrace trace("General Binding Update"); + trace.addDetail("URL", d->url); + trace.addDetail("Line", d->line); + trace.addDetail("Column", d->columnNumber); + + if (!d->updating) { + QQmlBindingProfiler prof(d->url, d->line, d->column); + prof.addDetail(expression()); + d->updating = true; + + QQmlAbstractExpression::DeleteWatcher watcher(d); + + if (d->property.propertyType() == qMetaTypeId()) { + + int idx = d->property.index(); + Q_ASSERT(idx != -1); + + QQmlBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(d->property.object(), + QMetaObject::WriteProperty, + idx, a); + + } else { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->context()->engine); + ep->referenceScarceResources(); + + bool isUndefined = false; + + v8::HandleScope handle_scope; + v8::Context::Scope scope(ep->v8engine()->context()); + v8::Local result = d->v8value(0, &isUndefined); + + trace.event("writing binding result"); + + bool needsErrorData = false; + if (!watcher.wasDeleted() && !d->hasError()) + needsErrorData = !QQmlPropertyPrivate::writeBinding(d->property, d->context(), + d, result, + isUndefined, flags); + + if (!watcher.wasDeleted()) { + + if (needsErrorData) { + QUrl url = QUrl(d->url); + int line = d->line; + if (url.isEmpty()) url = QUrl(QLatin1String("")); + + d->delayedError()->error.setUrl(url); + d->delayedError()->error.setLine(line); + d->delayedError()->error.setColumn(-1); + } + + if (d->hasError()) { + if (!d->delayedError()->addError(ep)) ep->warning(this->error()); + } else { + d->clearError(); + } + + } + + ep->dereferenceScarceResources(); + } + + if (!watcher.wasDeleted()) + d->updating = false; + } else { + QQmlBindingPrivate::printBindingLoopError(d->property); + } +} + +void QQmlBindingPrivate::printBindingLoopError(QQmlProperty &prop) +{ + qmlInfo(prop.object()) << QQmlBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name()); +} + +void QQmlBindingPrivate::expressionChanged() +{ + Q_Q(QQmlBinding); + q->update(); +} + +void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) +{ + Q_D(QQmlBinding); + d->enabled = e; + setNotifyOnValueChanged(e); + + if (e) + update(flags); +} + +bool QQmlBinding::enabled() const +{ + Q_D(const QQmlBinding); + + return d->enabled; +} + +QString QQmlBinding::expression() const +{ + return QQmlExpression::expression(); +} + +int QQmlBinding::propertyIndex() const +{ + Q_D(const QQmlBinding); + return d->targetProperty; +} + +QObject *QQmlBinding::object() const +{ + Q_D(const QQmlBinding); + return d->target; +} + +void QQmlBinding::retargetBinding(QObject *t, int i) +{ + Q_D(QQmlBinding); + d->target = t; + d->targetProperty = i; +} + +QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index) +: m_object(o), m_index(index), m_bindings(0) +{ +} + +QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding() +{ + while (m_bindings) { + QQmlAbstractBinding *binding = m_bindings; + binding->setEnabled(false, 0); + binding->destroy(); + } +} + +void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) +{ + if (e) { + QQmlAbstractBinding *bindings = m_bindings; + recursiveEnable(bindings, flags); + } else { + QQmlAbstractBinding *bindings = m_bindings; + recursiveDisable(bindings); + } +} + +void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags) +{ + if (!b) + return; + + recursiveEnable(b->m_nextBinding, flags); + + if (b) + b->setEnabled(true, flags); +} + +void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b) +{ + if (!b) + return; + + recursiveDisable(b->m_nextBinding); + + if (b) + b->setEnabled(false, 0); +} + +void QQmlValueTypeProxyBinding::update(QQmlPropertyPrivate::WriteFlags) +{ +} + +QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex) +{ + QQmlAbstractBinding *binding = m_bindings; + + while (binding && binding->propertyIndex() != propertyIndex) + binding = binding->m_nextBinding; + + return binding; +} + +/*! +Removes a collection of bindings, corresponding to the set bits in \a mask. +*/ +void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) +{ + QQmlAbstractBinding *binding = m_bindings; + while (binding) { + if (mask & (1 << (binding->propertyIndex() >> 24))) { + QQmlAbstractBinding *remove = binding; + binding = remove->m_nextBinding; + *remove->m_prevBinding = remove->m_nextBinding; + if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding; + remove->m_prevBinding = 0; + remove->m_nextBinding = 0; + remove->destroy(); + } else { + binding = binding->m_nextBinding; + } + } +} + +int QQmlValueTypeProxyBinding::propertyIndex() const +{ + return m_index; +} + +QObject *QQmlValueTypeProxyBinding::object() const +{ + return m_object; +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h new file mode 100644 index 0000000000..33823d7e7e --- /dev/null +++ b/src/qml/qml/qqmlbinding_p.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLBINDING_P_H +#define QQMLBINDING_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 "qqml.h" +#include "qqmlpropertyvaluesource.h" +#include "qqmlexpression.h" +#include "qqmlproperty.h" +#include "qqmlproperty_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding +{ +public: + typedef QWeakPointer Pointer; + + QQmlAbstractBinding(); + + virtual void destroy(); + + virtual QString expression() const; + + enum Type { PropertyBinding, ValueTypeProxy }; + virtual Type bindingType() const { return PropertyBinding; } + + // Should return the encoded property index for the binding. Should return this value + // even if the binding is not enabled or added to an object. + // Encoding is: coreIndex | (valueTypeIndex << 24) + virtual int propertyIndex() const = 0; + // Should return the object for the binding. Should return this object even if the + // binding is not enabled or added to the object. + virtual QObject *object() const = 0; + + void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); } + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags) = 0; + + void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } + virtual void update(QQmlPropertyPrivate::WriteFlags) = 0; + + void addToObject(); + void removeFromObject(); + + static inline Pointer getPointer(QQmlAbstractBinding *p); + +protected: + virtual ~QQmlAbstractBinding(); + void clear(); + + // Called by QQmlPropertyPrivate to "move" a binding to a different property. + // This is only used for alias properties, and only used by QQmlBinding not + // V8 or V4 bindings. The default implementation qFatal()'s to ensure that the + // method is never called for V4 or V8 bindings. + virtual void retargetBinding(QObject *, int); +private: + Pointer weakPointer(); + + friend class QQmlData; + friend class QQmlComponentPrivate; + friend class QQmlValueTypeProxyBinding; + friend class QQmlPropertyPrivate; + friend class QQmlVME; + friend class QtSharedPointer::ExternalRefCount; + + typedef QSharedPointer SharedPointer; + // To save memory, we also store the rarely used weakPointer() instance in here + QPointerValuePair m_mePtr; + + QQmlAbstractBinding **m_prevBinding; + QQmlAbstractBinding *m_nextBinding; +}; + +class QQmlValueTypeProxyBinding : public QQmlAbstractBinding +{ +public: + QQmlValueTypeProxyBinding(QObject *o, int coreIndex); + + virtual Type bindingType() const { return ValueTypeProxy; } + + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags); + virtual void update(QQmlPropertyPrivate::WriteFlags); + virtual int propertyIndex() const; + virtual QObject *object() const; + + QQmlAbstractBinding *binding(int propertyIndex); + + void removeBindings(quint32 mask); + +protected: + ~QQmlValueTypeProxyBinding(); + +private: + void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); + void recursiveDisable(QQmlAbstractBinding *); + + friend class QQmlAbstractBinding; + QObject *m_object; + int m_index; + QQmlAbstractBinding *m_bindings; +}; + +class QQmlContext; +class QQmlBindingPrivate; +class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlExpression, + public QQmlAbstractBinding +{ +Q_OBJECT +public: + enum EvaluateFlag { None = 0x00, RequiresThisObject = 0x01 }; + Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag) + + QQmlBinding(const QString &, QObject *, QQmlContext *, QObject *parent=0); + QQmlBinding(const QString &, QObject *, QQmlContextData *, QObject *parent=0); + QQmlBinding(const QString &, bool isRewritten, QObject *, QQmlContextData *, + const QString &url, int lineNumber, int columnNumber = 0, QObject *parent=0); + QQmlBinding(void *, QObject *, QQmlContextData *, QObject *parent=0); + + void setTarget(const QQmlProperty &); + void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *); + QQmlProperty property() const; + + void setEvaluateFlags(EvaluateFlags flags); + EvaluateFlags evaluateFlags() const; + + bool enabled() const; + + // Inherited from QQmlAbstractBinding + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags); + virtual void update(QQmlPropertyPrivate::WriteFlags flags); + virtual QString expression() const; + virtual int propertyIndex() const; + virtual QObject *object() const; + virtual void retargetBinding(QObject *, int); + + typedef int Identifier; + static Identifier Invalid; + static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *, + const QString &, int, QObject *parent=0); + + +public Q_SLOTS: + void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } + +protected: + ~QQmlBinding(); + +private: + Q_DECLARE_PRIVATE(QQmlBinding) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags) + +QQmlAbstractBinding::Pointer +QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p) +{ + return p ? p->weakPointer() : Pointer(); +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QQmlBinding*) + +#endif // QQMLBINDING_P_H diff --git a/src/qml/qml/qqmlbinding_p_p.h b/src/qml/qml/qqmlbinding_p_p.h new file mode 100644 index 0000000000..b53c903916 --- /dev/null +++ b/src/qml/qml/qqmlbinding_p_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLBINDING_P_P_H +#define QQMLBINDING_P_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 "qqmlbinding_p.h" + +#include "qqmlproperty.h" +#include "qqmlexpression_p.h" + +QT_BEGIN_NAMESPACE + +class QQmlBindingPrivate : public QQmlExpressionPrivate +{ + Q_DECLARE_PUBLIC(QQmlBinding) +public: + QQmlBindingPrivate(); + ~QQmlBindingPrivate(); + + virtual void expressionChanged(); + + static void printBindingLoopError(QQmlProperty &prop); + +protected: + virtual void refresh(); + +private: + bool updating:1; + bool enabled:1; + int columnNumber; + QQmlProperty property; + + QObject *target; + int targetProperty; +}; + +QT_END_NAMESPACE + +#endif // QQMLBINDING_P_P_H diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp new file mode 100644 index 0000000000..6f552450ef --- /dev/null +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlboundsignal_p.h" + +#include +#include "qqmlengine_p.h" +#include "qqmlexpression_p.h" +#include "qqmlcontext_p.h" +#include "qqmlmetatype_p.h" +#include "qqml.h" +#include "qqmlcontext.h" +#include "qqmlglobal_p.h" +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlBoundSignalParameters : public QObject +{ +Q_OBJECT +public: + QQmlBoundSignalParameters(const QMetaMethod &, QObject * = 0); + ~QQmlBoundSignalParameters(); + + void setValues(void **); + void clearValues(); + +private: + friend class MetaObject; + int metaCall(QMetaObject::Call, int _id, void **); + struct MetaObject : public QAbstractDynamicMetaObject { + MetaObject(QQmlBoundSignalParameters *b) + : parent(b) {} + + int metaCall(QMetaObject::Call c, int id, void **a) { + return parent->metaCall(c, id, a); + } + QQmlBoundSignalParameters *parent; + }; + + int *types; + void **values; + QMetaObject *myMetaObject; +}; + +static int evaluateIdx = -1; + +QQmlAbstractBoundSignal::QQmlAbstractBoundSignal(QObject *parent) +: QObject(parent) +{ +} + +QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() +{ +} + +QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +{ + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QQml_setParent_noEvent(this, parent); + QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); +} + +QQmlBoundSignal::QQmlBoundSignal(QQmlContext *ctxt, const QString &val, + QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +{ + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QQml_setParent_noEvent(this, parent); + QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); + + m_expression = new QQmlExpression(ctxt, scope, val); +} + +QQmlBoundSignal::~QQmlBoundSignal() +{ + delete m_expression; + m_expression = 0; +} + +int QQmlBoundSignal::index() const +{ + return m_signal.methodIndex(); +} + +/*! + Returns the signal expression. +*/ +QQmlExpression *QQmlBoundSignal::expression() const +{ + return m_expression; +} + +/*! + Sets the signal expression to \a e. Returns the current signal expression, + or null if there is no signal expression. + + The QQmlBoundSignal instance takes ownership of \a e. The caller is + assumes ownership of the returned QQmlExpression. +*/ +QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e) +{ + QQmlExpression *rv = m_expression; + m_expression = e; + if (m_expression) m_expression->setNotifyOnValueChanged(false); + return rv; +} + +QQmlBoundSignal *QQmlBoundSignal::cast(QObject *o) +{ + QQmlAbstractBoundSignal *s = qobject_cast(o); + return static_cast(s); +} + +int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) +{ + if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { + if (!m_expression) + return -1; + if (QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService::startRange(QQmlProfilerService::HandlingSignal); + QQmlProfilerService::rangeData(QQmlProfilerService::HandlingSignal, QLatin1String(m_signal.signature()) % QLatin1String(": ") % m_expression->expression()); + QQmlProfilerService::rangeLocation(QQmlProfilerService::HandlingSignal, m_expression->sourceFile(), m_expression->lineNumber(), m_expression->columnNumber()); + QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.signature())); + } + m_isEvaluating = true; + if (!m_paramsValid) { + if (!m_signal.parameterTypes().isEmpty()) + m_params = new QQmlBoundSignalParameters(m_signal, this); + m_paramsValid = true; + } + + if (m_params) m_params->setValues(a); + if (m_expression && m_expression->engine()) { + QQmlExpressionPrivate::get(m_expression)->value(m_params); + if (m_expression && m_expression->hasError()) + QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error()); + } + if (m_params) m_params->clearValues(); + m_isEvaluating = false; + QQmlProfilerService::endRange(QQmlProfilerService::HandlingSignal); + return -1; + } else { + return QObject::qt_metacall(c, id, a); + } +} + +QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, + QObject *parent) +: QObject(parent), types(0), values(0) +{ + MetaObject *mo = new MetaObject(this); + + // ### Optimize! + QMetaObjectBuilder mob; + mob.setSuperClass(&QQmlBoundSignalParameters::staticMetaObject); + mob.setClassName("QQmlBoundSignalParameters"); + + QList paramTypes = method.parameterTypes(); + QList paramNames = method.parameterNames(); + types = new int[paramTypes.count()]; + for (int ii = 0; ii < paramTypes.count(); ++ii) { + const QByteArray &type = paramTypes.at(ii); + const QByteArray &name = paramNames.at(ii); + + if (name.isEmpty() || type.isEmpty()) { + types[ii] = 0; + continue; + } + + QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData()); + if (QQmlMetaType::isQObject(t)) { + types[ii] = QMetaType::QObjectStar; + QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); + prop.setWritable(false); + } else { + QByteArray propType = type; + if (t >= QVariant::UserType || t == QVariant::Invalid) { + QByteArray scope; + QByteArray name; + int scopeIdx = propType.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = propType.left(scopeIdx); + name = propType.mid(scopeIdx + 2); + } else { + name = propType; + } + const QMetaObject *meta; + if (scope == "Qt") + meta = &QObject::staticQtMetaObject; + else + meta = parent->parent()->metaObject(); //### assumes parent->parent() + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) { + t = QVariant::Int; + propType = "int"; + break; + } + } + } + types[ii] = t; + QMetaPropertyBuilder prop = mob.addProperty(name, propType); + prop.setWritable(false); + } + } + myMetaObject = mob.toMetaObject(); + *static_cast(mo) = *myMetaObject; + + d_ptr->metaObject = mo; +} + +QQmlBoundSignalParameters::~QQmlBoundSignalParameters() +{ + delete [] types; + free(myMetaObject); +} + +void QQmlBoundSignalParameters::setValues(void **v) +{ + values = v; +} + +void QQmlBoundSignalParameters::clearValues() +{ + values = 0; +} + +int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) +{ + if (!values) + return -1; + + if (c == QMetaObject::ReadProperty && id >= 1) { + int t = types[id - 1]; + void *p = a[0]; + QMetaType::destruct(t, p); + QMetaType::construct(t, p, values[id]); + return -1; + } else { + return qt_metacall(c, id, a); + } +} + +QT_END_NAMESPACE + +#include diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h new file mode 100644 index 0000000000..11386159cb --- /dev/null +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLBOUNDSIGNAL_P_H +#define QQMLBOUNDSIGNAL_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 "qqmlexpression.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_QML_EXPORT QQmlAbstractBoundSignal : public QObject +{ + Q_OBJECT +public: + QQmlAbstractBoundSignal(QObject *parent = 0); + virtual ~QQmlAbstractBoundSignal() = 0; +}; + +class QQmlBoundSignalParameters; +class Q_QML_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal +{ +public: + QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent); + QQmlBoundSignal(QQmlContext *ctxt, const QString &val, QObject *scope, + const QMetaMethod &signal, QObject *parent); + virtual ~QQmlBoundSignal(); + + int index() const; + + QQmlExpression *expression() const; + QQmlExpression *setExpression(QQmlExpression *); + + bool isEvaluating() const { return m_isEvaluating; } + + static QQmlBoundSignal *cast(QObject *); + +protected: + virtual int qt_metacall(QMetaObject::Call c, int id, void **a); + +private: + QQmlExpression *m_expression; + QMetaMethod m_signal; + bool m_paramsValid : 1; + bool m_isEvaluating : 1; + QQmlBoundSignalParameters *m_params; +}; + +QT_END_NAMESPACE + +#endif // QQMLBOUNDSIGNAL_P_H diff --git a/src/qml/qml/qqmlcleanup.cpp b/src/qml/qml/qqmlcleanup.cpp new file mode 100644 index 0000000000..21ea02ee17 --- /dev/null +++ b/src/qml/qml/qqmlcleanup.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcleanup_p.h" + +#include "qqmlengine_p.h" + +QT_BEGIN_NAMESPACE + +/*! +\internal +\class QQmlCleanup +\brief The QQmlCleanup provides a callback when a QQmlEngine is deleted. + +Any object that needs cleanup to occur before the QQmlEngine's V8 engine is +destroyed should inherit from QQmlCleanup. The clear() virtual method will be +called by QQmlEngine just before it destroys the context. +*/ + + +/* +Create a QQmlCleanup that is not associated with any engine. +*/ +QQmlCleanup::QQmlCleanup() +: prev(0), next(0), engine(0) +{ +} + +/*! +Create a QQmlCleanup for \a engine +*/ +QQmlCleanup::QQmlCleanup(QQmlEngine *engine) +: prev(0), next(0), engine(0) +{ + if (!engine) + return; + + addToEngine(engine); +} + +/*! +Adds this object to \a engine's cleanup list. hasEngine() must be false +before calling this method. +*/ +void QQmlCleanup::addToEngine(QQmlEngine *engine) +{ + Q_ASSERT(engine); + Q_ASSERT(QQmlEnginePrivate::isEngineThread(engine)); + + this->engine = engine; + + QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine); + + if (p->cleanup) next = p->cleanup; + p->cleanup = this; + prev = &p->cleanup; + if (next) next->prev = &next; +} + +/*! +\fn bool QQmlCleanup::hasEngine() const + +Returns true if this QQmlCleanup is associated with an engine, otherwise false. +*/ + +/*! +\internal +*/ +QQmlCleanup::~QQmlCleanup() +{ + Q_ASSERT(!prev || engine); + Q_ASSERT(!prev || QQmlEnginePrivate::isEngineThread(engine)); + + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcleanup_p.h b/src/qml/qml/qqmlcleanup_p.h new file mode 100644 index 0000000000..2b7747d630 --- /dev/null +++ b/src/qml/qml/qqmlcleanup_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCLEANUP_P_H +#define QQMLCLEANUP_P_H + +#include + +// +// 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_BEGIN_NAMESPACE + +class QQmlEngine; + +// Exported for QtQuick1 +class Q_QML_EXPORT QQmlCleanup +{ +public: + QQmlCleanup(); + QQmlCleanup(QQmlEngine *); + virtual ~QQmlCleanup(); + + bool hasEngine() const { return prev != 0; } + void addToEngine(QQmlEngine *); +protected: + virtual void clear() = 0; + +private: + friend class QQmlEnginePrivate; + QQmlCleanup **prev; + QQmlCleanup *next; + + // Only used for asserts + QQmlEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QQMLCLEANUP_P_H + diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp new file mode 100644 index 0000000000..6a68784219 --- /dev/null +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcompiler_p.h" +#include "qqmlengine.h" +#include "qqmlcomponent.h" +#include "qqmlcomponent_p.h" +#include "qqmlcontext.h" +#include "qqmlcontext_p.h" +#ifdef QML_THREADED_VME_INTERPRETER +#include "qqmlvme_p.h" +#endif + +#include + +#include + +QT_BEGIN_NAMESPACE + +int QQmlCompiledData::pack(const char *data, size_t size) +{ + const char *p = packData.constData(); + unsigned int ps = packData.size(); + + for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { + if (0 == ::memcmp(p + ii, data, size)) + return ii; + } + + int rv = packData.size(); + packData.append(data, size); + return rv; +} + +int QQmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if (idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QQmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if (idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QQmlCompiledData::indexForUrl(const QUrl &data) +{ + int idx = urls.indexOf(data); + if (idx == -1) { + idx = urls.count(); + urls << data; + } + return idx; +} + +QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) +: engine(engine), importCache(0), root(0), rootPropertyCache(0) +{ + Q_ASSERT(engine); + + bytecode.reserve(1024); +} + +void QQmlCompiledData::destroy() +{ + if (engine && hasEngine()) + QQmlEnginePrivate::deleteInEngineThread(engine, this); + else + delete this; +} + +QQmlCompiledData::~QQmlCompiledData() +{ + clear(); + + for (int ii = 0; ii < types.count(); ++ii) { + if (types.at(ii).component) + types.at(ii).component->release(); + if (types.at(ii).typePropertyCache) + types.at(ii).typePropertyCache->release(); + } + + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + + for (int ii = 0; ii < contextCaches.count(); ++ii) + contextCaches.at(ii)->release(); + + for (int ii = 0; ii < scripts.count(); ++ii) + scripts.at(ii)->release(); + + if (importCache) + importCache->release(); + + if (rootPropertyCache) + rootPropertyCache->release(); +} + +void QQmlCompiledData::clear() +{ + for (int ii = 0; ii < programs.count(); ++ii) + qPersistentDispose(programs[ii].bindings); +} + +const QMetaObject *QQmlCompiledData::TypeReference::metaObject() const +{ + if (type) { + return type->metaObject(); + } else { + Q_ASSERT(component); + return component->root; + } +} + +/*! +Returns the property cache, if one alread exists. The cache is not referenced. +*/ +QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const +{ + if (type) + return typePropertyCache; + else + return component->rootPropertyCache; +} + +/*! +Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. +*/ +QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngine *engine) +{ + if (typePropertyCache) { + return typePropertyCache; + } else if (type) { + typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject()); + typePropertyCache->addref(); + return typePropertyCache; + } else { + return component->rootPropertyCache; + } +} + + +void QQmlCompiledData::dumpInstructions() +{ + if (!name.isEmpty()) + qWarning() << name; + qWarning().nospace() << "Index\tOperation\t\tData1\tData2\tData3\tComments"; + qWarning().nospace() << "-------------------------------------------------------------------------------"; + + const char *instructionStream = bytecode.constData(); + const char *endInstructionStream = bytecode.constData() + bytecode.size(); + + int instructionCount = 0; + while (instructionStream < endInstructionStream) { + QQmlInstruction *instr = (QQmlInstruction *)instructionStream; + dump(instr, instructionCount); + instructionStream += QQmlInstruction::size(instructionType(instr)); + instructionCount++; + } + + qWarning().nospace() << "-------------------------------------------------------------------------------"; +} + +int QQmlCompiledData::addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr) +{ +#ifdef QML_THREADED_VME_INTERPRETER + instr.common.code = QQmlVME::instructionJumpTable()[static_cast(type)]; +#else + instr.common.instructionType = type; +#endif + int ptrOffset = bytecode.size(); + int size = QQmlInstruction::size(type); + if (bytecode.capacity() <= bytecode.size() + size) + bytecode.reserve(bytecode.size() + size + 512); + bytecode.append(reinterpret_cast(&instr), size); + return ptrOffset; +} + +int QQmlCompiledData::nextInstructionIndex() +{ + return bytecode.size(); +} + +QQmlInstruction *QQmlCompiledData::instruction(int index) +{ + return (QQmlInstruction *)(bytecode.constData() + index); +} + +QQmlInstruction::Type QQmlCompiledData::instructionType(const QQmlInstruction *instr) +{ +#ifdef QML_THREADED_VME_INTERPRETER + void **jumpTable = QQmlVME::instructionJumpTable(); + void *code = instr->common.code; + +# define QML_CHECK_INSTR_CODE(I, FMT) \ + if (jumpTable[static_cast(QQmlInstruction::I)] == code) \ + return QQmlInstruction::I; + + FOR_EACH_QML_INSTR(QML_CHECK_INSTR_CODE) + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address"); + return static_cast(0); +# undef QML_CHECK_INSTR_CODE +#else + return static_cast(instr->common.instructionType); +#endif +} + +void QQmlCompiledData::initialize(QQmlEngine *engine) +{ + Q_ASSERT(!hasEngine()); + QQmlCleanup::addToEngine(engine); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp new file mode 100644 index 0000000000..65247e1e80 --- /dev/null +++ b/src/qml/qml/qqmlcompiler.cpp @@ -0,0 +1,3882 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcompiler_p.h" + +#include "qqmlpropertyvaluesource.h" +#include "qqmlcomponent.h" +#include +#include +#include "qqmlstringconverters_p.h" +#include "qqmlengine_p.h" +#include "qqmlengine.h" +#include "qqmlcontext.h" +#include "qqmlmetatype_p.h" +#include "qqmlcustomparser_p_p.h" +#include "qqmlcontext_p.h" +#include "qqmlcomponent_p.h" +#include +#include "qqmlvmemetaobject_p.h" +#include "qqmlexpression_p.h" +#include "qqmlproperty_p.h" +#include "qqmlrewrite_p.h" +#include "qqmlscriptstring.h" +#include "qqmlglobal_p.h" +#include "qqmlbinding_p.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); +DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS); + +using namespace QQmlJS; +using namespace QQmlScript; +using namespace QQmlCompilerTypes; + +static QString id_string(QLatin1String("id")); +static QString on_string(QLatin1String("on")); +static QString Changed_string(QLatin1String("Changed")); +static QString Component_string(QLatin1String("Component")); +static QString Component_import_string(QLatin1String("QML/Component")); +static QString qsTr_string(QLatin1String("qsTr")); +static QString qsTrId_string(QLatin1String("qsTrId")); + +/*! + Instantiate a new QQmlCompiler. +*/ +QQmlCompiler::QQmlCompiler(QQmlPool *pool) +: pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1), + cachedTranslationContextIndex(-1), componentStats(0) +{ + if (compilerStatDump()) + componentStats = pool->New(); +} + +/*! + Returns true if the last call to compile() caused errors. + + \sa errors() +*/ +bool QQmlCompiler::isError() const +{ + return !exceptions.isEmpty(); +} + +/*! + Return the list of errors from the last call to compile(), or an empty list + if there were no errors. +*/ +QList QQmlCompiler::errors() const +{ + return exceptions; +} + +/*! + Returns true if \a name refers to an attached property, false otherwise. + + Attached property names are those that start with a capital letter. +*/ +bool QQmlCompiler::isAttachedPropertyName(const QString &name) +{ + return isAttachedPropertyName(QHashedStringRef(&name)); +} + +bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name) +{ + return !name.isEmpty() && name.at(0).isUpper(); +} + +/*! + Returns true if \a name refers to a signal property, false otherwise. + + Signal property names are those that start with "on", followed by a first + character which is either a capital letter or one or more underscores followed + by a capital letter, which is then followed by other allowed characters. + + Note that although ECMA-262r3 supports dollarsigns and escaped unicode + character codes in property names, for simplicity and performance reasons + QML only supports letters, numbers and underscores. +*/ +bool QQmlCompiler::isSignalPropertyName(const QString &name) +{ + return isSignalPropertyName(QStringRef(&name)); +} + +bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name) +{ + if (name.length() < 3) return false; + if (!name.startsWith(on_string)) return false; + int ns = name.length(); + for (int i = 2; i < ns; ++i) { + const QChar curr = name.at(i); + if (curr.unicode() == '_') continue; + if (curr.isUpper()) return true; + return false; + } + return false; // consists solely of underscores - invalid. +} + +/*! + \macro COMPILE_EXCEPTION + \internal + Inserts an error into the QQmlCompiler error list, and returns false + (failure). + + \a token is used to source the error line and column, and \a desc is the + error itself. \a desc can be an expression that can be piped into QDebug. + + For example: + + \code + COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name)); + \endcode +*/ +#define COMPILE_EXCEPTION_LOCATION(line, column, desc) \ + { \ + QQmlError error; \ + error.setUrl(output->url); \ + error.setLine(line); \ + error.setColumn(column); \ + error.setDescription(desc.trimmed()); \ + exceptions << error; \ + return false; \ + } + +#define COMPILE_EXCEPTION(token, desc) \ + COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc) + +/*! + \macro COMPILE_CHECK + \internal + Returns false if \a is false, otherwise does nothing. +*/ +#define COMPILE_CHECK(a) \ + { \ + if (!a) return false; \ + } + +/*! + Returns true if literal \a v can be assigned to property \a prop, otherwise + false. + + This test corresponds to action taken by genLiteralAssignment(). Any change + made here, must have a corresponding action in genLiteralAssigment(). +*/ +bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Value *v) +{ + const QQmlScript::Variant &value = v->value; + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + + if (prop->core.isEnum()) { + QMetaProperty p = prop->parent->metaObject()->property(prop->index); + int enumValue; + bool ok; + if (p.isFlagType()) { + enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok); + } else + enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok); + + if (!ok) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration")); + + v->value = QQmlScript::Variant((double)enumValue); + return true; + } + + int type = prop->type; + + switch(type) { + case QMetaType::QVariant: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected")); + break; + case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected")); + break; + case QVariant::ByteArray: + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected")); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected")); + break; + case QVariant::RegExp: + COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); + break; + case QVariant::UInt: + { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(uint(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected")); + } + break; + case QVariant::Int: + { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(int(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected")); + } + break; + case QMetaType::Float: + if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); + break; + case QVariant::Double: + if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); + break; + case QVariant::Color: + { + bool ok; + QQmlStringConverters::colorFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected")); + } + break; +#ifndef QT_NO_DATESTRING + case QVariant::Date: + { + bool ok; + QQmlStringConverters::dateFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected")); + } + break; + case QVariant::Time: + { + bool ok; + QQmlStringConverters::timeFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected")); + } + break; + case QVariant::DateTime: + { + bool ok; + QQmlStringConverters::dateTimeFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected")); + } + break; +#endif // QT_NO_DATESTRING + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QQmlStringConverters::pointFFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QQmlStringConverters::sizeFFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QQmlStringConverters::rectFFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected")); + } + break; + case QVariant::Vector3D: + { + bool ok; + QQmlStringConverters::vector3DFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected")); + } + break; + case QVariant::Vector4D: + { + bool ok; + QQmlStringConverters::vector4DFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected")); + } + break; + default: + { + // check if assigning a literal value to a list property. + // in each case, check the singular, since an Array of the specified type + // will not go via this literal assignment codepath. + if (type == qMetaTypeId >()) { + if (!v->value.isNumber()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected")); + } + break; + } else if (type == qMetaTypeId >()) { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(int(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected")); + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isBoolean()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected")); + } + break; + } else if (type == qMetaTypeId >()) { // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected")); + } + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected")); + } + break; + } + + // otherwise, check for existence of string converter to custom type + QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type); + if (!converter) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type)))); + } + break; + } + return true; +} + +static QUrl urlFromUserString(const QString &data) +{ + QUrl u; + // Preserve any valid percent-encoded octets supplied by the source + u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode); + return u; +} + +/*! + Generate a store instruction for assigning literal \a v to property \a prop. + + Any literal assignment that is approved in testLiteralAssignment() must have + a corresponding action in this method. +*/ +void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Value *v) +{ + if (prop->core.isEnum()) { + Q_ASSERT(v->value.isNumber()); + // Preresolved value + int value = (int)v->value.asNumber(); + + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = value; + output->addInstruction(instr); + return; + } + + int type = prop->type; + switch(type) { + case QMetaType::QVariant: + { + if (v->value.isNumber()) { + double n = v->value.asNumber(); + if (double(int(n)) == n) { + if (prop->core.isVMEProperty()) { + Instruction::StoreVarInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(n); + output->addInstruction(instr); + } else { + Instruction::StoreVariantInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(n); + output->addInstruction(instr); + } + } else { + if (prop->core.isVMEProperty()) { + Instruction::StoreVarDouble instr; + instr.propertyIndex = prop->index; + instr.value = n; + output->addInstruction(instr); + } else { + Instruction::StoreVariantDouble instr; + instr.propertyIndex = prop->index; + instr.value = n; + output->addInstruction(instr); + } + } + } else if (v->value.isBoolean()) { + if (prop->core.isVMEProperty()) { + Instruction::StoreVarBool instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asBoolean(); + output->addInstruction(instr); + } else { + Instruction::StoreVariantBool instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asBoolean(); + output->addInstruction(instr); + } + } else { + if (prop->core.isVMEProperty()) { + Instruction::StoreVar instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } else { + Instruction::StoreVariant instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + } + } + break; + case QVariant::String: + { + Instruction::StoreString instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + break; + case QVariant::StringList: + { + Instruction::StoreStringList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + break; + case QVariant::ByteArray: + { + Instruction::StoreByteArray instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForByteArray(v->value.asString().toLatin1()); + output->addInstruction(instr); + } + break; + case QVariant::Url: + { + Instruction::StoreUrl instr; + QString string = v->value.asString(); + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string)); + instr.propertyIndex = prop->index; + instr.value = output->indexForUrl(u); + output->addInstruction(instr); + } + break; + case QVariant::UInt: + { + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = uint(v->value.asNumber()); + output->addInstruction(instr); + } + break; + case QVariant::Int: + { + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(v->value.asNumber()); + output->addInstruction(instr); + } + break; + case QMetaType::Float: + { + Instruction::StoreFloat instr; + instr.propertyIndex = prop->index; + instr.value = float(v->value.asNumber()); + output->addInstruction(instr); + } + break; + case QVariant::Double: + { + Instruction::StoreDouble instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asNumber(); + output->addInstruction(instr); + } + break; + case QVariant::Color: + { + Instruction::StoreColor instr; + QColor c = QQmlStringConverters::colorFromString(v->value.asString()); + instr.propertyIndex = prop->index; + instr.value = c.rgba(); + output->addInstruction(instr); + } + break; +#ifndef QT_NO_DATESTRING + case QVariant::Date: + { + Instruction::StoreDate instr; + QDate d = QQmlStringConverters::dateFromString(v->value.asString()); + instr.propertyIndex = prop->index; + instr.value = d.toJulianDay(); + output->addInstruction(instr); + } + break; + case QVariant::Time: + { + Instruction::StoreTime instr; + QTime time = QQmlStringConverters::timeFromString(v->value.asString()); + instr.propertyIndex = prop->index; + Q_ASSERT(sizeof(instr.time) == sizeof(QTime)); + ::memcpy(&instr.time, &time, sizeof(QTime)); + output->addInstruction(instr); + } + break; + case QVariant::DateTime: + { + Instruction::StoreDateTime instr; + QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString()); + QTime time = dateTime.time(); + instr.propertyIndex = prop->index; + instr.date = dateTime.date().toJulianDay(); + Q_ASSERT(sizeof(instr.time) == sizeof(QTime)); + ::memcpy(&instr.time, &time, sizeof(QTime)); + output->addInstruction(instr); + } + break; +#endif // QT_NO_DATESTRING + case QVariant::Point: + { + Instruction::StorePoint instr; + bool ok; + QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint(); + instr.propertyIndex = prop->index; + instr.point.xp = point.x(); + instr.point.yp = point.y(); + output->addInstruction(instr); + } + break; + case QVariant::PointF: + { + Instruction::StorePointF instr; + bool ok; + QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.point.xp = point.x(); + instr.point.yp = point.y(); + output->addInstruction(instr); + } + break; + case QVariant::Size: + { + Instruction::StoreSize instr; + bool ok; + QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize(); + instr.propertyIndex = prop->index; + instr.size.wd = size.width(); + instr.size.ht = size.height(); + output->addInstruction(instr); + } + break; + case QVariant::SizeF: + { + Instruction::StoreSizeF instr; + bool ok; + QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.size.wd = size.width(); + instr.size.ht = size.height(); + output->addInstruction(instr); + } + break; + case QVariant::Rect: + { + Instruction::StoreRect instr; + bool ok; + QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect(); + instr.propertyIndex = prop->index; + instr.rect.x1 = rect.left(); + instr.rect.y1 = rect.top(); + instr.rect.x2 = rect.right(); + instr.rect.y2 = rect.bottom(); + output->addInstruction(instr); + } + break; + case QVariant::RectF: + { + Instruction::StoreRectF instr; + bool ok; + QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.rect.xp = rect.left(); + instr.rect.yp = rect.top(); + instr.rect.w = rect.width(); + instr.rect.h = rect.height(); + output->addInstruction(instr); + } + break; + case QVariant::Bool: + { + Instruction::StoreBool instr; + bool b = v->value.asBoolean(); + instr.propertyIndex = prop->index; + instr.value = b; + output->addInstruction(instr); + } + break; + case QVariant::Vector3D: + { + Instruction::StoreVector3D instr; + bool ok; + QVector3D vector = QQmlStringConverters::vector3DFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.vector.xp = vector.x(); + instr.vector.yp = vector.y(); + instr.vector.zp = vector.z(); + output->addInstruction(instr); + } + break; + case QVariant::Vector4D: + { + Instruction::StoreVector4D instr; + bool ok; + QVector4D vector = QQmlStringConverters::vector4DFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.vector.xp = vector.x(); + instr.vector.yp = vector.y(); + instr.vector.zp = vector.z(); + instr.vector.wp = vector.w(); + output->addInstruction(instr); + } + break; + default: + { + // generate single literal value assignment to a list property if required + if (type == qMetaTypeId >()) { + Instruction::StoreDoubleQList instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asNumber(); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreIntegerQList instr; + instr.propertyIndex = prop->index; + instr.value = int(v->value.asNumber()); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreBoolQList instr; + bool b = v->value.asBoolean(); + instr.propertyIndex = prop->index; + instr.value = b; + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreUrlQList instr; + QString string = v->value.asString(); + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string)); + instr.propertyIndex = prop->index; + instr.value = output->indexForUrl(u); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreStringQList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + break; + } + + // otherwise, generate custom type literal assignment + Instruction::AssignCustomType instr; + instr.propertyIndex = prop->index; + instr.primitive = output->indexForString(v->value.asString()); + instr.type = type; + output->addInstruction(instr); + } + break; + } +} + +/*! + Resets data by clearing the lists that the QQmlCompiler modifies. +*/ +void QQmlCompiler::reset(QQmlCompiledData *data) +{ + data->types.clear(); + data->primitives.clear(); + data->datas.clear(); + data->bytecode.resize(0); +} + +/*! + Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine + with which the QQmlCompiledData will be associated. + + Returns true on success, false on failure. On failure, the compile errors + are available from errors(). + + If the environment variant QML_COMPILER_DUMP is set + (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr + on a successful compiler. +*/ +bool QQmlCompiler::compile(QQmlEngine *engine, + QQmlTypeData *unit, + QQmlCompiledData *out) +{ + exceptions.clear(); + + Q_ASSERT(out); + reset(out); + + QQmlScript::Object *root = unit->parser().tree(); + Q_ASSERT(root); + + this->engine = engine; + this->enginePrivate = QQmlEnginePrivate::get(engine); + this->unit = unit; + this->unitRoot = root; + this->output = out; + + // Compile types + const QList &resolvedTypes = unit->resolvedTypes(); + QList referencedTypes = unit->parser().referencedTypes(); + + for (int ii = 0; ii < resolvedTypes.count(); ++ii) { + QQmlCompiledData::TypeReference ref; + + const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii); + QQmlScript::TypeReference *parserRef = referencedTypes.at(ii); + + if (tref.type) { + ref.type = tref.type; + if (!ref.type->isCreatable()) { + QString err = ref.type->noCreationReason(); + if (err.isEmpty()) + err = tr( "Element is not creatable."); + COMPILE_EXCEPTION(parserRef->refObjects.first(), err); + } + + if (ref.type->containsRevisionedAttributes()) { + QQmlError cacheError; + ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion, + cacheError); + if (!ref.typePropertyCache) + COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description()); + ref.typePropertyCache->addref(); + } + + } else if (tref.typeData) { + ref.component = tref.typeData->compiledData(); + } + ref.className = parserRef->name; + out->types << ref; + } + + compileTree(root); + + if (!isError()) { + if (compilerDump()) + out->dumpInstructions(); + if (componentStats) + dumpStats(); + Q_ASSERT(out->rootPropertyCache); + } else { + reset(out); + } + + compileState = 0; + output = 0; + this->engine = 0; + this->enginePrivate = 0; + this->unit = 0; + this->cachedComponentTypeRef = -1; + this->cachedTranslationContextIndex = -1; + this->unitRoot = 0; + + return !isError(); +} + +void QQmlCompiler::compileTree(QQmlScript::Object *tree) +{ + compileState = pool->New(); + + compileState->root = tree; + if (componentStats) + componentStats->componentStat.lineNumber = tree->location.start.line; + + // We generate the importCache before we build the tree so that + // it can be used in the binding compiler. Given we "expect" the + // QML compilation to succeed, this isn't a waste. + output->importCache = new QQmlTypeNameCache(); + foreach (const QString &ns, unit->namespaces()) { + output->importCache->add(ns); + } + + int scriptIndex = 0; + foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) { + QString qualifier = script.qualifier; + QString enclosingNamespace; + + const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex != -1) { + enclosingNamespace = qualifier.left(lastDotIndex); + qualifier = qualifier.mid(lastDotIndex+1); + } + + output->importCache->add(qualifier, scriptIndex++, enclosingNamespace); + } + + unit->imports().populateCache(output->importCache, engine); + + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + + Instruction::Init init; + init.bindingsSize = compileState->totalBindingsCount; + init.parserStatusSize = compileState->parserStatusCount; + init.contextCache = genContextCache(); + init.objectStackSize = compileState->objectDepth.maxDepth(); + init.listStackSize = compileState->listDepth.maxDepth(); + if (compileState->compiledBindingData.isEmpty()) + init.compiledBinding = -1; + else + init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); + output->addInstruction(init); + + foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) { + Instruction::StoreImportedScript import; + import.value = output->scripts.count(); + + QQmlScriptData *scriptData = script.script->scriptData(); + scriptData->addref(); + output->scripts << scriptData; + output->addInstruction(import); + } + + if (!compileState->v8BindingProgram.isEmpty()) { + Instruction::InitV8Bindings bindings; + int index = output->programs.count(); + + typedef QQmlCompiledData::V8Program V8Program; + output->programs.append(V8Program(compileState->v8BindingProgram, output)); + + bindings.programIndex = index; + bindings.line = compileState->v8BindingProgramLine; + output->addInstruction(bindings); + } + + genObject(tree); + + Instruction::SetDefault def; + output->addInstruction(def); + + Instruction::Done done; + output->addInstruction(done); + + Q_ASSERT(tree->metatype); + + if (tree->metadata.isEmpty()) { + output->root = tree->metatype; + } else { + static_cast(output->rootData) = *tree->metaObject(); + output->root = &output->rootData; + } + if (!tree->metadata.isEmpty()) + enginePrivate->registerCompositeType(output); +} + +static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string) +{ + for (int ii = 0; ii < list.count(); ++ii) + if (string == list.at(ii)) + return true; + + return false; +} + +bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt) +{ + if (componentStats) + componentStats->componentStat.objects++; + + Q_ASSERT (obj->type != -1); + const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type); + obj->metatype = tr.metaObject(); + + if (tr.type) + obj->typeName = tr.type->qmlTypeName(); + + // This object is a "Component" element + if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); + return true; + } + + if (tr.component) { + typedef QQmlInstruction I; + const I *init = ((const I *)tr.component->bytecode.constData()); + Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init); + + // Adjust stack depths to include nested components + compileState->objectDepth.pushPop(init->init.objectStackSize); + compileState->listDepth.pushPop(init->init.listStackSize); + compileState->parserStatusCount += init->init.parserStatusSize; + compileState->totalBindingsCount += init->init.bindingsSize; + } + + compileState->objectDepth.push(); + + // Object instantiations reset the binding context + BindingContext objCtxt(obj); + + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(checkDynamicMeta(obj)); + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); + + // Find the native type and check for the QQmlParserStatus interface + QQmlType *type = toQmlType(obj); + Q_ASSERT(type); + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) + compileState->parserStatusCount++; + + // Check if this is a custom parser type. Custom parser types allow + // assignments to non-existent properties. These assignments are then + // compiled by the type. + bool isCustomParser = output->types.at(obj->type).type && + output->types.at(obj->type).type->customParser() != 0; + QList customProps; + + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + if (prop->name() == id_string) { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } + + // Merge + Property *defaultProperty = 0; + Property *skipProperty = 0; + if (obj->defaultProperty) { + defaultProperty = obj->defaultProperty; + + Property *explicitProperty = 0; + + const QMetaObject *mo = obj->metatype; + int idx = mo->indexOfClassInfo("DefaultProperty"); + if (idx != -1) { + QMetaClassInfo info = mo->classInfo(idx); + const char *p = info.value(); + if (p) { + int plen = 0; + char ord = 0; + while (char c = p[plen++]) { ord |= c; }; + --plen; + + if (ord & 0x80) { + // Utf8 - unoptimal, but seldom hit + QString *s = pool->NewString(QString::fromUtf8(p, plen)); + QHashedStringRef r(*s); + + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; + } + } + } + + if (!explicitProperty) + defaultProperty->setName(r); + + } else { + QHashedCStringRef r(p, plen); + + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; + } + } + } + + if (!explicitProperty) { + // Set the default property name + QChar *buffer = pool->NewRawArray(r.length()); + r.writeUtf16(buffer); + defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash())); + } + } + } + } + + if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) { + + skipProperty = explicitProperty; // We merge the values into defaultProperty + + // Find the correct insertion point + Value *insertPos = 0; + + for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) { + if (!(v->location.start < explicitProperty->values.first()->location.start)) + break; + insertPos = v; + } + + defaultProperty->values.insertAfter(insertPos, explicitProperty->values); + } + } + + QQmlCustomParser *cp = 0; + if (isCustomParser) + cp = output->types.at(obj->type).type->customParser(); + + // Build all explicit properties specified + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + + if (prop == skipProperty) + continue; + if (prop->name() == id_string) + continue; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj) && + (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) || + !isAttachedPropertyName(prop->name()))) { + int ids = compileState->ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState->ids.count(); + } else if (isSignalPropertyName(prop->name()) && + (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); + } else { + customProps << QQmlCustomParserNodePrivate::fromProperty(prop); + } + } else { + if (isSignalPropertyName(prop->name())) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); + } else { + int ids = compileState->ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState->ids.count(); + } + } + + if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) + prop->isDeferred = true; + + } + + // Build the default property + if (defaultProperty) { + Property *prop = defaultProperty; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj)) { + int ids = compileState->ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState->ids.count(); + } else { + customProps << QQmlCustomParserNodePrivate::fromProperty(prop); + } + } else { + int ids = compileState->ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState->ids.count(); + } + + if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) + prop->isDeferred = true; + } + + // Compile custom parser parts + if (isCustomParser && !customProps.isEmpty()) { + cp->clearErrors(); + cp->compiler = this; + cp->object = obj; + obj->custom = cp->compile(customProps); + cp->compiler = 0; + cp->object = 0; + foreach (QQmlError err, cp->errors()) { + err.setUrl(output->url); + exceptions << err; + } + } + + compileState->objectDepth.pop(); + + return true; +} + +void QQmlCompiler::genObject(QQmlScript::Object *obj) +{ + QQmlCompiledData::TypeReference &tr = output->types[obj->type]; + if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + if (obj->custom.isEmpty() && output->types.at(obj->type).type && + !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) { + + Instruction::CreateSimpleObject create; + create.create = output->types.at(obj->type).type->createFunction(); + create.typeSize = output->types.at(obj->type).type->createSize(); + create.type = obj->type; + create.line = obj->location.start.line; + create.column = obj->location.start.column; + output->addInstruction(create); + + } else { + + if (output->types.at(obj->type).type) { + Instruction::CreateCppObject create; + create.line = obj->location.start.line; + create.column = obj->location.start.column; + create.data = -1; + if (!obj->custom.isEmpty()) + create.data = output->indexForByteArray(obj->custom); + create.type = obj->type; + create.isRoot = (compileState->root == obj); + output->addInstruction(create); + } else { + Instruction::CreateQMLObject create; + create.type = obj->type; + create.isRoot = (compileState->root == obj); + + if (!obj->bindingBitmask.isEmpty()) { + Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); + create.bindingBits = output->indexForByteArray(obj->bindingBitmask); + } else { + create.bindingBits = -1; + } + output->addInstruction(create); + + Instruction::CompleteQMLObject complete; + complete.line = obj->location.start.line; + complete.column = obj->location.start.column; + complete.isRoot = (compileState->root == obj); + output->addInstruction(complete); + } + } + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + Instruction::StoreMetaObject meta; + meta.data = output->indexForByteArray(obj->metadata); + meta.aliasData = output->indexForByteArray(obj->synthdata); + meta.propertyCache = output->propertyCaches.count(); + + QQmlPropertyCache *propertyCache = obj->synthCache; + Q_ASSERT(propertyCache); + propertyCache->addref(); + + // Add flag for alias properties + if (!obj->synthdata.isEmpty()) { + const QQmlVMEMetaData *vmeMetaData = + reinterpret_cast(obj->synthdata.constData()); + for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { + int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; + QQmlPropertyData *data = propertyCache->property(index); + data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias); + } + } + + if (obj == unitRoot) { + propertyCache->addref(); + output->rootPropertyCache = propertyCache; + } + + output->propertyCaches << propertyCache; + output->addInstruction(meta); + } else if (obj == unitRoot) { + output->rootPropertyCache = tr.createPropertyCache(engine); + output->rootPropertyCache->addref(); + } + + // Set the object id + if (!obj->id.isEmpty()) { + Instruction::SetId id; + id.value = output->indexForString(obj->id); + id.index = obj->idIndex; + output->addInstruction(id); + } + + // Begin the class + if (tr.type && obj->parserStatusCast != -1) { + Instruction::BeginObject begin; + begin.castValue = obj->parserStatusCast; + output->addInstruction(begin); + } + + genObjectBody(obj); +} + +void QQmlCompiler::genObjectBody(QQmlScript::Object *obj) +{ + for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Q_ASSERT(prop->scriptStringScope != -1); + const QString &script = prop->values.first()->value.asScript(); + Instruction::StoreScriptString ss; + ss.propertyIndex = prop->index; + ss.value = output->indexForString(script); + ss.scope = prop->scriptStringScope; +// ss.bindingId = rewriteBinding(script, prop->name()); + ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX + ss.line = prop->location.start.line; + ss.column = prop->location.start.column; + output->addInstruction(ss); + } + + bool seenDefer = false; + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + if (!prop->isAlias) + genValueProperty(prop, obj); + } + if (seenDefer) { + Instruction::Defer defer; + defer.deferCount = 0; + int deferIdx = output->addInstruction(defer); + int nextInstructionIndex = output->nextInstructionIndex(); + + Instruction::DeferInit dinit; + // XXX - these are now massive over allocations + dinit.bindingsSize = compileState->totalBindingsCount; + dinit.parserStatusSize = compileState->parserStatusCount; + dinit.objectStackSize = compileState->objectDepth.maxDepth(); + dinit.listStackSize = compileState->listDepth.maxDepth(); + output->addInstruction(dinit); + + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); + } + + Instruction::Done done; + output->addInstruction(done); + + output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex; + } + + for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + + QQmlScript::Value *v = prop->values.first(); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + Instruction::AssignSignalObject assign; + assign.line = v->location.start.line; + assign.signal = output->indexForString(prop->name().toString()); + output->addInstruction(assign); + + } else if (v->type == Value::SignalExpression) { + + Instruction::StoreSignal store; + store.signalIndex = prop->index; + const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString()); + store.value = output->indexForByteArray(rewrite.toUtf8()); + store.context = v->signalExpressionContextStack; + store.line = v->location.start.line; + store.column = v->location.start.column; + output->addInstruction(store); + + } + + } + + for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Instruction::FetchAttached fetch; + fetch.id = prop->index; + fetch.line = prop->location.start.line; + output->addInstruction(fetch); + + genObjectBody(prop->value); + + Instruction::PopFetchedObject pop; + output->addInstruction(pop); + } + + for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Instruction::FetchObject fetch; + fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->addInstruction(fetch); + + if (!prop->value->metadata.isEmpty()) { + Instruction::StoreMetaObject meta; + meta.data = output->indexForByteArray(prop->value->metadata); + meta.aliasData = output->indexForByteArray(prop->value->synthdata); + meta.propertyCache = -1; + output->addInstruction(meta); + } + + genObjectBody(prop->value); + + Instruction::PopFetchedObject pop; + output->addInstruction(pop); + } + + for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + if (!prop->isAlias) + genValueTypeProperty(obj, prop); + } + + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + if (prop->isDeferred) + continue; + if (prop->isAlias) + genValueProperty(prop, obj); + } + + for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + if (prop->isAlias) + genValueTypeProperty(obj, prop); + } +} + +void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop) +{ + Instruction::FetchValueType fetch; + fetch.property = prop->index; + fetch.type = prop->type; + fetch.bindingSkipList = 0; + + if (obj->type == -1 || output->types.at(obj->type).component) { + // We only have to do this if this is a composite type. If it is a builtin + // type it can't possibly already have bindings that need to be cleared. + for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) { + if (!vprop->values.isEmpty()) { + Q_ASSERT(vprop->index >= 0 && vprop->index < 32); + fetch.bindingSkipList |= (1 << vprop->index); + } + } + } + + output->addInstruction(fetch); + + for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) { + genPropertyAssignment(vprop, prop->value, prop); + } + + Instruction::PopValueType pop; + pop.property = prop->index; + pop.type = prop->type; + pop.bindingSkipList = 0; + output->addInstruction(pop); +} + +void QQmlCompiler::genComponent(QQmlScript::Object *obj) +{ + QQmlScript::Object *root = obj->defaultProperty->values.first()->object; + Q_ASSERT(root); + + Instruction::CreateComponent create; + create.line = root->location.start.line; + create.column = root->location.start.column; + create.endLine = root->location.end.line; + create.isRoot = (compileState->root == obj); + int createInstruction = output->addInstruction(create); + int nextInstructionIndex = output->nextInstructionIndex(); + + ComponentCompileState *oldCompileState = compileState; + compileState = componentState(root); + + Instruction::Init init; + init.bindingsSize = compileState->totalBindingsCount; + init.parserStatusSize = compileState->parserStatusCount; + init.contextCache = genContextCache(); + init.objectStackSize = compileState->objectDepth.maxDepth(); + init.listStackSize = compileState->listDepth.maxDepth(); + if (compileState->compiledBindingData.isEmpty()) + init.compiledBinding = -1; + else + init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); + output->addInstruction(init); + + if (!compileState->v8BindingProgram.isEmpty()) { + Instruction::InitV8Bindings bindings; + int index = output->programs.count(); + + typedef QQmlCompiledData::V8Program V8Program; + output->programs.append(V8Program(compileState->v8BindingProgram, output)); + + bindings.programIndex = index; + bindings.line = compileState->v8BindingProgramLine; + output->addInstruction(bindings); + } + + genObject(root); + + Instruction::SetDefault def; + output->addInstruction(def); + + Instruction::Done done; + output->addInstruction(done); + + output->instruction(createInstruction)->createComponent.count = + output->nextInstructionIndex() - nextInstructionIndex; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + Instruction::SetId id; + id.value = output->indexForString(obj->id); + id.index = obj->idIndex; + output->addInstruction(id); + } + + if (obj == unitRoot) { + output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine); + output->rootPropertyCache->addref(); + } +} + +bool QQmlCompiler::buildComponent(QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + compileState->objectDepth.push(); + + // Find, check and set the "id" property (if any) + Property *idProp = 0; + if (obj->properties.isMany() || + (obj->properties.isOne() && obj->properties.first()->name() != id_string)) + COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id")); + + if (!obj->properties.isEmpty()) + idProp = obj->properties.first(); + + if (idProp) { + if (idProp->value || idProp->values.isMany() || idProp->values.first()->object) + COMPILE_EXCEPTION(idProp, tr("Invalid component id specification")); + COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive())) + + QString idVal = idProp->values.first()->primitive(); + + if (compileState->ids.value(idVal)) + COMPILE_EXCEPTION(idProp, tr("id is not unique")); + + obj->id = idVal; + addId(idVal, obj); + } + + // Check the Component tree is well formed + if (obj->defaultProperty && + (obj->defaultProperty->value || obj->defaultProperty->values.isMany() || + (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object))) + COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); + + if (!obj->dynamicProperties.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); + if (!obj->dynamicSignals.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); + if (!obj->dynamicSlots.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); + + QQmlScript::Object *root = 0; + if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty()) + root = obj->defaultProperty->values.first()->object; + + if (!root) + COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification")); + + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); + + compileState->objectDepth.pop(); + + return true; +} + +bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + ComponentCompileState *oldComponentCompileState = compileState; + compileState = pool->New(); + compileState->root = obj; + compileState->nested = true; + + if (componentStats) { + ComponentStat oldComponentStat = componentStats->componentStat; + + componentStats->componentStat = ComponentStat(); + componentStats->componentStat.lineNumber = obj->location.start.line; + + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + + componentStats->componentStat = oldComponentStat; + } else { + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + } + + compileState = oldComponentCompileState; + + return true; +} + + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt) +{ + Q_ASSERT(obj->metatype); + Q_ASSERT(!obj->defaultProperty); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context + + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + if (isSignalPropertyName(prop->name())) { + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); + } else { + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + } + } + + return true; +} + +int QQmlCompiler::componentTypeRef() +{ + if (cachedComponentTypeRef == -1) { + QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) { + cachedComponentTypeRef = ii; + return ii; + } + } + QQmlCompiledData::TypeReference ref; + ref.className = Component_string; + ref.type = t; + output->types << ref; + cachedComponentTypeRef = output->types.count() - 1; + } + return cachedComponentTypeRef; +} + +int QQmlCompiler::translationContextIndex() +{ + if (cachedTranslationContextIndex == -1) { + // This code must match that in the qsTr() implementation + const QString &path = output->name; + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : + QString(); + QByteArray contextUtf8 = context.toUtf8(); + cachedTranslationContextIndex = output->indexForByteArray(contextUtf8); + } + return cachedTranslationContextIndex; +} + +bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(obj->metaObject()); + + const QHashedStringRef &propName = prop->name(); + + Q_ASSERT(propName.startsWith(on_string)); + QString name = propName.mid(2, -1).toString(); + + // Note that the property name could start with any alpha or '_' or '$' character, + // so we need to do the lower-casing of the first alpha character. + for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) { + if (name.at(firstAlphaIndex).isUpper()) { + name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower(); + break; + } + } + + bool notInRevision = false; + + QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision); + + if (sig == 0) { + + if (notInRevision && 0 == property(obj, propName, 0)) { + Q_ASSERT(obj->type != -1); + const QList &resolvedTypes = unit->resolvedTypes(); + const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type); + if (type.type) { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion)); + } else { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString())); + } + } + + // If the "on" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + + } else { + + if (prop->value || !prop->values.isOne()) + COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); + + prop->index = sig->coreIndex; + prop->core = *sig; + + obj->addSignalProperty(prop); + + if (prop->values.first()->object) { + COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt)); + prop->values.first()->type = Value::SignalObject; + } else { + prop->values.first()->type = Value::SignalExpression; + + if (!prop->values.first()->value.isScript()) + COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)")); + + QString script = prop->values.first()->value.asScript().trimmed(); + if (script.isEmpty()) + COMPILE_EXCEPTION(prop, tr("Empty signal assignment")); + + prop->values.first()->signalExpressionContextStack = ctxt.stack; + } + } + + return true; +} + + +/*! + Returns true if (value) property \a prop exists on obj, false otherwise. +*/ +bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop, + QQmlScript::Object *obj) +{ + if (prop->name().isEmpty()) + return false; + if(isAttachedPropertyName(prop->name()) || prop->name() == id_string) + return true; + + return property(obj, prop->name()) != 0; +} + +bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + if (prop->isEmpty()) + COMPILE_EXCEPTION(prop, tr("Empty property assignment")); + + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); + + if (isAttachedPropertyName(prop->name())) { + // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here")); + } + + QQmlType *type = 0; + QQmlImportedNamespace *typeNamespace = 0; + unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace); + + if (typeNamespace) { + COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, + ctxt)); + return true; + } else if (!type || !type->attachedPropertiesType()) { + COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); + } + + if (!prop->value) + COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->attachedPropertiesId(); + prop->value->metatype = type->attachedPropertiesType(); + } else { + // Setup regular property data + bool notInRevision = false; + QQmlPropertyData *d = + prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision); + + if (d == 0 && notInRevision) { + const QList &resolvedTypes = unit->resolvedTypes(); + const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type); + if (type.type) { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion)); + } else { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString())); + } + } else if (d) { + prop->index = d->coreIndex; + prop->core = *d; + } else if (prop->isDefault) { + QMetaProperty p = QQmlMetaType::defaultProperty(metaObject); + QQmlPropertyData defaultPropertyData; + defaultPropertyData.load(p, engine); + if (p.name()) + prop->setName(QLatin1String(p.name())); + prop->core = defaultPropertyData; + prop->index = prop->core.coreIndex; + } + + // We can't error here as the "id" property does not require a + // successful index resolution + if (prop->index != -1) + prop->type = prop->core.propType; + + // Check if this is an alias + if (prop->index != -1 && + prop->parent && + prop->parent->type != -1 && + output->types.at(prop->parent->type).component) { + + QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache; + if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias()) + prop->isAlias = true; + } + + if (prop->index != -1 && !prop->values.isEmpty()) + prop->parent->setBindingBit(prop->index); + } + + if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) { + + // The magic "id" behavior doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.first()->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } else if (isAttachedPropertyName(prop->name())) { + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + + } else if (prop->index == -1) { + + if (prop->isDefault) { + COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property")); + } else { + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString())); + } + + } else if (prop->value) { + + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); + + } else if (prop->core.isQList()) { + + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + + } else if (prop->type == qMetaTypeId()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns, + QQmlScript::Property *nsProp, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + if (!nsProp->value) + COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace")); + + for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) { + + if (!isAttachedPropertyName(prop->name())) + COMPILE_EXCEPTION(prop, tr("Not an attached property name")); + + // Setup attached property data + + QQmlType *type = 0; + unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0); + + if (!type || !type->attachedPropertiesType()) + COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); + + if (!prop->value) + COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->index(); + prop->value->metatype = type->attachedPropertiesType(); + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + } + + return true; +} + +void QQmlCompiler::genValueProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj) +{ + if (prop->core.isQList()) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QQmlCompiler::genListProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj) +{ + int listType = enginePrivate->listType(prop->type); + + Instruction::FetchQList fetch; + fetch.property = prop->index; + bool listTypeIsInterface = QQmlMetaType::isInterface(listType); + fetch.type = listType; + output->addInstruction(fetch); + + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + Instruction::AssignObjectList assign; + assign.line = prop->location.start.line; + output->addInstruction(assign); + } else { + Instruction::StoreObjectQList store; + output->addInstruction(store); + } + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } + + } + + Instruction::PopQList pop; + output->addInstruction(pop); +} + +void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Property *valueTypeProperty) +{ + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { + + Q_ASSERT(v->type == Value::CreatedObject || + v->type == Value::PropertyBinding || + v->type == Value::Literal); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + + if (QQmlMetaType::isInterface(prop->type)) { + + Instruction::StoreInterface store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + + } else if (prop->type == QMetaType::QVariant) { + + if (prop->core.isVMEProperty()) { + Instruction::StoreVarObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + } else { + Instruction::StoreVariantObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + } + + + } else { + + Instruction::StoreObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + + } + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj, valueTypeProperty); + + } else if (v->type == Value::Literal) { + + genLiteralAssignment(prop, v); + + } + + } + + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { + + Q_ASSERT(v->type == Value::ValueSource || + v->type == Value::ValueInterceptor); + + if (v->type == Value::ValueSource) { + genObject(v->object); + + Instruction::StoreValueSource store; + if (valueTypeProperty) { + store.property = genValueTypeData(prop, valueTypeProperty); + store.owner = 1; + } else { + store.property = prop->core; + store.owner = 0; + } + QQmlType *valueType = toQmlType(v->object); + store.castValue = valueType->propertyValueSourceCast(); + output->addInstruction(store); + + } else if (v->type == Value::ValueInterceptor) { + genObject(v->object); + + Instruction::StoreValueInterceptor store; + if (valueTypeProperty) { + store.property = genValueTypeData(prop, valueTypeProperty); + store.owner = 1; + } else { + store.property = prop->core; + store.owner = 0; + } + QQmlType *valueType = toQmlType(v->object); + store.castValue = valueType->propertyValueInterceptorCast(); + output->addInstruction(store); + } + + } +} + +bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj) +{ + if (prop->value || + prop->values.isMany() || + prop->values.first()->object) + COMPILE_EXCEPTION(prop, tr("Invalid use of id property")); + + QQmlScript::Value *idValue = prop->values.first(); + QString val = idValue->primitive(); + + COMPILE_CHECK(checkValidId(idValue, val)); + + if (compileState->ids.value(val)) + COMPILE_EXCEPTION(prop, tr("id is not unique")); + + prop->values.first()->type = Value::Id; + + obj->id = val; + addId(val, obj); + + return true; +} + +void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj) +{ + Q_UNUSED(id); + Q_ASSERT(!compileState->ids.value(id)); + Q_ASSERT(obj->id == id); + obj->idIndex = compileState->ids.count(); + compileState->ids.append(obj); +} + +void QQmlCompiler::addBindingReference(JSBindingReference *ref) +{ + Q_ASSERT(ref->value && !ref->value->bindingReference); + ref->value->bindingReference = ref; + compileState->totalBindingsCount++; + compileState->bindings.prepend(ref); +} + +void QQmlCompiler::saveComponentState() +{ + Q_ASSERT(compileState->root); + Q_ASSERT(compileState->root->componentCompileState == 0); + + compileState->root->componentCompileState = compileState; + + if (componentStats) + componentStats->savedComponentStats.append(componentStats->componentStat); +} + +QQmlCompilerTypes::ComponentCompileState * +QQmlCompiler::componentState(QQmlScript::Object *obj) +{ + Q_ASSERT(obj->componentCompileState); + return obj->componentCompileState; +} + +// Build attached property object. In this example, +// Text { +// GridView.row: 10 +// } +// GridView is an attached property object. +bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->value); + Q_ASSERT(prop->index != -1); // This is set in buildProperty() + + compileState->objectDepth.push(); + + obj->addAttachedProperty(prop); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + + compileState->objectDepth.pop(); + + return true; +} + + +// Build "grouped" properties. In this example: +// Text { +// font.pointSize: 12 +// font.family: "Helvetica" +// } +// font is a nested property. pointSize and family are not. +bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->type != 0); + Q_ASSERT(prop->index != -1); + + if (QQmlValueTypeFactory::isValueType(prop->type)) { + if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) { + + if (!prop->values.isEmpty()) { + if (prop->values.first()->location < prop->value->location) { + COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value")); + } else { + COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value")); + } + } + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) { + COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + } + + + if (prop->isAlias) { + for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) { + vtProp->isAlias = true; + } + } + + COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type], + prop->value, obj, ctxt.incr())); + obj->addValueTypeProperty(prop); + } else { + COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); + } + + } else { + // Load the nested property's meta type + prop->value->metatype = enginePrivate->metaObjectForType(prop->type); + if (!prop->value->metatype) + COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); + + if (!prop->values.isEmpty()) + COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property")); + + obj->addGroupedProperty(prop); + + compileState->objectDepth.push(); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + + compileState->objectDepth.pop(); + } + + return true; +} + +bool QQmlCompiler::buildValueTypeProperty(QObject *type, + QQmlScript::Object *obj, + QQmlScript::Object *baseObj, + const BindingContext &ctxt) +{ + compileState->objectDepth.push(); + + if (obj->defaultProperty) + COMPILE_EXCEPTION(obj, tr("Invalid property use")); + obj->metatype = type->metaObject(); + + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + + QQmlPropertyData *d = property(obj, prop->name()); + if (d == 0) + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString())); + + prop->index = d->coreIndex; + prop->type = d->propType; + prop->core = *d; + prop->isValueTypeSubProperty = true; + + if (prop->value) + COMPILE_EXCEPTION(prop, tr("Property assignment expected")); + + if (prop->values.isMany()) { + COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); + } else if (!prop->values.isEmpty()) { + QQmlScript::Value *value = prop->values.first(); + + if (value->object) { + COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); + } else if (value->value.isScript()) { + // ### Check for writability + + //optimization for . enum assignments + bool isEnumAssignment = false; + + if (prop->core.isEnum()) + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment)); + + if (isEnumAssignment) { + value->type = Value::Literal; + } else { + JSBindingReference *reference = pool->New(); + reference->expression = value->value; + reference->property = prop; + reference->value = value; + reference->bindingContext = ctxt; + reference->bindingContext.owner++; + addBindingReference(reference); + value->type = Value::PropertyBinding; + } + } else { + COMPILE_CHECK(testLiteralAssignment(prop, value)); + value->type = Value::Literal; + } + } + + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { + Q_ASSERT(v->object); + + COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); + } + + obj->addValueProperty(prop); + } + + compileState->objectDepth.pop(); + + return true; +} + +// Build assignments to QML lists. QML lists are properties of type +// QQmlListProperty. List properties can accept a list of +// objects, or a single binding. +bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->core.isQList()); + + compileState->listDepth.push(); + + int t = prop->type; + + obj->addValueProperty(prop); + + int listType = enginePrivate->listType(t); + bool listTypeIsInterface = QQmlMetaType::isInterface(listType); + + bool assignedBinding = false; + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { + if (v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(buildObject(v->object, ctxt)); + + // We check object coercian here. We check interface assignment + // at runtime. + if (!listTypeIsInterface) { + if (!canCoerce(listType, v->object)) { + COMPILE_EXCEPTION(v, tr("Cannot assign object to list")); + } + } + + } else if (v->value.isScript()) { + if (assignedBinding) + COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists")); + + assignedBinding = true; + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + v->type = Value::PropertyBinding; + } else { + COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists")); + } + } + + compileState->listDepth.pop(); + + return true; +} + +// Compiles an assignment to a QQmlScriptString property +bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.isMany()) + COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property")); + + if (prop->values.first()->object) + COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected")); + + prop->scriptStringScope = ctxt.stack; + obj->addScriptStringProperty(prop); + + return true; +} + +// Compile regular property assignments of the form "property: " +bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const BindingContext &ctxt) +{ + obj->addValueProperty(prop); + + if (prop->values.isMany()) + COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") ); + + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { + if (v->object) { + + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); + + } + } + + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { + Q_ASSERT(v->object); + COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); + } + + return true; +} + +// Compile assigning a single object instance to a regular property +bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + + if (QQmlMetaType::isInterface(prop->type)) { + + // Assigning an object to an interface ptr property + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + + } else if (prop->type == QMetaType::QVariant) { + + // Assigning an object to a QVariant + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else { + // Normally buildObject() will set this up, but we need the static + // meta object earlier to test for assignability. It doesn't matter + // that there may still be outstanding synthesized meta object changes + // on this type, as they are not relevant for assignability testing + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); + + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions that might + // effect the properties on the type, but don't effect assignability + const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type); + + // Will be true if the assgned type inherits propertyMetaObject + bool isAssignable = false; + // Determine isAssignable value + if (propertyMetaObject) { + const QMetaObject *c = v->object->metatype; + while(c) { + isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject)); + c = c->superClass(); + } + } + + if (isAssignable) { + // Simple assignment + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) { + // Automatic "Component" insertion + QQmlScript::Object *root = v->object; + QQmlScript::Object *component = pool->New(); + component->type = componentTypeRef(); + component->typeName = QStringLiteral("Qt/Component"); + component->metatype = &QQmlComponent::staticMetaObject; + component->location = root->location; + QQmlScript::Value *componentValue = pool->New(); + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + } else { + COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property")); + } + } + + return true; +} + +// Compile assigning a single object instance to a regular property using the "on" syntax. +// +// For example: +// Item { +// NumberAnimation on x { } +// } +bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Object *baseObj, + QQmlScript::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); + + Q_UNUSED(obj); + + if (!prop->core.isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + + + // Normally buildObject() will set this up, but we need the static + // meta object earlier to test for assignability. It doesn't matter + // that there may still be outstanding synthesized meta object changes + // on this type, as they are not relevant for assignability testing + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); + + // Will be true if the assigned type inherits QQmlPropertyValueSource + bool isPropertyValue = false; + // Will be true if the assigned type inherits QQmlPropertyValueInterceptor + bool isPropertyInterceptor = false; + if (QQmlType *valueType = toQmlType(v->object)) { + isPropertyValue = valueType->propertyValueSourceCast() != -1; + isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1; + } + + if (isPropertyValue || isPropertyInterceptor) { + // Assign as a property value source + COMPILE_CHECK(buildObject(v->object, ctxt)); + + if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) + buildDynamicMeta(baseObj, ForceCreation); + v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; + } else { + COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString())); + } + + return true; +} + +// Compile assigning a literal or binding to a regular property +bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + + if (v->value.isScript()) { + + //optimization for . enum assignments + if (prop->core.isEnum()) { + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment)); + if (isEnumAssignment) { + v->type = Value::Literal; + return true; + } + } + + // Test for other binding optimizations + if (!buildLiteralBinding(v, prop, ctxt)) + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + + v->type = Value::PropertyBinding; + + } else { + + COMPILE_CHECK(testLiteralAssignment(prop, v)); + + v->type = Value::Literal; + } + + return true; +} + +bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *v, + bool *isAssignment) +{ + *isAssignment = false; + if (!prop->core.isEnum()) + return true; + + QMetaProperty mprop = obj->metaObject()->property(prop->index); + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + + QString string = v->value.asString(); + if (!string.at(0).isUpper()) + return true; + + QStringList parts = string.split(QLatin1Char('.')); + if (parts.count() != 2) + return true; + + QString typeName = parts.at(0); + QQmlType *type = 0; + unit->imports().resolveType(typeName, &type, 0, 0, 0, 0); + + //handle enums on value types (where obj->typeName is empty) + QString objTypeName = obj->typeName; + if (objTypeName.isEmpty()) { + QQmlType *objType = toQmlType(obj); + if (objType) + objTypeName = objType->qmlTypeName(); + } + + if (!type) + return true; + + QString enumValue = parts.at(1); + int value; + bool ok; + + if (objTypeName == type->qmlTypeName()) { + // When these two match, we can short cut the search + if (mprop.isFlagType()) { + value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); + } else { + value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); + } + } else { + // Otherwise we have to search the whole type + // This matches the logic in QV8TypeWrapper + QByteArray enumName = enumValue.toUtf8(); + const QMetaObject *metaObject = type->baseMetaObject(); + ok = false; + for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + value = e.keyToValue(enumName.constData(), &ok); + } + } + + if (!ok) + return true; + + v->type = Value::Literal; + v->value = QQmlScript::Variant((double)value); + *isAssignment = true; + + return true; +} + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast (0)->staticQtMetaObject; } +}; + +// Similar logic to above, but not knowing target property. +int QQmlCompiler::evaluateEnum(const QByteArray& script) const +{ + int dot = script.indexOf('.'); + if (dot > 0) { + const QByteArray &scope = script.left(dot); + QQmlType *type = 0; + unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0); + if (!type && scope != "Qt") + return -1; + const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get(); + const char *key = script.constData() + dot+1; + int i = mo->enumeratorCount(); + while (i--) { + bool ok; + int v = mo->enumerator(i).keyToValue(key, &ok); + if (ok) + return v; + } + } + return -1; +} + +const QMetaObject *QQmlCompiler::resolveType(const QString& name) const +{ + QQmlType *qmltype = 0; + if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) + return 0; + if (!qmltype) + return 0; + return qmltype->metaObject(); +} + +// similar to logic of completeComponentBuild, but also sticks data +// into primitives at the end +int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name) +{ + QQmlRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1)); + + QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0); + + return output->indexForString(rewrite); +} + +QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name) +{ + QQmlRewrite::RewriteSignalHandler rewriteSignalHandler; + return rewriteSignalHandler(value.asAST(), value.asScript(), name); +} + +// Ensures that the dynamic meta specification on obj is valid +bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj) +{ + bool seenDefaultProperty = false; + + // We use a coarse grain, 31 bit hash to check if there are duplicates. + // Calculating the hash for the names is not a waste as we have to test + // them against the illegalNames set anyway. + QHashField propNames; + QHashField methodNames; + + // Check properties + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + const QQmlScript::Object::DynamicProperty &prop = *p; + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION(&prop, tr("Duplicate default property")); + seenDefaultProperty = true; + } + + if (propNames.testAndSet(prop.name.hash())) { + for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; + p2 = obj->dynamicProperties.next(p2)) { + if (p2->name == prop.name) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Duplicate property name")); + } + } + } + + if (prop.name.at(0).isUpper()) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Property names cannot begin with an upper case letter")); + } + + if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Illegal property name")); + } + } + + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + const QQmlScript::Object::DynamicSignal &currSig = *s; + + if (methodNames.testAndSet(currSig.name.hash())) { + for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s; + s2 = obj->dynamicSignals.next(s2)) { + if (s2->name == currSig.name) + COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name")); + } + } + + if (currSig.name.at(0).isUpper()) + COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter")); + if (enginePrivate->v8engine()->illegalNames().contains(currSig.name)) + COMPILE_EXCEPTION(&currSig, tr("Illegal signal name")); + } + + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + const QQmlScript::Object::DynamicSlot &currSlot = *s; + + if (methodNames.testAndSet(currSlot.name.hash())) { + for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2; + s2 = obj->dynamicSignals.next(s2)) { + if (s2->name == currSlot.name) + COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name")); + } + for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s; + s2 = obj->dynamicSlots.next(s2)) { + if (s2->name == currSlot.name) + COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name")); + } + } + + if (currSlot.name.at(0).isUpper()) + COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter")); + if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name)) + COMPILE_EXCEPTION(&currSlot, tr("Illegal method name")); + } + + return true; +} + +bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj) +{ + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { + + if (!p->defaultValue || p->type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p->isDefaultProperty) { + property = obj->getDefaultProperty(); + } else { + property = obj->getProperty(p->name); + if (!property->values.isEmpty()) + COMPILE_EXCEPTION(property, tr("Property value set multiple times")); + } + + if (p->isReadOnly) + property->isReadOnlyDeclaration = true; + + if (property->value) + COMPILE_EXCEPTION(property, tr("Invalid property nesting")); + + property->values.append(p->defaultValue->values); + } + return true; +} + +Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) + +bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode) +{ + Q_ASSERT(obj); + Q_ASSERT(obj->metatype); + + if (mode != ForceCreation && + obj->dynamicProperties.isEmpty() && + obj->dynamicSignals.isEmpty() && + obj->dynamicSlots.isEmpty()) + return true; + + bool resolveAlias = (mode == ResolveAliases); + + const Object::DynamicProperty *defaultProperty = 0; + int aliasCount = 0; + int varPropCount = 0; + int totalPropCount = 0; + int firstPropertyVarIndex = 0; + + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + + if (p->type == Object::DynamicProperty::Alias) + aliasCount++; + if (p->type == Object::DynamicProperty::Var) + varPropCount++; + + if (p->isDefaultProperty && + (resolveAlias || p->type != Object::DynamicProperty::Alias)) + defaultProperty = p; + + if (!resolveAlias) { + // No point doing this for both the alias and non alias cases + QQmlPropertyData *d = property(obj, p->name); + if (d && d->isFinal()) + COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); + } + } + + bool buildData = resolveAlias || aliasCount == 0; + + QByteArray dynamicData; + if (buildData) { + typedef QQmlVMEMetaData VMD; + + dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + + (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) + + obj->dynamicSlots.count() * sizeof(VMD::MethodData) + + aliasCount * sizeof(VMD::AliasData), 0); + } + + int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1); + + QByteArray newClassName = obj->metatype->className(); + newClassName.append("_QML_"); + newClassName.append(QByteArray::number(uniqueClassId)); + + if (compileState->root == obj && !compileState->nested) { + QString path = output->url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + if (lastSlash > -1) { + QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId); + } + } + + QFastMetaBuilder builder; + QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), + obj->dynamicProperties.count() - (resolveAlias?0:aliasCount), + obj->dynamicSlots.count(), + obj->dynamicSignals.count() + obj->dynamicProperties.count(), + defaultProperty?1:0); + + struct TypeData { + Object::DynamicProperty::Type dtype; + int metaType; + const char *cppType; + } builtinTypes[] = { + { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" }, + { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" }, + { Object::DynamicProperty::Int, QMetaType::Int, "int" }, + { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" }, + { Object::DynamicProperty::Real, QMetaType::Double, "double" }, + { Object::DynamicProperty::String, QMetaType::QString, "QString" }, + { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" }, + { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" }, + { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" }, + { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" }, + { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" }, + }; + static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); + QFastMetaBuilder::StringRef typeRefs[builtinTypeCount]; + + // Reserve dynamic properties + if (obj->dynamicProperties.count()) { + typedef QQmlVMEMetaData VMD; + + int effectivePropertyIndex = 0; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + + // Reserve space for name + p->nameRef = builder.newString(p->name.utf8length()); + + int propertyType = 0; + bool readonly = false; + QFastMetaBuilder::StringRef typeRef; + + if (p->type == Object::DynamicProperty::Alias) { + continue; + } else if (p->type < builtinTypeCount) { + Q_ASSERT(builtinTypes[p->type].dtype == p->type); + propertyType = builtinTypes[p->type].metaType; + if (typeRefs[p->type].isEmpty()) + typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType)); + typeRef = typeRefs[p->type]; + + } else { + Q_ASSERT(p->type == Object::DynamicProperty::CustomList || + p->type == Object::DynamicProperty::Custom); + + // XXX don't double resolve this in the case of an alias run + + QByteArray customTypeName; + QQmlType *qmltype = 0; + QString url; + if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(p, tr("Invalid property type")); + + if (!qmltype) { + QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url)); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); + + QQmlCompiledData *data = tdata->compiledData(); + customTypeName = data->root->className(); + data->release(); + tdata->release(); + } else { + customTypeName = qmltype->typeName(); + } + + if (p->type == Object::DynamicProperty::Custom) { + customTypeName += '*'; + propertyType = QMetaType::QObjectStar; + } else { + readonly = true; + customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">"); + propertyType = qMetaTypeId >(); + } + + p->resolvedCustomTypeName = pool->NewByteArray(customTypeName); + p->typeRef = builder.newString(customTypeName.length()); + typeRef = p->typeRef; + } + + if (p->type == Object::DynamicProperty::Var) + continue; + + if (p->isReadOnly) + readonly = true; + + if (buildData) { + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + vmd->propertyCount++; + (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; + } + + if (p->type < builtinTypeCount) + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + else + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + + effectivePropertyIndex++; + } + + if (varPropCount) { + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + if (buildData) + vmd->varPropertyCount = varPropCount; + firstPropertyVarIndex = effectivePropertyIndex; + totalPropCount = varPropCount + effectivePropertyIndex; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Var) { + QFastMetaBuilder::StringRef typeRef = typeRefs[p->type]; + if (buildData) { + vmd->propertyCount++; + (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant; + } + + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + QMetaType::QVariant, + p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + + effectivePropertyIndex++; + } + } + } + + if (aliasCount) { + int aliasIndex = 0; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Alias) { + if (resolveAlias) { + Q_ASSERT(buildData); + ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++; + COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, + aliasIndex, *p)); + } + // Even if we aren't resolving the alias, we need a fake signal so that the + // metaobject remains consistent across the resolve and non-resolve alias runs + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + effectivePropertyIndex++; + aliasIndex++; + } + } + } + } + + // Reserve default property + QFastMetaBuilder::StringRef defPropRef; + if (defaultProperty) { + defPropRef = builder.newString(strlen("DefaultProperty")); + builder.setClassInfo(0, defPropRef, defaultProperty->nameRef); + } + + // Reserve dynamic signals + int signalIndex = 0; + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + + int paramCount = s->parameterNames.count(); + + int signatureSize = s->name.utf8length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */; + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */; + + s->signatureRef = builder.newString(signatureSize); + if (namesSize) s->parameterNamesRef = builder.newString(namesSize); + + if (buildData) + ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; + + builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef); + ++signalIndex; + } + + // Reserve dynamic slots + if (obj->dynamicSlots.count()) { + + // Allocate QVariant string + if (typeRefs[0].isEmpty()) + typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType)); + + typedef QQmlVMEMetaData VMD; + + int methodIndex = 0; + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); + + int signatureSize = s->name.utf8length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1)); + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); + + s->signatureRef = builder.newString(signatureSize); + if (namesSize) s->parameterNamesRef = builder.newString(namesSize); + + builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]); + + if (buildData) { + QString funcScript; + funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + + namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); + funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); + for (int jj = 0; jj < paramCount; ++jj) { + if (jj) funcScript.append(QLatin1Char(',')); + funcScript.append(QLatin1String(s->parameterNames.at(jj))); + } + funcScript += QLatin1Char(')') + s->body + QLatin1Char(')'); + + QByteArray utf8 = funcScript.toUtf8(); + VMD::MethodData methodData = { s->parameterNames.count(), 0, + utf8.length(), + s->location.start.line }; + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + vmd->methodCount++; + + VMD::MethodData &md = *(vmd->methodData() + methodIndex); + md = methodData; + md.bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)utf8.constData(), utf8.length()); + } + + + methodIndex++; + } + } + + // Now allocate used builtin types + for (int ii = 0; ii < builtinTypeCount; ++ii) { + if (!typeRefs[ii].isEmpty()) + typeRefs[ii].load(builtinTypes[ii].cppType); + } + + // Now allocate properties + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + + char *d = p->changedSignatureRef.data(); + p->name.writeUtf8(d); + strcpy(d + p->name.utf8length(), "Changed()"); + + if (p->type == Object::DynamicProperty::Alias && !resolveAlias) + continue; + + p->nameRef.load(p->name); + + if (p->type >= builtinTypeCount) { + Q_ASSERT(p->resolvedCustomTypeName); + p->typeRef.load(*p->resolvedCustomTypeName); + } + } + + // Allocate default property if necessary + if (defaultProperty) + strcpy(defPropRef.data(), "DefaultProperty"); + + // Now allocate signals + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + + char *d = s->signatureRef.data(); + char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); + s->name.writeUtf8(d); d += s->name.utf8length(); + *d++ = '('; + + for (int jj = 0; jj < s->parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, s->parameterTypes.at(jj).constData()); + d += s->parameterTypes.at(jj).length(); + s->parameterNames.at(jj).writeUtf8(d2); + d2 += s->parameterNames.at(jj).utf8length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; + } + + // Now allocate methods + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + char *d = s->signatureRef.data(); + char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); + s->name.writeUtf8(d); d += s->name.utf8length(); + *d++ = '('; + for (int jj = 0; jj < s->parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, "QVariant"); + d += strlen("QVariant"); + strcpy(d2, s->parameterNames.at(jj).constData()); + d2 += s->parameterNames.at(jj).length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; + } + + // Now allocate class name + classNameRef.load(newClassName); + + obj->metadata = builder.toData(); + builder.fromData(&obj->extObject, obj->metatype, obj->metadata); + + if (mode == IgnoreAliases && aliasCount) + compileState->aliasingObjects.append(obj); + + obj->synthdata = dynamicData; + + if (obj->synthCache) { + obj->synthCache->release(); + obj->synthCache = 0; + } + + if (obj->type != -1) { + QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine); + QQmlPropertyCache *cache = + superCache->copyAndAppend(engine, &obj->extObject, + QQmlPropertyData::NoFlags, + QQmlPropertyData::IsVMEFunction, + QQmlPropertyData::IsVMESignal); + + // now we modify the flags appropriately for var properties. + int propertyOffset = obj->extObject.propertyOffset(); + QQmlPropertyData *currPropData = 0; + for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) { + currPropData = cache->property(pvi + propertyOffset); + currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty); + } + + obj->synthCache = cache; + } + + return true; +} + +bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) +{ + if (val.isEmpty()) + COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); + + QChar ch = val.at(0); + if (ch.isLetter() && !ch.isLower()) + COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); + + QChar u(QLatin1Char('_')); + if (!ch.isLetter() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); + + for (int ii = 1; ii < val.count(); ++ii) { + ch = val.at(ii); + if (!ch.isLetterOrNumber() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); + } + + if (enginePrivate->v8engine()->illegalNames().contains(val)) + COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); + + return true; +} + +#include + +static QStringList astNodeToStringList(QQmlJS::AST::Node *node) +{ + if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast(node)->name.toString(); + return QStringList() << name; + } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { + QQmlJS::AST::FieldMemberExpression *expr = static_cast(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name.toString()); + return rv; + } + return QStringList(); +} + +bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, + QByteArray &data, + QQmlScript::Object *obj, + int propIndex, int aliasIndex, + Object::DynamicProperty &prop) +{ + if (!prop.defaultValue) + COMPILE_EXCEPTION(obj, tr("No property alias location")); + + if (!prop.defaultValue->values.isOne() || + prop.defaultValue->values.first()->object || + !prop.defaultValue->values.first()->value.isScript()) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST(); + if (!node) + COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() < 1 || alias.count() > 3) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as , . or ..")); + + QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); + if (!idObject) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); + + QByteArray typeName; + + int propIdx = -1; + int flags = 0; + int type = 0; + bool writable = false; + bool resettable = false; + if (alias.count() == 2 || alias.count() == 3) { + propIdx = indexOfProperty(idObject, alias.at(1)); + + if (-1 == propIdx) { + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + } else if (propIdx > 0xFFFF) { + COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds")); + } + + QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); + if (!aliasProperty.isScriptable()) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + writable = aliasProperty.isWritable() && !prop.isReadOnly; + resettable = aliasProperty.isResettable() && !prop.isReadOnly; + + if (aliasProperty.type() < QVariant::UserType + || uint(aliasProperty.type()) == QMetaType::QVariant) + type = aliasProperty.type(); + + if (alias.count() == 3) { + QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; + if (!valueType) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + propIdx |= ((unsigned int)aliasProperty.type()) << 24; + + int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); + if (valueTypeIndex == -1) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + Q_ASSERT(valueTypeIndex <= 0xFF); + + aliasProperty = valueType->metaObject()->property(valueTypeIndex); + propIdx |= (valueTypeIndex << 16); + + // update the property type + type = aliasProperty.type(); + if (type >= (int)QVariant::UserType) + type = 0; + } + + if (aliasProperty.isEnumType()) + typeName = "int"; // Avoid introducing a dependency on the aliased metaobject + else + typeName = aliasProperty.typeName(); + } else { + Q_ASSERT(idObject->type != -1); // How else did it get an id? + + const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); + if (ref.type) + typeName = ref.type->typeName(); + else + typeName = ref.component->root->className(); + + typeName += '*'; + } + + if (typeName.endsWith('*')) + flags |= QML_ALIAS_FLAG_PTR; + + QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; + + typedef QQmlVMEMetaData VMD; + VMD *vmd = (QQmlVMEMetaData *)data.data(); + *(vmd->aliasData() + aliasIndex) = aliasData; + + prop.nameRef = builder.newString(prop.name.utf8length()); + prop.resolvedCustomTypeName = pool->NewByteArray(typeName); + prop.typeRef = builder.newString(typeName.length()); + + int propertyFlags = 0; + if (writable) + propertyFlags |= QFastMetaBuilder::Writable; + if (resettable) + propertyFlags |= QFastMetaBuilder::Resettable; + + builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, + (QFastMetaBuilder::PropertyFlag)propertyFlags, + propIndex); + + return true; +} + +bool QQmlCompiler::buildBinding(QQmlScript::Value *value, + QQmlScript::Property *prop, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); + + if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); + + JSBindingReference *reference = pool->New(); + reference->expression = value->value; + reference->property = prop; + reference->value = value; + reference->bindingContext = ctxt; + addBindingReference(reference); + + return true; +} + +bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v, + QQmlScript::Property *prop, + const QQmlCompilerTypes::BindingContext &) +{ + Q_ASSERT(v->value.isScript()); + + if (!prop->core.isWritable()) + return false; + + AST::Node *binding = v->value.asAST(); + + if (prop->type == QVariant::String) { + if (AST::CallExpression *e = AST::cast(binding)) { + if (AST::IdentifierExpression *i = AST::cast(e->base)) { + if (i->name == qsTrId_string) { + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg2 || !arg2->next)) { + + QStringRef text; + int n = -1; + + text = AST::cast(arg1->expression)->value; + if (arg2) n = (int)AST::cast(arg2->expression)->value; + + TrBindingReference *reference = pool->New(); + reference->dataType = BindingReference::TrId; + reference->text = text; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } else if (i->name == qsTr_string) { + + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + AST::ArgumentList *arg3 = arg2?arg2->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) && + (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg3 || !arg3->next)) { + + QStringRef text; + QStringRef comment; + int n = -1; + + text = AST::cast(arg1->expression)->value; + if (arg2) comment = AST::cast(arg2->expression)->value; + if (arg3) n = (int)AST::cast(arg3->expression)->value; + + TrBindingReference *reference = pool->New(); + reference->dataType = BindingReference::Tr; + reference->text = text; + reference->comment = comment; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } + } + } + + } + + return false; +} + +void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding, + QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Property *valueTypeProperty) +{ + Q_UNUSED(obj); + Q_ASSERT(binding->bindingReference); + + const BindingReference &ref = *binding->bindingReference; + if (ref.dataType == BindingReference::TrId) { + const TrBindingReference &tr = static_cast(ref); + + Instruction::StoreTrIdString store; + store.propertyIndex = prop->core.coreIndex; + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::Tr) { + const TrBindingReference &tr = static_cast(ref); + + Instruction::StoreTrString store; + store.propertyIndex = prop->core.coreIndex; + store.context = translationContextIndex(); + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.comment = output->indexForByteArray(tr.comment.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::V4) { + const JSBindingReference &js = static_cast(ref); + + Instruction::StoreV4Binding store; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; + if (valueTypeProperty) { + store.property = (valueTypeProperty->index & 0xFFFF) | + ((valueTypeProperty->type & 0xFF)) << 16 | + ((prop->index & 0xFF) << 24); + store.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.property = prop->index; + store.isRoot = (compileState->root == obj); + } + store.line = binding->location.start.line; + store.column = binding->location.start.column; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::V8) { + const JSBindingReference &js = static_cast(ref); + + Instruction::StoreV8Binding store; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; + if (valueTypeProperty) { + store.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.isRoot = (compileState->root == obj); + } + store.line = binding->location.start.line; + store.column = binding->location.start.column; + + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { + store.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.property = prop->core; + } + + output->addInstruction(store); + } else if (ref.dataType == BindingReference::QtScript) { + const JSBindingReference &js = static_cast(ref); + + QQmlInstruction store; + store.assignBinding.value = output->indexForString(js.rewrittenExpression); + store.assignBinding.context = js.bindingContext.stack; + store.assignBinding.owner = js.bindingContext.owner; + store.assignBinding.line = binding->location.start.line; + store.assignBinding.column = binding->location.start.column; + + if (valueTypeProperty) { + store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.assignBinding.isRoot = (compileState->root == obj); + } + + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { + store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.assignBinding.property = prop->core; + } + output->addInstructionHelper( + !prop->isAlias ? QQmlInstruction::StoreBinding + : QQmlInstruction::StoreBindingOnAlias + , store); + } else { + Q_ASSERT(!"Unhandled BindingReference::DataType type"); + } +} + +int QQmlCompiler::genContextCache() +{ + if (compileState->ids.count() == 0) + return -1; + + QQmlIntegerCache *cache = new QQmlIntegerCache(); + cache->reserve(compileState->ids.count()); + for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) + cache->add(o->id, o->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + +QQmlPropertyData +QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, + QQmlScript::Property *prop) +{ + typedef QQmlPropertyPrivate QDPP; + return QDPP::saveValueType(prop->parent->metaObject(), prop->index, + enginePrivate->valueTypes[prop->type]->metaObject(), + valueTypeProp->index, engine); +} + +bool QQmlCompiler::completeComponentBuild() +{ + if (componentStats) + componentStats->componentStat.ids = compileState->ids.count(); + + for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; + aliasObject = compileState->aliasingObjects.next(aliasObject)) + COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + + QV4Compiler::Expression expr(unit->imports()); + expr.component = compileState->root; + expr.ids = &compileState->ids; + expr.importCache = output->importCache; + + QV4Compiler bindingCompiler; + + QList sharedBindings; + + for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { + + JSBindingReference &binding = *b; + + // ### We don't currently optimize for bindings on alias's - because + // of the solution to QTBUG-13719 + if (!binding.property->isAlias) { + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; + + int index = bindingCompiler.compile(expr, enginePrivate); + if (index != -1) { + binding.dataType = BindingReference::V4; + binding.compiledIndex = index; + if (componentStats) + componentStats->componentStat.optimizedBindings.append(b->value->location); + continue; + } + } + + // Pre-rewrite the expression + QString expression = binding.expression.asScript(); + + QQmlRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString()); + bool isSharable = false; + binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); + + if (isSharable && !binding.property->isValueTypeSubProperty && !binding.property->isAlias /* See above re alias */ && + binding.property->type != qMetaTypeId()) { + binding.dataType = BindingReference::V8; + sharedBindings.append(b); + } else { + binding.dataType = BindingReference::QtScript; + } + + if (componentStats) + componentStats->componentStat.scriptBindings.append(b->value->location); + } + + if (!sharedBindings.isEmpty()) { + struct Sort { + static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs) + { + return lhs->value->location.start.line < rhs->value->location.start.line; + } + }; + + qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt); + + int startLineNumber = sharedBindings.at(0)->value->location.start.line; + int lineNumber = startLineNumber; + + QByteArray functionArray("[", 1); + for (int ii = 0; ii < sharedBindings.count(); ++ii) { + + JSBindingReference *reference = sharedBindings.at(ii); + QQmlScript::Value *value = reference->value; + const QString &expression = reference->rewrittenExpression; + + if (ii != 0) functionArray.append(",", 1); + + while (lineNumber < value->location.start.line) { + lineNumber++; + functionArray.append("\n", 1); + } + + functionArray += expression.toUtf8(); + lineNumber += expression.count(QLatin1Char('\n')); + reference->compiledIndex = ii; + } + functionArray.append("]", 1); + + compileState->v8BindingProgram = functionArray; + compileState->v8BindingProgramLine = startLineNumber; + } + + if (bindingCompiler.isValid()) + compileState->compiledBindingData = bindingCompiler.program(); + + // Check pop()'s matched push()'s + Q_ASSERT(compileState->objectDepth.depth() == 0); + Q_ASSERT(compileState->listDepth.depth() == 0); + + saveComponentState(); + + return true; +} + +void QQmlCompiler::dumpStats() +{ + Q_ASSERT(componentStats); + qWarning().nospace() << "QML Document: " << output->url.toString(); + for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) { + const ComponentStat &stat = componentStats->savedComponentStats.at(ii); + qWarning().nospace() << " Component Line " << stat.lineNumber; + qWarning().nospace() << " Total Objects: " << stat.objects; + qWarning().nospace() << " IDs Used: " << stat.ids; + qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count(); + + { + QByteArray output; + for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) { + if (0 == (ii % 10)) { + if (ii) output.append("\n"); + output.append(" "); + } + + output.append("("); + output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line)); + output.append(":"); + output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column)); + output.append(") "); + } + if (!output.isEmpty()) + qWarning().nospace() << output.constData(); + } + + qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count(); + { + QByteArray output; + for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) { + if (0 == (ii % 10)) { + if (ii) output.append("\n"); + output.append(" "); + } + + output.append("("); + output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line)); + output.append(":"); + output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column)); + output.append(") "); + } + if (!output.isEmpty()) + qWarning().nospace() << output.constData(); + } + } +} + +/*! + Returns true if from can be assigned to a (QObject) property of type + to. +*/ +bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from) +{ + const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); + + while (fromMo) { + if (QQmlPropertyPrivate::equal(fromMo, toMo)) + return true; + fromMo = fromMo->superClass(); + } + return false; +} + +/*! + Returns the element name, as written in the QML file, for o. +*/ +QString QQmlCompiler::elementName(QQmlScript::Object *o) +{ + Q_ASSERT(o); + if (o->type != -1) { + return output->types.at(o->type).className; + } else { + return QString(); + } +} + +QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QQmlType *type = 0; + while (!type && mo) { + type = QQmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + +QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj) +{ + const QMetaObject *mo = obj->metatype; + + int idx = mo->indexOfClassInfo("DeferredPropertyNames"); + if (idx == -1) + return QStringList(); + + QMetaClassInfo classInfo = mo->classInfo(idx); + QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); + return rv; +} + +QQmlPropertyData * +QQmlCompiler::property(QQmlScript::Object *object, int index) +{ + QQmlPropertyCache *cache = 0; + + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + + return cache->property(index); +} + +QQmlPropertyData * +QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + QQmlPropertyCache *cache = 0; + + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + + QQmlPropertyData *d = cache->property(name); + + // Find the first property + while (d && d->isFunction()) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return 0; + } else { + return d; + } +} + +// This code must match the semantics of QQmlPropertyPrivate::findSignalByName +QQmlPropertyData * +QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + QQmlPropertyCache *cache = 0; + + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + + + QQmlPropertyData *d = cache->property(name); + if (notInRevision) *notInRevision = false; + + while (d && !(d->isFunction())) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return 0; + } else if (d) { + return d; + } + + if (name.endsWith(Changed_string)) { + QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length()); + + d = property(object, propName, notInRevision); + if (d) + return cache->method(d->notifyIndex); + } + + return 0; +} + +// This code must match the semantics of QQmlPropertyPrivate::findSignalByName +int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name, + bool *notInRevision) +{ + QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision); + return d?d->coreIndex:-1; +} + +int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name, + bool *notInRevision) +{ + return indexOfProperty(object, QStringRef(&name), notInRevision); +} + +int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name, + bool *notInRevision) +{ + QQmlPropertyData *d = property(object, name, notInRevision); + return d?d->coreIndex:-1; +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h new file mode 100644 index 0000000000..9b13b7e63b --- /dev/null +++ b/src/qml/qml/qqmlcompiler_p.h @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCOMPILER_P_H +#define QQMLCOMPILER_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 "qqml.h" +#include "qqmlerror.h" +#include +#include "qqmlinstruction_p.h" +#include "qqmlscript_p.h" +#include "qqmlengine_p.h" +#include +#include "qqmlpropertycache_p.h" +#include "qqmlintegercache_p.h" +#include "qqmltypenamecache_p.h" +#include "qqmltypeloader_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlEngine; +class QQmlComponent; +class QQmlContext; +class QQmlContextData; + +class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, + public QQmlCleanup +{ +public: + QQmlCompiledData(QQmlEngine *engine); + virtual ~QQmlCompiledData(); + + QQmlEngine *engine; + + QString name; + QUrl url; + QQmlTypeNameCache *importCache; + + struct TypeReference + { + TypeReference() + : type(0), typePropertyCache(0), component(0) {} + + QString className; + QQmlType *type; + QQmlPropertyCache *typePropertyCache; + QQmlCompiledData *component; + + const QMetaObject *metaObject() const; + QQmlPropertyCache *propertyCache() const; + QQmlPropertyCache *createPropertyCache(QQmlEngine *); + }; + QList types; + + struct V8Program { + V8Program(const QByteArray &p, QQmlCompiledData *c) + : program(p), cdata(c) {} + + QByteArray program; + v8::Persistent bindings; + QQmlCompiledData *cdata; + }; + + QList programs; + + const QMetaObject *root; + QAbstractDynamicMetaObject rootData; + QQmlPropertyCache *rootPropertyCache; + QList primitives; + QList datas; + QByteArray bytecode; + QList propertyCaches; + QList contextCaches; + QList scripts; + QList urls; + + struct Instruction { +#define QML_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlInstructionData I; + FOR_EACH_QML_INSTR(QML_INSTR_DATA_TYPEDEF) +#undef QML_INSTR_DATA_TYPEDEF + private: + Instruction(); + }; + + void dumpInstructions(); + + template + int addInstruction(const QQmlInstructionData &data) + { + QQmlInstruction genericInstr; + QQmlInstructionMeta::setData(genericInstr, data); + return addInstructionHelper(static_cast(Instr), genericInstr); + } + int nextInstructionIndex(); + QQmlInstruction *instruction(int index); + QQmlInstruction::Type instructionType(const QQmlInstruction *instr); + + bool isInitialized() const { return hasEngine(); } + void initialize(QQmlEngine *); + +protected: + virtual void destroy(); // From QQmlRefCount + virtual void clear(); // From QQmlCleanup + +private: + friend class QQmlCompiler; + + int addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr); + void dump(QQmlInstruction *, int idx = -1); + QQmlCompiledData(const QQmlCompiledData &other); + QQmlCompiledData &operator=(const QQmlCompiledData &other); + QByteArray packData; + int pack(const char *, size_t); + + int indexForString(const QString &); + int indexForByteArray(const QByteArray &); + int indexForUrl(const QUrl &); +}; + +namespace QQmlCompilerTypes { + struct BindingContext + { + BindingContext() + : stack(0), owner(0), object(0) {} + BindingContext(QQmlScript::Object *o) + : stack(0), owner(0), object(o) {} + BindingContext incr() const { + BindingContext rv(object); + rv.stack = stack + 1; + return rv; + } + bool isSubContext() const { return stack != 0; } + int stack; + int owner; + QQmlScript::Object *object; + }; + + struct BindingReference + { + enum DataType { QtScript, V4, V8, + Tr, TrId }; + DataType dataType; + }; + + struct JSBindingReference : public QQmlPool::Class, + public BindingReference + { + JSBindingReference() : nextReference(0) {} + + QQmlScript::Variant expression; + QQmlScript::Property *property; + QQmlScript::Value *value; + + int compiledIndex; + + QString rewrittenExpression; + BindingContext bindingContext; + + JSBindingReference *nextReference; + }; + + struct TrBindingReference : public QQmlPool::POD, + public BindingReference + { + QStringRef text; + QStringRef comment; + int n; + }; + + struct IdList : public QFieldList + { + QQmlScript::Object *value(const QString &id) const { + for (QQmlScript::Object *o = first(); o; o = next(o)) { + if (o->id == id) + return o; + } + return 0; + } + }; + + struct DepthStack { + DepthStack() : _depth(0), _maxDepth(0) {} + DepthStack(const DepthStack &o) : _depth(o._depth), _maxDepth(o._maxDepth) {} + DepthStack &operator=(const DepthStack &o) { _depth = o._depth; _maxDepth = o._maxDepth; return *this; } + + int depth() const { return _depth; } + int maxDepth() const { return _maxDepth; } + + void push() { ++_depth; _maxDepth = qMax(_depth, _maxDepth); } + void pop() { --_depth; Q_ASSERT(_depth >= 0); Q_ASSERT(_maxDepth > _depth); } + + void pushPop(int count) { _maxDepth = qMax(_depth + count, _maxDepth); } + private: + int _depth; + int _maxDepth; + }; + + // Contains all the incremental compiler state about a component. As + // a single QML file can have multiple components defined, there may be + // more than one of these for each compile + struct ComponentCompileState : public QQmlPool::Class + { + ComponentCompileState() + : parserStatusCount(0), totalBindingsCount(0), pushedProperties(0), nested(false), + v8BindingProgramLine(-1), root(0) {} + + IdList ids; + int parserStatusCount; + int totalBindingsCount; + int pushedProperties; + bool nested; + + QByteArray compiledBindingData; + QByteArray v8BindingProgram; + int v8BindingProgramLine; + + DepthStack objectDepth; + DepthStack listDepth; + + typedef QQmlCompilerTypes::JSBindingReference B; + typedef QFieldList JSBindingReferenceList; + JSBindingReferenceList bindings; + typedef QQmlScript::Object O; + typedef QFieldList AliasingObjectsList; + AliasingObjectsList aliasingObjects; + QQmlScript::Object *root; + }; +}; + +class QMetaObjectBuilder; +class Q_AUTOTEST_EXPORT QQmlCompiler +{ + Q_DECLARE_TR_FUNCTIONS(QQmlCompiler) +public: + QQmlCompiler(QQmlPool *); + + bool compile(QQmlEngine *, QQmlTypeData *, QQmlCompiledData *); + + bool isError() const; + QList errors() const; + + static bool isAttachedPropertyName(const QString &); + static bool isSignalPropertyName(const QString &); + static bool isAttachedPropertyName(const QHashedStringRef &); + static bool isSignalPropertyName(const QHashedStringRef &); + + int evaluateEnum(const QByteArray& script) const; // for QQmlCustomParser::evaluateEnum + const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType + int rewriteBinding(const QQmlScript::Variant& value, const QString& name); // for QQmlCustomParser::rewriteBinding + QString rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name); // for QQmlCustomParser::rewriteSignalHandler + +private: + typedef QQmlCompiledData::Instruction Instruction; + + static void reset(QQmlCompiledData *); + + void compileTree(QQmlScript::Object *tree); + + + bool buildObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); + bool buildComponent(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); + bool buildSubObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); + bool buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &); + bool buildProperty(QQmlScript::Property *prop, QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &); + bool buildPropertyInNamespace(QQmlImportedNamespace *ns, + QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &); + bool buildIdProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); + bool buildAttachedProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildGroupedProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildValueTypeProperty(QObject *type, + QQmlScript::Object *obj, + QQmlScript::Object *baseObj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildListProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildScriptStringProperty(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildPropertyAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildPropertyObjectAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *value, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildPropertyOnAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Object *baseObj, + QQmlScript::Value *value, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *value, + const QQmlCompilerTypes::BindingContext &ctxt); + bool doesPropertyExist(QQmlScript::Property *prop, QQmlScript::Object *obj); + bool testLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Value *value); + bool testQualifiedEnumAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Value *value, + bool *isAssignment); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation }; + bool mergeDynamicMetaProperties(QQmlScript::Object *obj); + bool buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QQmlScript::Object *obj); + bool buildBinding(QQmlScript::Value *, QQmlScript::Property *prop, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildLiteralBinding(QQmlScript::Value *, QQmlScript::Property *prop, + const QQmlCompilerTypes::BindingContext &ctxt); + bool buildComponentFromRoot(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); + bool compileAlias(QFastMetaBuilder &, + QByteArray &data, + QQmlScript::Object *obj, + int propIndex, int aliasIndex, + QQmlScript::Object::DynamicProperty &); + bool completeComponentBuild(); + bool checkValidId(QQmlScript::Value *, const QString &); + + + void genObject(QQmlScript::Object *obj); + void genObjectBody(QQmlScript::Object *obj); + void genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *); + void genComponent(QQmlScript::Object *obj); + void genValueProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); + void genListProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); + void genPropertyAssignment(QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Property *valueTypeProperty = 0); + void genLiteralAssignment(QQmlScript::Property *prop, + QQmlScript::Value *value); + void genBindingAssignment(QQmlScript::Value *binding, + QQmlScript::Property *prop, + QQmlScript::Object *obj, + QQmlScript::Property *valueTypeProperty = 0); + int genContextCache(); + + QQmlPropertyData genValueTypeData(QQmlScript::Property *prop, + QQmlScript::Property *valueTypeProp); + + int componentTypeRef(); + int translationContextIndex(); + + static QQmlType *toQmlType(QQmlScript::Object *from); + bool canCoerce(int to, QQmlScript::Object *from); + + QString elementName(QQmlScript::Object *); + + QStringList deferredProperties(QQmlScript::Object *); + + QQmlPropertyData *property(QQmlScript::Object *, int); + QQmlPropertyData *property(QQmlScript::Object *, const QHashedStringRef &, + bool *notInRevision = 0); + QQmlPropertyData *signal(QQmlScript::Object *, const QHashedStringRef &, + bool *notInRevision = 0); + int indexOfProperty(QQmlScript::Object *, const QHashedStringRef &, bool *notInRevision = 0); + int indexOfProperty(QQmlScript::Object *, const QString &, bool *notInRevision = 0); + int indexOfSignal(QQmlScript::Object *, const QString &, bool *notInRevision = 0); + + void addId(const QString &, QQmlScript::Object *); + + void dumpStats(); + + void addBindingReference(QQmlCompilerTypes::JSBindingReference *); + + QQmlCompilerTypes::ComponentCompileState *compileState; + + QQmlPool *pool; + + QQmlCompilerTypes::ComponentCompileState *componentState(QQmlScript::Object *); + void saveComponentState(); + + QList exceptions; + QQmlCompiledData *output; + QQmlEngine *engine; + QQmlEnginePrivate *enginePrivate; + QQmlScript::Object *unitRoot; + QQmlTypeData *unit; + int cachedComponentTypeRef; + int cachedTranslationContextIndex; + + // Compiler component statistics. Only collected if QML_COMPILER_STATS=1 + struct ComponentStat + { + ComponentStat() : ids(0), objects(0) {} + + int lineNumber; + + int ids; + QList scriptBindings; + QList optimizedBindings; + int objects; + }; + struct ComponentStats : public QQmlPool::Class + { + ComponentStat componentStat; + QList savedComponentStats; + }; + ComponentStats *componentStats; +}; + +QT_END_NAMESPACE + +#endif // QQMLCOMPILER_P_H diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp new file mode 100644 index 0000000000..e168f063c0 --- /dev/null +++ b/src/qml/qml/qqmlcomponent.cpp @@ -0,0 +1,1350 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcomponent.h" +#include "qqmlcomponent_p.h" +#include "qqmlcomponentattached_p.h" + +#include "qqmlcompiler_p.h" +#include "qqmlcontext_p.h" +#include "qqmlengine_p.h" +#include "qqmlvme_p.h" +#include "qqml.h" +#include "qqmlengine.h" +#include "qqmlbinding_p.h" +#include "qqmlbinding_p_p.h" +#include "qqmlscript_p.h" +#include +#include +#include "qqmlincubator.h" +#include "qqmlincubator_p.h" + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlComponentExtension : public QV8Engine::Deletable +{ +public: + QQmlComponentExtension(QV8Engine *); + virtual ~QQmlComponentExtension(); + + v8::Persistent incubationConstructor; + v8::Persistent initialProperties; + v8::Persistent forceCompletion; +}; +V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); + +/* + Try to do what's necessary for a reasonable display of the type + name, but no more (just enough for the client to do more extensive cleanup). + + Should only be called when debugging is enabled. +*/ +static inline QString buildTypeNameForDebug(const QMetaObject *metaObject) +{ + static const QString qmlMarker(QLatin1String("_QML")); + static const QChar underscore(QLatin1Char('_')); + static const QChar asterisk(QLatin1Char('*')); + QQmlType *type = QQmlMetaType::qmlType(metaObject); + QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(metaObject->className()); + if (!type) { + //### optimize further? + int marker = typeName.indexOf(qmlMarker); + if (marker != -1 && marker < typeName.count() - 1) { + if (typeName[marker + 1] == underscore) { + const QString className = typeName.left(marker) + asterisk; + type = QQmlMetaType::qmlType(QMetaType::type(className.toUtf8())); + if (type) + typeName = type->qmlTypeName(); + } + } + } + return typeName; +} + +/*! + \class QQmlComponent + \since 4.7 + \brief The QQmlComponent class encapsulates a QML component definition. + \mainclass + + Components are reusable, encapsulated QML elements with well-defined interfaces. + They are often defined in \l {qdeclarativedocuments.html}{Component Files}. + + A QQmlComponent instance can be created from a QML file. + For example, if there is a \c main.qml file like this: + + \qml + import QtQuick 2.0 + + Item { + width: 200 + height: 200 + } + \endqml + + The following code loads this QML file as a component, creates an instance of + this component using create(), and then queries the \l Item's \l {Item::}{width} + value: + + \code + QQmlEngine *engine = new QQmlEngine; + QQmlComponent component(engine, QUrl::fromLocalFile("main.qml")); + + QObject *myObject = component.create(); + QQuickItem *item = qobject_cast(myObject); + int width = item->width(); // width = 200 + \endcode + + + \section2 Network Components + + If the URL passed to QQmlComponent is a network resource, or if the QML document references a + network resource, the QQmlComponent has to fetch the network data before it is able to create + objects. In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading} + \l {QQmlComponent::status()}{status}. An application will have to wait until the component + is \l {QQmlComponent::Ready}{Ready} before calling \l {QQmlComponent::create()}. + + The following example shows how to load a QML file from a network resource. After creating + the QQmlComponent, it tests whether the component is loading. If it is, it connects to the + QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method + directly. Note that QQmlComponent::isLoading() may be false for a network component if the + component has been cached and is ready immediately. + + \code + MyApplication::MyApplication() + { + // ... + component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml")); + if (component->isLoading()) + QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), + this, SLOT(continueLoading())); + else + continueLoading(); + } + + void MyApplication::continueLoading() + { + if (component->isError()) { + qWarning() << component->errors(); + } else { + QObject *myObject = component->create(); + } + } + \endcode + + \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code} +*/ + +/*! + \qmlclass Component QQmlComponent + \ingroup qml-utility-elements + \since 4.7 + \brief The Component element encapsulates a QML component definition. + + Components are reusable, encapsulated QML elements with well-defined interfaces. + + Components are often defined by \l {qdeclarativedocuments.html}{component files} - + that is, \c .qml files. The \e Component element essentially allows QML components + to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file. + This may be useful for reusing a small component within a QML file, or for defining + a component that logically belongs with other QML components within a file. + + For example, here is a component that is used by multiple \l Loader objects. + It contains a single item, a \l Rectangle: + + \snippet doc/src/snippets/qml/component.qml 0 + + Notice that while a \l Rectangle by itself would be automatically + rendered and displayed, this is not the case for the above rectangle + because it is defined inside a \c Component. The component encapsulates the + QML elements within, as if they were defined in a separate QML + file, and is not loaded until requested (in this case, by the + two \l Loader objects). + + Defining a \c Component is similar to defining a \l {QML Document}{QML document}. + A QML document has a single top-level item that defines the behaviors and + properties of that component, and cannot define properties or behaviors outside + of that top-level item. In the same way, a \c Component definition contains a single + top level item (which in the above example is a \l Rectangle) and cannot define any + data outside of this item, with the exception of an \e id (which in the above example + is \e redSquare). + + The \c Component element is commonly used to provide graphical components + for views. For example, the ListView::delegate property requires a \c Component + to specify how each list item is to be displayed. + + \c Component objects can also be created dynamically using + \l{QML:Qt::createComponent()}{Qt.createComponent()}. +*/ + +/*! + \qmlattachedsignal Component::onCompleted() + + Emitted after component "startup" has completed. This can be used to + execute script code at startup, once the full QML environment has been + established. + + The \c {Component::onCompleted} attached property can be applied to + any element. The order of running the \c onCompleted scripts is + undefined. + + \qml + Rectangle { + Component.onCompleted: console.log("Completed Running!") + Rectangle { + Component.onCompleted: console.log("Nested Completed Running!") + } + } + \endqml +*/ + +/*! + \qmlattachedsignal Component::onDestruction() + + Emitted as the component begins destruction. This can be used to undo + work done in the onCompleted signal, or other imperative code in your + application. + + The \c {Component::onDestruction} attached property can be applied to + any element. However, it applies to the destruction of the component as + a whole, and not the destruction of the specific object. The order of + running the \c onDestruction scripts is undefined. + + \qml + Rectangle { + Component.onDestruction: console.log("Destruction Beginning!") + Rectangle { + Component.onDestruction: console.log("Nested Destruction Beginning!") + } + } + \endqml + + \sa QtQml +*/ + +/*! + \enum QQmlComponent::Status + + Specifies the loading status of the QQmlComponent. + + \value Null This QQmlComponent has no data. Call loadUrl() or setData() to add QML content. + \value Ready This QQmlComponent is ready and create() may be called. + \value Loading This QQmlComponent is loading network data. + \value Error An error has occurred. Call errors() to retrieve a list of \{QQmlError}{errors}. +*/ + +void QQmlComponentPrivate::typeDataReady(QQmlTypeData *) +{ + Q_Q(QQmlComponent); + + Q_ASSERT(typeData); + + fromTypeData(typeData); + typeData = 0; + + emit q->statusChanged(q->status()); +} + +void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p) +{ + Q_Q(QQmlComponent); + + progress = p; + + emit q->progressChanged(p); +} + +void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data) +{ + url = data->finalUrl(); + QQmlCompiledData *c = data->compiledData(); + + if (!c) { + Q_ASSERT(data->isError()); + state.errors = data->errors(); + } else { + cc = c; + } + + data->release(); +} + +void QQmlComponentPrivate::clear() +{ + if (typeData) { + typeData->unregisterCallback(this); + typeData->release(); + typeData = 0; + } + + if (cc) { + cc->release(); + cc = 0; + } +} + +/*! + \internal +*/ +QQmlComponent::QQmlComponent(QObject *parent) + : QObject(*(new QQmlComponentPrivate), parent) +{ +} + +/*! + Destruct the QQmlComponent. +*/ +QQmlComponent::~QQmlComponent() +{ + Q_D(QQmlComponent); + + if (d->state.completePending) { + qWarning("QQmlComponent: Component destroyed while completion pending"); + d->completeCreate(); + } + + if (d->typeData) { + d->typeData->unregisterCallback(d); + d->typeData->release(); + } + if (d->cc) + d->cc->release(); +} + +/*! + \qmlproperty enumeration Component::status + This property holds the status of component loading. It can be one of: + \list + \o Component.Null - no data is available for the component + \o Component.Ready - the component has been loaded, and can be used to create instances. + \o Component.Loading - the component is currently being loaded + \o Component.Error - an error occurred while loading the component. + Calling errorString() will provide a human-readable description of any errors. + \endlist + */ + +/*! + \property QQmlComponent::status + The component's current \l{QQmlComponent::Status} {status}. + */ +QQmlComponent::Status QQmlComponent::status() const +{ + Q_D(const QQmlComponent); + + if (d->typeData) + return Loading; + else if (!d->state.errors.isEmpty()) + return Error; + else if (d->engine && d->cc) + return Ready; + else + return Null; +} + +/*! + Returns true if status() == QQmlComponent::Null. +*/ +bool QQmlComponent::isNull() const +{ + return status() == Null; +} + +/*! + Returns true if status() == QQmlComponent::Ready. +*/ +bool QQmlComponent::isReady() const +{ + return status() == Ready; +} + +/*! + Returns true if status() == QQmlComponent::Error. +*/ +bool QQmlComponent::isError() const +{ + return status() == Error; +} + +/*! + Returns true if status() == QQmlComponent::Loading. +*/ +bool QQmlComponent::isLoading() const +{ + return status() == Loading; +} + +/*! + \qmlproperty real Component::progress + The progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ + +/*! + \property QQmlComponent::progress + The progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ +qreal QQmlComponent::progress() const +{ + Q_D(const QQmlComponent); + return d->progress; +} + +/*! + \fn void QQmlComponent::progressChanged(qreal progress) + + Emitted whenever the component's loading progress changes. \a progress will be the + current progress between 0.0 (nothing loaded) and 1.0 (finished). +*/ + +/*! + \fn void QQmlComponent::statusChanged(QQmlComponent::Status status) + + Emitted whenever the component's status changes. \a status will be the + new status. +*/ + +/*! + Create a QQmlComponent with no data and give it the specified + \a engine and \a parent. Set the data with setData(). +*/ +QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent) + : QObject(*(new QQmlComponentPrivate), parent) +{ + Q_D(QQmlComponent); + d->engine = engine; +} + +/*! + Create a QQmlComponent from the given \a url and give it the + specified \a parent and \a engine. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. + + \sa loadUrl() +*/ +QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent) +: QObject(*(new QQmlComponentPrivate), parent) +{ + Q_D(QQmlComponent); + d->engine = engine; + loadUrl(url); +} + +/*! + Create a QQmlComponent from the given \a fileName and give it the specified + \a parent and \a engine. + + \sa loadUrl() +*/ +QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, + QObject *parent) +: QObject(*(new QQmlComponentPrivate), parent) +{ + Q_D(QQmlComponent); + d->engine = engine; + loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName))); +} + +/*! + \internal +*/ +QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent) + : QObject(*(new QQmlComponentPrivate), parent) +{ + Q_D(QQmlComponent); + d->engine = engine; + d->cc = cc; + cc->addref(); + d->start = start; + d->url = cc->url; + d->progress = 1.0; +} + +/*! + Sets the QQmlComponent to use the given QML \a data. If \a url + is provided, it is used to set the component name and to provide + a base path for items resolved by this component. +*/ +void QQmlComponent::setData(const QByteArray &data, const QUrl &url) +{ + Q_D(QQmlComponent); + + d->clear(); + + d->url = url; + + QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.get(data, url); + + if (typeData->isCompleteOrError()) { + d->fromTypeData(typeData); + } else { + d->typeData = typeData; + d->typeData->registerCallback(d); + } + + d->progress = 1.0; + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! +Returns the QQmlContext the component was created in. This is only +valid for components created directly from QML. +*/ +QQmlContext *QQmlComponent::creationContext() const +{ + Q_D(const QQmlComponent); + if(d->creationContext) + return d->creationContext->asQQmlContext(); + + return qmlContext(this); +} + +/*! + Load the QQmlComponent from the provided \a url. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. +*/ +void QQmlComponent::loadUrl(const QUrl &url) +{ + Q_D(QQmlComponent); + + d->clear(); + + if ((url.isRelative() && !url.isEmpty()) + || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929 + d->url = d->engine->baseUrl().resolved(url); + else + d->url = url; + + if (url.isEmpty()) { + QQmlError error; + error.setDescription(tr("Invalid empty URL")); + d->state.errors << error; + return; + } + + QQmlTypeData *data = QQmlEnginePrivate::get(d->engine)->typeLoader.get(d->url); + + if (data->isCompleteOrError()) { + d->fromTypeData(data); + d->progress = 1.0; + } else { + d->typeData = data; + d->typeData->registerCallback(d); + d->progress = data->progress(); + } + + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! + Return the list of errors that occurred during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ +QList QQmlComponent::errors() const +{ + Q_D(const QQmlComponent); + if (isError()) + return d->state.errors; + else + return QList(); +} + +/*! + \qmlmethod string Component::errorString() + + Returns a human-readable description of any errors. + + The string includes the file, location, and description of each error. + If multiple errors are present they are separated by a newline character. + + If no errors are present, an empty string is returned. +*/ + +/*! + \internal + errorString is only meant as a way to get the errors in script +*/ +QString QQmlComponent::errorString() const +{ + Q_D(const QQmlComponent); + QString ret; + if(!isError()) + return ret; + foreach(const QQmlError &e, d->state.errors) { + ret += e.url().toString() + QLatin1Char(':') + + QString::number(e.line()) + QLatin1Char(' ') + + e.description() + QLatin1Char('\n'); + } + return ret; +} + +/*! + \qmlproperty url Component::url + The component URL. This is the URL that was used to construct the component. +*/ + +/*! + \property QQmlComponent::url + The component URL. This is the URL passed to either the constructor, + or the loadUrl() or setData() methods. +*/ +QUrl QQmlComponent::url() const +{ + Q_D(const QQmlComponent); + return d->url; +} + +/*! + \internal +*/ +QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + If \a context is 0 (the default), it will create the instance in the + engine' s \l {QQmlEngine::rootContext()}{root context}. +*/ +QObject *QQmlComponent::create(QQmlContext *context) +{ + Q_D(QQmlComponent); + + if (!context) + context = d->engine->rootContext(); + + QObject *rv = beginCreate(context); + completeCreate(); + return rv; +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QQmlComponent::create() to create a + component. + + Create an object instance from this component. Returns 0 if creation + failed. \a publicContext specifies the context within which to create the object + instance. + + When QQmlComponent constructs an instance, it occurs in three steps: + \list 1 + \i The object hierarchy is created, and constant values are assigned. + \i Property bindings are evaluated for the the first time. + \i If applicable, QQmlParserStatus::componentComplete() is called on objects. + \endlist + QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it + only performs step 1. QQmlComponent::completeCreate() must be called to + complete steps 2 and 3. + + This breaking point is sometimes useful when using attached properties to + communicate information to an instantiated component, as it allows their + initial values to be configured before property bindings take effect. +*/ +QObject *QQmlComponent::beginCreate(QQmlContext *publicContext) +{ + Q_D(QQmlComponent); + + Q_ASSERT(publicContext); + QQmlContextData *context = QQmlContextData::get(publicContext); + + return d->beginCreate(context); +} + +QObject * +QQmlComponentPrivate::beginCreate(QQmlContextData *context) +{ + Q_Q(QQmlComponent); + if (!context) { + qWarning("QQmlComponent: Cannot create a component in a null context"); + return 0; + } + + if (!context->isValid()) { + qWarning("QQmlComponent: Cannot create a component in an invalid context"); + return 0; + } + + if (context->engine != engine) { + qWarning("QQmlComponent: Must create component in context from the same QQmlEngine"); + return 0; + } + + if (state.completePending) { + qWarning("QQmlComponent: Cannot create new component instance before completing the previous"); + return 0; + } + + if (!q->isReady()) { + qWarning("QQmlComponent: Component is not ready"); + return 0; + } + + QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); + + bool isRoot = enginePriv->inProgressCreations == 0; + enginePriv->inProgressCreations++; + state.errors.clear(); + state.completePending = true; + + if (isRoot) + QQmlProfilerService::startRange(QQmlProfilerService::Creating); + + enginePriv->referenceScarceResources(); + state.vme.init(context, cc, start, creationContext); + QObject *rv = state.vme.execute(&state.errors); + enginePriv->dereferenceScarceResources(); + + if (rv) { + QQmlData *ddata = QQmlData::get(rv); + Q_ASSERT(ddata); + ddata->indestructible = true; + } + + if (enginePriv->isDebugging && rv) { + if (!context->isInternal) + context->asQQmlContextPrivate()->instances.append(rv); + QQmlEngineDebugService::instance()->objectCreated(engine, rv); + if (isRoot) { + QQmlProfilerService::rangeData(QQmlProfilerService::Creating, + buildTypeNameForDebug(rv->metaObject())); + QQmlData *data = QQmlData::get(rv); + Q_ASSERT(data); + QQmlProfilerService::rangeLocation(QQmlProfilerService::Creating, + cc->url, data->lineNumber, data->columnNumber); + } + } + + return rv; +} + +void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, + QObject *object, ConstructionState *state) +{ + enginePriv->inProgressCreations++; + state->errors.clear(); + state->completePending = true; + + state->vme.initDeferred(object); + state->vme.execute(&state->errors); +} + +void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state) +{ + if (state->completePending) { + state->vme.complete(); + + state->completePending = false; + + enginePriv->inProgressCreations--; + + if (0 == enginePriv->inProgressCreations) { + while (enginePriv->erroredBindings) { + enginePriv->warning(enginePriv->erroredBindings->error); + enginePriv->erroredBindings->removeError(); + } + } + } +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QQmlComponent::create() to create a + component. + + Complete a component creation begin with QQmlComponent::beginCreate(). +*/ +void QQmlComponent::completeCreate() +{ + Q_D(QQmlComponent); + + d->completeCreate(); +} + +void QQmlComponentPrivate::completeCreate() +{ + if (state.completePending) { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + complete(ep, &state); + + QQmlProfilerService::endRange(QQmlProfilerService::Creating); + } +} + +QQmlComponentAttached::QQmlComponentAttached(QObject *parent) +: QObject(parent), prev(0), next(0) +{ +} + +QQmlComponentAttached::~QQmlComponentAttached() +{ + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} + +/*! + \internal +*/ +QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj) +{ + QQmlComponentAttached *a = new QQmlComponentAttached(obj); + + QQmlEngine *engine = qmlEngine(obj); + if (!engine) + return a; + + if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin + QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine); + a->add(&p->activeVME->componentAttached); + } else { + QQmlData *d = QQmlData::get(obj); + Q_ASSERT(d); + Q_ASSERT(d->context); + a->add(&d->context->componentAttached); + } + + return a; +} + +void QQmlComponent::create(QQmlIncubator &i, QQmlContext *context, + QQmlContext *forContext) +{ + Q_D(QQmlComponent); + + if (!context) + context = d->engine->rootContext(); + + QQmlContextData *contextData = QQmlContextData::get(context); + QQmlContextData *forContextData = contextData; + if (forContext) forContextData = QQmlContextData::get(forContext); + + if (!contextData->isValid()) { + qWarning("QQmlComponent: Cannot create a component in an invalid context"); + return; + } + + if (contextData->engine != d->engine) { + qWarning("QQmlComponent: Must create component in context from the same QQmlEngine"); + return; + } + + if (!isReady()) { + qWarning("QQmlComponent: Component is not ready"); + return; + } + + i.clear(); + QQmlIncubatorPrivate *p = i.d; + + QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine); + + p->component = d->cc; p->component->addref(); + p->vme.init(contextData, d->cc, d->start, d->creationContext); + + enginePriv->incubate(i, forContextData); +} + +class QV8IncubatorResource : public QV8ObjectResource, + public QQmlIncubator +{ +V8_RESOURCE_TYPE(IncubatorType) +public: + QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous); + + static v8::Handle StatusChangedGetter(v8::Local, + const v8::AccessorInfo& info); + static v8::Handle StatusGetter(v8::Local, + const v8::AccessorInfo& info); + static v8::Handle ObjectGetter(v8::Local, + const v8::AccessorInfo& info); + static v8::Handle ForceCompletionGetter(v8::Local, + const v8::AccessorInfo& info); + static v8::Handle ForceCompletion(const v8::Arguments &args); + + static void StatusChangedSetter(v8::Local, v8::Local value, + const v8::AccessorInfo& info); + + void dispose(); + + v8::Persistent me; + QQmlGuard parent; + v8::Persistent valuemap; + v8::Persistent qmlGlobal; +protected: + virtual void statusChanged(Status); + virtual void setInitialState(QObject *); +}; + +static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) +{ + if (parent) { + me->setParent(parent); + typedef QQmlPrivate::AutoParentFunction APF; + QList functions = QQmlMetaType::parentFunctions(); + + bool needParent = false; + for (int ii = 0; ii < functions.count(); ++ii) { + QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent); + if (res == QQmlPrivate::Parented) { + needParent = false; + break; + } else if (res == QQmlPrivate::IncompatibleParent) { + needParent = true; + } + } + if (needParent) + qWarning("QQmlComponent: Created graphical object was not " + "placed in the graphics scene."); + } +} + +/*! + \qmlmethod object Component::createObject(Item parent, object properties) + + Creates and returns an object instance of this component that will have + the given \a parent and \a properties. The \a properties argument is optional. + Returns null if object creation fails. + + The object will be created in the same context as the one in which the component + was created. This function will always return null when called on components + which were not created in QML. + + If you wish to create an object without setting a parent, specify \c null for + the \a parent value. Note that if the returned object is to be displayed, you + must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent} + property, or else the object will not be visible. + + If a \a parent is not provided to createObject(), a reference to the returned object must be held so that + it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards, + since setting the Item parent does not change object ownership; only the graphical parent is changed. + + As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a + map of initial property values for the created object. These values are applied before object + creation is finalized. (This is more efficient than setting property values after object creation, + particularly where large sets of property values are defined, and also allows property bindings + to be set up before the object is created.) + + The \a properties argument is specified as a map of property-value items. For example, the code + below creates an object with initial \c x and \c y values of 100 and 200, respectively: + + \js + var component = Qt.createComponent("Button.qml"); + if (component.status == Component.Ready) + component.createObject(parent, {"x": 100, "y": 100}); + \endjs + + Dynamically created instances can be deleted with the \c destroy() method. + See \l {Dynamic Object Management in QML} for more information. +*/ +void QQmlComponent::createObject(QQmlV8Function *args) +{ + Q_D(QQmlComponent); + Q_ASSERT(d->engine); + Q_ASSERT(args); + + QObject *parent = 0; + v8::Local valuemap; + + if (args->Length() >= 1) + parent = args->engine()->toQObject((*args)[0]); + + if (args->Length() >= 2) { + v8::Local v = (*args)[1]; + if (!v->IsObject() || v->IsArray()) { + qmlInfo(this) << tr("createObject: value is not an object"); + args->returnValue(v8::Null()); + return; + } + valuemap = v8::Local::Cast(v); + } + + QV8Engine *v8engine = args->engine(); + + QQmlContext *ctxt = creationContext(); + if (!ctxt) ctxt = d->engine->rootContext(); + + QObject *rv = beginCreate(ctxt); + + if (!rv) { + args->returnValue(v8::Null()); + return; + } + + QQmlComponent_setQmlParent(rv, parent); + + v8::Handle ov = v8engine->newQObject(rv); + Q_ASSERT(ov->IsObject()); + v8::Handle object = v8::Handle::Cast(ov); + + if (!valuemap.IsEmpty()) { + QQmlComponentExtension *e = componentExtension(v8engine); + // Try catch isn't needed as the function itself is loaded with try/catch + v8::Handle function = e->initialProperties->Run(args->qmlGlobal()); + v8::Handle args[] = { object, valuemap }; + v8::Handle::Cast(function)->Call(v8engine->global(), 2, args); + } + + d->completeCreate(); + + Q_ASSERT(QQmlData::get(rv)); + QQmlData::get(rv)->setImplicitDestructible(); + + if (!rv) + args->returnValue(v8::Null()); + else + args->returnValue(object); +} + +/*! + \qmlmethod object Component::incubateObject(Item parent, object properties, enum mode) + + Creates an incubator for instance of this component. Incubators allow new component + instances to be instantiated asynchronously and not cause freezes in the UI. + + The \a parent argument specifies the parent the created instance will have. Omitting the + parameter or passing null will create anobject with no parent. In this case, a reference + to the created object must be maintained by the application of the object will eventually + be garbage collected. + + The \a properties argument is specified as a map of property-value items which will be + set on the created object during its construction. \a mode may be Qt.Synchronous or + Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously. + The default is asynchronously. In some circumstances, even if Qt.Synchronous is specified, + the incubator may create the object asynchronously. This happens if the component calling + incubateObject() is itself being created asynchronously. + + All three arguments are optional. + + If successful, the method returns an incubator, otherwise null. The incubator has the following + properties: + + \list + \i status The status of the incubator. Valid values are Component.Ready, Component.Loading and + Component.Error. + \i object The created object instance. Will only be available once the incubator is in the + Ready status. + \i onStatusChanged Specifies a callback function to be invoked when the status changes. The + status is passed as a parameter to the callback. + \i forceCompletion() Call to complete incubation synchronously. + \endlist + + The following example demonstrates how to use an incubator: + + \js + var component = Qt.createComponent("Button.qml"); + + var incubator = component.incubateObject(parent, { x: 10, y: 10 }); + if (incubator.status != Component.Ready) { + incubator.onStatusChanged = function(status) { + if (status == Component.Ready) { + print ("Object", incubator.object, "is now ready!"); + } + } + } else { + print ("Object", incubator.object, "is ready immediately!"); + } + \endjs +*/ + +void QQmlComponent::incubateObject(QQmlV8Function *args) +{ + Q_D(QQmlComponent); + Q_ASSERT(d->engine); + Q_UNUSED(d); + Q_ASSERT(args); + + QObject *parent = 0; + v8::Local valuemap; + QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous; + + if (args->Length() >= 1) + parent = args->engine()->toQObject((*args)[0]); + + if (args->Length() >= 2) { + v8::Local v = (*args)[1]; + if (v->IsNull()) { + } else if (!v->IsObject() || v->IsArray()) { + qmlInfo(this) << tr("createObject: value is not an object"); + args->returnValue(v8::Null()); + return; + } else { + valuemap = v8::Local::Cast(v); + } + } + + if (args->Length() >= 3) { + quint32 v = (*args)[2]->Uint32Value(); + if (v == 0) + mode = QQmlIncubator::Asynchronous; + else if (v == 1) + mode = QQmlIncubator::AsynchronousIfNested; + } + + QQmlComponentExtension *e = componentExtension(args->engine()); + + QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode); + v8::Local o = e->incubationConstructor->NewInstance(); + o->SetExternalResource(r); + + if (!valuemap.IsEmpty()) { + r->valuemap = qPersistentNew(valuemap); + r->qmlGlobal = qPersistentNew(args->qmlGlobal()); + } + r->parent = parent; + r->me = qPersistentNew(o); + + create(*r, creationContext()); + + if (r->status() == QQmlIncubator::Null) { + r->dispose(); + args->returnValue(v8::Null()); + } else { + args->returnValue(o); + } +} + +// XXX used by QSGLoader +void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle qmlGlobal, v8::Handle valuemap, QObject *toCreate) +{ + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + QV8Engine *v8engine = ep->v8engine(); + + v8::HandleScope handle_scope; + v8::Context::Scope scope(v8engine->context()); + v8::Handle ov = v8engine->newQObject(toCreate); + Q_ASSERT(ov->IsObject()); + v8::Handle object = v8::Handle::Cast(ov); + + if (!valuemap.IsEmpty()) { + QQmlComponentExtension *e = componentExtension(v8engine); + // Try catch isn't needed as the function itself is loaded with try/catch + v8::Handle function = e->initialProperties->Run(qmlGlobal); + v8::Handle args[] = { object, valuemap }; + v8::Handle::Cast(function)->Call(v8engine->global(), 2, args); + } + + QQmlData *ddata = QQmlData::get(toCreate); + Q_ASSERT(ddata); + ddata->setImplicitDestructible(); +} + + +QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine) +{ + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine)); + + { + v8::Local ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->InstanceTemplate()->SetInternalFieldCount(1); + ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"), + QV8IncubatorResource::StatusChangedGetter, + QV8IncubatorResource::StatusChangedSetter); + ft->InstanceTemplate()->SetAccessor(v8::String::New("status"), + QV8IncubatorResource::StatusGetter); + ft->InstanceTemplate()->SetAccessor(v8::String::New("object"), + QV8IncubatorResource::ObjectGetter); + ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"), + QV8IncubatorResource::ForceCompletionGetter); + incubationConstructor = qPersistentNew(ft->GetFunction()); + } + + { +#define INITIALPROPERTIES_SOURCE \ + "(function(object, values) {"\ + "try {"\ + "for(var property in values) {" \ + "try {"\ + "var properties = property.split(\".\");"\ + "var o = object;"\ + "for (var ii = 0; ii < properties.length - 1; ++ii) {"\ + "o = o[properties[ii]];"\ + "}"\ + "o[properties[properties.length - 1]] = values[property];"\ + "} catch(e) {}"\ + "}"\ + "} catch(e) {}"\ + "})" + initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE))); +#undef INITIALPROPERTIES_SOURCE + } +} + +v8::Handle QV8IncubatorResource::ObjectGetter(v8::Local, + const v8::AccessorInfo& info) +{ + QV8IncubatorResource *r = v8_resource_check(info.This()); + return r->engine->newQObject(r->object()); +} + +v8::Handle QV8IncubatorResource::ForceCompletionGetter(v8::Local, + const v8::AccessorInfo& info) +{ + QV8IncubatorResource *r = v8_resource_check(info.This()); + return componentExtension(r->engine)->forceCompletion; +} + +v8::Handle QV8IncubatorResource::ForceCompletion(const v8::Arguments &args) +{ + QV8IncubatorResource *r = v8_resource_cast(args.This()); + if (!r) + V8THROW_TYPE("Not an incubator object"); + + r->forceCompletion(); + + return v8::Undefined(); +} + +v8::Handle QV8IncubatorResource::StatusGetter(v8::Local, + const v8::AccessorInfo& info) +{ + QV8IncubatorResource *r = v8_resource_check(info.This()); + return v8::Integer::NewFromUnsigned(r->status()); +} + +v8::Handle QV8IncubatorResource::StatusChangedGetter(v8::Local, + const v8::AccessorInfo& info) +{ + return info.This()->GetInternalField(0); +} + +void QV8IncubatorResource::StatusChangedSetter(v8::Local, v8::Local value, + const v8::AccessorInfo& info) +{ + info.This()->SetInternalField(0, value); +} + +QQmlComponentExtension::~QQmlComponentExtension() +{ + qPersistentDispose(incubationConstructor); + qPersistentDispose(initialProperties); + qPersistentDispose(forceCompletion); +} + +QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m) +: QV8ObjectResource(engine), QQmlIncubator(m) +{ +} + +void QV8IncubatorResource::setInitialState(QObject *o) +{ + QQmlComponent_setQmlParent(o, parent); + + if (!valuemap.IsEmpty()) { + QQmlComponentExtension *e = componentExtension(engine); + + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + v8::Handle function = e->initialProperties->Run(qmlGlobal); + v8::Handle args[] = { engine->newQObject(o), valuemap }; + v8::Handle::Cast(function)->Call(engine->global(), 2, args); + + qPersistentDispose(valuemap); + qPersistentDispose(qmlGlobal); + } +} + +void QV8IncubatorResource::dispose() +{ + qPersistentDispose(valuemap); + qPersistentDispose(qmlGlobal); + // No further status changes are forthcoming, so we no long need a self reference + qPersistentDispose(me); +} + +void QV8IncubatorResource::statusChanged(Status s) +{ + if (s == Ready) { + Q_ASSERT(QQmlData::get(object())); + QQmlData::get(object())->setImplicitDestructible(); + } + + if (!me.IsEmpty()) { // Will be false in synchronous mode + v8::HandleScope scope; + v8::Local callback = me->GetInternalField(0); + + if (!callback.IsEmpty() && !callback->IsUndefined()) { + + if (callback->IsFunction()) { + v8::Context::Scope context_scope(engine->context()); + v8::Local f = v8::Local::Cast(callback); + v8::Handle args[] = { v8::Integer::NewFromUnsigned(s) }; + v8::TryCatch tc; + f->Call(me, 1, args); + if (tc.HasCaught()) { + QQmlError error; + QQmlExpressionPrivate::exceptionToError(tc.Message(), error); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), + error); + } + } + } + } + + if (s == Ready || s == Error) + dispose(); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h new file mode 100644 index 0000000000..1265fb1c7d --- /dev/null +++ b/src/qml/qml/qqmlcomponent.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCOMPONENT_H +#define QQMLCOMPONENT_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QByteArray; +class QQmlEngine; +class QQmlComponent; +class QQmlIncubator; +class QQmlV8Function; +class QQmlCompiledData; +class QQmlComponentPrivate; +class QQmlComponentAttached; + +class Q_QML_EXPORT QQmlComponent : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQmlComponent) + + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QUrl url READ url CONSTANT) + +public: + QQmlComponent(QObject *parent = 0); + QQmlComponent(QQmlEngine *, QObject *parent=0); + QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0); + QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0); + virtual ~QQmlComponent(); + + Q_ENUMS(Status) + enum Status { Null, Ready, Loading, Error }; + Status status() const; + + bool isNull() const; + bool isReady() const; + bool isError() const; + bool isLoading() const; + + QList errors() const; + Q_INVOKABLE QString errorString() const; + + qreal progress() const; + + QUrl url() const; + + virtual QObject *create(QQmlContext *context = 0); + virtual QObject *beginCreate(QQmlContext *); + virtual void completeCreate(); + + void create(QQmlIncubator &, QQmlContext *context = 0, + QQmlContext *forContext = 0); + + QQmlContext *creationContext() const; + + static QQmlComponentAttached *qmlAttachedProperties(QObject *); + +public Q_SLOTS: + void loadUrl(const QUrl &url); + void setData(const QByteArray &, const QUrl &baseUrl); + +Q_SIGNALS: + void statusChanged(QQmlComponent::Status); + void progressChanged(qreal); + +protected: + QQmlComponent(QQmlComponentPrivate &dd, QObject* parent); + Q_INVOKABLE void createObject(QQmlV8Function *); + Q_INVOKABLE void incubateObject(QQmlV8Function *); + +private: + QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent); + + Q_DISABLE_COPY(QQmlComponent) + friend class QQmlVME; + friend class QQmlTypeData; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QQmlComponent::Status) +QML_DECLARE_TYPE(QQmlComponent) +QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QQMLCOMPONENT_H diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h new file mode 100644 index 0000000000..731fb6a8a7 --- /dev/null +++ b/src/qml/qml/qqmlcomponent_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCOMPONENT_P_H +#define QQMLCOMPONENT_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 "qqmlcomponent.h" + +#include +#include "qqmlengine_p.h" +#include "qqmltypeloader_p.h" +#include +#include "qqmlvme_p.h" +#include "qqmlerror.h" +#include "qqml.h" + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QV8Engine; + +class QQmlComponent; +class QQmlEngine; +class QQmlCompiledData; + +class QQmlComponentAttached; +class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback +{ + Q_DECLARE_PUBLIC(QQmlComponent) + +public: + QQmlComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0) {} + + QObject *beginCreate(QQmlContextData *); + void completeCreate(); + void initializeObjectWithInitialProperties(v8::Handle qmlGlobal, v8::Handle valuemap, QObject *toCreate); + + QQmlTypeData *typeData; + virtual void typeDataReady(QQmlTypeData *); + virtual void typeDataProgress(QQmlTypeData *, qreal); + + void fromTypeData(QQmlTypeData *data); + + QUrl url; + qreal progress; + + int start; + QQmlCompiledData *cc; + + struct ConstructionState { + ConstructionState() : completePending(false) {} + + QQmlVME vme; + QList errors; + bool completePending; + }; + ConstructionState state; + + static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, + ConstructionState *state); + static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state); + + QQmlEngine *engine; + QQmlGuardedContextData creationContext; + + void clear(); + + static QQmlComponentPrivate *get(QQmlComponent *c) { + return static_cast(QObjectPrivate::get(c)); + } +}; + +QT_END_NAMESPACE + +#endif // QQMLCOMPONENT_P_H diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h new file mode 100644 index 0000000000..09d111c227 --- /dev/null +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCOMPONENTATTACHED_P_H +#define QQMLCOMPONENTATTACHED_P_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class Q_AUTOTEST_EXPORT QQmlComponentAttached : public QObject +{ + Q_OBJECT +public: + QQmlComponentAttached(QObject *parent = 0); + ~QQmlComponentAttached(); + + void add(QQmlComponentAttached **a) { + prev = a; next = *a; *a = this; + if (next) next->prev = &next; + } + void rem() { + if (next) next->prev = prev; + *prev = next; + next = 0; prev = 0; + } + QQmlComponentAttached **prev; + QQmlComponentAttached *next; + +Q_SIGNALS: + void completed(); + void destruction(); + +private: + friend class QQmlVME; + friend class QQmlContextData; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQMLCOMPONENTATTACHED_P_H diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp new file mode 100644 index 0000000000..38acc0b0c3 --- /dev/null +++ b/src/qml/qml/qqmlcontext.cpp @@ -0,0 +1,811 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcontext.h" +#include "qqmlcontext_p.h" +#include "qqmlcomponentattached_p.h" + +#include "qqmlcomponent_p.h" +#include "qqmlexpression_p.h" +#include "qqmlengine_p.h" +#include "qqmlengine.h" +#include "qqmlinfo.h" +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QQmlContextPrivate::QQmlContextPrivate() +: data(0), notifyIndex(-1) +{ +} + +/*! + \class QQmlContext + \since 4.7 + \brief The QQmlContext class defines a context within a QML engine. + \mainclass + + Contexts allow data to be exposed to the QML components instantiated by the + QML engine. + + Each QQmlContext contains a set of properties, distinct from its QObject + properties, that allow data to be explicitly bound to a context by name. The + context properties are defined and updated by calling + QQmlContext::setContextProperty(). The following example shows a Qt model + being bound to a context and then accessed from a QML file. + + \code + QQmlEngine engine; + QStringListModel modelData; + QQmlContext *context = new QQmlContext(engine.rootContext()); + context->setContextProperty("myModel", &modelData); + + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl()); + QObject *window = component.create(context); + \endcode + + Note it is the responsibility of the creator to delete any QQmlContext it + constructs. If the \c context object in the example is no longer needed when the + \c window component instance is destroyed, the \c context must be destroyed explicitly. + The simplest way to ensure this is to set \c window as the parent of \c context. + + To simplify binding and maintaining larger data sets, a context object can be set + on a QQmlContext. All the properties of the context object are available + by name in the context, as though they were all individually added through calls + to QQmlContext::setContextProperty(). Changes to the property's values are + detected through the property's notify signal. Setting a context object is both + faster and easier than manually adding and maintaing context property values. + + The following example has the same effect as the previous one, but it uses a context + object. + + \code + class MyDataSet : ... { + ... + Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged) + ... + }; + + MyDataSet myDataSet; + QQmlEngine engine; + QQmlContext *context = new QQmlContext(engine.rootContext()); + context->setContextObject(&myDataSet); + + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl()); + component.create(context); + \endcode + + All properties added explicitly by QQmlContext::setContextProperty() take + precedence over the context object's properties. + + \section2 The Context Hierarchy + + Contexts form a hierarchy. The root of this hierarchy is the QML engine's + \l {QQmlEngine::rootContext()}{root context}. Child contexts inherit + the context properties of their parents; if a child context sets a context property + that already exists in its parent, the new context property overrides that of the + parent. + + The following example defines two contexts - \c context1 and \c context2. The + second context overrides the "b" context property inherited from the first with a + new value. + + \code + QQmlEngine engine; + QQmlContext *context1 = new QQmlContext(engine.rootContext()); + QQmlContext *context2 = new QQmlContext(context1); + + context1->setContextProperty("a", 12); + context1->setContextProperty("b", 12); + + context2->setContextProperty("b", 15); + \endcode + + While QML objects instantiated in a context are not strictly owned by that + context, their bindings are. If a context is destroyed, the property bindings of + outstanding QML objects will stop evaluating. + + \warning Setting the context object or adding new context properties after an object + has been created in that context is an expensive operation (essentially forcing all bindings + to reevaluate). Thus whenever possible you should complete "setup" of the context + before using it to create any objects. + + \sa {Using QML Bindings in C++ Applications} +*/ + +/*! \internal */ +QQmlContext::QQmlContext(QQmlEngine *e, bool) +: QObject(*(new QQmlContextPrivate)) +{ + Q_D(QQmlContext); + d->data = new QQmlContextData(this); + + d->data->engine = e; +} + +/*! + Create a new QQmlContext as a child of \a engine's root context, and the + QObject \a parent. +*/ +QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent) +: QObject(*(new QQmlContextPrivate), parent) +{ + Q_D(QQmlContext); + d->data = new QQmlContextData(this); + + d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0); +} + +/*! + Create a new QQmlContext with the given \a parentContext, and the + QObject \a parent. +*/ +QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent) +: QObject(*(new QQmlContextPrivate), parent) +{ + Q_D(QQmlContext); + d->data = new QQmlContextData(this); + + d->data->setParent(parentContext?QQmlContextData::get(parentContext):0); +} + +/*! + \internal +*/ +QQmlContext::QQmlContext(QQmlContextData *data) +: QObject(*(new QQmlContextPrivate), 0) +{ + Q_D(QQmlContext); + d->data = data; +} + +/*! + Destroys the QQmlContext. + + Any expressions, or sub-contexts dependent on this context will be + invalidated, but not destroyed (unless they are parented to the QQmlContext + object). + */ +QQmlContext::~QQmlContext() +{ + Q_D(QQmlContext); + + if (!d->data->isInternal) + d->data->destroy(); +} + +/*! + Returns whether the context is valid. + + To be valid, a context must have a engine, and it's contextObject(), if any, + must not have been deleted. +*/ +bool QQmlContext::isValid() const +{ + Q_D(const QQmlContext); + return d->data && d->data->isValid(); +} + +/*! + Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the + QQmlEngine was destroyed. +*/ +QQmlEngine *QQmlContext::engine() const +{ + Q_D(const QQmlContext); + return d->data->engine; +} + +/*! + Return the context's parent QQmlContext, or 0 if this context has no + parent or if the parent has been destroyed. +*/ +QQmlContext *QQmlContext::parentContext() const +{ + Q_D(const QQmlContext); + return d->data->parent?d->data->parent->asQQmlContext():0; +} + +/*! + Return the context object, or 0 if there is no context object. +*/ +QObject *QQmlContext::contextObject() const +{ + Q_D(const QQmlContext); + return d->data->contextObject; +} + +/*! + Set the context \a object. +*/ +void QQmlContext::setContextObject(QObject *object) +{ + Q_D(QQmlContext); + + QQmlContextData *data = d->data; + + if (data->isInternal) { + qWarning("QQmlContext: Cannot set context object for internal context."); + return; + } + + if (!isValid()) { + qWarning("QQmlContext: Cannot set context object on invalid context."); + return; + } + + data->contextObject = object; +} + +/*! + Set a the \a value of the \a name property on this context. +*/ +void QQmlContext::setContextProperty(const QString &name, const QVariant &value) +{ + Q_D(QQmlContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + QQmlContextData *data = d->data; + + if (data->isInternal) { + qWarning("QQmlContext: Cannot set property on internal context."); + return; + } + + if (!isValid()) { + qWarning("QQmlContext: Cannot set property on invalid context."); + return; + } + + if (data->engine) { + bool ok; + QObject *o = QQmlEnginePrivate::get(data->engine)->toQObject(value, &ok); + if (ok) { + setContextProperty(name, o); + return; + } + } + + if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache(); + + int idx = data->propertyNames->value(name); + if (idx == -1) { + data->propertyNames->add(name, data->idValueCount + d->propertyValues.count()); + d->propertyValues.append(value); + + data->refreshExpressions(); + } else { + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +/*! + Set the \a value of the \a name property on this context. + + QQmlContext does \bold not take ownership of \a value. +*/ +void QQmlContext::setContextProperty(const QString &name, QObject *value) +{ + Q_D(QQmlContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + QQmlContextData *data = d->data; + + if (data->isInternal) { + qWarning("QQmlContext: Cannot set property on internal context."); + return; + } + + if (!isValid()) { + qWarning("QQmlContext: Cannot set property on invalid context."); + return; + } + + if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache(); + int idx = data->propertyNames->value(name); + + if (idx == -1) { + data->propertyNames->add(name, data->idValueCount + d->propertyValues.count()); + d->propertyValues.append(QVariant::fromValue(value)); + + data->refreshExpressions(); + } else { + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +/*! + Returns the value of the \a name property for this context + as a QVariant. + */ +QVariant QQmlContext::contextProperty(const QString &name) const +{ + Q_D(const QQmlContext); + QVariant value; + int idx = -1; + + QQmlContextData *data = d->data; + + if (data->propertyNames) + idx = data->propertyNames->value(name); + + if (idx == -1) { + QByteArray utf8Name = name.toUtf8(); + if (data->contextObject) { + QObject *obj = data->contextObject; + QQmlPropertyData local; + QQmlPropertyData *property = + QQmlPropertyCache::property(data->engine, obj, name, local); + + if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); + } + if (!value.isValid() && parentContext()) + value = parentContext()->contextProperty(name); + } else { + if (idx >= d->propertyValues.count()) + value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data()); + else + value = d->propertyValues[idx]; + } + + return value; +} + +/*! +Returns the name of \a object in this context, or an empty string if \a object +is not named in the context. Objects are named by setContextProperty(), or by ids in +the case of QML created contexts. + +If the object has multiple names, the first is returned. +*/ +QString QQmlContext::nameForObject(QObject *object) const +{ + Q_D(const QQmlContext); + + return d->data->findObjectId(object); +} + +/*! + Resolves the URL \a src relative to the URL of the + containing component. + + \sa QQmlEngine::baseUrl(), setBaseUrl() +*/ +QUrl QQmlContext::resolvedUrl(const QUrl &src) +{ + Q_D(QQmlContext); + return d->data->resolvedUrl(src); +} + +QUrl QQmlContextData::resolvedUrl(const QUrl &src) +{ + QQmlContextData *ctxt = this; + + if (src.isRelative() && !src.isEmpty()) { + if (ctxt) { + while(ctxt) { + if(ctxt->url.isValid()) + break; + else + ctxt = ctxt->parent; + } + + if (ctxt) + return ctxt->url.resolved(src); + else if (engine) + return engine->baseUrl().resolved(src); + } + return QUrl(); + } else { + return src; + } +} + + +/*! + Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl. + + Calling this function will override the url of the containing + component used by default. + + \sa resolvedUrl() +*/ +void QQmlContext::setBaseUrl(const QUrl &baseUrl) +{ + Q_D(QQmlContext); + + d->data->url = baseUrl; + d->data->urlString = baseUrl.toString(); +} + +/*! + Returns the base url of the component, or the containing component + if none is set. +*/ +QUrl QQmlContext::baseUrl() const +{ + Q_D(const QQmlContext); + const QQmlContextData* data = d->data; + while (data && data->url.isEmpty()) + data = data->parent; + + if (data) + return data->url; + else + return QUrl(); +} + +int QQmlContextPrivate::context_count(QQmlListProperty *prop) +{ + QQmlContext *context = static_cast(prop->object); + QQmlContextPrivate *d = QQmlContextPrivate::get(context); + int contextProperty = (int)(quintptr)prop->data; + + if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId >()) { + return 0; + } else { + return ((const QList *)d->propertyValues.at(contextProperty).constData())->count(); + } +} + +QObject *QQmlContextPrivate::context_at(QQmlListProperty *prop, int index) +{ + QQmlContext *context = static_cast(prop->object); + QQmlContextPrivate *d = QQmlContextPrivate::get(context); + int contextProperty = (int)(quintptr)prop->data; + + if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId >()) { + return 0; + } else { + return ((const QList *)d->propertyValues.at(contextProperty).constData())->at(index); + } +} + + +QQmlContextData::QQmlContextData() +: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), + isPragmaLibraryContext(false), unresolvedNames(false), publicContext(0), activeVMEData(0), + propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + componentAttached(0), v4bindings(0), v8bindings(0) +{ +} + +QQmlContextData::QQmlContextData(QQmlContext *ctxt) +: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), + isPragmaLibraryContext(false), unresolvedNames(false), publicContext(ctxt), activeVMEData(0), + propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + componentAttached(0), v4bindings(0), v8bindings(0) +{ +} + +void QQmlContextData::invalidate() +{ + while (componentAttached) { + QQmlComponentAttached *a = componentAttached; + componentAttached = a->next; + if (componentAttached) componentAttached->prev = &componentAttached; + + a->next = 0; + a->prev = 0; + + emit a->destruction(); + } + + while (childContexts) { + if (childContexts->ownedByParent) { + childContexts->destroy(); + } else { + childContexts->invalidate(); + } + } + + if (prevChild) { + *prevChild = nextChild; + if (nextChild) nextChild->prevChild = prevChild; + nextChild = 0; + prevChild = 0; + } + + engine = 0; + parent = 0; +} + +void QQmlContextData::clearContext() +{ + if (engine) { + while (componentAttached) { + QQmlComponentAttached *a = componentAttached; + componentAttached = a->next; + if (componentAttached) componentAttached->prev = &componentAttached; + + a->next = 0; + a->prev = 0; + + emit a->destruction(); + } + } + + QQmlAbstractExpression *expression = expressions; + while (expression) { + QQmlAbstractExpression *nextExpression = expression->m_nextExpression; + + expression->m_prevExpression = 0; + expression->m_nextExpression = 0; + + expression->setContext(0); + + expression = nextExpression; + } + expressions = 0; +} + +void QQmlContextData::destroy() +{ + if (linkedContext) + linkedContext->destroy(); + + if (engine) invalidate(); + + clearContext(); + + while (contextObjects) { + QQmlData *co = contextObjects; + contextObjects = contextObjects->nextContextObject; + + co->context = 0; + co->outerContext = 0; + co->nextContextObject = 0; + co->prevContextObject = 0; + } + + QQmlGuardedContextData *contextGuard = contextGuards; + while (contextGuard) { + QQmlGuardedContextData *next = contextGuard->m_next; + contextGuard->m_next = 0; + contextGuard->m_prev = 0; + contextGuard->m_contextData = 0; + contextGuard = next; + } + contextGuards = 0; + + if (propertyNames) + propertyNames->release(); + + if (imports) + imports->release(); + + if (v4bindings) + v4bindings->release(); + + if (v8bindings) + v8bindings->release(); + + for (int ii = 0; ii < importedScripts.count(); ++ii) { + qPersistentDispose(importedScripts[ii]); + } + + delete [] idValues; + + if (isInternal) + delete publicContext; + + delete this; +} + +void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership) +{ + if (p) { + parent = p; + engine = p->engine; + nextChild = p->childContexts; + if (nextChild) nextChild->prevChild = &nextChild; + prevChild = &p->childContexts; + p->childContexts = this; + ownedByParent = parentTakesOwnership; + } +} + +void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression) +{ + QQmlAbstractExpression::DeleteWatcher w(expression); + + if (expression->m_nextExpression) + refreshExpressionsRecursive(expression->m_nextExpression); + + if (!w.wasDeleted()) + expression->refresh(); +} + +static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh) +{ + return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames); +} + +void QQmlContextData::refreshExpressionsRecursive(bool isGlobal) +{ + // For efficiency, we try and minimize the number of guards we have to create + if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) { + QQmlGuardedContextData guard(this); + + if (childContexts) + childContexts->refreshExpressionsRecursive(isGlobal); + + if (guard.isNull()) return; + + if (nextChild) + nextChild->refreshExpressionsRecursive(isGlobal); + + if (guard.isNull()) return; + + if (expressions_to_run(this, isGlobal)) + refreshExpressionsRecursive(expressions); + + } else if (expressions_to_run(this, isGlobal)) { + + refreshExpressionsRecursive(expressions); + + } else if (nextChild && childContexts) { + + QQmlGuardedContextData guard(this); + + childContexts->refreshExpressionsRecursive(isGlobal); + + if (!guard.isNull() && nextChild) + nextChild->refreshExpressionsRecursive(isGlobal); + + } else if (nextChild) { + + nextChild->refreshExpressionsRecursive(isGlobal); + + } else if (childContexts) { + + childContexts->refreshExpressionsRecursive(isGlobal); + + } +} + +// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all +// context-tree dependent caches in the expressions, and should occur every time the context tree +// *structure* (not values) changes. +void QQmlContextData::refreshExpressions() +{ + bool isGlobal = (parent == 0); + + // For efficiency, we try and minimize the number of guards we have to create + if (expressions_to_run(this, isGlobal) && childContexts) { + QQmlGuardedContextData guard(this); + + childContexts->refreshExpressionsRecursive(isGlobal); + + if (!guard.isNull() && expressions_to_run(this, isGlobal)) + refreshExpressionsRecursive(expressions); + + } else if (expressions_to_run(this, isGlobal)) { + + refreshExpressionsRecursive(expressions); + + } else if (childContexts) { + + childContexts->refreshExpressionsRecursive(isGlobal); + + } +} + +void QQmlContextData::addObject(QObject *o) +{ + QQmlData *data = QQmlData::get(o, true); + + Q_ASSERT(data->context == 0); + + data->context = this; + data->outerContext = this; + + data->nextContextObject = contextObjects; + if (data->nextContextObject) + data->nextContextObject->prevContextObject = &data->nextContextObject; + data->prevContextObject = &contextObjects; + contextObjects = data; +} + +void QQmlContextData::setIdProperty(int idx, QObject *obj) +{ + idValues[idx] = obj; + idValues[idx].context = this; +} + +void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data) +{ + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; +} + +QString QQmlContextData::findObjectId(const QObject *obj) const +{ + if (!propertyNames) + return QString(); + + for (int ii = 0; ii < idValueCount; ii++) { + if (idValues[ii] == obj) + return propertyNames->findId(ii); + } + + if (publicContext) { + QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext); + for (int ii = 0; ii < p->propertyValues.count(); ++ii) + if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj)) + return propertyNames->findId(ii); + } + + if (linkedContext) + return linkedContext->findObjectId(obj); + return QString(); +} + +QQmlContext *QQmlContextData::asQQmlContext() +{ + if (!publicContext) + publicContext = new QQmlContext(this); + return publicContext; +} + +QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate() +{ + return QQmlContextPrivate::get(asQQmlContext()); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h new file mode 100644 index 0000000000..f6d8aa1d3a --- /dev/null +++ b/src/qml/qml/qqmlcontext.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCONTEXT_H +#define QQMLCONTEXT_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QString; +class QQmlEngine; +class QQmlRefCount; +class QQmlContextPrivate; +class QQmlCompositeTypeData; +class QQmlContextData; + +class Q_QML_EXPORT QQmlContext : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQmlContext) + +public: + QQmlContext(QQmlEngine *parent, QObject *objParent=0); + QQmlContext(QQmlContext *parent, QObject *objParent=0); + virtual ~QQmlContext(); + + bool isValid() const; + + QQmlEngine *engine() const; + QQmlContext *parentContext() const; + + QObject *contextObject() const; + void setContextObject(QObject *); + + QVariant contextProperty(const QString &) const; + void setContextProperty(const QString &, QObject *); + void setContextProperty(const QString &, const QVariant &); + + QString nameForObject(QObject *) const; + + QUrl resolvedUrl(const QUrl &); + + void setBaseUrl(const QUrl &); + QUrl baseUrl() const; + +private: + friend class QQmlVME; + friend class QQmlEngine; + friend class QQmlEnginePrivate; + friend class QQmlExpression; + friend class QQmlExpressionPrivate; + friend class QQmlComponent; + friend class QQmlComponentPrivate; + friend class QQmlScriptPrivate; + friend class QQmlBoundSignalProxy; + friend class QQmlContextData; + QQmlContext(QQmlContextData *); + QQmlContext(QQmlEngine *, bool); + Q_DISABLE_COPY(QQmlContext) +}; +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QList) + +QT_END_HEADER + +#endif // QQMLCONTEXT_H diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h new file mode 100644 index 0000000000..d10543bde5 --- /dev/null +++ b/src/qml/qml/qqmlcontext_p.h @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCONTEXT_P_H +#define QQMLCONTEXT_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 "qqmlcontext.h" + +#include "qqmldata_p.h" +#include "qqmlintegercache_p.h" +#include "qqmltypenamecache_p.h" +#include "qqmlnotifier_p.h" +#include "qqmllist.h" +#include "qqmlscript_p.h" + +#include +#include +#include + +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QV8Bindings; +class QQmlContext; +class QQmlExpression; +class QQmlEngine; +class QQmlExpression; +class QQmlExpressionPrivate; +class QQmlAbstractExpression; +class QV4Bindings; +class QQmlContextData; + +class QQmlContextPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQmlContext) +public: + QQmlContextPrivate(); + + QQmlContextData *data; + + QList propertyValues; + int notifyIndex; + + static QQmlContextPrivate *get(QQmlContext *context) { + return static_cast(QObjectPrivate::get(context)); + } + static QQmlContext *get(QQmlContextPrivate *context) { + return static_cast(context->q_func()); + } + + // Only used for debugging + QList > instances; + + static int context_count(QQmlListProperty *); + static QObject *context_at(QQmlListProperty *, int); +}; + +class QQmlVME; +class QQmlComponentAttached; +class QQmlGuardedContextData; +class Q_QML_EXPORT QQmlContextData +{ +public: + QQmlContextData(); + QQmlContextData(QQmlContext *); + void clearContext(); + void destroy(); + void invalidate(); + + inline bool isValid() const { + return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted); + } + + // My parent context and engine + QQmlContextData *parent; + QQmlEngine *engine; + + void setParent(QQmlContextData *, bool parentTakesOwnership = false); + void refreshExpressions(); + + void addObject(QObject *); + + QUrl resolvedUrl(const QUrl &); + + // My containing QQmlContext. If isInternal is true this owns publicContext. + // If internal is false publicContext owns this. + QQmlContext *asQQmlContext(); + QQmlContextPrivate *asQQmlContextPrivate(); + quint32 isInternal:1; + quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true. + quint32 isJSContext:1; + quint32 isPragmaLibraryContext:1; + quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name + quint32 dummy:28; + QQmlContext *publicContext; + + // VME data that is constructing this context if any + void *activeVMEData; + + // Property name cache + QQmlIntegerCache *propertyNames; + + // Context object + QObject *contextObject; + + // Any script blocks that exist on this context + QList > importedScripts; + + // Context base url + QUrl url; + QString urlString; + + // List of imports that apply to this context + QQmlTypeNameCache *imports; + + // My children + QQmlContextData *childContexts; + + // My peers in parent's childContexts list + QQmlContextData *nextChild; + QQmlContextData **prevChild; + + // Expressions that use this context + QQmlAbstractExpression *expressions; + + // Doubly-linked list of objects that are owned by this context + QQmlData *contextObjects; + + // Doubly-linked list of context guards (XXX merge with contextObjects) + QQmlGuardedContextData *contextGuards; + + // id guards + struct ContextGuard : public QQmlGuard + { + inline ContextGuard(); + inline ContextGuard &operator=(QObject *obj); + inline void objectDestroyed(QObject *); + + inline bool wasSet() const; + + QFlagPointer context; + QQmlNotifier bindings; + }; + ContextGuard *idValues; + int idValueCount; + void setIdProperty(int, QObject *); + void setIdPropertyData(QQmlIntegerCache *); + + // Linked contexts. this owns linkedContext. + QQmlContextData *linkedContext; + + // Linked list of uses of the Component attached property in this + // context + QQmlComponentAttached *componentAttached; + + // Optimized binding objects. Needed for deferred properties. + QV4Bindings *v4bindings; + QV8Bindings *v8bindings; + + // Return the outermost id for obj, if any. + QString findObjectId(const QObject *obj) const; + + static QQmlContextData *get(QQmlContext *context) { + return QQmlContextPrivate::get(context)->data; + } + +private: + void refreshExpressionsRecursive(bool isGlobal); + void refreshExpressionsRecursive(QQmlAbstractExpression *); + ~QQmlContextData() {} +}; + +class QQmlGuardedContextData +{ +public: + inline QQmlGuardedContextData(); + inline QQmlGuardedContextData(QQmlContextData *); + inline ~QQmlGuardedContextData(); + + inline QQmlContextData *contextData(); + inline void setContextData(QQmlContextData *); + + inline bool isNull() const { return !m_contextData; } + + inline operator QQmlContextData*() const { return m_contextData; } + inline QQmlContextData* operator->() const { return m_contextData; } + inline QQmlGuardedContextData &operator=(QQmlContextData *d); + +private: + QQmlGuardedContextData &operator=(const QQmlGuardedContextData &); + QQmlGuardedContextData(const QQmlGuardedContextData &); + friend class QQmlContextData; + + inline void clear(); + + QQmlContextData *m_contextData; + QQmlGuardedContextData *m_next; + QQmlGuardedContextData **m_prev; +}; + +QQmlGuardedContextData::QQmlGuardedContextData() +: m_contextData(0), m_next(0), m_prev(0) +{ +} + +QQmlGuardedContextData::QQmlGuardedContextData(QQmlContextData *data) +: m_contextData(0), m_next(0), m_prev(0) +{ + setContextData(data); +} + +QQmlGuardedContextData::~QQmlGuardedContextData() +{ + clear(); +} + +void QQmlGuardedContextData::setContextData(QQmlContextData *contextData) +{ + clear(); + + if (contextData) { + m_contextData = contextData; + m_next = contextData->contextGuards; + if (m_next) m_next->m_prev = &m_next; + m_prev = &contextData->contextGuards; + contextData->contextGuards = this; + } +} + +QQmlContextData *QQmlGuardedContextData::contextData() +{ + return m_contextData; +} + +void QQmlGuardedContextData::clear() +{ + if (m_prev) { + *m_prev = m_next; + if (m_next) m_next->m_prev = m_prev; + m_contextData = 0; + m_next = 0; + m_prev = 0; + } +} + +QQmlGuardedContextData & +QQmlGuardedContextData::operator=(QQmlContextData *d) +{ + setContextData(d); + return *this; +} + +QQmlContextData::ContextGuard::ContextGuard() +: context(0) +{ +} + +QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj) +{ + QQmlGuard::operator=(obj); + context.setFlag(); + bindings.notify(); // For alias connections + return *this; +} + +void QQmlContextData::ContextGuard::objectDestroyed(QObject *) +{ + if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted) + bindings.notify(); +} + +bool QQmlContextData::ContextGuard::wasSet() const +{ + return context.flag(); +} + +QT_END_NAMESPACE + +#endif // QQMLCONTEXT_P_H diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp new file mode 100644 index 0000000000..f888b61e7d --- /dev/null +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlcustomparser_p.h" +#include "qqmlcustomparser_p_p.h" + +#include "qqmlcompiler_p.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace QQmlScript; + +/*! + \class QQmlCustomParser + \brief The QQmlCustomParser class allows you to add new arbitrary types to QML. + \internal + + By subclassing QQmlCustomParser, you can add a parser for + building a particular type. + + The subclass must implement compile() and setCustomData(), and register + itself in the meta type system by calling the macro: + + \code + QML_REGISTER_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass) + \endcode +*/ + +/* + \fn QByteArray QQmlCustomParser::compile(const QList & properties) + + The custom parser processes \a properties, and returns + a QByteArray containing data meaningful only to the + custom parser; the type engine will pass this same data to + setCustomData() when making an instance of the data. + + Errors must be reported via the error() functions. + + The QByteArray may be cached between executions of the system, so + it must contain correctly-serialized data (not, for example, + pointers to stack objects). +*/ + +/* + \fn void QQmlCustomParser::setCustomData(QObject *object, const QByteArray &data) + + This function sets \a object to have the properties defined + by \a data, which is a block of data previously returned by a call + to compile(). + + Errors should be reported using qmlInfo(object). + + The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE. +*/ + +QQmlCustomParserNode +QQmlCustomParserNodePrivate::fromObject(QQmlScript::Object *root) +{ + QQmlCustomParserNode rootNode; + rootNode.d->name = root->typeName; + rootNode.d->location = root->location.start; + + for (Property *p = root->properties.first(); p; p = root->properties.next(p)) { + rootNode.d->properties << fromProperty(p); + } + + if (root->defaultProperty) + rootNode.d->properties << fromProperty(root->defaultProperty); + + return rootNode; +} + +QQmlCustomParserProperty +QQmlCustomParserNodePrivate::fromProperty(QQmlScript::Property *p) +{ + QQmlCustomParserProperty prop; + prop.d->name = p->name().toString(); + prop.d->isList = p->values.isMany(); + prop.d->location = p->location.start; + + if (p->value) { + QQmlCustomParserNode node = fromObject(p->value); + QList props = node.properties(); + for (int ii = 0; ii < props.count(); ++ii) + prop.d->values << QVariant::fromValue(props.at(ii)); + } else { + for (QQmlScript::Value *v = p->values.first(); v; v = p->values.next(v)) { + v->type = QQmlScript::Value::Literal; + + if(v->object) { + QQmlCustomParserNode node = fromObject(v->object); + prop.d->values << QVariant::fromValue(node); + } else { + prop.d->values << QVariant::fromValue(v->value); + } + + } + } + + return prop; +} + +QQmlCustomParserNode::QQmlCustomParserNode() +: d(new QQmlCustomParserNodePrivate) +{ +} + +QQmlCustomParserNode::QQmlCustomParserNode(const QQmlCustomParserNode &other) +: d(new QQmlCustomParserNodePrivate) +{ + *this = other; +} + +QQmlCustomParserNode &QQmlCustomParserNode::operator=(const QQmlCustomParserNode &other) +{ + d->name = other.d->name; + d->properties = other.d->properties; + d->location = other.d->location; + return *this; +} + +QQmlCustomParserNode::~QQmlCustomParserNode() +{ + delete d; d = 0; +} + +QString QQmlCustomParserNode::name() const +{ + return d->name; +} + +QList QQmlCustomParserNode::properties() const +{ + return d->properties; +} + +QQmlScript::Location QQmlCustomParserNode::location() const +{ + return d->location; +} + +QQmlCustomParserProperty::QQmlCustomParserProperty() +: d(new QQmlCustomParserPropertyPrivate) +{ +} + +QQmlCustomParserProperty::QQmlCustomParserProperty(const QQmlCustomParserProperty &other) +: d(new QQmlCustomParserPropertyPrivate) +{ + *this = other; +} + +QQmlCustomParserProperty &QQmlCustomParserProperty::operator=(const QQmlCustomParserProperty &other) +{ + d->name = other.d->name; + d->isList = other.d->isList; + d->values = other.d->values; + d->location = other.d->location; + return *this; +} + +QQmlCustomParserProperty::~QQmlCustomParserProperty() +{ + delete d; d = 0; +} + +QString QQmlCustomParserProperty::name() const +{ + return d->name; +} + +bool QQmlCustomParserProperty::isList() const +{ + return d->isList; +} + +QQmlScript::Location QQmlCustomParserProperty::location() const +{ + return d->location; +} + +QList QQmlCustomParserProperty::assignedValues() const +{ + return d->values; +} + +void QQmlCustomParser::clearErrors() +{ + exceptions.clear(); +} + +/*! + Reports an error with the given \a description. + + This can only be used during the compile() step. For errors during setCustomData(), use qmlInfo(). + + An error is generated referring to the position of the element in the source file. +*/ +void QQmlCustomParser::error(const QString& description) +{ + Q_ASSERT(object); + QQmlError error; + QString exceptionDescription; + error.setLine(object->location.start.line); + error.setColumn(object->location.start.column); + error.setDescription(description); + exceptions << error; +} + +/*! + Reports an error in parsing \a prop, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString& description) +{ + QQmlError error; + QString exceptionDescription; + error.setLine(prop.location().line); + error.setColumn(prop.location().column); + error.setDescription(description); + exceptions << error; +} + +/*! + Reports an error in parsing \a node, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& description) +{ + QQmlError error; + QString exceptionDescription; + error.setLine(node.location().line); + error.setColumn(node.location().column); + error.setDescription(description); + exceptions << error; +} + +/*! + If \a script is a simply enum expression (eg. Text.AlignLeft), + returns the integer equivalent (eg. 1). + + Otherwise, returns -1. +*/ +int QQmlCustomParser::evaluateEnum(const QByteArray& script) const +{ + return compiler->evaluateEnum(script); +} + +/*! + Resolves \a name to a type, or 0 if it is not a type. This can be used + to type-check object nodes. +*/ +const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const +{ + return compiler->resolveType(name); +} + +/*! + Rewrites \a value and returns an identifier that can be + used to construct the binding later. \a name + is used as the name of the rewritten function. +*/ +QQmlBinding::Identifier QQmlCustomParser::rewriteBinding(const QQmlScript::Variant &value, const QString& name) +{ + return compiler->rewriteBinding(value, name); +} + +/*! + Returns a rewritten \a handler. \a name + is used as the name of the rewritten function. +*/ +QString QQmlCustomParser::rewriteSignalHandler(const QQmlScript::Variant &value, const QString &name) +{ + return compiler->rewriteSignalHandler(value , name); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h new file mode 100644 index 0000000000..ecc4bae4c3 --- /dev/null +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCUSTOMPARSER_H +#define QQMLCUSTOMPARSER_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 "qqmlmetatype_p.h" +#include "qqmlerror.h" +#include "qqmlscript_p.h" +#include "qqmlbinding_p.h" + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QQmlCompiler; + +class QQmlCustomParserPropertyPrivate; +class Q_QML_EXPORT QQmlCustomParserProperty +{ +public: + QQmlCustomParserProperty(); + QQmlCustomParserProperty(const QQmlCustomParserProperty &); + QQmlCustomParserProperty &operator=(const QQmlCustomParserProperty &); + ~QQmlCustomParserProperty(); + + QString name() const; + QQmlScript::Location location() const; + + bool isList() const; + // Will be one of QQmlScript::Variant, QQmlCustomParserProperty or + // QQmlCustomParserNode + QList assignedValues() const; + +private: + friend class QQmlCustomParserNodePrivate; + friend class QQmlCustomParserPropertyPrivate; + QQmlCustomParserPropertyPrivate *d; +}; + +class QQmlCustomParserNodePrivate; +class Q_QML_EXPORT QQmlCustomParserNode +{ +public: + QQmlCustomParserNode(); + QQmlCustomParserNode(const QQmlCustomParserNode &); + QQmlCustomParserNode &operator=(const QQmlCustomParserNode &); + ~QQmlCustomParserNode(); + + QString name() const; + QQmlScript::Location location() const; + + QList properties() const; + +private: + friend class QQmlCustomParserNodePrivate; + QQmlCustomParserNodePrivate *d; +}; + +class Q_QML_EXPORT QQmlCustomParser +{ +public: + enum Flag { + NoFlag = 0x00000000, + AcceptsAttachedProperties = 0x00000001, + AcceptsSignalHandlers = 0x00000002 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + QQmlCustomParser() : compiler(0), object(0), m_flags(NoFlag) {} + QQmlCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {} + virtual ~QQmlCustomParser() {} + + void clearErrors(); + Flags flags() const { return m_flags; } + + virtual QByteArray compile(const QList &)=0; + virtual void setCustomData(QObject *, const QByteArray &)=0; + + QList errors() const { return exceptions; } + +protected: + void error(const QString& description); + void error(const QQmlCustomParserProperty&, const QString& description); + void error(const QQmlCustomParserNode&, const QString& description); + + int evaluateEnum(const QByteArray&) const; + + const QMetaObject *resolveType(const QString&) const; + + QQmlBinding::Identifier rewriteBinding(const QQmlScript::Variant&, const QString&); + QString rewriteSignalHandler(const QQmlScript::Variant&, const QString&); + +private: + QList exceptions; + QQmlCompiler *compiler; + QQmlScript::Object *object; + Flags m_flags; + friend class QQmlCompiler; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags); + +#if 0 +#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ + qmlRegisterCustomType(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE) +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QQmlCustomParserProperty) +Q_DECLARE_METATYPE(QQmlCustomParserNode) + +QT_END_HEADER + +#endif diff --git a/src/qml/qml/qqmlcustomparser_p_p.h b/src/qml/qml/qqmlcustomparser_p_p.h new file mode 100644 index 0000000000..c861f9e944 --- /dev/null +++ b/src/qml/qml/qqmlcustomparser_p_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLCUSTOMPARSER_P_H +#define QQMLCUSTOMPARSER_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 "qqmlcustomparser_p.h" + +#include "qqmlscript_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QQmlCustomParserNodePrivate +{ +public: + QString name; + QList properties; + QQmlScript::Location location; + + static QQmlCustomParserNode fromObject(QQmlScript::Object *); + static QQmlCustomParserProperty fromProperty(QQmlScript::Property *); +}; + +class QQmlCustomParserPropertyPrivate +{ +public: + QQmlCustomParserPropertyPrivate() + : isList(false) {} + + QString name; + bool isList; + QQmlScript::Location location; + QList values; +}; + +QT_END_NAMESPACE + +#endif // QQMLCUSTOMPARSER_P_H diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h new file mode 100644 index 0000000000..e4ba44583d --- /dev/null +++ b/src/qml/qml/qqmldata_p.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLDATA_P_H +#define QQMLDATA_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 +#include +#include + +QT_BEGIN_NAMESPACE + +template class QHash; +class QQmlGuardImpl; +class QQmlCompiledData; +class QQmlAbstractBinding; +class QQmlContext; +class QQmlPropertyCache; +class QQmlContextData; +class QQmlNotifier; +class QQmlDataExtended; +class QQmlNotifierEndpoint; +// This class is structured in such a way, that simply zero'ing it is the +// default state for elemental object allocations. This is crucial in the +// workings of the QQmlInstruction::CreateSimpleObject instruction. +// Don't change anything here without first considering that case! +class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData +{ +public: + QQmlData() + : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + hasTaintedV8Object(false), notifyList(0), context(0), outerContext(0), bindings(0), + nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), + lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), v8objectid(0), + propertyCache(0), guards(0), extendedData(0) { + init(); + } + + static inline void init() { + QAbstractDeclarativeData::destroyed = destroyed; + QAbstractDeclarativeData::parentChanged = parentChanged; + QAbstractDeclarativeData::objectNameChanged = objectNameChanged; + QAbstractDeclarativeData::signalEmitted = signalEmitted; + } + + static void destroyed(QAbstractDeclarativeData *, QObject *); + static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *); + static void objectNameChanged(QAbstractDeclarativeData *, QObject *); + static void signalEmitted(QAbstractDeclarativeData *, QObject *, int, void **); + + void destroyed(QObject *); + void parentChanged(QObject *, QObject *); + void objectNameChanged(QObject *); + + void setImplicitDestructible() { + if (!explicitIndestructibleSet) indestructible = false; + } + + quint32 ownMemory:1; + quint32 ownContext:1; + quint32 indestructible:1; + quint32 explicitIndestructibleSet:1; + quint32 hasTaintedV8Object:1; + quint32 dummy:27; + + struct NotifyList { + quint64 connectionMask; + + quint16 maximumTodoIndex; + quint16 notifiesSize; + + QQmlNotifierEndpoint *todo; + QQmlNotifierEndpoint**notifies; + void layout(); + private: + void layout(QQmlNotifierEndpoint*); + }; + NotifyList *notifyList; + + inline QQmlNotifierEndpoint *notify(int index); + void addNotify(int index, QQmlNotifierEndpoint *); + + // The context that created the C++ object + QQmlContextData *context; + // The outermost context in which this object lives + QQmlContextData *outerContext; + + QQmlAbstractBinding *bindings; + + // Linked list for QQmlContext::contextObjects + QQmlData *nextContextObject; + QQmlData**prevContextObject; + + int bindingBitsSize; + quint32 *bindingBits; + bool hasBindingBit(int) const; + void clearBindingBit(int); + void setBindingBit(QObject *obj, int); + + ushort lineNumber; + ushort columnNumber; + + QQmlCompiledData *deferredComponent; // Can't this be found from the context? + unsigned int deferredIdx; + + quint32 v8objectid; + v8::Persistent v8object; + + QQmlPropertyCache *propertyCache; + + QQmlGuardImpl *guards; + + static QQmlData *get(const QObject *object, bool create = false) { + QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); + if (priv->wasDeleted) { + Q_ASSERT(!create); + return 0; + } else if (priv->declarativeData) { + return static_cast(priv->declarativeData); + } else if (create) { + priv->declarativeData = new QQmlData; + return static_cast(priv->declarativeData); + } else { + return 0; + } + } + + bool hasExtendedData() const { return extendedData != 0; } + QQmlNotifier *objectNameNotifier() const; + QHash *attachedProperties() const; + +private: + // For objectNameNotifier and attachedProperties + mutable QQmlDataExtended *extendedData; +}; + +QQmlNotifierEndpoint *QQmlData::notify(int index) +{ + Q_ASSERT(index <= 0xFFFF); + + if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) { + return 0; + } else if (index < notifyList->notifiesSize) { + return notifyList->notifies[index]; + } else if (index <= notifyList->maximumTodoIndex) { + notifyList->layout(); + } + + if (index < notifyList->notifiesSize) { + return notifyList->notifies[index]; + } else { + return 0; + } +} + +QT_END_NAMESPACE + +#endif // QQMLDATA_P_H diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp new file mode 100644 index 0000000000..7b99214f04 --- /dev/null +++ b/src/qml/qml/qqmldirparser.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldirparser_p.h" +#include "qqmlerror.h" +#include "qqmlglobal_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QQmlDirParser::QQmlDirParser() + : _isParsed(false) +{ +} + +QQmlDirParser::~QQmlDirParser() +{ +} + +QUrl QQmlDirParser::url() const +{ + return _url; +} + +void QQmlDirParser::setUrl(const QUrl &url) +{ + _url = url; +} + +QString QQmlDirParser::fileSource() const +{ + return _filePathSouce; +} + +void QQmlDirParser::setFileSource(const QString &filePath) +{ + _filePathSouce = filePath; +} + +QString QQmlDirParser::source() const +{ + return _source; +} + +void QQmlDirParser::setSource(const QString &source) +{ + _isParsed = false; + _source = source; +} + +bool QQmlDirParser::isParsed() const +{ + return _isParsed; +} + +bool QQmlDirParser::parse() +{ + if (_isParsed) + return true; + + _isParsed = true; + _errors.clear(); + _plugins.clear(); + _components.clear(); + _scripts.clear(); + + if (_source.isEmpty() && !_filePathSouce.isEmpty()) { + QFile file(_filePathSouce); + if (!QQml_isFileCaseCorrect(_filePathSouce)) { + QQmlError error; + error.setDescription(QString::fromUtf8("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"").arg(_filePathSouce)); + _errors.prepend(error); + return false; + } else if (file.open(QFile::ReadOnly)) { + _source = QString::fromUtf8(file.readAll()); + } else { + QQmlError error; + error.setDescription(QString::fromUtf8("module \"$$URI$$\" definition \"%1\" not readable").arg(_filePathSouce)); + _errors.prepend(error); + return false; + } + } + + QTextStream stream(&_source); + int lineNumber = 0; + + forever { + ++lineNumber; + + const QString line = stream.readLine(); + if (line.isNull()) + break; + + QString sections[3]; + int sectionCount = 0; + + int index = 0; + const int length = line.length(); + + while (index != length) { + const QChar ch = line.at(index); + + if (ch.isSpace()) { + do { ++index; } + while (index != length && line.at(index).isSpace()); + + } else if (ch == QLatin1Char('#')) { + // recognized a comment + break; + + } else { + const int start = index; + + do { ++index; } + while (index != length && !line.at(index).isSpace()); + + const QString lexeme = line.mid(start, index - start); + + if (sectionCount >= 3) { + reportError(lineNumber, start, QLatin1String("unexpected token")); + + } else { + sections[sectionCount++] = lexeme; + } + } + } + + if (sectionCount == 0) { + continue; // no sections, no party. + + } else if (sections[0] == QLatin1String("plugin")) { + if (sectionCount < 2) { + reportError(lineNumber, -1, + QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); + + continue; + } + + const Plugin entry(sections[1], sections[2]); + + _plugins.append(entry); + + } else if (sections[0] == QLatin1String("internal")) { + if (sectionCount != 3) { + reportError(lineNumber, -1, + QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1)); + continue; + } + Component entry(sections[1], sections[2], -1, -1); + entry.internal = true; + _components.append(entry); + } else if (sections[0] == QLatin1String("typeinfo")) { + if (sectionCount != 2) { + reportError(lineNumber, -1, + QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); + continue; + } +#ifdef QT_CREATOR + TypeInfo typeInfo(sections[1]); + _typeInfos.append(typeInfo); +#endif + + } else if (sectionCount == 2) { + // No version specified (should only be used for relative qmldir files) + const Component entry(sections[0], sections[1], -1, -1); + _components.append(entry); + } else if (sectionCount == 3) { + const QString &version = sections[1]; + const int dotIndex = version.indexOf(QLatin1Char('.')); + + if (dotIndex == -1) { + reportError(lineNumber, -1, QLatin1String("expected '.'")); + } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) { + reportError(lineNumber, -1, QLatin1String("unexpected '.'")); + } else { + bool validVersionNumber = false; + const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber); + + if (validVersionNumber) { + const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber); + + if (validVersionNumber) { + const QString &fileName = sections[2]; + + if (fileName.endsWith(QLatin1String(".js"))) { + // A 'js' extension indicates a namespaced script import + const Script entry(sections[0], fileName, majorVersion, minorVersion); + _scripts.append(entry); + } else { + const Component entry(sections[0], fileName, majorVersion, minorVersion); + _components.append(entry); + } + } + } + } + } else { + reportError(lineNumber, -1, + QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); + } + } + + return hasError(); +} + +void QQmlDirParser::reportError(int line, int column, const QString &description) +{ + QQmlError error; + error.setUrl(_url); + error.setLine(line); + error.setColumn(column); + error.setDescription(description); + _errors.append(error); +} + +bool QQmlDirParser::hasError() const +{ + if (! _errors.isEmpty()) + return true; + + return false; +} + +QList QQmlDirParser::errors(const QString &uri) const +{ + QList errors = _errors; + for (int i = 0; i < errors.size(); ++i) { + QQmlError &e = errors[i]; + QString description = e.description(); + description.replace(QLatin1String("$$URI$$"), uri); + e.setDescription(description); + } + return errors; +} + +QList QQmlDirParser::plugins() const +{ + return _plugins; +} + +QList QQmlDirParser::components() const +{ + return _components; +} + +QList QQmlDirParser::scripts() const +{ + return _scripts; +} + +#ifdef QT_CREATOR +QList QQmlDirParser::typeInfos() const +{ + return _typeInfos; +} +#endif + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h new file mode 100644 index 0000000000..8c681309ac --- /dev/null +++ b/src/qml/qml/qqmldirparser_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLDIRPARSER_P_H +#define QQMLDIRPARSER_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 +#include + +QT_BEGIN_NAMESPACE + +class QQmlError; +class QQmlDirParser +{ + Q_DISABLE_COPY(QQmlDirParser) + +public: + QQmlDirParser(); + ~QQmlDirParser(); + + QUrl url() const; + void setUrl(const QUrl &url); + + QString fileSource() const; + void setFileSource(const QString &filePath); + + QString source() const; + void setSource(const QString &source); + + bool isParsed() const; + bool parse(); + + bool hasError() const; + QList errors(const QString &uri) const; + + struct Plugin + { + Plugin() {} + + Plugin(const QString &name, const QString &path) + : name(name), path(path) {} + + QString name; + QString path; + }; + + struct Component + { + Component() + : majorVersion(0), minorVersion(0), internal(false) {} + + Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion) + : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion), + internal(false) {} + + QString typeName; + QString fileName; + int majorVersion; + int minorVersion; + bool internal; + }; + + struct Script + { + Script() + : majorVersion(0), minorVersion(0) {} + + Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + + QString nameSpace; + QString fileName; + int majorVersion; + int minorVersion; + }; + + QList components() const; + QList