From 4bd20c2ac36c59eb72acc71bc78ddbc058199666 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 28 Nov 2012 11:00:23 +0100 Subject: [PATCH] Throw a SyntaxError instead of printing an error message. Change-Id: I94ef8a4f2bea80bc3689b104e381a9dc134439fa Reviewed-by: Lars Knoll --- main.cpp | 28 +++++++++++++++++++++++++--- qmljs_engine.cpp | 7 +++++++ qmljs_engine.h | 1 + qmljs_environment.cpp | 16 ++++++++++++++++ qmljs_environment.h | 17 +++++++++++++++++ qmljs_objects.cpp | 31 ++++++++++++++++++++++++++++--- qmljs_objects.h | 11 +++++++++-- qv4ecmaobjects.cpp | 2 +- qv4ecmaobjects_p.h | 2 +- 9 files changed, 105 insertions(+), 10 deletions(-) diff --git a/main.cpp b/main.cpp index bd1bcea89e..efe2b75b9b 100644 --- a/main.cpp +++ b/main.cpp @@ -108,10 +108,32 @@ struct TestHarnessError: FunctionObject static void showException(QQmlJS::VM::ExecutionContext *ctx) { - if (QQmlJS::VM::ErrorObject *e = ctx->engine->exception.asErrorObject()) - std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; - else + QQmlJS::VM::ErrorObject *e = ctx->engine->exception.asErrorObject(); + if (!e) { std::cerr << "Uncaught exception: " << qPrintable(ctx->engine->exception.toString(ctx)->toQString()) << std::endl; + return; + } + + if (QQmlJS::VM::SyntaxErrorObject *err = e->asSyntaxError()) { + QQmlJS::VM::DiagnosticMessage *msg = err->message(); + if (!msg) { + std::cerr << "Uncaught exception: Syntax error" << std::endl; + return; + } + + for (; msg; msg = msg->next) { + if (msg->fileName) + std::cerr << qPrintable(msg->fileName->toQString()); + std::cerr << ':' << msg->startLine << ':' << msg->startColumn << ": "; + if (msg->type == QQmlJS::VM::DiagnosticMessage::Error) + std::cerr << "error"; + else + std::cerr << "warning"; + std::cerr << ": " << qPrintable(msg->message->toQString()) << std::endl; + } + } else { + std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; + } } #ifndef QMLJS_NO_LLVM diff --git a/qmljs_engine.cpp b/qmljs_engine.cpp index acf221304e..6ac7250aef 100644 --- a/qmljs_engine.cpp +++ b/qmljs_engine.cpp @@ -316,6 +316,13 @@ Object *ExecutionEngine::newErrorObject(const Value &value) return object; } +Object *ExecutionEngine::newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message) +{ + SyntaxErrorObject *object = new SyntaxErrorObject(ctx, message); + object->prototype = syntaxErrorPrototype; + return object; +} + Object *ExecutionEngine::newMathObject(ExecutionContext *ctx) { MathObject *object = new MathObject(ctx); diff --git a/qmljs_engine.h b/qmljs_engine.h index 8d5662783a..9ed8421d27 100644 --- a/qmljs_engine.h +++ b/qmljs_engine.h @@ -175,6 +175,7 @@ struct ExecutionEngine FunctionObject *newRegExpCtor(ExecutionContext *ctx); Object *newErrorObject(const Value &value); + Object *newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message); Object *newMathObject(ExecutionContext *ctx); Object *newActivationObject(DeclarativeEnvironment *ctx); diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp index 299ffffc4a..f5b6624dc3 100644 --- a/qmljs_environment.cpp +++ b/qmljs_environment.cpp @@ -45,6 +45,17 @@ namespace QQmlJS { namespace VM { +DiagnosticMessage::DiagnosticMessage() + : fileName(0) + , offset(0) + , length(0) + , startLine(0) + , startColumn(0) + , type(0) + , message(0) + , next(0) +{} + DeclarativeEnvironment::DeclarativeEnvironment(ExecutionEngine *e) { engine = e; @@ -255,6 +266,11 @@ void ExecutionContext::throwError(const QString &message) throwError(Value::fromObject(engine->newErrorObject(v))); } +void ExecutionContext::throwSyntaxError(DiagnosticMessage *message) +{ + throwError(Value::fromObject(engine->newSyntaxErrorObject(this, message))); +} + void ExecutionContext::throwTypeError() { Value v = Value::fromString(this, QStringLiteral("Type error")); diff --git a/qmljs_environment.h b/qmljs_environment.h index f8339dec7e..74c362aa73 100644 --- a/qmljs_environment.h +++ b/qmljs_environment.h @@ -52,6 +52,22 @@ struct ExecutionEngine; struct ExecutionContext; struct DeclarativeEnvironment; +struct DiagnosticMessage +{ + enum { Error, Warning }; + + String *fileName; + quint32 offset; + quint32 length; + quint32 startLine; + unsigned startColumn: 31; + unsigned type: 1; + String *message; + DiagnosticMessage *next; + + DiagnosticMessage(); +}; + // This merges LexicalEnvironment and EnvironmentRecord from // Sec. 10.2 into one class struct DeclarativeEnvironment @@ -109,6 +125,7 @@ struct ExecutionContext void throwError(Value value); void throwError(const QString &message); + void throwSyntaxError(DiagnosticMessage *message); void throwTypeError(); void throwReferenceError(Value value); void throwUnimplemented(const QString &message); diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index a7d5d20b86..8039f0f1bf 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -525,10 +525,25 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct const bool parsed = parser.parseProgram(); - foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { - std::cerr << qPrintable(fileName) << ':' << m.loc.startLine << ':' << m.loc.startColumn - << ": error: " << qPrintable(m.message) << std::endl; + VM::DiagnosticMessage *error = 0, **errIt = &error; + foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) { + if (m.isError()) { + *errIt = new VM::DiagnosticMessage; // FIXME: should we ask the engine to create this object? + (*errIt)->fileName = ctx->engine->newString(fileName); + (*errIt)->offset = m.loc.offset; + (*errIt)->length = m.loc.length; + (*errIt)->startLine = m.loc.startLine; + (*errIt)->startColumn = m.loc.startColumn; + (*errIt)->type = VM::DiagnosticMessage::Error; + (*errIt)->message = ctx->engine->newString(m.message); + errIt = &(*errIt)->next; + } else { + std::cerr << qPrintable(fileName) << ':' << m.loc.startLine << ':' << m.loc.startColumn + << ": warning: " << qPrintable(m.message) << std::endl; + } } + if (error) + ctx->throwSyntaxError(error); if (parsed) { using namespace AST; @@ -612,6 +627,16 @@ void ErrorObject::setNameProperty(ExecutionContext *ctx) __put__(ctx, QLatin1String("name"), Value::fromString(ctx, className())); } +SyntaxErrorObject::SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message) + : ErrorObject(ctx->argument(0)) + , msg(message) +{ + if (message) + value = Value::fromString(message->message); + setNameProperty(ctx); +} + + Value ScriptFunction::construct(VM::ExecutionContext *ctx) { Object *obj = ctx->engine->newObject(); diff --git a/qmljs_objects.h b/qmljs_objects.h index 25790f457e..0b6f68992b 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -566,6 +566,8 @@ struct ErrorObject: Object { virtual ErrorObject *asErrorObject() { return this; } virtual Value __get__(ExecutionContext *ctx, String *name); + virtual struct SyntaxErrorObject *asSyntaxError() { return 0; } + protected: void setNameProperty(ExecutionContext *ctx); }; @@ -589,9 +591,14 @@ struct ReferenceErrorObject: ErrorObject { }; struct SyntaxErrorObject: ErrorObject { - SyntaxErrorObject(ExecutionContext *ctx) - : ErrorObject(ctx->argument(0)) { setNameProperty(ctx); } + SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *msg); virtual QString className() { return QStringLiteral("SyntaxError"); } + + virtual SyntaxErrorObject *asSyntaxError() { return this; } + DiagnosticMessage *message() { return msg; } + +private: + DiagnosticMessage *msg; }; struct TypeErrorObject: ErrorObject { diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index 67ef7aa8a5..b191144077 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -2630,7 +2630,7 @@ Value ReferenceErrorCtor::construct(ExecutionContext *ctx) Value SyntaxErrorCtor::construct(ExecutionContext *ctx) { - ctx->thisObject = Value::fromObject(new SyntaxErrorObject(ctx)); + ctx->thisObject = Value::fromObject(new SyntaxErrorObject(ctx, 0)); return ctx->thisObject; } diff --git a/qv4ecmaobjects_p.h b/qv4ecmaobjects_p.h index d94c979413..7afbe43ac5 100644 --- a/qv4ecmaobjects_p.h +++ b/qv4ecmaobjects_p.h @@ -375,7 +375,7 @@ struct ReferenceErrorPrototype: ReferenceErrorObject struct SyntaxErrorPrototype: SyntaxErrorObject { - SyntaxErrorPrototype(ExecutionContext *ctx): SyntaxErrorObject(ctx) {} + SyntaxErrorPrototype(ExecutionContext *ctx): SyntaxErrorObject(ctx, 0) {} void init(ExecutionContext *ctx, const Value &ctor) { ErrorPrototype::init(ctx, ctor, this); } };