Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4script.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4script_p.h"
5#include <private/qv4mm_p.h>
6#include "qv4function_p.h"
7#include "qv4context_p.h"
8#include "qv4debugging_p.h"
9#include "qv4scopedvalue_p.h"
10
11#include <private/qqmljsengine_p.h>
12#include <private/qqmljslexer_p.h>
13#include <private/qqmljsparser_p.h>
14#include <private/qqmljsast_p.h>
15#include <private/qqmlengine_p.h>
16#include <private/qqmlsourcecoordinate_p.h>
17#include <private/qv4profiling_p.h>
18#include <qv4runtimecodegen_p.h>
19
20#include <QtCore/QDebug>
21#include <QtCore/QString>
22#include <QScopedValueRollback>
23
24using namespace QV4;
25using namespace QQmlJS;
26
27Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer<ExecutableCompilationUnit> &compilationUnit)
28 : line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
29 , compilationUnit(compilationUnit), parseAsBinding(true)
30{
31 if (qml)
32 qmlContext.set(v4, *qml);
33
34 parsed = true;
35
36 vmFunction.set(v4,
37 compilationUnit ? compilationUnit->rootFunction() : nullptr);
38}
39
43
45{
46 if (parsed)
47 return;
48
49 parsed = true;
50
52 Scope valueScope(v4);
53
54 QV4::Compiler::Module module(v4->debugger() != nullptr);
55
56 if (sourceCode.startsWith(QLatin1String("function("))) {
57 static const int snippetLength = 70;
58 qWarning() << "Warning: Using function expressions as statements in scripts is not compliant with the ECMAScript specification:\n"
59 << (QStringView{sourceCode}.left(snippetLength) + QLatin1String("..."))
60 << "\nThis will throw a syntax error in Qt 5.12. If you want a function expression, surround it by parentheses.";
61 }
62
63 Engine ee, *engine = &ee;
64 Lexer lexer(engine);
66 Parser parser(engine);
67
68 const bool parsed = parser.parseProgram();
69
70 const auto diagnosticMessages = parser.diagnosticMessages();
71 for (const DiagnosticMessage &m : diagnosticMessages) {
72 if (m.isError()) {
73 valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
74 return;
75 } else {
76 qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
77 << ": warning: " << m.message;
78 }
79 }
80
81 if (parsed) {
82 using namespace AST;
83 Program *program = AST::cast<Program *>(parser.rootNode());
84 if (!program) {
85 // if parsing was successful, and we have no program, then
86 // we're done...:
87 return;
88 }
89
90 QV4::Compiler::JSUnitGenerator jsGenerator(&module);
91 RuntimeCodegen cg(v4, &jsGenerator, strictMode);
93 cg.setUseFastLookups(false);
95 if (v4->hasException)
96 return;
97
99 vmFunction.set(v4, compilationUnit->rootFunction());
100 }
101
102 if (!vmFunction) {
103 // ### FIX file/line number
104 ScopedObject error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
105 v4->throwError(error);
106 }
107}
108
110{
111 if (!parsed)
112 parse();
113 if (!vmFunction)
114 return Encode::undefined();
115
117 QV4::Scope valueScope(engine);
118
119 if (qmlContext.isUndefined()) {
120 QScopedValueRollback<Function*> savedGlobalCode(engine->globalCode, vmFunction);
121
122 return vmFunction->call(thisObject ? thisObject : engine->globalObject, nullptr, 0,
123 context);
124 } else {
125 Scoped<QmlContext> qml(valueScope, qmlContext.value());
126 return vmFunction->call(thisObject, nullptr, 0, qml);
127 }
128}
129
131{
132 if (!parsed)
133 parse();
134 return vmFunction;
135}
136
137QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(
138 QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine,
139 Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl,
140 const QString &source, QList<QQmlError> *reportedErrors,
141 QV4::Compiler::ContextType contextType)
142{
143 using namespace QV4::Compiler;
144 using namespace QQmlJS::AST;
145
146 Lexer lexer(jsEngine);
147 lexer.setCode(source, /*line*/1, /*qml mode*/false);
148 Parser parser(jsEngine);
149
150 parser.parseProgram();
151
152 QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(fileName, parser.diagnosticMessages());
153 if (!errors.isEmpty()) {
154 if (reportedErrors)
155 *reportedErrors << errors;
156 return nullptr;
157 }
158
159 Program *program = AST::cast<Program *>(parser.rootNode());
160 if (!program) {
161 // if parsing was successful, and we have no program, then
162 // we're done...:
163 return nullptr;
164 }
165
166 Codegen cg(unitGenerator, /*strict mode*/false);
167 cg.generateFromProgram(fileName, finalUrl, source, program, module, contextType);
168 if (cg.hasError()) {
169 if (reportedErrors) {
170 const auto v4Error = cg.error();
172 error.setUrl(cg.url());
173 error.setLine(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startLine));
174 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startColumn));
175 error.setDescription(v4Error.message);
176 reportedErrors->append(error);
177 }
178 return nullptr;
179 }
180
181 return cg.generateCompilationUnit(/*generate unit data*/false);
182}
183
185{
186 if (error)
187 error->clear();
188
190 const ExecutionEngine::DiskCacheOptions options = engine->diskCacheOptions();
191 if (const QQmlPrivate::CachedQmlUnit *cachedUnit
194 originalUrl,
198 &cacheError)
199 : nullptr) {
200 QQmlRefPointer<QV4::ExecutableCompilationUnit> jsUnit
201 = engine->insertCompilationUnit(
202 QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
203 cachedUnit->qmlData, cachedUnit->aotCompiledFunctions));
204 return new QV4::Script(engine, qmlContext, jsUnit);
205 }
206
208 if (!f.open(QIODevice::ReadOnly)) {
209 if (error) {
211 *error = originalUrl.toString() + QString::fromUtf8(" was compiled ahead of time with an incompatible version of Qt and the original source code cannot be found. Please recompile");
212 else
213 *error = QString::fromUtf8("Error opening source file %1: %2").arg(originalUrl.toString()).arg(f.errorString());
214 }
215 return nullptr;
216 }
217
218 QByteArray data = f.readAll();
220
221 auto result = new QV4::Script(engine, qmlContext, /*parseAsBinding*/false, sourceCode, originalUrl.toString());
223 result->parse();
224 return result;
225}
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qfile.h:93
QJSValue globalObject() const
Returns this engine's Global Object.
static QList< QQmlError > qmlErrorFromDiagnostics(const QString &fileName, const QList< QQmlJS::DiagnosticMessage > &diagnosticMessages)
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
static const QQmlPrivate::CachedQmlUnit * findCachedCompilationUnit(const QUrl &uri, CacheMode mode, CachedUnitLookupError *status)
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore
Definition qurl.h:94
void setUseFastLookups(bool b)
QQmlRefPointer< QV4::CompiledData::CompilationUnit > generateCompilationUnit(bool generateUnitData=true)
void generateFromProgram(const QString &fileName, const QString &finalUrl, const QString &sourceCode, QQmlJS::AST::Program *ast, Module *module, ContextType contextType=ContextType::Global)
QQmlJS::DiagnosticMessage error() const
ReturnedValue value() const
void set(ExecutionEngine *engine, const Value &value)
quint64 ReturnedValue
static void * context
DBusConnection const char DBusError * error
#define qWarning
Definition qlogging.h:166
const GLfloat * m
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLuint program
GLsizei GLsizei GLchar * source
GLenum GLenum GLsizei void GLsizei void * column
GLuint64EXT * result
[6]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
QJSEngine engine
[0]
static constexpr ReturnedValue undefined()
QQmlRefPointer< ExecutableCompilationUnit > insertCompilationUnit(QQmlRefPointer< QV4::CompiledData::CompilationUnit > &&unit)
QV4::Debugging::Debugger * debugger() const
ReturnedValue throwError(const Value &value)
Heap::Object * newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
ExecutionEngine * engine() const
Script(ExecutionContext *scope, QV4::Compiler::ContextType mode, const QString &sourceCode, const QString &source=QString(), int line=1, int column=0)
Definition qv4script_p.h:36
Function * function()
ReturnedValue run(const QV4::Value *thisObject=nullptr)
QV4::Compiler::ContextType contextType
Definition qv4script_p.h:57
QV4::PersistentValue qmlContext
Definition qv4script_p.h:58
bool parseAsBinding
Definition qv4script_p.h:61
static Script * createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error)
bool strictMode
Definition qv4script_p.h:54
QString sourceCode
Definition qv4script_p.h:52
static QQmlRefPointer< QV4::CompiledData::CompilationUnit > precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl, const QString &source, QList< QQmlError > *reportedErrors=nullptr, QV4::Compiler::ContextType contextType=QV4::Compiler::ContextType::Global)
ExecutionContext * context
Definition qv4script_p.h:53
bool inheritContext
Definition qv4script_p.h:55
void parse()
Definition qv4script.cpp:44
QString sourceFile
Definition qv4script_p.h:49
QQmlRefPointer< ExecutableCompilationUnit > compilationUnit
Definition qv4script_p.h:59
QV4::WriteBarrier::Pointer< Function > vmFunction
Definition qv4script_p.h:60