qmljs: use new qml parser

adds support for singleton and getter/setter properties

Change-Id: Ia6691ac7799a46885db0df44617617dcc3c13189
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com>
This commit is contained in:
Fawzi Mohamed
2013-11-06 14:17:23 +01:00
parent 0374d83e83
commit e9c97aa1d1
35 changed files with 2420 additions and 1675 deletions

View File

@@ -100,8 +100,9 @@ bool JsonCheck::visit(ObjectLiteral *ast)
return false;
QSet<QString> propertiesFound;
for (PropertyNameAndValueList *it = ast->properties; it; it = it->next) {
StringLiteralPropertyName *literalName = cast<StringLiteralPropertyName *>(it->name);
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
PropertyNameAndValue *assignment = AST::cast<AST::PropertyNameAndValue *>(it->assignment);
StringLiteralPropertyName *literalName = cast<StringLiteralPropertyName *>(assignment->name);
if (literalName) {
const QString &propertyName = literalName->id.toString();
if (m_schema->hasPropertySchema(propertyName)) {
@@ -109,7 +110,7 @@ bool JsonCheck::visit(ObjectLiteral *ast)
propertiesFound.insert(propertyName);
// Sec. 5.2: "... each property definition's value MUST be a schema..."
m_schema->enterNestedPropertySchema(propertyName);
processSchema(it->value);
processSchema(assignment->value);
m_schema->leaveNestedSchema();
} else {
analysis()->m_messages.append(Message(ErrInvalidPropertyName,
@@ -119,7 +120,7 @@ bool JsonCheck::visit(ObjectLiteral *ast)
}
} else {
analysis()->m_messages.append(Message(ErrStringValueExpected,
it->name->firstSourceLocation(),
assignment->name->firstSourceLocation(),
QString(), QString(),
false));
}

View File

@@ -12,7 +12,7 @@
me=$(dirname $0)
for i in $QTDIR/src/qml/qml/parser/*.{g,h,cpp,pri}; do
for i in $QTDIR/src/qml/parser/*.{g,h,cpp,pri}; do
sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qqmljs/qmljs/)
done

View File

@@ -104,7 +104,7 @@ bool QmlDirParser::parse(const QString &source)
if (ch->isNull())
break;
QString sections[3];
QString sections[4];
int sectionCount = 0;
do {
@@ -114,7 +114,7 @@ bool QmlDirParser::parse(const QString &source)
}
const QChar *start = ch;
scanWord(ch);
if (sectionCount < 3) {
if (sectionCount < 4) {
sections[sectionCount++] = source.mid(start-source.constData(), ch-start);
} else {
reportError(lineNumber, start-lineStart, QLatin1String("unexpected token"));
@@ -148,14 +148,14 @@ bool QmlDirParser::parse(const QString &source)
}
if (!firstLine) {
reportError(lineNumber, 0,
QString::fromUtf8("module identifier directive must be the first command in a qmldir file"));
QString::fromUtf8("module identifier directive must be the first directive in a qmldir file"));
continue;
}
_typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2) {
if (sectionCount < 2 || sectionCount > 3) {
reportError(lineNumber, 0,
QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
@@ -175,6 +175,43 @@ bool QmlDirParser::parse(const QString &source)
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
_components.insertMulti(entry.typeName, entry);
} else if (sections[0] == QLatin1String("singleton")) {
if (sectionCount < 3 || sectionCount > 4) {
reportError(lineNumber, 0,
QString::fromUtf8("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
} else if (sectionCount == 3) {
// handle qmldir directory listing case where singleton is defined in the following pattern:
// singleton TestSingletonType TestSingletonType.qml
Component entry(sections[1], sections[2], -1, -1);
entry.singleton = true;
_components.insertMulti(entry.typeName, entry);
} else {
// handle qmldir module listing case where singleton is defined in the following pattern:
// singleton TestSingletonType 2.0 TestSingletonType20.qml
const QString &version = sections[2];
const int dotIndex = version.indexOf(QLatin1Char('.'));
if (dotIndex == -1) {
reportError(lineNumber, 0, QLatin1String("expected '.'"));
} else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) {
reportError(lineNumber, 0, QLatin1String("unexpected '.'"));
} else {
bool validVersionNumber = false;
const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber);
if (validVersionNumber) {
const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber);
if (validVersionNumber) {
const QString &fileName = sections[3];
Component entry(sections[1], fileName, majorVersion, minorVersion);
entry.singleton = true;
_components.insertMulti(entry.typeName, entry);
}
}
}
}
} else if (sections[0] == QLatin1String("typeinfo")) {
if (sectionCount != 2) {
reportError(lineNumber, 0,

View File

@@ -83,17 +83,18 @@ public:
struct Component
{
Component()
: majorVersion(0), minorVersion(0), internal(false) {}
: majorVersion(0), minorVersion(0), internal(false), singleton(false) {}
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
internal(false) {}
internal(false), singleton(false) {}
QString typeName;
QString fileName;
int majorVersion;
int minorVersion;
bool internal;
bool singleton;
};
struct Script

View File

@@ -44,13 +44,13 @@ QT_BEGIN_NAMESPACE
QmlError includes a textual description of the error, as well
as location information (the file, line, and column). The toString()
function creates a single-line, human-readable string containing all of
method creates a single-line, human-readable string containing all of
this information, for example:
\code
file:///home/user/test.qml:7:8: Invalid property assignment: double expected
\endcode
You can use qDebug() or qWarning() to output errors to the console. This function
You can use qDebug() or qWarning() to output errors to the console. This method
will attempt to open the file indicated by the error
and include additional contextual information.
\code
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
^
\endcode
\note The QtQuick 1 version is named QDeclarativeError.
Note that the \l {Qt Quick 1} version is named QDeclarativeError
\sa QQuickView::errors(), QmlComponent::errors()
*/
@@ -78,10 +78,11 @@ public:
QString description;
quint16 line;
quint16 column;
QObject *object;
};
QmlErrorPrivate::QmlErrorPrivate()
: line(0), column(0)
: line(0), column(0), object()
{
}
@@ -116,6 +117,7 @@ QmlError &QmlError::operator=(const QmlError &other)
d->description = other.d->description;
d->line = other.d->line;
d->column = other.d->column;
d->object = other.d->object;
}
return *this;
}
@@ -137,7 +139,7 @@ bool QmlError::isValid() const
}
/*!
Returns the URL for the file that caused this error.
Returns the url for the file that caused this error.
*/
QUrl QmlError::url() const
{
@@ -208,6 +210,27 @@ void QmlError::setColumn(int column)
d->column = qmlSourceCoordinate(column);
}
/*!
Returns the nearest object where this error occurred.
Exceptions in bound property expressions set this to the object
to which the property belongs. It will be 0 for all
other exceptions.
*/
QObject *QmlError::object() const
{
if (d) return d->object;
else return 0;
}
/*!
Sets the nearest \a object where this error occurred.
*/
void QmlError::setObject(QObject *object)
{
if (!d) d = new QmlErrorPrivate;
d->object = object;
}
/*!
Returns the error as a human readable string.
*/
@@ -237,6 +260,7 @@ QString QmlError::toString() const
/*!
\relates QmlError
\fn QDebug operator<<(QDebug debug, const QmlError &error)
Outputs a human readable version of \a error to \a debug.
*/

View File

@@ -37,7 +37,6 @@
QT_BEGIN_NAMESPACE
class QDebug;
class QmlErrorPrivate;
class QmlError
@@ -58,6 +57,8 @@ public:
void setLine(int);
int column() const;
void setColumn(int);
QObject *object() const;
void setObject(QObject *);
QString toString() const;
private:

View File

