diff options
author | Ulf Hermann <[email protected]> | 2021-04-10 08:56:08 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2021-04-16 14:29:55 +0200 |
commit | 16b30313ad6d9421a75c228dcacf5e2f9ded29ed (patch) | |
tree | 9c89e4b8019447bc747bfe7b426abc0d88a591f7 | |
parent | 9cd1e7902ce882a54e369556068f2707090df658 (diff) |
Rework qmljsrootgen
This way it actually generates interesting data about the JavaScript
types, for example the functions of the String prototype. Add a helper
method to create a symbol to QJSEngine. This should be generally useful.
Change-Id: I6c7b253b9d6cdb61602ceeae0955aed8d942c139
Reviewed-by: Fabian Kosmale <[email protected]>
-rw-r--r-- | src/imports/builtins/jsroot.qmltypes | 1570 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 17 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4propertykey_p.h | 6 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 4 | ||||
-rw-r--r-- | tools/qmljsrootgen/main.cpp | 401 |
6 files changed, 1600 insertions, 399 deletions
diff --git a/src/imports/builtins/jsroot.qmltypes b/src/imports/builtins/jsroot.qmltypes index 0f68ac280f..419a4e5726 100644 --- a/src/imports/builtins/jsroot.qmltypes +++ b/src/imports/builtins/jsroot.qmltypes @@ -7,25 +7,145 @@ import QtQuick.tooling 1.2 Module { Component { + name: "Array" + accessSemantics: "reference" + prototype: "ArrayPrototype" + Property { name: "length"; type: "number" } + } + Component { name: "ArrayBuffer" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ArrayBufferPrototype" + } + Component { + name: "ArrayBufferPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "byteLength" } + Method { + name: "constructor" + type: "ArrayBuffer" + isConstructor: true + Parameter {} + } + Method { + name: "slice" + Parameter {} + Parameter {} + } + Method { name: "toString" } } Component { - name: "ArrayObject" + name: "ArrayPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } + prototype: "ObjectPrototype" Property { name: "length"; type: "number" } + Method { + name: "constructor" + type: "Array" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + Method { name: "toLocaleString" } + Method { + name: "concat" + Parameter {} + } + Method { + name: "copyWithin" + Parameter {} + Parameter {} + } + Method { name: "entries" } + Method { + name: "fill" + Parameter {} + } + Method { + name: "find" + Parameter {} + } + Method { + name: "findIndex" + Parameter {} + } + Method { + name: "includes" + Parameter {} + } + Method { + name: "join" + Parameter {} + } + Method { name: "keys" } + Method { name: "pop" } + Method { + name: "push" + Parameter {} + } + Method { name: "reverse" } + Method { name: "shift" } + Method { + name: "slice" + Parameter {} + Parameter {} + } + Method { + name: "sort" + Parameter {} + } + Method { + name: "splice" + Parameter {} + Parameter {} + } + Method { + name: "unshift" + Parameter {} + } + Method { + name: "indexOf" + Parameter {} + } + Method { + name: "lastIndexOf" + Parameter {} + } + Method { + name: "every" + Parameter {} + } + Method { + name: "some" + Parameter {} + } + Method { + name: "forEach" + Parameter {} + } + Method { + name: "map" + Parameter {} + } + Method { + name: "filter" + Parameter {} + } + Method { + name: "reduce" + Parameter {} + } + Method { + name: "reduceRight" + Parameter {} + } + Method { name: "values" } } Component { name: "Atomics" accessSemantics: "reference" - prototype: "Object" + prototype: "ObjectPrototype" Method { name: "add" Parameter {} @@ -98,92 +218,456 @@ Module { Parameter {} } } + Component { name: "Boolean"; accessSemantics: "reference"; prototype: "BooleanPrototype" } Component { - name: "BooleanObject" + name: "BooleanPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ObjectPrototype" + Method { + name: "constructor" + type: "Boolean" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + Method { name: "valueOf" } } Component { - name: "ConsoleObject" + name: "Console" accessSemantics: "reference" - prototype: "Object" - Method { name: "assert" } - Method { name: "count" } + prototype: "ObjectPrototype" Method { name: "debug" } - Method { name: "error" } - Method { name: "exception" } - Method { name: "info" } Method { name: "log" } + Method { name: "info" } + Method { name: "warn" } + Method { name: "error" } + Method { name: "assert" } + Method { name: "count" } Method { name: "profile" } Method { name: "profileEnd" } Method { name: "time" } Method { name: "timeEnd" } Method { name: "trace" } - Method { name: "warn" } + Method { name: "exception" } } + Component { name: "DataView"; accessSemantics: "reference"; prototype: "DataViewPrototype" } Component { - name: "DateObject" + name: "DataViewPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ObjectPrototype" + Property { name: "buffer" } + Property { name: "byteLength" } + Property { name: "byteOffset" } + Method { + name: "constructor" + type: "DataView" + isConstructor: true + Parameter {} + } + Method { + name: "getInt8" + Parameter {} + } + Method { + name: "getUint8" + Parameter {} + } + Method { + name: "getInt16" + Parameter {} + } + Method { + name: "getUint16" + Parameter {} + } + Method { + name: "getInt32" + Parameter {} + } + Method { + name: "getUint32" + Parameter {} + } + Method { + name: "getFloat32" + Parameter {} + } + Method { + name: "getFloat64" + Parameter {} + } + Method { + name: "setInt8" + Parameter {} + Parameter {} + } + Method { + name: "setUint8" + Parameter {} + Parameter {} + } + Method { + name: "setInt16" + Parameter {} + Parameter {} + } + Method { + name: "setUint16" + Parameter {} + Parameter {} + } + Method { + name: "setInt32" + Parameter {} + Parameter {} + } + Method { + name: "setUint32" + Parameter {} + Parameter {} + } + Method { + name: "setFloat32" + Parameter {} + Parameter {} + } + Method { + name: "setFloat64" + Parameter {} + Parameter {} + } + Method { + name: "getUInt8" + Parameter {} + } + Method { + name: "getUInt16" + Parameter {} + } + Method { + name: "getUInt32" + Parameter {} + } + Method { + name: "setUInt8" + Parameter {} + } + Method { + name: "setUInt16" + Parameter {} + } + Method { + name: "setUInt32" + Parameter {} + } } + Component { name: "Date"; accessSemantics: "reference"; prototype: "DatePrototype" } Component { - name: "ErrorObject" + name: "DatePrototype" accessSemantics: "reference" - prototype: "Object" + prototype: "ObjectPrototype" + Method { + name: "constructor" + type: "Date" + isConstructor: true + Parameter {} + Parameter {} + Parameter {} + Parameter {} + Parameter {} + Parameter {} + Parameter {} + } + Method { name: "toString" } + Method { name: "toDateString" } + Method { name: "toTimeString" } + Method { name: "toLocaleString" } + Method { name: "toLocaleDateString" } + Method { name: "toLocaleTimeString" } + Method { name: "valueOf" } + Method { name: "getTime" } + Method { name: "getYear" } + Method { name: "getFullYear" } + Method { name: "getUTCFullYear" } + Method { name: "getMonth" } + Method { name: "getUTCMonth" } + Method { name: "getDate" } + Method { name: "getUTCDate" } + Method { name: "getDay" } + Method { name: "getUTCDay" } + Method { name: "getHours" } + Method { name: "getUTCHours" } + Method { name: "getMinutes" } + Method { name: "getUTCMinutes" } + Method { name: "getSeconds" } + Method { name: "getUTCSeconds" } + Method { name: "getMilliseconds" } + Method { name: "getUTCMilliseconds" } + Method { name: "getTimezoneOffset" } + Method { + name: "setTime" + Parameter {} + } + Method { + name: "setMilliseconds" + Parameter {} + } + Method { + name: "setUTCMilliseconds" + Parameter {} + } + Method { + name: "setSeconds" + Parameter {} + Parameter {} + } + Method { + name: "setUTCSeconds" + Parameter {} + Parameter {} + } + Method { + name: "setMinutes" + Parameter {} + Parameter {} + Parameter {} + } + Method { + name: "setUTCMinutes" + Parameter {} + Parameter {} + Parameter {} + } + Method { + name: "setHours" + Parameter {} + Parameter {} + Parameter {} + Parameter {} + } + Method { + name: "setUTCHours" + Parameter {} + Parameter {} + Parameter {} + Parameter {} + } + Method { + name: "setDate" + Parameter {} + } + Method { + name: "setUTCDate" + Parameter {} + } + Method { + name: "setMonth" + Parameter {} + Parameter {} + } + Method { + name: "setUTCMonth" + Parameter {} + Parameter {} + } + Method { + name: "setYear" + Parameter {} + } + Method { + name: "setFullYear" + Parameter {} + Parameter {} + Parameter {} + } + Method { + name: "setUTCFullYear" + Parameter {} + Parameter {} + Parameter {} + } + Method { name: "toUTCString" } + Method { name: "toGMTString" } + Method { name: "toISOString" } + Method { + name: "toJSON" + Parameter {} + } + } + Component { + name: "Error" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "stack"; type: "string" } Property { name: "fileName" } Property { name: "lineNumber" } + } + Component { + name: "ErrorPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } + Method { + name: "constructor" + type: "Error" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + } + Component { + name: "EvalError" + accessSemantics: "reference" + prototype: "EvalErrorPrototype" Property { name: "stack"; type: "string" } - Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "EvalErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } + Method { + name: "constructor" + type: "EvalError" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + } + Component { + name: "Float32Array" + accessSemantics: "reference" + prototype: "Float32ArrayPrototype" + } + Component { + name: "Float32ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } + Method { + name: "constructor" + type: "Float32Array" + isConstructor: true + Parameter {} + Parameter {} + Parameter {} + } + } + Component { + name: "Float64Array" + accessSemantics: "reference" + prototype: "Float64ArrayPrototype" + } + Component { + name: "Float64ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } + Method { + name: "constructor" + type: "Float64Array" + isConstructor: true + Parameter {} + Parameter {} + Parameter {} + } + } + Component { + name: "Function" + accessSemantics: "reference" + prototype: "FunctionPrototype" + Property { name: "prototype"; type: "Object" } + Property { name: "name"; type: "string"; isReadonly: true } + Property { name: "length"; type: "number"; isReadonly: true } + } + Component { + name: "FunctionPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "name"; type: "string"; isReadonly: true } + Property { name: "length"; type: "number"; isReadonly: true } + Property { name: "caller" } + Property { name: "arguments" } + Method { + name: "constructor" + type: "Function" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + Method { + name: "apply" + Parameter {} + Parameter {} + } + Method { + name: "call" + Parameter {} + } + Method { + name: "bind" + Parameter {} + } + Method { name: "connect" } + Method { name: "disconnect" } } Component { name: "GlobalObject" accessSemantics: "reference" - prototype: "Object" - exports: ["QJSEngine/GlobalObject 1.0"] - exportMetaObjectRevisions: [256] + prototype: "ObjectPrototype" Property { name: "Atomics"; type: "Atomics" } - Property { name: "Infinity"; type: "number"; isReadonly: true } - Property { name: "JSON"; type: "JsonObject" } - Property { name: "Math"; type: "MathObject" } - Property { name: "NaN"; type: "number"; isReadonly: true } - Property { name: "Qt"; type: "QtObject" } + Property { name: "Math"; type: "Math" } + Property { name: "JSON"; type: "JSON" } Property { name: "Reflect"; type: "Reflect" } - Property { name: "console"; type: "ConsoleObject" } - Property { name: "undefined"; type: "undefined"; isReadonly: true } + Property { name: "undefined" } + Property { name: "NaN"; type: "number"; isReadonly: true } + Property { name: "Infinity"; type: "number"; isReadonly: true } + Property { name: "Qt"; type: "Qt" } + Property { name: "console"; type: "Console" } Method { - name: "Array" - type: "ArrayObject" + name: "Object" + type: "Object" isConstructor: true Parameter {} } Method { - name: "ArrayBuffer" - type: "ArrayBuffer" + name: "String" + type: "String" + isConstructor: true + Parameter {} + } + Method { name: "Symbol"; type: "undefined"; isConstructor: true } + Method { + name: "Number" + type: "Number" isConstructor: true Parameter {} } Method { name: "Boolean" - type: "BooleanObject" + type: "Boolean" isConstructor: true Parameter {} } Method { - name: "DataView" - type: "ErrorObject" + name: "Array" + type: "Array" + isConstructor: true + Parameter {} + } + Method { + name: "Function" + type: "Function" isConstructor: true Parameter {} } Method { name: "Date" - type: "DateObject" + type: "Date" isConstructor: true Parameter {} Parameter {} @@ -194,234 +678,356 @@ Module { Parameter {} } Method { + name: "RegExp" + type: "RegExp" + isConstructor: true + Parameter {} + Parameter {} + } + Method { name: "Error" - type: "ErrorObject" + type: "Error" isConstructor: true Parameter {} } Method { name: "EvalError" - type: "ErrorObject" + type: "EvalError" isConstructor: true Parameter {} } Method { - name: "Float32Array" - type: "TypedArray" + name: "RangeError" + type: "RangeError" isConstructor: true Parameter {} - Parameter {} + } + Method { + name: "ReferenceError" + type: "ReferenceError" + isConstructor: true Parameter {} } Method { - name: "Float64Array" - type: "TypedArray" + name: "SyntaxError" + type: "SyntaxError" isConstructor: true Parameter {} + } + Method { + name: "TypeError" + type: "TypeError" + isConstructor: true Parameter {} + } + Method { + name: "URIError" + type: "URIError" + isConstructor: true Parameter {} } Method { - name: "Function" - type: "ScriptFunction" + name: "Promise" + type: "Promise" isConstructor: true Parameter {} } + Method { name: "URL"; type: "URL"; isConstructor: true } + Method { name: "URLSearchParams"; type: "URLSearchParams"; isConstructor: true } Method { - name: "Int16Array" - type: "TypedArray" + name: "SharedArrayBuffer" + type: "SharedArrayBuffer" isConstructor: true Parameter {} + } + Method { + name: "ArrayBuffer" + type: "ArrayBuffer" + isConstructor: true Parameter {} + } + Method { + name: "DataView" + type: "DataView" + isConstructor: true Parameter {} } + Method { name: "WeakSet"; type: "WeakSet"; isConstructor: true } + Method { name: "Set"; type: "Set"; isConstructor: true } + Method { name: "WeakMap"; type: "WeakMap"; isConstructor: true } + Method { name: "Map"; type: "Map"; isConstructor: true } Method { - name: "Int32Array" - type: "TypedArray" + name: "Int8Array" + type: "Int8Array" isConstructor: true Parameter {} Parameter {} Parameter {} } Method { - name: "Int8Array" - type: "TypedArray" + name: "Uint8Array" + type: "Uint8Array" isConstructor: true Parameter {} Parameter {} Parameter {} } - Method { name: "Map"; type: "MapObject"; isConstructor: true } Method { - name: "Number" - type: "NumberObject" + name: "Int16Array" + type: "Int16Array" isConstructor: true Parameter {} + Parameter {} + Parameter {} } Method { - name: "Object" - type: "Object" + name: "Uint16Array" + type: "Uint16Array" isConstructor: true Parameter {} + Parameter {} + Parameter {} } Method { - name: "Promise" - type: "ErrorObject" + name: "Int32Array" + type: "Int32Array" isConstructor: true Parameter {} + Parameter {} + Parameter {} } Method { - name: "Proxy" - type: "ErrorObject" + name: "Uint32Array" + type: "Uint32Array" isConstructor: true Parameter {} Parameter {} + Parameter {} } - Method { name: "QT_TRANSLATE_NOOP" } - Method { name: "QT_TRID_NOOP" } - Method { name: "QT_TR_NOOP" } Method { - name: "RangeError" - type: "ErrorObject" + name: "Uint8ClampedArray" + type: "Uint8ClampedArray" isConstructor: true Parameter {} + Parameter {} + Parameter {} } Method { - name: "ReferenceError" - type: "ErrorObject" + name: "Float32Array" + type: "Float32Array" isConstructor: true Parameter {} + Parameter {} + Parameter {} } Method { - name: "RegExp" - type: "RegExpObject" + name: "Float64Array" + type: "Float64Array" isConstructor: true Parameter {} Parameter {} + Parameter {} } - Method { name: "Set"; type: "SetObject"; isConstructor: true } Method { - name: "SharedArrayBuffer" - type: "SharedArrayBuffer" + name: "Proxy" + type: "Proxy" isConstructor: true Parameter {} + Parameter {} } Method { - name: "String" - type: "StringObject" - isConstructor: true + name: "eval" Parameter {} } - Method { name: "Symbol"; type: "ErrorObject"; isConstructor: true } Method { - name: "SyntaxError" - type: "ErrorObject" - isConstructor: true + name: "parseInt" + Parameter {} Parameter {} } Method { - name: "TypeError" - type: "ErrorObject" - isConstructor: true + name: "parseFloat" Parameter {} } Method { - name: "URIError" - type: "ErrorObject" - isConstructor: true + name: "isNaN" Parameter {} } - Method { name: "URL"; type: "ErrorObject"; isConstructor: true } - Method { name: "URLSearchParams"; type: "UrlSearchParamsObject"; isConstructor: true } Method { - name: "Uint16Array" - type: "TypedArray" - isConstructor: true + name: "isFinite" Parameter {} + } + Method { + name: "decodeURI" Parameter {} + } + Method { + name: "decodeURIComponent" Parameter {} } Method { - name: "Uint32Array" - type: "TypedArray" + name: "encodeURI" + Parameter {} + } + Method { + name: "encodeURIComponent" + Parameter {} + } + Method { + name: "escape" + Parameter {} + } + Method { + name: "unescape" + Parameter {} + } + Method { name: "qsTranslate" } + Method { name: "QT_TRANSLATE_NOOP" } + Method { name: "qsTr" } + Method { name: "QT_TR_NOOP" } + Method { name: "qsTrId" } + Method { name: "QT_TRID_NOOP" } + Method { name: "print" } + Method { name: "gc" } + } + Component { name: "Int16Array"; accessSemantics: "reference"; prototype: "Int16ArrayPrototype" } + Component { + name: "Int16ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } + Method { + name: "constructor" + type: "Int16Array" isConstructor: true Parameter {} Parameter {} Parameter {} } + } + Component { name: "Int32Array"; accessSemantics: "reference"; prototype: "Int32ArrayPrototype" } + Component { + name: "Int32ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } Method { - name: "Uint8Array" - type: "TypedArray" + name: "constructor" + type: "Int32Array" isConstructor: true Parameter {} Parameter {} Parameter {} } + } + Component { name: "Int8Array"; accessSemantics: "reference"; prototype: "Int8ArrayPrototype" } + Component { + name: "Int8ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } Method { - name: "Uint8ClampedArray" - type: "TypedArray" + name: "constructor" + type: "Int8Array" isConstructor: true Parameter {} Parameter {} Parameter {} } - Method { name: "WeakMap"; type: "MapObject"; isConstructor: true } - Method { name: "WeakSet"; type: "SetObject"; isConstructor: true } + } + Component { + name: "IntrinsicTypedArrayPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "buffer" } + Property { name: "byteLength" } + Property { name: "byteOffset" } + Property { name: "length" } Method { - name: "decodeURI" + name: "copyWithin" + Parameter {} Parameter {} } + Method { name: "entries" } Method { - name: "decodeURIComponent" + name: "every" Parameter {} } Method { - name: "encodeURI" + name: "fill" Parameter {} } Method { - name: "encodeURIComponent" + name: "filter" Parameter {} } Method { - name: "escape" + name: "find" Parameter {} } Method { - name: "eval" + name: "findIndex" Parameter {} } - Method { name: "gc" } Method { - name: "isFinite" + name: "forEach" Parameter {} } Method { - name: "isNaN" + name: "includes" Parameter {} } Method { - name: "parseFloat" + name: "indexOf" Parameter {} } Method { - name: "parseInt" + name: "join" Parameter {} + } + Method { name: "keys" } + Method { + name: "lastIndexOf" Parameter {} } - Method { name: "print" } - Method { name: "qsTr" } - Method { name: "qsTrId" } - Method { name: "qsTranslate" } Method { - name: "unescape" + name: "map" + Parameter {} + } + Method { + name: "reduce" + Parameter {} + } + Method { + name: "reduceRight" + Parameter {} + } + Method { name: "reverse" } + Method { + name: "some" + Parameter {} + } + Method { + name: "set" + Parameter {} + } + Method { + name: "slice" + Parameter {} + Parameter {} + } + Method { + name: "subarray" + Parameter {} Parameter {} } + Method { name: "toLocaleString" } + Method { name: "toString" } + Method { name: "values" } } Component { - name: "JsonObject" + name: "JSON" accessSemantics: "reference" - prototype: "Object" + prototype: "ObjectPrototype" Method { name: "parse" Parameter {} @@ -434,23 +1040,48 @@ Module { Parameter {} } } + Component { name: "Map"; accessSemantics: "reference"; prototype: "MapPrototype" } Component { - name: "MapObject" + name: "MapPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ObjectPrototype" + Property { name: "size" } + Method { name: "constructor"; type: "Map"; isConstructor: true } + Method { name: "clear" } + Method { + name: "delete" + Parameter {} + } + Method { + name: "forEach" + Parameter {} + } + Method { + name: "get" + Parameter {} + } + Method { + name: "has" + Parameter {} + } + Method { name: "keys" } + Method { + name: "set" + Parameter {} + Parameter {} + } + Method { name: "values" } + Method { name: "entries" } } Component { - name: "MathObject" + name: "Math" accessSemantics: "reference" - prototype: "Object" + prototype: "ObjectPrototype" Property { name: "E"; type: "number"; isReadonly: true } - Property { name: "LN10"; type: "number"; isReadonly: true } Property { name: "LN2"; type: "number"; isReadonly: true } - Property { name: "LOG10E"; type: "number"; isReadonly: true } + Property { name: "LN10"; type: "number"; isReadonly: true } Property { name: "LOG2E"; type: "number"; isReadonly: true } + Property { name: "LOG10E"; type: "number"; isReadonly: true } Property { name: "PI"; type: "number"; isReadonly: true } Property { name: "SQRT1_2"; type: "number"; isReadonly: true } Property { name: "SQRT2"; type: "number"; isReadonly: true } @@ -479,12 +1110,12 @@ Module { Parameter {} } Method { - name: "atan2" - Parameter {} + name: "atanh" Parameter {} } Method { - name: "atanh" + name: "atan2" + Parameter {} Parameter {} } Method { @@ -598,22 +1229,62 @@ Module { Parameter {} } } + Component { name: "Number"; accessSemantics: "reference"; prototype: "NumberPrototype" } Component { - name: "NumberObject" + name: "NumberPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ObjectPrototype" + Method { + name: "constructor" + type: "Number" + isConstructor: true + Parameter {} + } + Method { + name: "toString" + Parameter {} + } + Method { name: "toLocaleString" } + Method { name: "valueOf" } + Method { + name: "toFixed" + Parameter {} + } + Method { + name: "toExponential" + Parameter {} + } + Method { + name: "toPrecision" + Parameter {} + } } + Component { name: "Object"; accessSemantics: "reference"; prototype: "ObjectPrototype" } Component { - name: "Object" + name: "ObjectPrototype" accessSemantics: "reference" - Property { name: "__proto__"; type: "undefined" } - Property { name: "__proto__"; type: "undefined" } - Property { name: "length"; type: "number"; isReadonly: true } - Property { name: "name"; type: "string"; isReadonly: true } - Property { name: "prototype"; type: "Object"; isReadonly: true } + Property { name: "__proto__" } + Method { + name: "constructor" + type: "Object" + isConstructor: true + Parameter {} + } + Method { name: "toString" } + Method { name: "toLocaleString" } + Method { name: "valueOf" } + Method { + name: "hasOwnProperty" + Parameter {} + } + Method { + name: "isPrototypeOf" + Parameter {} + } + Method { + name: "propertyIsEnumerable" + Parameter {} + } Method { name: "__defineGetter__" Parameter {} @@ -624,24 +1295,188 @@ Module { Parameter {} Parameter {} } + } + Component { name: "Promise"; accessSemantics: "reference"; prototype: "PromisePrototype" } + Component { + name: "PromisePrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Method { + name: "constructor" + type: "Promise" + isConstructor: true + Parameter {} + } + Method { + name: "then" + Parameter {} + Parameter {} + } Method { - name: "assign" + name: "catch" Parameter {} + } + } + Component { name: "Proxy"; accessSemantics: "reference"; prototype: "ObjectPrototype" } + Component { + name: "Qt" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "objectName"; type: "string" } + Property { name: "application"; type: "QtApplication" } + Property { name: "platform"; type: "QtPlatform" } + Property { name: "inputMethod"; type: "QtInputMethod" } + Property { name: "styleHints"; type: "QtStyleHints" } + Property { name: "uiLanguage"; type: "string" } + Method { + name: "callLater" + Parameter {} + } + Method { name: "objectNameChanged" } + Method { name: "include" } + Method { name: "isQtObject" } + Method { name: "color" } + Method { name: "rgba" } + Method { name: "hsla" } + Method { name: "hsva" } + Method { name: "colorEqual" } + Method { name: "rect" } + Method { name: "point" } + Method { name: "size" } + Method { name: "vector2d" } + Method { name: "vector3d" } + Method { name: "vector4d" } + Method { name: "quaternion" } + Method { name: "matrix4x4" } + Method { name: "lighter" } + Method { name: "darker" } + Method { name: "alpha" } + Method { name: "tint" } + Method { name: "formatDate" } + Method { name: "formatTime" } + Method { name: "formatDateTime" } + Method { name: "locale" } + Method { name: "resolvedUrl" } + Method { name: "openUrlExternally" } + Method { name: "font" } + Method { name: "fontFamilies" } + Method { name: "md5" } + Method { name: "btoa" } + Method { name: "atob" } + Method { name: "quit" } + Method { name: "exit" } + Method { name: "createQmlObject" } + Method { name: "createComponent" } + Method { name: "binding" } + } + Component { + name: "QtApplication" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "objectName"; type: "string" } + Property { name: "arguments"; type: "QtApplicationArguments" } + Property { name: "name"; type: "string" } + Property { name: "version"; type: "string" } + Property { name: "organization"; type: "string" } + Property { name: "domain"; type: "string" } + Method { name: "objectNameChanged" } + Method { name: "aboutToQuit" } + Method { name: "nameChanged" } + Method { name: "versionChanged" } + Method { name: "organizationChanged" } + Method { name: "domainChanged" } + Method { name: "setName" } + Method { name: "setVersion" } + Method { name: "setOrganization" } + Method { name: "setDomain" } + } + Component { + name: "QtApplicationArguments" + accessSemantics: "reference" + prototype: "ArrayPrototype" + Property { name: "0"; type: "string" } + Property { name: "1"; type: "string" } + Property { name: "length"; type: "number" } + } + Component { + name: "QtInputMethod" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "objectName"; type: "string" } + Method { name: "objectNameChanged" } + } + Component { + name: "QtPlatform" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "objectName"; type: "string" } + Property { name: "os"; type: "string" } + Property { name: "pluginName"; type: "string" } + Method { name: "objectNameChanged" } + } + Component { + name: "QtStyleHints" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "objectName"; type: "string" } + Method { name: "objectNameChanged" } + } + Component { + name: "RangeError" + accessSemantics: "reference" + prototype: "RangeErrorPrototype" + Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "RangeErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } + Method { + name: "constructor" + type: "RangeError" + isConstructor: true Parameter {} } + Method { name: "toString" } + } + Component { + name: "ReferenceError" + accessSemantics: "reference" + prototype: "ReferenceErrorPrototype" + Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "ReferenceErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } Method { name: "constructor" - type: "Object" + type: "ReferenceError" isConstructor: true Parameter {} } + Method { name: "toString" } + } + Component { + name: "Reflect" + accessSemantics: "reference" + prototype: "ObjectPrototype" Method { - name: "create" + name: "apply" + Parameter {} Parameter {} Parameter {} } Method { - name: "defineProperties" + name: "construct" Parameter {} Parameter {} } @@ -652,11 +1487,13 @@ Module { Parameter {} } Method { - name: "entries" + name: "deleteProperty" + Parameter {} Parameter {} } Method { - name: "freeze" + name: "get" + Parameter {} Parameter {} } Method { @@ -665,217 +1502,482 @@ Module { Parameter {} } Method { - name: "getOwnPropertyDescriptors" + name: "getPrototypeOf" Parameter {} } Method { - name: "getOwnPropertyNames" + name: "has" + Parameter {} Parameter {} } Method { - name: "getOwnPropertySymbols" + name: "isExtensible" Parameter {} } Method { - name: "getPrototypeOf" + name: "ownKeys" Parameter {} } Method { - name: "hasOwnProperty" + name: "preventExtensions" Parameter {} } Method { - name: "is" + name: "set" + Parameter {} Parameter {} Parameter {} } Method { - name: "isExtensible" + name: "setPrototypeOf" + Parameter {} Parameter {} } + } + Component { + name: "RegExp" + accessSemantics: "reference" + prototype: "RegExpPrototype" + Property { name: "lastIndex"; type: "number" } + } + Component { + name: "RegExpPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "flags"; type: "string" } + Property { name: "global" } + Property { name: "ignoreCase" } + Property { name: "multiline" } + Property { name: "source"; type: "string" } + Property { name: "sticky" } + Property { name: "unicode" } Method { - name: "isFrozen" + name: "constructor" + type: "RegExp" + isConstructor: true + Parameter {} Parameter {} } Method { - name: "isPrototypeOf" + name: "exec" Parameter {} } Method { - name: "isSealed" + name: "test" Parameter {} } + Method { name: "toString" } Method { - name: "keys" + name: "compile" + Parameter {} Parameter {} } + } + Component { name: "Set"; accessSemantics: "reference"; prototype: "SetPrototype" } + Component { + name: "SetPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "size" } + Method { name: "constructor"; type: "Set"; isConstructor: true } Method { - name: "preventExtensions" + name: "add" Parameter {} } + Method { name: "clear" } Method { - name: "propertyIsEnumerable" + name: "delete" Parameter {} } + Method { name: "entries" } Method { - name: "seal" + name: "forEach" Parameter {} } Method { - name: "setPrototypeOf" + name: "has" Parameter {} + } + Method { name: "keys" } + Method { name: "values" } + } + Component { + name: "SharedArrayBuffer" + accessSemantics: "reference" + prototype: "SharedArrayBufferPrototype" + } + Component { + name: "SharedArrayBufferPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Property { name: "byteLength" } + Method { + name: "constructor" + type: "SharedArrayBuffer" + isConstructor: true Parameter {} } - Method { name: "toLocaleString" } - Method { name: "toString" } - Method { name: "valueOf" } Method { - name: "values" + name: "slice" + Parameter {} Parameter {} } } Component { - name: "Reflect" + name: "String" + accessSemantics: "reference" + prototype: "StringPrototype" + Property { name: "length"; type: "number"; isReadonly: true } + } + Component { + name: "StringPrototype" accessSemantics: "reference" - prototype: "Object" + prototype: "ObjectPrototype" + Property { name: "length"; type: "number"; isReadonly: true } Method { - name: "apply" + name: "constructor" + type: "String" + isConstructor: true Parameter {} + } + Method { name: "toString" } + Method { name: "valueOf" } + Method { + name: "charAt" Parameter {} + } + Method { + name: "charCodeAt" Parameter {} } Method { - name: "construct" + name: "codePointAt" Parameter {} + } + Method { + name: "concat" Parameter {} } Method { - name: "defineProperty" + name: "endsWith" Parameter {} + } + Method { + name: "indexOf" Parameter {} + } + Method { + name: "includes" Parameter {} } Method { - name: "deleteProperty" + name: "lastIndexOf" Parameter {} + } + Method { + name: "localeCompare" Parameter {} } Method { - name: "get" + name: "match" + Parameter {} + } + Method { name: "normalize" } + Method { + name: "padEnd" Parameter {} + } + Method { + name: "padStart" Parameter {} } Method { - name: "getOwnPropertyDescriptor" + name: "repeat" + Parameter {} + } + Method { + name: "replace" Parameter {} Parameter {} } Method { - name: "getPrototypeOf" + name: "search" Parameter {} } Method { - name: "has" + name: "slice" Parameter {} Parameter {} } Method { - name: "isExtensible" + name: "split" + Parameter {} Parameter {} } Method { - name: "ownKeys" + name: "startsWith" Parameter {} } Method { - name: "preventExtensions" + name: "substr" + Parameter {} Parameter {} } Method { - name: "set" + name: "substring" Parameter {} Parameter {} + } + Method { name: "toLowerCase" } + Method { name: "toLocaleLowerCase" } + Method { name: "toUpperCase" } + Method { name: "toLocaleUpperCase" } + Method { name: "trim" } + Method { name: "arg" } + } + Component { + name: "SymbolPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Method { name: "constructor"; type: "undefined"; isConstructor: true } + Method { name: "toString" } + Method { name: "valueOf" } + } + Component { + name: "SyntaxError" + accessSemantics: "reference" + prototype: "SyntaxErrorPrototype" + Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "SyntaxErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } + Method { + name: "constructor" + type: "SyntaxError" + isConstructor: true Parameter {} } + Method { name: "toString" } + } + Component { + name: "TypeError" + accessSemantics: "reference" + prototype: "TypeErrorPrototype" + Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "TypeErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } Method { - name: "setPrototypeOf" + name: "constructor" + type: "TypeError" + isConstructor: true Parameter {} + } + Method { name: "toString" } + } + Component { + name: "URIError" + accessSemantics: "reference" + prototype: "URIErrorPrototype" + Property { name: "stack"; type: "string" } + Property { name: "fileName" } + Property { name: "lineNumber" } + } + Component { + name: "URIErrorPrototype" + accessSemantics: "reference" + prototype: "ErrorPrototype" + Property { name: "message"; type: "string" } + Property { name: "name"; type: "string" } + Method { + name: "constructor" + type: "URIError" + isConstructor: true Parameter {} } + Method { name: "toString" } } + Component { name: "URL"; accessSemantics: "reference"; prototype: "URLPrototype" } Component { - name: "RegExpObject" + name: "URLPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "lastIndex"; type: "number" } + prototype: "ObjectPrototype" + Property { name: "hash" } + Property { name: "host" } + Property { name: "hostname" } + Property { name: "href" } + Property { name: "origin" } + Property { name: "password" } + Property { name: "pathname" } + Property { name: "port" } + Property { name: "protocol" } + Property { name: "search" } + Property { name: "searchParams" } + Property { name: "username" } + Method { name: "toString" } + Method { name: "toJSON" } } Component { - name: "ScriptFunction" + name: "URLSearchParams" accessSemantics: "reference" - prototype: "Object" - Property { name: "length"; type: "number"; isReadonly: true } - Property { name: "name"; type: "string"; isReadonly: true } - Property { name: "prototype"; type: "Object" } + prototype: "URLSearchParamsPrototype" } Component { - name: "SetObject" + name: "URLSearchParamsPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "ObjectPrototype" + Method { name: "toString" } + Method { name: "sort" } + Method { name: "append" } + Method { name: "delete" } + Method { name: "has" } + Method { name: "set" } + Method { name: "get" } + Method { name: "getAll" } + Method { name: "forEach" } + Method { name: "entries" } + Method { name: "keys" } + Method { name: "values" } } Component { - name: "SharedArrayBuffer" + name: "Uint16Array" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "Uint16ArrayPrototype" } Component { - name: "StringObject" + name: "Uint16ArrayPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "length"; type: "number"; isReadonly: true } + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } Method { - name: "charAt" + name: "constructor" + type: "Uint16Array" + isConstructor: true + Parameter {} + Parameter {} Parameter {} } + } + Component { + name: "Uint32Array" + accessSemantics: "reference" + prototype: "Uint32ArrayPrototype" + } + Component { + name: "Uint32ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } Method { - name: "charCodeAt" + name: "constructor" + type: "Uint32Array" + isConstructor: true + Parameter {} + Parameter {} Parameter {} } + } + Component { name: "Uint8Array"; accessSemantics: "reference"; prototype: "Uint8ArrayPrototype" } + Component { + name: "Uint8ArrayPrototype" + accessSemantics: "reference" + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } Method { name: "constructor" - type: "StringObject" + type: "Uint8Array" isConstructor: true Parameter {} + Parameter {} + Parameter {} } - Method { name: "toString" } - Method { name: "valueOf" } } Component { - name: "TypedArray" + name: "Uint8ClampedArray" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length"; type: "number" } + prototype: "Uint8ClampedArrayPrototype" } Component { - name: "UrlSearchParamsObject" + name: "Uint8ClampedArrayPrototype" accessSemantics: "reference" - prototype: "Object" - Property { name: "index" } - Property { name: "input" } - Property { name: "length" } + prototype: "IntrinsicTypedArrayPrototype" + Property { name: "BYTES_PER_ELEMENT"; type: "number"; isReadonly: true } + Method { + name: "constructor" + type: "Uint8ClampedArray" + isConstructor: true + Parameter {} + Parameter {} + Parameter {} + } + } + Component { name: "WeakMap"; accessSemantics: "reference"; prototype: "WeakMapPrototype" } + Component { + name: "WeakMapPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Method { name: "constructor"; type: "WeakMap"; isConstructor: true } + Method { + name: "delete" + Parameter {} + } + Method { + name: "get" + Parameter {} + } + Method { + name: "has" + Parameter {} + } + Method { + name: "set" + Parameter {} + Parameter {} + } + } + Component { name: "WeakSet"; accessSemantics: "reference"; prototype: "WeakSetPrototype" } + Component { + name: "WeakSetPrototype" + accessSemantics: "reference" + prototype: "ObjectPrototype" + Method { name: "constructor"; type: "WeakSet"; isConstructor: true } + Method { + name: "add" + Parameter {} + } + Method { + name: "delete" + Parameter {} + } + Method { + name: "has" + Parameter {} + } + } + Component { name: "boolean"; accessSemantics: "value"; prototype: "BooleanPrototype" } + Component { + name: "function" + accessSemantics: "reference" + prototype: "FunctionPrototype" + Property { name: "prototype"; type: "Object" } + Property { name: "name"; type: "string"; isReadonly: true } + Property { name: "length"; type: "number"; isReadonly: true } } - Component { name: "bool"; accessSemantics: "reference" } - Component { name: "function"; accessSemantics: "reference" } - Component { name: "number"; accessSemantics: "reference" } - Component { name: "object"; accessSemantics: "reference" } - Component { name: "string"; accessSemantics: "reference" } - Component { name: "symbol"; accessSemantics: "reference" } - Component { name: "undefined"; accessSemantics: "reference" } + Component { name: "number"; accessSemantics: "value"; prototype: "NumberPrototype" } + Component { name: "object"; accessSemantics: "reference"; prototype: "ObjectPrototype" } + Component { name: "string"; accessSemantics: "value"; prototype: "StringPrototype" } + Component { name: "symbol"; accessSemantics: "value"; prototype: "SymbolPrototype" } + Component { name: "undefined"; accessSemantics: "value" } } diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 3778cba5f8..b27c6add75 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -53,6 +53,7 @@ #include <private/qv4qobjectwrapper_p.h> #include <private/qv4stackframe_p.h> #include <private/qv4module_p.h> +#include <private/qv4symbol_p.h> #include <QtCore/qdatetime.h> #include <QtCore/qmetaobject.h> @@ -591,6 +592,22 @@ QJSValue QJSEngine::newObject() } /*! + \since 6.2 + + Creates a JavaScript object of class Symbol, with value \a name. + + The prototype of the created object will be the Symbol prototype object. + + \sa newString() +*/ +QJSValue QJSEngine::newSymbol(const QString &name) +{ + QV4::Scope scope(m_v4Engine); + QV4::ScopedValue v(scope, QV4::Symbol::create(m_v4Engine, u'@' + name)); + return QJSValuePrivate::fromReturnedValue(v->asReturnedValue()); +} + +/*! \since 5.12 Creates a JavaScript object of class Error, with \a message as the error diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 33316d3db0..ac79b30ebc 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -73,6 +73,7 @@ public: QJSValue importModule(const QString &fileName); QJSValue newObject(); + QJSValue newSymbol(const QString &name); QJSValue newArray(uint length = 0); QJSValue newQObject(QObject *object); diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index b2a2ec3dea..b5dca2d2ac 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -124,11 +124,11 @@ public: return m(); } - Q_QML_EXPORT bool isString() const; - bool isSymbol() const; + Q_QML_PRIVATE_EXPORT bool isString() const; + Q_QML_PRIVATE_EXPORT bool isSymbol() const; bool isCanonicalNumericIndexString() const; - Q_QML_EXPORT QString toQString() const; + Q_QML_PRIVATE_EXPORT QString toQString() const; Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e); quint64 id() const { return val; } static PropertyKey fromId(quint64 id) { diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index d5e7533959..a72c47f325 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -227,7 +227,7 @@ void TestQmllint::verifyJsRoot() QProcess typeregistrarProcess; typeregistrarProcess.setWorkingDirectory(dir.path()); - typeregistrarProcess.start(m_qmltyperegistrarPath, {"jsroot.json", "--generate-qmltypes", "jsroot.qmltypes", "--import-name", "QJSEngine", "--major-version", "1", "--minor-version", "0"}); + typeregistrarProcess.start(m_qmltyperegistrarPath, {"jsroot.json", "--generate-qmltypes", "jsroot.qmltypes"}); typeregistrarProcess.waitForFinished(); @@ -249,7 +249,7 @@ void TestQmllint::verifyJsRoot() // If any of the following asserts fail you need to update jsroot.qmltypes using the following commands: // // qmljsrootgen jsroot.json - // qmltyperegistrar jsroot.json --generate-qmltypes src/imports/builtins/jsroot.qmltypes --import-name QJSEngine --major-version 1 --minor-version 0 + // qmltyperegistrar jsroot.json --generate-qmltypes src/imports/builtins/jsroot.qmltypes QStringList currentLines = currentJsRootContent.split(QLatin1Char('\n')); QStringList generatedLines = generatedJsRootContent.split(QLatin1Char('\n')); diff --git a/tools/qmljsrootgen/main.cpp b/tools/qmljsrootgen/main.cpp index e3b1ddb28d..c721d79964 100644 --- a/tools/qmljsrootgen/main.cpp +++ b/tools/qmljsrootgen/main.cpp @@ -31,6 +31,7 @@ #include <QtQml/private/qv4global_p.h> #include <QtQml/private/qv4functionobject_p.h> #include <QtQml/qjsengine.h> +#include <QtQml/qjsmanagedvalue.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qfile.h> @@ -42,149 +43,159 @@ struct PropertyInfo { QString name; - QV4::PropertyAttributes attr; - bool fromConstructor; + bool writable; }; -QList<PropertyInfo> getPropertyInfos(QJSValue *value, bool extractConstructor = false) { - if (!value->isObject()) - return {}; - - auto *object = QJSValuePrivate::asManagedType<QV4::Object>(value); - auto *propertyTable = &object->internalClass()->propertyTable; - - QList<PropertyInfo> infos; - for (int i = 0; i < propertyTable->d->alloc; i++) { - auto &propKey = propertyTable->d->entries[i].identifier; - - if (!propKey.isValid()) - continue; - - PropertyInfo propInfo {propKey.toQString(), object->internalClass()->propertyData.at(propertyTable->d->entries[i].index), false}; - infos << propInfo; - } +static QV4::ReturnedValue asManaged(const QJSManagedValue &value) +{ + const QJSValue jsVal = value.toJSValue(); + const QV4::Managed *managed = QJSValuePrivate::asManagedType<QV4::Managed>(&jsVal); + return managed ? managed->asReturnedValue() : QV4::Encode::undefined(); +} +static QJSManagedValue checkedProperty(const QJSManagedValue &value, const QString &name) +{ + return value.hasProperty(name) ? QJSManagedValue(value.property(name), value.engine()) + : QJSManagedValue(QJSPrimitiveUndefined(), value.engine()); +} - if (!extractConstructor || !value->hasProperty(QStringLiteral("constructor"))) { - std::sort(infos.begin(), infos.end(), [](PropertyInfo& a, PropertyInfo& b) { return a.name < b.name; }); - return infos; - } +QList<PropertyInfo> getPropertyInfos(const QJSManagedValue &value) +{ + QV4::Scope scope(value.engine()->handle()); + QV4::ScopedObject scoped(scope, asManaged(value)); + if (!scoped) + return {}; - QJSValue constructor = value->property("constructor"); - auto *objectCtor = QJSValuePrivate::asManagedType<QV4::Object>(&constructor); - auto *propertyTableCtor = &objectCtor->internalClass()->propertyTable; + QList<PropertyInfo> infos; - for (int i = 0; i < propertyTableCtor->d->alloc; i++) { - auto &propKey = propertyTableCtor->d->entries[i].identifier; + QScopedPointer<QV4::OwnPropertyKeyIterator> iterator(scoped->ownPropertyKeys(scoped)); + QV4::Scoped<QV4::InternalClass> internalClass(scope, scoped->internalClass()); - if (!propKey.isValid()) + for (auto key = iterator->next(scoped); key.isValid(); key = iterator->next(scoped)) { + if (key.isSymbol()) continue; - PropertyInfo propInfo {propKey.toQString(), objectCtor->internalClass()->propertyData.at(propertyTableCtor->d->entries[i].index), true}; - infos << propInfo; - } - - - std::sort(infos.begin(), infos.end(), [](PropertyInfo& a, PropertyInfo& b) { return a.name < b.name; }); - - return infos; -} - -void buildBaseType(QString className, QJsonArray *classes) -{ - QJsonObject classObject { - {QStringLiteral("className"), className}, - {QStringLiteral("qualifiedClassName"), className}, - {QStringLiteral("object"), true}, - {QStringLiteral("classInfos"), - QJsonArray({ - QJsonObject({ - { QStringLiteral("name"), QStringLiteral("QML.Element") }, - { QStringLiteral("value"), QStringLiteral("anonymous") } - }) - }) - } + const auto *entry = internalClass->d()->propertyTable.lookup(key); + infos.append({ + key.toQString(), + !entry || internalClass->d()->propertyData.at(entry->index).isWritable() + }); }; - classes->append(classObject); + return infos; } -enum class SeenType { - Normal, - Constructed +struct State { + QMap<QString, QJSValue> constructors; + QMap<QString, QJSValue> prototypes; + QSet<QString> primitives; }; -void buildClass(QJSValue value, QJsonArray *classes, bool globalObject, QMap<QString, SeenType> &seen, SeenType seenType = SeenType::Normal) { - QJsonObject classObject; +static QString buildConstructor(const QJSManagedValue &constructor, QJsonArray *classes, + State *seen, const QString &name); - auto *object = QJSValuePrivate::asManagedType<QV4::Object>(&value); - - QString className = globalObject ? QStringLiteral("GlobalObject") : QString::fromUtf8(object->vtable()->className); +static QString findClassName(const QJSManagedValue &value) +{ + if (value.isUndefined()) + return QStringLiteral("undefined"); + if (value.isBoolean()) + return QStringLiteral("boolean"); + if (value.isNumber()) + return QStringLiteral("number"); + if (value.isString()) + return QStringLiteral("string"); + if (value.isSymbol()) + return QStringLiteral("symbol"); + + QV4::Scope scope(value.engine()->handle()); + if (QV4::ScopedValue scoped(scope, asManaged(value)); scoped->isManaged()) + return scoped->managed()->vtable()->className; + + Q_UNREACHABLE(); + return QString(); +} - // Make sure we're not building the same class twice if it has been fully seen - if (seen.contains(className) && (seen[className] != SeenType::Constructed || seenType == SeenType::Constructed)) - return; +static QString buildClass(const QJSManagedValue &value, QJsonArray *classes, + State *seen, const QString &name) +{ + if (value.isNull()) + return QString(); - seen.insert(className, seenType); + if (seen->primitives.contains(name)) + return name; + else if (name.at(0).isLower()) + seen->primitives.insert(name); - // See if there is a lesser duplicate that needs to be removed. - for (auto it = classes->begin(); it != classes->end(); ++it) { - if (it->toObject()[QStringLiteral("className")] == className) { - it = classes->erase(it); - break; - } - } + QJsonObject classObject; + QV4::Scope scope(value.engine()->handle()); - classObject[QStringLiteral("className")] = className; - classObject[QStringLiteral("qualifiedClassName")] = className; + classObject[QStringLiteral("className")] = name; + classObject[QStringLiteral("qualifiedClassName")] = name; classObject[QStringLiteral("classInfos")] = QJsonArray({ QJsonObject({ { QStringLiteral("name"), QStringLiteral("QML.Element") }, - { QStringLiteral("value"), globalObject ? QStringLiteral("auto") : QStringLiteral("anonymous") } + { QStringLiteral("value"), QStringLiteral("anonymous") } }) }); - classObject[QStringLiteral("object")] = true; + if (value.isObject() || value.isFunction()) + classObject[QStringLiteral("object")] = true; + else + classObject[QStringLiteral("gadget")] = true; - QV4::Scope scope(object); + const QJSManagedValue prototype = value.prototype(); - QJSValue prototype = value.prototype(); + if (!prototype.isNull()) { + QString protoName; + for (auto it = seen->prototypes.begin(), end = seen->prototypes.end(); it != end; ++it) { + if (prototype.strictlyEquals(QJSManagedValue(*it, value.engine()))) { + protoName = it.key(); + break; + } + } - // Try to see whether calling the prototype constructor or the prototype's prototype constructor uncovers any types. - // (It usually doesn't) - if (prototype.property("constructor").isCallable()) { - buildClass(prototype.property("constructor").callAsConstructor(), classes, false, seen, SeenType::Constructed); - } + if (protoName.isEmpty()) { + if (name.endsWith(QStringLiteral("ErrorPrototype")) + && name != QStringLiteral("ErrorPrototype")) { + protoName = QStringLiteral("ErrorPrototype"); + } else if (name.endsWith(QStringLiteral("Prototype"))) { + protoName = findClassName(prototype); + if (!protoName.endsWith(QStringLiteral("Prototype"))) + protoName += QStringLiteral("Prototype"); + } else { + protoName = name.at(0).toUpper() + name.mid(1) + QStringLiteral("Prototype"); + } - if (prototype.prototype().property("constructor").isCallable()) { - buildClass(prototype.prototype().property("constructor").callAsConstructor(), classes, false, seen, SeenType::Constructed); - } + auto it = seen->prototypes.find(protoName); + if (it == seen->prototypes.end()) { + seen->prototypes.insert(protoName, prototype.toJSValue()); + buildClass(prototype, classes, seen, protoName); + } else if (!it->strictlyEquals(prototype.toJSValue())) { + qWarning() << "Cannot find a distinct name for the prototype of" << name; + qWarning() << protoName << "is already in use."; + } + } - classObject[QStringLiteral("superClasses")] = QJsonArray { - QJsonObject ({ - { QStringLiteral("access"), QStringLiteral("public") }, - { QStringLiteral("name"), className == QStringLiteral("Object") ? QStringLiteral("QJSValue") : QStringLiteral("Object") } - })}; + classObject[QStringLiteral("superClasses")] = QJsonArray { + QJsonObject ({ + { QStringLiteral("access"), QStringLiteral("public") }, + { QStringLiteral("name"), protoName } + })}; + } QJsonArray properties, methods; - for (const PropertyInfo &info : getPropertyInfos(&value, className == QStringLiteral("Object"))) { - QJSValue prop; - - if (info.fromConstructor) - prop = value.property("constructor").property(info.name); - else - prop = value.property(info.name); - - // This appears in many property tables despite not being real properties - if (info.name.startsWith(QStringLiteral("@Symbol."))) - continue; - + for (const PropertyInfo &info : getPropertyInfos(value)) { + QJSManagedValue prop = checkedProperty(value, info.name); + if (prop.engine()->hasError()) { + qWarning() << "Cannot retrieve property " << info.name << "of" << name; + qWarning().noquote() << " " << prop.engine()->catchError().toString(); + } // Method or constructor - if (prop.isCallable()) { - const QV4::FunctionObject *propFunction = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&prop); + if (prop.isFunction()) { + QV4::Scoped<QV4::FunctionObject> propFunction(scope, asManaged(prop)); QJsonObject methodObject; @@ -194,26 +205,31 @@ void buildClass(QJSValue value, QJsonArray *classes, bool globalObject, QMap<QSt if (propFunction->isConstructor()) { methodObject.insert(QStringLiteral("isConstructor"), true); - - QJSValue constructed = prop.callAsConstructor(); - if (constructed.isObject()) { - auto *constructedObject = QJSValuePrivate::asManagedType<QV4::Object>(&constructed); - QString classObjectType = constructedObject->vtable()->className; - - buildClass(constructed, classes, false, seen, SeenType::Constructed); - - methodObject.insert(QStringLiteral("returnType"), classObjectType); - } else { - qWarning() << "Warning: Calling constructor" << info.name << "failed"; + QString ctorName; + if (info.name.at(0).isUpper()) { + ctorName = info.name; + } else if (info.name == QStringLiteral("constructor")) { + if (name.endsWith(QStringLiteral("Prototype"))) + ctorName = name.chopped(strlen("Prototype")); + else if (name.endsWith(QStringLiteral("PrototypeMember"))) + ctorName = name.chopped(strlen("PrototypeMember")); + else + ctorName = name; + + if (!ctorName.endsWith(QStringLiteral("Constructor"))) + ctorName += QStringLiteral("Constructor"); } + + methodObject.insert( + QStringLiteral("returnType"), + buildConstructor(prop, classes, seen, ctorName)); } const int formalParams = propFunction->getLength(); QJsonArray arguments; - for (int i = 0; i < formalParams; i++) { + for (int i = 0; i < formalParams; i++) arguments.append(QJsonObject {}); - } methodObject.insert(QStringLiteral("arguments"), arguments); @@ -228,52 +244,91 @@ void buildClass(QJSValue value, QJsonArray *classes, bool globalObject, QMap<QSt propertyObject.insert(QStringLiteral("name"), info.name); // Insert faux member entry if we're allowed to write to this - if (info.attr.isWritable()) + if (info.writable) propertyObject.insert(QStringLiteral("member"), QStringLiteral("fakeMember")); - // Writing out the types is kind of hard in this case because we often have no corresponding QObject type - if (prop.isQObject()) { - propertyObject.insert(QStringLiteral("type"), prop.toQObject()->metaObject()->className()); - } else { - QString type; - - if (prop.isString()) { - type = QStringLiteral("string"); - } else if (prop.isBool()){ - type = QStringLiteral("bool"); - } else if (prop.isNumber()) { - type = QStringLiteral("number"); - } else if (prop.isUndefined()) { - type = QStringLiteral("undefined"); - } else if (prop.isArray() || prop.isNull() || prop.isObject()) { - type = QStringLiteral("object"); + if (!prop.isUndefined() && !prop.isNull()) { + QString propClassName = findClassName(prop); + if (!propClassName.at(0).isLower() && info.name != QStringLiteral("prototype")) { + propClassName = (name == QStringLiteral("GlobalObject")) + ? QString() + : name.at(0).toUpper() + name.mid(1); + + propClassName += info.name.at(0).toUpper() + info.name.mid(1); + propertyObject.insert(QStringLiteral("type"), + buildClass(prop, classes, seen, propClassName)); } else { - qWarning() << "Warning: Failed to resolve type of property" << info.name; - type = QStringLiteral("undefined"); + // If it's the "prototype" property we just refer to generic "Object", + // and if it's a value type, we handle it separately. + propertyObject.insert(QStringLiteral("type"), propClassName); } - - if (seenType != SeenType::Constructed || !prop.isUndefined()) - propertyObject.insert(QStringLiteral("type"), type); } + properties.append(propertyObject); + } + + classObject[QStringLiteral("properties")] = properties; + classObject[QStringLiteral("methods")] = methods; - if (prop.isObject() && !prop.isQObject()) { - buildClass(prop, classes, false, seen); + classes->append(classObject); - auto *object = QJSValuePrivate::asManagedType<QV4::Object>(&prop); + return name; +} - propertyObject.insert(QStringLiteral("type"), object->vtable()->className); - } +static QString buildConstructor(const QJSManagedValue &constructor, QJsonArray *classes, + State *seen, const QString &name) +{ + QJSEngine *engine = constructor.engine(); + + // If the constructor appears in the global object, use the name from there. + const QJSManagedValue globalObject(engine->globalObject(), engine); + const auto infos = getPropertyInfos(globalObject); + for (const auto &info : infos) { + const QJSManagedValue member(globalObject.property(info.name), engine); + if (member.strictlyEquals(constructor) && info.name != name) + return buildConstructor(constructor, classes, seen, info.name); + } - properties.append(propertyObject); + QJSManagedValue constructed; + if (name == QStringLiteral("Symbol")) + return QStringLiteral("undefined"); // Cannot construct symbols with "new"; + + if (name == QStringLiteral("URL")) { + constructed = QJSManagedValue( + constructor.callAsConstructor({ QJSValue(QStringLiteral("http://a.bc")) }), + engine); + } else if (name == QStringLiteral("Promise")) { + constructed = QJSManagedValue( + constructor.callAsConstructor( + { engine->evaluate(QStringLiteral("(function() {})")) }), + engine); + } else if (name == QStringLiteral("DataView")) { + constructed = QJSManagedValue( + constructor.callAsConstructor( + { engine->evaluate(QStringLiteral("new ArrayBuffer()")) }), + engine); + } else if (name == QStringLiteral("Proxy")) { + constructed = QJSManagedValue(constructor.callAsConstructor( + { engine->newObject(), engine->newObject() }), engine); + } else { + constructed = QJSManagedValue(constructor.callAsConstructor(), engine); } - classObject[QStringLiteral("properties")] = properties; - classObject[QStringLiteral("methods")] = methods; + if (engine->hasError()) { + qWarning() << "Calling constructor" << name << "failed"; + qWarning().noquote() << " " << engine->catchError().toString(); + return QString(); + } else if (name.isEmpty()) { + Q_UNREACHABLE(); + } - // Make sure that in the unlikely accident that some subclass has already provided a normal replacement for this constructed type - // there are no duplicate entries. - if (seenType != SeenType::Constructed || seen[className] != SeenType::Normal) - classes->append(classObject); + auto it = seen->constructors.find(name); + if (it == seen->constructors.end()) { + seen->constructors.insert(name, constructor.toJSValue()); + return buildClass(constructed, classes, seen, name); + } else if (!constructor.strictlyEquals(QJSManagedValue(*it, constructor.engine()))) { + qWarning() << "Two constructors of the same name seen:" << name; + } + return name; } int main(int argc, char *argv[]) @@ -294,16 +349,42 @@ int main(int argc, char *argv[]) engine.installExtensions(QJSEngine::AllExtensions); QJsonArray classesArray; + State seen; - // Add JS types so they can be referenced by other classes - for (const QString &name : { QStringLiteral("string"), QStringLiteral("undefined"), QStringLiteral("number"), - QStringLiteral("object"), QStringLiteral("bool"), QStringLiteral("symbol"), QStringLiteral("function")}) { - buildBaseType(name, &classesArray); - } + // object. Do this first to claim the "Object" name for the prototype. + buildClass(QJSManagedValue(engine.newObject(), &engine), &classesArray, &seen, + QStringLiteral("object")); + + + buildClass(QJSManagedValue(engine.globalObject(), &engine), &classesArray, &seen, + QStringLiteral("GlobalObject")); + + // Add JS types, in case they aren't used anywhere. + + + // function + buildClass(QJSManagedValue(engine.evaluate(QStringLiteral("(function() {})")), &engine), + &classesArray, &seen, QStringLiteral("function")); + + // string + buildClass(QJSManagedValue(QStringLiteral("s"), &engine), &classesArray, &seen, + QStringLiteral("string")); + + // undefined + buildClass(QJSManagedValue(QJSPrimitiveUndefined(), &engine), &classesArray, &seen, + QStringLiteral("undefined")); + + // number + buildClass(QJSManagedValue(QJSPrimitiveValue(1.1), &engine), &classesArray, &seen, + QStringLiteral("number")); - QMap<QString, SeenType> seen {}; + // boolean + buildClass(QJSManagedValue(QJSPrimitiveValue(true), &engine), &classesArray, &seen, + QStringLiteral("boolean")); - buildClass(engine.globalObject(), &classesArray, true, seen); + // symbol + buildClass(QJSManagedValue(engine.newSymbol(QStringLiteral("s")), &engine), + &classesArray, &seen, QStringLiteral("symbol")); // Generate the fake metatypes json structure QJsonDocument metatypesJson = QJsonDocument( |