Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js')
-rw-r--r--qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js1354
1 files changed, 677 insertions, 677 deletions
diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js
index 0c2e0425834..64959ecb5eb 100644
--- a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js
+++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js
@@ -1,678 +1,678 @@
-/*******************************************************************************
- * Copyright (c) 2015 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * QNX Software Systems - Initial API and implementation
- *******************************************************************************/
-
-// This will only be visible globally if we are in a browser environment
-var injectQMLLoose;
-
-(function (root, mod) {
- if (typeof exports === "object" && typeof module === "object") // CommonJS
- return mod(module.exports);
- if (typeof define === "function" && define.amd) // AMD
- return define(["exports"], mod);
- mod(root.acornQMLLooseInjector || (root.acornQMLLooseInjector = {})); // Plain browser env
-})(this, function (exports) {
- "use strict";
-
- exports.inject = function (acorn) {
- // Acorn token types
- var tt = acorn.tokTypes;
-
- // QML token types
- var qtt = acorn.qmlTokTypes;
- var keywords = acorn.qmlKeywords;
-
- // QML parser methods
- var lp = acorn.LooseParser.prototype;
- var pp = acorn.Parser.prototype;
-
- /*
- * Parses a set of QML Header Items (QMLImport or QMLPragma)
- */
- lp.qml_parseHeaderItemList = function () {
- var node = this.startNode();
- node.items = [];
-
- var loop = true;
- while (loop) {
- if (this.isContextual(qtt._import)) {
- node.items.push(this.qml_parseImport());
- } else if (this.isContextual(qtt._pragma)) {
- node.items.push(this.qml_parsePragma());
- } else {
- loop = false;
- }
- }
-
- return this.finishNode(node, "QMLHeaderItemList");
- };
-
- /*
- * Parses a QML Pragma statement of the form:
- * 'pragma' <QMLQualifiedID>
- */
- lp.qml_parsePragma = function () {
- var node = this.startNode();
- this.expectContextual(qtt._pragma);
- node.id = this.qml_parseQualifiedId(true);
- this.semicolon();
- return this.finishNode(node, "QMLPragma");
- };
-
- /*
- * Parses a QML Import of the form:
- * 'import' <QMLModule> [as <QMLQualifier>]
- * 'import' <StringLiteral> [as <QMLQualifier>]
- *
- * as specified by http://doc.qt.io/qt-5/qtqml-syntax-imports.html
- */
- lp.qml_parseImport = function () {
- var node = this.startNode();
- this.expectContextual(qtt._import);
-
- switch (this.tok.type) {
- case tt.string:
- node.module = null;
- node.directory = this.parseExprAtom();
- break;
- default:
- node.module = this.qml_parseModule();
- node.directory = null;
- break;
- }
-
- // Parse the qualifier, if any
- if (this.isContextual(qtt._as)) {
- node.qualifier = this.qml_parseQualifier();
- }
- this.semicolon();
-
- return this.finishNode(node, "QMLImport");
- };
-
- /*
- * Parses a QML Module of the form:
- * <QMLQualifiedId> <QMLVersionLiteral>
- */
- lp.qml_parseModule = function () {
- var node = this.startNode();
-
- node.id = this.qml_parseQualifiedId(false);
- node.version = this.qml_parseVersionLiteral();
-
- return this.finishNode(node, "QMLModule");
- };
-
- /*
- * Parses a QML Version Literal which consists of a major and minor
- * version separated by a '.'
- */
- lp.qml_parseVersionLiteral = function () {
- var node = this.startNode();
-
- var matches;
- if (this.tok.type === tt.num) {
- node.raw = this.input.slice(this.tok.start, this.tok.end);
- node.value = this.tok.value;
- this.next();
- } else {
- node.value = 0;
- node.raw = "0.0";
- }
-
- return this.finishNode(node, "QMLVersionLiteral");
- };
-
- /*
- * Parses a QML Qualifier of the form:
- * 'as' <Identifier>
- */
- lp.qml_parseQualifier = function () {
- var node = this.startNode();
- this.expectContextual(qtt._as);
- node.id = this.qml_parseIdent(false);
- return this.finishNode(node, "QMLQualifier");
- };
-
- /*
- * Parses a QML Object Definition of the form:
- * <QMLQualifiedId> { (<QMLObjectMember>)* }
- *
- * http://doc.qt.io/qt-5/qtqml-syntax-basics.html#object-declarations
- */
- lp.qml_parseObjectDefinition = function (isBinding) {
- var node = this.startNode();
- node.id = this.qml_parseQualifiedId(false);
- node.body = this.qml_parseObjectInitializer();
- return this.finishNode(node, isBinding ? "QMLObjectBinding" : "QMLObjectDefinition");
- };
-
- /*
- * Parses a QML Object Initializer of the form:
- * '{' <QMLObjectMember>* '}'
- */
- lp.qml_parseObjectInitializer = function () {
- var node = this.startNode();
- this.pushCx();
- this.expect(tt.braceL);
- var blockIndent = this.curIndent,
- line = this.curLineStart;
- node.members = [];
- while (!this.closes(tt.braceR, blockIndent, line, true)) {
- var member = this.qml_parseObjectMember();
- if (member) {
- node.members.push(member);
- }
- }
- this.popCx();
- this.eat(tt.braceR);
- return this.finishNode(node, "QMLObjectInitializer");
- };
-
- /*
- * Parses a QML Object Member which can be one of the following:
- * - a QML Property Binding
- * - a QML Property Declaration
- * - a QML Property Modifier
- * - a QML Object Literal
- * - a JavaScript Function Declaration
- * - a QML Signal Definition
- */
- lp.qml_parseObjectMember = function () {
- if (this.tok.type === tt._default || this.isContextual(qtt._readonly) || this.isContextual(qtt._property) || this.qml_isPrimitiveType(this.tok.type, this.tok.value)) {
- return this.qml_parsePropertyDeclaration();
- } else if (this.isContextual(qtt._signal)) {
- return this.qml_parseSignalDefinition();
- } else if (this.tok.type === tt._function) {
- return this.qml_parseFunctionMember();
- } else if (this.qml_isIdent(this.tok.type, this.tok.value) || this.tok.type === tt.dot) {
- var la = this.lookAhead(1);
- if (this.qml_isIdent(la.type, la.value) && la.value !== qtt._on) {
- // Two identifiers in a row means this is most likely a property declaration
- // with the 'property' token missing.
- return this.qml_parsePropertyDeclaration();
- } else {
- return this.qml_parseMemberStartsWithIdentifier() || this.qml_parsePropertyBinding();
- }
- } else if (this.tok.type === tt.colon) {
- return this.qml_parsePropertyBinding();
- } else if (this.tok.type === tt.braceL) {
- return this.qml_parseObjectDefinition();
- }
- // ignore the current token if it didn't pass the previous tests
- this.next();
- };
-
- /*
- * Parses a QML Object Member that starts with an identifier. This method solves the
- * ambiguities that arise from QML having multiple Object Members that start with
- * Qualified IDs as well as the fact that several of its keywords can be used as part
- * of these Qualified IDs.
- */
- lp.qml_parseMemberStartsWithIdentifier = function () {
- // Jump past the potential Qualified ID
- var i = 1,
- la = this.tok;
- if (this.qml_isIdent(la.type, la.value)) {
- la = this.lookAhead(i++);
- }
- while (la.type === tt.dot) {
- la = this.lookAhead(i++);
- if (this.qml_isIdent(la.type, la.value)) {
- la = this.lookAhead(i++);
- }
- }
-
- // Check the last lookahead token
- switch (la.type) {
- case tt.braceL:
- return this.qml_parseObjectDefinition();
- case tt.colon:
- return this.qml_parsePropertyBinding();
- case tt.name:
- if (la.value === qtt._on) {
- return this.qml_parsePropertyModifier();
- }
- break;
- }
- return null;
- };
-
- /*
- * Parses a JavaScript function as a member of a QML Object Literal
- */
- lp.qml_parseFunctionMember = function () {
- var node = this.startNode();
- this.expect(tt._function);
- return this.qml_parseFunction(node, true);
- };
-
- /*
- * QML version of 'parseFunction' needed to have proper error tolerant parsing
- * for QML member functions versus their JavaScript counterparts. The main
- * difference between the two functions is that this implementation will not
- * forcefully insert '(' and '{' tokens for the body and parameters. Instead,
- * it will silently create an empty parameter list or body and let parsing
- * continue normally.
- */
- lp.qml_parseFunction = function (node, isStatement) {
- this.initFunction(node);
- if (this.tok.type === tt.name) node.id = this.parseIdent();
- else if (isStatement) node.id = this.dummyIdent();
- node.params = this.tok.type === tt.parenL ? this.parseFunctionParams() : [];
- if (this.tok.type === tt.braceL) {
- node.body = this.parseBlock();
- } else {
- if (this.options.locations) {
- node.body = this.startNodeAt([this.last.end, this.last.loc.end]);
- } else {
- node.body = this.startNodeAt(this.last.end);
- }
- node.body.body = [];
- this.finishNode(node.body, "BlockStatement");
- }
- return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
- };
-
- /*
- * Parses a QML Property Modifier of the form:
- * <QMLQualifiedID> 'on' <QMLQualifiedID> <QMLInitializer>
- */
- lp.qml_parsePropertyModifier = function () {
- var node = this.startNode();
- node.kind = this.qml_parseQualifiedId(false);
- this.expectContextual(qtt._on);
- node.id = this.qml_parseQualifiedId(false);
- node.body = this.qml_parseObjectInitializer();
- return this.finishNode(node, "QMLPropertyModifier");
- };
-
- /*
- * Parses a QML Property of the form:
- * <QMLQualifiedID> <QMLBinding>
- */
- lp.qml_parsePropertyBinding = function () {
- var node = this.startNode();
- node.id = this.qml_parseQualifiedId(false);
- var start = this.storeCurrentPos();
- this.expect(tt.colon);
- node.binding = this.qml_parseBinding(start);
- return this.finishNode(node, "QMLPropertyBinding");
- };
-
- /*
- * Parses a QML Signal Definition of the form:
- * 'signal' <Identifier> [(<QMLPropertyType> <Identifier> [',' <QMLPropertyType> <Identifier>]* )]?
- */
- lp.qml_parseSignalDefinition = function () {
- var node = this.startNode();
-
- // Check if this is an object literal or property binding first
- var objOrBind = this.qml_parseMemberStartsWithIdentifier();
- if (objOrBind) {
- return objOrBind;
- }
- this.expectContextual(qtt._signal);
-
- node.id = this.qml_parseIdent(false);
- this.qml_parseSignalParams(node);
- this.semicolon();
- return this.finishNode(node, "QMLSignalDefinition");
- };
-
- /*
- * Checks if the given node is a dummy identifier
- */
- function isDummy(node) {
- return node.name === "✖";
- }
-
- /*
- * Parses QML Signal Parameters of the form:
- * [(<QMLPropertyType> <Identifier> [',' <QMLPropertyType> <Identifier>]* )]?
- */
- lp.qml_parseSignalParams = function (node) {
- this.pushCx();
- var indent = this.curIndent,
- line = this.curLineStart;
- node.params = [];
- if (this.eat(tt.parenL)) {
- while (!this.closes(tt.parenR, indent + 1, line) && this.tok.type !== tt.braceR) {
- var param = this.startNode();
- param.kind = this.qml_parsePropertyType();
-
- // Break out of an infinite loop where we continously consume dummy ids
- if (isDummy(param.kind.id) && this.tok.type !== tt.comma) {
- break;
- }
-
- param.id = this.qml_parseIdent(false);
- node.params.push(this.finishNode(param, "QMLParameter"));
-
- // Break out of an infinite loop where we continously consume dummy ids
- if (isDummy(param.id) && this.tok.type !== tt.comma) {
- break;
- }
- this.eat(tt.comma);
- }
- this.popCx();
- if (!this.eat(tt.parenR)) {
- // If there is no closing brace, make the node span to the start
- // of the next token (this is useful for Tern)
- this.last.end = this.tok.start;
- if (this.options.locations) this.last.loc.end = this.tok.loc.start;
- }
- }
- };
-
- /*
- * Parses a QML Property Declaration of the form:
- * ['default'|'readonly'] 'property' <QMLType> <Identifier> [<QMLBinding>]
- */
- lp.qml_parsePropertyDeclaration = function () {
- var node = this.startNode();
- var objOrBind = null;
-
- // Parse 'default' or 'readonly'
- node.default = false;
- node.readonly = false;
- if (this.eat(tt._default)) {
- node.default = true;
- } else if (this.isContextual(qtt._readonly)) {
- objOrBind = this.qml_parseMemberStartsWithIdentifier();
- if (objOrBind) {
- objOrBind.default = undefined;
- objOrBind.readonly = undefined;
- return objOrBind;
- }
- this.expectContextual(qtt._readonly);
- node.readonly = true;
- }
-
- if (!node.default && !node.readonly) {
- objOrBind = this.qml_parseMemberStartsWithIdentifier();
- if (objOrBind) {
- return objOrBind;
- }
- this.expectContextual(qtt._property);
- } else {
- this.expectContextual(qtt._property);
- }
-
-
- node.kind = this.qml_parsePropertyType();
- if (this.tok.value === "<") {
- this.expect(tt.relational); // '<'
- node.modifier = this.qml_parsePropertyType();
- this.expect(tt.relational); // '>'
- }
-
- node.id = this.qml_parseIdent(false);
-
- var start = this.storeCurrentPos();
- if (this.eat(tt.colon)) {
- node.binding = this.qml_parseBinding(start);
- } else {
- node.binding = null;
- this.semicolon();
- }
-
- return this.finishNode(node, "QMLPropertyDeclaration");
- };
-
- /*
- * Parses a QML Property Type of the form:
- * <Identifier>
- */
- lp.qml_parsePropertyType = function () {
- var node = this.startNode();
- node.primitive = false;
- if (this.qml_isPrimitiveType(this.tok.type, this.tok.value)) {
- node.primitive = true;
- }
- node.id = this.qml_parseIdent(true);
- return this.finishNode(node, "QMLPropertyType");
- };
-
- /*
- * Parses one of the following possibilities for a QML Property assignment:
- * - QML Object Binding
- * - QML Array Binding
- * - QML Script Binding
- */
- lp.qml_parseBinding = function (start) {
- var i, la;
- if (this.options.mode === "qmltypes") {
- return this.qml_parseScriptBinding(start, false);
- }
-
- if (this.tok.type === tt.braceL) {
- return this.qml_parseScriptBinding(start, true);
- } else if (this.tok.type === tt.bracketL) {
- // Perform look ahead to determine whether this is an expression or
- // a QML Array Binding
- i = 1;
- la = this.lookAhead(i++);
- if (la.type === tt.name) {
- while (la.type === tt.dot || la.type === tt.name) {
- la = this.lookAhead(i++);
- }
- if (la.type === tt.braceL) {
- return this.qml_parseArrayBinding();
- }
- }
- return this.qml_parseScriptBinding(start, true);
- }
- // Perform look ahead to determine whether this is an expression or
- // a QML Object Literal
- i = 1;
- la = this.tok;
- if (this.qml_isIdent(la.type, la.value)) {
- la = this.lookAhead(i++);
- }
- while (la.type === tt.dot) {
- la = this.lookAhead(i++);
- if (this.qml_isIdent(la.type, la.value)) {
- la = this.lookAhead(i++);
- }
- }
-
- if (la.type === tt.braceL) {
- return this.qml_parseObjectDefinition(true);
- } else {
- return this.qml_parseScriptBinding(start, true);
- }
- };
-
- /*
- * Parses a QML Array Binding of the form:
- * '[' [<QMLObjectDefinition> (',' <QMLObjectDefinition>)*] ']'
- */
- lp.qml_parseArrayBinding = function () {
- var node = this.startNode();
- var indent = this.curIndent,
- line = this.curLineStart;
- this.pushCx();
- this.expect(tt.bracketL);
- node.elements = [];
- while (!this.closes(tt.bracketR, indent + 1, line) && this.tok.type !== tt.braceR) {
- var obj = this.qml_parseObjectDefinition();
- node.elements.push(obj);
-
- // Break out of an infinite loop where we continously consume dummy ids
- if (isDummy(obj.id) && this.tok.type !== tt.comma) {
- break;
- }
-
- this.eat(tt.comma);
- }
- this.popCx();
- if (!this.eat(tt.bracketR)) {
- // If there is no closing brace, make the node span to the start
- // of the next token (this is useful for Tern)
- this.last.end = this.tok.start;
- if (this.options.locations) this.last.loc.end = this.tok.loc.start;
- }
- return this.finishNode(node, "QMLArrayBinding");
- };
-
- /*
- * Parses one of the following Script Bindings:
- * - Single JavaScript Expression
- * - QML Statement Block (A block of JavaScript statements)
- */
- lp.qml_parseScriptBinding = function (start, allowStatementBlock) {
- // Help out Tern a little by starting the Script Binding at the end of
- // the colon token (only if we consume invalid syntax).
- var node = this.startNodeAt(start);
- node.block = false;
- if (allowStatementBlock && this.tok.type === tt.braceL) {
- node.block = true;
- node.script = this.qml_parseStatementBlock();
- } else {
- node.script = this.parseExpression(false);
- this.semicolon();
- }
-
- // If this node consumed valid syntax, reset its start position
- if (node.script.type !== "Identifier" || node.script.name !== "✖") {
- if (node.loc) {
- node.loc.start = node.script.loc.start;
- }
- if (node.range) {
- node.range = node.script.range;
- }
- node.start = node.script.start;
- node.end = node.script.end;
- }
-
- return this.finishNode(node, "QMLScriptBinding");
- };
-
- /*
- * Parses a QML Statement Block of the form:
- * { <Statement>* }
- */
- lp.qml_parseStatementBlock = function () {
- var node = this.startNode();
- this.pushCx();
- this.expect(tt.braceL);
- var blockIndent = this.curIndent,
- line = this.curLineStart;
- node.body = [];
- while (!this.closes(tt.braceR, blockIndent, line, true)) {
- node.body.push(this.parseStatement(true, false));
- }
- this.popCx();
- this.eat(tt.braceR);
- return this.finishNode(node, "QMLStatementBlock");
- };
-
- /*
- * Parses a Qualified ID of the form:
- * <Identifier> ('.' <Identifier>)*
- *
- * If 'liberal' is true then this method will allow non-contextual QML keywords as
- * identifiers.
- */
- lp.qml_parseQualifiedId = function (liberal) {
- var node = this.startNode();
- node.parts = [];
- node.parts.push(this.qml_parseIdent(liberal));
- while (this.eat(tt.dot)) {
- node.parts.push(this.qml_parseIdent(liberal));
- }
-
- node.name = "";
- for (var i = 0; i < node.parts.length; i++) {
- node.name += node.parts[i].name;
- if (i < node.parts.length - 1) {
- node.name += ".";
- }
- }
-
- return this.finishNode(node, "QMLQualifiedID");
- };
-
- /*
- * Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
- * to throw an error if a non-contextual QML keyword is found.
- *
- * If 'liberal' is true then this method will allow non-contextual QML keywords as
- * identifiers.
- */
- lp.qml_parseIdent = function (liberal) {
- // Check for non-contextual QML keywords
- if (!liberal) {
- if (!this.qml_isIdent(this.tok.type, this.tok.value)) {
- return this.dummyIdent();
- }
- }
- return this.parseIdent();
- };
-
- /*
- * Checks the next token to see if it matches the given contextual keyword. If the
- * contextual keyword was not found, this function looks ahead at the next two tokens
- * and jumps ahead if it was found there. Returns whether or not the keyword was found.
- */
- lp.expectContextual = function (name) {
- if (this.eatContextual(name)) return true;
- for (var i = 1; i <= 2; i++) {
- if (this.lookAhead(i).type == tt.name && this.lookAhead(i).value === name) {
- for (var j = 0; j < i; j++) this.next();
- return true;
- }
- }
- };
-
- // Functions left un-changed from the main parser
- lp.qml_isIdent = pp.qml_isIdent;
- lp.qml_eatPrimitiveType = pp.qml_eatPrimitiveType;
- lp.qml_isPrimitiveType = pp.qml_isPrimitiveType;
-
- acorn.pluginsLoose.qml = function (instance) {
-
- // Extend acorn's 'parseTopLevel' method
- instance.extend("parseTopLevel", function (nextMethod) {
- return function () {
- // Make parsing simpler by only allowing ECMA Version 5 or older ('import' is
- // not a keyword in this version of ECMA Script). Qt 5.5 runs with ECMA Script
- // 5 anyway, so this makes sense.
- if (!this.options.ecmaVersion || this.options.ecmaVersion > 5) {
- throw new Error("QML only supports ECMA Script Language Specification 5 or older");
- }
-
- if (this.options.mode === "qml" || this.options.mode === "qmltypes") {
- // Most of QML's constructs sit at the top-level of the parse tree,
- // replacing JavaScripts top-level. Here we are parsing such things
- // as the root object literal and header statements of QML. Eventually,
- // these rules will delegate down to JavaScript expressions.
- var node = this.startNode();
- node.mode = this.options.mode;
- node.headerItemList = this.qml_parseHeaderItemList();
- node.rootObject = null;
- if (this.tok.type !== tt.eof) {
- node.rootObject = this.qml_parseObjectDefinition();
- }
-
- return this.finishNode(node, "QMLProgram");
- } else if (this.options.mode === "js") {
- return nextMethod.call(this);
- } else {
- throw new Error("Unknown mode '" + this.options.mode + "'");
- }
- };
- });
- };
-
- return acorn;
- };
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+// This will only be visible globally if we are in a browser environment
+var injectQMLLoose;
+
+(function (root, mod) {
+ if (typeof exports === "object" && typeof module === "object") // CommonJS
+ return mod(module.exports);
+ if (typeof define === "function" && define.amd) // AMD
+ return define(["exports"], mod);
+ mod(root.acornQMLLooseInjector || (root.acornQMLLooseInjector = {})); // Plain browser env
+})(this, function (exports) {
+ "use strict";
+
+ exports.inject = function (acorn) {
+ // Acorn token types
+ var tt = acorn.tokTypes;
+
+ // QML token types
+ var qtt = acorn.qmlTokTypes;
+ var keywords = acorn.qmlKeywords;
+
+ // QML parser methods
+ var lp = acorn.LooseParser.prototype;
+ var pp = acorn.Parser.prototype;
+
+ /*
+ * Parses a set of QML Header Items (QMLImport or QMLPragma)
+ */
+ lp.qml_parseHeaderItemList = function () {
+ var node = this.startNode();
+ node.items = [];
+
+ var loop = true;
+ while (loop) {
+ if (this.isContextual(qtt._import)) {
+ node.items.push(this.qml_parseImport());
+ } else if (this.isContextual(qtt._pragma)) {
+ node.items.push(this.qml_parsePragma());
+ } else {
+ loop = false;
+ }
+ }
+
+ return this.finishNode(node, "QMLHeaderItemList");
+ };
+
+ /*
+ * Parses a QML Pragma statement of the form:
+ * 'pragma' <QMLQualifiedID>
+ */
+ lp.qml_parsePragma = function () {
+ var node = this.startNode();
+ this.expectContextual(qtt._pragma);
+ node.id = this.qml_parseQualifiedId(true);
+ this.semicolon();
+ return this.finishNode(node, "QMLPragma");
+ };
+
+ /*
+ * Parses a QML Import of the form:
+ * 'import' <QMLModule> [as <QMLQualifier>]
+ * 'import' <StringLiteral> [as <QMLQualifier>]
+ *
+ * as specified by http://doc.qt.io/qt-5/qtqml-syntax-imports.html
+ */
+ lp.qml_parseImport = function () {
+ var node = this.startNode();
+ this.expectContextual(qtt._import);
+
+ switch (this.tok.type) {
+ case tt.string:
+ node.module = null;
+ node.directory = this.parseExprAtom();
+ break;
+ default:
+ node.module = this.qml_parseModule();
+ node.directory = null;
+ break;
+ }
+
+ // Parse the qualifier, if any
+ if (this.isContextual(qtt._as)) {
+ node.qualifier = this.qml_parseQualifier();
+ }
+ this.semicolon();
+
+ return this.finishNode(node, "QMLImport");
+ };
+
+ /*
+ * Parses a QML Module of the form:
+ * <QMLQualifiedId> <QMLVersionLiteral>
+ */
+ lp.qml_parseModule = function () {
+ var node = this.startNode();
+
+ node.id = this.qml_parseQualifiedId(false);
+ node.version = this.qml_parseVersionLiteral();
+
+ return this.finishNode(node, "QMLModule");
+ };
+
+ /*
+ * Parses a QML Version Literal which consists of a major and minor
+ * version separated by a '.'
+ */
+ lp.qml_parseVersionLiteral = function () {
+ var node = this.startNode();
+
+ var matches;
+ if (this.tok.type === tt.num) {
+ node.raw = this.input.slice(this.tok.start, this.tok.end);
+ node.value = this.tok.value;
+ this.next();
+ } else {
+ node.value = 0;
+ node.raw = "0.0";
+ }
+
+ return this.finishNode(node, "QMLVersionLiteral");
+ };
+
+ /*
+ * Parses a QML Qualifier of the form:
+ * 'as' <Identifier>
+ */
+ lp.qml_parseQualifier = function () {
+ var node = this.startNode();
+ this.expectContextual(qtt._as);
+ node.id = this.qml_parseIdent(false);
+ return this.finishNode(node, "QMLQualifier");
+ };
+
+ /*
+ * Parses a QML Object Definition of the form:
+ * <QMLQualifiedId> { (<QMLObjectMember>)* }
+ *
+ * http://doc.qt.io/qt-5/qtqml-syntax-basics.html#object-declarations
+ */
+ lp.qml_parseObjectDefinition = function (isBinding) {
+ var node = this.startNode();
+ node.id = this.qml_parseQualifiedId(false);
+ node.body = this.qml_parseObjectInitializer();
+ return this.finishNode(node, isBinding ? "QMLObjectBinding" : "QMLObjectDefinition");
+ };
+
+ /*
+ * Parses a QML Object Initializer of the form:
+ * '{' <QMLObjectMember>* '}'
+ */
+ lp.qml_parseObjectInitializer = function () {
+ var node = this.startNode();
+ this.pushCx();
+ this.expect(tt.braceL);
+ var blockIndent = this.curIndent,
+ line = this.curLineStart;
+ node.members = [];
+ while (!this.closes(tt.braceR, blockIndent, line, true)) {
+ var member = this.qml_parseObjectMember();
+ if (member) {
+ node.members.push(member);
+ }
+ }
+ this.popCx();
+ this.eat(tt.braceR);
+ return this.finishNode(node, "QMLObjectInitializer");
+ };
+
+ /*
+ * Parses a QML Object Member which can be one of the following:
+ * - a QML Property Binding
+ * - a QML Property Declaration
+ * - a QML Property Modifier
+ * - a QML Object Literal
+ * - a JavaScript Function Declaration
+ * - a QML Signal Definition
+ */
+ lp.qml_parseObjectMember = function () {
+ if (this.tok.type === tt._default || this.isContextual(qtt._readonly) || this.isContextual(qtt._property) || this.qml_isPrimitiveType(this.tok.type, this.tok.value)) {
+ return this.qml_parsePropertyDeclaration();
+ } else if (this.isContextual(qtt._signal)) {
+ return this.qml_parseSignalDefinition();
+ } else if (this.tok.type === tt._function) {
+ return this.qml_parseFunctionMember();
+ } else if (this.qml_isIdent(this.tok.type, this.tok.value) || this.tok.type === tt.dot) {
+ var la = this.lookAhead(1);
+ if (this.qml_isIdent(la.type, la.value) && la.value !== qtt._on) {
+ // Two identifiers in a row means this is most likely a property declaration
+ // with the 'property' token missing.
+ return this.qml_parsePropertyDeclaration();
+ } else {
+ return this.qml_parseMemberStartsWithIdentifier() || this.qml_parsePropertyBinding();
+ }
+ } else if (this.tok.type === tt.colon) {
+ return this.qml_parsePropertyBinding();
+ } else if (this.tok.type === tt.braceL) {
+ return this.qml_parseObjectDefinition();
+ }
+ // ignore the current token if it didn't pass the previous tests
+ this.next();
+ };
+
+ /*
+ * Parses a QML Object Member that starts with an identifier. This method solves the
+ * ambiguities that arise from QML having multiple Object Members that start with
+ * Qualified IDs as well as the fact that several of its keywords can be used as part
+ * of these Qualified IDs.
+ */
+ lp.qml_parseMemberStartsWithIdentifier = function () {
+ // Jump past the potential Qualified ID
+ var i = 1,
+ la = this.tok;
+ if (this.qml_isIdent(la.type, la.value)) {
+ la = this.lookAhead(i++);
+ }
+ while (la.type === tt.dot) {
+ la = this.lookAhead(i++);
+ if (this.qml_isIdent(la.type, la.value)) {
+ la = this.lookAhead(i++);
+ }
+ }
+
+ // Check the last lookahead token
+ switch (la.type) {
+ case tt.braceL:
+ return this.qml_parseObjectDefinition();
+ case tt.colon:
+ return this.qml_parsePropertyBinding();
+ case tt.name:
+ if (la.value === qtt._on) {
+ return this.qml_parsePropertyModifier();
+ }
+ break;
+ }
+ return null;
+ };
+
+ /*
+ * Parses a JavaScript function as a member of a QML Object Literal
+ */
+ lp.qml_parseFunctionMember = function () {
+ var node = this.startNode();
+ this.expect(tt._function);
+ return this.qml_parseFunction(node, true);
+ };
+
+ /*
+ * QML version of 'parseFunction' needed to have proper error tolerant parsing
+ * for QML member functions versus their JavaScript counterparts. The main
+ * difference between the two functions is that this implementation will not
+ * forcefully insert '(' and '{' tokens for the body and parameters. Instead,
+ * it will silently create an empty parameter list or body and let parsing
+ * continue normally.
+ */
+ lp.qml_parseFunction = function (node, isStatement) {
+ this.initFunction(node);
+ if (this.tok.type === tt.name) node.id = this.parseIdent();
+ else if (isStatement) node.id = this.dummyIdent();
+ node.params = this.tok.type === tt.parenL ? this.parseFunctionParams() : [];
+ if (this.tok.type === tt.braceL) {
+ node.body = this.parseBlock();
+ } else {
+ if (this.options.locations) {
+ node.body = this.startNodeAt([this.last.end, this.last.loc.end]);
+ } else {
+ node.body = this.startNodeAt(this.last.end);
+ }
+ node.body.body = [];
+ this.finishNode(node.body, "BlockStatement");
+ }
+ return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
+ };
+
+ /*
+ * Parses a QML Property Modifier of the form:
+ * <QMLQualifiedID> 'on' <QMLQualifiedID> <QMLInitializer>
+ */
+ lp.qml_parsePropertyModifier = function () {
+ var node = this.startNode();
+ node.kind = this.qml_parseQualifiedId(false);
+ this.expectContextual(qtt._on);
+ node.id = this.qml_parseQualifiedId(false);
+ node.body = this.qml_parseObjectInitializer();
+ return this.finishNode(node, "QMLPropertyModifier");
+ };
+
+ /*
+ * Parses a QML Property of the form:
+ * <QMLQualifiedID> <QMLBinding>
+ */
+ lp.qml_parsePropertyBinding = function () {
+ var node = this.startNode();
+ node.id = this.qml_parseQualifiedId(false);
+ var start = this.storeCurrentPos();
+ this.expect(tt.colon);
+ node.binding = this.qml_parseBinding(start);
+ return this.finishNode(node, "QMLPropertyBinding");
+ };
+
+ /*
+ * Parses a QML Signal Definition of the form:
+ * 'signal' <Identifier> [(<QMLPropertyType> <Identifier> [',' <QMLPropertyType> <Identifier>]* )]?
+ */
+ lp.qml_parseSignalDefinition = function () {
+ var node = this.startNode();
+
+ // Check if this is an object literal or property binding first
+ var objOrBind = this.qml_parseMemberStartsWithIdentifier();
+ if (objOrBind) {
+ return objOrBind;
+ }
+ this.expectContextual(qtt._signal);
+
+ node.id = this.qml_parseIdent(false);
+ this.qml_parseSignalParams(node);
+ this.semicolon();
+ return this.finishNode(node, "QMLSignalDefinition");
+ };
+
+ /*
+ * Checks if the given node is a dummy identifier
+ */
+ function isDummy(node) {
+ return node.name === "✖";
+ }
+
+ /*
+ * Parses QML Signal Parameters of the form:
+ * [(<QMLPropertyType> <Identifier> [',' <QMLPropertyType> <Identifier>]* )]?
+ */
+ lp.qml_parseSignalParams = function (node) {
+ this.pushCx();
+ var indent = this.curIndent,
+ line = this.curLineStart;
+ node.params = [];
+ if (this.eat(tt.parenL)) {
+ while (!this.closes(tt.parenR, indent + 1, line) && this.tok.type !== tt.braceR) {
+ var param = this.startNode();
+ param.kind = this.qml_parsePropertyType();
+
+ // Break out of an infinite loop where we continously consume dummy ids
+ if (isDummy(param.kind.id) && this.tok.type !== tt.comma) {
+ break;
+ }
+
+ param.id = this.qml_parseIdent(false);
+ node.params.push(this.finishNode(param, "QMLParameter"));
+
+ // Break out of an infinite loop where we continously consume dummy ids
+ if (isDummy(param.id) && this.tok.type !== tt.comma) {
+ break;
+ }
+ this.eat(tt.comma);
+ }
+ this.popCx();
+ if (!this.eat(tt.parenR)) {
+ // If there is no closing brace, make the node span to the start
+ // of the next token (this is useful for Tern)
+ this.last.end = this.tok.start;
+ if (this.options.locations) this.last.loc.end = this.tok.loc.start;
+ }
+ }
+ };
+
+ /*
+ * Parses a QML Property Declaration of the form:
+ * ['default'|'readonly'] 'property' <QMLType> <Identifier> [<QMLBinding>]
+ */
+ lp.qml_parsePropertyDeclaration = function () {
+ var node = this.startNode();
+ var objOrBind = null;
+
+ // Parse 'default' or 'readonly'
+ node.default = false;
+ node.readonly = false;
+ if (this.eat(tt._default)) {
+ node.default = true;
+ } else if (this.isContextual(qtt._readonly)) {
+ objOrBind = this.qml_parseMemberStartsWithIdentifier();
+ if (objOrBind) {
+ objOrBind.default = undefined;
+ objOrBind.readonly = undefined;
+ return objOrBind;
+ }
+ this.expectContextual(qtt._readonly);
+ node.readonly = true;
+ }
+
+ if (!node.default && !node.readonly) {
+ objOrBind = this.qml_parseMemberStartsWithIdentifier();
+ if (objOrBind) {
+ return objOrBind;
+ }
+ this.expectContextual(qtt._property);
+ } else {
+ this.expectContextual(qtt._property);
+ }
+
+
+ node.kind = this.qml_parsePropertyType();
+ if (this.tok.value === "<") {
+ this.expect(tt.relational); // '<'
+ node.modifier = this.qml_parsePropertyType();
+ this.expect(tt.relational); // '>'
+ }
+
+ node.id = this.qml_parseIdent(false);
+
+ var start = this.storeCurrentPos();
+ if (this.eat(tt.colon)) {
+ node.binding = this.qml_parseBinding(start);
+ } else {
+ node.binding = null;
+ this.semicolon();
+ }
+
+ return this.finishNode(node, "QMLPropertyDeclaration");
+ };
+
+ /*
+ * Parses a QML Property Type of the form:
+ * <Identifier>
+ */
+ lp.qml_parsePropertyType = function () {
+ var node = this.startNode();
+ node.primitive = false;
+ if (this.qml_isPrimitiveType(this.tok.type, this.tok.value)) {
+ node.primitive = true;
+ }
+ node.id = this.qml_parseIdent(true);
+ return this.finishNode(node, "QMLPropertyType");
+ };
+
+ /*
+ * Parses one of the following possibilities for a QML Property assignment:
+ * - QML Object Binding
+ * - QML Array Binding
+ * - QML Script Binding
+ */
+ lp.qml_parseBinding = function (start) {
+ var i, la;
+ if (this.options.mode === "qmltypes") {
+ return this.qml_parseScriptBinding(start, false);
+ }
+
+ if (this.tok.type === tt.braceL) {
+ return this.qml_parseScriptBinding(start, true);
+ } else if (this.tok.type === tt.bracketL) {
+ // Perform look ahead to determine whether this is an expression or
+ // a QML Array Binding
+ i = 1;
+ la = this.lookAhead(i++);
+ if (la.type === tt.name) {
+ while (la.type === tt.dot || la.type === tt.name) {
+ la = this.lookAhead(i++);
+ }
+ if (la.type === tt.braceL) {
+ return this.qml_parseArrayBinding();
+ }
+ }
+ return this.qml_parseScriptBinding(start, true);
+ }
+ // Perform look ahead to determine whether this is an expression or
+ // a QML Object Literal
+ i = 1;
+ la = this.tok;
+ if (this.qml_isIdent(la.type, la.value)) {
+ la = this.lookAhead(i++);
+ }
+ while (la.type === tt.dot) {
+ la = this.lookAhead(i++);
+ if (this.qml_isIdent(la.type, la.value)) {
+ la = this.lookAhead(i++);
+ }
+ }
+
+ if (la.type === tt.braceL) {
+ return this.qml_parseObjectDefinition(true);
+ } else {
+ return this.qml_parseScriptBinding(start, true);
+ }
+ };
+
+ /*
+ * Parses a QML Array Binding of the form:
+ * '[' [<QMLObjectDefinition> (',' <QMLObjectDefinition>)*] ']'
+ */
+ lp.qml_parseArrayBinding = function () {
+ var node = this.startNode();
+ var indent = this.curIndent,
+ line = this.curLineStart;
+ this.pushCx();
+ this.expect(tt.bracketL);
+ node.elements = [];
+ while (!this.closes(tt.bracketR, indent + 1, line) && this.tok.type !== tt.braceR) {
+ var obj = this.qml_parseObjectDefinition();
+ node.elements.push(obj);
+
+ // Break out of an infinite loop where we continously consume dummy ids
+ if (isDummy(obj.id) && this.tok.type !== tt.comma) {
+ break;
+ }
+
+ this.eat(tt.comma);
+ }
+ this.popCx();
+ if (!this.eat(tt.bracketR)) {
+ // If there is no closing brace, make the node span to the start
+ // of the next token (this is useful for Tern)
+ this.last.end = this.tok.start;
+ if (this.options.locations) this.last.loc.end = this.tok.loc.start;
+ }
+ return this.finishNode(node, "QMLArrayBinding");
+ };
+
+ /*
+ * Parses one of the following Script Bindings:
+ * - Single JavaScript Expression
+ * - QML Statement Block (A block of JavaScript statements)
+ */
+ lp.qml_parseScriptBinding = function (start, allowStatementBlock) {
+ // Help out Tern a little by starting the Script Binding at the end of
+ // the colon token (only if we consume invalid syntax).
+ var node = this.startNodeAt(start);
+ node.block = false;
+ if (allowStatementBlock && this.tok.type === tt.braceL) {
+ node.block = true;
+ node.script = this.qml_parseStatementBlock();
+ } else {
+ node.script = this.parseExpression(false);
+ this.semicolon();
+ }
+
+ // If this node consumed valid syntax, reset its start position
+ if (node.script.type !== "Identifier" || node.script.name !== "✖") {
+ if (node.loc) {
+ node.loc.start = node.script.loc.start;
+ }
+ if (node.range) {
+ node.range = node.script.range;
+ }
+ node.start = node.script.start;
+ node.end = node.script.end;
+ }
+
+ return this.finishNode(node, "QMLScriptBinding");
+ };
+
+ /*
+ * Parses a QML Statement Block of the form:
+ * { <Statement>* }
+ */
+ lp.qml_parseStatementBlock = function () {
+ var node = this.startNode();
+ this.pushCx();
+ this.expect(tt.braceL);
+ var blockIndent = this.curIndent,
+ line = this.curLineStart;
+ node.body = [];
+ while (!this.closes(tt.braceR, blockIndent, line, true)) {
+ node.body.push(this.parseStatement(true, false));
+ }
+ this.popCx();
+ this.eat(tt.braceR);
+ return this.finishNode(node, "QMLStatementBlock");
+ };
+
+ /*
+ * Parses a Qualified ID of the form:
+ * <Identifier> ('.' <Identifier>)*
+ *
+ * If 'liberal' is true then this method will allow non-contextual QML keywords as
+ * identifiers.
+ */
+ lp.qml_parseQualifiedId = function (liberal) {
+ var node = this.startNode();
+ node.parts = [];
+ node.parts.push(this.qml_parseIdent(liberal));
+ while (this.eat(tt.dot)) {
+ node.parts.push(this.qml_parseIdent(liberal));
+ }
+
+ node.name = "";
+ for (var i = 0; i < node.parts.length; i++) {
+ node.name += node.parts[i].name;
+ if (i < node.parts.length - 1) {
+ node.name += ".";
+ }
+ }
+
+ return this.finishNode(node, "QMLQualifiedID");
+ };
+
+ /*
+ * Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
+ * to throw an error if a non-contextual QML keyword is found.
+ *
+ * If 'liberal' is true then this method will allow non-contextual QML keywords as
+ * identifiers.
+ */
+ lp.qml_parseIdent = function (liberal) {
+ // Check for non-contextual QML keywords
+ if (!liberal) {
+ if (!this.qml_isIdent(this.tok.type, this.tok.value)) {
+ return this.dummyIdent();
+ }
+ }
+ return this.parseIdent();
+ };
+
+ /*
+ * Checks the next token to see if it matches the given contextual keyword. If the
+ * contextual keyword was not found, this function looks ahead at the next two tokens
+ * and jumps ahead if it was found there. Returns whether or not the keyword was found.
+ */
+ lp.expectContextual = function (name) {
+ if (this.eatContextual(name)) return true;
+ for (var i = 1; i <= 2; i++) {
+ if (this.lookAhead(i).type == tt.name && this.lookAhead(i).value === name) {
+ for (var j = 0; j < i; j++) this.next();
+ return true;
+ }
+ }
+ };
+
+ // Functions left un-changed from the main parser
+ lp.qml_isIdent = pp.qml_isIdent;
+ lp.qml_eatPrimitiveType = pp.qml_eatPrimitiveType;
+ lp.qml_isPrimitiveType = pp.qml_isPrimitiveType;
+
+ acorn.pluginsLoose.qml = function (instance) {
+
+ // Extend acorn's 'parseTopLevel' method
+ instance.extend("parseTopLevel", function (nextMethod) {
+ return function () {
+ // Make parsing simpler by only allowing ECMA Version 5 or older ('import' is
+ // not a keyword in this version of ECMA Script). Qt 5.5 runs with ECMA Script
+ // 5 anyway, so this makes sense.
+ if (!this.options.ecmaVersion || this.options.ecmaVersion > 5) {
+ throw new Error("QML only supports ECMA Script Language Specification 5 or older");
+ }
+
+ if (this.options.mode === "qml" || this.options.mode === "qmltypes") {
+ // Most of QML's constructs sit at the top-level of the parse tree,
+ // replacing JavaScripts top-level. Here we are parsing such things
+ // as the root object literal and header statements of QML. Eventually,
+ // these rules will delegate down to JavaScript expressions.
+ var node = this.startNode();
+ node.mode = this.options.mode;
+ node.headerItemList = this.qml_parseHeaderItemList();
+ node.rootObject = null;
+ if (this.tok.type !== tt.eof) {
+ node.rootObject = this.qml_parseObjectDefinition();
+ }
+
+ return this.finishNode(node, "QMLProgram");
+ } else if (this.options.mode === "js") {
+ return nextMethod.call(this);
+ } else {
+ throw new Error("Unknown mode '" + this.options.mode + "'");
+ }
+ };
+ });
+ };
+
+ return acorn;
+ };
}); \ No newline at end of file

Back to the top