Separate JSON parsing from the JavaScript parser.
Switch JSON parsing to creating the value directly instead of createing code to create the value. Review URL: http://codereview.chromium.org/4135004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5715 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a8f2714425
commit
938d88e193
@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
|
||||
script->set_context_data((*i::Top::global_context())->data());
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
if (info->is_eval() || info->is_json()) {
|
||||
Script::CompilationType compilation_type = info->is_json()
|
||||
? Script::COMPILATION_TYPE_JSON
|
||||
: Script::COMPILATION_TYPE_EVAL;
|
||||
if (info->is_eval()) {
|
||||
Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
|
||||
script->set_compilation_type(Smi::FromInt(compilation_type));
|
||||
// For eval scripts add information on the function from which eval was
|
||||
// called.
|
||||
@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
|
||||
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
bool is_global,
|
||||
ValidationState validate) {
|
||||
// Note that if validation is required then no path through this function
|
||||
// is allowed to return a value without validating that the input is legal
|
||||
// json.
|
||||
bool is_json = (validate == VALIDATE_JSON);
|
||||
|
||||
bool is_global) {
|
||||
int source_length = source->length();
|
||||
Counters::total_eval_size.Increment(source_length);
|
||||
Counters::total_compile_size.Increment(source_length);
|
||||
@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
VMState state(COMPILER);
|
||||
|
||||
// Do a lookup in the compilation cache; if the entry is not there, invoke
|
||||
// the compiler and add the result to the cache. If we're evaluating json
|
||||
// we bypass the cache since we can't be sure a potential value in the
|
||||
// cache has been validated.
|
||||
// the compiler and add the result to the cache.
|
||||
Handle<SharedFunctionInfo> result;
|
||||
if (!is_json) {
|
||||
result = CompilationCache::LookupEval(source, context, is_global);
|
||||
}
|
||||
result = CompilationCache::LookupEval(source, context, is_global);
|
||||
|
||||
if (result.is_null()) {
|
||||
// Create a script object describing the script to be compiled.
|
||||
@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsEval();
|
||||
if (is_global) info.MarkAsGlobal();
|
||||
if (is_json) info.MarkAsJson();
|
||||
info.SetCallingContext(context);
|
||||
result = MakeFunctionInfo(&info);
|
||||
if (!result.is_null() && !is_json) {
|
||||
// For json it's unlikely that we'll ever see exactly the same string
|
||||
// again so we don't use the compilation cache.
|
||||
if (!result.is_null()) {
|
||||
CompilationCache::PutEval(source, context, is_global, result);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
|
||||
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
|
||||
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
|
||||
bool is_json() const { return (flags_ & IsJson::mask()) != 0; }
|
||||
bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
|
||||
FunctionLiteral* function() const { return function_; }
|
||||
Scope* scope() const { return scope_; }
|
||||
@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsGlobal::encode(true);
|
||||
}
|
||||
void MarkAsJson() {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsJson::encode(true);
|
||||
}
|
||||
void MarkAsInLoop() {
|
||||
ASSERT(is_lazy());
|
||||
flags_ |= IsInLoop::encode(true);
|
||||
@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
// Flags that can be set for eager compilation.
|
||||
class IsEval: public BitField<bool, 1, 1> {};
|
||||
class IsGlobal: public BitField<bool, 2, 1> {};
|
||||
class IsJson: public BitField<bool, 3, 1> {};
|
||||
// Flags that can be set for lazy compilation.
|
||||
class IsInLoop: public BitField<bool, 4, 1> {};
|
||||
class IsInLoop: public BitField<bool, 3, 1> {};
|
||||
|
||||
unsigned flags_;
|
||||
|
||||
// Fields filled in by the compilation pipeline.
|
||||
// AST filled in by the parser.
|
||||
FunctionLiteral* function_;
|
||||
// The scope of the function literal as a convenience. Set to indidicate
|
||||
// The scope of the function literal as a convenience. Set to indicate
|
||||
// that scopes have been analyzed.
|
||||
Scope* scope_;
|
||||
// The compiled code.
|
||||
@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
|
||||
class Compiler : public AllStatic {
|
||||
public:
|
||||
enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
|
||||
|
||||
// All routines return a JSFunction.
|
||||
// If an error occurs an exception is raised and
|
||||
// the return handle contains NULL.
|
||||
@ -172,8 +164,7 @@ class Compiler : public AllStatic {
|
||||
// Compile a String source within a context for Eval.
|
||||
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
bool is_global,
|
||||
ValidationState validation);
|
||||
bool is_global);
|
||||
|
||||
// Compile from function info (used for lazy compilation). Returns true on
|
||||
// success and false if the compilation resulted in a stack overflow.
|
||||
|
@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
|
||||
try {
|
||||
try {
|
||||
// Convert the JSON string to an object.
|
||||
request = %CompileString('(' + json_request + ')', false)();
|
||||
request = %CompileString('(' + json_request + ')')();
|
||||
|
||||
// Create an initial response.
|
||||
response = this.createResponse(request);
|
||||
|
@ -29,8 +29,7 @@ var $JSON = global.JSON;
|
||||
|
||||
function ParseJSONUnfiltered(text) {
|
||||
var s = $String(text);
|
||||
var f = %CompileString(s, true);
|
||||
return f();
|
||||
return %ParseJson(s);
|
||||
}
|
||||
|
||||
function Revive(holder, name, reviver) {
|
||||
|
@ -3409,8 +3409,7 @@ class Script: public Struct {
|
||||
// Script compilation types.
|
||||
enum CompilationType {
|
||||
COMPILATION_TYPE_HOST = 0,
|
||||
COMPILATION_TYPE_EVAL = 1,
|
||||
COMPILATION_TYPE_JSON = 2
|
||||
COMPILATION_TYPE_EVAL = 1
|
||||
};
|
||||
|
||||
// [source]: the script source.
|
||||
|
274
src/parser.cc
274
src/parser.cc
@ -1382,56 +1382,6 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
|
||||
}
|
||||
|
||||
|
||||
FunctionLiteral* Parser::ParseJson(Handle<String> source) {
|
||||
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
||||
|
||||
HistogramTimerScope timer(&Counters::parse);
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
|
||||
// Initialize parser state.
|
||||
source->TryFlatten(TENURED);
|
||||
scanner_.Initialize(source, JSON);
|
||||
ASSERT(target_stack_ == NULL);
|
||||
|
||||
FunctionLiteral* result = NULL;
|
||||
Handle<String> no_name = factory()->EmptySymbol();
|
||||
|
||||
{
|
||||
Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, false);
|
||||
LexicalScope lexical_scope(this, scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
bool ok = true;
|
||||
Expression* expression = ParseJson(&ok);
|
||||
if (ok) {
|
||||
ZoneListWrapper<Statement> statement = factory()->NewList<Statement>(1);
|
||||
statement.Add(new ExpressionStatement(expression));
|
||||
result = NEW(FunctionLiteral(
|
||||
no_name,
|
||||
top_scope_,
|
||||
statement.elements(),
|
||||
temp_scope.materialized_literal_count(),
|
||||
temp_scope.expected_property_count(),
|
||||
temp_scope.only_simple_this_property_assignments(),
|
||||
temp_scope.this_property_assignments(),
|
||||
0,
|
||||
0,
|
||||
source->length(),
|
||||
false,
|
||||
temp_scope.ContainsLoops()));
|
||||
} else if (scanner().stack_overflow()) {
|
||||
Top::StackOverflow();
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the target stack is empty.
|
||||
ASSERT(target_stack_ == NULL);
|
||||
|
||||
// If there was a syntax error we have to get rid of the AST
|
||||
// and it is not safe to do so before the scope has been deleted.
|
||||
if (result == NULL) zone_scope.DeleteOnExit();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Parser::ReportMessage(const char* type, Vector<const char*> args) {
|
||||
Scanner::Location source_location = scanner_.location();
|
||||
ReportMessageAt(source_location, type, args);
|
||||
@ -4281,145 +4231,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
|
||||
// ----------------------------------------------------------------------------
|
||||
// JSON
|
||||
|
||||
Expression* Parser::ParseJson(bool* ok) {
|
||||
Expression* result = ParseJsonValue(CHECK_OK);
|
||||
Expect(Token::EOS, CHECK_OK);
|
||||
Handle<Object> JsonParser::ParseJson(Handle<String> source) {
|
||||
source->TryFlatten();
|
||||
scanner_.Initialize(source, JSON);
|
||||
Handle<Object> result = ParseJsonValue();
|
||||
if (result.is_null() || scanner_.Next() != Token::EOS) {
|
||||
if (scanner_.stack_overflow()) {
|
||||
// Scanner failed.
|
||||
Top::StackOverflow();
|
||||
} else {
|
||||
// Parse failed. Scanner's current token is the unexpected token.
|
||||
Token::Value token = scanner_.current_token();
|
||||
|
||||
const char* message;
|
||||
const char* name_opt = NULL;
|
||||
|
||||
switch (token) {
|
||||
case Token::EOS:
|
||||
message = "unexpected_eos";
|
||||
break;
|
||||
case Token::NUMBER:
|
||||
message = "unexpected_token_number";
|
||||
break;
|
||||
case Token::STRING:
|
||||
message = "unexpected_token_string";
|
||||
break;
|
||||
case Token::IDENTIFIER:
|
||||
message = "unexpected_token_identifier";
|
||||
break;
|
||||
default:
|
||||
message = "unexpected_token";
|
||||
name_opt = Token::String(token);
|
||||
ASSERT(name_opt != NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
Scanner::Location source_location = scanner_.location();
|
||||
MessageLocation location(Factory::NewScript(source),
|
||||
source_location.beg_pos,
|
||||
source_location.end_pos);
|
||||
int argc = (name_opt == NULL) ? 0 : 1;
|
||||
Handle<JSArray> array = Factory::NewJSArray(argc);
|
||||
if (name_opt != NULL) {
|
||||
SetElement(array,
|
||||
0,
|
||||
Factory::NewStringFromUtf8(CStrVector(name_opt)));
|
||||
}
|
||||
Handle<Object> result = Factory::NewSyntaxError(message, array);
|
||||
Top::Throw(*result, &location);
|
||||
return Handle<Object>::null();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Handle<String> JsonParser::GetString() {
|
||||
int literal_length = scanner_.literal_length();
|
||||
if (literal_length == 0) {
|
||||
return Factory::empty_string();
|
||||
}
|
||||
const char* literal_string = scanner_.literal_string();
|
||||
Vector<const char> literal(literal_string, literal_length);
|
||||
return Factory::NewStringFromUtf8(literal);
|
||||
}
|
||||
|
||||
|
||||
// Parse any JSON value.
|
||||
Expression* Parser::ParseJsonValue(bool* ok) {
|
||||
Token::Value token = peek();
|
||||
Handle<Object> JsonParser::ParseJsonValue() {
|
||||
Token::Value token = scanner_.Next();
|
||||
switch (token) {
|
||||
case Token::STRING: {
|
||||
Consume(Token::STRING);
|
||||
int literal_length = scanner_.literal_length();
|
||||
const char* literal_string = scanner_.literal_string();
|
||||
if (literal_length == 0) {
|
||||
return NEW(Literal(Factory::empty_string()));
|
||||
}
|
||||
Vector<const char> literal(literal_string, literal_length);
|
||||
return NEW(Literal(Factory::NewStringFromUtf8(literal, TENURED)));
|
||||
return GetString();
|
||||
}
|
||||
case Token::NUMBER: {
|
||||
Consume(Token::NUMBER);
|
||||
ASSERT(scanner_.literal_length() > 0);
|
||||
double value = StringToDouble(scanner_.literal(),
|
||||
NO_FLAGS, // Hex, octal or trailing junk.
|
||||
OS::nan_value());
|
||||
return NewNumberLiteral(value);
|
||||
return Factory::NewNumber(value);
|
||||
}
|
||||
case Token::FALSE_LITERAL:
|
||||
Consume(Token::FALSE_LITERAL);
|
||||
return NEW(Literal(Factory::false_value()));
|
||||
return Factory::false_value();
|
||||
case Token::TRUE_LITERAL:
|
||||
Consume(Token::TRUE_LITERAL);
|
||||
return NEW(Literal(Factory::true_value()));
|
||||
return Factory::true_value();
|
||||
case Token::NULL_LITERAL:
|
||||
Consume(Token::NULL_LITERAL);
|
||||
return NEW(Literal(Factory::null_value()));
|
||||
case Token::LBRACE: {
|
||||
Expression* result = ParseJsonObject(CHECK_OK);
|
||||
return result;
|
||||
}
|
||||
case Token::LBRACK: {
|
||||
Expression* result = ParseJsonArray(CHECK_OK);
|
||||
return result;
|
||||
}
|
||||
return Factory::null_value();
|
||||
case Token::LBRACE:
|
||||
return ParseJsonObject();
|
||||
case Token::LBRACK:
|
||||
return ParseJsonArray();
|
||||
default:
|
||||
*ok = false;
|
||||
ReportUnexpectedToken(token);
|
||||
return NULL;
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse a JSON object. Scanner must be right after '{' token.
|
||||
Expression* Parser::ParseJsonObject(bool* ok) {
|
||||
Consume(Token::LBRACE);
|
||||
ZoneListWrapper<ObjectLiteral::Property> properties =
|
||||
factory()->NewList<ObjectLiteral::Property>(4);
|
||||
int boilerplate_properties = 0;
|
||||
if (peek() != Token::RBRACE) {
|
||||
Handle<Object> JsonParser::ParseJsonObject() {
|
||||
Handle<JSFunction> object_constructor(
|
||||
Top::global_context()->object_function());
|
||||
Handle<JSObject> json_object = Factory::NewJSObject(object_constructor);
|
||||
if (scanner_.peek() == Token::RBRACE) {
|
||||
scanner_.Next();
|
||||
} else {
|
||||
do {
|
||||
Expect(Token::STRING, CHECK_OK);
|
||||
Handle<String> key = GetSymbol(CHECK_OK);
|
||||
Expect(Token::COLON, CHECK_OK);
|
||||
Expression* value = ParseJsonValue(CHECK_OK);
|
||||
Literal* key_literal;
|
||||
if (scanner_.Next() != Token::STRING) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
Handle<String> key = GetString();
|
||||
if (scanner_.Next() != Token::COLON) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
Handle<Object> value = ParseJsonValue();
|
||||
if (value.is_null()) return Handle<Object>::null();
|
||||
uint32_t index;
|
||||
if (key->AsArrayIndex(&index)) {
|
||||
key_literal = NewNumberLiteral(index);
|
||||
SetElement(json_object, index, value);
|
||||
} else {
|
||||
key_literal = NEW(Literal(key));
|
||||
SetProperty(json_object, key, value, NONE);
|
||||
}
|
||||
ObjectLiteral::Property* property =
|
||||
NEW(ObjectLiteral::Property(key_literal, value));
|
||||
properties.Add(property);
|
||||
|
||||
if (IsBoilerplateProperty(property)) {
|
||||
boilerplate_properties++;
|
||||
}
|
||||
} while (Check(Token::COMMA));
|
||||
} while (scanner_.Next() == Token::COMMA);
|
||||
if (scanner_.current_token() != Token::RBRACE) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
Expect(Token::RBRACE, CHECK_OK);
|
||||
|
||||
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
|
||||
if (is_pre_parsing_) return NULL;
|
||||
|
||||
Handle<FixedArray> constant_properties =
|
||||
Factory::NewFixedArray(boilerplate_properties * 2, TENURED);
|
||||
bool is_simple = true;
|
||||
bool fast_elements = true;
|
||||
int depth = 1;
|
||||
BuildObjectLiteralConstantProperties(properties.elements(),
|
||||
constant_properties,
|
||||
&is_simple,
|
||||
&fast_elements,
|
||||
&depth);
|
||||
return new ObjectLiteral(constant_properties,
|
||||
properties.elements(),
|
||||
literal_index,
|
||||
is_simple,
|
||||
fast_elements,
|
||||
depth);
|
||||
return json_object;
|
||||
}
|
||||
|
||||
|
||||
// Parse a JSON array. Scanner must be right after '[' token.
|
||||
Expression* Parser::ParseJsonArray(bool* ok) {
|
||||
Consume(Token::LBRACK);
|
||||
Handle<Object> JsonParser::ParseJsonArray() {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
ZoneList<Handle<Object> > elements(4);
|
||||
|
||||
ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4);
|
||||
if (peek() != Token::RBRACK) {
|
||||
Token::Value token = scanner_.peek();
|
||||
if (token == Token::RBRACK) {
|
||||
scanner_.Next();
|
||||
} else {
|
||||
do {
|
||||
Expression* exp = ParseJsonValue(CHECK_OK);
|
||||
values.Add(exp);
|
||||
} while (Check(Token::COMMA));
|
||||
Handle<Object> element = ParseJsonValue();
|
||||
if (element.is_null()) return Handle<Object>::null();
|
||||
elements.Add(element);
|
||||
token = scanner_.Next();
|
||||
} while (token == Token::COMMA);
|
||||
if (token != Token::RBRACK) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
Expect(Token::RBRACK, CHECK_OK);
|
||||
|
||||
// Update the scope information before the pre-parsing bailout.
|
||||
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
|
||||
// Allocate a fixed array with all the elements.
|
||||
Handle<FixedArray> fast_elements =
|
||||
Factory::NewFixedArray(elements.length());
|
||||
|
||||
if (is_pre_parsing_) return NULL;
|
||||
for (int i = 0, n = elements.length(); i < n; i++) {
|
||||
fast_elements->set(i, *elements[i]);
|
||||
}
|
||||
|
||||
// Allocate a fixed array with all the literals.
|
||||
Handle<FixedArray> literals =
|
||||
Factory::NewFixedArray(values.length(), TENURED);
|
||||
|
||||
bool is_simple;
|
||||
int depth;
|
||||
BuildArrayLiteralBoilerplateLiterals(values.elements(),
|
||||
literals,
|
||||
&is_simple,
|
||||
&depth);
|
||||
return NEW(ArrayLiteral(literals, values.elements(),
|
||||
literal_index, is_simple, depth));
|
||||
return Factory::NewJSArrayWithElements(fast_elements);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Regular expressions
|
||||
|
||||
@ -5368,11 +5338,7 @@ bool Parser::Parse(CompilationInfo* info) {
|
||||
ASSERT(Top::has_pending_exception());
|
||||
} else {
|
||||
Handle<String> source = Handle<String>(String::cast(script->source()));
|
||||
// JSON is always global.
|
||||
ASSERT(!info->is_json() || info->is_global());
|
||||
result = info->is_json()
|
||||
? parser.ParseJson(source)
|
||||
: parser.ParseProgram(source, info->is_global());
|
||||
result = parser.ParseProgram(source, info->is_global());
|
||||
}
|
||||
}
|
||||
|
||||
|
67
src/parser.h
67
src/parser.h
@ -218,7 +218,6 @@ class Parser {
|
||||
FunctionLiteral* ParseProgram(Handle<String> source,
|
||||
bool in_global_context);
|
||||
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
|
||||
FunctionLiteral* ParseJson(Handle<String> source);
|
||||
|
||||
// The minimum number of contiguous assignment that will
|
||||
// be treated as an initialization block. Benchmarks show that
|
||||
@ -411,29 +410,6 @@ class Parser {
|
||||
Handle<String> type,
|
||||
Vector< Handle<Object> > arguments);
|
||||
|
||||
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
|
||||
// specification section 15.12.1 (and appendix A.8).
|
||||
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
|
||||
|
||||
// Parse JSON input as a single JSON value.
|
||||
Expression* ParseJson(bool* ok);
|
||||
|
||||
// Parse a single JSON value from input (grammar production JSONValue).
|
||||
// A JSON value is either a (double-quoted) string literal, a number literal,
|
||||
// one of "true", "false", or "null", or an object or array literal.
|
||||
Expression* ParseJsonValue(bool* ok);
|
||||
// Parse a JSON object literal (grammar production JSONObject).
|
||||
// An object literal is a squiggly-braced and comma separated sequence
|
||||
// (possibly empty) of key/value pairs, where the key is a JSON string
|
||||
// literal, the value is a JSON value, and the two are spearated by a colon.
|
||||
// A JavaScript object also allows numbers and identifiers as keys.
|
||||
Expression* ParseJsonObject(bool* ok);
|
||||
// Parses a JSON array literal (grammar production JSONArray). An array
|
||||
// literal is a square-bracketed and comma separated sequence (possibly empty)
|
||||
// of JSON values.
|
||||
// A JavaScript array allows leaving out values from the sequence.
|
||||
Expression* ParseJsonArray(bool* ok);
|
||||
|
||||
friend class Target;
|
||||
friend class TargetScope;
|
||||
friend class LexicalScope;
|
||||
@ -472,6 +448,49 @@ class CompileTimeValue: public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
|
||||
// specification section 15.12.1 (and appendix A.8).
|
||||
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
|
||||
class JsonParser BASE_EMBEDDED {
|
||||
public:
|
||||
// Parse JSON input as a single JSON value.
|
||||
// Returns null handle and sets exception if parsing failed.
|
||||
static Handle<Object> Parse(Handle<String> source) {
|
||||
return JsonParser().ParseJson(source);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonParser() { }
|
||||
~JsonParser() { }
|
||||
|
||||
// Parse a string containing a single JSON value.
|
||||
Handle<Object> ParseJson(Handle<String>);
|
||||
// Parse a single JSON value from input (grammar production JSONValue).
|
||||
// A JSON value is either a (double-quoted) string literal, a number literal,
|
||||
// one of "true", "false", or "null", or an object or array literal.
|
||||
Handle<Object> ParseJsonValue();
|
||||
// Parse a JSON object literal (grammar production JSONObject).
|
||||
// An object literal is a squiggly-braced and comma separated sequence
|
||||
// (possibly empty) of key/value pairs, where the key is a JSON string
|
||||
// literal, the value is a JSON value, and the two are separated by a colon.
|
||||
// A JSON array dosn't allow numbers and identifiers as keys, like a
|
||||
// JavaScript array.
|
||||
Handle<Object> ParseJsonObject();
|
||||
// Parses a JSON array literal (grammar production JSONArray). An array
|
||||
// literal is a square-bracketed and comma separated sequence (possibly empty)
|
||||
// of JSON values.
|
||||
// A JSON array doesn't allow leaving out values from the sequence, nor does
|
||||
// it allow a terminal comma, like a JavaScript array does.
|
||||
Handle<Object> ParseJsonArray();
|
||||
|
||||
// Mark that a parsing error has happened at the current token, and
|
||||
// return a null handle. Primarily for readability.
|
||||
Handle<Object> ReportUnexpectedToken() { return Handle<Object>::null(); }
|
||||
// Converts the currently parsed literal to a JavaScript String.
|
||||
Handle<String> GetString();
|
||||
|
||||
Scanner scanner_;
|
||||
};
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_PARSER_H_
|
||||
|
@ -7129,20 +7129,31 @@ static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* Runtime_ParseJson(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT_EQ(1, args.length());
|
||||
CONVERT_ARG_CHECKED(String, source, 0);
|
||||
|
||||
Handle<Object> result = JsonParser::Parse(source);
|
||||
if (result.is_null()) {
|
||||
// Syntax error or stack overflow in scanner.
|
||||
ASSERT(Top::has_pending_exception());
|
||||
return Failure::Exception();
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* Runtime_CompileString(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT_EQ(2, args.length());
|
||||
ASSERT_EQ(1, args.length());
|
||||
CONVERT_ARG_CHECKED(String, source, 0);
|
||||
CONVERT_ARG_CHECKED(Oddball, is_json, 1)
|
||||
|
||||
// Compile source string in the global context.
|
||||
Handle<Context> context(Top::context()->global_context());
|
||||
Compiler::ValidationState validate = (is_json->IsTrue())
|
||||
? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
|
||||
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
|
||||
context,
|
||||
true,
|
||||
validate);
|
||||
true);
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> fun =
|
||||
Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
|
||||
@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source,
|
||||
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
|
||||
source,
|
||||
Handle<Context>(Top::context()),
|
||||
Top::context()->IsGlobalContext(),
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
Top::context()->IsGlobalContext());
|
||||
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
|
||||
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
|
||||
shared,
|
||||
@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
Compiler::CompileEval(function_source,
|
||||
context,
|
||||
context->IsGlobalContext(),
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
context->IsGlobalContext());
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> compiled_function =
|
||||
Factory::NewFunctionFromSharedFunctionInfo(shared, context);
|
||||
@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
Compiler::CompileEval(source,
|
||||
context,
|
||||
true,
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
true);
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> compiled_function =
|
||||
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
|
||||
|
@ -164,6 +164,9 @@ namespace internal {
|
||||
F(RegExpConstructResult, 3, 1) \
|
||||
F(RegExpCloneResult, 1, 1) \
|
||||
\
|
||||
/* JSON */ \
|
||||
F(ParseJson, 1, 1) \
|
||||
\
|
||||
/* Strings */ \
|
||||
F(StringCharCodeAt, 2, 1) \
|
||||
F(StringIndexOf, 3, 1) \
|
||||
@ -222,7 +225,7 @@ namespace internal {
|
||||
/* Numbers */ \
|
||||
\
|
||||
/* Globals */ \
|
||||
F(CompileString, 2, 1) \
|
||||
F(CompileString, 1, 1) \
|
||||
F(GlobalPrint, 1, 1) \
|
||||
\
|
||||
/* Eval */ \
|
||||
|
@ -296,6 +296,9 @@ class Scanner {
|
||||
// Returns the next token.
|
||||
Token::Value Next();
|
||||
|
||||
// Returns the current token again.
|
||||
Token::Value current_token() { return current_.token; }
|
||||
|
||||
// One token look-ahead (past the token returned by Next()).
|
||||
Token::Value peek() const { return next_.token; }
|
||||
|
||||
|
@ -140,7 +140,7 @@ function GlobalEval(x) {
|
||||
'be the global object from which eval originated');
|
||||
}
|
||||
|
||||
var f = %CompileString(x, false);
|
||||
var f = %CompileString(x);
|
||||
if (!IS_FUNCTION(f)) return f;
|
||||
|
||||
return f.call(this);
|
||||
@ -151,7 +151,7 @@ function GlobalEval(x) {
|
||||
function GlobalExecScript(expr, lang) {
|
||||
// NOTE: We don't care about the character casing.
|
||||
if (!lang || /javascript/i.test(lang)) {
|
||||
var f = %CompileString(ToString(expr), false);
|
||||
var f = %CompileString(ToString(expr));
|
||||
f.call(%GlobalReceiver(global));
|
||||
}
|
||||
return null;
|
||||
@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1
|
||||
|
||||
// The call to SetNewFunctionAttributes will ensure the prototype
|
||||
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
|
||||
var f = %CompileString(source, false)();
|
||||
var f = %CompileString(source)();
|
||||
%FunctionSetName(f, "anonymous");
|
||||
return %SetNewFunctionAttributes(f);
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled.
|
||||
var source_count = 0; // Total number of scources compiled.
|
||||
var host_compilations = 0; // Number of scources compiled through the API.
|
||||
var eval_compilations = 0; // Number of scources compiled through eval.
|
||||
var json_compilations = 0; // Number of scources compiled through JSON.parse.
|
||||
|
||||
|
||||
function compileSource(source) {
|
||||
@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) {
|
||||
case Debug.ScriptCompilationType.Eval:
|
||||
eval_compilations++;
|
||||
break;
|
||||
case Debug.ScriptCompilationType.JSON:
|
||||
json_compilations++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) {
|
||||
// For source with 'eval' there will be compile events with substrings
|
||||
// as well as with with the exact source.
|
||||
assertTrue(current_source.indexOf(event_data.script().source()) >= 0);
|
||||
} else if (current_source.indexOf('JSON.parse') == 0) {
|
||||
// For JSON the JSON source will be in parentheses.
|
||||
var s = event_data.script().source();
|
||||
if (s[0] == '(') {
|
||||
s = s.substring(1, s.length - 2);
|
||||
}
|
||||
assertTrue(current_source.indexOf(s) >= 0);
|
||||
} else {
|
||||
// For source without 'eval' there will be a compile events with the
|
||||
// exact source.
|
||||
@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event.
|
||||
compileSource('eval("eval(\'(function(){return a;})\')")');
|
||||
source_count += 2; // Using eval causes additional compilation event.
|
||||
compileSource('JSON.parse(\'{"a":1,"b":2}\')');
|
||||
source_count++; // Using JSON.parse causes additional compilation event.
|
||||
// Using JSON.parse does not causes additional compilation events.
|
||||
compileSource('x=1; //@ sourceURL=myscript.js');
|
||||
|
||||
// Make sure that the debug event listener was invoked.
|
||||
@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener")
|
||||
assertEquals(before_compile_count, after_compile_count);
|
||||
|
||||
// Check the actual number of events (no compilation through the API as all
|
||||
// source compiled through eval except for one JSON.parse call).
|
||||
// source compiled through eval).
|
||||
assertEquals(source_count, after_compile_count);
|
||||
assertEquals(0, host_compilations);
|
||||
assertEquals(source_count - 1, eval_compilations);
|
||||
assertEquals(1, json_compilations);
|
||||
assertEquals(source_count, eval_compilations);
|
||||
|
||||
Debug.setListener(null);
|
||||
|
@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
|
||||
|
||||
|
||||
// Test the script mirror for different functions.
|
||||
testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0);
|
||||
testScriptMirror(function(){}, 'mirror-script.js', 98, 2, 0);
|
||||
testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
|
||||
testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
|
||||
testScriptMirror(eval('(function(){\n })'), null, 2, 2, 1, '(function(){\n })', 88);
|
||||
testScriptMirror(%CompileString('{"a":1,"b":2}', true), null, 1, 2, 2, '{"a":1,"b":2}');
|
||||
testScriptMirror(%CompileString('{"a":1,\n "b":2}', true), null, 2, 2, 2, '{"a":1,\n "b":2}');
|
||||
|
||||
// Test taking slices of source.
|
||||
var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script();
|
||||
|
Loading…
Reference in New Issue
Block a user