From 31150e4af1e0b3fb43a5db305c3a3e30f8d5f1ac Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Tue, 24 Nov 2015 13:59:46 -0500 Subject: [PATCH] Bug 481126 - QML Scoping Issues Fixed the following issues with QML: -The parent scope of a QML Object is the file's root Object scope -Content assist for an Object Property should only display the immediate Object's properties, not it's parent(s) -Content assist for an incomplete property binding should display JavaScript hints as well Added missing license headers and new tests. Had to modify the acorn-qml parser plugin in order to make some of the changes. Added tests for those as well. Change-Id: I289167cbaacd8088f87dfafc689e67c0110d942f Signed-off-by: Matthew Bastien --- qt/org.eclipse.cdt.qt.core/acorn-qml/index.js | 3 +- .../acorn-qml/inject.js | 40 +- .../acorn-qml/loose/index.js | 3 +- .../acorn-qml/loose/inject.js | 92 ++- .../acorn-qml/test/driver.js | 1 + .../acorn-qml/test/run.js | 3 +- .../acorn-qml/test/tests-qml.js | 574 +++++++++++------- .../acorn-qml/walk/index.js | 18 +- .../tern-qml/demo/qml-demo.html | 6 +- qt/org.eclipse.cdt.qt.core/tern-qml/qml.js | 568 ++++++++++++----- .../tern-qml/test/driver.js | 47 +- .../tern-qml/test/ecma5-defs.js | 10 + .../tern-qml/test/run.js | 12 + .../tern-qml/test/test-completions.js | 422 +++++++++++-- .../tern-qml/test/test-finddef.js | 207 ++++++- 15 files changed, 1491 insertions(+), 515 deletions(-) diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/index.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/index.js index ce774dcf2b9..f724fad6cb1 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/index.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/index.js @@ -8,7 +8,6 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ -'use strict'; // This will only be visible globally if we are in a browser environment var acornQML; @@ -20,5 +19,7 @@ var acornQML; return define(["./inject.js", "acorn/dist/acorn"], mod); acornQML = mod(injectQML, acorn); // Plain browser env })(function (injectQML, acorn) { + 'use strict'; + return injectQML(acorn); }) \ No newline at end of file diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js index 38b94bf26cf..25ed656b34c 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js @@ -8,7 +8,6 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ -'use strict'; // This will only be visible globally if we are in a browser environment var injectQML; @@ -20,6 +19,8 @@ var injectQML; return define([], mod); injectQML = mod(); // Plain browser env })(function () { + 'use strict'; + return function (acorn) { // Acorn token types var tt = acorn.tokTypes; @@ -93,11 +94,9 @@ var injectQML; var loop = true; while (loop) { if (this.isContextual(qtt._import)) { - var qmlImport = this.qml_parseImportStatement(); - node.statements.push(qmlImport); + node.statements.push(this.qml_parseImportStatement()); } else if (this.isContextual(qtt._pragma)) { - var qmlPragma = this.qml_parsePragmaStatement(); - node.statements.push(qmlPragma); + node.statements.push(this.qml_parsePragmaStatement()); } else { loop = false; } @@ -293,7 +292,7 @@ var injectQML; node.id = this.qml_parseQualifiedId(false); } this.expect(tt.colon); - node.expr = this.qml_parsePropertyAssignment(); + node.binding = this.qml_parseBinding(); return this.finishNode(node, "QMLPropertyBinding"); } @@ -401,10 +400,10 @@ var injectQML; node.kind = this.qml_parseKind(); node.id = this.qml_parseIdent(false); if (!this.eat(tt.colon)) { - node.init = null; + node.binding = null; this.semicolon(); } else { - node.init = this.qml_parsePropertyAssignment(); + node.binding = this.qml_parseBinding(); } return this.finishNode(node, "QMLPropertyDeclaration"); @@ -412,24 +411,35 @@ var injectQML; /* * Parses one of the following possibilities for a QML Property assignment: - * - JavaScript Expression - * - QML JavaScript Statement Block * - QML Object Literal + * - QML Script Binding */ - pp.qml_parsePropertyAssignment = function () { + pp.qml_parseBinding = function () { // TODO: solve ambiguity where a QML Object Literal starts with a // Qualified Id that looks very similar to a MemberExpression in // JavaScript. For now, we just won't parse statements like: // test: QMLObject { } // test: QMLObject.QualifiedId { } + return this.qml_parseScriptBinding(); + } + + /* + * Parses one of the following Script Bindings: + * - Single JavaScript Expression + * - QML Statement Block (A block of JavaScript statements) + */ + pp.qml_parseScriptBinding = function () { + var node = this.startNode(); + node.block = false; if (this.type === tt.braceL) { - return this.qml_parseStatementBlock(); + node.block = true; + node.script = this.qml_parseStatementBlock(); } else { - var node = this.parseExpression(false); + node.script = this.parseExpression(false); this.semicolon(); - return node; } + return this.finishNode(node, "QMLScriptBinding"); } /* @@ -576,7 +586,7 @@ var injectQML; this.raise(this.pos, "Expected EOF after QML Root Object"); } - return this.finishNode(node, "Program"); + return this.finishNode(node, "QMLProgram"); }; }); } diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/index.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/index.js index 26073abe7bf..db2d6f5d249 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/index.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/index.js @@ -8,7 +8,6 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ -'use strict'; // This will only be visible globally if we are in a browser environment var acornQMLLoose; @@ -20,5 +19,7 @@ var acornQMLLoose; return define(["./inject.js", "acorn", "acorn/dist/acorn_loose"], mod); acornQMLLoose = mod(injectQMLLoose, acorn, acorn); // Plain browser env })(function (injectQMLLoose, acorn, acorn_loose) { + "use strict"; + return injectQMLLoose(acorn); }) \ No newline at end of file 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 a181eacc7e2..40f732711b9 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 @@ -8,7 +8,6 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ -'use strict'; // This will only be visible globally if we are in a browser environment var injectQMLLoose; @@ -20,6 +19,8 @@ var injectQMLLoose; return define([], mod); injectQMLLoose = mod(); // Plain browser env })(function () { + "use strict"; + return function (acorn) { // Acorn token types var tt = acorn.tokTypes; @@ -43,11 +44,9 @@ var injectQMLLoose; var loop = true; while (loop) { if (this.isContextual(qtt._import)) { - var qmlImport = this.qml_parseImportStatement(); - node.statements.push(qmlImport); + node.statements.push(this.qml_parseImportStatement()); } else if (this.isContextual(qtt._pragma)) { - var qmlPragma = this.qml_parsePragmaStatement(); - node.statements.push(qmlPragma); + node.statements.push(this.qml_parsePragmaStatement()); } else { loop = false; } @@ -292,8 +291,9 @@ var injectQMLLoose; lp.qml_parsePropertyBinding = function () { var node = this.startNode(); node.id = this.qml_parseQualifiedId(false); + var start = this.storeCurrentPos(); this.expect(tt.colon); - node.expr = this.qml_parsePropertyAssignment(); + node.binding = this.qml_parseBinding(start); return this.finishNode(node, "QMLPropertyBinding"); } @@ -399,10 +399,11 @@ var injectQMLLoose; node.kind = this.qml_parseKind(); node.id = this.qml_parseIdent(false); + var start = this.storeCurrentPos(); if (this.eat(tt.colon)) { - node.init = this.qml_parsePropertyAssignment(); + node.binding = this.qml_parseBinding(start); } else { - node.init = null; + node.binding = null; this.semicolon(); } @@ -411,35 +412,64 @@ var injectQMLLoose; /* * Parses one of the following possibilities for a QML Property assignment: - * - JavaScript Expression - * - QML JavaScript Statement Block * - QML Object Literal + * - QML Script Binding */ - lp.qml_parsePropertyAssignment = function () { + lp.qml_parseBinding = function (start) { if (this.tok.type === tt.braceL) { - return this.qml_parseStatementBlock(); - } else { - // Perform look ahead to determine whether this is an expression or - // a QML Object Literal - var i = 1, la = this.tok; + return this.qml_parseScriptBinding(start); + } + // Perform look ahead to determine whether this is an expression or + // a QML Object Literal + 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++); } - 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_parseObjectLiteral(); - } else { - var node = this.parseExpression(false); - this.semicolon(); - return node; - } } + + if (la.type === tt.braceL) { + return this.qml_parseObjectLiteral(); + } else { + return this.qml_parseScriptBinding(start); + } + } + + /* + * Parses one of the following Script Bindings: + * - Single JavaScript Expression + * - QML Statement Block (A block of JavaScript statements) + */ + lp.qml_parseScriptBinding = function (start) { + // 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 (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"); } /* @@ -559,7 +589,7 @@ var injectQMLLoose; node.rootObject = this.qml_parseObjectLiteral(); } - return this.finishNode(node, "Program"); + return this.finishNode(node, "QMLProgram"); }; }); } diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/driver.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/driver.js index a9fe8990c5d..cfa2c1a3164 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/driver.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/driver.js @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ +"use-strict"; var tests = []; diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/run.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/run.js index fa87a5e8fbf..fb56196c428 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/run.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/run.js @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ +"use-strict"; var driver = require("./driver.js"); require("./tests-qml.js"); @@ -48,7 +49,7 @@ var stats, modes = { return opts.loose !== false; } } - } + }, }; function report(state, code, message) { diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/tests-qml.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/tests-qml.js index d0d066b5f1c..d50df7a4208 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/test/tests-qml.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/test/tests-qml.js @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ +"use-strict"; var test = require("./driver.js").test; var testFail = require("./driver.js").testFail; @@ -794,14 +795,17 @@ test('a{ readonly property var w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 28 }, end: { line: 1, column: 29 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -822,14 +826,17 @@ test('a{ default property var w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 27 }, end: { line: 1, column: 28 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -858,14 +865,17 @@ test('a{ property var w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 20 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -886,14 +896,17 @@ test('a{ property boolean w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 23 }, end: { line: 1, column: 24 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -914,14 +927,17 @@ test('a{ property double w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 22 }, end: { line: 1, column: 23 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -942,14 +958,17 @@ test('a{ property int w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 20 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -970,14 +989,17 @@ test('a{ property list w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 20 }, end: { line: 1, column: 21 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -998,14 +1020,17 @@ test('a{ property color w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 21 }, end: { line: 1, column: 22 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1026,14 +1051,17 @@ test('a{ property real w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 20 }, end: { line: 1, column: 21 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1054,14 +1082,17 @@ test('a{ property string w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 22 }, end: { line: 1, column: 23 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1082,14 +1113,17 @@ test('a{ property url w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 20 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1119,14 +1153,17 @@ test('a{ property QtObject w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 24 }, end: { line: 1, column: 25 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1147,14 +1184,17 @@ test('a{ property alias w: 3 }', rootObjectMembers([{ }, name: "w" }, - init: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 21 }, end: { line: 1, column: 22 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1173,14 +1213,17 @@ test('a{ w: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "w" }], name: "w" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 7 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1203,14 +1246,17 @@ test('a{ x.y.z: 3 }', rootObjectMembers([{ ], name: "x.y.z" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 10 }, end: { line: 1, column: 11 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1253,14 +1299,17 @@ test('a{ alias: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "alias" }], name: "alias" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 10 }, end: { line: 1, column: 11 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1279,14 +1328,17 @@ test('a{ list: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "list" }], name: "list" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 9 }, end: { line: 1, column: 10 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1305,14 +1357,17 @@ test('a{ property: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "property" }], name: "property" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1331,14 +1386,17 @@ test('a{ readonly: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "readonly" }], name: "readonly" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1357,14 +1415,17 @@ test('a{ signal: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "signal" }], name: "signal" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 11 }, end: { line: 1, column: 12 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1383,14 +1444,17 @@ test('a{ color: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "color" }], name: "color" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 10 }, end: { line: 1, column: 11 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1409,14 +1473,17 @@ test('a{ real: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "real" }], name: "real" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 9 }, end: { line: 1, column: 10 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1435,14 +1502,17 @@ test('a{ string: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "string" }], name: "string" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 11 }, end: { line: 1, column: 12 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1461,14 +1531,17 @@ test('a{ url: 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "url" }], name: "url" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 8 }, end: { line: 1, column: 9 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -1487,45 +1560,48 @@ test('a{ onClicked: Qt.quit(0) }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "onClicked" }], name: "onClicked" }, - expr: { - type: "CallExpression", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 24 } }, - callee: { - type: "MemberExpression", - loc: { - start: { line: 1, column: 14 }, - end: { line: 1, column: 21 } - }, - object: { - type: "Identifier", + script: { + type: "CallExpression", + callee: { + type: "MemberExpression", loc: { start: { line: 1, column: 14 }, - end: { line: 1, column: 16 } - }, - name: "Qt" - }, - property: { - type: "Identifier", - loc: { - start: { line: 1, column: 17 }, end: { line: 1, column: 21 } }, - name: "quit" + object: { + type: "Identifier", + loc: { + start: { line: 1, column: 14 }, + end: { line: 1, column: 16 } + }, + name: "Qt" + }, + property: { + type: "Identifier", + loc: { + start: { line: 1, column: 17 }, + end: { line: 1, column: 21 } + }, + name: "quit" + }, + computed: false }, - computed: false - }, - arguments: [{ - type: "Literal", - loc: { - start: { line: 1, column: 22 }, - end: { line: 1, column: 23 } - }, - value: 0, - raw: "0" - }] + arguments: [{ + type: "Literal", + loc: { + start: { line: 1, column: 22 }, + end: { line: 1, column: 23 } + }, + value: 0, + raw: "0" + }] + } } }])); @@ -1862,20 +1938,23 @@ test('a{ id: test }', rootObjectMembers([{ }], name: "id" }, - expr: { - type: "Identifier", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 7 }, end: { line: 1, column: 11 } }, - name: "test" + script: { + type: "Identifier", + name: "test" + } } }])); /* * Test the base QML Hello World program created by Eclipse CDT. */ -test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true\n\n\tMouseArea {\n\t\tanchors.fill: parent\n\t\tonClicked: {\n\t\t\tQt.quit();\n\t\t}\n\t}\n\t\tText {\n\t\t\ttext: qsTr("Hello World")\n\t\t\tanchors.centerIn: parent\n\t}\n}', +test('import QtQuick 2.3\nimport QtQuick.Window 2.2\nWindow {\n\tvisible: true\n\n\tMouseArea {\n\t\tanchors.fill: parent\n\t\tonClicked: {\n\t\t\tQt.quit();\n\t\t}\n\t}\n\tText {\n\t\ttext: qsTr("Hello World")\n\t\tanchors.centerIn: parent\n\t}\n}', program([{ type: "QMLImportStatement", loc: { @@ -1950,14 +2029,14 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true }],{ type: "QMLObjectLiteral", loc: { - start: { line: 3, column: 1 }, + start: { line: 3, column: 0 }, end: { line: 16, column: 1 } }, id: { type: "QMLQualifiedID", loc: { - start: { line: 3, column: 1 }, - end: { line: 3, column: 7 } + start: { line: 3, column: 0 }, + end: { line: 3, column: 6 } }, parts: [{ type: "Identifier", name: "Window" }], name: "Window" @@ -1965,7 +2044,7 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true body: { type: "QMLMemberBlock", loc: { - start: { line: 3, column: 8 }, + start: { line: 3, column: 7 }, end: { line: 16, column: 1 } }, members: [ @@ -1984,14 +2063,17 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true parts: [{ type: "Identifier", name: "visible" }], name: "visible" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 4, column: 10 }, end: { line: 4, column: 14 } }, - value: true, - raw: "true" + script: { + type: "Literal", + value: true, + raw: "true" + } } }, { @@ -2034,13 +2116,16 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true ], name: "anchors.fill" }, - expr: { - type: "Identifier", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 7, column: 16 }, end: { line: 7, column: 22 } }, - name: "parent" + script: { + type: "Identifier", + name: "parent" + } } }, { @@ -2058,31 +2143,34 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true parts: [{ type: "Identifier", name: "onClicked" }], name: "onClicked" }, - expr: { - type: "QMLStatementBlock", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 8, column: 13 }, end: { line: 10, column: 3 } }, - statements: [{ - type: "ExpressionStatement", - expression: { - type: "CallExpression", - callee: { - type: "MemberExpression", - object: { - type: "Identifier", - name: "Qt" + script: { + type: "QMLStatementBlock", + statements: [{ + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + name: "Qt" + }, + property: { + type: "Identifier", + name: "quit" + }, + computed: false }, - property: { - type: "Identifier", - name: "quit" - }, - computed: false - }, - arguments: [] - } - }] + arguments: [] + } + }] + } } } ] @@ -2091,14 +2179,14 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true { type: "QMLObjectLiteral", loc: { - start: { line: 12, column: 2 }, + start: { line: 12, column: 1 }, end: { line: 15, column: 2 } }, id: { type: "QMLQualifiedID", loc: { - start: { line: 12, column: 2 }, - end: { line: 12, column: 6 } + start: { line: 12, column: 1 }, + end: { line: 12, column: 5 } }, parts: [{ type: "Identifier", name: "Text" }], name: "Text" @@ -2106,53 +2194,56 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true body: { type: "QMLMemberBlock", loc: { - start: { line: 12, column: 7 }, + start: { line: 12, column: 6 }, end: { line: 15, column: 2 } }, members: [ { type: "QMLPropertyBinding", loc: { - start: { line: 13, column: 3 }, - end: { line: 13, column: 28 } + start: { line: 13, column: 2 }, + end: { line: 13, column: 27 } }, id: { type: "QMLQualifiedID", loc: { - start: { line: 13, column: 3 }, - end: { line: 13, column: 7 } + start: { line: 13, column: 2 }, + end: { line: 13, column: 6 } }, parts: [{ type: "Identifier", name: "text" }], name: "text" }, - expr: { - type: "CallExpression", + binding: { + type: "QMLScriptBinding", loc: { - start: { line: 13, column: 9 }, - end: { line: 13, column: 28 } + start: { line: 13, column: 8 }, + end: { line: 13, column: 27 } }, - callee: { - type: "Identifier", - name: "qsTr" - }, - arguments: [{ - type: "Literal", - value: "Hello World", - raw: "\"Hello World\"" - }] + script: { + type: "CallExpression", + callee: { + type: "Identifier", + name: "qsTr" + }, + arguments: [{ + type: "Literal", + value: "Hello World", + raw: "\"Hello World\"" + }] + } } }, { type: "QMLPropertyBinding", loc: { - start: { line: 14, column: 3 }, - end: { line: 14, column: 27 } + start: { line: 14, column: 2 }, + end: { line: 14, column: 26 } }, id: { type: "QMLQualifiedID", loc: { - start: { line: 14, column: 3 }, - end: { line: 14, column: 19 } + start: { line: 14, column: 2 }, + end: { line: 14, column: 18 } }, parts: [ { type: "Identifier", name: "anchors" }, @@ -2160,9 +2251,12 @@ test('import QtQuick 2.3\nimport QtQuick.Window 2.2\n\tWindow {\n\tvisible: true ], name: "anchors.centerIn" }, - expr: { - type: "Identifier", - name: "parent" + binding: { + type: "QMLScriptBinding", + script: { + type: "Identifier", + name: "parent" + } } } ] @@ -2451,6 +2545,18 @@ testLoose('Window {\n\tprop: 3', rootObject({ }, parts: [{ type: "Identifier", name: "prop" }], name: "prop" + }, + binding: { + type: "QMLScriptBinding", + loc: { + start: { line: 2, column: 7 }, + end: { line: 2, column: 8 } + }, + script: { + type: "Literal", + value: 3, + raw: "3" + } } }] } @@ -2545,7 +2651,8 @@ testLoose('a{ property var }', rootObjectMembers([{ end: { line: 1, column: 17 } }, name: "✖" - } + }, + binding: null }])); testLoose('a{ w }', rootObjectMembers([{ @@ -2563,13 +2670,16 @@ testLoose('a{ w }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "w" }], name: "w" }, - expr: { - type: "Identifier", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 5 }, end: { line: 1, column: 5 } }, - name: "✖" + script: { + type: "Identifier", + name: "✖" + } } }])); @@ -2588,13 +2698,16 @@ testLoose('a{ w: }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "w" }], name: "w" }, - expr: { - type: "Identifier", + binding: { + type: "QMLScriptBinding", loc: { - start: { line: 1, column: 7 }, + start: { line: 1, column: 4 }, end: { line: 1, column: 7 } }, - name: "✖" + script: { + type: "Identifier", + name: "✖" + } } }])); @@ -2613,14 +2726,17 @@ testLoose('a{ : 3 }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "✖" }], name: "✖" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 5 }, end: { line: 1, column: 6 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -2642,14 +2758,17 @@ testLoose('a{ anchors.: 3 }', rootObjectMembers([{ ], name: "anchors.✖" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -2672,14 +2791,17 @@ testLoose('a{ anchors..: 3 }', rootObjectMembers([{ ], name: "anchors.✖.✖" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 15 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -2702,14 +2824,17 @@ testLoose('a{ ..: 3 }', rootObjectMembers([{ ], name: "✖.✖.✖" }, - expr: { - type: "Literal", + binding: { + type: "QMLScriptBinding", loc: { start: { line: 1, column: 7 }, end: { line: 1, column: 8 } }, - value: 3, - raw: "3" + script: { + type: "Literal", + value: 3, + raw: "3" + } } }])); @@ -2730,7 +2855,7 @@ testLoose('a{ var }', rootObjectMembers([{ }, name: "✖" }, - init: null + binding: null }])); testLoose('a{ var w }', rootObjectMembers([{ @@ -2750,7 +2875,7 @@ testLoose('a{ var w }', rootObjectMembers([{ }, name: "w" }, - init: null + binding: null }])); testLoose('a{ obj w }', rootObjectMembers([{ @@ -2778,7 +2903,7 @@ testLoose('a{ obj w }', rootObjectMembers([{ }, name: "w" }, - init: null + binding: null }])); // TODO: Allow this to run with the normal parser once the ambiguity is solved @@ -2799,7 +2924,7 @@ testLoose('a{ property var b: Window {} }', rootObjectMembers([{ }, name: "b" }, - init: { + binding: { type: "QMLObjectLiteral", loc: { start: { line: 1, column: 19 }, @@ -2841,7 +2966,7 @@ testLoose('a{ b: Window {} }', rootObjectMembers([{ parts: [{ type: "Identifier", name: "b" }], name: "b" }, - expr: { + binding: { type: "QMLObjectLiteral", loc: { start: { line: 1, column: 6 }, @@ -2999,7 +3124,7 @@ testLoose('Window {\n\tfunction\n\tproperty var prop\n}', rootObjectMembers([ }, name: "prop" }, - init: null + binding: null } ])); @@ -3054,7 +3179,7 @@ testLoose('Window {\n\tfunction (something)\n\tproperty var prop\n}', rootObject }, name: "prop" }, - init: null + binding: null } ])); @@ -3100,7 +3225,7 @@ testLoose('Window {\n\tfunction (\n\tproperty var prop\n}', rootObjectMembers([ }, name: "prop" }, - init: null + binding: null } ])); @@ -3110,7 +3235,7 @@ testLoose('Window {\n\tfunction (\n\tproperty var prop\n}', rootObjectMembers([ */ function program(headerStatements, rootObject) { return { - type: "Program", + type: "QMLProgram", headerStatements: { type: "QMLHeaderStatements", statements: headerStatements || [] @@ -3165,7 +3290,10 @@ function rootObjectMembers(members, obj) { function javaScript(expr, objMembers) { objMembers = objMembers || rootObjectMembers([{ type: "QMLPropertyBinding", - expr: expr + binding: { + type: "QMLScriptBinding", + script: expr + } }]); return objMembers; } \ No newline at end of file diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/walk/index.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/walk/index.js index aad79857d53..4ff5a0769b5 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/walk/index.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/walk/index.js @@ -8,15 +8,15 @@ * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ -'use strict'; - (function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - return mod(require("acorn/dist/walk")); + return module.exports = mod(require("acorn/dist/walk")); if (typeof define == "function" && define.amd) // AMD return define(["acorn/dist/walk"], mod); mod(acorn.walk); // Plain browser env })(function (walk) { + "use strict"; + function skipThrough(node, st, c) { c(node, st) } @@ -24,7 +24,7 @@ function ignore(node, st, c) {} var base = walk.base; - base["Program"] = function (node, st, c) { + base["QMLProgram"] = function (node, st, c) { c(node.headerStatements, st); if (node.rootObject) { c(node.rootObject, st, "QMLRootObject"); @@ -49,18 +49,22 @@ }; base["QMLMember"] = skipThrough; base["QMLPropertyDeclaration"] = function (node, st, c) { - if (node.init) { - c(node.init, st); + if (node.binding) { + c(node.binding, st); } }; base["QMLSignalDefinition"] = ignore; base["QMLPropertyBinding"] = function (node, st, c) { - c(node.expr, st); + c(node.binding, st); }; + base["QMLScriptBinding"] = function (node, st, c) { + c(node.script, st); + } base["QMLQualifiedID"] = ignore; base["QMLStatementBlock"] = function (node, st, c) { for (var i = 0; i < node.statements.length; i++) { c(node.statements[i], st, "Statement"); } }; + return walk; }) \ No newline at end of file diff --git a/qt/org.eclipse.cdt.qt.core/tern-qml/demo/qml-demo.html b/qt/org.eclipse.cdt.qt.core/tern-qml/demo/qml-demo.html index 1349e002b97..ddb97e23118 100644 --- a/qt/org.eclipse.cdt.qt.core/tern-qml/demo/qml-demo.html +++ b/qt/org.eclipse.cdt.qt.core/tern-qml/demo/qml-demo.html @@ -21,7 +21,9 @@ - + + + @@ -57,7 +59,9 @@

Demo with QML Tern plugin

+
+