Chromium Code Reviews| 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; |
| } |