@@ -24,7 +24,7 @@
%parser QmlJSGrammar
%decl qmljsparser_p.h
%impl qmljsparser.cpp
%expect 2
%expect 5
%expect-rr 2
%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
@@ -65,8 +65,11 @@
--- context keywords.
%token T_PUBLIC "public"
%token T_IMPORT "import"
%token T_PRAGMA "pragma"
%token T_AS "as"
%token T_ON "on"
%token T_GET "get"
%token T_SET "set"
%token T_ERROR
@@ -79,7 +82,7 @@
%token T_FEED_JS_PROGRAM
%nonassoc SHIFT_THERE
%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY
%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET
%nonassoc REDUCE_HERE
%start TopLevel
@@ -125,16 +128,16 @@
**
****************************************************************************/
#include <QtCore/QtDebug>
#include <QtCore/QCoreApplication>
#include <string.h>
#include "qmljsengine_p.h"
#include "qmljslexer_p.h"
#include "qmljsast_p.h"
#include "qmljsmemorypool_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qcoreapplication.h>
#include <string.h>
./
/:/****************************************************************************
@@ -210,8 +213,8 @@
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
QT_QML_BEGIN_NAMESPACE
@@ -240,7 +243,8 @@ public:
AST::FunctionDeclaration *FunctionDeclaration;
AST::Node *Node;
AST::PropertyName *PropertyName;
AST::PropertyNameAndValueList *PropertyNameAndValueList;
AST::PropertyAssignment *PropertyAssignment;
AST::PropertyAssignmentList *PropertyAssignmentList;
AST::SourceElement *SourceElement;
AST::SourceElements *SourceElements;
AST::Statement *Statement;
@@ -250,7 +254,8 @@ public:
AST::VariableDeclarationList *VariableDeclarationList;
AST::UiProgram *UiProgram;
AST::UiImportList *UiImportList;
AST::UiHeaderItemList *UiHeaderItemList;
AST::UiPragma *UiPragma;
AST::UiImport *UiImport;
AST::UiParameterList *UiParameterList;
AST::UiPublicMember *UiPublicMember;
@@ -263,6 +268,7 @@ public:
AST::UiObjectMemberList *UiObjectMemberList;
AST::UiArrayMemberList *UiArrayMemberList;
AST::UiQualifiedId *UiQualifiedId;
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
};
public:
@@ -344,6 +350,7 @@ protected:
{ return location_stack [tos + index - 1]; }
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
protected:
Engine *driver;
@@ -388,7 +395,8 @@ protected:
/.
#include "qmljsparser_p.h"
#include <QVarLengthArray>
#include <QtCore/qvarlengtharray.h>
//
// W A R N I N G
@@ -482,6 +490,19 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
return 0;
}
AST::UiQualifiedPragmaId *Parser::reparseAsQualifiedPragmaId(AST::ExpressionNode *expr)
{
if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
AST::UiQualifiedPragmaId *q = new (pool) AST::UiQualifiedPragmaId(idExpr->name);
q->identifierToken = idExpr->identifierToken;
return q->finish();
}
return 0;
}
bool Parser::parse(int startToken)
{
Lexer *lexer = driver->lexer();
@@ -590,38 +611,62 @@ case $rule_number: {
} break;
./
UiProgram: UiImportListOpt UiRootMember ;
UiProgram: UiHeaderItemListOpt UiRootMember;
/.
case $rule_number: {
sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiHeaderItemList,
sym(2).UiObjectMemberList->finish());
} break;
./
UiImportListOpt: Empty ;
UiImportListOpt: UiImportList ;
UiHeaderItemListOpt: Empty ;
UiHeaderItemListOpt: UiHeaderItemList ;
/.
case $rule_number: {
sym(1).Node = sym(1).UiImportList->finish();
sym(1).Node = sym(1).UiHeaderItemList->finish();
} break;
./
UiImportList: UiImport ;
UiHeaderItemList: UiPragma ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
} break;
./
UiImportList: UiImportList UiImport ;
UiHeaderItemList: UiImport ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
} break;
./
UiHeaderItemList: UiHeaderItemList UiPragma ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiPragma);
} break;
./
UiHeaderItemList: UiHeaderItemList UiImport ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiImport);
} break;
./
PragmaId: MemberExpression ;
ImportId: MemberExpression ;
UiPragma: UiPragmaHead T_AUTOMATIC_SEMICOLON ;
UiPragma: UiPragmaHead T_SEMICOLON ;
/.
case $rule_number: {
sym(1).UiPragma->semicolonToken = loc(2);
} break;
./
UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
UiImport: UiImportHead T_SEMICOLON ;
/.
@@ -662,6 +707,28 @@ case $rule_number: {
} break;
./
UiPragmaHead: T_PRAGMA PragmaId ;
/.
case $rule_number: {
AST::UiPragma *node = 0;
if (AST::UiQualifiedPragmaId *qualifiedId = reparseAsQualifiedPragmaId(sym(2).Expression)) {
node = new (pool) AST::UiPragma(qualifiedId);
}
sym(1).Node = node;
if (node) {
node->pragmaToken = loc(1);
} else {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
QLatin1String("Expected a qualified name id")));
return false; // ### remove me
}
} break;
./
UiImportHead: T_IMPORT ImportId ;
/.
@@ -1043,6 +1110,8 @@ JsIdentifier: T_PROPERTY ;
JsIdentifier: T_SIGNAL ;
JsIdentifier: T_READONLY ;
JsIdentifier: T_ON ;
JsIdentifier: T_GET ;
JsIdentifier: T_SET ;
--------------------------------------------------------------------------------------------------------
-- Expressions
@@ -1219,13 +1288,13 @@ case $rule_number: {
-- } break;
-- ./
PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ;
PrimaryExpression: T_LBRACE PropertyAssignmentListOpt T_RBRACE ;
/.
case $rule_number: {
AST::ObjectLiteral *node = 0;
if (sym(2).Node)
node = new (pool) AST::ObjectLiteral(
sym(2).PropertyNameAndValueList->finish ());
sym(2).PropertyAssignmentList->finish ());
else
node = new (pool) AST::ObjectLiteral();
node->lbraceToken = loc(1);
@@ -1234,11 +1303,11 @@ case $rule_number: {
} break;
./
PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ;
PrimaryExpression: T_LBRACE PropertyAssignmentList T_COMMA T_RBRACE ;
/.
case $rule_number: {
AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
sym(2).PropertyNameAndValueList->finish ());
sym(2).PropertyAssignmentList->finish ());
node->lbraceToken = loc(1);
node->rbraceToken = loc(4);
sym(1).Node = node;
@@ -1255,6 +1324,7 @@ case $rule_number: {
} break;
./
UiQualifiedId: MemberExpression ;
/.
case $rule_number: {
@@ -1330,40 +1400,62 @@ case $rule_number: {
} break;
./
PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ;
PropertyAssignment: PropertyName T_COLON AssignmentExpression ;
/.
case $rule_number: {
AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
AST::PropertyNameAndValue *node = new (pool) AST::PropertyNameAndValue(
sym(1).PropertyName, sym(3).Expression);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ;
PropertyAssignment: T_GET PropertyName T_LPAREN T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
sym(2).PropertyName, sym(6).FunctionBody);
node->getSetToken = loc(1);
node->lparenToken = loc(3);
node->rparenToken = loc(4);
node->lbraceToken = loc(5);
node->rbraceToken = loc(7);
sym(1).Node = node;
} break;
./
PropertyAssignment: T_SET PropertyName T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
sym(2).PropertyName, sym(4).FormalParameterList, sym(7).FunctionBody);
node->getSetToken = loc(1);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
node->lbraceToken = loc(6);
node->rbraceToken = loc(8);
sym(1).Node = node;
} break;
./
PropertyAssignmentList: PropertyAssignment ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::PropertyAssignmentList(sym(1).PropertyAssignment);
} break;
./
PropertyAssignmentList: PropertyAssignmentList T_COMMA PropertyAssignment ;
/.
case $rule_number: {
AST::PropertyAssignmentList *node = new (pool) AST::PropertyAssignmentList(
sym(1).PropertyAssignmentList, sym(3).PropertyAssignment);
node->commaToken = loc(2);
node->colonToken = loc(4);
sym(1).Node = node;
} break;
./
PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
/.
case $rule_number: {
AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
./
PropertyName: T_SIGNAL ;
/.case $rule_number:./
PropertyName: T_PROPERTY ;
PropertyName: JsIdentifier %prec SHIFT_THERE ;
/.
case $rule_number: {
AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
@@ -2669,20 +2761,7 @@ case $rule_number: {
} break;
./
LabelledStatement: T_SIGNAL T_COLON Statement ;
/.case $rule_number:./
LabelledStatement: T_PROPERTY T_COLON Statement ;
/.
case $rule_number: {
AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
node->identifierToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
LabelledStatement: T_IDENTIFIER T_COLON Statement ;
LabelledStatement: JsIdentifier T_COLON Statement ;
/.
case $rule_number: {
AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
@@ -2762,7 +2841,12 @@ case $rule_number: {
} break;
./
FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
-- tell the parser to prefer function declarations to function expressions.
-- That is, the `Function' symbol is used to mark the start of a function
-- declaration.
Function: T_FUNCTION %prec REDUCE_HERE ;
FunctionDeclaration: Function JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
@@ -2776,7 +2860,7 @@ case $rule_number: {
} break;
./
FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
FunctionExpression: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
@@ -2791,6 +2875,19 @@ case $rule_number: {
} break;
./
FunctionExpression: T_FUNCTION T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
node->lbraceToken = loc(5);
node->rbraceToken = loc(7);
sym(1).Node = node;
} break;
./
FormalParameterList: JsIdentifier ;
/.
case $rule_number: {
@@ -2877,23 +2974,14 @@ case $rule_number: {
} break;
./
IdentifierOpt: ;
/.
case $rule_number: {
stringRef(1) = QStringRef();
} break;
./
IdentifierOpt: JsIdentifier ;
PropertyNameAndValueListOpt: ;
PropertyAssignmentListOpt: ;
/.
case $rule_number: {
sym(1).Node = 0;
} break;
./
PropertyNameAndValueListOpt: PropertyNameAndValueList ;
PropertyAssignmentListOpt: PropertyAssignmentList ;
/.
} // switch

View File

@@ -201,12 +201,32 @@ void Elision::accept0(Visitor *visitor)
visitor->endVisit(this);
}
void PropertyNameAndValueList::accept0(Visitor *visitor)
void PropertyNameAndValue::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
for (PropertyNameAndValueList *it = this; it; it = it->next) {
accept(it->name, visitor);
accept(it->value, visitor);
accept(name, visitor);
accept(value, visitor);
}
visitor->endVisit(this);
}
void PropertyGetterSetter::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(name, visitor);
accept(formals, visitor);
accept(functionBody, visitor);
}
visitor->endVisit(this);
}
void PropertyAssignmentList::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
for (PropertyAssignmentList *it = this; it; it = it->next) {
accept(it->assignment, visitor);
}
}
@@ -789,7 +809,7 @@ void DebuggerStatement::accept0(Visitor *visitor)
void UiProgram::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(imports, visitor);
accept(headers, visitor);
accept(members, visitor);
}
@@ -900,16 +920,34 @@ void UiImport::accept0(Visitor *visitor)
visitor->endVisit(this);
}
void UiImportList::accept0(Visitor *visitor)
void UiQualifiedPragmaId::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(import, visitor);
}
visitor->endVisit(this);
}
void UiPragma::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(pragmaType, visitor);
}
visitor->endVisit(this);
}
void UiHeaderItemList::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(headerItem, visitor);
accept(next, visitor);
}
visitor->endVisit(this);
}
void UiSourceElement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {

View File

@@ -45,7 +45,7 @@
#include "qmljsglobal_p.h"
#include "qmljsmemorypool_p.h"
#include <QtCore/QString>
#include <QtCore/qstring.h>
QT_QML_BEGIN_NAMESPACE
@@ -164,8 +164,10 @@ public:
Kind_PreDecrementExpression,
Kind_PreIncrementExpression,
Kind_Program,
Kind_PropertyAssignmentList,
Kind_PropertyGetterSetter,
Kind_PropertyName,
Kind_PropertyNameAndValueList,
Kind_PropertyNameAndValue,
Kind_RegExpLiteral,
Kind_ReturnStatement,
Kind_SourceElement,
@@ -193,18 +195,20 @@ public:
Kind_UiArrayBinding,
Kind_UiImport,
Kind_UiImportList,
Kind_UiObjectBinding,
Kind_UiObjectDefinition,
Kind_UiObjectInitializer,
Kind_UiObjectMemberList,
Kind_UiArrayMemberList,
Kind_UiPragma,
Kind_UiProgram,
Kind_UiParameterList,
Kind_UiPublicMember,
Kind_UiQualifiedId,
Kind_UiQualifiedPragmaId,
Kind_UiScriptBinding,
Kind_UiSourceElement
Kind_UiSourceElement,
Kind_UiHeaderItemList
};
inline Node()
@@ -475,7 +479,7 @@ public:
ObjectLiteral():
properties (0) { kind = K; }
ObjectLiteral(PropertyNameAndValueList *plist):
ObjectLiteral(PropertyAssignmentList *plist):
properties (plist) { kind = K; }
virtual void accept0(Visitor *visitor);
@@ -487,7 +491,7 @@ public:
{ return rbraceToken; }
// attributes
PropertyNameAndValueList *properties;
PropertyAssignmentList *properties;
SourceLocation lbraceToken;
SourceLocation rbraceToken;
};
@@ -591,50 +595,113 @@ public:
SourceLocation propertyNameToken;
};
class QML_PARSER_EXPORT PropertyNameAndValueList: public Node
class QML_PARSER_EXPORT PropertyAssignment: public Node
{
public:
QMLJS_DECLARE_AST_NODE(PropertyNameAndValueList)
PropertyAssignment() {}
};
PropertyNameAndValueList(PropertyName *n, ExpressionNode *v):
name (n), value (v), next (this)
{ kind = K; }
class QML_PARSER_EXPORT PropertyAssignmentList: public Node
{
public:
QMLJS_DECLARE_AST_NODE(PropertyAssignmentList)
PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v):
name (n), value (v)
PropertyAssignmentList(PropertyAssignment *assignment)
: assignment(assignment)
, next(this)
{ kind = K; }
PropertyAssignmentList(PropertyAssignmentList *previous, PropertyAssignment *assignment)
: assignment(assignment)
{
kind = K;
next = previous->next;
previous->next = this;
}
inline PropertyAssignmentList *finish ()
{
PropertyAssignmentList *front = next;
next = 0;
return front;
}
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return assignment->firstSourceLocation(); }
virtual SourceLocation lastSourceLocation() const
{ return next ? next->lastSourceLocation() : assignment->lastSourceLocation(); }
// attributes
PropertyAssignment *assignment;
PropertyAssignmentList *next;
SourceLocation commaToken;
};
class QML_PARSER_EXPORT PropertyNameAndValue: public PropertyAssignment
{
public:
QMLJS_DECLARE_AST_NODE(PropertyNameAndValue)
PropertyNameAndValue(PropertyName *n, ExpressionNode *v)
: name(n), value(v)
{ kind = K; }
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return name->firstSourceLocation(); }
virtual SourceLocation lastSourceLocation() const
{
if (next)
return next->lastSourceLocation();
return value->lastSourceLocation();
}
inline PropertyNameAndValueList *finish ()
{
PropertyNameAndValueList *front = next;
next = 0;
return front;
}
{ return value->lastSourceLocation(); }
// attributes
PropertyName *name;
ExpressionNode *value;
PropertyNameAndValueList *next;
SourceLocation colonToken;
ExpressionNode *value;
SourceLocation commaToken;
};
class QML_PARSER_EXPORT PropertyGetterSetter: public PropertyAssignment
{
public:
QMLJS_DECLARE_AST_NODE(PropertyGetterSetter)
enum Type {
Getter,
Setter
};
PropertyGetterSetter(PropertyName *n, FunctionBody *b)
: type(Getter), name(n), formals(0), functionBody (b)
{ kind = K; }
PropertyGetterSetter(PropertyName *n, FormalParameterList *f, FunctionBody *b)
: type(Setter), name(n), formals(f), functionBody (b)
{ kind = K; }
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return getSetToken; }
virtual SourceLocation lastSourceLocation() const
{ return rbraceToken; }
// attributes
Type type;
SourceLocation getSetToken;
PropertyName *name;
SourceLocation lparenToken;
FormalParameterList *formals;
SourceLocation rparenToken;
SourceLocation lbraceToken;
FunctionBody *functionBody;
SourceLocation rbraceToken;
};
class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
{
public:
@@ -2194,44 +2261,6 @@ public:
SourceLocation semicolonToken;
};
class QML_PARSER_EXPORT UiImportList: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiImportList)
UiImportList(UiImport *import)
: import(import),
next(this)
{ kind = K; }
UiImportList(UiImportList *previous, UiImport *import)
: import(import)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiImportList *finish()
{
UiImportList *head = next;
next = 0;
return head;
}
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return import->firstSourceLocation(); }
virtual SourceLocation lastSourceLocation() const
{ return next ? next->lastSourceLocation() : import->lastSourceLocation(); }
// attributes
UiImport *import;
UiImportList *next;
};
class QML_PARSER_EXPORT UiObjectMember: public Node
{
public:
@@ -2278,21 +2307,131 @@ public:
UiObjectMember *member;
};
class QML_PARSER_EXPORT UiQualifiedPragmaId: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiQualifiedPragmaId)
UiQualifiedPragmaId(const QStringRef &name)
: next(this), name(name)
{ kind = K; }
UiQualifiedPragmaId(UiQualifiedPragmaId *previous, const QStringRef &name)
: name(name)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiQualifiedPragmaId *finish()
{
UiQualifiedPragmaId *head = next;
next = 0;
return head;
}
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return identifierToken; }
virtual SourceLocation lastSourceLocation() const
{ return next ? next->lastSourceLocation() : identifierToken; }
// attributes
UiQualifiedPragmaId *next;
QStringRef name;
SourceLocation identifierToken;
};
class QML_PARSER_EXPORT UiPragma: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiPragma)
UiPragma(UiQualifiedPragmaId *type)
: pragmaType(type)
{ kind = K; }
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return pragmaToken; }
virtual SourceLocation lastSourceLocation() const
{ return semicolonToken; }
// attributes
UiQualifiedPragmaId *pragmaType;
SourceLocation pragmaToken;
SourceLocation semicolonToken;
};
class QML_PARSER_EXPORT UiHeaderItemList: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiHeaderItemList)
UiHeaderItemList(UiImport *import)
: headerItem(import), next(this)
{ kind = K; }
UiHeaderItemList(UiPragma *pragma)
: headerItem(pragma), next(this)
{ kind = K; }
UiHeaderItemList(UiHeaderItemList *previous, UiImport *import)
: headerItem(import)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiHeaderItemList(UiHeaderItemList *previous, UiPragma *pragma)
: headerItem(pragma)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiHeaderItemList *finish()
{
UiHeaderItemList *head = next;
next = 0;
return head;
}
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{ return headerItem->firstSourceLocation(); }
virtual SourceLocation lastSourceLocation() const
{ return next ? next->lastSourceLocation() : headerItem->lastSourceLocation(); }
// attributes
Node *headerItem;
UiHeaderItemList *next;
};
class QML_PARSER_EXPORT UiProgram: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiProgram)
UiProgram(UiImportList *imports, UiObjectMemberList *members)
: imports(imports), members(members)
UiProgram(UiHeaderItemList *headers, UiObjectMemberList *members)
: headers(headers), members(members)
{ kind = K; }
virtual void accept0(Visitor *visitor);
virtual SourceLocation firstSourceLocation() const
{
if (imports)
return imports->firstSourceLocation();
if (headers)
return headers->firstSourceLocation();
else if (members)
return members->firstSourceLocation();
return SourceLocation();
@@ -2302,13 +2441,13 @@ public:
{
if (members)
return members->lastSourceLocation();
else if (imports)
return imports->lastSourceLocation();
else if (headers)
return headers->lastSourceLocation();
return SourceLocation();
}
// attributes
UiImportList *imports;
UiHeaderItemList *headers;
UiObjectMemberList *members;
};

View File

@@ -86,7 +86,9 @@ class ArrayLiteral;
class ObjectLiteral;
class ElementList;
class Elision;
class PropertyNameAndValueList;
class PropertyAssignmentList;
class PropertyGetterSetter;
class PropertyNameAndValue;
class PropertyName;
class IdentifierPropertyName;
class StringLiteralPropertyName;
@@ -153,7 +155,7 @@ class NestedExpression;
// ui elements
class UiProgram;
class UiImportList;
class UiPragma;
class UiImport;
class UiPublicMember;
class UiParameterList;
@@ -167,6 +169,8 @@ class UiObjectMember;
class UiObjectMemberList;
class UiArrayMemberList;
class UiQualifiedId;
class UiQualifiedPragmaId;
class UiHeaderItemList;
} } // namespace AST

View File

@@ -59,7 +59,8 @@ public:
// Ui
virtual bool visit(UiProgram *) { return true; }
virtual bool visit(UiImportList *) { return true; }
virtual bool visit(UiHeaderItemList *) { return true; }
virtual bool visit(UiPragma *) { return true; }
virtual bool visit(UiImport *) { return true; }
virtual bool visit(UiPublicMember *) { return true; }
virtual bool visit(UiSourceElement *) { return true; }
@@ -72,10 +73,12 @@ public:
virtual bool visit(UiObjectMemberList *) { return true; }
virtual bool visit(UiArrayMemberList *) { return true; }
virtual bool visit(UiQualifiedId *) { return true; }
virtual bool visit(UiQualifiedPragmaId *) { return true; }
virtual void endVisit(UiProgram *) {}
virtual void endVisit(UiImportList *) {}
virtual void endVisit(UiImport *) {}
virtual void endVisit(UiHeaderItemList *) {}
virtual void endVisit(UiPragma *) {}
virtual void endVisit(UiPublicMember *) {}
virtual void endVisit(UiSourceElement *) {}
virtual void endVisit(UiObjectDefinition *) {}
@@ -87,6 +90,7 @@ public:
virtual void endVisit(UiObjectMemberList *) {}
virtual void endVisit(UiArrayMemberList *) {}
virtual void endVisit(UiQualifiedId *) {}
virtual void endVisit(UiQualifiedPragmaId *) {}
// QmlJS
virtual bool visit(ThisExpression *) { return true; }
@@ -125,8 +129,14 @@ public:
virtual bool visit(Elision *) { return true; }
virtual void endVisit(Elision *) {}
virtual bool visit(PropertyNameAndValueList *) { return true; }
virtual void endVisit(PropertyNameAndValueList *) {}
virtual bool visit(PropertyAssignmentList *) { return true; }
virtual void endVisit(PropertyAssignmentList *) {}
virtual bool visit(PropertyNameAndValue *) { return true; }
virtual void endVisit(PropertyNameAndValue *) {}
virtual bool visit(PropertyGetterSetter *) { return true; }
virtual void endVisit(PropertyGetterSetter *) {}
virtual bool visit(NestedExpression *) { return true; }
virtual void endVisit(NestedExpression *) {}

View File

@@ -30,15 +30,15 @@
#include "qmljsengine_p.h"
#include "qmljsglobal_p.h"
#include <qnumeric.h>
#include <QHash>
#include <QDebug>
#include <QtCore/qnumeric.h>
#include <QtCore/qhash.h>
#include <QtCore/qdebug.h>
QT_QML_BEGIN_NAMESPACE
namespace QmlJS {
static int toDigit(char c)
static inline int toDigit(char c)
{
if ((c >= '0') && (c <= '9'))
return c - '0';

View File

@@ -91,6 +91,7 @@ public:
~Engine();
void setCode(const QString &code);
const QString &code() const { return _code; }
void addComment(int pos, int len, int line, int col);
QList<AST::SourceLocation> comments() const;

View File

@@ -49,8 +49,10 @@
# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
// QmlDevTools is a static library
# define QML_PARSER_EXPORT
# else
# elif defined(QT_BUILD_QML_LIB)
# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
# else
# define QML_PARSER_EXPORT
# endif
#endif // QT_CREATOR

File diff suppressed because it is too large Load Diff

View File

@@ -52,12 +52,12 @@ class QML_PARSER_EXPORT QmlJSGrammar
public:
enum VariousConstants {
EOF_SYMBOL = 0,
REDUCE_HERE = 102,
SHIFT_THERE = 101,
REDUCE_HERE = 105,
SHIFT_THERE = 104,
T_AND = 1,
T_AND_AND = 2,
T_AND_EQ = 3,
T_AS = 92,
T_AS = 93,
T_AUTOMATIC_SEMICOLON = 62,
T_BREAK = 4,
T_CASE = 5,
@@ -79,18 +79,19 @@ public:
T_EQ = 17,
T_EQ_EQ = 18,
T_EQ_EQ_EQ = 19,
T_ERROR = 94,
T_ERROR = 97,
T_FALSE = 83,
T_FEED_JS_EXPRESSION = 98,
T_FEED_JS_PROGRAM = 100,
T_FEED_JS_SOURCE_ELEMENT = 99,
T_FEED_JS_STATEMENT = 97,
T_FEED_UI_OBJECT_MEMBER = 96,
T_FEED_UI_PROGRAM = 95,
T_FEED_JS_EXPRESSION = 101,
T_FEED_JS_PROGRAM = 103,
T_FEED_JS_SOURCE_ELEMENT = 102,
T_FEED_JS_STATEMENT = 100,
T_FEED_UI_OBJECT_MEMBER = 99,
T_FEED_UI_PROGRAM = 98,
T_FINALLY = 20,
T_FOR = 21,
T_FUNCTION = 22,
T_GE = 23,
T_GET = 95,
T_GT = 24,
T_GT_GT = 25,
T_GT_GT_EQ = 26,
@@ -118,13 +119,14 @@ public:
T_NOT_EQ_EQ = 46,
T_NULL = 81,
T_NUMERIC_LITERAL = 47,
T_ON = 93,
T_ON = 94,
T_OR = 48,
T_OR_EQ = 49,
T_OR_OR = 50,
T_PLUS = 51,
T_PLUS_EQ = 52,
T_PLUS_PLUS = 53,
T_PRAGMA = 92,
T_PROPERTY = 66,
T_PUBLIC = 90,
T_QUESTION = 54,
@@ -137,6 +139,7 @@ public:
T_RETURN = 59,
T_RPAREN = 60,
T_SEMICOLON = 61,
T_SET = 96,
T_SIGNAL = 67,
T_STAR = 63,
T_STAR_EQ = 64,
@@ -155,15 +158,15 @@ public:
T_XOR = 79,
T_XOR_EQ = 80,
ACCEPT_STATE = 645,
RULE_COUNT = 350,
STATE_COUNT = 646,
TERMINAL_COUNT = 103,
NON_TERMINAL_COUNT = 107,
ACCEPT_STATE = 663,
RULE_COUNT = 357,
STATE_COUNT = 664,
TERMINAL_COUNT = 106,
NON_TERMINAL_COUNT = 111,
GOTO_INDEX_OFFSET = 646,
GOTO_INFO_OFFSET = 3019,
GOTO_CHECK_OFFSET = 3019
GOTO_INDEX_OFFSET = 664,
GOTO_INFO_OFFSET = 3104,
GOTO_CHECK_OFFSET = 3104
};
static const char *const spell [];

View File

@@ -41,6 +41,12 @@
// We mean it.
//
#include "qmljslexer_p.h"
QT_QML_BEGIN_NAMESPACE
namespace QmlJS {
// Note on the int() casts in the following code:
// they casts values from Lexer's anonymous enum (aliasing some of the inherited
// QmlJSGrammar::VariousConstants) to int when used with inherited values of the
@@ -82,10 +88,17 @@ static inline int classify3(const QChar *s, bool qmlMode) {
}
}
}
else if (s[0].unicode() == 'g') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 't') {
return Lexer::T_GET;
}
}
}
else if (s[0].unicode() == 'i') {
if (s[1].unicode() == 'n') {
if (s[2].unicode() == 't') {
return qmlMode ? int(Lexer::T_INT) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_INT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -96,6 +109,13 @@ static inline int classify3(const QChar *s, bool qmlMode) {
}
}
}
else if (s[0].unicode() == 's') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 't') {
return Lexer::T_SET;
}
}
}
else if (s[0].unicode() == 't') {
if (s[1].unicode() == 'r') {
if (s[2].unicode() == 'y') {
@@ -118,7 +138,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
if (s[1].unicode() == 'y') {
if (s[2].unicode() == 't') {
if (s[3].unicode() == 'e') {
return qmlMode ? int(Lexer::T_BYTE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_BYTE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -134,7 +154,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
else if (s[1].unicode() == 'h') {
if (s[2].unicode() == 'a') {
if (s[3].unicode() == 'r') {
return qmlMode ? int(Lexer::T_CHAR) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_CHAR) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -159,7 +179,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 't') {
if (s[3].unicode() == 'o') {
return qmlMode ? int(Lexer::T_GOTO) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_GOTO) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -168,7 +188,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 'g') {
return qmlMode ? int(Lexer::T_LONG) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_LONG) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -254,7 +274,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 's') {
if (s[4].unicode() == 't') {
return qmlMode ? Lexer::T_CONST : Lexer::T_RESERVED_WORD;
return qmlMode ? int(Lexer::T_CONST) : int(Lexer::T_RESERVED_WORD);
}
}
}
@@ -274,7 +294,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 'a') {
if (s[4].unicode() == 'l') {
return qmlMode ? int(Lexer::T_FINAL) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_FINAL) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -283,7 +303,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'o') {
if (s[3].unicode() == 'a') {
if (s[4].unicode() == 't') {
return qmlMode ? int(Lexer::T_FLOAT) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_FLOAT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -294,7 +314,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'o') {
if (s[3].unicode() == 'r') {
if (s[4].unicode() == 't') {
return qmlMode ? int(Lexer::T_SHORT) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_SHORT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -303,7 +323,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'p') {
if (s[3].unicode() == 'e') {
if (s[4].unicode() == 'r') {
return qmlMode ? int(Lexer::T_SUPER) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_SUPER) : int(Lexer::T_RESERVED_WORD);
}
}
}
@@ -352,7 +372,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'b') {
if (s[4].unicode() == 'l') {
if (s[5].unicode() == 'e') {
return qmlMode ? int(Lexer::T_DOUBLE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_DOUBLE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -378,7 +398,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'o') {
if (s[4].unicode() == 'r') {
if (s[5].unicode() == 't') {
return qmlMode ? Lexer::T_IMPORT : Lexer::T_RESERVED_WORD;
return qmlMode ? int(Lexer::T_IMPORT) : int(Lexer::T_RESERVED_WORD);
}
}
}
@@ -391,7 +411,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'i') {
if (s[4].unicode() == 'v') {
if (s[5].unicode() == 'e') {
return qmlMode ? int(Lexer::T_NATIVE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_NATIVE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -410,6 +430,17 @@ static inline int classify6(const QChar *s, bool qmlMode) {
}
}
}
else if (s[1].unicode() == 'r') {
if (s[2].unicode() == 'a') {
if (s[3].unicode() == 'g') {
if (s[4].unicode() == 'm') {
if (s[5].unicode() == 'a') {
return qmlMode ? Lexer::T_PRAGMA : Lexer::T_IDENTIFIER;
}
}
}
}
}
}
else if (s[0].unicode() == 'r') {
if (s[1].unicode() == 'e') {
@@ -441,7 +472,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 't') {
if (s[4].unicode() == 'i') {
if (s[5].unicode() == 'c') {
return qmlMode ? int(Lexer::T_STATIC) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_STATIC) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -465,7 +496,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'o') {
if (s[4].unicode() == 'w') {
if (s[5].unicode() == 's') {
return qmlMode ? int(Lexer::T_THROWS) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_THROWS) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -494,7 +525,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'e') {
if (s[5].unicode() == 'a') {
if (s[6].unicode() == 'n') {
return qmlMode ? int(Lexer::T_BOOLEAN) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_BOOLEAN) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -554,7 +585,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'a') {
if (s[5].unicode() == 'g') {
if (s[6].unicode() == 'e') {
return qmlMode ? int(Lexer::T_PACKAGE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_PACKAGE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -567,7 +598,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'a') {
if (s[5].unicode() == 't') {
if (s[6].unicode() == 'e') {
return qmlMode ? int(Lexer::T_PRIVATE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_PRIVATE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -587,7 +618,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
if (s[5].unicode() == 'a') {
if (s[6].unicode() == 'c') {
if (s[7].unicode() == 't') {
return qmlMode ? int(Lexer::T_ABSTRACT) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_ABSTRACT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -689,7 +720,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
if (s[5].unicode() == 'i') {
if (s[6].unicode() == 'l') {
if (s[7].unicode() == 'e') {
return qmlMode ? int(Lexer::T_VOLATILE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_VOLATILE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -711,7 +742,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 'a') {
if (s[7].unicode() == 'c') {
if (s[8].unicode() == 'e') {
return qmlMode ? int(Lexer::T_INTERFACE) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_INTERFACE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -730,7 +761,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 't') {
if (s[7].unicode() == 'e') {
if (s[8].unicode() == 'd') {
return qmlMode ? int(Lexer::T_PROTECTED) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_PROTECTED) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -749,7 +780,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 'e') {
if (s[7].unicode() == 'n') {
if (s[8].unicode() == 't') {
return qmlMode ? int(Lexer::T_TRANSIENT) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_TRANSIENT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -773,7 +804,7 @@ static inline int classify10(const QChar *s, bool qmlMode) {
if (s[7].unicode() == 'n') {
if (s[8].unicode() == 't') {
if (s[9].unicode() == 's') {
return qmlMode ? int(Lexer::T_IMPLEMENTS) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_IMPLEMENTS) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -819,7 +850,7 @@ static inline int classify12(const QChar *s, bool qmlMode) {
if (s[9].unicode() == 'z') {
if (s[10].unicode() == 'e') {
if (s[11].unicode() == 'd') {
return qmlMode ? int(Lexer::T_SYNCHRONIZED) : Lexer::T_IDENTIFIER;
return qmlMode ? int(Lexer::T_SYNCHRONIZED) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -851,4 +882,8 @@ int Lexer::classify(const QChar *s, int n, bool qmlMode) {
} // switch
}
} // namespace QmlJS
QT_QML_END_NAMESPACE
#endif // QMLJSKEYWORDS_P_H

View File

@@ -30,10 +30,11 @@
#include "qmljslexer_p.h"
#include "qmljsengine_p.h"
#include "qmljsmemorypool_p.h"
#include "qmljskeywords_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QVarLengthArray>
#include <QtCore/QDebug>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
@@ -41,7 +42,7 @@ QT_END_NAMESPACE
using namespace QmlJS;
static int regExpFlagFromChar(const QChar &ch)
static inline int regExpFlagFromChar(const QChar &ch)
{
switch (ch.unicode()) {
case 'g': return Lexer::RegExp_Global;
@@ -51,7 +52,7 @@ static int regExpFlagFromChar(const QChar &ch)
return 0;
}
static unsigned char convertHex(ushort c)
static inline unsigned char convertHex(ushort c)
{
if (c >= '0' && c <= '9')
return (c - '0');
@@ -61,12 +62,12 @@ static unsigned char convertHex(ushort c)
return (c - 'A' + 10);
}
static QChar convertHex(QChar c1, QChar c2)
static inline QChar convertHex(QChar c1, QChar c2)
{
return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
}
static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
static inline QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
{
return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
(convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
@@ -124,6 +125,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_tokenSpell = QStringRef();
_codePtr = code.unicode();
_endPtr = _codePtr + code.length();
_lastLinePtr = _codePtr;
_tokenLinePtr = _codePtr;
_tokenStartPtr = _codePtr;
@@ -165,6 +167,52 @@ void Lexer::scanChar()
}
}
namespace {
inline bool isBinop(int tok)
{
switch (tok) {
case Lexer::T_AND:
case Lexer::T_AND_AND:
case Lexer::T_AND_EQ:
case Lexer::T_DIVIDE_:
case Lexer::T_DIVIDE_EQ:
case Lexer::T_EQ:
case Lexer::T_EQ_EQ:
case Lexer::T_EQ_EQ_EQ:
case Lexer::T_GE:
case Lexer::T_GT:
case Lexer::T_GT_GT:
case Lexer::T_GT_GT_EQ:
case Lexer::T_GT_GT_GT:
case Lexer::T_GT_GT_GT_EQ:
case Lexer::T_LE:
case Lexer::T_LT:
case Lexer::T_LT_LT:
case Lexer::T_LT_LT_EQ:
case Lexer::T_MINUS:
case Lexer::T_MINUS_EQ:
case Lexer::T_NOT_EQ:
case Lexer::T_NOT_EQ_EQ:
case Lexer::T_OR:
case Lexer::T_OR_EQ:
case Lexer::T_OR_OR:
case Lexer::T_PLUS:
case Lexer::T_PLUS_EQ:
case Lexer::T_REMAINDER:
case Lexer::T_REMAINDER_EQ:
case Lexer::T_RETURN:
case Lexer::T_STAR:
case Lexer::T_STAR_EQ:
case Lexer::T_XOR:
case Lexer::T_XOR_EQ:
return true;
default:
return false;
}
}
} // anonymous namespace
int Lexer::lex()
{
const int previousTokenKind = _tokenKind;
@@ -181,9 +229,15 @@ int Lexer::lex()
switch (_tokenKind) {
case T_LBRACE:
case T_SEMICOLON:
case T_QUESTION:
case T_COLON:
case T_TILDE:
_delimited = true;
break;
default:
if (isBinop(_tokenKind))
_delimited = true;
break;
case T_IF:
case T_FOR:
@@ -193,6 +247,7 @@ int Lexer::lex()
_parenthesesCount = 0;
break;
case T_ELSE:
case T_DO:
_parenthesesState = BalancedParentheses;
break;
@@ -221,7 +276,8 @@ int Lexer::lex()
break;
case BalancedParentheses:
_parenthesesState = IgnoreParentheses;
if (_tokenKind != T_DO && _tokenKind != T_ELSE)
_parenthesesState = IgnoreParentheses;
break;
} // switch
@@ -263,6 +319,80 @@ QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
return QChar();
}
QChar Lexer::decodeHexEscapeCharacter(bool *ok)
{
if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
scanChar();
const QChar c1 = _char;
scanChar();
const QChar c2 = _char;
scanChar();
if (ok)
*ok = true;
return convertHex(c1, c2);
}
*ok = false;
return QChar();
}
static inline bool isIdentifierStart(QChar ch)
{
// fast path for ascii
if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
(ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
ch == QLatin1Char('$') || ch == QLatin1Char('_'))
return true;
switch (ch.category()) {
case QChar::Number_Letter:
case QChar::Letter_Uppercase:
case QChar::Letter_Lowercase:
case QChar::Letter_Titlecase:
case QChar::Letter_Modifier:
case QChar::Letter_Other:
return true;
default:
break;
}
return false;
}
static bool isIdentifierPart(QChar ch)
{
// fast path for ascii
if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
(ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
(ch.unicode() >= '0' && ch.unicode() <= '9') ||
ch == QLatin1Char('$') || ch == QLatin1Char('_') ||
ch.unicode() == 0x200c /* ZWNJ */ || ch.unicode() == 0x200d /* ZWJ */)
return true;
switch (ch.category()) {
case QChar::Mark_NonSpacing:
case QChar::Mark_SpacingCombining:
case QChar::Number_DecimalDigit:
case QChar::Number_Letter:
case QChar::Letter_Uppercase:
case QChar::Letter_Lowercase:
case QChar::Letter_Titlecase:
case QChar::Letter_Modifier:
case QChar::Letter_Other:
case QChar::Punctuation_Connector:
return true;
default:
break;
}
return false;
}
int Lexer::scanToken()
{
if (_stackToken != -1) {
@@ -298,7 +428,7 @@ again:
_tokenStartPtr = _codePtr - 1;
_tokenLine = _currentLineNumber;
if (_char.isNull())
if (_codePtr > _endPtr)
return EOF_SYMBOL;
const QChar ch = _char;
@@ -383,7 +513,7 @@ again:
case '/':
if (_char == QLatin1Char('*')) {
scanChar();
while (!_char.isNull()) {
while (_codePtr <= _endPtr) {
if (_char == QLatin1Char('*')) {
scanChar();
if (_char == QLatin1Char('/')) {
@@ -401,7 +531,7 @@ again:
}
}
} else if (_char == QLatin1Char('/')) {
while (!_char.isNull() && !isLineTerminator()) {
while (_codePtr <= _endPtr && !isLineTerminator()) {
scanChar();
}
if (_engine) {
@@ -543,8 +673,14 @@ again:
const QChar *startCode = _codePtr;
if (_engine) {
while (!_char.isNull()) {
if (isLineTerminator() || _char == QLatin1Char('\\')) {
while (_codePtr <= _endPtr) {
if (isLineTerminator()) {
if (qmlMode())
break;
_errorCode = IllegalCharacter;
_errorMessage = QCoreApplication::translate("QmlParser", "Stray newline in string literal");
return T_ERROR;
} else if (_char == QLatin1Char('\\')) {
break;
} else if (_char == quote) {
_tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
@@ -562,7 +698,7 @@ again:
while (startCode != _codePtr - 1)
_tokenText += *startCode++;
while (! _char.isNull()) {
while (_codePtr <= _endPtr) {
if (unsigned sequenceLength = isLineTerminatorSequence()) {
multilineStringLiteral = true;
_tokenText += _char;
@@ -580,32 +716,29 @@ again:
scanChar();
QChar u;
bool ok = false;
switch (_char.unicode()) {
// unicode escape sequence
case 'u':
case 'u': {
bool ok = false;
u = decodeUnicodeEscapeCharacter(&ok);
if (! ok)
u = _char;
break;
if (! ok) {
_errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
return T_ERROR;
}
} break;
// hex escape sequence
case 'x':
if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
scanChar();
const QChar c1 = _char;
scanChar();
const QChar c2 = _char;
scanChar();
u = convertHex(c1, c2);
} else {
u = _char;
case 'x': {
bool ok = false;
u = decodeHexEscapeCharacter(&ok);
if (!ok) {
_errorCode = IllegalHexadecimalEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Illegal hexadecimal escape sequence");
return T_ERROR;
}
break;
} break;
// single character escape sequence
case '\\': u = QLatin1Char('\\'); scanChar(); break;
@@ -619,32 +752,31 @@ again:
case 'v': u = QLatin1Char('\v'); scanChar(); break;
case '0':
if (! _codePtr[1].isDigit()) {
if (! _codePtr->isDigit()) {
scanChar();
u = QLatin1Char('\0');
} else {
// ### parse deprecated octal escape sequence ?
u = _char;
break;
}
break;
// fall through
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
_errorCode = IllegalEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Octal escape sequences are not allowed");
return T_ERROR;
case '\r':
if (isLineTerminatorSequence() == 2) {
_tokenText += QLatin1Char('\r');
u = QLatin1Char('\n');
} else {
u = QLatin1Char('\r');
}
scanChar();
break;
case '\n':
case 0x2028u:
case 0x2029u:
u = _char;
scanChar();
break;
continue;
default:
// non escape character
@@ -675,28 +807,28 @@ again:
case '9':
return scanNumber(ch);
default:
if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
bool identifierWithEscapeChars = false;
if (ch == QLatin1Char('\\')) {
identifierWithEscapeChars = true;
default: {
QChar c = ch;
bool identifierWithEscapeChars = false;
if (c == QLatin1Char('\\') && _char == QLatin1Char('u')) {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
if (! ok) {
_errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
return T_ERROR;
}
}
if (isIdentifierStart(c)) {
if (identifierWithEscapeChars) {
_tokenText.resize(0);
bool ok = false;
_tokenText += decodeUnicodeEscapeCharacter(&ok);
_tokenText += c;
_validTokenText = true;
if (! ok) {
_errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
return T_ERROR;
}
}
while (true) {
if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
if (identifierWithEscapeChars)
_tokenText += _char;
scanChar();
} else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
c = _char;
if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
if (! identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
@@ -706,31 +838,41 @@ again:
scanChar(); // skip '\\'
bool ok = false;
_tokenText += decodeUnicodeEscapeCharacter(&ok);
c = decodeUnicodeEscapeCharacter(&ok);
if (! ok) {
_errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
return T_ERROR;
}
} else {
_tokenLength = _codePtr - _tokenStartPtr - 1;
if (isIdentifierPart(c))
_tokenText += c;
continue;
} else if (isIdentifierPart(c)) {
if (identifierWithEscapeChars)
_tokenText += c;
int kind = T_IDENTIFIER;
if (! identifierWithEscapeChars)
kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
if (_engine) {
if (kind == T_IDENTIFIER && identifierWithEscapeChars)
_tokenSpell = _engine->newStringRef(_tokenText);
else
_tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
}
return kind;
scanChar();
continue;
}
_tokenLength = _codePtr - _tokenStartPtr - 1;
int kind = T_IDENTIFIER;
if (! identifierWithEscapeChars)
kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
if (_engine) {
if (kind == T_IDENTIFIER && identifierWithEscapeChars)
_tokenSpell = _engine->newStringRef(_tokenText);
else
_tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
}
return kind;
}
}
}
break;
}
@@ -741,12 +883,14 @@ again:
int Lexer::scanNumber(QChar ch)
{
if (ch != QLatin1Char('0')) {
double integer = ch.unicode() - '0';
QByteArray buf;
buf.reserve(64);
buf += ch.toLatin1();
QChar n = _char;
const QChar *code = _codePtr;
while (n.isDigit()) {
integer = integer * 10 + (n.unicode() - '0');
buf += n.toLatin1();
n = *code++;
}
@@ -755,17 +899,23 @@ int Lexer::scanNumber(QChar ch)
_codePtr = code - 1;
scanChar();
}
_tokenValue = integer;
buf.append('\0');
_tokenValue = strtod(buf.constData(), 0);
return T_NUMERIC_LITERAL;
}
} else if (_char.isDigit() && !qmlMode()) {
_errorCode = IllegalCharacter;
_errorMessage = QCoreApplication::translate("QmlParser", "Decimal numbers can't start with '0'");
return T_ERROR;
}
QVarLengthArray<char,32> chars;
chars.append(ch.unicode());
if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
// parse hex integer literal
ch = _char; // remember the x or X to use it in the error message below.
// parse hex integer literal
chars.append(_char.unicode());
scanChar(); // consume `x'
@@ -774,6 +924,12 @@ int Lexer::scanNumber(QChar ch)
scanChar();
}
if (chars.size() < 3) {
_errorCode = IllegalHexNumber;
_errorMessage = QCoreApplication::translate("QmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
return T_ERROR;
}
_tokenValue = integerFromString(chars.constData(), chars.size(), 16);
return T_NUMERIC_LITERAL;
}
@@ -871,7 +1027,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_patternFlags = 0;
while (isIdentLetter(_char)) {
int flag = regExpFlagFromChar(_char);
if (flag == 0) {
if (flag == 0 || _patternFlags & flag) {
_errorMessage = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'")
.arg(QChar(_char));
return false;
@@ -888,7 +1044,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_tokenText += _char;
scanChar();
if (_char.isNull() || isLineTerminator()) {
if (_codePtr > _endPtr || isLineTerminator()) {
_errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
return false;
}
@@ -902,15 +1058,15 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_tokenText += _char;
scanChar();
while (! _char.isNull() && ! isLineTerminator()) {
while (_codePtr <= _endPtr && ! isLineTerminator()) {
if (_char == QLatin1Char(']'))
break;
if (_char == QLatin1Char('\\')) {
else if (_char == QLatin1Char('\\')) {
// regular expression backslash sequence
_tokenText += _char;
scanChar();
if (_char.isNull() || isLineTerminator()) {
if (_codePtr > _endPtr || isLineTerminator()) {
_errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
return false;
}
@@ -933,7 +1089,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
break;
default:
if (_char.isNull() || isLineTerminator()) {
if (_codePtr > _endPtr || isLineTerminator()) {
_errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal");
return false;
} else {
@@ -1160,5 +1316,3 @@ bool Lexer::scanDirectives(Directives *directives)
return true;
}
#include "qmljskeywords_p.h"

View File

@@ -43,7 +43,8 @@
#include "qmljsglobal_p.h"
#include "qmljsgrammar_p.h"
#include <QtCore/QString>
#include <QtCore/qstring.h>
QT_QML_BEGIN_NAMESPACE
@@ -109,12 +110,14 @@ public:
enum Error {
NoError,
IllegalCharacter,
IllegalHexNumber,
UnclosedStringLiteral,
IllegalEscapeSequence,
IllegalUnicodeEscapeSequence,
UnclosedComment,
IllegalExponentIndicator,
IllegalIdentifier
IllegalIdentifier,
IllegalHexadecimalEscapeSequence
};
enum RegExpBodyPrefix {
@@ -189,6 +192,7 @@ private:
void syncProhibitAutomaticSemicolon();
QChar decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
private:
Engine *_engine;
@@ -199,6 +203,7 @@ private:
QStringRef _tokenSpell;
const QChar *_codePtr;
const QChar *_endPtr;
const QChar *_lastLinePtr;
const QChar *_tokenLinePtr;
const QChar *_tokenStartPtr;

File diff suppressed because it is too large Load Diff

View File

@@ -59,8 +59,8 @@
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
QT_QML_BEGIN_NAMESPACE
@@ -89,7 +89,8 @@ public:
AST::FunctionDeclaration *FunctionDeclaration;
AST::Node *Node;
AST::PropertyName *PropertyName;
AST::PropertyNameAndValueList *PropertyNameAndValueList;
AST::PropertyAssignment *PropertyAssignment;
AST::PropertyAssignmentList *PropertyAssignmentList;
AST::SourceElement *SourceElement;
AST::SourceElements *SourceElements;
AST::Statement *Statement;
@@ -99,7 +100,8 @@ public:
AST::VariableDeclarationList *VariableDeclarationList;
AST::UiProgram *UiProgram;
AST::UiImportList *UiImportList;
AST::UiHeaderItemList *UiHeaderItemList;
AST::UiPragma *UiPragma;
AST::UiImport *UiImport;
AST::UiParameterList *UiParameterList;
AST::UiPublicMember *UiPublicMember;
@@ -112,6 +114,7 @@ public:
AST::UiObjectMemberList *UiObjectMemberList;
AST::UiArrayMemberList *UiArrayMemberList;
AST::UiQualifiedId *UiQualifiedId;
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
};
public:
@@ -193,6 +196,7 @@ protected:
{ return location_stack [tos + index - 1]; }
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
protected:
Engine *driver;
@@ -232,9 +236,9 @@ protected:
#define J_SCRIPT_REGEXPLITERAL_RULE1 79
#define J_SCRIPT_REGEXPLITERAL_RULE1 87
#define J_SCRIPT_REGEXPLITERAL_RULE2 80
#define J_SCRIPT_REGEXPLITERAL_RULE2 88
QT_QML_END_NAMESPACE

View File

@@ -363,11 +363,12 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q
qmlText += doc->source().midRef(begin, end - begin);
QStringList importList;
for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
if (!it->import)
for (UiHeaderItemList *it = doc->qmlProgram()->headers; it; it = it->next) {
UiImport *import = AST::cast<UiImport *>(it->headerItem);
if (!import)
continue;
unsigned importBegin = it->import->firstSourceLocation().begin();
unsigned importEnd = it->import->lastSourceLocation().end();
unsigned importBegin = import->firstSourceLocation().begin();
unsigned importEnd = import->lastSourceLocation().end();
importList << doc->source().mid(importBegin, importEnd - importBegin);
}

View File

@@ -38,6 +38,7 @@
#include "parser/qmldirparser_p.h"
#include "parser/qmljsengine_p.h"
#include "qmljs_global.h"
#include "qmljsconstants.h"
namespace QmlJS {

View File

@@ -125,7 +125,17 @@ bool Evaluate::visit(AST::UiProgram *)
return false;
}
bool Evaluate::visit(AST::UiImportList *)
bool Evaluate::visit(AST::UiHeaderItemList *)
{
return false;
}
bool Evaluate::visit(AST::UiQualifiedPragmaId *)
{
return false;
}
bool Evaluate::visit(AST::UiPragma *)
{
return false;
}
@@ -281,7 +291,17 @@ bool Evaluate::visit(AST::Elision *)
return false;
}
bool Evaluate::visit(AST::PropertyNameAndValueList *)
bool Evaluate::visit(AST::PropertyAssignmentList *)
{
return false;
}
bool Evaluate::visit(AST::PropertyGetterSetter *)
{
return false;
}
bool Evaluate::visit(AST::PropertyNameAndValue *)
{
return false;
}

View File

@@ -64,7 +64,9 @@ protected:
// Ui
virtual bool visit(AST::UiProgram *ast);
virtual bool visit(AST::UiImportList *ast);
virtual bool visit(AST::UiHeaderItemList *ast);
virtual bool visit(AST::UiQualifiedPragmaId *ast);
virtual bool visit(AST::UiPragma *ast);
virtual bool visit(AST::UiImport *ast);
virtual bool visit(AST::UiPublicMember *ast);
virtual bool visit(AST::UiSourceElement *ast);
@@ -90,7 +92,9 @@ protected:
virtual bool visit(AST::ObjectLiteral *ast);
virtual bool visit(AST::ElementList *ast);
virtual bool visit(AST::Elision *ast);
virtual bool visit(AST::PropertyNameAndValueList *ast);
virtual bool visit(AST::PropertyAssignmentList *ast);
virtual bool visit(AST::PropertyGetterSetter *ast);
virtual bool visit(AST::PropertyNameAndValue *ast);
virtual bool visit(AST::NestedExpression *ast);
virtual bool visit(AST::IdentifierPropertyName *ast);
virtual bool visit(AST::StringLiteralPropertyName *ast);

View File

@@ -662,15 +662,38 @@ protected:
return false;
}
virtual bool visit(PropertyNameAndValueList *ast)
virtual bool visit(PropertyAssignmentList *ast)
{
for (PropertyNameAndValueList *it = ast; it; it = it->next) {
accept(it->name);
out(": ", ast->colonToken);
accept(it->value);
if (it->next) {
out(",", ast->commaToken); // always invalid?
newLine();
for (PropertyAssignmentList *it = ast; it; it = it->next) {
PropertyNameAndValue *assignment = AST::cast<PropertyNameAndValue *>(it->assignment);
if (assignment) {
accept(assignment->name);
out(": ", assignment->colonToken);
accept(assignment->value);
if (it->next) {
out(",", ast->commaToken); // always invalid?
newLine();
}
continue;
}
PropertyGetterSetter *getterSetter = AST::cast<PropertyGetterSetter *>(it->assignment);
if (getterSetter) {
switch (getterSetter->type) {
case PropertyGetterSetter::Getter:
out("get");
break;
case PropertyGetterSetter::Setter:
out("set");
break;
}
accept(getterSetter->name);
out("(", getterSetter->lparenToken);
accept(getterSetter->formals);
out("(", getterSetter->rparenToken);
out(" {", getterSetter->lbraceToken);
accept(getterSetter->functionBody);
out(" }", getterSetter->rbraceToken);
}
}
return false;
@@ -1136,10 +1159,10 @@ protected:
}
virtual bool visit(UiImportList *ast)
virtual bool visit(UiHeaderItemList *ast)
{
for (UiImportList *it = ast; it; it = it->next) {
accept(it->import);
for (UiHeaderItemList *it = ast; it; it = it->next) {
accept(it->headerItem);
newLine();
}
requireEmptyLine();

View File

@@ -93,12 +93,12 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
return;
}
if (!ast->imports || ast->imports->next) {
if (!ast->headers || ast->headers->next || !AST::cast<AST::UiImport *>(ast->headers->headerItem)) {
addError(SourceLocation(), tr("Expected a single import."));
return;
}
UiImport *import = ast->imports->import;
UiImport *import = AST::cast<AST::UiImport *>(ast->headers->headerItem);
if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
addError(import->importToken, tr("Expected import of QtQuick.tooling."));
return;
@@ -612,20 +612,28 @@ void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUt
return;
}
for (PropertyNameAndValueList *it = objectLit->properties; it; it = it->next) {
StringLiteralPropertyName *propName = dynamic_cast<StringLiteralPropertyName *>(it->name);
NumericLiteral *value = dynamic_cast<NumericLiteral *>(it->value);
UnaryMinusExpression *minus = dynamic_cast<UnaryMinusExpression *>(it->value);
if (minus)
value = dynamic_cast<NumericLiteral *>(minus->expression);
if (!propName || !value) {
addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
for (PropertyAssignmentList *it = objectLit->properties; it; it = it->next) {
PropertyNameAndValue *assignement = AST::cast<PropertyNameAndValue *>(it->assignment);
if (assignement) {
StringLiteralPropertyName *propName = dynamic_cast<StringLiteralPropertyName *>(assignement->name);
NumericLiteral *value = dynamic_cast<NumericLiteral *>(assignement->value);
UnaryMinusExpression *minus = dynamic_cast<UnaryMinusExpression *>(assignement->value);
if (minus)
value = dynamic_cast<NumericLiteral *>(minus->expression);
if (!propName || !value) {
addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
continue;
}
double v = value->value;
if (minus)
v = -v;
fme->addKey(propName->id.toString(), v);
continue;
}
double v = value->value;
if (minus)
v = -v;
fme->addKey(propName->id.toString(), v);
PropertyGetterSetter *getterSetter = AST::cast<PropertyGetterSetter *>(it->assignment);
if (getterSetter) {
addError(objectLit->firstSourceLocation(), tr("Enum should not contain getter and setters, but only 'string: number' elements."));
}
}
}

View File

@@ -31,6 +31,7 @@
#define QMLJS_QMLJSUTILS_H
#include "qmljs_global.h"
#include "qmljsconstants.h"
#include "parser/qmljsastfwd_p.h"
#include "parser/qmljsengine_p.h"
@@ -67,7 +68,7 @@ AST::SourceLocation locationFromRange(const T *node)
template <class T>
DiagnosticMessage errorMessage(const T *node, const QString &message)
{
return DiagnosticMessage(Severity::Error,
return DiagnosticMessage(QmlJS::Severity::Error,
locationFromRange(node),
message);
}

View File

@@ -49,7 +49,7 @@ bool ChangeImportsVisitor::add(QmlJS::AST::UiProgram *ast, const Import &import)
if (!ast)
return false;
if (ast->imports && ast->imports->import) {
if (ast->headers && ast->headers->headerItem) {
int insertionPoint = 0;
if (ast->members && ast->members->member)
insertionPoint = ast->members->member->firstSourceLocation().begin();
@@ -77,10 +77,11 @@ bool ChangeImportsVisitor::remove(QmlJS::AST::UiProgram *ast, const Import &impo
if (!ast)
return false;
for (UiImportList *iter = ast->imports; iter; iter = iter->next) {
if (equals(iter->import, import)) {
int start = iter->import->firstSourceLocation().begin();
int end = iter->import->lastSourceLocation().end();
for (UiHeaderItemList *iter = ast->headers; iter; iter = iter->next) {
UiImport *iterImport = AST::cast<UiImport *>(iter->headerItem);
if (equals(iterImport, import)) {
int start = iterImport->firstSourceLocation().begin();
int end = iterImport->lastSourceLocation().end();
includeSurroundingWhitespace(start, end);
replace(start, end - start, QString());
setDidRewriting(true);

View File

@@ -89,12 +89,13 @@ protected:
return oldStateName;
}
bool visit(UiImportList *ast) {
for (UiImportList *it = ast; it; it = it->next) {
if (it->import) {
m_paster->addImports(createImport(it->import));
bool visit(UiHeaderItemList *ast) {
for (UiHeaderItemList *it = ast; it; it = it->next) {
AST::UiImport *import = AST::cast<AST::UiImport *>(it->headerItem)
if (import) {
m_paster->addImports(createImport(import));
m_locations.remove(toLocation(it->import->firstSourceLocation(), it->import->lastSourceLocation()));
m_locations.remove(toLocation(import->firstSourceLocation(), import->lastSourceLocation()));
}
}

View File

@@ -690,8 +690,8 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc,
{
QList<Import> existingImports = m_rewriterView->model()->imports();
for (UiImportList *iter = doc->qmlProgram()->imports; iter; iter = iter->next) {
UiImport *import = iter->import;
for (UiHeaderItemList *iter = doc->qmlProgram()->headers; iter; iter = iter->next) {
UiImport *import = AST::cast<UiImport *>(iter->headerItem);
if (!import)
continue;

View File

@@ -93,8 +93,8 @@ public:
QString imports;
UiProgram *prog = currentFile->qmljsDocument()->qmlProgram();
if (prog && prog->imports) {
const int start = currentFile->startOf(prog->imports->firstSourceLocation());
if (prog && prog->headers) {
const int start = currentFile->startOf(prog->headers->firstSourceLocation());
const int end = currentFile->startOf(prog->members->member->firstSourceLocation());
imports = currentFile->textOf(start, end);
}

View File

@@ -270,7 +270,7 @@ private:
QModelIndex index = m_model->enterTestCase(rhsObjLit);
m_nodeToIndex.insert(rhsObjLit, index);
if (AST::PropertyNameAndValueList *properties = rhsObjLit->properties)
if (AST::PropertyAssignmentList *properties = rhsObjLit->properties)
visitProperties(properties);
m_model->leaveTestCase();
@@ -278,14 +278,14 @@ private:
return true;
}
void visitProperties(AST::PropertyNameAndValueList *properties)
void visitProperties(AST::PropertyAssignmentList *properties)
{
while (properties) {
QModelIndex index = m_model->enterTestCaseProperties(properties);
m_nodeToIndex.insert(properties, index);
if (AST::ObjectLiteral *objLiteral = AST::cast<AST::ObjectLiteral *>(properties->value))
visitProperties(objLiteral->properties);
if (AST::PropertyNameAndValue *assignment = AST::cast<AST::PropertyNameAndValue *>(properties->assignment))
if (AST::ObjectLiteral *objLiteral = AST::cast<AST::ObjectLiteral *>(assignment->value))
visitProperties(objLiteral->properties);
m_model->leaveTestCaseProperties();
properties = properties->next;
@@ -595,24 +595,38 @@ void QmlOutlineModel::leaveTestCase()
leaveNode();
}
QModelIndex QmlOutlineModel::enterTestCaseProperties(AST::PropertyNameAndValueList *propertyNameAndValueList)
QModelIndex QmlOutlineModel::enterTestCaseProperties(AST::PropertyAssignmentList *propertyAssignmentList)
{
QMap<int, QVariant> objectData;
if (AST::IdentifierPropertyName *propertyName = AST::cast<AST::IdentifierPropertyName *>(propertyNameAndValueList->name)) {
objectData.insert(Qt::DisplayRole, propertyName->id.toString());
objectData.insert(ItemTypeRole, ElementBindingType);
QmlOutlineItem *item;
if (propertyNameAndValueList->value->kind == AST::Node::Kind_FunctionExpression)
item = enterNode(objectData, propertyNameAndValueList, 0, m_icons->functionDeclarationIcon());
else if (propertyNameAndValueList->value->kind == AST::Node::Kind_ObjectLiteral)
item = enterNode(objectData, propertyNameAndValueList, 0, m_icons->objectDefinitionIcon());
else
item = enterNode(objectData, propertyNameAndValueList, 0, m_icons->scriptBindingIcon());
if (AST::PropertyNameAndValue *assignment = AST::cast<AST::PropertyNameAndValue *>(
propertyAssignmentList->assignment)) {
if (AST::IdentifierPropertyName *propertyName = AST::cast<AST::IdentifierPropertyName *>(assignment->name)) {
objectData.insert(Qt::DisplayRole, propertyName->id.toString());
objectData.insert(ItemTypeRole, ElementBindingType);
QmlOutlineItem *item;
if (assignment->value->kind == AST::Node::Kind_FunctionExpression)
item = enterNode(objectData, assignment, 0, m_icons->functionDeclarationIcon());
else if (assignment->value->kind == AST::Node::Kind_ObjectLiteral)
item = enterNode(objectData, assignment, 0, m_icons->objectDefinitionIcon());
else
item = enterNode(objectData, assignment, 0, m_icons->scriptBindingIcon());
return item->index();
} else {
return QModelIndex();
return item->index();
}
}
if (AST::PropertyGetterSetter *getterSetter = AST::cast<AST::PropertyGetterSetter *>(
propertyAssignmentList->assignment)) {
if (AST::IdentifierPropertyName *propertyName = AST::cast<AST::IdentifierPropertyName *>(getterSetter->name)) {
objectData.insert(Qt::DisplayRole, propertyName->id.toString());
objectData.insert(ItemTypeRole, ElementBindingType);
QmlOutlineItem *item;
item = enterNode(objectData, getterSetter, 0, m_icons->functionDeclarationIcon());
return item->index();
}
}
return QModelIndex();
}
void QmlOutlineModel::leaveTestCaseProperties()
@@ -642,8 +656,8 @@ AST::SourceLocation QmlOutlineModel::sourceLocation(const QModelIndex &index) co
location = getLocation(member);
else if (AST::ExpressionNode *expression = node->expressionCast())
location = getLocation(expression);
else if (AST::PropertyNameAndValueList *propertyNameAndValueList = AST::cast<AST::PropertyNameAndValueList *>(node))
location = getLocation(propertyNameAndValueList);
else if (AST::PropertyAssignmentList *propertyAssignmentList = AST::cast<AST::PropertyAssignmentList *>(node))
location = getLocation(propertyAssignmentList);
}
return location;
}
@@ -913,7 +927,15 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::ExpressionNode *exprNode)
return location;
}
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyNameAndValueList *propertyNode) {
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyAssignmentList *propertyNode) {
if (AST::PropertyNameAndValue *assignment = AST::cast<AST::PropertyNameAndValue *>(propertyNode->assignment))
return getLocation(assignment);
if (AST::PropertyGetterSetter *getterSetter = AST::cast<AST::PropertyGetterSetter *>(propertyNode->assignment))
return getLocation(getterSetter);
return propertyNode->commaToken; // should never happen
}
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyNameAndValue *propertyNode) {
AST::SourceLocation location;
location.offset = propertyNode->name->propertyNameToken.offset;
location.length = propertyNode->value->lastSourceLocation().end() - location.offset;
@@ -921,6 +943,14 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyNameAndValueList *
return location;
}
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyGetterSetter *propertyNode) {
AST::SourceLocation location;
location.offset = propertyNode->name->propertyNameToken.offset;
location.length = propertyNode->rbraceToken.end() - location.offset;
return location;
}
QIcon QmlOutlineModel::getIcon(AST::UiQualifiedId *qualifiedId) {
QIcon icon;
if (qualifiedId) {

View File

@@ -122,7 +122,7 @@ private:
QModelIndex enterTestCase(QmlJS::AST::ObjectLiteral *objectLiteral);
void leaveTestCase();
QModelIndex enterTestCaseProperties(QmlJS::AST::PropertyNameAndValueList *propertyNameAndValueList);
QModelIndex enterTestCaseProperties(QmlJS::AST::PropertyAssignmentList *propertyAssignmentList);
void leaveTestCaseProperties();
private:
@@ -139,7 +139,9 @@ private:
static QString asString(QmlJS::AST::UiQualifiedId *id);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::UiObjectMember *objMember);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::ExpressionNode *exprNode);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PropertyNameAndValueList *propertyNode);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PropertyAssignmentList *propertyNode);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PropertyNameAndValue *propertyNode);
static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PropertyGetterSetter *propertyNode);
QIcon getIcon(QmlJS::AST::UiQualifiedId *objDef);
QString getAnnotation(QmlJS::AST::UiObjectInitializer *objInitializer);

View File

@@ -40,7 +40,7 @@ namespace {
// ### does not necessarily give the full AST path!
// intentionally does not contain lists like
// UiImportList, SourceElements, UiObjectMemberList
// UiHeaderItemList, SourceElements, UiObjectMemberList
class AstPath: protected AST::Visitor
{
QList<AST::Node *> _path;