2013-08-06 14:41:28 +00:00
/****************************************************************************
* *
* * Copyright ( C ) 2013 Digia Plc and / or its subsidiary ( - ies ) .
* * Contact : http : //www.qt-project.org/legal
* *
* * This file is part of the tools applications of the Qt Toolkit .
* *
* * $ QT_BEGIN_LICENSE : LGPL $
* * Commercial License Usage
* * Licensees holding valid commercial Qt licenses may use this file in
* * accordance with the commercial license agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and Digia . For licensing terms and
* * conditions see http : //qt.digia.com/licensing. For further information
* * use the contact form at http : //qt.digia.com/contact-us.
* *
* * GNU Lesser General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * In addition , as a special exception , Digia gives you certain additional
* * rights . These rights are described in the Digia 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.
* *
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "qqmlcodegenerator_p.h"
# include <private/qv4compileddata_p.h>
# include <private/qqmljsparser_p.h>
# include <private/qqmljslexer_p.h>
2013-09-13 13:03:51 +00:00
# include <private/qqmlcompiler_p.h>
2013-11-17 04:10:23 +00:00
# include <private/qqmlglobal_p.h>
2013-08-06 14:41:28 +00:00
# include <QCoreApplication>
2013-10-29 10:59:54 +00:00
# ifdef CONST
# undef CONST
# endif
2013-08-06 14:41:28 +00:00
QT_USE_NAMESPACE
2013-11-17 04:10:23 +00:00
DEFINE_BOOL_CONFIG_OPTION ( lookupHints , QML_LOOKUP_HINTS ) ;
2013-08-06 14:41:28 +00:00
using namespace QtQml ;
2013-09-11 17:28:13 +00:00
# define COMPILE_EXCEPTION(location, desc) \
{ \
recordError ( location , desc ) ; \
return false ; \
}
2014-01-07 14:35:20 +00:00
void QmlObject : : init ( MemoryPool * pool , int typeNameIndex , int id , const AST : : SourceLocation & loc )
{
inheritedTypeNameIndex = typeNameIndex ;
location . line = loc . startLine ;
location . column = loc . startColumn ;
idIndex = id ;
indexOfDefaultProperty = - 1 ;
properties = pool - > New < PoolList < QmlProperty > > ( ) ;
qmlSignals = pool - > New < PoolList < Signal > > ( ) ;
bindings = pool - > New < PoolList < Binding > > ( ) ;
functions = pool - > New < PoolList < Function > > ( ) ;
2014-01-28 09:41:58 +00:00
declarationsOverride = 0 ;
2014-01-07 14:35:20 +00:00
}
2013-08-06 14:41:28 +00:00
void QmlObject : : dump ( DebugStream & out )
{
out < < inheritedTypeNameIndex < < " { " < < endl ;
out . indent + + ;
out . indent - - ;
out < < " } " < < endl ;
}
2013-09-13 13:03:51 +00:00
QStringList Signal : : parameterStringList ( const QStringList & stringPool ) const
{
QStringList result ;
result . reserve ( parameters - > count ) ;
for ( SignalParameter * param = parameters - > first ; param ; param = param - > next )
result < < stringPool . at ( param - > nameIndex ) ;
return result ;
}
2013-12-06 10:29:43 +00:00
QQmlCodeGenerator : : QQmlCodeGenerator ( const QSet < QString > & illegalNames )
: illegalNames ( illegalNames )
, _object ( 0 )
2014-01-27 12:09:01 +00:00
, _propertyDeclaration ( 0 )
2013-08-06 14:41:28 +00:00
, jsGenerator ( 0 )
{
}
bool QQmlCodeGenerator : : generateFromQml ( const QString & code , const QUrl & url , const QString & urlString , ParsedQML * output )
{
2013-09-11 17:28:13 +00:00
this - > url = url ;
2013-08-06 14:41:28 +00:00
AST : : UiProgram * program = 0 ;
{
QQmlJS : : Lexer lexer ( & output - > jsParserEngine ) ;
lexer . setCode ( code , /*line = */ 1 ) ;
QQmlJS : : Parser parser ( & output - > jsParserEngine ) ;
if ( ! parser . parse ( ) | | ! parser . diagnosticMessages ( ) . isEmpty ( ) ) {
// Extract errors from the parser
foreach ( const DiagnosticMessage & m , parser . diagnosticMessages ( ) ) {
if ( m . isWarning ( ) ) {
qWarning ( " %s:%d : %s " , qPrintable ( urlString ) , m . loc . startLine , qPrintable ( m . message ) ) ;
continue ;
}
QQmlError error ;
error . setUrl ( url ) ;
error . setDescription ( m . message ) ;
error . setLine ( m . loc . startLine ) ;
error . setColumn ( m . loc . startColumn ) ;
errors < < error ;
}
return false ;
}
program = parser . ast ( ) ;
Q_ASSERT ( program ) ;
}
output - > code = code ;
2013-09-13 11:43:15 +00:00
output - > program = program ;
2013-08-06 14:41:28 +00:00
qSwap ( _imports , output - > imports ) ;
2013-09-24 19:49:10 +00:00
qSwap ( _pragmas , output - > pragmas ) ;
2013-08-06 14:41:28 +00:00
qSwap ( _objects , output - > objects ) ;
qSwap ( _functions , output - > functions ) ;
2013-09-12 08:53:20 +00:00
qSwap ( _typeReferences , output - > typeReferences ) ;
2013-08-06 14:41:28 +00:00
this - > pool = output - > jsParserEngine . pool ( ) ;
this - > jsGenerator = & output - > jsGenerator ;
2013-09-19 11:32:13 +00:00
emptyStringIndex = registerString ( QString ( ) ) ;
2013-08-06 14:41:28 +00:00
sourceCode = code ;
2013-08-22 19:08:37 +00:00
accept ( program - > headers ) ;
2013-08-06 14:41:28 +00:00
if ( program - > members - > next ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Unexpected object definition " ) ) ;
AST : : SourceLocation loc = program - > members - > next - > firstSourceLocation ( ) ;
error . setLine ( loc . startLine ) ;
error . setColumn ( loc . startColumn ) ;
errors < < error ;
return false ;
}
2013-09-13 11:43:15 +00:00
2013-08-06 14:41:28 +00:00
AST : : UiObjectDefinition * rootObject = AST : : cast < AST : : UiObjectDefinition * > ( program - > members - > member ) ;
Q_ASSERT ( rootObject ) ;
output - > indexOfRootObject = defineQMLObject ( rootObject ) ;
2013-09-12 08:53:20 +00:00
collectTypeReferences ( ) ;
2013-08-06 14:41:28 +00:00
qSwap ( _imports , output - > imports ) ;
2013-09-24 19:49:10 +00:00
qSwap ( _pragmas , output - > pragmas ) ;
2013-08-06 14:41:28 +00:00
qSwap ( _objects , output - > objects ) ;
qSwap ( _functions , output - > functions ) ;
2013-09-12 08:53:20 +00:00
qSwap ( _typeReferences , output - > typeReferences ) ;
2013-09-16 15:25:53 +00:00
return errors . isEmpty ( ) ;
2013-08-06 14:41:28 +00:00
}
2013-09-13 13:03:51 +00:00
bool QQmlCodeGenerator : : isSignalPropertyName ( const QString & name )
{
if ( name . length ( ) < 3 ) return false ;
if ( ! name . startsWith ( QStringLiteral ( " on " ) ) ) 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.
}
2013-08-06 14:41:28 +00:00
bool QQmlCodeGenerator : : visit ( AST : : UiArrayMemberList * ast )
{
return AST : : Visitor : : visit ( ast ) ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiProgram * )
{
Q_ASSERT ( ! " should not happen " ) ;
return false ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiObjectDefinition * node )
{
2013-09-12 12:43:56 +00:00
// The grammar can't distinguish between two different definitions here:
// Item { ... }
// versus
// font { ... }
// The former is a new binding with no property name and "Item" as type name,
// and the latter is a binding to the font property with no type name but
// only initializer.
AST : : UiQualifiedId * lastId = node - > qualifiedTypeNameId ;
while ( lastId - > next )
lastId = lastId - > next ;
bool isType = lastId - > name . unicode ( ) - > isUpper ( ) ;
if ( isType ) {
int idx = defineQMLObject ( node ) ;
2013-09-30 06:37:37 +00:00
appendBinding ( node - > qualifiedTypeNameId - > identifierToken , emptyStringIndex , idx ) ;
2013-09-12 12:43:56 +00:00
} else {
2014-01-28 09:41:58 +00:00
int idx = defineQMLObject ( /*qualfied type name id*/ 0 , node - > qualifiedTypeNameId - > firstSourceLocation ( ) , node - > initializer , /*declarations should go here*/ _object ) ;
2013-09-12 12:43:56 +00:00
appendBinding ( node - > qualifiedTypeNameId , idx ) ;
}
2013-08-06 14:41:28 +00:00
return false ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiObjectBinding * node )
{
2014-01-29 07:55:02 +00:00
int idx = defineQMLObject ( node - > qualifiedTypeNameId , node - > qualifiedTypeNameId - > firstSourceLocation ( ) , node - > initializer ) ;
2013-09-30 15:39:49 +00:00
appendBinding ( node - > qualifiedId , idx , node - > hasOnToken ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiScriptBinding * node )
{
2013-09-12 12:43:56 +00:00
appendBinding ( node - > qualifiedId , node - > statement ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
2013-09-16 15:25:53 +00:00
bool QQmlCodeGenerator : : visit ( AST : : UiArrayBinding * node )
2013-08-06 14:41:28 +00:00
{
2013-09-16 15:25:53 +00:00
QmlObject * object = 0 ;
2013-09-17 15:23:49 +00:00
AST : : UiQualifiedId * name = node - > qualifiedId ;
if ( ! resolveQualifiedId ( & name , & object ) )
return false ;
2013-09-16 15:25:53 +00:00
qSwap ( _object , object ) ;
AST : : UiArrayMemberList * member = node - > members ;
while ( member ) {
AST : : UiObjectDefinition * def = AST : : cast < AST : : UiObjectDefinition * > ( member - > member ) ;
int idx = defineQMLObject ( def ) ;
appendBinding ( name - > identifierToken , registerString ( name - > name . toString ( ) ) , idx , /*isListItem*/ true ) ;
member = member - > next ;
}
qSwap ( _object , object ) ;
return false ;
2013-08-06 14:41:28 +00:00
}
2013-08-22 19:08:37 +00:00
bool QQmlCodeGenerator : : visit ( AST : : UiHeaderItemList * list )
2013-08-06 14:41:28 +00:00
{
return AST : : Visitor : : visit ( list ) ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiObjectInitializer * ast )
{
return AST : : Visitor : : visit ( ast ) ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiObjectMemberList * ast )
{
return AST : : Visitor : : visit ( ast ) ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiParameterList * ast )
{
return AST : : Visitor : : visit ( ast ) ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiQualifiedId * id )
{
return AST : : Visitor : : visit ( id ) ;
}
void QQmlCodeGenerator : : accept ( AST : : Node * node )
{
AST : : Node : : acceptChild ( node , this ) ;
}
2013-09-11 17:28:13 +00:00
bool QQmlCodeGenerator : : sanityCheckFunctionNames ( )
{
QSet < QString > functionNames ;
for ( Function * f = _object - > functions - > first ; f ; f = f - > next ) {
2013-12-10 14:25:22 +00:00
AST : : FunctionDeclaration * function = AST : : cast < AST : : FunctionDeclaration * > ( _functions . at ( f - > index ) . node ) ;
2013-09-11 17:28:13 +00:00
Q_ASSERT ( function ) ;
QString name = function - > name . toString ( ) ;
if ( functionNames . contains ( name ) )
COMPILE_EXCEPTION ( function - > identifierToken , tr ( " Duplicate method name " ) ) ;
functionNames . insert ( name ) ;
2014-01-17 14:56:14 +00:00
if ( _object - > signalNames . contains ( name ) )
2013-09-11 17:28:13 +00:00
COMPILE_EXCEPTION ( function - > identifierToken , tr ( " Duplicate method name " ) ) ;
if ( name . at ( 0 ) . isUpper ( ) )
COMPILE_EXCEPTION ( function - > identifierToken , tr ( " Method names cannot begin with an upper case letter " ) ) ;
2013-12-06 10:29:43 +00:00
if ( illegalNames . contains ( name ) )
COMPILE_EXCEPTION ( function - > identifierToken , tr ( " Illegal method name " ) ) ;
2013-09-11 17:28:13 +00:00
}
return true ;
}
2014-01-28 09:41:58 +00:00
int QQmlCodeGenerator : : defineQMLObject ( AST : : UiQualifiedId * qualifiedTypeNameId , const AST : : SourceLocation & location , AST : : UiObjectInitializer * initializer , QmlObject * declarationsOverride )
2013-08-06 14:41:28 +00:00
{
QmlObject * obj = New < QmlObject > ( ) ;
_objects . append ( obj ) ;
const int objectIndex = _objects . size ( ) - 1 ;
qSwap ( _object , obj ) ;
2014-01-29 07:55:02 +00:00
_object - > init ( pool , registerString ( asString ( qualifiedTypeNameId ) ) , emptyStringIndex , location ) ;
2014-01-28 09:41:58 +00:00
_object - > declarationsOverride = declarationsOverride ;
2013-08-06 14:41:28 +00:00
2014-01-28 09:41:58 +00:00
// A new object is also a boundary for property declarations.
QmlProperty * declaration = 0 ;
qSwap ( _propertyDeclaration , declaration ) ;
2013-09-11 17:28:13 +00:00
2013-08-06 14:41:28 +00:00
accept ( initializer ) ;
2014-01-28 09:41:58 +00:00
qSwap ( _propertyDeclaration , declaration ) ;
2013-09-11 17:28:13 +00:00
sanityCheckFunctionNames ( ) ;
2013-08-06 14:41:28 +00:00
qSwap ( _object , obj ) ;
return objectIndex ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiImport * node )
{
QString uri ;
QV4 : : CompiledData : : Import * import = New < QV4 : : CompiledData : : Import > ( ) ;
if ( ! node - > fileName . isNull ( ) ) {
uri = node - > fileName . toString ( ) ;
if ( uri . endsWith ( QLatin1String ( " .js " ) ) ) {
import - > type = QV4 : : CompiledData : : Import : : ImportScript ;
} else {
import - > type = QV4 : : CompiledData : : Import : : ImportFile ;
}
} else {
import - > type = QV4 : : CompiledData : : Import : : ImportLibrary ;
uri = asString ( node - > importUri ) ;
}
2013-09-19 11:32:13 +00:00
import - > qualifierIndex = emptyStringIndex ;
2013-08-06 14:41:28 +00:00
// Qualifier
if ( ! node - > importId . isNull ( ) ) {
QString qualifier = node - > importId . toString ( ) ;
if ( ! qualifier . at ( 0 ) . isUpper ( ) ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Invalid import qualifier ID " ) ) ;
error . setLine ( node - > importIdToken . startLine ) ;
error . setColumn ( node - > importIdToken . startColumn ) ;
errors < < error ;
return false ;
}
if ( qualifier = = QLatin1String ( " Qt " ) ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Reserved name \" Qt \" cannot be used as an qualifier " ) ) ;
error . setLine ( node - > importIdToken . startLine ) ;
error . setColumn ( node - > importIdToken . startColumn ) ;
errors < < error ;
return false ;
}
import - > qualifierIndex = registerString ( qualifier ) ;
// Check for script qualifier clashes
bool isScript = import - > type = = QV4 : : CompiledData : : Import : : ImportScript ;
for ( int ii = 0 ; ii < _imports . count ( ) ; + + ii ) {
QV4 : : CompiledData : : Import * other = _imports . at ( ii ) ;
bool otherIsScript = other - > type = = QV4 : : CompiledData : : Import : : ImportScript ;
if ( ( isScript | | otherIsScript ) & & qualifier = = jsGenerator - > strings . at ( other - > qualifierIndex ) ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Script import qualifiers must be unique. " ) ) ;
error . setLine ( node - > importIdToken . startLine ) ;
error . setColumn ( node - > importIdToken . startColumn ) ;
errors < < error ;
return false ;
}
}
} else if ( import - > type = = QV4 : : CompiledData : : Import : : ImportScript ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Script import requires a qualifier " ) ) ;
error . setLine ( node - > fileNameToken . startLine ) ;
error . setColumn ( node - > fileNameToken . startColumn ) ;
errors < < error ;
return false ;
}
if ( node - > versionToken . isValid ( ) ) {
extractVersion ( textRefAt ( node - > versionToken ) , & import - > majorVersion , & import - > minorVersion ) ;
} else if ( import - > type = = QV4 : : CompiledData : : Import : : ImportLibrary ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Library import requires a version " ) ) ;
error . setLine ( node - > importIdToken . startLine ) ;
error . setColumn ( node - > importIdToken . startColumn ) ;
errors < < error ;
return false ;
2013-09-24 19:49:10 +00:00
} else {
// For backward compatibility in how the imports are loaded we
// must otherwise initialize the major and minor version to -1.
import - > majorVersion = - 1 ;
import - > minorVersion = - 1 ;
2013-08-06 14:41:28 +00:00
}
2013-09-30 04:36:35 +00:00
import - > location . line = node - > importToken . startLine ;
import - > location . column = node - > importToken . startColumn ;
2013-08-06 14:41:28 +00:00
import - > uriIndex = registerString ( uri ) ;
_imports . append ( import ) ;
return false ;
}
2013-09-24 19:49:10 +00:00
bool QQmlCodeGenerator : : visit ( AST : : UiPragma * node )
2013-08-22 19:08:37 +00:00
{
2013-09-24 19:49:10 +00:00
Pragma * pragma = New < Pragma > ( ) ;
// For now the only valid pragma is Singleton, so lets validate the input
if ( ! node - > pragmaType - > name . isNull ( ) )
{
if ( QLatin1String ( " Singleton " ) = = node - > pragmaType - > name )
{
pragma - > type = Pragma : : PragmaSingleton ;
} else {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Pragma requires a valid qualifier " ) ) ;
error . setLine ( node - > pragmaToken . startLine ) ;
error . setColumn ( node - > pragmaToken . startColumn ) ;
errors < < error ;
return false ;
}
} else {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Pragma requires a valid qualifier " ) ) ;
error . setLine ( node - > pragmaToken . startLine ) ;
error . setColumn ( node - > pragmaToken . startColumn ) ;
errors < < error ;
return false ;
}
pragma - > location . line = node - > pragmaToken . startLine ;
pragma - > location . column = node - > pragmaToken . startColumn ;
_pragmas . append ( pragma ) ;
return false ;
2013-08-22 19:08:37 +00:00
}
2013-09-19 11:32:13 +00:00
static QStringList astNodeToStringList ( QQmlJS : : AST : : Node * node )
{
if ( node - > kind = = QQmlJS : : AST : : Node : : Kind_IdentifierExpression ) {
QString name =
static_cast < QQmlJS : : AST : : IdentifierExpression * > ( node ) - > name . toString ( ) ;
return QStringList ( ) < < name ;
} else if ( node - > kind = = QQmlJS : : AST : : Node : : Kind_FieldMemberExpression ) {
QQmlJS : : AST : : FieldMemberExpression * expr = static_cast < QQmlJS : : AST : : FieldMemberExpression * > ( node ) ;
QStringList rv = astNodeToStringList ( expr - > base ) ;
if ( rv . isEmpty ( ) )
return rv ;
rv . append ( expr - > name . toString ( ) ) ;
return rv ;
}
return QStringList ( ) ;
}
2013-08-06 14:41:28 +00:00
bool QQmlCodeGenerator : : visit ( AST : : UiPublicMember * node )
{
static const struct TypeNameToType {
const char * name ;
size_t nameLength ;
QV4 : : CompiledData : : Property : : Type type ;
} propTypeNameToTypes [ ] = {
{ " int " , strlen ( " int " ) , QV4 : : CompiledData : : Property : : Int } ,
{ " bool " , strlen ( " bool " ) , QV4 : : CompiledData : : Property : : Bool } ,
{ " double " , strlen ( " double " ) , QV4 : : CompiledData : : Property : : Real } ,
{ " real " , strlen ( " real " ) , QV4 : : CompiledData : : Property : : Real } ,
{ " string " , strlen ( " string " ) , QV4 : : CompiledData : : Property : : String } ,
{ " url " , strlen ( " url " ) , QV4 : : CompiledData : : Property : : Url } ,
{ " color " , strlen ( " color " ) , QV4 : : CompiledData : : Property : : Color } ,
// Internally QTime, QDate and QDateTime are all supported.
// To be more consistent with JavaScript we expose only
// QDateTime as it matches closely with the Date JS type.
// We also call it "date" to match.
// { "time", strlen("time"), Property::Time },
// { "date", strlen("date"), Property::Date },
{ " date " , strlen ( " date " ) , QV4 : : CompiledData : : Property : : DateTime } ,
{ " rect " , strlen ( " rect " ) , QV4 : : CompiledData : : Property : : Rect } ,
{ " point " , strlen ( " point " ) , QV4 : : CompiledData : : Property : : Point } ,
{ " size " , strlen ( " size " ) , QV4 : : CompiledData : : Property : : Size } ,
{ " font " , strlen ( " font " ) , QV4 : : CompiledData : : Property : : Font } ,
{ " vector2d " , strlen ( " vector2d " ) , QV4 : : CompiledData : : Property : : Vector2D } ,
{ " vector3d " , strlen ( " vector3d " ) , QV4 : : CompiledData : : Property : : Vector3D } ,
{ " vector4d " , strlen ( " vector4d " ) , QV4 : : CompiledData : : Property : : Vector4D } ,
{ " quaternion " , strlen ( " quaternion " ) , QV4 : : CompiledData : : Property : : Quaternion } ,
{ " matrix4x4 " , strlen ( " matrix4x4 " ) , QV4 : : CompiledData : : Property : : Matrix4x4 } ,
{ " variant " , strlen ( " variant " ) , QV4 : : CompiledData : : Property : : Variant } ,
{ " var " , strlen ( " var " ) , QV4 : : CompiledData : : Property : : Var }
} ;
static const int propTypeNameToTypesCount = sizeof ( propTypeNameToTypes ) /
sizeof ( propTypeNameToTypes [ 0 ] ) ;
2014-01-28 09:41:58 +00:00
QmlObject * declarationsTarget = _object - > declarationsOverride ? _object - > declarationsOverride : _object ;
2013-08-06 14:41:28 +00:00
if ( node - > type = = AST : : UiPublicMember : : Signal ) {
Signal * signal = New < Signal > ( ) ;
2013-09-11 17:28:13 +00:00
QString signalName = node - > name . toString ( ) ;
signal - > nameIndex = registerString ( signalName ) ;
2013-09-06 12:14:20 +00:00
2014-01-30 16:07:23 +00:00
AST : : SourceLocation loc = node - > typeToken ;
2013-09-06 12:14:20 +00:00
signal - > location . line = loc . startLine ;
signal - > location . column = loc . startColumn ;
2013-08-06 14:41:28 +00:00
signal - > parameters = New < PoolList < SignalParameter > > ( ) ;
AST : : UiParameterList * p = node - > parameters ;
while ( p ) {
const QStringRef & memberType = p - > type ;
if ( memberType . isEmpty ( ) ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Expected parameter type " ) ) ;
error . setLine ( node - > typeToken . startLine ) ;
error . setColumn ( node - > typeToken . startColumn ) ;
errors < < error ;
return false ;
}
const TypeNameToType * type = 0 ;
for ( int typeIndex = 0 ; typeIndex < propTypeNameToTypesCount ; + + typeIndex ) {
const TypeNameToType * t = propTypeNameToTypes + typeIndex ;
if ( t - > nameLength = = size_t ( memberType . length ( ) ) & &
2013-11-01 11:38:32 +00:00
QHashedString : : compare ( memberType . constData ( ) , t - > name , static_cast < int > ( t - > nameLength ) ) ) {
2013-08-06 14:41:28 +00:00
type = t ;
break ;
}
}
SignalParameter * param = New < SignalParameter > ( ) ;
if ( ! type ) {
if ( memberType . at ( 0 ) . isUpper ( ) ) {
// Must be a QML object type.
// Lazily determine type during compilation.
param - > type = QV4 : : CompiledData : : Property : : Custom ;
param - > customTypeNameIndex = registerString ( p - > type . toString ( ) ) ;
} else {
QQmlError error ;
QString errStr = QCoreApplication : : translate ( " QQmlParser " , " Invalid signal parameter type: " ) ;
errStr . append ( memberType . toString ( ) ) ;
error . setDescription ( errStr ) ;
error . setLine ( node - > typeToken . startLine ) ;
error . setColumn ( node - > typeToken . startColumn ) ;
errors < < error ;
return false ;
}
} else {
// the parameter is a known basic type
param - > type = type - > type ;
2013-09-19 11:32:13 +00:00
param - > customTypeNameIndex = emptyStringIndex ;
2013-08-06 14:41:28 +00:00
}
param - > nameIndex = registerString ( p - > name . toString ( ) ) ;
2013-09-12 08:53:20 +00:00
param - > location . line = p - > identifierToken . startLine ;
param - > location . column = p - > identifierToken . startColumn ;
2013-08-06 14:41:28 +00:00
signal - > parameters - > append ( param ) ;
p = p - > next ;
}
2014-01-17 14:56:14 +00:00
if ( _object - > signalNames . contains ( signalName ) )
2013-09-11 17:28:13 +00:00
COMPILE_EXCEPTION ( node - > identifierToken , tr ( " Duplicate signal name " ) ) ;
2014-01-17 14:56:14 +00:00
_object - > signalNames . insert ( signalName ) ;
2013-09-11 17:28:13 +00:00
if ( signalName . at ( 0 ) . isUpper ( ) )
COMPILE_EXCEPTION ( node - > identifierToken , tr ( " Signal names cannot begin with an upper case letter " ) ) ;
2013-12-06 10:29:43 +00:00
if ( illegalNames . contains ( signalName ) )
COMPILE_EXCEPTION ( node - > identifierToken , tr ( " Illegal signal name " ) ) ;
2013-09-11 17:28:13 +00:00
2014-01-28 09:41:58 +00:00
declarationsTarget - > qmlSignals - > append ( signal ) ;
2013-08-06 14:41:28 +00:00
} else {
const QStringRef & memberType = node - > memberType ;
const QStringRef & name = node - > name ;
bool typeFound = false ;
QV4 : : CompiledData : : Property : : Type type ;
if ( ( unsigned ) memberType . length ( ) = = strlen ( " alias " ) & &
2013-11-01 11:38:32 +00:00
QHashedString : : compare ( memberType . constData ( ) , " alias " , static_cast < int > ( strlen ( " alias " ) ) ) ) {
2013-08-06 14:41:28 +00:00
type = QV4 : : CompiledData : : Property : : Alias ;
typeFound = true ;
}
for ( int ii = 0 ; ! typeFound & & ii < propTypeNameToTypesCount ; + + ii ) {
const TypeNameToType * t = propTypeNameToTypes + ii ;
if ( t - > nameLength = = size_t ( memberType . length ( ) ) & &
2013-11-01 11:38:32 +00:00
QHashedString : : compare ( memberType . constData ( ) , t - > name , static_cast < int > ( t - > nameLength ) ) ) {
2013-08-06 14:41:28 +00:00
type = t - > type ;
typeFound = true ;
}
}
if ( ! typeFound & & memberType . at ( 0 ) . isUpper ( ) ) {
const QStringRef & typeModifier = node - > typeModifier ;
if ( typeModifier . isEmpty ( ) ) {
type = QV4 : : CompiledData : : Property : : Custom ;
} else if ( ( unsigned ) typeModifier . length ( ) = = strlen ( " list " ) & &
2013-11-01 11:38:32 +00:00
QHashedString : : compare ( typeModifier . constData ( ) , " list " , static_cast < int > ( strlen ( " list " ) ) ) ) {
2013-08-06 14:41:28 +00:00
type = QV4 : : CompiledData : : Property : : CustomList ;
} else {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Invalid property type modifier " ) ) ;
error . setLine ( node - > typeModifierToken . startLine ) ;
error . setColumn ( node - > typeModifierToken . startColumn ) ;
errors < < error ;
return false ;
}
typeFound = true ;
} else if ( ! node - > typeModifier . isNull ( ) ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Unexpected property type modifier " ) ) ;
error . setLine ( node - > typeModifierToken . startLine ) ;
error . setColumn ( node - > typeModifierToken . startColumn ) ;
errors < < error ;
return false ;
}
if ( ! typeFound ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Expected property type " ) ) ;
error . setLine ( node - > typeToken . startLine ) ;
error . setColumn ( node - > typeToken . startColumn ) ;
errors < < error ;
return false ;
}
QmlProperty * property = New < QmlProperty > ( ) ;
property - > flags = 0 ;
if ( node - > isReadonlyMember )
property - > flags | = QV4 : : CompiledData : : Property : : IsReadOnly ;
property - > type = type ;
if ( type > = QV4 : : CompiledData : : Property : : Custom )
property - > customTypeNameIndex = registerString ( memberType . toString ( ) ) ;
else
2013-09-19 11:32:13 +00:00
property - > customTypeNameIndex = emptyStringIndex ;
2013-08-06 14:41:28 +00:00
property - > nameIndex = registerString ( name . toString ( ) ) ;
2013-09-09 11:51:31 +00:00
AST : : SourceLocation loc = node - > firstSourceLocation ( ) ;
property - > location . line = loc . startLine ;
property - > location . column = loc . startColumn ;
2013-09-19 11:32:13 +00:00
property - > aliasPropertyValueIndex = emptyStringIndex ;
if ( type = = QV4 : : CompiledData : : Property : : Alias ) {
if ( ! node - > statement & & ! node - > binding )
COMPILE_EXCEPTION ( loc , tr ( " No property alias location " ) ) ;
2013-09-30 07:41:35 +00:00
AST : : SourceLocation rhsLoc ;
if ( node - > binding )
rhsLoc = node - > binding - > firstSourceLocation ( ) ;
else if ( node - > statement )
rhsLoc = node - > statement - > firstSourceLocation ( ) ;
else
rhsLoc = node - > semicolonToken ;
property - > aliasLocation . line = rhsLoc . startLine ;
property - > aliasLocation . column = rhsLoc . startColumn ;
2013-09-19 11:32:13 +00:00
QStringList alias ;
2013-09-30 07:41:35 +00:00
if ( AST : : ExpressionStatement * stmt = AST : : cast < AST : : ExpressionStatement * > ( node - > statement ) ) {
alias = astNodeToStringList ( stmt - > expression ) ;
if ( alias . isEmpty ( ) ) {
if ( isStatementNodeScript ( node - > statement ) ) {
COMPILE_EXCEPTION ( rhsLoc , tr ( " Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> " ) ) ;
} else {
COMPILE_EXCEPTION ( rhsLoc , tr ( " Invalid alias location " ) ) ;
}
}
} else {
COMPILE_EXCEPTION ( rhsLoc , tr ( " Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> " ) ) ;
}
2013-09-19 11:32:13 +00:00
2013-09-30 07:41:35 +00:00
if ( alias . count ( ) < 1 | | alias . count ( ) > 3 )
COMPILE_EXCEPTION ( rhsLoc , tr ( " Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> " ) ) ;
2013-09-19 11:32:13 +00:00
property - > aliasIdValueIndex = registerString ( alias . first ( ) ) ;
QString propertyValue = alias . value ( 1 ) ;
if ( alias . count ( ) = = 3 ) {
propertyValue + = QLatin1Char ( ' . ' ) ;
propertyValue + = alias . at ( 2 ) ;
}
property - > aliasPropertyValueIndex = registerString ( propertyValue ) ;
2014-01-27 12:09:01 +00:00
} else if ( node - > statement ) {
qSwap ( _propertyDeclaration , property ) ;
appendBinding ( node - > identifierToken , _propertyDeclaration - > nameIndex , node - > statement ) ;
qSwap ( _propertyDeclaration , property ) ;
}
2013-08-06 14:41:28 +00:00
2014-01-28 09:41:58 +00:00
declarationsTarget - > properties - > append ( property ) ;
2013-08-06 14:41:28 +00:00
if ( node - > isDefaultMember ) {
if ( _object - > indexOfDefaultProperty ! = - 1 ) {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " Duplicate default property " ) ) ;
error . setLine ( node - > defaultToken . startLine ) ;
error . setColumn ( node - > defaultToken . startColumn ) ;
errors < < error ;
return false ;
}
_object - > indexOfDefaultProperty = _object - > properties - > count - 1 ;
}
2014-01-27 12:09:01 +00:00
if ( node - > binding ) {
qSwap ( _propertyDeclaration , property ) ;
// process QML-like initializers (e.g. property Object o: Object {})
AST : : Node : : accept ( node - > binding , this ) ;
qSwap ( _propertyDeclaration , property ) ;
}
2013-08-06 14:41:28 +00:00
}
return false ;
}
bool QQmlCodeGenerator : : visit ( AST : : UiSourceElement * node )
{
if ( AST : : FunctionDeclaration * funDecl = AST : : cast < AST : : FunctionDeclaration * > ( node - > sourceElement ) ) {
_functions < < funDecl ;
Function * f = New < Function > ( ) ;
2013-12-11 12:44:56 +00:00
f - > functionDeclaration = funDecl ;
2014-01-31 08:42:27 +00:00
AST : : SourceLocation loc = funDecl - > identifierToken ;
2013-12-11 12:44:56 +00:00
f - > location . line = loc . startLine ;
f - > location . column = loc . startColumn ;
2013-08-06 14:41:28 +00:00
f - > index = _functions . size ( ) - 1 ;
2014-01-28 09:41:58 +00:00
QmlObject * functionDeclarationsTarget = _object - > declarationsOverride ? _object - > declarationsOverride : _object ;
functionDeclarationsTarget - > functions - > append ( f ) ;
2013-08-06 14:41:28 +00:00
} else {
QQmlError error ;
error . setDescription ( QCoreApplication : : translate ( " QQmlParser " , " JavaScript declaration outside Script element " ) ) ;
error . setLine ( node - > firstSourceLocation ( ) . startLine ) ;
error . setColumn ( node - > firstSourceLocation ( ) . startColumn ) ;
errors < < error ;
}
return false ;
}
QString QQmlCodeGenerator : : asString ( AST : : UiQualifiedId * node )
{
QString s ;
for ( AST : : UiQualifiedId * it = node ; it ; it = it - > next ) {
s . append ( it - > name ) ;
if ( it - > next )
s . append ( QLatin1Char ( ' . ' ) ) ;
}
return s ;
}
QStringRef QQmlCodeGenerator : : asStringRef ( AST : : Node * node )
{
if ( ! node )
return QStringRef ( ) ;
return textRefAt ( node - > firstSourceLocation ( ) , node - > lastSourceLocation ( ) ) ;
}
void QQmlCodeGenerator : : extractVersion ( QStringRef string , int * maj , int * min )
{
* maj = - 1 ; * min = - 1 ;
if ( ! string . isEmpty ( ) ) {
int dot = string . indexOf ( QLatin1Char ( ' . ' ) ) ;
if ( dot < 0 ) {
2013-10-04 04:54:18 +00:00
* maj = string . toInt ( ) ;
2013-08-06 14:41:28 +00:00
* min = 0 ;
} else {
2013-10-04 04:54:18 +00:00
* maj = string . left ( dot ) . toInt ( ) ;
* min = string . mid ( dot + 1 ) . toInt ( ) ;
2013-08-06 14:41:28 +00:00
}
}
}
QStringRef QQmlCodeGenerator : : textRefAt ( const AST : : SourceLocation & first , const AST : : SourceLocation & last ) const
{
return QStringRef ( & sourceCode , first . offset , last . offset + last . length - first . offset ) ;
}
void QQmlCodeGenerator : : setBindingValue ( QV4 : : CompiledData : : Binding * binding , AST : : Statement * statement )
{
2014-01-24 15:49:03 +00:00
AST : : SourceLocation loc = statement - > firstSourceLocation ( ) ;
binding - > valueLocation . line = loc . startLine ;
binding - > valueLocation . column = loc . startColumn ;
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_Invalid ;
2014-01-27 12:09:01 +00:00
if ( _propertyDeclaration & & ( _propertyDeclaration - > flags & QV4 : : CompiledData : : Property : : IsReadOnly ) )
binding - > flags | = QV4 : : CompiledData : : Binding : : InitializerForReadOnlyDeclaration ;
2013-08-06 14:41:28 +00:00
if ( AST : : ExpressionStatement * stmt = AST : : cast < AST : : ExpressionStatement * > ( statement ) ) {
AST : : ExpressionNode * expr = stmt - > expression ;
if ( AST : : StringLiteral * lit = AST : : cast < AST : : StringLiteral * > ( expr ) ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_String ;
binding - > stringIndex = registerString ( lit - > value . toString ( ) ) ;
2013-08-06 14:41:28 +00:00
} else if ( expr - > kind = = AST : : Node : : Kind_TrueLiteral ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_Boolean ;
2013-08-06 14:41:28 +00:00
binding - > value . b = true ;
} else if ( expr - > kind = = AST : : Node : : Kind_FalseLiteral ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_Boolean ;
2013-08-06 14:41:28 +00:00
binding - > value . b = false ;
} else if ( AST : : NumericLiteral * lit = AST : : cast < AST : : NumericLiteral * > ( expr ) ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_Number ;
2013-08-06 14:41:28 +00:00
binding - > value . d = lit - > value ;
} else {
if ( AST : : UnaryMinusExpression * unaryMinus = AST : : cast < AST : : UnaryMinusExpression * > ( expr ) ) {
if ( AST : : NumericLiteral * lit = AST : : cast < AST : : NumericLiteral * > ( unaryMinus - > expression ) ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_Number ;
2013-08-06 14:41:28 +00:00
binding - > value . d = - lit - > value ;
}
}
}
}
// Do binding instead
2013-09-13 07:08:41 +00:00
if ( binding - > type = = QV4 : : CompiledData : : Binding : : Type_Invalid ) {
binding - > type = QV4 : : CompiledData : : Binding : : Type_Script ;
2013-08-06 14:41:28 +00:00
_functions < < statement ;
binding - > value . compiledScriptIndex = _functions . size ( ) - 1 ;
2013-09-13 07:08:41 +00:00
binding - > stringIndex = registerString ( asStringRef ( statement ) . toString ( ) ) ;
2013-08-06 14:41:28 +00:00
}
}
2013-09-12 12:43:56 +00:00
void QQmlCodeGenerator : : appendBinding ( AST : : UiQualifiedId * name , AST : : Statement * value )
{
QmlObject * object = 0 ;
2013-09-17 15:23:49 +00:00
if ( ! resolveQualifiedId ( & name , & object ) )
return ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
appendBinding ( name - > identifierToken , registerString ( name - > name . toString ( ) ) , value ) ;
qSwap ( _object , object ) ;
}
2013-09-30 15:39:49 +00:00
void QQmlCodeGenerator : : appendBinding ( AST : : UiQualifiedId * name , int objectIndex , bool isOnAssignment )
2013-09-12 12:43:56 +00:00
{
QmlObject * object = 0 ;
2013-09-17 15:23:49 +00:00
if ( ! resolveQualifiedId ( & name , & object ) )
return ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
2013-09-30 15:39:49 +00:00
appendBinding ( name - > identifierToken , registerString ( name - > name . toString ( ) ) , objectIndex , /*isListItem*/ false , isOnAssignment ) ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
}
2013-09-11 17:28:13 +00:00
void QQmlCodeGenerator : : appendBinding ( const AST : : SourceLocation & nameLocation , int propertyNameIndex , AST : : Statement * value )
2013-08-06 14:41:28 +00:00
{
2013-09-11 17:28:13 +00:00
if ( ! sanityCheckPropertyName ( nameLocation , propertyNameIndex ) )
return ;
2013-09-12 14:53:32 +00:00
if ( stringAt ( propertyNameIndex ) = = QStringLiteral ( " id " ) ) {
setId ( value ) ;
return ;
}
2013-08-06 14:41:28 +00:00
Binding * binding = New < Binding > ( ) ;
binding - > propertyNameIndex = propertyNameIndex ;
2013-09-13 13:03:51 +00:00
binding - > location . line = nameLocation . startLine ;
binding - > location . column = nameLocation . startColumn ;
binding - > flags = 0 ;
2013-08-06 14:41:28 +00:00
setBindingValue ( binding , value ) ;
2014-01-28 09:41:58 +00:00
bindingsTarget ( ) - > append ( binding ) ;
2013-08-06 14:41:28 +00:00
}
2013-09-30 15:39:49 +00:00
void QQmlCodeGenerator : : appendBinding ( const AST : : SourceLocation & nameLocation , int propertyNameIndex , int objectIndex , bool isListItem , bool isOnAssignment )
2013-08-06 14:41:28 +00:00
{
2013-09-30 15:39:49 +00:00
if ( ! sanityCheckPropertyName ( nameLocation , propertyNameIndex , isListItem | isOnAssignment ) )
2013-09-11 17:28:13 +00:00
return ;
2013-09-17 15:23:49 +00:00
if ( stringAt ( propertyNameIndex ) = = QStringLiteral ( " id " ) ) {
recordError ( nameLocation , tr ( " Invalid component id specification " ) ) ;
return ;
}
2013-08-06 14:41:28 +00:00
Binding * binding = New < Binding > ( ) ;
binding - > propertyNameIndex = propertyNameIndex ;
2013-09-13 13:03:51 +00:00
binding - > location . line = nameLocation . startLine ;
binding - > location . column = nameLocation . startColumn ;
2014-01-24 15:49:03 +00:00
const QmlObject * obj = _objects . at ( objectIndex ) ;
binding - > valueLocation = obj - > location ;
2013-09-13 13:03:51 +00:00
binding - > flags = 0 ;
2014-01-10 12:34:41 +00:00
2014-01-27 12:09:01 +00:00
if ( _propertyDeclaration & & ( _propertyDeclaration - > flags & QV4 : : CompiledData : : Property : : IsReadOnly ) )
binding - > flags | = QV4 : : CompiledData : : Binding : : InitializerForReadOnlyDeclaration ;
2014-01-10 12:34:41 +00:00
// No type name on the initializer means it must be a group property
if ( stringAt ( _objects . at ( objectIndex ) - > inheritedTypeNameIndex ) . isEmpty ( ) )
binding - > type = QV4 : : CompiledData : : Binding : : Type_GroupProperty ;
else
binding - > type = QV4 : : CompiledData : : Binding : : Type_Object ;
2013-09-30 15:39:49 +00:00
if ( isOnAssignment )
binding - > flags | = QV4 : : CompiledData : : Binding : : IsOnAssignment ;
2013-08-06 14:41:28 +00:00
binding - > value . objectIndex = objectIndex ;
2014-01-28 09:41:58 +00:00
bindingsTarget ( ) - > append ( binding ) ;
}
PoolList < Binding > * QQmlCodeGenerator : : bindingsTarget ( ) const
{
if ( _propertyDeclaration & & _object - > declarationsOverride )
return _object - > declarationsOverride - > bindings ;
return _object - > bindings ;
2013-08-06 14:41:28 +00:00
}
2013-09-11 17:28:13 +00:00
2013-09-12 14:53:32 +00:00
bool QQmlCodeGenerator : : setId ( AST : : Statement * value )
{
AST : : SourceLocation loc = value - > firstSourceLocation ( ) ;
QStringRef str ;
2013-09-17 15:21:11 +00:00
AST : : Node * node = value ;
if ( AST : : ExpressionStatement * stmt = AST : : cast < AST : : ExpressionStatement * > ( node ) ) {
2013-09-12 14:53:32 +00:00
if ( AST : : StringLiteral * lit = AST : : cast < AST : : StringLiteral * > ( stmt - > expression ) )
str = lit - > value ;
2013-09-17 15:21:11 +00:00
else
node = stmt - > expression ;
}
2013-09-12 14:53:32 +00:00
if ( str . isEmpty ( ) )
2013-09-17 15:21:11 +00:00
str = asStringRef ( node ) ;
2013-09-12 14:53:32 +00:00
if ( str . isEmpty ( ) )
COMPILE_EXCEPTION ( loc , tr ( " Invalid empty ID " ) ) ;
QChar ch = str . at ( 0 ) ;
if ( ch . isLetter ( ) & & ! ch . isLower ( ) )
COMPILE_EXCEPTION ( loc , tr ( " IDs cannot start with an uppercase letter " ) ) ;
QChar u ( QLatin1Char ( ' _ ' ) ) ;
if ( ! ch . isLetter ( ) & & ch ! = u )
COMPILE_EXCEPTION ( loc , tr ( " IDs must start with a letter or underscore " ) ) ;
for ( int ii = 1 ; ii < str . count ( ) ; + + ii ) {
ch = str . at ( ii ) ;
if ( ! ch . isLetterOrNumber ( ) & & ch ! = u )
COMPILE_EXCEPTION ( loc , tr ( " IDs must contain only letters, numbers, and underscores " ) ) ;
}
2013-12-06 10:29:43 +00:00
QString idQString ( str . toString ( ) ) ;
if ( illegalNames . contains ( idQString ) )
COMPILE_EXCEPTION ( loc , tr ( " ID illegally masks global JavaScript property " ) ) ;
2013-09-12 14:53:32 +00:00
2013-12-06 10:29:43 +00:00
_object - > idIndex = registerString ( idQString ) ;
2013-09-17 15:27:07 +00:00
_object - > locationOfIdProperty . line = loc . startLine ;
_object - > locationOfIdProperty . column = loc . startColumn ;
2013-09-12 14:53:32 +00:00
return true ;
}
2013-09-17 15:23:49 +00:00
bool QQmlCodeGenerator : : resolveQualifiedId ( AST : : UiQualifiedId * * nameToResolve , QmlObject * * object )
2013-09-12 12:43:56 +00:00
{
2014-01-24 11:01:33 +00:00
AST : : UiQualifiedId * qualifiedIdElement = * nameToResolve ;
if ( qualifiedIdElement - > name = = QStringLiteral ( " id " ) & & qualifiedIdElement - > next )
COMPILE_EXCEPTION ( qualifiedIdElement - > identifierToken , tr ( " Invalid use of id property " ) ) ;
// If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
QString currentName = qualifiedIdElement - > name . toString ( ) ;
if ( qualifiedIdElement - > next ) {
foreach ( QV4 : : CompiledData : : Import * import , _imports )
if ( import - > qualifierIndex ! = emptyStringIndex
& & stringAt ( import - > qualifierIndex ) = = currentName ) {
qualifiedIdElement = qualifiedIdElement - > next ;
currentName + = QLatin1Char ( ' . ' ) ;
currentName + = qualifiedIdElement - > name ;
2014-01-24 12:13:58 +00:00
if ( ! qualifiedIdElement - > name . unicode ( ) - > isUpper ( ) )
COMPILE_EXCEPTION ( qualifiedIdElement - > firstSourceLocation ( ) , tr ( " Expected type name " ) ) ;
2014-01-24 11:01:33 +00:00
break ;
}
}
2013-09-17 15:23:49 +00:00
2013-09-12 12:43:56 +00:00
* object = _object ;
2014-01-24 11:01:33 +00:00
while ( qualifiedIdElement - > next ) {
2013-09-12 12:43:56 +00:00
Binding * binding = New < Binding > ( ) ;
2014-01-24 11:01:33 +00:00
binding - > propertyNameIndex = registerString ( currentName ) ;
binding - > location . line = qualifiedIdElement - > identifierToken . startLine ;
binding - > location . column = qualifiedIdElement - > identifierToken . startColumn ;
2014-01-24 15:49:03 +00:00
binding - > valueLocation . line = binding - > valueLocation . column = 0 ;
2013-09-13 13:03:51 +00:00
binding - > flags = 0 ;
2013-09-16 12:38:58 +00:00
2014-01-24 11:01:33 +00:00
if ( qualifiedIdElement - > name . unicode ( ) - > isUpper ( ) )
2013-09-16 12:38:58 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_AttachedProperty ;
else
binding - > type = QV4 : : CompiledData : : Binding : : Type_GroupProperty ;
2013-09-12 12:43:56 +00:00
2014-01-28 09:41:58 +00:00
int objIndex = defineQMLObject ( 0 , AST : : SourceLocation ( ) , 0 , 0 ) ;
2013-09-12 12:43:56 +00:00
binding - > value . objectIndex = objIndex ;
( * object ) - > bindings - > append ( binding ) ;
* object = _objects [ objIndex ] ;
2014-01-24 11:01:33 +00:00
qualifiedIdElement = qualifiedIdElement - > next ;
if ( qualifiedIdElement )
currentName = qualifiedIdElement - > name . toString ( ) ;
2013-09-12 12:43:56 +00:00
}
2014-01-24 11:01:33 +00:00
* nameToResolve = qualifiedIdElement ;
2013-09-17 15:23:49 +00:00
return true ;
2013-09-12 12:43:56 +00:00
}
2013-09-30 15:39:49 +00:00
bool QQmlCodeGenerator : : sanityCheckPropertyName ( const AST : : SourceLocation & nameLocation , int nameIndex , bool isListItemOnOrAssignment )
2013-09-11 17:28:13 +00:00
{
2013-09-12 12:43:56 +00:00
const QString & name = jsGenerator - > strings . at ( nameIndex ) ;
if ( name . isEmpty ( ) )
return true ;
2013-09-16 15:25:53 +00:00
// List items are implement by multiple bindings to the same name, so allow duplicates.
2013-09-30 15:39:49 +00:00
if ( ! isListItemOnOrAssignment ) {
2014-01-17 14:56:14 +00:00
if ( _object - > propertyNames . contains ( name ) )
2013-09-16 15:25:53 +00:00
COMPILE_EXCEPTION ( nameLocation , tr ( " Duplicate property name " ) ) ;
2013-09-11 17:28:13 +00:00
2014-01-17 14:56:14 +00:00
_object - > propertyNames . insert ( name ) ;
2013-09-16 15:25:53 +00:00
}
2013-09-11 17:28:13 +00:00
if ( name . at ( 0 ) . isUpper ( ) )
COMPILE_EXCEPTION ( nameLocation , tr ( " Property names cannot begin with an upper case letter " ) ) ;
2013-12-06 10:29:43 +00:00
if ( illegalNames . contains ( name ) )
COMPILE_EXCEPTION ( nameLocation , tr ( " Illegal property name " ) ) ;
2013-09-11 17:28:13 +00:00
return true ;
}
void QQmlCodeGenerator : : recordError ( const AST : : SourceLocation & location , const QString & description )
{
QQmlError error ;
error . setUrl ( url ) ;
error . setLine ( location . startLine ) ;
error . setColumn ( location . startColumn ) ;
error . setDescription ( description ) ;
errors < < error ;
}
2013-09-12 08:53:20 +00:00
void QQmlCodeGenerator : : collectTypeReferences ( )
{
foreach ( QmlObject * obj , _objects ) {
2014-01-27 15:55:49 +00:00
if ( ! stringAt ( obj - > inheritedTypeNameIndex ) . isEmpty ( ) ) {
QV4 : : CompiledData : : TypeReference & r = _typeReferences . add ( obj - > inheritedTypeNameIndex , obj - > location ) ;
r . needsCreation = true ;
}
2013-09-12 08:53:20 +00:00
for ( QmlProperty * prop = obj - > properties - > first ; prop ; prop = prop - > next ) {
2014-01-22 15:40:46 +00:00
if ( prop - > type > = QV4 : : CompiledData : : Property : : Custom ) {
// ### FIXME: We could report the more accurate location here by using prop->location, but the old
// compiler can't and the tests expect it to be the object location right now.
2014-01-27 15:55:49 +00:00
QV4 : : CompiledData : : TypeReference & r = _typeReferences . add ( prop - > customTypeNameIndex , obj - > location ) ;
r . needsCreation = true ;
2014-01-22 15:40:46 +00:00
}
2013-09-12 08:53:20 +00:00
}
2013-09-13 14:39:00 +00:00
for ( Binding * binding = obj - > bindings - > first ; binding ; binding = binding - > next ) {
2013-09-16 12:38:58 +00:00
if ( binding - > type = = QV4 : : CompiledData : : Binding : : Type_AttachedProperty )
2013-09-13 14:39:00 +00:00
_typeReferences . add ( binding - > propertyNameIndex , binding - > location ) ;
}
2013-09-12 08:53:20 +00:00
}
}
2013-08-06 14:41:28 +00:00
QQmlScript : : LocationSpan QQmlCodeGenerator : : location ( AST : : SourceLocation start , AST : : SourceLocation end )
{
QQmlScript : : LocationSpan rv ;
rv . start . line = start . startLine ;
rv . start . column = start . startColumn ;
rv . end . line = end . startLine ;
rv . end . column = end . startColumn + end . length - 1 ;
rv . range . offset = start . offset ;
rv . range . length = end . offset + end . length - start . offset ;
return rv ;
}
2013-09-30 07:41:35 +00:00
bool QQmlCodeGenerator : : isStatementNodeScript ( AST : : Statement * statement )
{
if ( AST : : ExpressionStatement * stmt = AST : : cast < AST : : ExpressionStatement * > ( statement ) ) {
AST : : ExpressionNode * expr = stmt - > expression ;
2013-11-01 11:38:32 +00:00
if ( AST : : cast < AST : : StringLiteral * > ( expr ) )
2013-09-30 07:41:35 +00:00
return false ;
else if ( expr - > kind = = AST : : Node : : Kind_TrueLiteral )
return false ;
else if ( expr - > kind = = AST : : Node : : Kind_FalseLiteral )
return false ;
2013-11-01 11:38:32 +00:00
else if ( AST : : cast < AST : : NumericLiteral * > ( expr ) )
2013-09-30 07:41:35 +00:00
return false ;
else {
if ( AST : : UnaryMinusExpression * unaryMinus = AST : : cast < AST : : UnaryMinusExpression * > ( expr ) ) {
2013-11-01 11:38:32 +00:00
if ( AST : : cast < AST : : NumericLiteral * > ( unaryMinus - > expression ) ) {
2013-09-30 07:41:35 +00:00
return false ;
}
}
}
}
return true ;
}
2013-10-08 09:44:57 +00:00
QV4 : : CompiledData : : QmlUnit * QmlUnitGenerator : : generate ( ParsedQML & output , const QVector < int > & runtimeFunctionIndices )
2013-08-06 14:41:28 +00:00
{
jsUnitGenerator = & output . jsGenerator ;
int unitSize = 0 ;
QV4 : : CompiledData : : Unit * jsUnit = jsUnitGenerator - > generateUnit ( & unitSize ) ;
const int importSize = sizeof ( QV4 : : CompiledData : : Import ) * output . imports . count ( ) ;
const int objectOffsetTableSize = output . objects . count ( ) * sizeof ( quint32 ) ;
QHash < QmlObject * , quint32 > objectOffsets ;
int objectsSize = 0 ;
foreach ( QmlObject * o , output . objects ) {
objectOffsets . insert ( o , unitSize + importSize + objectOffsetTableSize + objectsSize ) ;
objectsSize + = QV4 : : CompiledData : : Object : : calculateSizeExcludingSignals ( o - > functions - > count , o - > properties - > count , o - > qmlSignals - > count , o - > bindings - > count ) ;
int signalTableSize = 0 ;
for ( Signal * s = o - > qmlSignals - > first ; s ; s = s - > next )
signalTableSize + = QV4 : : CompiledData : : Signal : : calculateSize ( s - > parameters - > count ) ;
objectsSize + = signalTableSize ;
}
const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize ;
char * data = ( char * ) malloc ( totalSize ) ;
memcpy ( data , jsUnit , unitSize ) ;
free ( jsUnit ) ;
jsUnit = 0 ;
QV4 : : CompiledData : : QmlUnit * qmlUnit = reinterpret_cast < QV4 : : CompiledData : : QmlUnit * > ( data ) ;
qmlUnit - > header . flags | = QV4 : : CompiledData : : Unit : : IsQml ;
qmlUnit - > offsetToImports = unitSize ;
qmlUnit - > nImports = output . imports . count ( ) ;
qmlUnit - > offsetToObjects = unitSize + importSize ;
qmlUnit - > nObjects = output . objects . count ( ) ;
qmlUnit - > indexOfRootObject = output . indexOfRootObject ;
// write imports
char * importPtr = data + qmlUnit - > offsetToImports ;
foreach ( QV4 : : CompiledData : : Import * imp , output . imports ) {
QV4 : : CompiledData : : Import * importToWrite = reinterpret_cast < QV4 : : CompiledData : : Import * > ( importPtr ) ;
* importToWrite = * imp ;
importPtr + = sizeof ( QV4 : : CompiledData : : Import ) ;
}
// write objects
quint32 * objectTable = reinterpret_cast < quint32 * > ( data + qmlUnit - > offsetToObjects ) ;
char * objectPtr = data + qmlUnit - > offsetToObjects + objectOffsetTableSize ;
foreach ( QmlObject * o , output . objects ) {
* objectTable + + = objectOffsets . value ( o ) ;
QV4 : : CompiledData : : Object * objectToWrite = reinterpret_cast < QV4 : : CompiledData : : Object * > ( objectPtr ) ;
objectToWrite - > inheritedTypeNameIndex = o - > inheritedTypeNameIndex ;
objectToWrite - > indexOfDefaultProperty = o - > indexOfDefaultProperty ;
objectToWrite - > idIndex = o - > idIndex ;
2013-09-08 09:05:20 +00:00
objectToWrite - > location = o - > location ;
2013-09-17 15:27:07 +00:00
objectToWrite - > locationOfIdProperty = o - > locationOfIdProperty ;
2013-08-06 14:41:28 +00:00
quint32 nextOffset = sizeof ( QV4 : : CompiledData : : Object ) ;
objectToWrite - > nFunctions = o - > functions - > count ;
objectToWrite - > offsetToFunctions = nextOffset ;
nextOffset + = objectToWrite - > nFunctions * sizeof ( quint32 ) ;
objectToWrite - > nProperties = o - > properties - > count ;
objectToWrite - > offsetToProperties = nextOffset ;
nextOffset + = objectToWrite - > nProperties * sizeof ( QV4 : : CompiledData : : Property ) ;
objectToWrite - > nSignals = o - > qmlSignals - > count ;
objectToWrite - > offsetToSignals = nextOffset ;
nextOffset + = objectToWrite - > nSignals * sizeof ( quint32 ) ;
objectToWrite - > nBindings = o - > bindings - > count ;
objectToWrite - > offsetToBindings = nextOffset ;
nextOffset + = objectToWrite - > nBindings * sizeof ( QV4 : : CompiledData : : Binding ) ;
quint32 * functionsTable = reinterpret_cast < quint32 * > ( objectPtr + objectToWrite - > offsetToFunctions ) ;
for ( Function * f = o - > functions - > first ; f ; f = f - > next )
2013-10-08 09:44:57 +00:00
* functionsTable + + = runtimeFunctionIndices [ f - > index ] ;
2013-08-06 14:41:28 +00:00
char * propertiesPtr = objectPtr + objectToWrite - > offsetToProperties ;
for ( QmlProperty * p = o - > properties - > first ; p ; p = p - > next ) {
QV4 : : CompiledData : : Property * propertyToWrite = reinterpret_cast < QV4 : : CompiledData : : Property * > ( propertiesPtr ) ;
* propertyToWrite = * p ;
propertiesPtr + = sizeof ( QV4 : : CompiledData : : Property ) ;
}
char * bindingPtr = objectPtr + objectToWrite - > offsetToBindings ;
for ( Binding * b = o - > bindings - > first ; b ; b = b - > next ) {
QV4 : : CompiledData : : Binding * bindingToWrite = reinterpret_cast < QV4 : : CompiledData : : Binding * > ( bindingPtr ) ;
* bindingToWrite = * b ;
2013-10-08 09:44:57 +00:00
if ( b - > type = = QV4 : : CompiledData : : Binding : : Type_Script )
bindingToWrite - > value . compiledScriptIndex = runtimeFunctionIndices [ b - > value . compiledScriptIndex ] ;
2013-08-06 14:41:28 +00:00
bindingPtr + = sizeof ( QV4 : : CompiledData : : Binding ) ;
}
quint32 * signalOffsetTable = reinterpret_cast < quint32 * > ( objectPtr + objectToWrite - > offsetToSignals ) ;
quint32 signalTableSize = 0 ;
char * signalPtr = objectPtr + nextOffset ;
for ( Signal * s = o - > qmlSignals - > first ; s ; s = s - > next ) {
* signalOffsetTable + + = signalPtr - objectPtr ;
QV4 : : CompiledData : : Signal * signalToWrite = reinterpret_cast < QV4 : : CompiledData : : Signal * > ( signalPtr ) ;
signalToWrite - > nameIndex = s - > nameIndex ;
2013-09-06 12:14:20 +00:00
signalToWrite - > location = s - > location ;
2013-08-06 14:41:28 +00:00
signalToWrite - > nParameters = s - > parameters - > count ;
QV4 : : CompiledData : : Parameter * parameterToWrite = reinterpret_cast < QV4 : : CompiledData : : Parameter * > ( signalPtr + sizeof ( * signalToWrite ) ) ;
for ( SignalParameter * param = s - > parameters - > first ; param ; param = param - > next , + + parameterToWrite )
* parameterToWrite = * param ;
int size = QV4 : : CompiledData : : Signal : : calculateSize ( s - > parameters - > count ) ;
signalTableSize + = size ;
signalPtr + = size ;
}
objectPtr + = QV4 : : CompiledData : : Object : : calculateSizeExcludingSignals ( o - > functions - > count , o - > properties - > count , o - > qmlSignals - > count , o - > bindings - > count ) ;
objectPtr + = signalTableSize ;
}
2013-09-24 19:49:10 +00:00
// enable flag if we encountered pragma Singleton
foreach ( Pragma * p , output . pragmas ) {
if ( p - > type = = Pragma : : PragmaSingleton ) {
qmlUnit - > header . flags | = QV4 : : CompiledData : : Unit : : IsSingleton ;
break ;
}
}
2013-08-06 14:41:28 +00:00
return qmlUnit ;
}
int QmlUnitGenerator : : getStringId ( const QString & str ) const
{
return jsUnitGenerator - > getStringId ( str ) ;
}
2013-11-29 07:42:07 +00:00
JSCodeGen : : JSCodeGen ( const QString & fileName , const QString & sourceCode , V4IR : : Module * jsModule , Engine * jsEngine , AST : : UiProgram * qmlRoot , QQmlTypeNameCache * imports )
2013-10-24 08:38:29 +00:00
: QQmlJS : : Codegen ( /*strict mode*/ false )
, sourceCode ( sourceCode )
, jsEngine ( jsEngine )
, qmlRoot ( qmlRoot )
2013-10-24 12:51:02 +00:00
, imports ( imports )
2013-12-10 14:25:22 +00:00
, _disableAcceleratedLookups ( false )
2013-10-29 12:02:48 +00:00
, _contextObject ( 0 )
, _scopeObject ( 0 )
, _contextObjectTemp ( - 1 )
, _scopeObjectTemp ( - 1 )
, _importedScriptsTemp ( - 1 )
2013-11-02 17:48:18 +00:00
, _idArrayTemp ( - 1 )
2013-10-08 09:44:57 +00:00
{
2013-10-24 08:38:29 +00:00
_module = jsModule ;
_module - > setFileName ( fileName ) ;
2013-11-18 23:31:04 +00:00
_fileNameIsUrl = true ;
2013-10-08 09:44:57 +00:00
}
2013-10-24 12:51:02 +00:00
void JSCodeGen : : beginContextScope ( const JSCodeGen : : ObjectIdMapping & objectIds , QQmlPropertyCache * contextObject )
2013-08-06 14:41:28 +00:00
{
2013-10-24 12:51:02 +00:00
_idObjects = objectIds ;
_contextObject = contextObject ;
_scopeObject = 0 ;
}
2013-10-23 14:24:58 +00:00
2013-10-24 12:51:02 +00:00
void JSCodeGen : : beginObjectScope ( QQmlPropertyCache * scopeObject )
{
_scopeObject = scopeObject ;
}
2013-12-10 14:25:22 +00:00
QVector < int > JSCodeGen : : generateJSCodeForFunctionsAndBindings ( const QList < CompiledFunctionOrExpression > & functions )
2013-10-24 12:51:02 +00:00
{
2013-10-08 09:44:57 +00:00
QVector < int > runtimeFunctionIndices ( functions . size ( ) ) ;
2013-08-06 14:41:28 +00:00
2013-10-23 14:24:58 +00:00
ScanFunctions scan ( this , sourceCode , GlobalCode ) ;
scan . enterEnvironment ( 0 , QmlBinding ) ;
2013-11-01 11:38:32 +00:00
scan . enterQmlScope ( qmlRoot , QStringLiteral ( " context scope " ) ) ;
2013-12-10 14:25:22 +00:00
foreach ( const CompiledFunctionOrExpression & f , functions ) {
Q_ASSERT ( f . node ! = qmlRoot ) ;
AST : : FunctionDeclaration * function = AST : : cast < AST : : FunctionDeclaration * > ( f . node ) ;
2013-08-06 14:41:28 +00:00
2013-11-11 15:13:00 +00:00
if ( function )
scan . enterQmlFunction ( function ) ;
else
2013-12-10 14:25:22 +00:00
scan . enterEnvironment ( f . node , QmlBinding ) ;
2013-11-11 15:13:00 +00:00
2013-12-10 14:25:22 +00:00
scan ( function ? function - > body : f . node ) ;
2013-08-06 14:41:28 +00:00
scan . leaveEnvironment ( ) ;
2013-09-13 11:43:15 +00:00
}
2013-10-23 14:24:58 +00:00
scan . leaveEnvironment ( ) ;
scan . leaveEnvironment ( ) ;
2013-09-13 11:43:15 +00:00
_env = 0 ;
2013-11-01 11:38:32 +00:00
_function = _module - > functions . at ( defineFunction ( QStringLiteral ( " context scope " ) , qmlRoot , 0 , 0 ) ) ;
2013-09-13 11:43:15 +00:00
2013-10-08 09:44:57 +00:00
for ( int i = 0 ; i < functions . count ( ) ; + + i ) {
2013-12-10 14:25:22 +00:00
const CompiledFunctionOrExpression & qmlFunction = functions . at ( i ) ;
AST : : Node * node = qmlFunction . node ;
2013-10-08 09:44:57 +00:00
Q_ASSERT ( node ! = qmlRoot ) ;
2013-09-13 11:43:15 +00:00
AST : : FunctionDeclaration * function = AST : : cast < AST : : FunctionDeclaration * > ( node ) ;
2013-08-06 14:41:28 +00:00
QString name ;
if ( function )
name = function - > name . toString ( ) ;
2013-12-10 14:25:22 +00:00
else if ( ! qmlFunction . name . isEmpty ( ) )
name = qmlFunction . name ;
2013-08-06 14:41:28 +00:00
else
2013-12-10 14:25:22 +00:00
name = QStringLiteral ( " %qml-expression-entry " ) ;
2013-08-06 14:41:28 +00:00
2013-09-18 19:37:35 +00:00
AST : : SourceElements * body ;
if ( function )
body = function - > body ? function - > body - > elements : 0 ;
else {
// Synthesize source elements.
2013-10-08 09:44:57 +00:00
QQmlJS : : MemoryPool * pool = jsEngine - > pool ( ) ;
AST : : Statement * stmt = node - > statementCast ( ) ;
if ( ! stmt ) {
Q_ASSERT ( node - > expressionCast ( ) ) ;
AST : : ExpressionNode * expr = node - > expressionCast ( ) ;
stmt = new ( pool ) AST : : ExpressionStatement ( expr ) ;
}
AST : : SourceElement * element = new ( pool ) AST : : StatementSourceElement ( stmt ) ;
body = new ( pool ) AST : : SourceElements ( element ) ;
2013-09-18 19:37:35 +00:00
body = body - > finish ( ) ;
}
2013-12-10 14:25:22 +00:00
_disableAcceleratedLookups = qmlFunction . disableAcceleratedLookups ;
2013-10-18 12:02:56 +00:00
int idx = defineFunction ( name , node ,
function ? function - > formals : 0 ,
body ) ;
runtimeFunctionIndices [ i ] = idx ;
2013-08-06 14:41:28 +00:00
}
qDeleteAll ( _envMap ) ;
_envMap . clear ( ) ;
2013-10-08 09:44:57 +00:00
return runtimeFunctionIndices ;
2013-08-06 14:41:28 +00:00
}
2013-09-13 11:43:15 +00:00
2013-11-25 14:58:36 +00:00
QQmlPropertyData * JSCodeGen : : lookupQmlCompliantProperty ( QQmlPropertyCache * cache , const QString & name , bool * propertyExistsButForceNameLookup )
2013-10-24 12:51:02 +00:00
{
2013-10-25 12:23:39 +00:00
if ( propertyExistsButForceNameLookup )
* propertyExistsButForceNameLookup = false ;
2013-10-24 12:51:02 +00:00
QQmlPropertyData * pd = cache - > property ( name , /*object*/ 0 , /*context*/ 0 ) ;
// Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time
if ( pd & & pd - > isFunction ( ) ) {
2013-10-25 12:23:39 +00:00
if ( propertyExistsButForceNameLookup )
* propertyExistsButForceNameLookup = true ;
2013-10-24 12:51:02 +00:00
pd = 0 ;
}
if ( pd & & ! cache - > isAllowedInRevision ( pd ) )
pd = 0 ;
2013-11-25 14:58:36 +00:00
// Return a copy allocated from our memory pool. Property data pointers can change
// otherwise when the QQmlPropertyCache changes later in the QML type compilation process.
if ( pd ) {
QQmlPropertyData * copy = pd ;
pd = _function - > New < QQmlPropertyData > ( ) ;
* pd = * copy ;
}
2013-10-24 12:51:02 +00:00
return pd ;
}
2013-10-30 15:49:32 +00:00
static void initMetaObjectResolver ( V4IR : : MemberExpressionResolver * resolver , QQmlPropertyCache * metaObject ) ;
2013-10-25 12:23:39 +00:00
2013-11-02 21:46:25 +00:00
enum MetaObjectResolverFlags {
2013-11-17 17:07:06 +00:00
AllPropertiesAreFinal = 0x1 ,
LookupsIncludeEnums = 0x2 ,
LookupsExcludeProperties = 0x4 ,
ResolveTypeInformationOnly = 0x8
2013-11-02 21:46:25 +00:00
} ;
2013-11-14 23:06:18 +00:00
static void initMetaObjectResolver ( V4IR : : MemberExpressionResolver * resolver , QQmlPropertyCache * metaObject ) ;
static V4IR : : Type resolveQmlType ( QQmlEnginePrivate * qmlEngine , V4IR : : MemberExpressionResolver * resolver , V4IR : : Member * member )
{
V4IR : : Type result = V4IR : : VarType ;
QQmlType * type = static_cast < QQmlType * > ( resolver - > data ) ;
2014-01-02 07:48:55 +00:00
if ( member - > name - > constData ( ) - > isUpper ( ) ) {
bool ok = false ;
int value = type - > enumValue ( * member - > name , & ok ) ;
if ( ok ) {
member - > setEnumValue ( value ) ;
resolver - > clear ( ) ;
return V4IR : : SInt32Type ;
2013-11-14 23:06:18 +00:00
}
2014-01-02 07:48:55 +00:00
}
if ( type - > isCompositeSingleton ( ) ) {
QQmlTypeData * tdata = qmlEngine - > typeLoader . getType ( type - > singletonInstanceInfo ( ) - > url ) ;
Q_ASSERT ( tdata ) ;
Q_ASSERT ( tdata - > isComplete ( ) ) ;
initMetaObjectResolver ( resolver , qmlEngine - > propertyCacheForType ( tdata - > compiledData ( ) - > metaTypeId ) ) ;
resolver - > flags | = AllPropertiesAreFinal ;
return resolver - > resolveMember ( qmlEngine , resolver , member ) ;
} else if ( const QMetaObject * attachedMeta = type - > attachedPropertiesType ( ) ) {
QQmlPropertyCache * cache = qmlEngine - > cache ( attachedMeta ) ;
initMetaObjectResolver ( resolver , cache ) ;
member - > setAttachedPropertiesId ( type - > attachedPropertiesId ( ) ) ;
2013-11-14 23:06:18 +00:00
return resolver - > resolveMember ( qmlEngine , resolver , member ) ;
}
resolver - > clear ( ) ;
return result ;
}
static void initQmlTypeResolver ( V4IR : : MemberExpressionResolver * resolver , QQmlType * qmlType )
{
resolver - > resolveMember = & resolveQmlType ;
resolver - > data = qmlType ;
resolver - > extraData = 0 ;
resolver - > flags = 0 ;
}
static V4IR : : Type resolveImportNamespace ( QQmlEnginePrivate * , V4IR : : MemberExpressionResolver * resolver , V4IR : : Member * member )
{
V4IR : : Type result = V4IR : : VarType ;
QQmlTypeNameCache * typeNamespace = static_cast < QQmlTypeNameCache * > ( resolver - > extraData ) ;
void * importNamespace = resolver - > data ;
QQmlTypeNameCache : : Result r = typeNamespace - > query ( * member - > name , importNamespace ) ;
if ( r . isValid ( ) ) {
member - > freeOfSideEffects = true ;
if ( r . scriptIndex ! = - 1 ) {
// TODO: remember the index and replace with subscript later.
result = V4IR : : VarType ;
} else if ( r . type ) {
// TODO: Propagate singleton information, so that it is loaded
// through the singleton getter in the run-time. Until then we
// can't accelerate access :(
if ( ! r . type - > isSingleton ( ) ) {
initQmlTypeResolver ( resolver , r . type ) ;
return V4IR : : QObjectType ;
}
} else {
Q_ASSERT ( false ) ; // How can this happen?
}
}
resolver - > clear ( ) ;
return result ;
}
static void initImportNamespaceResolver ( V4IR : : MemberExpressionResolver * resolver , QQmlTypeNameCache * imports , const void * importNamespace )
{
resolver - > resolveMember = & resolveImportNamespace ;
resolver - > data = const_cast < void * > ( importNamespace ) ;
resolver - > extraData = imports ;
resolver - > flags = 0 ;
}
2013-10-30 15:49:32 +00:00
static V4IR : : Type resolveMetaObjectProperty ( QQmlEnginePrivate * qmlEngine , V4IR : : MemberExpressionResolver * resolver , V4IR : : Member * member )
{
V4IR : : Type result = V4IR : : VarType ;
2013-11-02 21:46:25 +00:00
QQmlPropertyCache * metaObject = static_cast < QQmlPropertyCache * > ( resolver - > data ) ;
if ( member - > name - > constData ( ) - > isUpper ( ) & & ( resolver - > flags & LookupsIncludeEnums ) ) {
const QMetaObject * mo = metaObject - > createMetaObject ( ) ;
QByteArray enumName = member - > name - > toUtf8 ( ) ;
for ( int ii = mo - > enumeratorCount ( ) - 1 ; ii > = 0 ; - - ii ) {
QMetaEnum metaEnum = mo - > enumerator ( ii ) ;
bool ok ;
int value = metaEnum . keyToValue ( enumName . constData ( ) , & ok ) ;
if ( ok ) {
2013-12-05 13:53:58 +00:00
member - > setEnumValue ( value ) ;
2013-11-02 21:46:25 +00:00
resolver - > clear ( ) ;
return V4IR : : SInt32Type ;
}
}
}
2013-10-30 15:49:32 +00:00
2013-11-02 21:46:25 +00:00
if ( qmlEngine & & ! ( resolver - > flags & LookupsExcludeProperties ) ) {
QQmlPropertyData * property = member - > property ;
2013-10-30 15:49:32 +00:00
if ( ! property & & metaObject ) {
2013-11-02 21:46:25 +00:00
if ( QQmlPropertyData * candidate = metaObject - > property ( * member - > name , /*object*/ 0 , /*context*/ 0 ) ) {
const bool isFinalProperty = ( candidate - > isFinal ( ) | | ( resolver - > flags & AllPropertiesAreFinal ) )
& & ! candidate - > isFunction ( ) ;
2013-11-17 04:10:23 +00:00
if ( lookupHints ( )
& & ! ( resolver - > flags & AllPropertiesAreFinal )
& & ! candidate - > isFinal ( )
& & ! candidate - > isFunction ( )
& & candidate - > isDirect ( ) ) {
qWarning ( ) < < " Hint: Access to property " < < * member - > name < < " of " < < metaObject - > className ( ) < < " could be accelerated if it was marked as FINAL " ;
}
2013-11-02 21:46:25 +00:00
if ( isFinalProperty & & metaObject - > isAllowedInRevision ( candidate ) ) {
property = candidate ;
2013-11-17 17:07:06 +00:00
member - > inhibitTypeConversionOnWrite = true ;
if ( ! ( resolver - > flags & ResolveTypeInformationOnly ) )
member - > property = candidate ; // Cache for next iteration and isel needs it.
2013-11-02 21:46:25 +00:00
}
2013-10-25 12:23:39 +00:00
}
}
2013-10-30 15:49:32 +00:00
if ( property ) {
// Enums cannot be mapped to IR types, they need to go through the run-time handling
// of accepting strings that will then be converted to the right values.
if ( property - > isEnum ( ) )
return V4IR : : VarType ;
switch ( property - > propType ) {
case QMetaType : : Bool : result = V4IR : : BoolType ; break ;
case QMetaType : : Int : result = V4IR : : SInt32Type ; break ;
case QMetaType : : Double : result = V4IR : : DoubleType ; break ;
case QMetaType : : QString : result = V4IR : : StringType ; break ;
default :
if ( property - > isQObject ( ) ) {
if ( QQmlPropertyCache * cache = qmlEngine - > propertyCacheForType ( property - > propType ) ) {
initMetaObjectResolver ( resolver , cache ) ;
return V4IR : : QObjectType ;
}
2013-11-17 17:07:06 +00:00
} else if ( QQmlValueType * valueType = QQmlValueTypeFactory : : valueType ( property - > propType ) ) {
if ( QQmlPropertyCache * cache = qmlEngine - > cache ( valueType - > metaObject ( ) ) ) {
initMetaObjectResolver ( resolver , cache ) ;
resolver - > flags | = ResolveTypeInformationOnly ;
return V4IR : : QObjectType ;
}
2013-10-30 15:49:32 +00:00
}
break ;
2013-10-25 12:23:39 +00:00
}
}
}
2013-10-30 15:49:32 +00:00
resolver - > clear ( ) ;
return result ;
}
static void initMetaObjectResolver ( V4IR : : MemberExpressionResolver * resolver , QQmlPropertyCache * metaObject )
{
resolver - > resolveMember = & resolveMetaObjectProperty ;
resolver - > data = metaObject ;
2013-11-02 21:46:25 +00:00
resolver - > flags = 0 ;
2013-11-14 23:06:18 +00:00
resolver - > isQObjectResolver = true ;
2013-10-25 12:23:39 +00:00
}
2013-10-29 12:02:48 +00:00
void JSCodeGen : : beginFunctionBodyHook ( )
{
_contextObjectTemp = _block - > newTemp ( ) ;
_scopeObjectTemp = _block - > newTemp ( ) ;
_importedScriptsTemp = _block - > newTemp ( ) ;
2013-11-02 17:48:18 +00:00
_idArrayTemp = _block - > newTemp ( ) ;
2013-10-29 12:02:48 +00:00
V4IR : : Temp * temp = _block - > TEMP ( _contextObjectTemp ) ;
initMetaObjectResolver ( & temp - > memberResolver , _contextObject ) ;
move ( temp , _block - > NAME ( V4IR : : Name : : builtin_qml_context_object , 0 , 0 ) ) ;
temp = _block - > TEMP ( _scopeObjectTemp ) ;
initMetaObjectResolver ( & temp - > memberResolver , _scopeObject ) ;
move ( temp , _block - > NAME ( V4IR : : Name : : builtin_qml_scope_object , 0 , 0 ) ) ;
move ( _block - > TEMP ( _importedScriptsTemp ) , _block - > NAME ( V4IR : : Name : : builtin_qml_imported_scripts_object , 0 , 0 ) ) ;
2013-11-02 17:48:18 +00:00
move ( _block - > TEMP ( _idArrayTemp ) , _block - > NAME ( V4IR : : Name : : builtin_qml_id_array , 0 , 0 ) ) ;
2013-10-29 12:02:48 +00:00
}
2013-10-24 12:51:02 +00:00
V4IR : : Expr * JSCodeGen : : fallbackNameLookup ( const QString & name , int line , int col )
2013-09-13 11:43:15 +00:00
{
2013-12-10 14:25:22 +00:00
if ( _disableAcceleratedLookups )
return 0 ;
2013-10-29 12:02:48 +00:00
Q_UNUSED ( line )
Q_UNUSED ( col )
2013-10-23 14:24:58 +00:00
// Implement QML lookup semantics in the current file context.
2013-10-24 12:51:02 +00:00
//
// Note: We do not check if properties of the qml scope object or context object
// are final. That's because QML tries to get as close as possible to lexical scoping,
// which means in terms of properties that only those visible at compile time are chosen.
// I.e. access to a "foo" property declared within the same QML component as "property int foo"
// will always access that instance and as integer. If a sub-type implements its own property string foo,
// then that one is not chosen for accesses from within this file, because it wasn't visible at compile
// time. This corresponds to the logic in QQmlPropertyCache::findProperty to find the property associated
// with the correct QML context.
2013-09-13 11:43:15 +00:00
2013-10-23 14:24:58 +00:00
// Look for IDs first.
2013-10-24 12:51:02 +00:00
foreach ( const IdMapping & mapping , _idObjects )
2013-10-23 14:24:58 +00:00
if ( name = = mapping . name ) {
2013-11-02 19:35:33 +00:00
_function - > idObjectDependencies . insert ( mapping . idIndex ) ;
2013-11-02 17:48:18 +00:00
V4IR : : Expr * s = subscript ( _block - > TEMP ( _idArrayTemp ) , _block - > CONST ( V4IR : : SInt32Type , mapping . idIndex ) ) ;
V4IR : : Temp * result = _block - > TEMP ( _block - > newTemp ( ) ) ;
_block - > MOVE ( result , s ) ;
result = _block - > TEMP ( result - > index ) ;
2014-01-02 11:17:31 +00:00
if ( mapping . type ) {
initMetaObjectResolver ( & result - > memberResolver , mapping . type ) ;
result - > memberResolver . flags | = AllPropertiesAreFinal ;
}
2013-11-02 17:48:18 +00:00
result - > isReadOnly = true ; // don't allow use as lvalue
return result ;
2013-10-23 14:24:58 +00:00
}
2013-11-02 19:35:33 +00:00
{
2013-10-24 12:51:02 +00:00
QQmlTypeNameCache : : Result r = imports - > query ( name ) ;
2013-10-28 16:02:54 +00:00
if ( r . isValid ( ) ) {
2013-11-02 21:46:25 +00:00
if ( r . scriptIndex ! = - 1 ) {
return subscript ( _block - > TEMP ( _importedScriptsTemp ) , _block - > CONST ( V4IR : : SInt32Type , r . scriptIndex ) ) ;
} else if ( r . type ) {
V4IR : : Name * typeName = _block - > NAME ( name , line , col ) ;
2013-11-14 23:06:18 +00:00
// Make sure the run-time loads this through the more efficient singleton getter.
2014-01-02 07:48:55 +00:00
typeName - > qmlSingleton = r . type - > isCompositeSingleton ( ) ;
2013-11-14 23:06:18 +00:00
typeName - > freeOfSideEffects = true ;
V4IR : : Temp * result = _block - > TEMP ( _block - > newTemp ( ) ) ;
2013-11-02 21:46:25 +00:00
_block - > MOVE ( result , typeName ) ;
2014-01-02 07:48:55 +00:00
result = _block - > TEMP ( result - > index ) ;
initQmlTypeResolver ( & result - > memberResolver , r . type ) ;
return result ;
2013-11-02 21:46:25 +00:00
} else {
2013-11-14 23:06:18 +00:00
Q_ASSERT ( r . importNamespace ) ;
V4IR : : Name * namespaceName = _block - > NAME ( name , line , col ) ;
namespaceName - > freeOfSideEffects = true ;
V4IR : : Temp * result = _block - > TEMP ( _block - > newTemp ( ) ) ;
initImportNamespaceResolver ( & result - > memberResolver , imports , r . importNamespace ) ;
_block - > MOVE ( result , namespaceName ) ;
return _block - > TEMP ( result - > index ) ;
2013-11-02 21:46:25 +00:00
}
2013-10-28 16:02:54 +00:00
}
2013-10-24 12:51:02 +00:00
}
2013-11-02 19:35:33 +00:00
if ( _scopeObject ) {
2013-10-24 12:51:02 +00:00
bool propertyExistsButForceNameLookup = false ;
QQmlPropertyData * pd = lookupQmlCompliantProperty ( _scopeObject , name , & propertyExistsButForceNameLookup ) ;
if ( propertyExistsButForceNameLookup )
return 0 ;
if ( pd ) {
2013-10-29 12:02:48 +00:00
V4IR : : Temp * base = _block - > TEMP ( _scopeObjectTemp ) ;
2013-10-30 15:49:32 +00:00
initMetaObjectResolver ( & base - > memberResolver , _scopeObject ) ;
2013-12-05 13:53:58 +00:00
return _block - > MEMBER ( base , _function - > newString ( name ) , pd , V4IR : : Member : : MemberOfQmlScopeObject ) ;
2013-10-24 12:51:02 +00:00
}
}
2013-11-02 19:35:33 +00:00
if ( _contextObject ) {
2013-10-24 12:51:02 +00:00
bool propertyExistsButForceNameLookup = false ;
QQmlPropertyData * pd = lookupQmlCompliantProperty ( _contextObject , name , & propertyExistsButForceNameLookup ) ;
if ( propertyExistsButForceNameLookup )
return 0 ;
if ( pd ) {
2013-10-29 12:02:48 +00:00
V4IR : : Temp * base = _block - > TEMP ( _contextObjectTemp ) ;
2013-10-30 15:49:32 +00:00
initMetaObjectResolver ( & base - > memberResolver , _contextObject ) ;
2013-12-05 13:53:58 +00:00
return _block - > MEMBER ( base , _function - > newString ( name ) , pd , V4IR : : Member : : MemberOfQmlContextObject ) ;
2013-10-24 12:51:02 +00:00
}
}
2013-10-23 14:24:58 +00:00
// fall back to name lookup at run-time.
return 0 ;
2013-09-13 11:43:15 +00:00
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
SignalHandlerConverter : : SignalHandlerConverter ( QQmlEnginePrivate * enginePrivate , ParsedQML * parsedQML ,
QQmlCompiledData * unit )
: enginePrivate ( enginePrivate )
, parsedQML ( parsedQML )
2013-09-13 13:03:51 +00:00
, unit ( unit )
{
}
bool SignalHandlerConverter : : convertSignalHandlerExpressionsToFunctionDeclarations ( )
{
2013-12-11 12:44:56 +00:00
for ( int objectIndex = 0 ; objectIndex < parsedQML - > objects . count ( ) ; + + objectIndex ) {
QmlObject * const obj = parsedQML - > objects . at ( objectIndex ) ;
2013-09-13 13:03:51 +00:00
QString elementName = stringAt ( obj - > inheritedTypeNameIndex ) ;
if ( elementName . isEmpty ( ) )
continue ;
2014-01-17 11:16:07 +00:00
QQmlCompiledData : : TypeReference * tr = unit - > resolvedTypes . value ( obj - > inheritedTypeNameIndex ) ;
2014-01-15 16:29:04 +00:00
QQmlCustomParser * customParser = ( tr & & tr - > type ) ? tr - > type - > customParser ( ) : 0 ;
if ( customParser & & ! ( customParser - > flags ( ) & QQmlCustomParser : : AcceptsSignalHandlers ) )
2013-10-01 07:04:50 +00:00
continue ;
2013-12-11 12:44:56 +00:00
QQmlPropertyCache * cache = unit - > propertyCaches . value ( objectIndex ) ;
2014-01-19 13:40:25 +00:00
if ( ! cache )
continue ;
2013-09-13 14:39:00 +00:00
if ( ! convertSignalHandlerExpressionsToFunctionDeclarations ( obj , elementName , cache ) )
return false ;
}
return true ;
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
bool SignalHandlerConverter : : convertSignalHandlerExpressionsToFunctionDeclarations ( QmlObject * obj , const QString & typeName , QQmlPropertyCache * propertyCache )
{
// map from signal name defined in qml itself to list of parameters
QHash < QString , QStringList > customSignals ;
for ( Binding * binding = obj - > bindings - > first ; binding ; binding = binding - > next ) {
QString propertyName = stringAt ( binding - > propertyNameIndex ) ;
// Attached property?
2013-09-16 12:38:58 +00:00
if ( binding - > type = = QV4 : : CompiledData : : Binding : : Type_AttachedProperty ) {
2013-09-13 14:39:00 +00:00
QmlObject * attachedObj = parsedQML - > objects [ binding - > value . objectIndex ] ;
2014-01-17 11:16:07 +00:00
QQmlCompiledData : : TypeReference * typeRef = unit - > resolvedTypes . value ( binding - > propertyNameIndex ) ;
QQmlType * type = typeRef ? typeRef - > type : 0 ;
2013-09-18 19:41:24 +00:00
const QMetaObject * attachedType = type ? type - > attachedPropertiesType ( ) : 0 ;
if ( ! attachedType )
COMPILE_EXCEPTION ( binding - > location , tr ( " Non-existent attached object " ) ) ;
QQmlPropertyCache * cache = enginePrivate - > cache ( attachedType ) ;
2013-09-13 14:39:00 +00:00
if ( ! convertSignalHandlerExpressionsToFunctionDeclarations ( attachedObj , propertyName , cache ) )
return false ;
continue ;
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
if ( ! QQmlCodeGenerator : : isSignalPropertyName ( propertyName ) )
continue ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
PropertyResolver resolver ( propertyCache ) ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
Q_ASSERT ( propertyName . startsWith ( QStringLiteral ( " on " ) ) ) ;
propertyName . remove ( 0 , 2 ) ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
// 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 < propertyName . size ( ) ; + + firstAlphaIndex ) {
if ( propertyName . at ( firstAlphaIndex ) . isUpper ( ) ) {
propertyName [ firstAlphaIndex ] = propertyName . at ( firstAlphaIndex ) . toLower ( ) ;
break ;
2013-09-13 13:03:51 +00:00
}
2013-09-13 14:39:00 +00:00
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
QList < QString > parameters ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
bool notInRevision = false ;
QQmlPropertyData * signal = resolver . signal ( propertyName , & notInRevision ) ;
if ( signal ) {
int sigIndex = propertyCache - > methodIndexToSignalIndex ( signal - > coreIndex ) ;
2014-01-30 15:41:22 +00:00
sigIndex = propertyCache - > originalClone ( sigIndex ) ;
2013-09-13 14:39:00 +00:00
foreach ( const QByteArray & param , propertyCache - > signalParameterNames ( sigIndex ) )
parameters < < QString : : fromUtf8 ( param ) ;
} else {
if ( notInRevision ) {
// Try assinging it as a property later
if ( resolver . property ( propertyName , /*notInRevision ptr*/ 0 ) )
continue ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
const QString & originalPropertyName = stringAt ( binding - > propertyNameIndex ) ;
2013-09-13 13:03:51 +00:00
2014-01-17 11:16:07 +00:00
QQmlCompiledData : : TypeReference * typeRef = unit - > resolvedTypes . value ( obj - > inheritedTypeNameIndex ) ;
const QQmlType * type = typeRef ? typeRef - > type : 0 ;
2013-09-13 14:39:00 +00:00
if ( type ) {
COMPILE_EXCEPTION ( binding - > location , tr ( " \" %1.%2 \" is not available in %3 %4.%5. " ) . arg ( typeName ) . arg ( originalPropertyName ) . arg ( type - > module ( ) ) . arg ( type - > majorVersion ( ) ) . arg ( type - > minorVersion ( ) ) ) ;
} else {
COMPILE_EXCEPTION ( binding - > location , tr ( " \" %1.%2 \" is not available due to component versioning. " ) . arg ( typeName ) . arg ( originalPropertyName ) ) ;
2013-09-13 13:03:51 +00:00
}
2013-09-13 14:39:00 +00:00
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
// Try to look up the signal parameter names in the object itself
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
// build cache if necessary
if ( customSignals . isEmpty ( ) ) {
for ( Signal * signal = obj - > qmlSignals - > first ; signal ; signal = signal - > next ) {
const QString & signalName = stringAt ( signal - > nameIndex ) ;
customSignals . insert ( signalName , signal - > parameterStringList ( parsedQML - > jsGenerator . strings ) ) ;
2013-09-13 13:03:51 +00:00
}
2013-09-20 12:32:06 +00:00
for ( QmlProperty * property = obj - > properties - > first ; property ; property = property - > next ) {
const QString propName = stringAt ( property - > nameIndex ) ;
customSignals . insert ( propName , QStringList ( ) ) ;
}
2013-09-13 14:39:00 +00:00
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
QHash < QString , QStringList > : : ConstIterator entry = customSignals . find ( propertyName ) ;
if ( entry = = customSignals . constEnd ( ) & & propertyName . endsWith ( QStringLiteral ( " Changed " ) ) ) {
2013-11-01 11:38:32 +00:00
QString alternateName = propertyName . mid ( 0 , propertyName . length ( ) - static_cast < int > ( strlen ( " Changed " ) ) ) ;
2013-09-13 14:39:00 +00:00
entry = customSignals . find ( alternateName ) ;
2013-09-13 13:03:51 +00:00
}
2013-09-13 14:39:00 +00:00
if ( entry = = customSignals . constEnd ( ) ) {
// Can't find even a custom signal, then just don't do anything and try
// keeping the binding as a regular property assignment.
continue ;
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
parameters = entry . value ( ) ;
}
2013-09-13 13:03:51 +00:00
2014-01-30 12:31:14 +00:00
binding - > propertyNameIndex = parsedQML - > jsGenerator . registerString ( propertyName ) ;
// Binding object to signal means connect the signal to the object's default method.
if ( binding - > type = = QV4 : : CompiledData : : Binding : : Type_Object ) {
binding - > flags | = QV4 : : CompiledData : : Binding : : IsSignalHandlerObject ;
continue ;
}
2014-01-09 15:25:03 +00:00
if ( binding - > type ! = QV4 : : CompiledData : : Binding : : Type_Script ) {
COMPILE_EXCEPTION ( binding - > location , tr ( " Incorrectly specified signal assignment " ) ) ;
}
2013-09-13 14:39:00 +00:00
QQmlJS : : Engine & jsEngine = parsedQML - > jsParserEngine ;
QQmlJS : : MemoryPool * pool = jsEngine . pool ( ) ;
AST : : FormalParameterList * paramList = 0 ;
foreach ( const QString & param , parameters ) {
QStringRef paramNameRef = jsEngine . newStringRef ( param ) ;
2013-09-13 13:03:51 +00:00
if ( paramList )
2013-09-13 14:39:00 +00:00
paramList = new ( pool ) AST : : FormalParameterList ( paramList , paramNameRef ) ;
else
paramList = new ( pool ) AST : : FormalParameterList ( paramNameRef ) ;
}
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
if ( paramList )
paramList = paramList - > finish ( ) ;
2013-09-13 13:03:51 +00:00
2013-12-10 14:25:22 +00:00
AST : : Statement * statement = static_cast < AST : : Statement * > ( parsedQML - > functions [ binding - > value . compiledScriptIndex ] . node ) ;
2013-09-13 14:39:00 +00:00
AST : : SourceElement * sourceElement = new ( pool ) AST : : StatementSourceElement ( statement ) ;
AST : : SourceElements * elements = new ( pool ) AST : : SourceElements ( sourceElement ) ;
elements = elements - > finish ( ) ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
AST : : FunctionBody * body = new ( pool ) AST : : FunctionBody ( elements ) ;
2013-09-13 13:03:51 +00:00
2013-09-13 14:39:00 +00:00
AST : : FunctionDeclaration * functionDeclaration = new ( pool ) AST : : FunctionDeclaration ( jsEngine . newStringRef ( propertyName ) , paramList , body ) ;
parsedQML - > functions [ binding - > value . compiledScriptIndex ] = functionDeclaration ;
binding - > flags | = QV4 : : CompiledData : : Binding : : IsSignalHandlerExpression ;
2013-09-13 13:03:51 +00:00
}
return true ;
}
void SignalHandlerConverter : : recordError ( const QV4 : : CompiledData : : Location & location , const QString & description )
{
QQmlError error ;
error . setUrl ( unit - > url ) ;
error . setLine ( location . line ) ;
error . setColumn ( location . column ) ;
error . setDescription ( description ) ;
errors < < error ;
}
2014-01-31 08:26:16 +00:00
QQmlPropertyData * PropertyResolver : : property ( const QString & name , bool * notInRevision , QObject * object , QQmlContextData * context )
2013-09-13 13:03:51 +00:00
{
if ( notInRevision ) * notInRevision = false ;
2014-01-31 08:26:16 +00:00
QQmlPropertyData * d = cache - > property ( name , object , context ) ;
2013-09-13 13:03:51 +00:00
// 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 ;
}
}
2014-01-31 08:26:16 +00:00
QQmlPropertyData * PropertyResolver : : signal ( const QString & name , bool * notInRevision , QObject * object , QQmlContextData * context )
2013-09-13 13:03:51 +00:00
{
if ( notInRevision ) * notInRevision = false ;
2014-01-31 08:26:16 +00:00
QQmlPropertyData * d = cache - > property ( name , object , context ) ;
2013-09-13 13:03:51 +00:00
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 & & d - > isSignal ( ) ) {
return d ;
}
if ( name . endsWith ( QStringLiteral ( " Changed " ) ) ) {
2013-11-01 11:38:32 +00:00
QString propName = name . mid ( 0 , name . length ( ) - static_cast < int > ( strlen ( " Changed " ) ) ) ;
2013-09-13 13:03:51 +00:00
2014-01-31 08:26:16 +00:00
d = property ( propName , notInRevision , object , context ) ;
2013-09-13 13:03:51 +00:00
if ( d )
return cache - > signal ( d - > notifyIndex ) ;
}
return 0 ;
}