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

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 // Check that all case expressions are of the same type, either int, String,
6048 // double or any other class that does not override the == operator.
6049 // The expressions are compile-time constants and are thus in the form
6050 // of a LiteralNode.
6051 void Parser::CheckCaseExpressions(const GrowableArray<LiteralNode*>& values) {
6052 const intptr_t num_expressions = values.length();
6053 if (num_expressions == 0) {
6054 return;
6055 }
6056 const Instance& first_value = values[0]->literal();
6057 for (intptr_t i = 0; i < num_expressions; i++) {
Ivan Posva 2013/09/27 00:24:59 Why don't you start with i = 1? Otherwise you just
hausner 2013/09/27 00:31:34 Because I still need to check that the first value
6058 const Instance& val = values[i]->literal();
6059 const intptr_t val_pos = values[i]->token_pos();
6060 if (first_value.IsInteger()) {
6061 if (!val.IsInteger()) {
6062 ErrorMsg(val_pos, "expected case expression of type int");
6063 }
6064 continue;
6065 }
6066 if (first_value.IsString()) {
6067 if (!val.IsString()) {
6068 ErrorMsg(val_pos, "expected case expression of type String");
6069 }
6070 continue;
6071 }
6072 if (first_value.IsDouble()) {
6073 if (!val.IsDouble()) {
6074 ErrorMsg(val_pos, "expected case expression of type double");
6075 }
6076 continue;
6077 }
6078 if (val.clazz() != first_value.clazz()) {
6079 ErrorMsg(val_pos, "all case expressions must be of same type");
6080 }
6081 Class& cls = Class::Handle(val.clazz());
6082 const Function& equal_op = Function::Handle(
6083 Resolver::ResolveDynamicAnyArgs(cls, Symbols::EqualOperator()));
Ivan Posva 2013/09/27 00:24:59 Can't you hoist this check out of the loop? Once y
hausner 2013/09/27 00:31:34 Good point. If I hoist it out I have to duplicate
Ivan Posva 2013/09/27 00:44:45 You can hoist the whole testing out. Most of the t
hausner 2013/09/27 00:49:16 The whole reason why int and String are handled se
6084 ASSERT(!equal_op.IsNull());
6085 cls = equal_op.Owner();
6086 if (!cls.IsObjectClass()) {
6087 ErrorMsg(val_pos,
6088 "type class of case expression must not implement operator ==");
6089 }
6090 }
6091 }
6092
6093
6047 CaseNode* Parser::ParseCaseClause(LocalVariable* switch_expr_value, 6094 CaseNode* Parser::ParseCaseClause(LocalVariable* switch_expr_value,
6095 GrowableArray<LiteralNode*>* case_expr_values,
6048 SourceLabel* case_label) { 6096 SourceLabel* case_label) {
6049 TRACE_PARSER("ParseCaseClause"); 6097 TRACE_PARSER("ParseCaseClause");
6050 bool default_seen = false; 6098 bool default_seen = false;
6051 const intptr_t case_pos = TokenPos(); 6099 const intptr_t case_pos = TokenPos();
6052 // The case expressions node sequence does not own the enclosing scope. 6100 // The case expressions node sequence does not own the enclosing scope.
6053 SequenceNode* case_expressions = new SequenceNode(case_pos, NULL); 6101 SequenceNode* case_expressions = new SequenceNode(case_pos, NULL);
6054 while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) { 6102 while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) {
6055 if (CurrentToken() == Token::kCASE) { 6103 if (CurrentToken() == Token::kCASE) {
6056 if (default_seen) { 6104 if (default_seen) {
6057 ErrorMsg("default clause must be last case"); 6105 ErrorMsg("default clause must be last case");
6058 } 6106 }
6059 ConsumeToken(); // Keyword case. 6107 ConsumeToken(); // Keyword case.
6060 const intptr_t expr_pos = TokenPos(); 6108 const intptr_t expr_pos = TokenPos();
6061 AstNode* expr = ParseExpr(kRequireConst, kConsumeCascades); 6109 AstNode* expr = ParseExpr(kRequireConst, kConsumeCascades);
6110 ASSERT(expr->IsLiteralNode());
6111 case_expr_values->Add(expr->AsLiteralNode());
6112
6062 AstNode* switch_expr_load = new LoadLocalNode(case_pos, 6113 AstNode* switch_expr_load = new LoadLocalNode(case_pos,
6063 switch_expr_value); 6114 switch_expr_value);
6064 AstNode* case_comparison = new ComparisonNode(expr_pos, 6115 AstNode* case_comparison = new ComparisonNode(expr_pos,
6065 Token::kEQ, 6116 Token::kEQ,
6066 expr, 6117 expr,
6067 switch_expr_load); 6118 switch_expr_load);
6068 case_expressions->Add(case_comparison); 6119 case_expressions->Add(case_comparison);
6069 } else { 6120 } else {
6070 if (default_seen) { 6121 if (default_seen) {
6071 ErrorMsg("only one default clause is allowed"); 6122 ErrorMsg("only one default clause is allowed");
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
6140 new LocalVariable(expr_pos, 6191 new LocalVariable(expr_pos,
6141 Symbols::SwitchExpr(), 6192 Symbols::SwitchExpr(),
6142 Type::ZoneHandle(Type::DynamicType())); 6193 Type::ZoneHandle(Type::DynamicType()));
6143 current_block_->scope->AddVariable(temp_variable); 6194 current_block_->scope->AddVariable(temp_variable);
6144 AstNode* save_switch_expr = 6195 AstNode* save_switch_expr =
6145 new StoreLocalNode(expr_pos, temp_variable, switch_expr); 6196 new StoreLocalNode(expr_pos, temp_variable, switch_expr);
6146 current_block_->statements->Add(save_switch_expr); 6197 current_block_->statements->Add(save_switch_expr);
6147 6198
6148 // Parse case clauses 6199 // Parse case clauses
6149 bool default_seen = false; 6200 bool default_seen = false;
6201 GrowableArray<LiteralNode*> case_expr_values;
6150 while (true) { 6202 while (true) {
6151 // Check for statement label 6203 // Check for statement label
6152 SourceLabel* case_label = NULL; 6204 SourceLabel* case_label = NULL;
6153 if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) { 6205 if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) {
6154 // Case statements start with a label. 6206 // Case statements start with a label.
6155 String* label_name = CurrentLiteral(); 6207 String* label_name = CurrentLiteral();
6156 const intptr_t label_pos = TokenPos(); 6208 const intptr_t label_pos = TokenPos();
6157 ConsumeToken(); // Consume label identifier. 6209 ConsumeToken(); // Consume label identifier.
6158 ConsumeToken(); // Consume colon. 6210 ConsumeToken(); // Consume colon.
6159 case_label = current_block_->scope->LocalLookupLabel(*label_name); 6211 case_label = current_block_->scope->LocalLookupLabel(*label_name);
(...skipping 10 matching lines...) Expand all
6170 ErrorMsg(label_pos, "label '%s' already exists in scope", 6222 ErrorMsg(label_pos, "label '%s' already exists in scope",
6171 label_name->ToCString()); 6223 label_name->ToCString());
6172 } 6224 }
6173 ASSERT(case_label->kind() == SourceLabel::kCase); 6225 ASSERT(case_label->kind() == SourceLabel::kCase);
6174 } 6226 }
6175 if (CurrentToken() == Token::kCASE || 6227 if (CurrentToken() == Token::kCASE ||
6176 CurrentToken() == Token::kDEFAULT) { 6228 CurrentToken() == Token::kDEFAULT) {
6177 if (default_seen) { 6229 if (default_seen) {
6178 ErrorMsg("no case clauses allowed after default clause"); 6230 ErrorMsg("no case clauses allowed after default clause");
6179 } 6231 }
6180 CaseNode* case_clause = ParseCaseClause(temp_variable, case_label); 6232 CaseNode* case_clause =
6233 ParseCaseClause(temp_variable, &case_expr_values, case_label);
6181 default_seen = case_clause->contains_default(); 6234 default_seen = case_clause->contains_default();
6182 current_block_->statements->Add(case_clause); 6235 current_block_->statements->Add(case_clause);
6183 } else if (CurrentToken() != Token::kRBRACE) { 6236 } else if (CurrentToken() != Token::kRBRACE) {
6184 ErrorMsg("'case' or '}' expected"); 6237 ErrorMsg("'case' or '}' expected");
6185 } else if (case_label != NULL) { 6238 } else if (case_label != NULL) {
6186 ErrorMsg("expecting at least one case clause after label"); 6239 ErrorMsg("expecting at least one case clause after label");
6187 } else { 6240 } else {
6188 break; 6241 break;
6189 } 6242 }
6190 } 6243 }
6191 6244
6192 // TODO(hausner): Check that all expressions in case clauses are 6245 // Check that all expressions in case clauses are of the same class,
6193 // of the same class, or implement int or String (issue 7307). 6246 // or implement int, double or String.
6247 CheckCaseExpressions(case_expr_values);
6194 6248
6195 // Check for unresolved label references. 6249 // Check for unresolved label references.
6196 SourceLabel* unresolved_label = 6250 SourceLabel* unresolved_label =
6197 current_block_->scope->CheckUnresolvedLabels(); 6251 current_block_->scope->CheckUnresolvedLabels();
6198 if (unresolved_label != NULL) { 6252 if (unresolved_label != NULL) {
6199 ErrorMsg("unresolved reference to label '%s'", 6253 ErrorMsg("unresolved reference to label '%s'",
6200 unresolved_label->name().ToCString()); 6254 unresolved_label->name().ToCString());
6201 } 6255 }
6202 6256
6203 SequenceNode* switch_body = CloseBlock(); 6257 SequenceNode* switch_body = CloseBlock();
(...skipping 4342 matching lines...) Expand 10 before | Expand all | Expand 10 after
10546 void Parser::SkipQualIdent() { 10600 void Parser::SkipQualIdent() {
10547 ASSERT(IsIdentifier()); 10601 ASSERT(IsIdentifier());
10548 ConsumeToken(); 10602 ConsumeToken();
10549 if (CurrentToken() == Token::kPERIOD) { 10603 if (CurrentToken() == Token::kPERIOD) {
10550 ConsumeToken(); // Consume the kPERIOD token. 10604 ConsumeToken(); // Consume the kPERIOD token.
10551 ExpectIdentifier("identifier expected after '.'"); 10605 ExpectIdentifier("identifier expected after '.'");
10552 } 10606 }
10553 } 10607 }
10554 10608
10555 } // namespace dart 10609 } // 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