Commit e9c97aa1 authored by Fawzi Mohamed's avatar Fawzi Mohamed
Browse files

qmljs: use new qml parser



adds support for singleton and getter/setter properties

Change-Id: Ia6691ac7799a46885db0df44617617dcc3c13189
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
Reviewed-by: default avatarThomas Hartmann <Thomas.Hartmann@digia.com>
parent 0374d83e
......@@ -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));
}
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -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.
*/
......
......@@ -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:
......
......@@ -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).UiHeaderItemList->finish();
} break;
./
UiHeaderItemList: UiPragma ;
/.
case $rule_number: {
sym(1).Node = sym(1).UiImportList->finish();
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
} break;
./
UiImportList: UiImport ;
UiHeaderItemList: UiImport ;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
} break;
./
UiImportList: UiImportList UiImport ;
UiHeaderItemList: UiHeaderItemList UiPragma ;
/.
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).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);
node->commaToken = loc(2);
node->colonToken = loc(4);
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;
./
PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
PropertyAssignment: T_SET PropertyName T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
node->propertyNameToken = loc(1);
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;
./
PropertyName: T_SIGNAL ;
/.case $rule_number:./
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);
sym(1).Node = node;
} break;
./
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: {