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

Side by Side Diff: runtime/vm/parser.cc

Issue 24768004: Check types of case expressions (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/co19/co19-runtime.status » ('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 (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "vm/bigint_operations.h" 8 #include "vm/bigint_operations.h"
9 #include "vm/bootstrap.h" 9 #include "vm/bootstrap.h"
10 #include "vm/class_finalizer.h" 10 #include "vm/class_finalizer.h"
(...skipping 6026 matching lines...) Expand 10 before | Expand all | Expand 10 after
6037 if (label != NULL) { 6037 if (label != NULL) {
6038 current_block_->statements->Add(if_node); 6038 current_block_->statements->Add(if_node);
6039 SequenceNode* sequence = CloseBlock(); 6039 SequenceNode* sequence = CloseBlock();
6040 sequence->set_label(label); 6040 sequence->set_label(label);
6041 if_node = sequence; 6041 if_node = sequence;
6042 } 6042 }
6043 return if_node; 6043 return if_node;
6044 } 6044 }
6045 6045
6046 6046
6047 void Parser::CheckCaseExpressions(const GrowableArray<LiteralNode*>& values) {
srdjan 2013/09/26 18:35:43 Add brief comment what checks are done.
hausner 2013/09/26 18:54:59 Done.
6048 const intptr_t num_expressions = values.length();
6049 if (num_expressions == 0) {
6050 return;
6051 }
6052 const Instance& first_value = values[0]->literal();
6053 for (intptr_t i = 0; i < num_expressions; i++) {
6054 const Instance& val = values[i]->literal();
6055 const intptr_t val_pos = values[i]->token_pos();
6056 if (first_value.IsInteger()) {
6057 if (!val.IsInteger()) {
6058 ErrorMsg(val_pos, "expected case expression of type int");
6059 }
6060 continue;
6061 }
6062 if (first_value.IsString()) {
6063 if (!val.IsString()) {
6064 ErrorMsg(val_pos, "expected case expression of type String");
6065 }
6066 continue;
6067 }
6068 if (first_value.IsDouble()) {
6069 if (!val.IsDouble()) {
6070 ErrorMsg(val_pos, "expected case expression of type double");
6071 }
6072 continue;
6073 }
6074 if (val.clazz() != first_value.clazz()) {
6075 ErrorMsg(val_pos, "all case expressions must be of same type");
6076 }
6077 Class& cls = Class::Handle(val.clazz());
6078 const Function& equal_op = Function::Handle(
6079 Resolver::ResolveDynamicAnyArgs(cls, Symbols::EqualOperator()));
6080 ASSERT(!equal_op.IsNull());
6081 cls = equal_op.Owner();
6082 if (!cls.IsObjectClass()) {
6083 ErrorMsg(val_pos,
6084 "type class of case expression must not implement operator ==");
6085 }
6086 }
6087 }
6088
6089
6047 CaseNode* Parser::ParseCaseClause(LocalVariable* switch_expr_value, 6090 CaseNode* Parser::ParseCaseClause(LocalVariable* switch_expr_value,
6091 GrowableArray<LiteralNode*>* case_expr_values,
6048 SourceLabel* case_label) { 6092 SourceLabel* case_label) {
6049 TRACE_PARSER("ParseCaseClause"); 6093 TRACE_PARSER("ParseCaseClause");
6050 bool default_seen = false; 6094 bool default_seen = false;
6051 const intptr_t case_pos = TokenPos(); 6095 const intptr_t case_pos = TokenPos();
6052 // The case expressions node sequence does not own the enclosing scope. 6096 // The case expressions node sequence does not own the enclosing scope.
6053 SequenceNode* case_expressions = new SequenceNode(case_pos, NULL); 6097 SequenceNode* case_expressions = new SequenceNode(case_pos, NULL);
6054 while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) { 6098 while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) {
6055 if (CurrentToken() == Token::kCASE) { 6099 if (CurrentToken() == Token::kCASE) {
6056 if (default_seen) { 6100 if (default_seen) {
6057 ErrorMsg("default clause must be last case"); 6101 ErrorMsg("default clause must be last case");
6058 } 6102 }
6059 ConsumeToken(); // Keyword case. 6103 ConsumeToken(); // Keyword case.
6060 const intptr_t expr_pos = TokenPos(); 6104 const intptr_t expr_pos = TokenPos();
6061 AstNode* expr = ParseExpr(kRequireConst, kConsumeCascades); 6105 AstNode* expr = ParseExpr(kRequireConst, kConsumeCascades);
6106 ASSERT(expr->IsLiteralNode());
6107 case_expr_values->Add(expr->AsLiteralNode());
6108
6062 AstNode* switch_expr_load = new LoadLocalNode(case_pos, 6109 AstNode* switch_expr_load = new LoadLocalNode(case_pos,
6063 switch_expr_value); 6110 switch_expr_value);
6064 AstNode* case_comparison = new ComparisonNode(expr_pos, 6111 AstNode* case_comparison = new ComparisonNode(expr_pos,
6065 Token::kEQ, 6112 Token::kEQ,
6066 expr, 6113 expr,
6067 switch_expr_load); 6114 switch_expr_load);
6068 case_expressions->Add(case_comparison); 6115 case_expressions->Add(case_comparison);
6069 } else { 6116 } else {
6070 if (default_seen) { 6117 if (default_seen) {
6071 ErrorMsg("only one default clause is allowed"); 6118 ErrorMsg("only one default clause is allowed");
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
6140 new LocalVariable(expr_pos, 6187 new LocalVariable(expr_pos,
6141 Symbols::SwitchExpr(), 6188 Symbols::SwitchExpr(),
6142 Type::ZoneHandle(Type::DynamicType())); 6189 Type::ZoneHandle(Type::DynamicType()));
6143 current_block_->scope->AddVariable(temp_variable); 6190 current_block_->scope->AddVariable(temp_variable);
6144 AstNode* save_switch_expr = 6191 AstNode* save_switch_expr =
6145 new StoreLocalNode(expr_pos, temp_variable, switch_expr); 6192 new StoreLocalNode(expr_pos, temp_variable, switch_expr);
6146 current_block_->statements->Add(save_switch_expr); 6193 current_block_->statements->Add(save_switch_expr);
6147 6194
6148 // Parse case clauses 6195 // Parse case clauses
6149 bool default_seen = false; 6196 bool default_seen = false;
6197 GrowableArray<LiteralNode*> case_expr_values;
6150 while (true) { 6198 while (true) {
6151 // Check for statement label 6199 // Check for statement label
6152 SourceLabel* case_label = NULL; 6200 SourceLabel* case_label = NULL;
6153 if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) { 6201 if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) {
6154 // Case statements start with a label. 6202 // Case statements start with a label.
6155 String* label_name = CurrentLiteral(); 6203 String* label_name = CurrentLiteral();
6156 const intptr_t label_pos = TokenPos(); 6204 const intptr_t label_pos = TokenPos();
6157 ConsumeToken(); // Consume label identifier. 6205 ConsumeToken(); // Consume label identifier.
6158 ConsumeToken(); // Consume colon. 6206 ConsumeToken(); // Consume colon.
6159 case_label = current_block_->scope->LocalLookupLabel(*label_name); 6207 case_label = current_block_->scope->LocalLookupLabel(*label_name);
(...skipping 10 matching lines...) Expand all
6170 ErrorMsg(label_pos, "label '%s' already exists in scope", 6218 ErrorMsg(label_pos, "label '%s' already exists in scope",
6171 label_name->ToCString()); 6219 label_name->ToCString());
6172 } 6220 }
6173 ASSERT(case_label->kind() == SourceLabel::kCase); 6221 ASSERT(case_label->kind() == SourceLabel::kCase);
6174 } 6222 }
6175 if (CurrentToken() == Token::kCASE || 6223 if (CurrentToken() == Token::kCASE ||
6176 CurrentToken() == Token::kDEFAULT) { 6224 CurrentToken() == Token::kDEFAULT) {
6177 if (default_seen) { 6225 if (default_seen) {
6178 ErrorMsg("no case clauses allowed after default clause"); 6226 ErrorMsg("no case clauses allowed after default clause");
6179 } 6227 }
6180 CaseNode* case_clause = ParseCaseClause(temp_variable, case_label); 6228 CaseNode* case_clause =
6229 ParseCaseClause(temp_variable, &case_expr_values, case_label);
6181 default_seen = case_clause->contains_default(); 6230 default_seen = case_clause->contains_default();
6182 current_block_->statements->Add(case_clause); 6231 current_block_->statements->Add(case_clause);
6183 } else if (CurrentToken() != Token::kRBRACE) { 6232 } else if (CurrentToken() != Token::kRBRACE) {
6184 ErrorMsg("'case' or '}' expected"); 6233 ErrorMsg("'case' or '}' expected");
6185 } else if (case_label != NULL) { 6234 } else if (case_label != NULL) {
6186 ErrorMsg("expecting at least one case clause after label"); 6235 ErrorMsg("expecting at least one case clause after label");
6187 } else { 6236 } else {
6188 break; 6237 break;
6189 } 6238 }
6190 } 6239 }
6191 6240
6192 // TODO(hausner): Check that all expressions in case clauses are 6241 // Check that all expressions in case clauses are of the same class,
6193 // of the same class, or implement int or String (issue 7307). 6242 // or implement int, double or String.
6243 CheckCaseExpressions(case_expr_values);
6194 6244
6195 // Check for unresolved label references. 6245 // Check for unresolved label references.
6196 SourceLabel* unresolved_label = 6246 SourceLabel* unresolved_label =
6197 current_block_->scope->CheckUnresolvedLabels(); 6247 current_block_->scope->CheckUnresolvedLabels();
6198 if (unresolved_label != NULL) { 6248 if (unresolved_label != NULL) {
6199 ErrorMsg("unresolved reference to label '%s'", 6249 ErrorMsg("unresolved reference to label '%s'",
6200 unresolved_label->name().ToCString()); 6250 unresolved_label->name().ToCString());
6201 } 6251 }
6202 6252
6203 SequenceNode* switch_body = CloseBlock(); 6253 SequenceNode* switch_body = CloseBlock();
(...skipping 4342 matching lines...) Expand 10 before | Expand all | Expand 10 after
10546 void Parser::SkipQualIdent() { 10596 void Parser::SkipQualIdent() {
10547 ASSERT(IsIdentifier()); 10597 ASSERT(IsIdentifier());
10548 ConsumeToken(); 10598 ConsumeToken();
10549 if (CurrentToken() == Token::kPERIOD) { 10599 if (CurrentToken() == Token::kPERIOD) {
10550 ConsumeToken(); // Consume the kPERIOD token. 10600 ConsumeToken(); // Consume the kPERIOD token.
10551 ExpectIdentifier("identifier expected after '.'"); 10601 ExpectIdentifier("identifier expected after '.'");
10552 } 10602 }
10553 } 10603 }
10554 10604
10555 } // namespace dart 10605 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/co19/co19-runtime.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698