OLD | NEW |
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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/ast.h" | 8 #include "src/ast.h" |
9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 set_allow_harmony_classes(FLAG_harmony_classes); | 877 set_allow_harmony_classes(FLAG_harmony_classes); |
878 set_allow_harmony_object_literals(FLAG_harmony_object_literals); | 878 set_allow_harmony_object_literals(FLAG_harmony_object_literals); |
879 set_allow_harmony_sloppy(FLAG_harmony_sloppy); | 879 set_allow_harmony_sloppy(FLAG_harmony_sloppy); |
880 set_allow_harmony_unicode(FLAG_harmony_unicode); | 880 set_allow_harmony_unicode(FLAG_harmony_unicode); |
881 set_allow_harmony_computed_property_names( | 881 set_allow_harmony_computed_property_names( |
882 FLAG_harmony_computed_property_names); | 882 FLAG_harmony_computed_property_names); |
883 set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); | 883 set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); |
884 set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls); | 884 set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls); |
885 set_allow_harmony_destructuring(FLAG_harmony_destructuring); | 885 set_allow_harmony_destructuring(FLAG_harmony_destructuring); |
886 set_allow_harmony_spread_arrays(FLAG_harmony_spread_arrays); | 886 set_allow_harmony_spread_arrays(FLAG_harmony_spread_arrays); |
| 887 set_allow_harmony_default_parameters(FLAG_harmony_default_parameters); |
887 set_allow_strong_mode(FLAG_strong_mode); | 888 set_allow_strong_mode(FLAG_strong_mode); |
888 for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; | 889 for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
889 ++feature) { | 890 ++feature) { |
890 use_counts_[feature] = 0; | 891 use_counts_[feature] = 0; |
891 } | 892 } |
892 if (info->ast_value_factory() == NULL) { | 893 if (info->ast_value_factory() == NULL) { |
893 // info takes ownership of AstValueFactory. | 894 // info takes ownership of AstValueFactory. |
894 info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed())); | 895 info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed())); |
895 info->set_ast_value_factory_owned(); | 896 info->set_ast_value_factory_owned(); |
896 ast_value_factory_ = info->ast_value_factory(); | 897 ast_value_factory_ = info->ast_value_factory(); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 : FunctionLiteral::NAMED_EXPRESSION) | 1142 : FunctionLiteral::NAMED_EXPRESSION) |
1142 : FunctionLiteral::DECLARATION; | 1143 : FunctionLiteral::DECLARATION; |
1143 bool ok = true; | 1144 bool ok = true; |
1144 | 1145 |
1145 if (shared_info->is_arrow()) { | 1146 if (shared_info->is_arrow()) { |
1146 Scope* scope = | 1147 Scope* scope = |
1147 NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction); | 1148 NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction); |
1148 scope->set_start_position(shared_info->start_position()); | 1149 scope->set_start_position(shared_info->start_position()); |
1149 ExpressionClassifier formals_classifier; | 1150 ExpressionClassifier formals_classifier; |
1150 bool has_rest = false; | 1151 bool has_rest = false; |
| 1152 bool has_parameter_expressions = false; |
| 1153 |
| 1154 // TODO(caitp): make default parameters work in arrow functions |
| 1155 ZoneList<Expression*>* initializers = |
| 1156 new (zone()) ZoneList<Expression*>(0, zone()); |
1151 if (Check(Token::LPAREN)) { | 1157 if (Check(Token::LPAREN)) { |
1152 // '(' StrictFormalParameters ')' | 1158 // '(' StrictFormalParameters ')' |
1153 ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok); | 1159 ParseFormalParameterList(scope, initializers, |
| 1160 &has_parameter_expressions, &has_rest, |
| 1161 &formals_classifier, &ok); |
1154 if (ok) ok = Check(Token::RPAREN); | 1162 if (ok) ok = Check(Token::RPAREN); |
1155 } else { | 1163 } else { |
1156 // BindingIdentifier | 1164 // BindingIdentifier |
1157 ParseFormalParameter(scope, has_rest, &formals_classifier, &ok); | 1165 ParseFormalParameter(scope, has_rest, &formals_classifier, &ok); |
1158 } | 1166 } |
1159 | 1167 |
1160 if (ok) { | 1168 if (ok) { |
1161 Expression* expression = | 1169 Expression* expression = |
1162 ParseArrowFunctionLiteral(scope, has_rest, formals_classifier, &ok); | 1170 ParseArrowFunctionLiteral(scope, has_rest, formals_classifier, &ok); |
1163 if (ok) { | 1171 if (ok) { |
(...skipping 2233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3397 | 3405 |
3398 inner_scope->set_end_position(scanner()->location().end_pos); | 3406 inner_scope->set_end_position(scanner()->location().end_pos); |
3399 inner_block->set_scope(inner_scope); | 3407 inner_block->set_scope(inner_scope); |
3400 scope_ = for_scope; | 3408 scope_ = for_scope; |
3401 | 3409 |
3402 outer_loop->Initialize(NULL, NULL, NULL, inner_block); | 3410 outer_loop->Initialize(NULL, NULL, NULL, inner_block); |
3403 return outer_block; | 3411 return outer_block; |
3404 } | 3412 } |
3405 | 3413 |
3406 | 3414 |
| 3415 ZoneList<Statement*>* Parser::DesugarInitializeParameters( |
| 3416 Scope* scope, bool has_parameter_expressions, |
| 3417 ZoneList<Expression*>* initializers) { |
| 3418 DCHECK(scope->is_function_scope()); |
| 3419 |
| 3420 if (has_parameter_expressions) { |
| 3421 // If has_parameter_expressions for the function is true, each parameter is |
| 3422 // desugared as follows: |
| 3423 // |
| 3424 // SingleNameBinding : |
| 3425 // let <name> = %_Arguments(<index>); |
| 3426 // SingleNameBinding Initializer |
| 3427 // let <name> = IS_UNDEFINED(%_Arguments(<index>)) ? <initializer> |
| 3428 // : %_Arguments(<index>); |
| 3429 // |
| 3430 // TODO(caitp, dslomov): support BindingPatterns & rest parameters |
| 3431 // |
| 3432 scope->UndeclareParametersForExpressions(); |
| 3433 ZoneList<Statement*>* body = |
| 3434 new (zone()) ZoneList<Statement*>(initializers->length(), zone()); |
| 3435 for (int i = 0; i < initializers->length(); ++i) { |
| 3436 Expression* initializer = initializers->at(i); |
| 3437 |
| 3438 // Position of parameter VariableProxy, for hole-checking |
| 3439 int pos = scope->parameter_position(i); |
| 3440 |
| 3441 static const int kCapacity = 1; |
| 3442 static const bool kIsInitializerBlock = true; |
| 3443 Block* param_block = |
| 3444 factory()->NewBlock(nullptr, kCapacity, kIsInitializerBlock, pos); |
| 3445 |
| 3446 VariableProxy* proxy = |
| 3447 NewUnresolved(scope->parameter(i)->raw_name(), LET); |
| 3448 VariableDeclaration* declaration = factory()->NewVariableDeclaration( |
| 3449 proxy, LET, scope, RelocInfo::kNoPosition); |
| 3450 |
| 3451 bool ok = true; |
| 3452 // All formal parameters have been removed from the scope VariableMap, |
| 3453 // and so Declare() should not be able to fail. |
| 3454 proxy = factory()->NewVariableProxy(Declare(declaration, true, &ok), pos); |
| 3455 DCHECK(ok); |
| 3456 |
| 3457 const AstRawString* fn_name = ast_value_factory()->empty_string(); |
| 3458 const Runtime::Function* arguments = |
| 3459 Runtime::FunctionForId(Runtime::kInlineArguments); |
| 3460 ZoneList<Expression*>* arguments_i0 = |
| 3461 new (zone()) ZoneList<Expression*>(1, zone()); |
| 3462 arguments_i0->Add(factory()->NewSmiLiteral(i, RelocInfo::kNoPosition), |
| 3463 zone()); |
| 3464 |
| 3465 if (initializer == nullptr) { |
| 3466 // let <name> = %_Arguments(i) |
| 3467 Expression* assign = factory()->NewAssignment( |
| 3468 Token::INIT_LET, proxy, |
| 3469 factory()->NewCallRuntime(fn_name, arguments, arguments_i0, |
| 3470 RelocInfo::kNoPosition), |
| 3471 RelocInfo::kNoPosition); |
| 3472 param_block->AddStatement( |
| 3473 factory()->NewExpressionStatement(assign, RelocInfo::kNoPosition), |
| 3474 zone()); |
| 3475 proxy->var()->set_initializer_position(pos); |
| 3476 } else { |
| 3477 // IS_UNDEFINED(%_Arguments(i)) ? <initializer> : %_Arguments(i); |
| 3478 ZoneList<Expression*>* arguments_i1 = |
| 3479 new (zone()) ZoneList<Expression*>(1, zone()); |
| 3480 arguments_i1->Add(factory()->NewSmiLiteral(i, RelocInfo::kNoPosition), |
| 3481 zone()); |
| 3482 |
| 3483 Expression* arg_or_default = factory()->NewConditional( |
| 3484 // condition: |
| 3485 factory()->NewCompareOperation( |
| 3486 Token::EQ_STRICT, |
| 3487 factory()->NewCallRuntime(fn_name, arguments, arguments_i0, |
| 3488 RelocInfo::kNoPosition), |
| 3489 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
| 3490 RelocInfo::kNoPosition), |
| 3491 // if true: |
| 3492 initializer, |
| 3493 // if false: |
| 3494 factory()->NewCallRuntime(fn_name, arguments, arguments_i1, |
| 3495 RelocInfo::kNoPosition), |
| 3496 RelocInfo::kNoPosition); |
| 3497 |
| 3498 Expression* assign = factory()->NewAssignment( |
| 3499 Token::INIT_LET, proxy, arg_or_default, RelocInfo::kNoPosition); |
| 3500 |
| 3501 param_block->AddStatement( |
| 3502 factory()->NewExpressionStatement(assign, RelocInfo::kNoPosition), |
| 3503 zone()); |
| 3504 proxy->var()->set_initializer_position(initializer->position()); |
| 3505 } |
| 3506 body->Add(param_block, zone()); |
| 3507 } |
| 3508 return body; |
| 3509 } else { |
| 3510 // If has_parameter_expressions is false, remove the unnecessary parameter |
| 3511 // block scopes. |
| 3512 ZoneList<Scope*>* scopes = scope->inner_scopes(); |
| 3513 for (int i = 0; i < scopes->length(); ++i) { |
| 3514 Scope* scope = scopes->at(i); |
| 3515 DCHECK(scope->is_block_scope()); |
| 3516 scope->FinalizeBlockScope(); |
| 3517 } |
| 3518 return nullptr; |
| 3519 } |
| 3520 } |
| 3521 |
| 3522 |
3407 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, | 3523 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
3408 bool* ok) { | 3524 bool* ok) { |
3409 // ForStatement :: | 3525 // ForStatement :: |
3410 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | 3526 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement |
3411 | 3527 |
3412 int stmt_pos = peek_position(); | 3528 int stmt_pos = peek_position(); |
3413 bool is_const = false; | 3529 bool is_const = false; |
3414 Statement* init = NULL; | 3530 Statement* init = NULL; |
3415 ZoneList<const AstRawString*> lexical_bindings(1, zone()); | 3531 ZoneList<const AstRawString*> lexical_bindings(1, zone()); |
3416 | 3532 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3767 const AstRawString* raw_name = expr->AsVariableProxy()->raw_name(); | 3883 const AstRawString* raw_name = expr->AsVariableProxy()->raw_name(); |
3768 Scanner::Location param_location(expr->position(), | 3884 Scanner::Location param_location(expr->position(), |
3769 expr->position() + raw_name->length()); | 3885 expr->position() + raw_name->length()); |
3770 | 3886 |
3771 // When the formal parameter was originally seen, it was parsed as a | 3887 // When the formal parameter was originally seen, it was parsed as a |
3772 // VariableProxy and recorded as unresolved in the scope. Here we undo that | 3888 // VariableProxy and recorded as unresolved in the scope. Here we undo that |
3773 // parse-time side-effect. | 3889 // parse-time side-effect. |
3774 parser_->scope_->RemoveUnresolved(expr->AsVariableProxy()); | 3890 parser_->scope_->RemoveUnresolved(expr->AsVariableProxy()); |
3775 | 3891 |
3776 bool is_rest = false; | 3892 bool is_rest = false; |
3777 bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest); | 3893 int pos = expr->position(); |
| 3894 bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest, pos); |
3778 | 3895 |
3779 if (is_duplicate && !duplicate_loc->IsValid()) { | 3896 if (is_duplicate && !duplicate_loc->IsValid()) { |
3780 *duplicate_loc = param_location; | 3897 *duplicate_loc = param_location; |
3781 } | 3898 } |
3782 } | 3899 } |
3783 | 3900 |
3784 | 3901 |
3785 void ParserTraits::ParseArrowFunctionFormalParameters( | 3902 void ParserTraits::ParseArrowFunctionFormalParameters( |
3786 Scope* scope, Expression* params, const Scanner::Location& params_loc, | 3903 Scope* scope, Expression* params, const Scanner::Location& params_loc, |
3787 bool* is_rest, Scanner::Location* duplicate_loc, bool* ok) { | 3904 bool* is_rest, Scanner::Location* duplicate_loc, bool* ok) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3878 | 3995 |
3879 // Calling a generator returns a generator object. That object is stored | 3996 // Calling a generator returns a generator object. That object is stored |
3880 // in a temporary variable, a definition that is used by "yield" | 3997 // in a temporary variable, a definition that is used by "yield" |
3881 // expressions. This also marks the FunctionState as a generator. | 3998 // expressions. This also marks the FunctionState as a generator. |
3882 Variable* temp = scope_->DeclarationScope()->NewTemporary( | 3999 Variable* temp = scope_->DeclarationScope()->NewTemporary( |
3883 ast_value_factory()->dot_generator_object_string()); | 4000 ast_value_factory()->dot_generator_object_string()); |
3884 function_state.set_generator_object_variable(temp); | 4001 function_state.set_generator_object_variable(temp); |
3885 } | 4002 } |
3886 | 4003 |
3887 bool has_rest = false; | 4004 bool has_rest = false; |
| 4005 bool has_parameter_expressions = false; |
3888 Expect(Token::LPAREN, CHECK_OK); | 4006 Expect(Token::LPAREN, CHECK_OK); |
3889 int start_position = scanner()->location().beg_pos; | 4007 int start_position = scanner()->location().beg_pos; |
3890 scope_->set_start_position(start_position); | 4008 scope_->set_start_position(start_position); |
3891 num_parameters = ParseFormalParameterList(scope, &has_rest, | 4009 ZoneList<Expression*>* initializers = |
3892 &formals_classifier, CHECK_OK); | 4010 new (zone()) ZoneList<Expression*>(0, zone()); |
| 4011 num_parameters = ParseFormalParameterList( |
| 4012 scope, initializers, &has_parameter_expressions, &has_rest, |
| 4013 &formals_classifier, CHECK_OK); |
3893 Expect(Token::RPAREN, CHECK_OK); | 4014 Expect(Token::RPAREN, CHECK_OK); |
3894 int formals_end_position = scanner()->location().end_pos; | 4015 int formals_end_position = scanner()->location().end_pos; |
3895 | 4016 |
3896 CheckArityRestrictions(num_parameters, arity_restriction, has_rest, | 4017 CheckArityRestrictions(num_parameters, arity_restriction, has_rest, |
3897 start_position, formals_end_position, CHECK_OK); | 4018 start_position, formals_end_position, CHECK_OK); |
3898 | 4019 |
3899 Expect(Token::LBRACE, CHECK_OK); | 4020 Expect(Token::LBRACE, CHECK_OK); |
3900 | 4021 |
3901 // If we have a named function expression, we add a local variable | 4022 // If we have a named function expression, we add a local variable |
3902 // declaration to the body of the function with the name of the | 4023 // declaration to the body of the function with the name of the |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3983 is_lazily_parsed = false; | 4104 is_lazily_parsed = false; |
3984 | 4105 |
3985 // This is probably an initialization function. Inform the compiler it | 4106 // This is probably an initialization function. Inform the compiler it |
3986 // should also eager-compile this function, and that we expect it to be | 4107 // should also eager-compile this function, and that we expect it to be |
3987 // used once. | 4108 // used once. |
3988 eager_compile_hint = FunctionLiteral::kShouldEagerCompile; | 4109 eager_compile_hint = FunctionLiteral::kShouldEagerCompile; |
3989 should_be_used_once_hint = true; | 4110 should_be_used_once_hint = true; |
3990 } | 4111 } |
3991 } | 4112 } |
3992 if (!is_lazily_parsed) { | 4113 if (!is_lazily_parsed) { |
3993 body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op, | 4114 body = DesugarInitializeParameters(scope, has_parameter_expressions, |
3994 kind, CHECK_OK); | 4115 initializers); |
| 4116 if (has_parameter_expressions) { |
| 4117 // TODO(caitp): Function body scope must be a declaration scope |
| 4118 Scope* function_body_scope = NewScope(scope, BLOCK_SCOPE); |
| 4119 function_body_scope->set_start_position(scope->start_position()); |
| 4120 function_body_scope->SetScopeName(function_name); |
| 4121 BlockState function_body_state(&scope_, function_body_scope); |
| 4122 ZoneList<Statement*>* inner_body = ParseEagerFunctionBody( |
| 4123 function_name, pos, fvar, fvar_init_op, kind, CHECK_OK); |
| 4124 |
| 4125 // Declare Block node |
| 4126 Block* block = |
| 4127 factory()->NewBlock(nullptr, inner_body->length(), false, pos); |
| 4128 block->set_scope(function_body_scope); |
| 4129 for (int i = 0; i < inner_body->length(); ++i) { |
| 4130 block->AddStatement(inner_body->at(i), zone()); |
| 4131 } |
| 4132 |
| 4133 scope->set_end_position(function_body_scope->end_position()); |
| 4134 body->Add(block, zone()); |
| 4135 } else { |
| 4136 body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op, |
| 4137 kind, CHECK_OK); |
| 4138 } |
3995 materialized_literal_count = function_state.materialized_literal_count(); | 4139 materialized_literal_count = function_state.materialized_literal_count(); |
3996 expected_property_count = function_state.expected_property_count(); | 4140 expected_property_count = function_state.expected_property_count(); |
3997 handler_count = function_state.handler_count(); | 4141 handler_count = function_state.handler_count(); |
3998 | 4142 |
3999 if (is_strong(language_mode()) && IsSubclassConstructor(kind)) { | 4143 if (is_strong(language_mode()) && IsSubclassConstructor(kind)) { |
4000 if (!function_state.super_location().IsValid()) { | 4144 if (!function_state.super_location().IsValid()) { |
4001 ReportMessageAt(function_name_location, | 4145 ReportMessageAt(function_name_location, |
4002 MessageTemplate::kStrongSuperCallMissing, | 4146 MessageTemplate::kStrongSuperCallMissing, |
4003 kReferenceError); | 4147 kReferenceError); |
4004 *ok = false; | 4148 *ok = false; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4268 reusable_preparser_->set_allow_harmony_computed_property_names( | 4412 reusable_preparser_->set_allow_harmony_computed_property_names( |
4269 allow_harmony_computed_property_names()); | 4413 allow_harmony_computed_property_names()); |
4270 reusable_preparser_->set_allow_harmony_rest_params( | 4414 reusable_preparser_->set_allow_harmony_rest_params( |
4271 allow_harmony_rest_params()); | 4415 allow_harmony_rest_params()); |
4272 reusable_preparser_->set_allow_harmony_spreadcalls( | 4416 reusable_preparser_->set_allow_harmony_spreadcalls( |
4273 allow_harmony_spreadcalls()); | 4417 allow_harmony_spreadcalls()); |
4274 reusable_preparser_->set_allow_harmony_destructuring( | 4418 reusable_preparser_->set_allow_harmony_destructuring( |
4275 allow_harmony_destructuring()); | 4419 allow_harmony_destructuring()); |
4276 reusable_preparser_->set_allow_harmony_spread_arrays( | 4420 reusable_preparser_->set_allow_harmony_spread_arrays( |
4277 allow_harmony_spread_arrays()); | 4421 allow_harmony_spread_arrays()); |
| 4422 reusable_preparser_->set_allow_harmony_default_parameters( |
| 4423 allow_harmony_default_parameters()); |
4278 reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); | 4424 reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); |
4279 } | 4425 } |
4280 PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( | 4426 PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( |
4281 language_mode(), function_state_->kind(), logger, bookmark); | 4427 language_mode(), function_state_->kind(), logger, bookmark); |
4282 if (pre_parse_timer_ != NULL) { | 4428 if (pre_parse_timer_ != NULL) { |
4283 pre_parse_timer_->Stop(); | 4429 pre_parse_timer_->Stop(); |
4284 } | 4430 } |
4285 return result; | 4431 return result; |
4286 } | 4432 } |
4287 | 4433 |
(...skipping 1502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5790 | 5936 |
5791 Expression* Parser::SpreadCallNew(Expression* function, | 5937 Expression* Parser::SpreadCallNew(Expression* function, |
5792 ZoneList<v8::internal::Expression*>* args, | 5938 ZoneList<v8::internal::Expression*>* args, |
5793 int pos) { | 5939 int pos) { |
5794 args->InsertAt(0, function, zone()); | 5940 args->InsertAt(0, function, zone()); |
5795 | 5941 |
5796 return factory()->NewCallRuntime( | 5942 return factory()->NewCallRuntime( |
5797 ast_value_factory()->reflect_construct_string(), NULL, args, pos); | 5943 ast_value_factory()->reflect_construct_string(), NULL, args, pos); |
5798 } | 5944 } |
5799 } } // namespace v8::internal | 5945 } } // namespace v8::internal |
OLD | NEW |