| Index: preparser/preparser-process.cc
|
| ===================================================================
|
| --- preparser/preparser-process.cc (revision 7948)
|
| +++ preparser/preparser-process.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -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 @@
|
| }
|
|
|
|
|
| +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,133 @@
|
| };
|
|
|
|
|
| -int main(int argc, char* argv[]) {
|
| - // Check for filename argument.
|
| - if (argc < 2) {
|
| - fprintf(stderr, "ERROR: No filename on command line.\n");
|
| +
|
| +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);
|
| - return EXIT_FAILURE;
|
| }
|
| - const char* filename = argv[1];
|
| + exit(EXIT_FAILURE);
|
| +};
|
|
|
| +
|
| +bool IsFlag(const char* arg) {
|
| + // Anything starting with '-' is considered a flag.
|
| + // It's summarily ignored for now.
|
| + return arg[0] == '-';
|
| +}
|
| +
|
| +
|
| +struct ExceptionExpectation {
|
| + ExceptionExpectation()
|
| + : throws(false), type(NULL), beg_pos(-1), end_pos(-1) { }
|
| + bool throws;
|
| + const char* type;
|
| + int beg_pos;
|
| + int end_pos;
|
| +};
|
| +
|
| +
|
| +void CheckException(v8::PreParserData* data,
|
| + ExceptionExpectation* expects) {
|
| + PreparseDataInterpreter reader(data->data(), data->size());
|
| + if (expects->throws) {
|
| + if (!reader.throws()) {
|
| + if (expects->type == NULL) {
|
| + fail(data, "Didn't throw as expected\n");
|
| + } else {
|
| + fail(data, "Didn't throw \"%s\" as expected\n", expects->type);
|
| + }
|
| + }
|
| + if (expects->type != NULL) {
|
| + const char* actual_message = reader.message();
|
| + if (strcmp(expects->type, actual_message)) {
|
| + fail(data, "Wrong error message. Expected <%s>, found <%s>\n",
|
| + expects->type, actual_message);
|
| + }
|
| + }
|
| + if (expects->beg_pos >= 0) {
|
| + if (expects->beg_pos != reader.beg_pos()) {
|
| + fail(data, "Wrong error start position: Expected %i, found %i\n",
|
| + expects->beg_pos, reader.beg_pos());
|
| + }
|
| + }
|
| + if (expects->end_pos >= 0) {
|
| + if (expects->end_pos != reader.end_pos()) {
|
| + fail(data, "Wrong error end position: Expected %i, found %i\n",
|
| + expects->end_pos, reader.end_pos());
|
| + }
|
| + }
|
| + } else if (reader.throws()) {
|
| + const char* message = reader.message();
|
| + fail(data, "Throws unexpectedly with message: %s\n", message);
|
| + }
|
| +}
|
| +
|
| +
|
| +ExceptionExpectation ParseExpectation(int argc, const char* argv[]) {
|
| + ExceptionExpectation expects;
|
| +
|
| + // Parse exception expectations from (the remainder of) the command line.
|
| + int arg_index = 0;
|
| + // Skip any flags.
|
| + while (argc > arg_index && IsFlag(argv[arg_index])) arg_index++;
|
| + if (argc > arg_index) {
|
| + if (strncmp("throws", argv[arg_index], 7)) {
|
| + // First argument after filename, if present, must be the verbatim
|
| + // "throws", marking that the preparsing should fail with an exception.
|
| + fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n");
|
| + }
|
| + expects.throws = true;
|
| + do {
|
| + arg_index++;
|
| + } while (argc > arg_index && IsFlag(argv[arg_index]));
|
| + if (argc > arg_index) {
|
| + // Next argument is the exception type identifier.
|
| + expects.type = argv[arg_index];
|
| + do {
|
| + arg_index++;
|
| + } while (argc > arg_index && IsFlag(argv[arg_index]));
|
| + if (argc > arg_index) {
|
| + expects.beg_pos = atoi(argv[arg_index]);
|
| + do {
|
| + arg_index++;
|
| + } while (argc > arg_index && IsFlag(argv[arg_index]));
|
| + if (argc > arg_index) {
|
| + expects.end_pos = atoi(argv[arg_index]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return expects;
|
| +}
|
| +
|
| +
|
| +int main(int argc, const char* argv[]) {
|
| + // Parse command line.
|
| + // Format: preparser <scriptfile> ["throws" [<exn-type> [<start> [<end>]]]]
|
| + // Any flags on the line are ignored.
|
| +
|
| + // Check for mandatory filename argument.
|
| + int arg_index = 1;
|
| + while (argc > arg_index && IsFlag(argv[arg_index])) arg_index++;
|
| + if (argc <= arg_index) {
|
| + fail(NULL, "ERROR: No filename on command line.\n");
|
| + }
|
| + const char* filename = argv[arg_index];
|
| + // Check remainder of command line for exception expectations.
|
| + arg_index++;
|
| + ExceptionExpectation expects =
|
| + ParseExpectation(argc - arg_index, argv + arg_index);
|
| +
|
| // Open JS file.
|
| FILE* input = fopen(filename, "rb");
|
| if (input == NULL) {
|
| @@ -151,19 +345,12 @@
|
|
|
| // 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, &expects);
|
|
|
| return EXIT_SUCCESS;
|
| }
|
|
|