Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(520)

Side by Side Diff: src/parsing/parser.cc

Issue 2481163002: Assign unique IDs to FunctionLiterals (Closed)
Patch Set: updates Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/parsing/parser.h" 5 #include "src/parsing/parser.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "src/api.h" 9 #include "src/api.h"
10 #include "src/ast/ast-expression-rewriter.h" 10 #include "src/ast/ast-expression-rewriter.h"
11 #include "src/ast/ast-function-literal-id-reindexer.h"
11 #include "src/ast/ast-literal-reindexer.h" 12 #include "src/ast/ast-literal-reindexer.h"
12 #include "src/ast/ast-traversal-visitor.h" 13 #include "src/ast/ast-traversal-visitor.h"
13 #include "src/ast/ast.h" 14 #include "src/ast/ast.h"
14 #include "src/bailout-reason.h" 15 #include "src/bailout-reason.h"
15 #include "src/base/platform/platform.h" 16 #include "src/base/platform/platform.h"
16 #include "src/char-predicates-inl.h" 17 #include "src/char-predicates-inl.h"
17 #include "src/messages.h" 18 #include "src/messages.h"
18 #include "src/parsing/duplicate-finder.h" 19 #include "src/parsing/duplicate-finder.h"
19 #include "src/parsing/parameter-initializer-rewriter.h" 20 #include "src/parsing/parameter-initializer-rewriter.h"
20 #include "src/parsing/parse-info.h" 21 #include "src/parsing/parse-info.h"
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 284
284 materialized_literal_count = function_state.materialized_literal_count(); 285 materialized_literal_count = function_state.materialized_literal_count();
285 expected_property_count = function_state.expected_property_count(); 286 expected_property_count = function_state.expected_property_count();
286 } 287 }
287 288
288 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( 289 FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
289 name, function_scope, body, materialized_literal_count, 290 name, function_scope, body, materialized_literal_count,
290 expected_property_count, parameter_count, parameter_count, 291 expected_property_count, parameter_count, parameter_count,
291 FunctionLiteral::kNoDuplicateParameters, 292 FunctionLiteral::kNoDuplicateParameters,
292 FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, 293 FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos,
293 true); 294 true, GetNextFunctionLiteralId());
294 295
295 function_literal->set_requires_class_field_init(requires_class_field_init); 296 function_literal->set_requires_class_field_init(requires_class_field_init);
296 297
297 return function_literal; 298 return function_literal;
298 } 299 }
299 300
300 // ---------------------------------------------------------------------------- 301 // ----------------------------------------------------------------------------
301 // The CHECK_OK macro is a convenient macro to enforce error 302 // The CHECK_OK macro is a convenient macro to enforce error
302 // handling for functions that may fail (by returning !*ok). 303 // handling for functions that may fail (by returning !*ok).
303 // 304 //
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 738
738 739
739 FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { 740 FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
740 // Note that this function can be called from the main thread or from a 741 // Note that this function can be called from the main thread or from a
741 // background thread. We should not access anything Isolate / heap dependent 742 // background thread. We should not access anything Isolate / heap dependent
742 // via ParseInfo, and also not pass it forward. 743 // via ParseInfo, and also not pass it forward.
743 DCHECK_NULL(scope_state_); 744 DCHECK_NULL(scope_state_);
744 DCHECK_NULL(target_stack_); 745 DCHECK_NULL(target_stack_);
745 746
746 ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY); 747 ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
748 ResetFunctionLiteralId();
749 DCHECK(info->function_literal_id() == FunctionLiteral::kIdTypeTopLevel ||
750 info->function_literal_id() == FunctionLiteral::kIdTypeInvalid);
747 751
748 FunctionLiteral* result = NULL; 752 FunctionLiteral* result = NULL;
749 { 753 {
750 Scope* outer = original_scope_; 754 Scope* outer = original_scope_;
751 DCHECK_NOT_NULL(outer); 755 DCHECK_NOT_NULL(outer);
752 parsing_module_ = info->is_module(); 756 parsing_module_ = info->is_module();
753 if (info->is_eval()) { 757 if (info->is_eval()) {
754 outer = NewEvalScope(outer); 758 outer = NewEvalScope(outer);
755 } else if (parsing_module_) { 759 } else if (parsing_module_) {
756 DCHECK_EQ(outer, info->script_scope()); 760 DCHECK_EQ(outer, info->script_scope());
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 const AstRawString* raw_name, 901 const AstRawString* raw_name,
898 Utf16CharacterStream* source) { 902 Utf16CharacterStream* source) {
899 scanner_.Initialize(source); 903 scanner_.Initialize(source);
900 DCHECK_NULL(scope_state_); 904 DCHECK_NULL(scope_state_);
901 DCHECK_NULL(target_stack_); 905 DCHECK_NULL(target_stack_);
902 906
903 DCHECK(ast_value_factory()); 907 DCHECK(ast_value_factory());
904 fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); 908 fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
905 fni_->PushEnclosingName(raw_name); 909 fni_->PushEnclosingName(raw_name);
906 910
911 ResetFunctionLiteralId();
912 DCHECK_LT(0, info->function_literal_id());
913 SkipFunctionLiterals(info->function_literal_id() - 1);
914
907 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); 915 ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
908 916
909 // Place holder for the result. 917 // Place holder for the result.
910 FunctionLiteral* result = nullptr; 918 FunctionLiteral* result = nullptr;
911 919
912 { 920 {
913 // Parse the function literal. 921 // Parse the function literal.
914 Scope* outer = original_scope_; 922 Scope* outer = original_scope_;
915 DeclarationScope* outer_function = outer->GetClosureScope(); 923 DeclarationScope* outer_function = outer->GetClosureScope();
916 DCHECK(outer); 924 DCHECK(outer);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
963 if (ok) ok = Check(Token::RPAREN); 971 if (ok) ok = Check(Token::RPAREN);
964 } else { 972 } else {
965 // BindingIdentifier 973 // BindingIdentifier
966 ParseFormalParameter(&formals, &ok); 974 ParseFormalParameter(&formals, &ok);
967 if (ok) DeclareFormalParameter(formals.scope, formals.at(0)); 975 if (ok) DeclareFormalParameter(formals.scope, formals.at(0));
968 } 976 }
969 } 977 }
970 978
971 if (ok) { 979 if (ok) {
972 checkpoint.Restore(&formals.materialized_literals_count); 980 checkpoint.Restore(&formals.materialized_literals_count);
981 if (GetLastFunctionLiteralId() != info->function_literal_id() - 1) {
982 // If there were FunctionLiterals in the parameters, we need to
983 // renumber them to shift down so the next function literal id for
984 // the arrow function is the one requested.
985 AstFunctionLiteralIdReindexer reindexer(
986 stack_limit_,
987 (info->function_literal_id() - 1) - GetLastFunctionLiteralId());
988 for (const auto p : formals.params) {
989 if (p.pattern != nullptr) reindexer.Reindex(p.pattern);
990 if (p.initializer != nullptr) reindexer.Reindex(p.initializer);
991 }
992 ResetFunctionLiteralId();
993 SkipFunctionLiterals(info->function_literal_id() - 1);
994 }
995
973 // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should 996 // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
974 // not be observable, or else the preparser would have failed. 997 // not be observable, or else the preparser would have failed.
975 Expression* expression = ParseArrowFunctionLiteral(true, formals, &ok); 998 Expression* expression = ParseArrowFunctionLiteral(true, formals, &ok);
976 if (ok) { 999 if (ok) {
977 // Scanning must end at the same position that was recorded 1000 // Scanning must end at the same position that was recorded
978 // previously. If not, parsing has been interrupted due to a stack 1001 // previously. If not, parsing has been interrupted due to a stack
979 // overflow, at which point the partially parsed arrow function 1002 // overflow, at which point the partially parsed arrow function
980 // concise body happens to be a valid expression. This is a problem 1003 // concise body happens to be a valid expression. This is a problem
981 // only for arrow functions with single expression bodies, since there 1004 // only for arrow functions with single expression bodies, since there
982 // is no end token such as "}" for normal functions. 1005 // is no end token such as "}" for normal functions.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 if (info->requires_class_field_init()) { 1038 if (info->requires_class_field_init()) {
1016 result = InsertClassFieldInitializer(result); 1039 result = InsertClassFieldInitializer(result);
1017 } 1040 }
1018 } 1041 }
1019 // Make sure the results agree. 1042 // Make sure the results agree.
1020 DCHECK(ok == (result != nullptr)); 1043 DCHECK(ok == (result != nullptr));
1021 } 1044 }
1022 1045
1023 // Make sure the target stack is empty. 1046 // Make sure the target stack is empty.
1024 DCHECK_NULL(target_stack_); 1047 DCHECK_NULL(target_stack_);
1048 DCHECK_IMPLIES(result,
1049 info->function_literal_id() == result->function_literal_id());
1025 return result; 1050 return result;
1026 } 1051 }
1027 1052
1028 Statement* Parser::ParseModuleItem(bool* ok) { 1053 Statement* Parser::ParseModuleItem(bool* ok) {
1029 // ecma262/#prod-ModuleItem 1054 // ecma262/#prod-ModuleItem
1030 // ModuleItem : 1055 // ModuleItem :
1031 // ImportDeclaration 1056 // ImportDeclaration
1032 // ExportDeclaration 1057 // ExportDeclaration
1033 // StatementListItem 1058 // StatementListItem
1034 1059
(...skipping 1591 matching lines...) Expand 10 before | Expand all | Expand 10 after
2626 bool is_lazy_inner_function = 2651 bool is_lazy_inner_function =
2627 use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function; 2652 use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function;
2628 2653
2629 ZoneList<Statement*>* body = nullptr; 2654 ZoneList<Statement*>* body = nullptr;
2630 int materialized_literal_count = -1; 2655 int materialized_literal_count = -1;
2631 int expected_property_count = -1; 2656 int expected_property_count = -1;
2632 bool should_be_used_once_hint = false; 2657 bool should_be_used_once_hint = false;
2633 int num_parameters = -1; 2658 int num_parameters = -1;
2634 int function_length = -1; 2659 int function_length = -1;
2635 bool has_duplicate_parameters = false; 2660 bool has_duplicate_parameters = false;
2661 int function_literal_id = GetNextFunctionLiteralId();
2636 2662
2637 Zone* outer_zone = zone(); 2663 Zone* outer_zone = zone();
2638 DeclarationScope* scope; 2664 DeclarationScope* scope;
2639 2665
2640 { 2666 {
2641 // Temporary zones can nest. When we migrate free variables (see below), we 2667 // Temporary zones can nest. When we migrate free variables (see below), we
2642 // need to recreate them in the previous Zone. 2668 // need to recreate them in the previous Zone.
2643 AstNodeFactory previous_zone_ast_node_factory(ast_value_factory()); 2669 AstNodeFactory previous_zone_ast_node_factory(ast_value_factory());
2644 previous_zone_ast_node_factory.set_zone(zone()); 2670 previous_zone_ast_node_factory.set_zone(zone());
2645 2671
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
2742 } // DiscardableZoneScope goes out of scope. 2768 } // DiscardableZoneScope goes out of scope.
2743 2769
2744 FunctionLiteral::ParameterFlag duplicate_parameters = 2770 FunctionLiteral::ParameterFlag duplicate_parameters =
2745 has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters 2771 has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
2746 : FunctionLiteral::kNoDuplicateParameters; 2772 : FunctionLiteral::kNoDuplicateParameters;
2747 2773
2748 // Note that the FunctionLiteral needs to be created in the main Zone again. 2774 // Note that the FunctionLiteral needs to be created in the main Zone again.
2749 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( 2775 FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
2750 function_name, scope, body, materialized_literal_count, 2776 function_name, scope, body, materialized_literal_count,
2751 expected_property_count, num_parameters, function_length, 2777 expected_property_count, num_parameters, function_length,
2752 duplicate_parameters, function_type, eager_compile_hint, pos, true); 2778 duplicate_parameters, function_type, eager_compile_hint, pos, true,
2779 function_literal_id);
2753 function_literal->set_function_token_position(function_token_pos); 2780 function_literal->set_function_token_position(function_token_pos);
2754 if (should_be_used_once_hint) 2781 if (should_be_used_once_hint)
2755 function_literal->set_should_be_used_once_hint(); 2782 function_literal->set_should_be_used_once_hint();
2756 2783
2757 if (should_infer_name) { 2784 if (should_infer_name) {
2758 DCHECK_NOT_NULL(fni_); 2785 DCHECK_NOT_NULL(fni_);
2759 fni_->AddFunction(function_literal); 2786 fni_->AddFunction(function_literal);
2760 } 2787 }
2761 return function_literal; 2788 return function_literal;
2762 } 2789 }
(...skipping 27 matching lines...) Expand all
2790 Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); 2817 Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
2791 *num_parameters = entry.num_parameters(); 2818 *num_parameters = entry.num_parameters();
2792 *function_length = entry.function_length(); 2819 *function_length = entry.function_length();
2793 *has_duplicate_parameters = entry.has_duplicate_parameters(); 2820 *has_duplicate_parameters = entry.has_duplicate_parameters();
2794 *materialized_literal_count = entry.literal_count(); 2821 *materialized_literal_count = entry.literal_count();
2795 *expected_property_count = entry.property_count(); 2822 *expected_property_count = entry.property_count();
2796 SetLanguageMode(function_scope, entry.language_mode()); 2823 SetLanguageMode(function_scope, entry.language_mode());
2797 if (entry.uses_super_property()) 2824 if (entry.uses_super_property())
2798 function_scope->RecordSuperPropertyUsage(); 2825 function_scope->RecordSuperPropertyUsage();
2799 if (entry.calls_eval()) function_scope->RecordEvalCall(); 2826 if (entry.calls_eval()) function_scope->RecordEvalCall();
2827 SkipFunctionLiterals(entry.num_inner_functions());
2800 return kLazyParsingComplete; 2828 return kLazyParsingComplete;
2801 } 2829 }
2802 cached_parse_data_->Reject(); 2830 cached_parse_data_->Reject();
2803 } 2831 }
2804 2832
2805 // With no cached data, we partially parse the function, without building an 2833 // With no cached data, we partially parse the function, without building an
2806 // AST. This gathers the data needed to build a lazy function. 2834 // AST. This gathers the data needed to build a lazy function.
2807 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse"); 2835 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
2808 2836
2809 if (reusable_preparser_ == NULL) { 2837 if (reusable_preparser_ == NULL) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2842 PreParserLogger* logger = reusable_preparser_->logger(); 2870 PreParserLogger* logger = reusable_preparser_->logger();
2843 function_scope->set_end_position(logger->end()); 2871 function_scope->set_end_position(logger->end());
2844 Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); 2872 Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
2845 total_preparse_skipped_ += 2873 total_preparse_skipped_ +=
2846 function_scope->end_position() - function_scope->start_position(); 2874 function_scope->end_position() - function_scope->start_position();
2847 *num_parameters = logger->num_parameters(); 2875 *num_parameters = logger->num_parameters();
2848 *function_length = logger->function_length(); 2876 *function_length = logger->function_length();
2849 *has_duplicate_parameters = logger->has_duplicate_parameters(); 2877 *has_duplicate_parameters = logger->has_duplicate_parameters();
2850 *materialized_literal_count = logger->literals(); 2878 *materialized_literal_count = logger->literals();
2851 *expected_property_count = logger->properties(); 2879 *expected_property_count = logger->properties();
2880 SkipFunctionLiterals(logger->num_inner_functions());
2852 if (!is_inner_function && produce_cached_parse_data()) { 2881 if (!is_inner_function && produce_cached_parse_data()) {
2853 DCHECK(log_); 2882 DCHECK(log_);
2854 log_->LogFunction( 2883 log_->LogFunction(
2855 function_scope->start_position(), function_scope->end_position(), 2884 function_scope->start_position(), function_scope->end_position(),
2856 *num_parameters, *function_length, *has_duplicate_parameters, 2885 *num_parameters, *function_length, *has_duplicate_parameters,
2857 *materialized_literal_count, *expected_property_count, language_mode(), 2886 *materialized_literal_count, *expected_property_count, language_mode(),
2858 function_scope->uses_super_property(), function_scope->calls_eval()); 2887 function_scope->uses_super_property(), function_scope->calls_eval(),
2888 logger->num_inner_functions());
2859 } 2889 }
2860 return kLazyParsingComplete; 2890 return kLazyParsingComplete;
2861 } 2891 }
2862 2892
2863 2893
2864 Statement* Parser::BuildAssertIsCoercible(Variable* var) { 2894 Statement* Parser::BuildAssertIsCoercible(Variable* var) {
2865 // if (var === null || var === undefined) 2895 // if (var === null || var === undefined)
2866 // throw /* type error kNonCoercible) */; 2896 // throw /* type error kNonCoercible) */;
2867 2897
2868 Expression* condition = factory()->NewBinaryOperation( 2898 Expression* condition = factory()->NewBinaryOperation(
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after
3428 body->Add(factory()->NewReturnStatement(ThisExpression(kNoSourcePosition), 3458 body->Add(factory()->NewReturnStatement(ThisExpression(kNoSourcePosition),
3429 kNoSourcePosition), 3459 kNoSourcePosition),
3430 zone()); 3460 zone());
3431 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( 3461 FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
3432 ast_value_factory()->empty_string(), initializer_scope, body, 3462 ast_value_factory()->empty_string(), initializer_scope, body,
3433 initializer_state.materialized_literal_count(), 3463 initializer_state.materialized_literal_count(),
3434 initializer_state.expected_property_count(), 0, count, 3464 initializer_state.expected_property_count(), 0, count,
3435 FunctionLiteral::kNoDuplicateParameters, 3465 FunctionLiteral::kNoDuplicateParameters,
3436 FunctionLiteral::kAnonymousExpression, 3466 FunctionLiteral::kAnonymousExpression,
3437 FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position(), 3467 FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position(),
3438 true); 3468 true, GetNextFunctionLiteralId());
3439 function_literal->set_is_class_field_initializer(true); 3469 function_literal->set_is_class_field_initializer(true);
3440 return function_literal; 3470 return function_literal;
3441 } 3471 }
3442 3472
3443 FunctionLiteral* Parser::InsertClassFieldInitializer( 3473 FunctionLiteral* Parser::InsertClassFieldInitializer(
3444 FunctionLiteral* constructor) { 3474 FunctionLiteral* constructor) {
3445 Statement* call_initializer = factory()->NewExpressionStatement( 3475 Statement* call_initializer = factory()->NewExpressionStatement(
3446 CallClassFieldInitializer( 3476 CallClassFieldInitializer(
3447 constructor->scope(), 3477 constructor->scope(),
3448 constructor->scope()->NewUnresolved( 3478 constructor->scope()->NewUnresolved(
(...skipping 23 matching lines...) Expand all
3472 } 3502 }
3473 3503
3474 // This method declares a property of the given class. It updates the 3504 // This method declares a property of the given class. It updates the
3475 // following fields of class_info, as appropriate: 3505 // following fields of class_info, as appropriate:
3476 // - constructor 3506 // - constructor
3477 // - static_initializer_var 3507 // - static_initializer_var
3478 // - instance_field_initializers 3508 // - instance_field_initializers
3479 // - properties 3509 // - properties
3480 void Parser::DeclareClassProperty(const AstRawString* class_name, 3510 void Parser::DeclareClassProperty(const AstRawString* class_name,
3481 ClassLiteralProperty* property, 3511 ClassLiteralProperty* property,
3512 ClassLiteralProperty::Kind kind,
3513 bool is_static, bool is_constructor,
3482 ClassInfo* class_info, bool* ok) { 3514 ClassInfo* class_info, bool* ok) {
3483 if (class_info->has_seen_constructor && class_info->constructor == nullptr) { 3515 if (is_constructor) {
3516 DCHECK(!class_info->constructor);
3484 class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral(); 3517 class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral();
3485 DCHECK_NOT_NULL(class_info->constructor); 3518 DCHECK_NOT_NULL(class_info->constructor);
3486 class_info->constructor->set_raw_name( 3519 class_info->constructor->set_raw_name(
3487 class_name != nullptr ? class_name 3520 class_name != nullptr ? class_name
3488 : ast_value_factory()->empty_string()); 3521 : ast_value_factory()->empty_string());
3489 return; 3522 return;
3490 } 3523 }
3491 3524
3492 if (property->kind() == ClassLiteralProperty::FIELD) { 3525 if (property->kind() == ClassLiteralProperty::FIELD) {
3493 DCHECK(allow_harmony_class_fields()); 3526 DCHECK(allow_harmony_class_fields());
(...skipping 1978 matching lines...) Expand 10 before | Expand all | Expand 10 after
5472 5505
5473 return final_loop; 5506 return final_loop;
5474 } 5507 }
5475 5508
5476 #undef CHECK_OK 5509 #undef CHECK_OK
5477 #undef CHECK_OK_VOID 5510 #undef CHECK_OK_VOID
5478 #undef CHECK_FAILED 5511 #undef CHECK_FAILED
5479 5512
5480 } // namespace internal 5513 } // namespace internal
5481 } // namespace v8 5514 } // namespace v8
OLDNEW
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | src/parsing/parser-base.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698