| 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;
|
| }
|
|
|