Index: preparser/preparser-process.cc |
diff --git a/preparser/preparser-process.cc b/preparser/preparser-process.cc |
index fb6e38660aba998c2f89e1eb6cbeb8a7aba214ac..486094617987be22b496fdce351038d53db9ea77 100644 |
--- a/preparser/preparser-process.cc |
+++ b/preparser/preparser-process.cc |
@@ -28,16 +28,29 @@ |
#include <stdlib.h> |
#include <stdarg.h> |
#include <stdio.h> |
+#include <string.h> |
#include "../include/v8stdint.h" |
#include "../include/v8-preparser.h" |
+#include "../src/preparse-data-format.h" |
+ |
+namespace i = v8::internal; |
+ |
// This file is only used for testing the stand-alone preparser |
// library. |
-// The first (and only) argument must be the path of a JavaScript file. |
-// This file is preparsed and the resulting preparser data is written |
-// to stdout. Diagnostic output is output on stderr. |
-// The file must contain only ASCII characters (UTF-8 isn't supported). |
+// The first argument must be the path of a JavaScript source file. |
+// Optionally this can be followed by the word "throws" (case sensitive), |
+// which signals that the parsing is expected to throw - the default is |
+// to expect the parsing to not throw. |
+// The command line can further be followed by a message text (the |
+// *type* of the exception to throw), and even more optionally, the |
+// start and end position reported with the exception. |
+// |
+// This source file is preparsed and tested against the expectations, and if |
+// successful, the resulting preparser data is written to stdout. |
+// Diagnostic output is output on stderr. |
+// The source file must contain only ASCII characters (UTF-8 isn't supported). |
// The file is read into memory, so it should have a reasonable size. |
@@ -97,6 +110,69 @@ bool WriteBuffer(FILE* dest, const void* buffer, size_t length) { |
} |
+class PreparseDataInterpreter { |
+ public: |
+ PreparseDataInterpreter(const uint8_t* data, int length) |
+ : data_(data), length_(length), message_(NULL) { } |
+ |
+ ~PreparseDataInterpreter() { |
+ if (message_ != NULL) delete[] message_; |
+ } |
+ |
+ bool valid() { |
+ int header_length = |
+ i::PreparseDataConstants::kHeaderSize * sizeof(int); // NOLINT |
+ return length_ >= header_length; |
+ } |
+ |
+ bool throws() { |
+ return valid() && |
+ word(i::PreparseDataConstants::kHasErrorOffset) != 0; |
+ } |
+ |
+ const char* message() { |
+ if (message_ != NULL) return message_; |
+ if (!throws()) return NULL; |
+ int text_pos = i::PreparseDataConstants::kHeaderSize + |
+ i::PreparseDataConstants::kMessageTextPos; |
+ int length = word(text_pos); |
+ char* buffer = new char[length + 1]; |
+ for (int i = 1; i <= length; i++) { |
+ int character = word(text_pos + i); |
+ buffer[i - 1] = character; |
+ } |
+ buffer[length] = '\0'; |
+ message_ = buffer; |
+ return buffer; |
+ } |
+ |
+ int beg_pos() { |
+ if (!throws()) return -1; |
+ return word(i::PreparseDataConstants::kHeaderSize + |
+ i::PreparseDataConstants::kMessageStartPos); |
+ } |
+ |
+ int end_pos() { |
+ if (!throws()) return -1; |
+ return word(i::PreparseDataConstants::kHeaderSize + |
+ i::PreparseDataConstants::kMessageEndPos); |
+ } |
+ |
+ private: |
+ int word(int offset) { |
+ const int* word_data = reinterpret_cast<const int*>(data_); |
+ if (word_data + offset < reinterpret_cast<const int*>(data_ + length_)) { |
+ return word_data[offset]; |
+ } |
+ return -1; |
+ } |
+ |
+ const uint8_t* const data_; |
+ const int length_; |
+ const char* message_; |
+}; |
+ |
+ |
template <typename T> |
class ScopedPointer { |
public: |
@@ -109,15 +185,93 @@ class ScopedPointer { |
}; |
+ |
+void fail(v8::PreParserData* data, const char* message, ...) { |
+ va_list args; |
+ va_start(args, message); |
+ vfprintf(stderr, message, args); |
+ va_end(args); |
+ fflush(stderr); |
+ // Print preparser data to stdout. |
+ uint32_t size = data->size(); |
+ fprintf(stderr, "LOG: data size: %u\n", size); |
+ if (!WriteBuffer(stdout, data->data(), size)) { |
+ perror("ERROR: Writing data"); |
+ fflush(stderr); |
+ } |
+ exit(EXIT_FAILURE); |
+}; |
+ |
+ |
+void CheckException(v8::PreParserData* data, |
+ bool throws, |
+ const char* message, |
+ int beg_pos, |
+ int end_pos) { |
+ PreparseDataInterpreter reader(data->data(), data->size()); |
+ if (throws) { |
+ if (!reader.throws()) { |
+ if (message == NULL) { |
+ fail(data, "Didn't throw as expected\n"); |
+ } else { |
+ fail(data, "Didn't throw \"%s\" as expected\n", message); |
+ } |
+ } |
+ if (message != NULL) { |
+ const char* actual_message = reader.message(); |
+ if (strcmp(message, actual_message)) { |
+ fail(data, "Wrong error message. Expected <%s>, found <%s>\n", |
+ message, actual_message); |
+ } |
+ } |
+ if (beg_pos >= 0) { |
+ if (beg_pos != reader.beg_pos()) { |
+ fail(data, "Wrong error start position: Expected %i, found %i\n", |
+ beg_pos, reader.beg_pos()); |
+ } |
+ } |
+ if (end_pos >= 0) { |
+ if (end_pos != reader.end_pos()) { |
+ fail(data, "Wrong error end position: Expected %i, found %i\n", |
+ end_pos, reader.end_pos()); |
+ } |
+ } |
+ } else if (reader.throws()) { |
+ const char* message = reader.message(); |
+ fail(data, "Throws unexpectedly with message: %s\n", |
+ message); |
+ } |
+} |
+ |
int main(int argc, char* argv[]) { |
// Check for filename argument. |
if (argc < 2) { |
- fprintf(stderr, "ERROR: No filename on command line.\n"); |
- fflush(stderr); |
- return EXIT_FAILURE; |
+ fail(NULL, "ERROR: No filename on command line.\n"); |
} |
const char* filename = argv[1]; |
+ // Parse expectations. |
+ bool throws = false; |
+ const char* throws_message = NULL; |
+ int throws_beg_pos = -1; |
+ int throws_end_pos = -1; |
+ // Check for throws argument. |
+ if (argc > 2) { |
+ if (strncmp("throws", argv[2], 6)) { |
+ fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n"); |
+ } |
+ throws = true; |
+ if (argc > 3) { |
+ throws_message = argv[3]; |
+ } |
+ if (argc > 4) { |
+ throws_beg_pos = atoi(argv[4]); |
+ } |
+ if (argc > 5) { |
+ throws_end_pos = atoi(argv[5]); |
+ } |
+ } |
+ |
// Open JS file. |
FILE* input = fopen(filename, "rb"); |
if (input == NULL) { |
@@ -151,19 +305,13 @@ int main(int argc, char* argv[]) { |
// Fail if stack overflow. |
if (data.stack_overflow()) { |
- fprintf(stderr, "ERROR: Stack overflow\n"); |
- fflush(stderr); |
- return EXIT_FAILURE; |
+ fail(&data, "ERROR: Stack overflow\n"); |
} |
- // Print preparser data to stdout. |
- uint32_t size = data.size(); |
- fprintf(stderr, "LOG: Success, data size: %u\n", size); |
- fflush(stderr); |
- if (!WriteBuffer(stdout, data.data(), size)) { |
- perror("ERROR: Writing data"); |
- return EXIT_FAILURE; |
- } |
+ // Check that the expected exception is thrown, if an exception is |
+ // expected. |
+ CheckException(&data, throws, throws_message, |
+ throws_beg_pos, throws_end_pos); |
return EXIT_SUCCESS; |
} |