bool _allowFuncDecls;
};
-Codegen::Codegen(QV4::ExecutionContext *context, bool strict)
+Codegen::Codegen(bool strict)
: _module(0)
, _function(0)
, _block(0)
, _loop(0)
, _labelledStatement(0)
, _scopeAndFinally(0)
- , _context(context)
, _strictMode(strict)
- , _errorHandler(0)
-{
-}
-
-Codegen::Codegen(ErrorHandler *errorHandler, bool strictMode)
- : _module(0)
- , _function(0)
- , _block(0)
- , _exitBlock(0)
- , _throwBlock(0)
- , _returnAddress(0)
- , _mode(GlobalCode)
- , _env(0)
- , _loop(0)
- , _labelledStatement(0)
- , _scopeAndFinally(0)
- , _context(0)
- , _strictMode(strictMode)
- , _errorHandler(errorHandler)
{
}
void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
- QV4::DiagnosticMessage *msg = new QV4::DiagnosticMessage;
- msg->fileName = _fileName;
- msg->offset = loc.begin();
- msg->startLine = loc.startLine;
- msg->startColumn = loc.startColumn;
- msg->message = detail;
- if (_context)
- _context->throwSyntaxError(msg);
- else if (_errorHandler)
- _errorHandler->syntaxError(msg);
- else
- Q_ASSERT(!"No error handler available.");
+ QQmlError error;
+ error.setUrl(QUrl::fromLocalFile(_fileName));
+ error.setDescription(detail);
+ error.setLine(loc.startLine);
+ error.setColumn(loc.startColumn);
+ _errors << error;
}
void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
- if (_context)
- _context->throwReferenceError(QV4::Value::fromString(_context, detail), _fileName, loc.startLine);
- else if (_errorHandler)
- throwSyntaxError(loc, detail);
- else
- Q_ASSERT(!"No error handler available.");
+ QQmlError error;
+ error.setUrl(QUrl::fromLocalFile(_fileName));
+ error.setDescription(detail);
+ error.setLine(loc.startLine);
+ error.setColumn(loc.startColumn);
+ _errors << error;
+}
+
+void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
+{
+ context->throwSyntaxError(detail, _fileName, loc.startLine, loc.startColumn);
+}
+
+void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
+{
+ context->throwReferenceError(detail, _fileName, loc.startLine, loc.startColumn);
}
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
#include <QtCore/QStringList>
+#include <qqmlerror.h>
#include <assert.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct DiagnosticMessage;
struct ExecutionContext;
}
}
-
-class ErrorHandler
-{
-public:
- virtual void syntaxError(QV4::DiagnosticMessage *message) = 0;
-};
-
class Q_QML_EXPORT Codegen: protected AST::Visitor
{
public:
- Codegen(QV4::ExecutionContext *ctx, bool strict);
- Codegen(ErrorHandler *errorHandler, bool strictMode);
+ Codegen(bool strict);
enum Mode {
GlobalCode,
virtual bool visit(AST::UiSourceElement *ast);
void throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr* expr, const AST::SourceLocation &loc);
+ virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
- void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
- void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+ QList<QQmlError> errors();
-private:
+protected:
QString _fileName;
Result _expr;
QString _property;
ScopeAndFinally *_scopeAndFinally;
QHash<AST::Node *, Environment *> _envMap;
QHash<AST::FunctionExpression *, int> _functionMap;
- QV4::ExecutionContext *_context;
bool _strictMode;
- ErrorHandler *_errorHandler;
+
+ QList<QQmlError> _errors;
class ScanFunctions;
};
+class RuntimeCodegen : public Codegen
+{
+public:
+ RuntimeCodegen(QV4::ExecutionContext *ctx, bool strict)
+ : Codegen(strict)
+ , context(ctx)
+ {}
+
+ virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+private:
+ QV4::ExecutionContext *context;
+};
+
}
QT_END_NAMESPACE
#include "qv4mm_p.h"
#include <qv4argumentsobject_p.h>
#include "qv4function_p.h"
+#include "qv4errorobject_p.h"
using namespace QV4;
-DiagnosticMessage::DiagnosticMessage()
- : offset(0)
- , length(0)
- , startLine(0)
- , startColumn(0)
- , type(0)
- , next(0)
-{}
-
-DiagnosticMessage::~DiagnosticMessage()
-{
- delete next;
-}
-
-String *DiagnosticMessage::buildFullMessage(ExecutionContext *ctx) const
-{
- QString msg;
- if (!fileName.isEmpty())
- msg = fileName + QLatin1Char(':');
- msg += QString::number(startLine) + QLatin1Char(':') + QString::number(startColumn) + QLatin1String(": ");
- if (type == QV4::DiagnosticMessage::Error)
- msg += QLatin1String("error");
- else
- msg += QLatin1String("warning");
- msg += ": " + message;
-
- return ctx->engine->newString(msg);
-}
-
void ExecutionContext::createMutableBinding(String *name, bool deletable)
{
}
if (strictMode)
- throwSyntaxError(0);
+ throwSyntaxError(QString("Can't delete property %1").arg(name->toQString()));
return true;
}
throwError(Value::fromObject(engine->newErrorObject(v)));
}
-void ExecutionContext::throwSyntaxError(DiagnosticMessage *message)
+void ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
+{
+ Object *error = engine->newSyntaxErrorObject(message, fileName, line, column);
+ throwError(Value::fromObject(error));
+}
+
+void ExecutionContext::throwSyntaxError(const QString &message)
{
- throwError(Value::fromObject(engine->newSyntaxErrorObject(this, message)));
+ Object *error = engine->newSyntaxErrorObject(message);
+ throwError(Value::fromObject(error));
}
void ExecutionContext::throwTypeError()
throwError(Value::fromObject(engine->newReferenceErrorObject(msg)));
}
-void ExecutionContext::throwReferenceError(Value value, const QString &fileName, int line)
+void ExecutionContext::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
{
- String *s = value.toString(this);
- QString msg = s->toQString() + QStringLiteral(" is not defined");
- throwError(Value::fromObject(engine->newReferenceErrorObject(msg, fileName, line)));
+ QString msg = message + QStringLiteral(" is not defined");
+ throwError(Value::fromObject(engine->newReferenceErrorObject(msg, fileName, line, column)));
}
void ExecutionContext::throwRangeError(Value value)
struct ExecutionEngine;
struct DeclarativeEnvironment;
struct Lookup;
-
-struct Q_QML_EXPORT DiagnosticMessage
-{
- enum { Error, Warning };
-
- QString fileName;
- quint32 offset;
- quint32 length;
- quint32 startLine;
- unsigned startColumn: 31;
- unsigned type: 1;
- QString message;
- DiagnosticMessage *next;
-
- DiagnosticMessage();
- ~DiagnosticMessage();
- String *buildFullMessage(ExecutionContext *ctx) const;
-};
-
struct CallContext;
struct Q_QML_EXPORT ExecutionContext
void Q_NORETURN throwError(const Value &value);
void Q_NORETURN throwError(const QString &message);
- void Q_NORETURN throwSyntaxError(DiagnosticMessage *message);
+ void Q_NORETURN throwSyntaxError(const QString &message);
+ void Q_NORETURN throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
void Q_NORETURN throwTypeError();
void Q_NORETURN throwTypeError(const QString &message);
void Q_NORETURN throwReferenceError(Value value);
- void Q_NORETURN throwReferenceError(Value value, const QString &fileName, int line);
+ void Q_NORETURN throwReferenceError(const QString &value, const QString &fileName, int line, int column);
void Q_NORETURN throwRangeError(Value value);
void Q_NORETURN throwURIError(Value msg);
void Q_NORETURN throwUnimplemented(const QString &message);
return object;
}
-Object *ExecutionEngine::newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
+Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
{
- return new (memoryManager) SyntaxErrorObject(ctx, message);
+ return new (memoryManager) SyntaxErrorObject(this, Value::fromString(this, message));
}
-Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
+Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
{
- return new (memoryManager) SyntaxErrorObject(this, message);
+ return new (memoryManager) SyntaxErrorObject(this, message, fileName, line, column);
}
return new (memoryManager) ReferenceErrorObject(this, message);
}
-Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber)
+Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber)
{
- return new (memoryManager) ReferenceErrorObject(this, message, fileName, lineNumber);
+ return new (memoryManager) ReferenceErrorObject(this, message, fileName, lineNumber, columnNumber);
}
struct BoundFunction;
struct RegExpObject;
struct ErrorObject;
+struct SyntaxErrorObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
RegExpObject *newRegExpObject(const QRegExp &re);
Object *newErrorObject(const Value &value);
- Object *newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message);
+ Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column);
Object *newSyntaxErrorObject(const QString &message);
Object *newReferenceErrorObject(const QString &message);
- Object *newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber);
+ Object *newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber);
Object *newTypeErrorObject(const QString &message);
Object *newRangeErrorObject(const QString &message);
Object *newURIErrorObject(Value message);
}
}
+ErrorObject::ErrorObject(ExecutionEngine *engine, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
+ : Object(engine)
+ , stack(0)
+{
+ type = Type_ErrorObject;
+ vtbl = &static_vtbl;
+ subtype = t;
+ defineAccessorProperty(engine, QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
+
+ defineDefaultProperty(engine, QStringLiteral("name"), Value::fromString(engine, className()));
+
+ stackTrace = engine->stackTrace();
+ ExecutionEngine::StackFrame frame;
+ frame.source = fileName;
+ frame.line = line;
+ frame.column = column;
+ stackTrace.prepend(frame);
+
+ if (!stackTrace.isEmpty()) {
+ defineDefaultProperty(engine, QStringLiteral("fileName"), Value::fromString(engine, stackTrace.at(0).source));
+ defineDefaultProperty(engine, QStringLiteral("lineNumber"), Value::fromInt32(stackTrace.at(0).line));
+ }
+
+ defineDefaultProperty(engine, QStringLiteral("message"), Value::fromString(engine->newString(message)));
+}
+
Value ErrorObject::method_get_stack(SimpleCallContext *ctx)
{
ErrorObject *This = ctx->thisObject.asErrorObject();
SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg)
: ErrorObject(engine, msg, SyntaxError)
- , msg(0)
{
vtbl = &static_vtbl;
prototype = engine->syntaxErrorPrototype;
}
-SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg)
- : ErrorObject(engine, Value::fromString(engine, msg), SyntaxError)
- , msg(0)
+SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
+ : ErrorObject(engine, msg, fileName, lineNumber, columnNumber, SyntaxError)
{
vtbl = &static_vtbl;
prototype = engine->syntaxErrorPrototype;
}
-SyntaxErrorObject::SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
- : ErrorObject(ctx->engine, message ? Value::fromString(message->buildFullMessage(ctx)) : ctx->argument(0), SyntaxError)
- , msg(message)
-{
- vtbl = &static_vtbl;
- prototype = ctx->engine->syntaxErrorPrototype;
- if (message) {
- defineDefaultProperty(ctx->engine, QStringLiteral("fileName"), Value::fromString(ctx, message->fileName));
- defineDefaultProperty(ctx->engine, QStringLiteral("lineNumber"), Value::fromInt32(message->startLine));
- }
-}
-
-
-
EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message)
: ErrorObject(engine, message, EvalError)
{
prototype = engine->referenceErrorPrototype;
}
-ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber)
- : ErrorObject(engine, Value::fromString(engine, msg), ReferenceError)
+ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
+ : ErrorObject(engine, msg, fileName, lineNumber, columnNumber, ReferenceError)
{
prototype = engine->referenceErrorPrototype;
- defineDefaultProperty(engine, QStringLiteral("fileName"), Value::fromString(engine->rootContext, fileName));
- defineDefaultProperty(engine, QStringLiteral("lineNumber"), Value::fromInt32(lineNumber));
}
TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message)
};
ErrorObject(ExecutionEngine *engine, const Value &message, ErrorType t = Error);
+ ErrorObject(ExecutionEngine *engine, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error);
SyntaxErrorObject *asSyntaxError();
struct ReferenceErrorObject: ErrorObject {
ReferenceErrorObject(ExecutionEngine *engine, const Value &message);
ReferenceErrorObject(ExecutionEngine *engine, const QString &msg);
- ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber);
+ ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
};
struct SyntaxErrorObject: ErrorObject {
SyntaxErrorObject(ExecutionEngine *engine, const Value &msg);
- SyntaxErrorObject(ExecutionEngine *engine, const QString &msg);
- SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *msg);
- ~SyntaxErrorObject() { delete msg; }
- static void destroy(Managed *that) { static_cast<SyntaxErrorObject *>(that)->~SyntaxErrorObject(); }
+ SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
- DiagnosticMessage *message() { return msg; }
-
-private:
- DiagnosticMessage *msg;
protected:
static const ManagedVTable static_vtbl;
};
struct SyntaxErrorPrototype: SyntaxErrorObject
{
- SyntaxErrorPrototype(ExecutionEngine *engine): SyntaxErrorObject(engine, 0) { vtbl = &static_vtbl; }
+ SyntaxErrorPrototype(ExecutionEngine *engine): SyntaxErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
};
QQmlJS::V4IR::Module module;
- QQmlJS::Codegen cg(v4->current, f->strictMode);
+ QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
QQmlJS::V4IR::Function *irf = cg(QString(), function, fe, &module);
QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
Value result = parser.parse(&error);
if (error.error != QJsonParseError::NoError) {
DEBUG << "parse error" << error.errorString();
- ctx->throwSyntaxError(0);
+ ctx->throwSyntaxError("JSON.parse: Parse error");
}
return result;
const bool parsed = parser.parseProgram();
- DiagnosticMessage *error = 0, **errIt = &error;
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
if (m.isError()) {
- *errIt = new DiagnosticMessage;
- (*errIt)->fileName = sourceFile;
- (*errIt)->offset = m.loc.offset;
- (*errIt)->length = m.loc.length;
- (*errIt)->startLine = m.loc.startLine;
- (*errIt)->startColumn = m.loc.startColumn;
- (*errIt)->type = DiagnosticMessage::Error;
- (*errIt)->message = m.message;
- errIt = &(*errIt)->next;
+ scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
} else {
qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
<< ": warning: " << m.message;
}
}
- if (error)
- scope->throwSyntaxError(error);
if (parsed) {
using namespace AST;
for (String * const *i = scope->variables(), * const *ei = i + scope->variableCount(); i < ei; ++i)
inheritedLocals.append(*i ? (*i)->toQString() : QString());
- Codegen cg(scope, strictMode);
+ RuntimeCodegen cg(scope, strictMode);
V4IR::Function *globalIRCode = cg(sourceFile, sourceCode, program, &module,
parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
if (!vmFunction)
// ### FIX file/line number
- v4->current->throwError(QV4::Value::fromObject(v4->newSyntaxErrorObject(v4->current, 0)));
+ v4->current->throwError(QV4::Value::fromObject(v4->newSyntaxErrorObject("Syntax error")));
}
Value Script::run()
void QQmlJavaScriptExpression::exceptionToError(const QV4::Exception &e, QQmlError &error)
{
+ QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
+ if (!trace.isEmpty()) {
+ QV4::ExecutionEngine::StackFrame frame = trace.first();
+ error.setUrl(QUrl(frame.source));
+ error.setLine(frame.line);
+ error.setColumn(frame.column);
+ }
QV4::ErrorObject *errorObj = e.value().asErrorObject();
- if (errorObj && errorObj->subtype == QV4::ErrorObject::SyntaxError) {
- QV4::DiagnosticMessage *msg = static_cast<QV4::SyntaxErrorObject*>(errorObj)->message();
- error.setUrl(QUrl(msg->fileName));
- error.setLine(msg->startLine);
- error.setColumn(msg->startColumn);
- error.setDescription(msg->message);
- // ### FIXME: support msg->next
- } else {
- QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
- if (!trace.isEmpty()) {
- QV4::ExecutionEngine::StackFrame frame = trace.first();
- error.setUrl(QUrl(frame.source));
- error.setLine(frame.line);
- error.setColumn(frame.column);
- }
+ if (errorObj && errorObj->asSyntaxError())
+ error.setDescription(errorObj->get(errorObj->engine()->newString("message")).toQString());
+ else
error.setDescription(e.value().toQString());
- }
}
QV4::PersistentValue
if (!e) {
std::cerr << "Uncaught exception: " << qPrintable(exception.value().toString(ctx)->toQString()) << std::endl;
} else {
- if (QV4::SyntaxErrorObject *err = e->asSyntaxError()) {
- QV4::DiagnosticMessage *msg = err->message();
- if (!msg) {
- std::cerr << "Uncaught exception: Syntax error" << std::endl;
- return;
- }
-
- for (; msg; msg = msg->next) {
- std::cerr << qPrintable(msg->buildFullMessage(ctx)->toQString()) << std::endl;
- }
- } else {
- std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
- }
+ std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
}
foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) {