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

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

Issue 2267663002: [parser] Apply an adaptation of the CRTP (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@nickie-2263973003-add-const
Patch Set: Formatting Created 4 years, 4 months 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
« no previous file with comments | « no previous file | src/parsing/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #ifndef V8_PARSING_PARSER_H_ 5 #ifndef V8_PARSING_PARSER_H_
6 #define V8_PARSING_PARSER_H_ 6 #define V8_PARSING_PARSER_H_
7 7
8 #include "src/ast/ast.h" 8 #include "src/ast/ast.h"
9 #include "src/ast/scopes.h" 9 #include "src/ast/scopes.h"
10 #include "src/parsing/parser-base.h" 10 #include "src/parsing/parser-base.h"
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 }; 130 };
131 131
132 explicit ParserFormalParameters(DeclarationScope* scope) 132 explicit ParserFormalParameters(DeclarationScope* scope)
133 : FormalParametersBase(scope), params(4, scope->zone()) {} 133 : FormalParametersBase(scope), params(4, scope->zone()) {}
134 ZoneList<Parameter> params; 134 ZoneList<Parameter> params;
135 135
136 int Arity() const { return params.length(); } 136 int Arity() const { return params.length(); }
137 const Parameter& at(int i) const { return params[i]; } 137 const Parameter& at(int i) const { return params[i]; }
138 }; 138 };
139 139
140 template <>
141 class ParserBaseTraits<Parser> {
142 public:
143 typedef ParserBaseTraits<Parser> ParserTraits;
140 144
141 class ParserTraits {
142 public:
143 struct Type { 145 struct Type {
144 // TODO(marja): To be removed. The Traits object should contain all the data
145 // it needs.
146 typedef v8::internal::Parser* Parser;
147
148 typedef Variable GeneratorVariable; 146 typedef Variable GeneratorVariable;
149 147
150 typedef v8::internal::AstProperties AstProperties; 148 typedef v8::internal::AstProperties AstProperties;
151 149
152 typedef v8::internal::ExpressionClassifier<ParserTraits> 150 typedef v8::internal::ExpressionClassifier<ParserTraits>
153 ExpressionClassifier; 151 ExpressionClassifier;
154 152
155 // Return types for traversing functions. 153 // Return types for traversing functions.
156 typedef const AstRawString* Identifier; 154 typedef const AstRawString* Identifier;
157 typedef v8::internal::Expression* Expression; 155 typedef v8::internal::Expression* Expression;
158 typedef Yield* YieldExpression; 156 typedef Yield* YieldExpression;
159 typedef v8::internal::FunctionLiteral* FunctionLiteral; 157 typedef v8::internal::FunctionLiteral* FunctionLiteral;
160 typedef v8::internal::ClassLiteral* ClassLiteral; 158 typedef v8::internal::ClassLiteral* ClassLiteral;
161 typedef v8::internal::Literal* Literal; 159 typedef v8::internal::Literal* Literal;
162 typedef ObjectLiteral::Property* ObjectLiteralProperty; 160 typedef ObjectLiteral::Property* ObjectLiteralProperty;
163 typedef ZoneList<v8::internal::Expression*>* ExpressionList; 161 typedef ZoneList<v8::internal::Expression*>* ExpressionList;
164 typedef ZoneList<ObjectLiteral::Property*>* PropertyList; 162 typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
165 typedef ParserFormalParameters::Parameter FormalParameter; 163 typedef ParserFormalParameters::Parameter FormalParameter;
166 typedef ParserFormalParameters FormalParameters; 164 typedef ParserFormalParameters FormalParameters;
167 typedef ZoneList<v8::internal::Statement*>* StatementList; 165 typedef ZoneList<v8::internal::Statement*>* StatementList;
168 166
169 // For constructing objects returned by the traversing functions. 167 // For constructing objects returned by the traversing functions.
170 typedef AstNodeFactory Factory; 168 typedef AstNodeFactory Factory;
171 }; 169 };
172 170
173 explicit ParserTraits(Parser* parser) : parser_(parser) {} 171 // TODO(nikolaos): The traits methods should not need to call methods
172 // of the implementation object.
173 Parser* delegate() { return reinterpret_cast<Parser*>(this); }
174 const Parser* delegate() const {
175 return reinterpret_cast<const Parser*>(this);
176 }
174 177
175 // Helper functions for recursive descent. 178 // Helper functions for recursive descent.
176 bool IsEval(const AstRawString* identifier) const; 179 bool IsEval(const AstRawString* identifier) const;
177 bool IsArguments(const AstRawString* identifier) const; 180 bool IsArguments(const AstRawString* identifier) const;
178 bool IsEvalOrArguments(const AstRawString* identifier) const; 181 bool IsEvalOrArguments(const AstRawString* identifier) const;
179 bool IsUndefined(const AstRawString* identifier) const; 182 bool IsUndefined(const AstRawString* identifier) const;
180 V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const; 183 V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
181 184
182 // Returns true if the expression is of type "this.foo". 185 // Returns true if the expression is of type "this.foo".
183 static bool IsThisProperty(Expression* expression); 186 static bool IsThisProperty(Expression* expression);
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 bool* ok); 464 bool* ok);
462 465
463 V8_INLINE ZoneList<typename Type::ExpressionClassifier::Error>* 466 V8_INLINE ZoneList<typename Type::ExpressionClassifier::Error>*
464 GetReportedErrorList() const; 467 GetReportedErrorList() const;
465 V8_INLINE Zone* zone() const; 468 V8_INLINE Zone* zone() const;
466 469
467 V8_INLINE ZoneList<Expression*>* GetNonPatternList() const; 470 V8_INLINE ZoneList<Expression*>* GetNonPatternList() const;
468 471
469 V8_INLINE Expression* RewriteYieldStar(Expression* generator, 472 V8_INLINE Expression* RewriteYieldStar(Expression* generator,
470 Expression* expression, int pos); 473 Expression* expression, int pos);
471
472 private:
473 Parser* parser_;
474 }; 474 };
475 475
476 476 class Parser : public ParserBase<Parser> {
477 class Parser : public ParserBase<ParserTraits> {
478 public: 477 public:
479 explicit Parser(ParseInfo* info); 478 explicit Parser(ParseInfo* info);
480 ~Parser() { 479 ~Parser() {
481 delete reusable_preparser_; 480 delete reusable_preparser_;
482 reusable_preparser_ = NULL; 481 reusable_preparser_ = NULL;
483 delete cached_parse_data_; 482 delete cached_parse_data_;
484 cached_parse_data_ = NULL; 483 cached_parse_data_ = NULL;
485 } 484 }
486 485
487 // Parses the source code represented by the compilation info and sets its 486 // Parses the source code represented by the compilation info and sets its
488 // function literal. Returns false (and deallocates any allocated AST 487 // function literal. Returns false (and deallocates any allocated AST
489 // nodes) if parsing failed. 488 // nodes) if parsing failed.
490 static bool ParseStatic(ParseInfo* info); 489 static bool ParseStatic(ParseInfo* info);
491 bool Parse(ParseInfo* info); 490 bool Parse(ParseInfo* info);
492 void ParseOnBackground(ParseInfo* info); 491 void ParseOnBackground(ParseInfo* info);
493 492
494 void DeserializeScopeChain(ParseInfo* info, Handle<Context> context, 493 void DeserializeScopeChain(ParseInfo* info, Handle<Context> context,
495 Scope::DeserializationMode deserialization_mode); 494 Scope::DeserializationMode deserialization_mode);
496 495
497 // Handle errors detected during parsing, move statistics to Isolate, 496 // Handle errors detected during parsing, move statistics to Isolate,
498 // internalize strings (move them to the heap). 497 // internalize strings (move them to the heap).
499 void Internalize(Isolate* isolate, Handle<Script> script, bool error); 498 void Internalize(Isolate* isolate, Handle<Script> script, bool error);
500 void HandleSourceURLComments(Isolate* isolate, Handle<Script> script); 499 void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
501 500
502 private: 501 private:
503 friend class ParserTraits; 502 // TODO(nikolaos): This should not be necessary. It will be removed
503 // when the traits object stops delegating to the implementation object.
504 friend class ParserBaseTraits<Parser>;
504 505
505 // Runtime encoding of different completion modes. 506 // Runtime encoding of different completion modes.
506 enum CompletionKind { 507 enum CompletionKind {
507 kNormalCompletion, 508 kNormalCompletion,
508 kThrowCompletion, 509 kThrowCompletion,
509 kAbruptCompletion 510 kAbruptCompletion
510 }; 511 };
511 512
512 enum class FunctionBodyType { kNormal, kSingleExpression }; 513 enum class FunctionBodyType { kNormal, kSingleExpression };
513 514
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 int total_preparse_skipped_; 956 int total_preparse_skipped_;
956 HistogramTimer* pre_parse_timer_; 957 HistogramTimer* pre_parse_timer_;
957 958
958 bool parsing_on_main_thread_; 959 bool parsing_on_main_thread_;
959 960
960 #ifdef DEBUG 961 #ifdef DEBUG
961 void Print(AstNode* node); 962 void Print(AstNode* node);
962 #endif // DEBUG 963 #endif // DEBUG
963 }; 964 };
964 965
965 966 bool ParserBaseTraits<Parser>::IsFutureStrictReserved(
966 bool ParserTraits::IsFutureStrictReserved(
967 const AstRawString* identifier) const { 967 const AstRawString* identifier) const {
968 return parser_->scanner()->IdentifierIsFutureStrictReserved(identifier); 968 return delegate()->scanner()->IdentifierIsFutureStrictReserved(identifier);
969 } 969 }
970 970
971 const AstRawString* ParserTraits::EmptyIdentifierString() const { 971 const AstRawString* ParserBaseTraits<Parser>::EmptyIdentifierString() const {
972 return parser_->ast_value_factory()->empty_string(); 972 return delegate()->ast_value_factory()->empty_string();
973 }
974
975 void ParserBaseTraits<Parser>::SkipLazyFunctionBody(
976 int* materialized_literal_count, int* expected_property_count, bool* ok,
977 Scanner::BookmarkScope* bookmark) {
978 return delegate()->SkipLazyFunctionBody(
979 materialized_literal_count, expected_property_count, ok, bookmark);
980 }
981
982 ZoneList<Statement*>* ParserBaseTraits<Parser>::ParseEagerFunctionBody(
983 const AstRawString* name, int pos, const ParserFormalParameters& parameters,
984 FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) {
985 return delegate()->ParseEagerFunctionBody(name, pos, parameters, kind,
986 function_type, ok);
987 }
988
989 void ParserBaseTraits<Parser>::CheckConflictingVarDeclarations(Scope* scope,
990 bool* ok) {
991 delegate()->CheckConflictingVarDeclarations(scope, ok);
973 } 992 }
974 993
975 994
976 void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
977 int* expected_property_count, bool* ok,
978 Scanner::BookmarkScope* bookmark) {
979 return parser_->SkipLazyFunctionBody(materialized_literal_count,
980 expected_property_count, ok, bookmark);
981 }
982
983
984 ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
985 const AstRawString* name, int pos, const ParserFormalParameters& parameters,
986 FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) {
987 return parser_->ParseEagerFunctionBody(name, pos, parameters, kind,
988 function_type, ok);
989 }
990
991 void ParserTraits::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
992 parser_->CheckConflictingVarDeclarations(scope, ok);
993 }
994
995
996 // Support for handling complex values (array and object literals) that 995 // Support for handling complex values (array and object literals) that
997 // can be fully handled at compile time. 996 // can be fully handled at compile time.
998 class CompileTimeValue: public AllStatic { 997 class CompileTimeValue: public AllStatic {
999 public: 998 public:
1000 enum LiteralType { 999 enum LiteralType {
1001 OBJECT_LITERAL_FAST_ELEMENTS, 1000 OBJECT_LITERAL_FAST_ELEMENTS,
1002 OBJECT_LITERAL_SLOW_ELEMENTS, 1001 OBJECT_LITERAL_SLOW_ELEMENTS,
1003 ARRAY_LITERAL 1002 ARRAY_LITERAL
1004 }; 1003 };
1005 1004
1006 static bool IsCompileTimeValue(Expression* expression); 1005 static bool IsCompileTimeValue(Expression* expression);
1007 1006
1008 // Get the value as a compile time value. 1007 // Get the value as a compile time value.
1009 static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression); 1008 static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression);
1010 1009
1011 // Get the type of a compile time value returned by GetValue(). 1010 // Get the type of a compile time value returned by GetValue().
1012 static LiteralType GetLiteralType(Handle<FixedArray> value); 1011 static LiteralType GetLiteralType(Handle<FixedArray> value);
1013 1012
1014 // Get the elements array of a compile time value returned by GetValue(). 1013 // Get the elements array of a compile time value returned by GetValue().
1015 static Handle<FixedArray> GetElements(Handle<FixedArray> value); 1014 static Handle<FixedArray> GetElements(Handle<FixedArray> value);
1016 1015
1017 private: 1016 private:
1018 static const int kLiteralTypeSlot = 0; 1017 static const int kLiteralTypeSlot = 0;
1019 static const int kElementsSlot = 1; 1018 static const int kElementsSlot = 1;
1020 1019
1021 DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue); 1020 DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
1022 }; 1021 };
1023 1022
1024 1023 ParserBaseTraits<Parser>::TemplateLiteralState
1025 ParserTraits::TemplateLiteralState ParserTraits::OpenTemplateLiteral(int pos) { 1024 ParserBaseTraits<Parser>::OpenTemplateLiteral(int pos) {
1026 return parser_->OpenTemplateLiteral(pos); 1025 return delegate()->OpenTemplateLiteral(pos);
1027 } 1026 }
1028 1027
1029 1028 void ParserBaseTraits<Parser>::AddTemplateSpan(TemplateLiteralState* state,
1030 void ParserTraits::AddTemplateSpan(TemplateLiteralState* state, bool tail) { 1029 bool tail) {
1031 parser_->AddTemplateSpan(state, tail); 1030 delegate()->AddTemplateSpan(state, tail);
1032 } 1031 }
1033 1032
1034 1033 void ParserBaseTraits<Parser>::AddTemplateExpression(
1035 void ParserTraits::AddTemplateExpression(TemplateLiteralState* state, 1034 TemplateLiteralState* state, Expression* expression) {
1036 Expression* expression) { 1035 delegate()->AddTemplateExpression(state, expression);
1037 parser_->AddTemplateExpression(state, expression);
1038 } 1036 }
1039 1037
1040 1038 Expression* ParserBaseTraits<Parser>::CloseTemplateLiteral(
1041 Expression* ParserTraits::CloseTemplateLiteral(TemplateLiteralState* state, 1039 TemplateLiteralState* state, int start, Expression* tag) {
1042 int start, Expression* tag) { 1040 return delegate()->CloseTemplateLiteral(state, start, tag);
1043 return parser_->CloseTemplateLiteral(state, start, tag);
1044 } 1041 }
1045 1042
1046 1043 ZoneList<v8::internal::Expression*>* ParserBaseTraits<
1047 ZoneList<v8::internal::Expression*>* ParserTraits::PrepareSpreadArguments( 1044 Parser>::PrepareSpreadArguments(ZoneList<v8::internal::Expression*>* list) {
1048 ZoneList<v8::internal::Expression*>* list) { 1045 return delegate()->PrepareSpreadArguments(list);
1049 return parser_->PrepareSpreadArguments(list);
1050 } 1046 }
1051 1047
1052 1048 Expression* ParserBaseTraits<Parser>::SpreadCall(
1053 Expression* ParserTraits::SpreadCall(Expression* function, 1049 Expression* function, ZoneList<v8::internal::Expression*>* args, int pos) {
1054 ZoneList<v8::internal::Expression*>* args, 1050 return delegate()->SpreadCall(function, args, pos);
1055 int pos) {
1056 return parser_->SpreadCall(function, args, pos);
1057 } 1051 }
1058 1052
1059 1053 Expression* ParserBaseTraits<Parser>::SpreadCallNew(
1060 Expression* ParserTraits::SpreadCallNew(
1061 Expression* function, ZoneList<v8::internal::Expression*>* args, int pos) { 1054 Expression* function, ZoneList<v8::internal::Expression*>* args, int pos) {
1062 return parser_->SpreadCallNew(function, args, pos); 1055 return delegate()->SpreadCallNew(function, args, pos);
1063 } 1056 }
1064 1057
1065 1058 void ParserBaseTraits<Parser>::AddFormalParameter(
1066 void ParserTraits::AddFormalParameter(ParserFormalParameters* parameters, 1059 ParserFormalParameters* parameters, Expression* pattern,
1067 Expression* pattern, 1060 Expression* initializer, int initializer_end_position, bool is_rest) {
1068 Expression* initializer,
1069 int initializer_end_position,
1070 bool is_rest) {
1071 bool is_simple = pattern->IsVariableProxy() && initializer == nullptr; 1061 bool is_simple = pattern->IsVariableProxy() && initializer == nullptr;
1072 const AstRawString* name = is_simple 1062 const AstRawString* name =
1073 ? pattern->AsVariableProxy()->raw_name() 1063 is_simple ? pattern->AsVariableProxy()->raw_name()
1074 : parser_->ast_value_factory()->empty_string(); 1064 : delegate()->ast_value_factory()->empty_string();
1075 parameters->params.Add( 1065 parameters->params.Add(
1076 ParserFormalParameters::Parameter(name, pattern, initializer, 1066 ParserFormalParameters::Parameter(name, pattern, initializer,
1077 initializer_end_position, is_rest), 1067 initializer_end_position, is_rest),
1078 parameters->scope->zone()); 1068 parameters->scope->zone());
1079 } 1069 }
1080 1070
1081 void ParserTraits::DeclareFormalParameter( 1071 void ParserBaseTraits<Parser>::DeclareFormalParameter(
1082 DeclarationScope* scope, const ParserFormalParameters::Parameter& parameter, 1072 DeclarationScope* scope, const ParserFormalParameters::Parameter& parameter,
1083 Type::ExpressionClassifier* classifier) { 1073 Type::ExpressionClassifier* classifier) {
1084 bool is_duplicate = false; 1074 bool is_duplicate = false;
1085 bool is_simple = classifier->is_simple_parameter_list(); 1075 bool is_simple = classifier->is_simple_parameter_list();
1086 auto name = is_simple || parameter.is_rest 1076 auto name = is_simple || parameter.is_rest
1087 ? parameter.name 1077 ? parameter.name
1088 : parser_->ast_value_factory()->empty_string(); 1078 : delegate()->ast_value_factory()->empty_string();
1089 auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY; 1079 auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY;
1090 if (!is_simple) scope->SetHasNonSimpleParameters(); 1080 if (!is_simple) scope->SetHasNonSimpleParameters();
1091 bool is_optional = parameter.initializer != nullptr; 1081 bool is_optional = parameter.initializer != nullptr;
1092 Variable* var = 1082 Variable* var =
1093 scope->DeclareParameter(name, mode, is_optional, parameter.is_rest, 1083 scope->DeclareParameter(name, mode, is_optional, parameter.is_rest,
1094 &is_duplicate, parser_->ast_value_factory()); 1084 &is_duplicate, delegate()->ast_value_factory());
1095 if (is_duplicate) { 1085 if (is_duplicate) {
1096 classifier->RecordDuplicateFormalParameterError( 1086 classifier->RecordDuplicateFormalParameterError(
1097 parser_->scanner()->location()); 1087 delegate()->scanner()->location());
1098 } 1088 }
1099 if (is_sloppy(scope->language_mode())) { 1089 if (is_sloppy(scope->language_mode())) {
1100 // TODO(sigurds) Mark every parameter as maybe assigned. This is a 1090 // TODO(sigurds) Mark every parameter as maybe assigned. This is a
1101 // conservative approximation necessary to account for parameters 1091 // conservative approximation necessary to account for parameters
1102 // that are assigned via the arguments array. 1092 // that are assigned via the arguments array.
1103 var->set_maybe_assigned(); 1093 var->set_maybe_assigned();
1104 } 1094 }
1105 } 1095 }
1106 1096
1107 void ParserTraits::AddParameterInitializationBlock( 1097 void ParserBaseTraits<Parser>::AddParameterInitializationBlock(
1108 const ParserFormalParameters& parameters, 1098 const ParserFormalParameters& parameters,
1109 ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok) { 1099 ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok) {
1110 if (!parameters.is_simple) { 1100 if (!parameters.is_simple) {
1111 auto* init_block = 1101 auto* init_block =
1112 parser_->BuildParameterInitializationBlock(parameters, ok); 1102 delegate()->BuildParameterInitializationBlock(parameters, ok);
1113 if (!*ok) return; 1103 if (!*ok) return;
1114 1104
1115 if (is_async) { 1105 if (is_async) {
1116 init_block = parser_->BuildRejectPromiseOnException(init_block); 1106 init_block = delegate()->BuildRejectPromiseOnException(init_block);
1117 } 1107 }
1118 1108
1119 if (init_block != nullptr) { 1109 if (init_block != nullptr) {
1120 body->Add(init_block, parser_->zone()); 1110 body->Add(init_block, delegate()->zone());
1121 } 1111 }
1122 } 1112 }
1123 } 1113 }
1124 1114
1125 Expression* ParserTraits::ParseAsyncFunctionExpression(bool* ok) { 1115 Expression* ParserBaseTraits<Parser>::ParseAsyncFunctionExpression(bool* ok) {
1126 return parser_->ParseAsyncFunctionExpression(ok); 1116 return delegate()->ParseAsyncFunctionExpression(ok);
1127 } 1117 }
1128 1118
1129 DoExpression* ParserTraits::ParseDoExpression(bool* ok) { 1119 DoExpression* ParserBaseTraits<Parser>::ParseDoExpression(bool* ok) {
1130 return parser_->ParseDoExpression(ok); 1120 return delegate()->ParseDoExpression(ok);
1131 } 1121 }
1132 1122
1133 Expression* ParserTraits::RewriteYieldStar(Expression* generator, 1123 Expression* ParserBaseTraits<Parser>::RewriteYieldStar(Expression* generator,
1134 Expression* iterable, int pos) { 1124 Expression* iterable,
1135 return parser_->RewriteYieldStar(generator, iterable, pos); 1125 int pos) {
1126 return delegate()->RewriteYieldStar(generator, iterable, pos);
1136 } 1127 }
1137 1128
1138 } // namespace internal 1129 } // namespace internal
1139 } // namespace v8 1130 } // namespace v8
1140 1131
1141 #endif // V8_PARSING_PARSER_H_ 1132 #endif // V8_PARSING_PARSER_H_
OLDNEW
« no previous file with comments | « no previous file | src/parsing/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698