Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 3ae85774f719728be16802ec8c3c3800feca5e35..30efa243c38cb4957ce1b89b2c4e92797f0ee2e0 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -91,7 +91,7 @@ class PositionStack { |
class Parser { |
public: |
Parser(Handle<Script> script, bool allow_natives_syntax, |
- v8::Extension* extension, bool is_pre_parsing, |
+ v8::Extension* extension, ParserMode is_pre_parsing, |
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data); |
virtual ~Parser() { } |
@@ -112,6 +112,8 @@ class Parser { |
FunctionLiteral* ParseLazy(Handle<String> source, |
Handle<String> name, |
int start_position, bool is_expression); |
+ FunctionLiteral* ParseJson(Handle<String> source, |
+ unibrow::CharacterStream* stream); |
// The minimum number of contiguous assignment that will |
// be treated as an initialization block. Benchmarks show that |
@@ -202,7 +204,21 @@ class Parser { |
Expression* ParseObjectLiteral(bool* ok); |
Expression* ParseRegExpLiteral(bool seen_equal, bool* ok); |
- // Decide if a property should be the object boilerplate. |
+ // Populate the constant properties fixed array for a materialized object |
+ // literal. |
+ void BuildObjectLiteralConstantProperties( |
+ ZoneList<ObjectLiteral::Property*>* properties, |
+ Handle<FixedArray> constants, |
+ bool* is_simple_out, |
Mads Ager (chromium)
2010/02/01 08:42:19
Remove the _out prefix on these out params?
Lasse Reichstein
2010/02/01 12:17:30
Done.
|
+ int* depth_out); |
+ |
+ // Populate the literals fixed array for a materialized array literal. |
+ void BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* properties, |
+ Handle<FixedArray> constants, |
+ bool* is_simple_out, |
Mads Ager (chromium)
2010/02/01 08:42:19
Remove _out on these as well?
Lasse Reichstein
2010/02/01 12:17:30
Done, too.
|
+ int* depth_out); |
+ |
+ // Decide if a property should be in the object boilerplate. |
bool IsBoilerplateProperty(ObjectLiteral::Property* property); |
// If the expression is a literal, return the literal value; |
// if the expression is a materialized literal and is simple return a |
@@ -231,6 +247,7 @@ class Parser { |
INLINE(Token::Value Next()) { return scanner_.Next(); } |
INLINE(void Consume(Token::Value token)); |
void Expect(Token::Value token, bool* ok); |
+ bool Check(Token::Value token); |
void ExpectSemicolon(bool* ok); |
// Get odd-ball literals. |
@@ -277,6 +294,12 @@ class Parser { |
Handle<String> type, |
Vector< Handle<Object> > arguments); |
+ // Parse JSON expressions and sub-expressions. |
+ Expression* ParseJson(bool* ok); |
+ Expression* ParseJsonValue(bool* ok); |
+ Expression* ParseJsonObject(bool* ok); |
+ Expression* ParseJsonArray(bool* ok); |
+ |
friend class Target; |
friend class TargetScope; |
friend class LexicalScope; |
@@ -983,7 +1006,7 @@ class AstBuildingParser : public Parser { |
public: |
AstBuildingParser(Handle<Script> script, bool allow_natives_syntax, |
v8::Extension* extension, ScriptDataImpl* pre_data) |
- : Parser(script, allow_natives_syntax, extension, false, |
+ : Parser(script, allow_natives_syntax, extension, PARSE, |
factory(), log(), pre_data) { } |
virtual void ReportMessageAt(Scanner::Location loc, const char* message, |
Vector<const char*> args); |
@@ -1002,9 +1025,9 @@ class PreParser : public Parser { |
public: |
PreParser(Handle<Script> script, bool allow_natives_syntax, |
v8::Extension* extension) |
- : Parser(script, allow_natives_syntax, extension, true, |
- factory(), recorder(), NULL) |
- , factory_(true) { } |
+ : Parser(script, allow_natives_syntax, extension, PREPARSE, |
+ factory(), recorder(), NULL), |
+ factory_(true) { } |
virtual void ReportMessageAt(Scanner::Location loc, const char* message, |
Vector<const char*> args); |
virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, |
@@ -1147,7 +1170,7 @@ class LexicalScope BASE_EMBEDDED { |
Parser::Parser(Handle<Script> script, |
bool allow_natives_syntax, |
v8::Extension* extension, |
- bool is_pre_parsing, |
+ ParserMode is_pre_parsing, |
ParserFactory* factory, |
ParserLog* log, |
ScriptDataImpl* pre_data) |
@@ -1161,7 +1184,7 @@ Parser::Parser(Handle<Script> script, |
extension_(extension), |
factory_(factory), |
log_(log), |
- is_pre_parsing_(is_pre_parsing), |
+ is_pre_parsing_(is_pre_parsing == PREPARSE), |
pre_data_(pre_data) { |
} |
@@ -1172,7 +1195,7 @@ bool Parser::PreParseProgram(Handle<String> source, |
AssertNoZoneAllocation assert_no_zone_allocation; |
AssertNoAllocation assert_no_allocation; |
NoHandleAllocation no_handle_allocation; |
- scanner_.Init(source, stream, 0); |
+ scanner_.Init(source, stream, 0, JAVASCRIPT); |
ASSERT(target_stack_ == NULL); |
mode_ = PARSE_EAGERLY; |
DummyScope top_scope; |
@@ -1195,7 +1218,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, |
// Initialize parser state. |
source->TryFlattenIfNotFlat(); |
- scanner_.Init(source, stream, 0); |
+ scanner_.Init(source, stream, 0, JAVASCRIPT); |
ASSERT(target_stack_ == NULL); |
// Compute the parsing mode. |
@@ -1254,7 +1277,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source, |
SafeStringInputBuffer buffer(source.location()); |
// Initialize parser state. |
- scanner_.Init(source, &buffer, start_position); |
+ scanner_.Init(source, &buffer, start_position, JAVASCRIPT); |
ASSERT(target_stack_ == NULL); |
mode_ = PARSE_EAGERLY; |
@@ -1290,6 +1313,55 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source, |
return result; |
} |
+FunctionLiteral* Parser::ParseJson(Handle<String> source, |
+ unibrow::CharacterStream* stream) { |
+ CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); |
+ |
+ HistogramTimerScope timer(&Counters::parse); |
+ Counters::total_parse_size.Increment(source->length()); |
+ |
+ // Initialize parser state. |
+ source->TryFlattenIfNotFlat(); |
+ scanner_.Init(source, stream, 0, 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)); |
+ } 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(); |
@@ -3122,7 +3194,7 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { |
void Parser::ReportUnexpectedToken(Token::Value token) { |
// We don't report stack overflows here, to avoid increasing the |
// stack depth even further. Instead we report it after parsing is |
- // over, in ParseProgram. |
+ // over, in ParseProgram/ParseJson. |
if (token == Token::ILLEGAL && scanner().stack_overflow()) |
return; |
// Four of the tokens are treated specially |
@@ -3454,32 +3526,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
Handle<FixedArray> constant_properties = |
Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED); |
- int position = 0; |
+ |
bool is_simple = true; |
int depth = 1; |
- for (int i = 0; i < properties.length(); i++) { |
- ObjectLiteral::Property* property = properties.at(i); |
- if (!IsBoilerplateProperty(property)) { |
- is_simple = false; |
- continue; |
- } |
- MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); |
- if (m_literal != NULL && m_literal->depth() + 1 > depth) { |
- depth = m_literal->depth() + 1; |
- } |
- |
- // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined |
- // value for COMPUTED properties, the real value is filled in at |
- // runtime. The enumeration order is maintained. |
- Handle<Object> key = property->key()->handle(); |
- Handle<Object> value = GetBoilerplateValue(property->value()); |
- is_simple = is_simple && !value->IsUndefined(); |
- |
- // Add name, value pair to the fixed array. |
- constant_properties->set(position++, *key); |
- constant_properties->set(position++, *value); |
- } |
- |
+ BuildObjectLiteralConstantProperties(properties.elements(), |
+ constant_properties, |
+ &is_simple, |
+ &depth); |
return new ObjectLiteral(constant_properties, |
properties.elements(), |
literal_index, |
@@ -3720,6 +3773,16 @@ void Parser::Expect(Token::Value token, bool* ok) { |
} |
+bool Parser::Check(Token::Value token) { |
+ Token::Value next = peek(); |
+ if (next == token) { |
+ Consume(next); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
void Parser::ExpectSemicolon(bool* ok) { |
// Check for automatic semicolon insertion according to |
// the rules given in ECMA-262, section 7.9, page 21. |
@@ -3886,6 +3949,207 @@ Expression* Parser::NewThrowError(Handle<String> constructor, |
scanner().location().beg_pos); |
} |
+// ---------------------------------------------------------------------------- |
+// JSON |
+ |
+void Parser::BuildObjectLiteralConstantProperties( |
Mads Ager (chromium)
2010/02/01 08:42:19
This is used for normal parsing of object literals
Lasse Reichstein
2010/02/01 12:17:30
Done.
|
+ ZoneList<ObjectLiteral::Property*>* properties, |
+ Handle<FixedArray> constant_properties, |
+ bool* is_simple_out, |
+ int* depth_out) { |
+ int position = 0; |
+ bool is_simple = true; |
+ int depth = 1; |
+ for (int i = 0; i < properties->length(); i++) { |
+ ObjectLiteral::Property* property = properties->at(i); |
+ if (!IsBoilerplateProperty(property)) { |
+ is_simple = false; |
+ continue; |
+ } |
+ MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); |
+ if (m_literal != NULL && m_literal->depth() + 1 > depth) { |
+ depth = m_literal->depth() + 1; |
+ } |
+ |
+ // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined |
+ // value for COMPUTED properties, the real value is filled in at |
+ // runtime. The enumeration order is maintained. |
+ Handle<Object> key = property->key()->handle(); |
+ Handle<Object> value = GetBoilerplateValue(property->value()); |
+ is_simple = is_simple && !value->IsUndefined(); |
+ |
+ // Add name, value pair to the fixed array. |
+ constant_properties->set(position++, *key); |
+ constant_properties->set(position++, *value); |
+ } |
+ |
+ *is_simple_out = is_simple; |
+ *depth_out = depth; |
+} |
+ |
+ |
+Expression* Parser::ParseJson(bool* ok) { |
+ Expression* result = ParseJsonValue(CHECK_OK); |
+ Expect(Token::EOS, CHECK_OK); |
+ return result; |
+} |
+ |
+ |
+// Parse any JSON value. |
+Expression* Parser::ParseJsonValue(bool* ok) { |
+ Token::Value token = peek(); |
+ 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))); |
+ } |
+ case Token::NUMBER: { |
+ Consume(Token::NUMBER); |
+ ASSERT(scanner_.literal_length() > 0); |
+ double value = StringToDouble(scanner_.literal_string(), |
+ NO_FLAGS, // Hex, octal or trailing junk. |
+ OS::nan_value()); |
+ return NewNumberLiteral(value); |
+ } |
+ case Token::FALSE_LITERAL: |
+ Consume(Token::FALSE_LITERAL); |
+ return NEW(Literal(Factory::false_value())); |
+ case Token::TRUE_LITERAL: |
+ Consume(Token::TRUE_LITERAL); |
+ return NEW(Literal(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; |
+ } |
+ default: |
+ *ok = false; |
+ ReportUnexpectedToken(token); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+// 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) { |
+ do { |
+ Expect(Token::STRING, CHECK_OK); |
+ Handle<String> key = factory()->LookupSymbol(scanner_.literal_string(), |
+ scanner_.literal_length()); |
+ Expect(Token::COLON, CHECK_OK); |
+ Expression* value = ParseJsonValue(CHECK_OK); |
+ Literal* key_literal; |
+ uint32_t index; |
+ if (key->AsArrayIndex(&index)) { |
+ key_literal = NewNumberLiteral(index); |
+ } else { |
+ key_literal = NEW(Literal(key)); |
+ } |
+ ObjectLiteral::Property* property = |
+ NEW(ObjectLiteral::Property(key_literal, value)); |
+ properties.Add(property); |
+ |
+ if (IsBoilerplateProperty(property)) { |
+ boilerplate_properties++; |
+ } |
+ } while (Check(Token::COMMA)); |
+ } |
+ 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; |
+ int depth = 1; |
+ BuildObjectLiteralConstantProperties(properties.elements(), |
+ constant_properties, |
+ &is_simple, |
+ &depth); |
+ return new ObjectLiteral(constant_properties, |
+ properties.elements(), |
+ literal_index, |
+ is_simple, |
+ depth); |
+} |
+ |
+ |
+void Parser::BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* values, |
+ Handle<FixedArray> literals, |
+ bool* is_simple_out, |
+ int* depth_out) { |
+ // Fill in the literals. |
+ bool is_simple = true; |
+ int depth = 1; |
+ for (int i = 0; i < values->length(); i++) { |
+ MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral(); |
+ if (m_literal != NULL && m_literal->depth() + 1 > depth) { |
+ depth = m_literal->depth() + 1; |
+ } |
+ Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i)); |
+ if (boilerplate_value->IsUndefined()) { |
+ literals->set_the_hole(i); |
+ is_simple = false; |
+ } else { |
+ literals->set(i, *boilerplate_value); |
+ } |
+ } |
+ |
+ *is_simple_out = is_simple; |
+ *depth_out = depth; |
+} |
+ |
+ |
+// Parse a JSON object. Scanner must be right after '[' token. |
+Expression* Parser::ParseJsonArray(bool* ok) { |
+ Consume(Token::LBRACK); |
+ |
+ ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4); |
+ if (peek() != Token::RBRACK) { |
+ do { |
+ Expression* exp = ParseJsonValue(CHECK_OK); |
+ values.Add(exp); |
+ } while (Check(Token::COMMA)); |
+ } |
+ Expect(Token::RBRACK, CHECK_OK); |
+ |
+ // Update the scope information before the pre-parsing bailout. |
+ int literal_index = temp_scope_->NextMaterializedLiteralIndex(); |
+ |
+ if (is_pre_parsing_) return NULL; |
+ |
+ // 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)); |
+} |
+ |
// ---------------------------------------------------------------------------- |
// Regular expressions |
@@ -4761,7 +5025,8 @@ bool ParseRegExp(FlatStringReader* input, |
FunctionLiteral* MakeAST(bool compile_in_global_context, |
Handle<Script> script, |
v8::Extension* extension, |
- ScriptDataImpl* pre_data) { |
+ ScriptDataImpl* pre_data, |
+ bool is_json) { |
bool allow_natives_syntax = |
always_allow_natives_syntax || |
FLAG_allow_natives_syntax || |
@@ -4773,15 +5038,21 @@ FunctionLiteral* MakeAST(bool compile_in_global_context, |
Vector<const char*> args = pre_data->BuildArgs(); |
parser.ReportMessageAt(loc, message, args); |
DeleteArray(message); |
- for (int i = 0; i < args.length(); i++) |
+ for (int i = 0; i < args.length(); i++) { |
DeleteArray(args[i]); |
+ } |
DeleteArray(args.start()); |
return NULL; |
} |
Handle<String> source = Handle<String>(String::cast(script->source())); |
SafeStringInputBuffer input(source.location()); |
- FunctionLiteral* result = parser.ParseProgram(source, |
- &input, compile_in_global_context); |
+ FunctionLiteral* result; |
+ if (is_json) { |
+ ASSERT(compile_in_global_context); |
+ result = parser.ParseJson(source, &input); |
+ } else { |
+ result = parser.ParseProgram(source, &input, compile_in_global_context); |
+ } |
return result; |
} |