Throw a SyntaxError instead of printing an error message.
authorErik Verbruggen <erik.verbruggen@digia.com>
Wed, 28 Nov 2012 10:00:23 +0000 (11:00 +0100)
committerLars Knoll <lars.knoll@digia.com>
Wed, 28 Nov 2012 11:31:20 +0000 (12:31 +0100)
Change-Id: I94ef8a4f2bea80bc3689b104e381a9dc134439fa
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
main.cpp
qmljs_engine.cpp
qmljs_engine.h
qmljs_environment.cpp
qmljs_environment.h
qmljs_objects.cpp
qmljs_objects.h
qv4ecmaobjects.cpp
qv4ecmaobjects_p.h

index bd1bcea..efe2b75 100644 (file)
--- 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
index acf2213..6ac7250 100644 (file)
@@ -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);
index 8d56627..9ed8421 100644 (file)
@@ -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);
 
index 299ffff..f5b6624 100644 (file)
 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"));
index f8339de..74c362a 100644 (file)
@@ -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);
index a7d5d20..8039f0f 100644 (file)
@@ -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();
index 25790f4..0b6f689 100644 (file)
@@ -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 {
index 67ef7aa..b191144 100644 (file)
@@ -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;
 }
 
index d94c979..7afbe43 100644 (file)
@@ -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); }
 };