1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "private/qv4object_p.h"
5#include "private/qv4runtime_p.h"
6#include "private/qv4functionobject_p.h"
7#include "private/qv4errorobject_p.h"
8#include "private/qv4globalobject_p.h"
9#include "private/qv4codegen_p.h"
10#include "private/qv4objectproto_p.h"
11#include "private/qv4mm_p.h"
12#include "private/qv4context_p.h"
13#include "private/qv4script_p.h"
14#include "private/qv4string_p.h"
15#include "private/qv4module_p.h"
16#include "private/qqmlbuiltinfunctions_p.h"
17
18#include <QtCore/QCoreApplication>
19#include <QtCore/QFile>
20#include <QtCore/QFileInfo>
21#include <QtCore/QDateTime>
22#include <private/qqmljsengine_p.h>
23#include <private/qqmljslexer_p.h>
24#include <private/qqmljsparser_p.h>
25#include <private/qqmljsast_p.h>
26
27#include <iostream>
28
29static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exception, const QV4::StackTrace &trace)
30{
31 QV4::Scope scope(ctx);
32 QV4::ScopedValue ex(scope, exception);
33 QV4::ErrorObject *e = ex->as<QV4::ErrorObject>();
34 if (!e) {
35 std::cerr << "Uncaught exception: " << qPrintable(ex->toQString()) << std::endl;
36 } else {
37 std::cerr << "Uncaught exception: " << qPrintable(e->toQStringNoThrow()) << std::endl;
38 }
39
40 for (const QV4::StackFrame &frame : trace) {
41 std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source);
42 if (frame.line >= 0)
43 std::cerr << ':' << frame.line;
44 std::cerr << ')' << std::endl;
45 }
46}
47
48int main(int argc, char *argv[])
49{
50 QCoreApplication app(argc, argv);
51 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
52 QStringList args = app.arguments();
53 args.removeFirst();
54
55 bool runAsQml = false;
56 bool runAsModule = false;
57 bool cache = false;
58
59 if (!args.isEmpty()) {
60 if (args.constFirst() == QLatin1String("--jit")) {
61 qputenv(varName: "QV4_JIT_CALL_THRESHOLD", value: QByteArray("0"));
62 args.removeFirst();
63 }
64 if (args.constFirst() == QLatin1String("--interpret")) {
65 qputenv(varName: "QV4_FORCE_INTERPRETER", value: QByteArray("1"));
66 args.removeFirst();
67 }
68
69 if (args.constFirst() == QLatin1String("--qml")) {
70 runAsQml = true;
71 args.removeFirst();
72 }
73
74 if (args.constFirst() == QLatin1String("--module")) {
75 runAsModule = true;
76 args.removeFirst();
77 }
78
79 if (args.constFirst() == QLatin1String("--cache")) {
80 cache = true;
81 args.removeFirst();
82 }
83
84 if (args.constFirst() == QLatin1String("--help")) {
85 std::cerr << "Usage: qmljs [|--jit|--interpret|--qml] file..." << std::endl;
86 return EXIT_SUCCESS;
87 }
88 }
89
90 QV4::ExecutionEngine vm;
91
92 QV4::Scope scope(&vm);
93 QV4::ScopedContext ctx(scope, vm.rootContext());
94
95 QV4::GlobalExtensions::init(globalObject: vm.globalObject, extensions: QJSEngine::ConsoleExtension | QJSEngine::GarbageCollectionExtension);
96
97 for (const QString &fn : std::as_const(t&: args)) {
98 QV4::ScopedValue result(scope);
99 if (runAsModule) {
100 auto module = vm.loadModule(url: QUrl::fromLocalFile(localfile: QFileInfo(fn).absoluteFilePath()));
101 if (module.compiled) {
102 if (module.compiled->instantiate(engine: &vm))
103 module.compiled->evaluate();
104 } else if (module.native) {
105 // Nothing to do. Native modules have no global code.
106 } else {
107 vm.throwError(QStringLiteral("Could not load module file"));
108 }
109 } else {
110 QFile file(fn);
111 if (!file.open(flags: QFile::ReadOnly)) {
112 std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
113 return EXIT_FAILURE;
114 }
115 QScopedPointer<QV4::Script> script;
116 if (cache && QFile::exists(fileName: fn + QLatin1Char('c'))) {
117 QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
118 = QV4::ExecutableCompilationUnit::create();
119 QString error;
120 if (unit->loadFromDisk(url: QUrl::fromLocalFile(localfile: fn), sourceTimeStamp: QFileInfo(fn).lastModified(), errorString: &error)) {
121 script.reset(other: new QV4::Script(&vm, nullptr, unit));
122 } else {
123 std::cout << "Error loading" << qPrintable(fn) << "from disk cache:" << qPrintable(error) << std::endl;
124 }
125 }
126 if (!script) {
127 QByteArray ba = file.readAll();
128 const QString code = QString::fromUtf8(utf8: ba.constData(), size: ba.size());
129 file.close();
130
131 script.reset(other: new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, fn));
132 script->parseAsBinding = runAsQml;
133 script->parse();
134 }
135 if (!scope.hasException()) {
136 const auto unit = script->compilationUnit;
137 if (cache && unit && !(unit->unitData()->flags & QV4::CompiledData::Unit::StaticData)) {
138 if (unit->unitData()->sourceTimeStamp == 0) {
139 const_cast<QV4::CompiledData::Unit*>(unit->unitData())->sourceTimeStamp = QFileInfo(fn).lastModified().toMSecsSinceEpoch();
140 }
141 QString saveError;
142 if (!unit->saveToDisk(unitUrl: QUrl::fromLocalFile(localfile: fn), errorString: &saveError)) {
143 std::cout << "Error saving JS cache file: " << qPrintable(saveError) << std::endl;
144 }
145 }
146// QElapsedTimer t; t.start();
147 result = script->run();
148// std::cout << t.elapsed() << " ms. elapsed" << std::endl;
149 }
150 }
151 if (scope.hasException()) {
152 QV4::StackTrace trace;
153 QV4::ScopedValue ex(scope, scope.engine->catchException(trace: &trace));
154 showException(ctx, exception: ex, trace);
155 return EXIT_FAILURE;
156 }
157 if (!result->isUndefined()) {
158 if (! qgetenv(varName: "SHOW_EXIT_VALUE").isEmpty())
159 std::cout << "exit value: " << qPrintable(result->toQString()) << std::endl;
160 }
161 }
162
163 return EXIT_SUCCESS;
164}
165

source code of qtdeclarative/tools/qmljs/qmljs.cpp