2013-08-06 14:41:28 +00:00
/****************************************************************************
* *
2016-01-19 09:38:36 +00:00
* * Copyright ( C ) 2016 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
2013-08-06 14:41:28 +00:00
* *
* * This file is part of the tools applications of the Qt Toolkit .
* *
2016-01-19 09:38:36 +00:00
* * $ QT_BEGIN_LICENSE : LGPL $
2013-08-06 14:41:28 +00:00
* * 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
2015-01-28 11:55:39 +00:00
* * a written agreement between you and The Qt Company . For licensing terms
2016-01-19 09:38:36 +00:00
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
2013-08-06 14:41:28 +00:00
* *
* * GNU Lesser General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU Lesser
2016-01-19 09:38:36 +00:00
* * General Public License version 3 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL3 included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 3 requirements
* * will be met : https : //www.gnu.org/licenses/lgpl-3.0.html.
2013-08-06 14:41:28 +00:00
* *
2016-01-19 09:38:36 +00:00
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 2.0 or ( at your option ) the GNU General
* * Public license version 3 or any later version approved by the KDE Free
* * Qt Foundation . The licenses are as published by the Free Software
* * Foundation and appearing in the file LICENSE . GPL2 and LICENSE . GPL3
* * included in the packaging of this file . Please review the following
* * information to ensure the GNU General Public License requirements will
* * be met : https : //www.gnu.org/licenses/gpl-2.0.html and
* * https : //www.gnu.org/licenses/gpl-3.0.html.
2013-08-06 14:41:28 +00:00
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-03-17 20:26:04 +00:00
# include "qqmlirbuilder_p.h"
2013-08-06 14:41:28 +00:00
2015-02-14 21:46:41 +00:00
# include <private/qv4value_p.h>
2013-08-06 14:41:28 +00:00
# include <private/qv4compileddata_p.h>
# include <private/qqmljsparser_p.h>
# include <private/qqmljslexer_p.h>
# include <QCoreApplication>
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
# include <private/qqmlglobal_p.h>
# include <private/qqmltypeloader_p.h>
# include <private/qqmlengine_p.h>
# include <private/qqmlcompiler_p.h>
# endif
2013-10-29 10:59:54 +00:00
# ifdef CONST
# undef CONST
# endif
2013-08-06 14:41:28 +00:00
QT_USE_NAMESPACE
2014-02-03 12:30:06 +00:00
static const quint32 emptyStringIndex = 0 ;
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
2013-11-17 04:10:23 +00:00
DEFINE_BOOL_CONFIG_OPTION ( lookupHints , QML_LOOKUP_HINTS ) ;
2014-03-12 15:55:06 +00:00
# endif // V4_BOOTSTRAP
2013-11-17 04:10:23 +00:00
2014-03-17 16:11:20 +00:00
using namespace QmlIR ;
2013-08-06 14:41:28 +00:00
2013-09-11 17:28:13 +00:00
# define COMPILE_EXCEPTION(location, desc) \
{ \
recordError ( location , desc ) ; \
return false ; \
}
2014-03-17 16:11:20 +00:00
void Object : : init ( QQmlJS : : MemoryPool * pool , int typeNameIndex , int id , const QQmlJS : : AST : : SourceLocation & loc )
2014-01-07 14:35:20 +00:00
{
inheritedTypeNameIndex = typeNameIndex ;
location . line = loc . startLine ;
location . column = loc . startColumn ;
idIndex = id ;
indexOfDefaultProperty = - 1 ;
2014-03-17 16:11:20 +00:00
properties = pool - > New < PoolList < Property > > ( ) ;
2014-01-07 14:35:20 +00:00
qmlSignals = pool - > New < PoolList < Signal > > ( ) ;
bindings = pool - > New < PoolList < Binding > > ( ) ;
functions = pool - > New < PoolList < Function > > ( ) ;
2014-02-25 15:36:41 +00:00
functionsAndExpressions = pool - > New < PoolList < CompiledFunctionOrExpression > > ( ) ;
runtimeFunctionIndices = 0 ;
2014-01-28 09:41:58 +00:00
declarationsOverride = 0 ;
2014-01-07 14:35:20 +00:00
}
2014-03-17 16:11:20 +00:00
QString Object : : sanityCheckFunctionNames ( const QSet < QString > & illegalNames , QQmlJS : : AST : : SourceLocation * errorLocation )
2014-01-31 13:00:53 +00:00
{
QSet < int > functionNames ;
for ( Function * f = functions - > first ; f ; f = f - > next ) {
2014-02-25 15:36:41 +00:00
QQmlJS : : AST : : FunctionDeclaration * function = f - > functionDeclaration ;
2014-01-31 13:00:53 +00:00
Q_ASSERT ( function ) ;
* errorLocation = function - > identifierToken ;
if ( functionNames . contains ( f - > nameIndex ) )
return tr ( " Duplicate method name " ) ;
functionNames . insert ( f - > nameIndex ) ;
2014-02-25 13:22:36 +00:00
2014-03-17 16:11:20 +00:00
for ( QmlIR : : Signal * s = qmlSignals - > first ; s ; s = s - > next ) {
2014-02-25 13:22:36 +00:00
if ( s - > nameIndex = = f - > nameIndex )
return tr ( " Duplicate method name " ) ;
}
2014-01-31 13:00:53 +00:00
2014-02-25 15:36:41 +00:00
const QString name = function - > name . toString ( ) ;
2014-01-31 13:00:53 +00:00
if ( name . at ( 0 ) . isUpper ( ) )
return tr ( " Method names cannot begin with an upper case letter " ) ;
if ( illegalNames . contains ( name ) )
return tr ( " Illegal method name " ) ;
}
return QString ( ) ; // no error
}
2014-03-17 16:11:20 +00:00
QString Object : : appendSignal ( Signal * signal )
2014-01-31 13:00:53 +00:00
{
2014-03-17 16:11:20 +00:00
Object * target = declarationsOverride ;
2014-01-31 13:00:53 +00:00
if ( ! target )
target = this ;
2014-02-25 13:22:36 +00:00
for ( Signal * s = qmlSignals - > first ; s ; s = s - > next ) {
if ( s - > nameIndex = = signal - > nameIndex )
return tr ( " Duplicate signal name " ) ;
}
2014-01-31 13:00:53 +00:00
target - > qmlSignals - > append ( signal ) ;
return QString ( ) ; // no error
}
2014-03-17 16:11:20 +00:00
QString Object : : appendProperty ( Property * prop , const QString & propertyName , bool isDefaultProperty , const QQmlJS : : AST : : SourceLocation & defaultToken , QQmlJS : : AST : : SourceLocation * errorLocation )
2014-01-31 13:00:53 +00:00
{
2014-03-17 16:11:20 +00:00
Object * target = declarationsOverride ;
2014-01-31 13:00:53 +00:00
if ( ! target )
target = this ;
2014-01-31 14:09:46 +00:00
2014-03-17 16:11:20 +00:00
for ( Property * p = target - > properties - > first ; p ; p = p - > next )
2014-02-25 13:22:36 +00:00
if ( p - > nameIndex = = prop - > nameIndex )
return tr ( " Duplicate property name " ) ;
2014-01-31 14:09:46 +00:00
if ( propertyName . constData ( ) - > isUpper ( ) )
return tr ( " Property names cannot begin with an upper case letter " ) ;
2014-01-31 13:00:53 +00:00
const int index = target - > properties - > append ( prop ) ;
if ( isDefaultProperty ) {
2014-01-31 14:09:46 +00:00
if ( target - > indexOfDefaultProperty ! = - 1 ) {
* errorLocation = defaultToken ;
return tr ( " Duplicate default property " ) ;
}
2014-01-31 13:00:53 +00:00
target - > indexOfDefaultProperty = index ;
}
2014-01-31 14:09:46 +00:00
return QString ( ) ; // no error
2014-01-31 13:00:53 +00:00
}
2014-03-17 16:11:20 +00:00
void Object : : appendFunction ( QmlIR : : Function * f )
2014-01-31 13:00:53 +00:00
{
2014-03-17 16:11:20 +00:00
Object * target = declarationsOverride ;
2014-01-31 13:00:53 +00:00
if ( ! target )
target = this ;
target - > functions - > append ( f ) ;
}
2014-03-17 16:11:20 +00:00
QString Object : : appendBinding ( Binding * b , bool isListBinding )
2014-01-31 14:09:46 +00:00
{
2014-02-03 12:30:06 +00:00
const bool bindingToDefaultProperty = ( b - > propertyNameIndex = = 0 ) ;
if ( ! isListBinding & & ! bindingToDefaultProperty
2014-01-31 14:09:46 +00:00
& & b - > type ! = QV4 : : CompiledData : : Binding : : Type_GroupProperty
& & b - > type ! = QV4 : : CompiledData : : Binding : : Type_AttachedProperty
& & ! ( b - > flags & QV4 : : CompiledData : : Binding : : IsOnAssignment ) ) {
2014-02-20 12:48:24 +00:00
Binding * existing = findBinding ( b - > propertyNameIndex ) ;
if ( existing & & existing - > isValueBinding ( ) = = b - > isValueBinding ( ) & & ! ( existing - > flags & QV4 : : CompiledData : : Binding : : IsOnAssignment ) )
2014-01-31 14:09:46 +00:00
return tr ( " Property value set multiple times " ) ;
}
2014-03-04 14:26:18 +00:00
if ( bindingToDefaultProperty )
insertSorted ( b ) ;
else
2014-02-03 09:29:04 +00:00
bindings - > prepend ( b ) ;
2014-01-31 14:09:46 +00:00
return QString ( ) ; // no error
}
2014-03-17 16:11:20 +00:00
Binding * Object : : findBinding ( quint32 nameIndex ) const
2014-02-20 12:48:24 +00:00
{
for ( Binding * b = bindings - > first ; b ; b = b - > next )
if ( b - > propertyNameIndex = = nameIndex )
return b ;
return 0 ;
}
2014-03-17 16:11:20 +00:00
void Object : : insertSorted ( Binding * b )
2014-03-04 14:26:18 +00:00
{
Binding * insertionPoint = bindings - > findSortedInsertionPoint < QV4 : : CompiledData : : Location , QV4 : : CompiledData : : Binding , & QV4 : : CompiledData : : Binding : : valueLocation > ( b ) ;
bindings - > insertAfter ( insertionPoint , b ) ;
}
2014-04-01 09:00:27 +00:00
QString Object : : bindingAsString ( Document * doc , int scriptIndex ) const
{
CompiledFunctionOrExpression * foe = functionsAndExpressions - > slowAt ( scriptIndex ) ;
QQmlJS : : AST : : Node * node = foe - > node ;
if ( QQmlJS : : AST : : ExpressionStatement * exprStmt = QQmlJS : : AST : : cast < QQmlJS : : AST : : ExpressionStatement * > ( node ) )
node = exprStmt - > expression ;
QQmlJS : : AST : : SourceLocation start = node - > firstSourceLocation ( ) ;
QQmlJS : : AST : : SourceLocation end = node - > lastSourceLocation ( ) ;
return doc - > code . mid ( start . offset , end . offset + end . length - start . offset ) ;
}
2014-03-27 16:07:06 +00:00
QStringList Signal : : parameterStringList ( const QV4 : : Compiler : : StringTableGenerator * stringPool ) const
2013-09-13 13:03:51 +00:00
{
QStringList result ;
result . reserve ( parameters - > count ) ;
for ( SignalParameter * param = parameters - > first ; param ; param = param - > next )
2014-03-27 16:07:06 +00:00
result < < stringPool - > stringForIndex ( param - > nameIndex ) ;
2013-09-13 13:03:51 +00:00
return result ;
}
2014-03-18 17:21:18 +00:00
static void replaceWithSpace ( QString & str , int idx , int n )
{
QChar * data = str . data ( ) + idx ;
const QChar space ( QLatin1Char ( ' ' ) ) ;
for ( int ii = 0 ; ii < n ; + + ii )
* data + + = space ;
}
2014-03-27 16:07:06 +00:00
void Document : : collectTypeReferences ( )
{
foreach ( Object * obj , objects ) {
if ( obj - > inheritedTypeNameIndex ! = emptyStringIndex ) {
QV4 : : CompiledData : : TypeReference & r = typeReferences . add ( obj - > inheritedTypeNameIndex , obj - > location ) ;
r . needsCreation = true ;
r . errorWhenNotFound = true ;
}
for ( const Property * prop = obj - > firstProperty ( ) ; prop ; prop = prop - > next ) {
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.
QV4 : : CompiledData : : TypeReference & r = typeReferences . add ( prop - > customTypeNameIndex , obj - > location ) ;
r . needsCreation = true ;
r . errorWhenNotFound = true ;
}
}
for ( const Binding * binding = obj - > firstBinding ( ) ; binding ; binding = binding - > next ) {
if ( binding - > type = = QV4 : : CompiledData : : Binding : : Type_AttachedProperty )
typeReferences . add ( binding - > propertyNameIndex , binding - > location ) ;
}
}
}
2014-03-18 22:39:02 +00:00
void Document : : removeScriptPragmas ( QString & script )
{
const QString pragma ( QLatin1String ( " pragma " ) ) ;
const QString library ( QLatin1String ( " library " ) ) ;
QQmlJS : : Lexer l ( 0 ) ;
l . setCode ( script , 0 ) ;
int token = l . lex ( ) ;
while ( true ) {
if ( token ! = QQmlJSGrammar : : T_DOT )
return ;
int startOffset = l . tokenOffset ( ) ;
int startLine = l . tokenStartLine ( ) ;
token = l . lex ( ) ;
if ( token ! = QQmlJSGrammar : : T_PRAGMA | |
l . tokenStartLine ( ) ! = startLine | |
script . mid ( l . tokenOffset ( ) , l . tokenLength ( ) ) ! = pragma )
return ;
token = l . lex ( ) ;
if ( token ! = QQmlJSGrammar : : T_IDENTIFIER | |
l . tokenStartLine ( ) ! = startLine )
return ;
QString pragmaValue = script . mid ( l . tokenOffset ( ) , l . tokenLength ( ) ) ;
int endOffset = l . tokenLength ( ) + l . tokenOffset ( ) ;
token = l . lex ( ) ;
if ( l . tokenStartLine ( ) = = startLine )
return ;
if ( pragmaValue = = library ) {
replaceWithSpace ( script , startOffset , endOffset - startOffset ) ;
} else {
return ;
}
}
}
2014-03-27 16:07:06 +00:00
Document : : Document ( bool debugMode )
: jsModule ( debugMode )
, program ( 0 )
2015-04-28 14:53:37 +00:00
, indexOfRootObject ( 0 )
2014-08-06 12:59:34 +00:00
, jsGenerator ( & jsModule )
2014-03-27 16:07:06 +00:00
, unitFlags ( 0 )
{
}
2014-12-05 15:32:56 +00:00
ScriptDirectivesCollector : : ScriptDirectivesCollector ( QQmlJS : : Engine * engine , QV4 : : Compiler : : JSUnitGenerator * unitGenerator )
: engine ( engine )
, jsGenerator ( unitGenerator )
, hasPragmaLibrary ( false )
{
}
void ScriptDirectivesCollector : : pragmaLibrary ( )
{
hasPragmaLibrary = true ;
}
void ScriptDirectivesCollector : : importFile ( const QString & jsfile , const QString & module , int lineNumber , int column )
{
QV4 : : CompiledData : : Import * import = engine - > pool ( ) - > New < QV4 : : CompiledData : : Import > ( ) ;
import - > type = QV4 : : CompiledData : : Import : : ImportScript ;
import - > uriIndex = jsGenerator - > registerString ( jsfile ) ;
import - > qualifierIndex = jsGenerator - > registerString ( module ) ;
import - > location . line = lineNumber ;
import - > location . column = column ;
imports < < import ;
}
void ScriptDirectivesCollector : : importModule ( const QString & uri , const QString & version , const QString & module , int lineNumber , int column )
{
QV4 : : CompiledData : : Import * import = engine - > pool ( ) - > New < QV4 : : CompiledData : : Import > ( ) ;
import - > type = QV4 : : CompiledData : : Import : : ImportLibrary ;
import - > uriIndex = jsGenerator - > registerString ( uri ) ;
int vmaj ;
int vmin ;
IRBuilder : : extractVersion ( QStringRef ( & version ) , & vmaj , & vmin ) ;
import - > majorVersion = vmaj ;
import - > minorVersion = vmin ;
import - > qualifierIndex = jsGenerator - > registerString ( module ) ;
import - > location . line = lineNumber ;
import - > location . column = column ;
imports < < import ;
}
2014-03-17 20:26:04 +00:00
IRBuilder : : IRBuilder ( const QSet < QString > & illegalNames )
2013-12-06 10:29:43 +00:00
: illegalNames ( illegalNames )
, _object ( 0 )
2014-01-27 12:09:01 +00:00
, _propertyDeclaration ( 0 )
2015-12-11 19:43:37 +00:00
, pool ( 0 )
2013-08-06 14:41:28 +00:00
, jsGenerator ( 0 )
{
}
2014-06-04 15:32:31 +00:00
bool IRBuilder : : generateFromQml ( const QString & code , const QString & url , Document * output )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiProgram * program = 0 ;
2013-08-06 14:41:28 +00:00
{
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
2014-02-14 12:58:40 +00:00
foreach ( const QQmlJS : : DiagnosticMessage & m , parser . diagnosticMessages ( ) ) {
2013-08-06 14:41:28 +00:00
if ( m . isWarning ( ) ) {
2014-06-04 15:32:31 +00:00
qWarning ( " %s:%d : %s " , qPrintable ( url ) , m . loc . startLine , qPrintable ( m . message ) ) ;
2013-08-06 14:41:28 +00:00
continue ;
}
2014-02-27 08:59:43 +00:00
recordError ( m . loc , m . message ) ;
2013-08-06 14:41:28 +00:00
}
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 ) ;
this - > pool = output - > jsParserEngine . pool ( ) ;
this - > jsGenerator = & output - > jsGenerator ;
2014-02-03 12:30:06 +00:00
Q_ASSERT ( registerString ( QString ( ) ) = = emptyStringIndex ) ;
2013-09-19 11:32:13 +00:00
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 ) {
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc = program - > members - > next - > firstSourceLocation ( ) ;
2014-02-27 08:59:43 +00:00
recordError ( loc , QCoreApplication : : translate ( " QQmlParser " , " Unexpected object definition " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
2013-09-13 11:43:15 +00:00
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiObjectDefinition * rootObject = QQmlJS : : AST : : cast < QQmlJS : : AST : : UiObjectDefinition * > ( program - > members - > member ) ;
2013-08-06 14:41:28 +00:00
Q_ASSERT ( rootObject ) ;
2014-03-27 16:07:06 +00:00
defineQMLObject ( & output - > indexOfRootObject , rootObject ) ;
2013-09-12 08:53:20 +00:00
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 ) ;
2013-09-16 15:25:53 +00:00
return errors . isEmpty ( ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : isSignalPropertyName ( const QString & name )
2013-09-13 13:03:51 +00:00
{
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.
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiArrayMemberList * ast )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( ast ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiProgram * )
2013-08-06 14:41:28 +00:00
{
Q_ASSERT ( ! " should not happen " ) ;
return false ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiObjectDefinition * node )
2013-08-06 14:41:28 +00:00
{
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.
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiQualifiedId * lastId = node - > qualifiedTypeNameId ;
2013-09-12 12:43:56 +00:00
while ( lastId - > next )
lastId = lastId - > next ;
bool isType = lastId - > name . unicode ( ) - > isUpper ( ) ;
if ( isType ) {
2014-02-19 14:55:11 +00:00
int idx = 0 ;
if ( ! defineQMLObject ( & idx , node ) )
return false ;
2014-02-20 12:48:24 +00:00
const QQmlJS : : AST : : SourceLocation nameLocation = node - > qualifiedTypeNameId - > identifierToken ;
appendBinding ( nameLocation , nameLocation , emptyStringIndex , idx ) ;
2013-09-12 12:43:56 +00:00
} else {
2014-02-19 14:55:11 +00:00
int idx = 0 ;
if ( ! defineQMLObject ( & idx , /*qualfied type name id*/ 0 , node - > qualifiedTypeNameId - > firstSourceLocation ( ) , node - > initializer , /*declarations should go here*/ _object ) )
return false ;
2013-09-12 12:43:56 +00:00
appendBinding ( node - > qualifiedTypeNameId , idx ) ;
}
2013-08-06 14:41:28 +00:00
return false ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiObjectBinding * node )
2013-08-06 14:41:28 +00:00
{
2014-02-19 14:55:11 +00:00
int idx = 0 ;
if ( ! defineQMLObject ( & idx , node - > qualifiedTypeNameId , node - > qualifiedTypeNameId - > firstSourceLocation ( ) , node - > initializer ) )
return false ;
2013-09-30 15:39:49 +00:00
appendBinding ( node - > qualifiedId , idx , node - > hasOnToken ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiScriptBinding * node )
2013-08-06 14:41:28 +00:00
{
2013-09-12 12:43:56 +00:00
appendBinding ( node - > qualifiedId , node - > statement ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiArrayBinding * node )
2013-08-06 14:41:28 +00:00
{
2014-02-20 12:48:24 +00:00
const QQmlJS : : AST : : SourceLocation qualifiedNameLocation = node - > qualifiedId - > identifierToken ;
2014-03-17 16:11:20 +00:00
Object * object = 0 ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiQualifiedId * name = node - > qualifiedId ;
2013-09-17 15:23:49 +00:00
if ( ! resolveQualifiedId ( & name , & object ) )
return false ;
2013-09-16 15:25:53 +00:00
qSwap ( _object , object ) ;
2014-02-20 11:51:53 +00:00
const int propertyNameIndex = registerString ( name - > name . toString ( ) ) ;
2014-02-20 12:48:24 +00:00
if ( bindingsTarget ( ) - > findBinding ( propertyNameIndex ) ! = 0 ) {
2014-02-20 11:51:53 +00:00
recordError ( name - > identifierToken , tr ( " Property value set multiple times " ) ) ;
return false ;
}
2014-03-04 14:26:18 +00:00
QVarLengthArray < QQmlJS : : AST : : UiArrayMemberList * , 16 > memberList ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiArrayMemberList * member = node - > members ;
2013-09-16 15:25:53 +00:00
while ( member ) {
2014-03-04 14:26:18 +00:00
memberList . append ( member ) ;
member = member - > next ;
}
for ( int i = memberList . count ( ) - 1 ; i > = 0 ; - - i ) {
member = memberList . at ( i ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiObjectDefinition * def = QQmlJS : : AST : : cast < QQmlJS : : AST : : UiObjectDefinition * > ( member - > member ) ;
2013-09-16 15:25:53 +00:00
2014-02-19 14:55:11 +00:00
int idx = 0 ;
if ( ! defineQMLObject ( & idx , def ) )
return false ;
2014-02-20 12:48:24 +00:00
appendBinding ( qualifiedNameLocation , name - > identifierToken , propertyNameIndex , idx , /*isListItem*/ true ) ;
2013-09-16 15:25:53 +00:00
}
qSwap ( _object , object ) ;
return false ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiHeaderItemList * list )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( list ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiObjectInitializer * ast )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( ast ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiObjectMemberList * ast )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( ast ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiParameterList * ast )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( ast ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiQualifiedId * id )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
return QQmlJS : : AST : : Visitor : : visit ( id ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : accept ( QQmlJS : : AST : : Node * node )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : Node : : acceptChild ( node , this ) ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : defineQMLObject ( int * objectIndex , QQmlJS : : AST : : UiQualifiedId * qualifiedTypeNameId , const QQmlJS : : AST : : SourceLocation & location , QQmlJS : : AST : : UiObjectInitializer * initializer , Object * declarationsOverride )
2013-08-06 14:41:28 +00:00
{
2014-02-19 14:55:11 +00:00
if ( QQmlJS : : AST : : UiQualifiedId * lastName = qualifiedTypeNameId ) {
while ( lastName - > next )
lastName = lastName - > next ;
if ( ! lastName - > name . constData ( ) - > isUpper ( ) ) {
recordError ( lastName - > identifierToken , tr ( " Expected type name " ) ) ;
return false ;
}
}
2014-03-17 16:11:20 +00:00
Object * obj = New < Object > ( ) ;
2013-08-06 14:41:28 +00:00
_objects . append ( obj ) ;
2014-02-19 14:55:11 +00:00
* objectIndex = _objects . size ( ) - 1 ;
2013-08-06 14:41:28 +00:00
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.
2014-03-17 16:11:20 +00:00
Property * declaration = 0 ;
2014-01-28 09:41:58 +00:00
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-08-06 14:41:28 +00:00
qSwap ( _object , obj ) ;
2014-01-31 13:00:53 +00:00
2014-02-19 14:55:11 +00:00
if ( ! errors . isEmpty ( ) )
return false ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc ;
2014-02-25 15:36:41 +00:00
QString error = obj - > sanityCheckFunctionNames ( illegalNames , & loc ) ;
2014-02-19 14:55:11 +00:00
if ( ! error . isEmpty ( ) ) {
2014-01-31 13:00:53 +00:00
recordError ( loc , error ) ;
2014-02-19 14:55:11 +00:00
return false ;
}
2014-01-31 13:00:53 +00:00
2014-02-19 14:55:11 +00:00
return true ;
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiImport * node )
2013-08-06 14:41:28 +00:00
{
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 ( ) ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > importIdToken , QCoreApplication : : translate ( " QQmlParser " , " Invalid import qualifier ID " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
if ( qualifier = = QLatin1String ( " Qt " ) ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > importIdToken , QCoreApplication : : translate ( " QQmlParser " , " Reserved name \" Qt \" cannot be used as an qualifier " ) ) ;
2013-08-06 14:41:28 +00:00
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 ) {
2014-03-27 16:07:06 +00:00
const QV4 : : CompiledData : : Import * other = _imports . at ( ii ) ;
2013-08-06 14:41:28 +00:00
bool otherIsScript = other - > type = = QV4 : : CompiledData : : Import : : ImportScript ;
2014-03-27 16:07:06 +00:00
if ( ( isScript | | otherIsScript ) & & qualifier = = jsGenerator - > stringForIndex ( other - > qualifierIndex ) ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > importIdToken , QCoreApplication : : translate ( " QQmlParser " , " Script import qualifiers must be unique. " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
}
} else if ( import - > type = = QV4 : : CompiledData : : Import : : ImportScript ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > fileNameToken , QCoreApplication : : translate ( " QQmlParser " , " Script import requires a qualifier " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
if ( node - > versionToken . isValid ( ) ) {
extractVersion ( textRefAt ( node - > versionToken ) , & import - > majorVersion , & import - > minorVersion ) ;
} else if ( import - > type = = QV4 : : CompiledData : : Import : : ImportLibrary ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > importIdToken , QCoreApplication : : translate ( " QQmlParser " , " Library import requires a version " ) ) ;
2013-08-06 14:41:28 +00:00
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 ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : 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 {
2014-02-27 08:59:43 +00:00
recordError ( node - > pragmaToken , QCoreApplication : : translate ( " QQmlParser " , " Pragma requires a valid qualifier " ) ) ;
2013-09-24 19:49:10 +00:00
return false ;
}
} else {
2014-02-27 08:59:43 +00:00
recordError ( node - > pragmaToken , QCoreApplication : : translate ( " QQmlParser " , " Pragma requires a valid qualifier " ) ) ;
2013-09-24 19:49:10 +00:00
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 ( ) ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiPublicMember * node )
2013-08-06 14:41:28 +00:00
{
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-02-14 12:58:40 +00:00
if ( node - > type = = QQmlJS : : AST : : UiPublicMember : : Signal ) {
2013-08-06 14:41:28 +00:00
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-02-14 12:58:40 +00:00
QQmlJS : : 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 > > ( ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiParameterList * p = node - > parameters ;
2013-08-06 14:41:28 +00:00
while ( p ) {
const QStringRef & memberType = p - > type ;
if ( memberType . isEmpty ( ) ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > typeToken , QCoreApplication : : translate ( " QQmlParser " , " Expected parameter type " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
const TypeNameToType * type = 0 ;
for ( int typeIndex = 0 ; typeIndex < propTypeNameToTypesCount ; + + typeIndex ) {
const TypeNameToType * t = propTypeNameToTypes + typeIndex ;
2014-03-12 15:55:06 +00:00
if ( memberType = = QLatin1String ( 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 {
QString errStr = QCoreApplication : : translate ( " QQmlParser " , " Invalid signal parameter type: " ) ;
errStr . append ( memberType . toString ( ) ) ;
2014-02-27 08:59:43 +00:00
recordError ( node - > typeToken , errStr ) ;
2013-08-06 14:41:28 +00:00
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 ;
}
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-31 13:00:53 +00:00
QString error = _object - > appendSignal ( signal ) ;
if ( ! error . isEmpty ( ) ) {
recordError ( node - > identifierToken , error ) ;
return false ;
}
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 ;
2014-03-12 15:55:06 +00:00
if ( memberType = = QLatin1String ( " 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 ;
2014-03-12 15:55:06 +00:00
if ( memberType = = QLatin1String ( 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 ;
2014-03-12 15:55:06 +00:00
} else if ( typeModifier = = QLatin1String ( " list " ) ) {
2013-08-06 14:41:28 +00:00
type = QV4 : : CompiledData : : Property : : CustomList ;
} else {
2014-02-27 08:59:43 +00:00
recordError ( node - > typeModifierToken , QCoreApplication : : translate ( " QQmlParser " , " Invalid property type modifier " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
typeFound = true ;
} else if ( ! node - > typeModifier . isNull ( ) ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > typeModifierToken , QCoreApplication : : translate ( " QQmlParser " , " Unexpected property type modifier " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
if ( ! typeFound ) {
2014-02-27 08:59:43 +00:00
recordError ( node - > typeToken , QCoreApplication : : translate ( " QQmlParser " , " Expected property type " ) ) ;
2013-08-06 14:41:28 +00:00
return false ;
}
2014-03-17 16:11:20 +00:00
Property * property = New < Property > ( ) ;
2013-08-06 14:41:28 +00:00
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
2014-01-31 14:09:46 +00:00
const QString propName = name . toString ( ) ;
property - > nameIndex = registerString ( propName ) ;
2013-08-06 14:41:28 +00:00
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc = node - > firstSourceLocation ( ) ;
2013-09-09 11:51:31 +00:00
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 " ) ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation rhsLoc ;
2013-09-30 07:41:35 +00:00
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 ;
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : ExpressionStatement * stmt = QQmlJS : : AST : : cast < QQmlJS : : AST : : ExpressionStatement * > ( node - > statement ) ) {
2013-09-30 07:41:35 +00:00
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
}
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation errorLocation ;
2014-01-31 14:09:46 +00:00
QString error ;
if ( illegalNames . contains ( propName ) )
error = tr ( " Illegal property name " ) ;
else
error = _object - > appendProperty ( property , propName , node - > isDefaultMember , node - > defaultToken , & errorLocation ) ;
if ( ! error . isEmpty ( ) ) {
if ( errorLocation . startLine = = 0 )
errorLocation = node - > identifierToken ;
2014-02-27 08:59:43 +00:00
recordError ( errorLocation , error ) ;
2014-01-31 13:00:53 +00:00
return false ;
2013-08-06 14:41:28 +00:00
}
2014-02-27 07:11:40 +00:00
qSwap ( _propertyDeclaration , property ) ;
2014-01-27 12:09:01 +00:00
if ( node - > binding ) {
// process QML-like initializers (e.g. property Object o: Object {})
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : Node : : accept ( node - > binding , this ) ;
2014-02-27 07:11:40 +00:00
} else if ( node - > statement & & type ! = QV4 : : CompiledData : : Property : : Alias ) {
appendBinding ( node - > identifierToken , node - > identifierToken , _propertyDeclaration - > nameIndex , node - > statement ) ;
2014-01-27 12:09:01 +00:00
}
2014-02-27 07:11:40 +00:00
qSwap ( _propertyDeclaration , property ) ;
2013-08-06 14:41:28 +00:00
}
return false ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : visit ( QQmlJS : : AST : : UiSourceElement * node )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : FunctionDeclaration * funDecl = QQmlJS : : AST : : cast < QQmlJS : : AST : : FunctionDeclaration * > ( node - > sourceElement ) ) {
2014-02-25 15:36:41 +00:00
CompiledFunctionOrExpression * foe = New < CompiledFunctionOrExpression > ( ) ;
foe - > node = funDecl ;
foe - > nameIndex = registerString ( funDecl - > name . toString ( ) ) ;
foe - > disableAcceleratedLookups = false ;
const int index = _object - > functionsAndExpressions - > append ( foe ) ;
2013-08-06 14:41:28 +00:00
Function * f = New < Function > ( ) ;
2013-12-11 12:44:56 +00:00
f - > functionDeclaration = funDecl ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc = funDecl - > identifierToken ;
2013-12-11 12:44:56 +00:00
f - > location . line = loc . startLine ;
f - > location . column = loc . startColumn ;
2014-02-25 15:36:41 +00:00
f - > index = index ;
2014-01-31 13:00:53 +00:00
f - > nameIndex = registerString ( funDecl - > name . toString ( ) ) ;
_object - > appendFunction ( f ) ;
2013-08-06 14:41:28 +00:00
} else {
2014-02-27 08:59:43 +00:00
recordError ( node - > firstSourceLocation ( ) , QCoreApplication : : translate ( " QQmlParser " , " JavaScript declaration outside Script element " ) ) ;
2013-08-06 14:41:28 +00:00
}
return false ;
}
2014-03-17 20:26:04 +00:00
QString IRBuilder : : asString ( QQmlJS : : AST : : UiQualifiedId * node )
2013-08-06 14:41:28 +00:00
{
QString s ;
2014-02-14 12:58:40 +00:00
for ( QQmlJS : : AST : : UiQualifiedId * it = node ; it ; it = it - > next ) {
2013-08-06 14:41:28 +00:00
s . append ( it - > name ) ;
if ( it - > next )
s . append ( QLatin1Char ( ' . ' ) ) ;
}
return s ;
}
2014-03-17 20:26:04 +00:00
QStringRef IRBuilder : : asStringRef ( QQmlJS : : AST : : Node * node )
2013-08-06 14:41:28 +00:00
{
if ( ! node )
return QStringRef ( ) ;
return textRefAt ( node - > firstSourceLocation ( ) , node - > lastSourceLocation ( ) ) ;
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : extractVersion ( QStringRef string , int * maj , int * min )
2013-08-06 14:41:28 +00:00
{
* 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
}
}
}
2014-03-17 20:26:04 +00:00
QStringRef IRBuilder : : textRefAt ( const QQmlJS : : AST : : SourceLocation & first , const QQmlJS : : AST : : SourceLocation & last ) const
2013-08-06 14:41:28 +00:00
{
return QStringRef ( & sourceCode , first . offset , last . offset + last . length - first . offset ) ;
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : setBindingValue ( QV4 : : CompiledData : : Binding * binding , QQmlJS : : AST : : Statement * statement )
2013-08-06 14:41:28 +00:00
{
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc = statement - > firstSourceLocation ( ) ;
2014-01-24 15:49:03 +00:00
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
2014-02-26 09:26:51 +00:00
QQmlJS : : AST : : ExpressionStatement * exprStmt = QQmlJS : : AST : : cast < QQmlJS : : AST : : ExpressionStatement * > ( statement ) ;
if ( exprStmt ) {
QQmlJS : : AST : : ExpressionNode * const expr = exprStmt - > expression ;
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : StringLiteral * lit = QQmlJS : : AST : : cast < QQmlJS : : AST : : StringLiteral * > ( expr ) ) {
2013-09-13 07:08:41 +00:00
binding - > type = QV4 : : CompiledData : : Binding : : Type_String ;
binding - > stringIndex = registerString ( lit - > value . toString ( ) ) ;
2014-02-14 12:58:40 +00:00
} else if ( expr - > kind = = QQmlJS : : 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 ;
2014-02-14 12:58:40 +00:00
} else if ( expr - > kind = = QQmlJS : : 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 ;
2014-02-14 12:58:40 +00:00
} else if ( QQmlJS : : AST : : NumericLiteral * lit = QQmlJS : : AST : : cast < QQmlJS : : 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 {
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : UnaryMinusExpression * unaryMinus = QQmlJS : : AST : : cast < QQmlJS : : AST : : UnaryMinusExpression * > ( expr ) ) {
if ( QQmlJS : : AST : : NumericLiteral * lit = QQmlJS : : AST : : cast < QQmlJS : : 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 ;
2014-02-25 15:36:41 +00:00
CompiledFunctionOrExpression * expr = New < CompiledFunctionOrExpression > ( ) ;
expr - > node = statement ;
2014-03-03 11:04:57 +00:00
expr - > nameIndex = registerString ( QStringLiteral ( " expression for " ) + stringAt ( binding - > propertyNameIndex ) ) ;
2014-02-25 15:36:41 +00:00
expr - > disableAcceleratedLookups = false ;
const int index = bindingsTarget ( ) - > functionsAndExpressions - > append ( expr ) ;
binding - > value . compiledScriptIndex = index ;
2014-04-01 09:00:27 +00:00
// We don't need to store the binding script as string, except for script strings
// and types with custom parsers. Those will be added later in the compilation phase.
binding - > stringIndex = emptyStringIndex ;
2013-08-06 14:41:28 +00:00
}
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : appendBinding ( QQmlJS : : AST : : UiQualifiedId * name , QQmlJS : : AST : : Statement * value )
2013-09-12 12:43:56 +00:00
{
2014-02-20 12:48:24 +00:00
const QQmlJS : : AST : : SourceLocation qualifiedNameLocation = name - > identifierToken ;
2014-03-17 16:11:20 +00:00
Object * object = 0 ;
2013-09-17 15:23:49 +00:00
if ( ! resolveQualifiedId ( & name , & object ) )
return ;
2014-04-03 15:20:18 +00:00
if ( _object = = object & & name - > name = = QStringLiteral ( " id " ) ) {
setId ( name - > identifierToken , value ) ;
return ;
}
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
2014-02-20 12:48:24 +00:00
appendBinding ( qualifiedNameLocation , name - > identifierToken , registerString ( name - > name . toString ( ) ) , value ) ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : appendBinding ( QQmlJS : : AST : : UiQualifiedId * name , int objectIndex , bool isOnAssignment )
2013-09-12 12:43:56 +00:00
{
2014-02-20 12:48:24 +00:00
const QQmlJS : : AST : : SourceLocation qualifiedNameLocation = name - > identifierToken ;
2014-03-17 16:11:20 +00:00
Object * object = 0 ;
2014-03-03 11:39:32 +00:00
if ( ! resolveQualifiedId ( & name , & object , isOnAssignment ) )
2013-09-17 15:23:49 +00:00
return ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
2014-02-20 12:48:24 +00:00
appendBinding ( qualifiedNameLocation , name - > identifierToken , registerString ( name - > name . toString ( ) ) , objectIndex , /*isListItem*/ false , isOnAssignment ) ;
2013-09-12 12:43:56 +00:00
qSwap ( _object , object ) ;
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : appendBinding ( const QQmlJS : : AST : : SourceLocation & qualifiedNameLocation , const QQmlJS : : AST : : SourceLocation & nameLocation , quint32 propertyNameIndex , QQmlJS : : AST : : Statement * value )
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-02-03 12:30:06 +00:00
QString error = bindingsTarget ( ) - > appendBinding ( binding , /*isListBinding*/ false ) ;
2014-01-31 14:09:46 +00:00
if ( ! error . isEmpty ( ) ) {
2014-02-20 12:48:24 +00:00
recordError ( qualifiedNameLocation , error ) ;
2014-01-31 14:09:46 +00:00
}
2013-08-06 14:41:28 +00:00
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : appendBinding ( const QQmlJS : : AST : : SourceLocation & qualifiedNameLocation , const QQmlJS : : AST : : SourceLocation & nameLocation , quint32 propertyNameIndex , int objectIndex , bool isListItem , bool isOnAssignment )
2013-08-06 14:41:28 +00:00
{
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
2014-03-17 16:11:20 +00:00
const Object * obj = _objects . at ( objectIndex ) ;
2014-01-24 15:49:03 +00:00
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
2014-02-03 12:30:06 +00:00
if ( _objects . at ( objectIndex ) - > inheritedTypeNameIndex = = emptyStringIndex )
2014-01-10 12:34:41 +00:00
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 ;
2014-01-31 14:42:20 +00:00
if ( isListItem )
binding - > flags | = QV4 : : CompiledData : : Binding : : IsListItem ;
2013-09-30 15:39:49 +00:00
2013-08-06 14:41:28 +00:00
binding - > value . objectIndex = objectIndex ;
2014-02-03 12:30:06 +00:00
QString error = bindingsTarget ( ) - > appendBinding ( binding , isListItem ) ;
2014-01-31 14:09:46 +00:00
if ( ! error . isEmpty ( ) ) {
2014-02-20 12:48:24 +00:00
recordError ( qualifiedNameLocation , error ) ;
2014-01-31 14:09:46 +00:00
}
2014-01-28 09:41:58 +00:00
}
2014-03-17 20:26:04 +00:00
Object * IRBuilder : : bindingsTarget ( ) const
2014-01-28 09:41:58 +00:00
{
if ( _propertyDeclaration & & _object - > declarationsOverride )
2014-01-31 13:00:53 +00:00
return _object - > declarationsOverride ;
return _object ;
2013-08-06 14:41:28 +00:00
}
2013-09-11 17:28:13 +00:00
2014-03-17 20:26:04 +00:00
bool IRBuilder : : setId ( const QQmlJS : : AST : : SourceLocation & idLocation , QQmlJS : : AST : : Statement * value )
2013-09-12 14:53:32 +00:00
{
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceLocation loc = value - > firstSourceLocation ( ) ;
2013-09-12 14:53:32 +00:00
QStringRef str ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : Node * node = value ;
if ( QQmlJS : : AST : : ExpressionStatement * stmt = QQmlJS : : AST : : cast < QQmlJS : : AST : : ExpressionStatement * > ( node ) ) {
if ( QQmlJS : : AST : : StringLiteral * lit = QQmlJS : : AST : : cast < QQmlJS : : AST : : StringLiteral * > ( stmt - > expression ) ) {
2013-09-12 14:53:32 +00:00
str = lit - > value ;
2014-01-31 11:33:26 +00:00
node = 0 ;
} else
2013-09-17 15:21:11 +00:00
node = stmt - > expression ;
}
2013-09-12 14:53:32 +00:00
2014-01-31 11:33:26 +00:00
if ( node & & 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
2014-01-31 14:23:30 +00:00
if ( _object - > idIndex ! = emptyStringIndex )
COMPILE_EXCEPTION ( idLocation , tr ( " Property value set multiple times " ) ) ;
2013-12-06 10:29:43 +00:00
_object - > idIndex = registerString ( idQString ) ;
2014-02-10 20:00:49 +00:00
_object - > locationOfIdProperty . line = idLocation . startLine ;
_object - > locationOfIdProperty . column = idLocation . startColumn ;
2013-09-12 14:53:32 +00:00
return true ;
}
2014-03-17 20:26:04 +00:00
bool IRBuilder : : resolveQualifiedId ( QQmlJS : : AST : : UiQualifiedId * * nameToResolve , Object * * object , bool onAssignment )
2013-09-12 12:43:56 +00:00
{
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : UiQualifiedId * qualifiedIdElement = * nameToResolve ;
2014-01-24 11:01:33 +00:00
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 ) {
2014-03-27 16:07:06 +00:00
foreach ( const QV4 : : CompiledData : : Import * import , _imports )
2014-01-24 11:01:33 +00:00
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 ) {
2014-02-20 12:48:24 +00:00
const quint32 propertyNameIndex = registerString ( currentName ) ;
const bool isAttachedProperty = qualifiedIdElement - > name . unicode ( ) - > isUpper ( ) ;
Binding * binding = ( * object ) - > findBinding ( propertyNameIndex ) ;
if ( binding ) {
if ( isAttachedProperty ) {
if ( ! binding - > isAttachedProperty ( ) )
binding = 0 ;
} else if ( ! binding - > isGroupProperty ( ) ) {
binding = 0 ;
}
}
if ( ! binding ) {
binding = New < Binding > ( ) ;
binding - > propertyNameIndex = propertyNameIndex ;
binding - > location . line = qualifiedIdElement - > identifierToken . startLine ;
binding - > location . column = qualifiedIdElement - > identifierToken . startColumn ;
binding - > valueLocation . line = qualifiedIdElement - > next - > identifierToken . startLine ;
binding - > valueLocation . column = qualifiedIdElement - > next - > identifierToken . startColumn ;
binding - > flags = 0 ;
2014-03-03 11:39:32 +00:00
if ( onAssignment )
binding - > flags | = QV4 : : CompiledData : : Binding : : IsOnAssignment ;
2014-02-20 12:48:24 +00:00
if ( isAttachedProperty )
binding - > type = QV4 : : CompiledData : : Binding : : Type_AttachedProperty ;
else
binding - > type = QV4 : : CompiledData : : Binding : : Type_GroupProperty ;
2013-09-12 12:43:56 +00:00
2014-02-20 12:48:24 +00:00
int objIndex = 0 ;
if ( ! defineQMLObject ( & objIndex , 0 , QQmlJS : : AST : : SourceLocation ( ) , 0 , 0 ) )
return false ;
binding - > value . objectIndex = objIndex ;
2013-09-12 12:43:56 +00:00
2014-02-20 12:48:24 +00:00
QString error = ( * object ) - > appendBinding ( binding , /*isListBinding*/ false ) ;
if ( ! error . isEmpty ( ) ) {
recordError ( qualifiedIdElement - > identifierToken , error ) ;
return false ;
}
* object = _objects . at ( objIndex ) ;
} else {
Q_ASSERT ( binding - > isAttachedProperty ( ) | | binding - > isGroupProperty ( ) ) ;
* object = _objects . at ( binding - > value . objectIndex ) ;
2014-01-31 14:09:46 +00:00
}
2013-09-12 12:43:56 +00:00
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
}
2014-03-17 20:26:04 +00:00
void IRBuilder : : recordError ( const QQmlJS : : AST : : SourceLocation & location , const QString & description )
2013-09-11 17:28:13 +00:00
{
2014-03-12 15:55:06 +00:00
QQmlJS : : DiagnosticMessage error ;
error . loc = location ;
error . message = description ;
2013-09-11 17:28:13 +00:00
errors < < error ;
}
2013-09-12 08:53:20 +00:00
2014-03-17 20:26:04 +00:00
bool IRBuilder : : isStatementNodeScript ( QQmlJS : : AST : : Statement * statement )
2013-09-30 07:41:35 +00:00
{
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : ExpressionStatement * stmt = QQmlJS : : AST : : cast < QQmlJS : : AST : : ExpressionStatement * > ( statement ) ) {
QQmlJS : : AST : : ExpressionNode * expr = stmt - > expression ;
if ( QQmlJS : : AST : : cast < QQmlJS : : AST : : StringLiteral * > ( expr ) )
2013-09-30 07:41:35 +00:00
return false ;
2014-02-14 12:58:40 +00:00
else if ( expr - > kind = = QQmlJS : : AST : : Node : : Kind_TrueLiteral )
2013-09-30 07:41:35 +00:00
return false ;
2014-02-14 12:58:40 +00:00
else if ( expr - > kind = = QQmlJS : : AST : : Node : : Kind_FalseLiteral )
2013-09-30 07:41:35 +00:00
return false ;
2014-02-14 12:58:40 +00:00
else if ( QQmlJS : : AST : : cast < QQmlJS : : AST : : NumericLiteral * > ( expr ) )
2013-09-30 07:41:35 +00:00
return false ;
else {
2014-02-14 12:58:40 +00:00
if ( QQmlJS : : AST : : UnaryMinusExpression * unaryMinus = QQmlJS : : AST : : cast < QQmlJS : : AST : : UnaryMinusExpression * > ( expr ) ) {
if ( QQmlJS : : AST : : cast < QQmlJS : : AST : : NumericLiteral * > ( unaryMinus - > expression ) ) {
2013-09-30 07:41:35 +00:00
return false ;
}
}
}
}
return true ;
}
2014-08-06 12:59:34 +00:00
QV4 : : CompiledData : : Unit * QmlUnitGenerator : : generate ( Document & output )
2013-08-06 14:41:28 +00:00
{
2014-10-04 15:18:15 +00:00
QQmlRefPointer < QV4 : : CompiledData : : CompilationUnit > compilationUnit = output . javaScriptCompilationUnit ;
2014-03-27 16:07:06 +00:00
QV4 : : CompiledData : : Unit * jsUnit = compilationUnit - > createUnitData ( & output ) ;
const uint unitSize = jsUnit - > unitSize ;
2013-08-06 14:41:28 +00:00
const int importSize = sizeof ( QV4 : : CompiledData : : Import ) * output . imports . count ( ) ;
const int objectOffsetTableSize = output . objects . count ( ) * sizeof ( quint32 ) ;
2014-03-17 16:11:20 +00:00
QHash < Object * , quint32 > objectOffsets ;
2013-08-06 14:41:28 +00:00
int objectsSize = 0 ;
2014-03-17 16:11:20 +00:00
foreach ( Object * o , output . objects ) {
2013-08-06 14:41:28 +00:00
objectOffsets . insert ( o , unitSize + importSize + objectOffsetTableSize + objectsSize ) ;
2014-01-31 13:00:53 +00:00
objectsSize + = QV4 : : CompiledData : : Object : : calculateSizeExcludingSignals ( o - > functionCount ( ) , o - > propertyCount ( ) , o - > signalCount ( ) , o - > bindingCount ( ) ) ;
2013-08-06 14:41:28 +00:00
int signalTableSize = 0 ;
2014-01-31 13:00:53 +00:00
for ( const Signal * s = o - > firstSignal ( ) ; s ; s = s - > next )
2013-08-06 14:41:28 +00:00
signalTableSize + = QV4 : : CompiledData : : Signal : : calculateSize ( s - > parameters - > count ) ;
objectsSize + = signalTableSize ;
}
2014-09-24 10:27:21 +00:00
const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize + output . jsGenerator . stringTable . sizeOfTableAndData ( ) ;
2013-08-06 14:41:28 +00:00
char * data = ( char * ) malloc ( totalSize ) ;
memcpy ( data , jsUnit , unitSize ) ;
2015-05-05 11:14:36 +00:00
memset ( data + unitSize , 0 , totalSize - unitSize ) ;
2014-03-27 16:07:06 +00:00
if ( jsUnit ! = compilationUnit - > data )
free ( jsUnit ) ;
2013-08-06 14:41:28 +00:00
jsUnit = 0 ;
2014-08-06 12:59:34 +00:00
QV4 : : CompiledData : : Unit * qmlUnit = reinterpret_cast < QV4 : : CompiledData : : Unit * > ( data ) ;
qmlUnit - > unitSize = totalSize ;
qmlUnit - > flags | = output . unitFlags ;
qmlUnit - > flags | = QV4 : : CompiledData : : Unit : : IsQml ;
2013-08-06 14:41:28 +00:00
qmlUnit - > offsetToImports = unitSize ;
qmlUnit - > nImports = output . imports . count ( ) ;
qmlUnit - > offsetToObjects = unitSize + importSize ;
qmlUnit - > nObjects = output . objects . count ( ) ;
qmlUnit - > indexOfRootObject = output . indexOfRootObject ;
2014-09-24 10:27:21 +00:00
qmlUnit - > offsetToStringTable = totalSize - output . jsGenerator . stringTable . sizeOfTableAndData ( ) ;
qmlUnit - > stringTableSize = output . jsGenerator . stringTable . stringCount ( ) ;
2013-08-06 14:41:28 +00:00
// write imports
char * importPtr = data + qmlUnit - > offsetToImports ;
2014-03-27 16:07:06 +00:00
foreach ( const QV4 : : CompiledData : : Import * imp , output . imports ) {
2013-08-06 14:41:28 +00:00
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 ;
2014-03-17 16:11:20 +00:00
foreach ( Object * o , output . objects ) {
2013-08-06 14:41:28 +00:00
* 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 ) ;
2014-01-31 13:00:53 +00:00
objectToWrite - > nFunctions = o - > functionCount ( ) ;
2013-08-06 14:41:28 +00:00
objectToWrite - > offsetToFunctions = nextOffset ;
nextOffset + = objectToWrite - > nFunctions * sizeof ( quint32 ) ;
2014-01-31 13:00:53 +00:00
objectToWrite - > nProperties = o - > propertyCount ( ) ;
2013-08-06 14:41:28 +00:00
objectToWrite - > offsetToProperties = nextOffset ;
nextOffset + = objectToWrite - > nProperties * sizeof ( QV4 : : CompiledData : : Property ) ;
2014-01-31 13:00:53 +00:00
objectToWrite - > nSignals = o - > signalCount ( ) ;
2013-08-06 14:41:28 +00:00
objectToWrite - > offsetToSignals = nextOffset ;
nextOffset + = objectToWrite - > nSignals * sizeof ( quint32 ) ;
2014-01-31 13:00:53 +00:00
objectToWrite - > nBindings = o - > bindingCount ( ) ;
2013-08-06 14:41:28 +00:00
objectToWrite - > offsetToBindings = nextOffset ;
nextOffset + = objectToWrite - > nBindings * sizeof ( QV4 : : CompiledData : : Binding ) ;
quint32 * functionsTable = reinterpret_cast < quint32 * > ( objectPtr + objectToWrite - > offsetToFunctions ) ;
2014-01-31 13:00:53 +00:00
for ( const Function * f = o - > firstFunction ( ) ; f ; f = f - > next )
2014-02-25 15:36:41 +00:00
* functionsTable + + = o - > runtimeFunctionIndices - > at ( f - > index ) ;
2013-08-06 14:41:28 +00:00
char * propertiesPtr = objectPtr + objectToWrite - > offsetToProperties ;
2014-03-17 16:11:20 +00:00
for ( const Property * p = o - > firstProperty ( ) ; p ; p = p - > next ) {
2013-08-06 14:41:28 +00:00
QV4 : : CompiledData : : Property * propertyToWrite = reinterpret_cast < QV4 : : CompiledData : : Property * > ( propertiesPtr ) ;
* propertyToWrite = * p ;
propertiesPtr + = sizeof ( QV4 : : CompiledData : : Property ) ;
}
char * bindingPtr = objectPtr + objectToWrite - > offsetToBindings ;
2014-02-25 15:36:41 +00:00
bindingPtr = writeBindings ( bindingPtr , o , & QV4 : : CompiledData : : Binding : : isValueBindingNoAlias ) ;
bindingPtr = writeBindings ( bindingPtr , o , & QV4 : : CompiledData : : Binding : : isSignalHandler ) ;
bindingPtr = writeBindings ( bindingPtr , o , & QV4 : : CompiledData : : Binding : : isAttachedProperty ) ;
bindingPtr = writeBindings ( bindingPtr , o , & QV4 : : CompiledData : : Binding : : isGroupProperty ) ;
bindingPtr = writeBindings ( bindingPtr , o , & QV4 : : CompiledData : : Binding : : isValueBindingToAlias ) ;
2014-02-03 09:29:04 +00:00
Q_ASSERT ( ( bindingPtr - objectToWrite - > offsetToBindings - objectPtr ) / sizeof ( QV4 : : CompiledData : : Binding ) = = unsigned ( o - > bindingCount ( ) ) ) ;
2013-08-06 14:41:28 +00:00
quint32 * signalOffsetTable = reinterpret_cast < quint32 * > ( objectPtr + objectToWrite - > offsetToSignals ) ;
quint32 signalTableSize = 0 ;
char * signalPtr = objectPtr + nextOffset ;
2014-01-31 13:00:53 +00:00
for ( const Signal * s = o - > firstSignal ( ) ; s ; s = s - > next ) {
2013-08-06 14:41:28 +00:00
* 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 ;
}
2014-01-31 13:00:53 +00:00
objectPtr + = QV4 : : CompiledData : : Object : : calculateSizeExcludingSignals ( o - > functionCount ( ) , o - > propertyCount ( ) , o - > signalCount ( ) , o - > bindingCount ( ) ) ;
2013-08-06 14:41:28 +00:00
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 ) {
2014-08-06 12:59:34 +00:00
qmlUnit - > flags | = QV4 : : CompiledData : : Unit : : IsSingleton ;
2013-09-24 19:49:10 +00:00
break ;
}
}
2014-09-24 10:27:21 +00:00
output . jsGenerator . stringTable . serialize ( qmlUnit ) ;
2013-08-06 14:41:28 +00:00
return qmlUnit ;
}
2014-03-17 16:11:20 +00:00
char * QmlUnitGenerator : : writeBindings ( char * bindingPtr , Object * o , BindingFilter filter ) const
2014-02-03 09:29:04 +00:00
{
for ( const Binding * b = o - > firstBinding ( ) ; b ; b = b - > next ) {
if ( ! ( b - > * ( filter ) ) ( ) )
continue ;
QV4 : : CompiledData : : Binding * bindingToWrite = reinterpret_cast < QV4 : : CompiledData : : Binding * > ( bindingPtr ) ;
* bindingToWrite = * b ;
if ( b - > type = = QV4 : : CompiledData : : Binding : : Type_Script )
2014-02-25 15:36:41 +00:00
bindingToWrite - > value . compiledScriptIndex = o - > runtimeFunctionIndices - > at ( b - > value . compiledScriptIndex ) ;
2014-02-03 09:29:04 +00:00
bindingPtr + = sizeof ( QV4 : : CompiledData : : Binding ) ;
}
return bindingPtr ;
}
2014-03-17 16:11:20 +00:00
JSCodeGen : : JSCodeGen ( const QString & fileName , const QString & sourceCode , QV4 : : IR : : Module * jsModule , QQmlJS : : Engine * jsEngine ,
2014-03-27 16:07:06 +00:00
QQmlJS : : AST : : UiProgram * qmlRoot , QQmlTypeNameCache * imports , const QV4 : : Compiler : : StringTableGenerator * stringPool )
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 )
2014-02-25 15:36:41 +00:00
, stringPool ( stringPool )
2013-12-10 14:25:22 +00:00
, _disableAcceleratedLookups ( false )
2013-10-29 12:02:48 +00:00
, _contextObject ( 0 )
, _scopeObject ( 0 )
2015-06-18 11:12:31 +00:00
, _qmlContextTemp ( - 1 )
2013-10-29 12:02:48 +00:00
, _importedScriptsTemp ( - 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 ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : FunctionDeclaration * function = QQmlJS : : AST : : cast < QQmlJS : : 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 ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : 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
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : FunctionDeclaration * function = QQmlJS : : AST : : cast < QQmlJS : : AST : : FunctionDeclaration * > ( node ) ;
2013-08-06 14:41:28 +00:00
QString name ;
if ( function )
name = function - > name . toString ( ) ;
2014-02-25 15:36:41 +00:00
else if ( qmlFunction . nameIndex ! = 0 )
2014-03-27 16:07:06 +00:00
name = stringPool - > stringForIndex ( qmlFunction . nameIndex ) ;
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
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceElements * body ;
2013-09-18 19:37:35 +00:00
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 ( ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : Statement * stmt = node - > statementCast ( ) ;
2013-10-08 09:44:57 +00:00
if ( ! stmt ) {
Q_ASSERT ( node - > expressionCast ( ) ) ;
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : ExpressionNode * expr = node - > expressionCast ( ) ;
stmt = new ( pool ) QQmlJS : : AST : : ExpressionStatement ( expr ) ;
2013-10-08 09:44:57 +00:00
}
2014-02-14 12:58:40 +00:00
QQmlJS : : AST : : SourceElement * element = new ( pool ) QQmlJS : : AST : : StatementSourceElement ( stmt ) ;
body = new ( pool ) QQmlJS : : 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
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
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-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
} ;
2014-03-17 16:11:20 +00:00
static void initMetaObjectResolver ( QV4 : : IR : : MemberExpressionResolver * resolver , QQmlPropertyCache * metaObject ) ;
2013-11-14 23:06:18 +00:00
2014-03-17 16:11:20 +00:00
static QV4 : : IR : : Type resolveQmlType ( QQmlEnginePrivate * qmlEngine , QV4 : : IR : : MemberExpressionResolver * resolver , QV4 : : IR : : Member * member )
2013-11-14 23:06:18 +00:00
{
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Type result = QV4 : : IR : : VarType ;
2013-11-14 23:06:18 +00:00
QQmlType * type = static_cast < QQmlType * > ( resolver - > data ) ;
2014-01-02 07:48:55 +00:00
if ( member - > name - > constData ( ) - > isUpper ( ) ) {
bool ok = false ;
2015-09-14 19:23:32 +00:00
int value = type - > enumValue ( qmlEngine , * member - > name , & ok ) ;
2014-01-02 07:48:55 +00:00
if ( ok ) {
member - > setEnumValue ( value ) ;
resolver - > clear ( ) ;
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : SInt32Type ;
2013-11-14 23:06:18 +00:00
}
2014-01-02 07:48:55 +00:00
}
if ( type - > isCompositeSingleton ( ) ) {
2014-09-10 11:18:39 +00:00
QQmlRefPointer < QQmlTypeData > tdata = qmlEngine - > typeLoader . getType ( type - > singletonInstanceInfo ( ) - > url ) ;
2014-01-02 07:48:55 +00:00
Q_ASSERT ( tdata ) ;
2014-10-25 09:15:49 +00:00
tdata - > release ( ) ; // Decrease the reference count added from QQmlTypeLoader::getType()
2014-09-10 11:18:39 +00:00
// When a singleton tries to reference itself, it may not be complete yet.
if ( tdata - > isComplete ( ) ) {
initMetaObjectResolver ( resolver , qmlEngine - > propertyCacheForType ( tdata - > compiledData ( ) - > metaTypeId ) ) ;
resolver - > flags | = AllPropertiesAreFinal ;
return resolver - > resolveMember ( qmlEngine , resolver , member ) ;
}
2014-07-23 17:43:38 +00:00
} else if ( type - > isSingleton ( ) ) {
const QMetaObject * singletonMeta = type - > singletonInstanceInfo ( ) - > instanceMetaObject ;
if ( singletonMeta ) { // QJSValue-based singletons cannot be accelerated
initMetaObjectResolver ( resolver , qmlEngine - > cache ( singletonMeta ) ) ;
member - > kind = QV4 : : IR : : Member : : MemberOfSingletonObject ;
return resolver - > resolveMember ( qmlEngine , resolver , member ) ;
}
2015-09-14 20:02:55 +00:00
} else if ( const QMetaObject * attachedMeta = type - > attachedPropertiesType ( qmlEngine ) ) {
2014-01-02 07:48:55 +00:00
QQmlPropertyCache * cache = qmlEngine - > cache ( attachedMeta ) ;
initMetaObjectResolver ( resolver , cache ) ;
2015-09-14 20:02:55 +00:00
member - > setAttachedPropertiesId ( type - > attachedPropertiesId ( qmlEngine ) ) ;
2013-11-14 23:06:18 +00:00
return resolver - > resolveMember ( qmlEngine , resolver , member ) ;
}
resolver - > clear ( ) ;
return result ;
}
2014-03-17 16:11:20 +00:00
static void initQmlTypeResolver ( QV4 : : IR : : MemberExpressionResolver * resolver , QQmlType * qmlType )
2013-11-14 23:06:18 +00:00
{
2015-01-09 13:17:31 +00:00
Q_ASSERT ( resolver ) ;
2013-11-14 23:06:18 +00:00
resolver - > resolveMember = & resolveQmlType ;
resolver - > data = qmlType ;
resolver - > extraData = 0 ;
resolver - > flags = 0 ;
}
2014-03-17 16:11:20 +00:00
static QV4 : : IR : : Type resolveImportNamespace ( QQmlEnginePrivate * , QV4 : : IR : : MemberExpressionResolver * resolver , QV4 : : IR : : Member * member )
2013-11-14 23:06:18 +00:00
{
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Type result = QV4 : : IR : : VarType ;
2013-11-14 23:06:18 +00:00
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.
2014-03-17 16:11:20 +00:00
result = QV4 : : IR : : VarType ;
2013-11-14 23:06:18 +00:00
} 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 ) ;
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : QObjectType ;
2013-11-14 23:06:18 +00:00
}
} else {
Q_ASSERT ( false ) ; // How can this happen?
}
}
resolver - > clear ( ) ;
return result ;
}
2014-03-17 16:11:20 +00:00
static void initImportNamespaceResolver ( QV4 : : IR : : MemberExpressionResolver * resolver , QQmlTypeNameCache * imports , const void * importNamespace )
2013-11-14 23:06:18 +00:00
{
resolver - > resolveMember = & resolveImportNamespace ;
resolver - > data = const_cast < void * > ( importNamespace ) ;
resolver - > extraData = imports ;
resolver - > flags = 0 ;
}
2014-03-17 16:11:20 +00:00
static QV4 : : IR : : Type resolveMetaObjectProperty ( QQmlEnginePrivate * qmlEngine , QV4 : : IR : : MemberExpressionResolver * resolver , QV4 : : IR : : Member * member )
2013-10-30 15:49:32 +00:00
{
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Type result = QV4 : : IR : : 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 ( ) ;
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : SInt32Type ;
2013-11-02 21:46:25 +00:00
}
}
}
2013-10-30 15:49:32 +00:00
2015-11-24 09:13:58 +00:00
if ( member - > kind ! = QV4 : : IR : : Member : : MemberOfIdObjectsArray & & member - > kind ! = QV4 : : IR : : Member : : MemberOfSingletonObject & &
qmlEngine & & ! ( resolver - > flags & LookupsExcludeProperties ) ) {
2013-11-02 21:46:25 +00:00
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 ( ) )
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : VarType ;
2013-10-30 15:49:32 +00:00
switch ( property - > propType ) {
2014-03-17 16:11:20 +00:00
case QMetaType : : Bool : result = QV4 : : IR : : BoolType ; break ;
case QMetaType : : Int : result = QV4 : : IR : : SInt32Type ; break ;
case QMetaType : : Double : result = QV4 : : IR : : DoubleType ; break ;
case QMetaType : : QString : result = QV4 : : IR : : StringType ; break ;
2013-10-30 15:49:32 +00:00
default :
if ( property - > isQObject ( ) ) {
if ( QQmlPropertyCache * cache = qmlEngine - > propertyCacheForType ( property - > propType ) ) {
initMetaObjectResolver ( resolver , cache ) ;
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : QObjectType ;
2013-10-30 15:49:32 +00:00
}
2014-11-10 10:39:03 +00:00
} else if ( const QMetaObject * valueTypeMetaObject = QQmlValueTypeFactory : : metaObjectForMetaType ( property - > propType ) ) {
if ( QQmlPropertyCache * cache = qmlEngine - > cache ( valueTypeMetaObject ) ) {
2013-11-17 17:07:06 +00:00
initMetaObjectResolver ( resolver , cache ) ;
resolver - > flags | = ResolveTypeInformationOnly ;
2014-03-17 16:11:20 +00:00
return QV4 : : IR : : QObjectType ;
2013-11-17 17:07:06 +00:00
}
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 ;
}
2014-03-17 16:11:20 +00:00
static void initMetaObjectResolver ( QV4 : : IR : : MemberExpressionResolver * resolver , QQmlPropertyCache * metaObject )
2013-10-30 15:49:32 +00:00
{
2015-01-09 13:17:31 +00:00
Q_ASSERT ( resolver ) ;
2013-10-30 15:49:32 +00:00
resolver - > resolveMember = & resolveMetaObjectProperty ;
resolver - > data = metaObject ;
2013-11-02 21:46:25 +00:00
resolver - > flags = 0 ;
2013-10-25 12:23:39 +00:00
}
2014-03-12 15:55:06 +00:00
# endif // V4_BOOTSTRAP
2013-10-29 12:02:48 +00:00
void JSCodeGen : : beginFunctionBodyHook ( )
{
2015-06-18 11:12:31 +00:00
_qmlContextTemp = _block - > newTemp ( ) ;
2013-10-29 12:02:48 +00:00
_importedScriptsTemp = _block - > newTemp ( ) ;
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
2015-06-18 11:12:31 +00:00
QV4 : : IR : : Temp * temp = _block - > TEMP ( _qmlContextTemp ) ;
move ( temp , _block - > NAME ( QV4 : : IR : : Name : : builtin_qml_context , 0 , 0 ) ) ;
2014-03-17 16:11:20 +00:00
move ( _block - > TEMP ( _importedScriptsTemp ) , _block - > NAME ( QV4 : : IR : : Name : : builtin_qml_imported_scripts_object , 0 , 0 ) ) ;
2014-03-12 15:55:06 +00:00
# endif
2013-10-29 12:02:48 +00:00
}
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Expr * JSCodeGen : : fallbackNameLookup ( const QString & name , int line , int col )
2013-09-13 11:43:15 +00:00
{
2013-10-29 12:02:48 +00:00
Q_UNUSED ( line )
Q_UNUSED ( col )
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
if ( _disableAcceleratedLookups )
return 0 ;
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 ) ;
2015-06-22 14:33:40 +00:00
QV4 : : IR : : Expr * s = _block - > MEMBER ( _block - > TEMP ( _qmlContextTemp ) , _function - > newString ( name ) , 0 , QV4 : : IR : : Member : : MemberOfIdObjectsArray , mapping . idIndex ) ;
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Temp * result = _block - > TEMP ( _block - > newTemp ( ) ) ;
2013-11-02 17:48:18 +00:00
_block - > MOVE ( result , s ) ;
result = _block - > TEMP ( result - > index ) ;
2014-01-02 11:17:31 +00:00
if ( mapping . type ) {
2015-01-09 13:17:31 +00:00
result - > memberResolver = _function - > New < QV4 : : IR : : MemberExpressionResolver > ( ) ;
initMetaObjectResolver ( result - > memberResolver , mapping . type ) ;
result - > memberResolver - > flags | = AllPropertiesAreFinal ;
2014-01-02 11:17:31 +00:00
}
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 ) {
2014-03-17 16:11:20 +00:00
return subscript ( _block - > TEMP ( _importedScriptsTemp ) , _block - > CONST ( QV4 : : IR : : SInt32Type , r . scriptIndex ) ) ;
2013-11-02 21:46:25 +00:00
} else if ( r . type ) {
2014-03-17 16:11:20 +00:00
QV4 : : IR : : 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 ;
2014-03-17 16:11:20 +00:00
QV4 : : IR : : 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 ) ;
2015-01-09 13:17:31 +00:00
result - > memberResolver = _function - > New < QV4 : : IR : : MemberExpressionResolver > ( ) ;
initQmlTypeResolver ( result - > memberResolver , r . type ) ;
2014-01-02 07:48:55 +00:00
return result ;
2013-11-02 21:46:25 +00:00
} else {
2013-11-14 23:06:18 +00:00
Q_ASSERT ( r . importNamespace ) ;
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Name * namespaceName = _block - > NAME ( name , line , col ) ;
2013-11-14 23:06:18 +00:00
namespaceName - > freeOfSideEffects = true ;
2014-03-17 16:11:20 +00:00
QV4 : : IR : : Temp * result = _block - > TEMP ( _block - > newTemp ( ) ) ;
2015-01-09 13:17:31 +00:00
result - > memberResolver = _function - > New < QV4 : : IR : : MemberExpressionResolver > ( ) ;
initImportNamespaceResolver ( result - > memberResolver , imports , r . importNamespace ) ;
2013-11-14 23:06:18 +00:00
_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 ) {
2015-06-19 12:18:13 +00:00
QV4 : : IR : : Temp * base = _block - > TEMP ( _qmlContextTemp ) ;
2015-01-09 13:17:31 +00:00
base - > memberResolver = _function - > New < QV4 : : IR : : MemberExpressionResolver > ( ) ;
initMetaObjectResolver ( base - > memberResolver , _scopeObject ) ;
2014-03-17 16:11:20 +00:00
return _block - > MEMBER ( base , _function - > newString ( name ) , pd , QV4 : : IR : : 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 ) {
2015-06-22 05:46:32 +00:00
QV4 : : IR : : Temp * base = _block - > TEMP ( _qmlContextTemp ) ;
2015-01-09 13:17:31 +00:00
base - > memberResolver = _function - > New < QV4 : : IR : : MemberExpressionResolver > ( ) ;
initMetaObjectResolver ( base - > memberResolver , _contextObject ) ;
2014-03-17 16:11:20 +00:00
return _block - > MEMBER ( base , _function - > newString ( name ) , pd , QV4 : : IR : : Member : : MemberOfQmlContextObject ) ;
2013-10-24 12:51:02 +00:00
}
}
2014-03-12 15:55:06 +00:00
# else
Q_UNUSED ( name )
# endif // V4_BOOTSTRAP
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
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
2016-01-19 14:37:26 +00:00
QQmlPropertyData * PropertyResolver : : property ( const QString & name , bool * notInRevision , RevisionCheck check )
2013-09-13 13:03:51 +00:00
{
if ( notInRevision ) * notInRevision = false ;
2016-01-19 14:37:26 +00:00
QQmlPropertyData * d = cache - > property ( name , 0 , 0 ) ;
2013-09-13 13:03:51 +00:00
// Find the first property
while ( d & & d - > isFunction ( ) )
d = cache - > overrideData ( d ) ;
2016-01-19 14:37:26 +00:00
if ( check ! = IgnoreRevision & & d & & ! cache - > isAllowedInRevision ( d ) ) {
2013-09-13 13:03:51 +00:00
if ( notInRevision ) * notInRevision = true ;
return 0 ;
} else {
return d ;
}
}
2016-01-19 14:37:26 +00:00
QQmlPropertyData * PropertyResolver : : signal ( const QString & name , bool * notInRevision )
2013-09-13 13:03:51 +00:00
{
if ( notInRevision ) * notInRevision = false ;
2016-01-19 14:37:26 +00:00
QQmlPropertyData * d = cache - > property ( name , 0 , 0 ) ;
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
2016-01-19 14:37:26 +00:00
d = property ( propName , notInRevision ) ;
2013-09-13 13:03:51 +00:00
if ( d )
return cache - > signal ( d - > notifyIndex ) ;
}
return 0 ;
}
2014-03-12 15:55:06 +00:00
# endif // V4_BOOTSTRAP