OSDN Git Service

compiler: Fix parse of (<- chan <- chan <- int)(x).
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Oct 2012 22:22:39 +0000 (22:22 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Oct 2012 22:22:39 +0000 (22:22 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_7-branch@192012 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h

index f6b9715..1ec283d 100644 (file)
@@ -3315,6 +3315,61 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
                  bool* is_type_switch)
 {
   const Token* token = this->peek_token();
+
+  // There is a complex parse for <- chan.  The choices are
+  // Convert x to type <- chan int:
+  //   (<- chan int)(x)         
+  // Receive from (x converted to type chan <- chan int):
+  //   (<- chan <- chan int (x))
+  // Convert x to type <- chan (<- chan int).
+  //   (<- chan <- chan int)(x)
+  if (token->is_op(OPERATOR_CHANOP))
+    {
+      Location location = token->location();
+      if (this->advance_token()->is_keyword(KEYWORD_CHAN))
+       {
+         Expression* expr = this->primary_expr(false, may_be_composite_lit,
+                                               NULL);
+         if (expr->is_error_expression())
+           return expr;
+         else if (!expr->is_type_expression())
+           return Expression::make_receive(expr, location);
+         else
+           {
+             if (expr->type()->is_error_type())
+               return expr;
+
+             // We picked up "chan TYPE", but it is not a type
+             // conversion.
+             Channel_type* ct = expr->type()->channel_type();
+             if (ct == NULL)
+               {
+                 // This is probably impossible.
+                 error_at(location, "expected channel type");
+                 return Expression::make_error(location);
+               }
+             else if (ct->may_receive())
+               {
+                 // <- chan TYPE.
+                 Type* t = Type::make_channel_type(false, true,
+                                                   ct->element_type());
+                 return Expression::make_type(t, location);
+               }
+             else
+               {
+                 // <- chan <- TYPE.  Because we skipped the leading
+                 // <-, we parsed this as chan <- TYPE.  With the
+                 // leading <-, we parse it as <- chan (<- TYPE).
+                 Type *t = this->reassociate_chan_direction(ct, location);
+                 return Expression::make_type(t, location);
+               }
+           }
+       }
+
+      this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
+      token = this->peek_token();
+    }
+
   if (token->is_op(OPERATOR_PLUS)
       || token->is_op(OPERATOR_MINUS)
       || token->is_op(OPERATOR_NOT)
@@ -3327,14 +3382,6 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
       Operator op = token->op();
       this->advance_token();
 
-      if (op == OPERATOR_CHANOP
-         && this->peek_token()->is_keyword(KEYWORD_CHAN))
-       {
-         // This is "<- chan" which must be the start of a type.
-         this->unget_token(Token::make_operator_token(op, location));
-         return Expression::make_type(this->type(), location);
-       }
-
       Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
       if (expr->is_error_expression())
        ;
@@ -3354,6 +3401,32 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
                              is_type_switch);
 }
 
+// This is called for the obscure case of
+//   (<- chan <- chan int)(x)
+// In unary_expr we remove the leading <- and parse the remainder,
+// which gives us
+//   chan <- (chan int)
+// When we add the leading <- back in, we really want
+//   <- chan (<- chan int)
+// This means that we need to reassociate.
+
+Type*
+Parse::reassociate_chan_direction(Channel_type *ct, Location location)
+{
+  Channel_type* ele = ct->element_type()->channel_type();
+  if (ele == NULL)
+    {
+      error_at(location, "parse error");
+      return Type::make_error_type();
+    }
+  Type* sub = ele;
+  if (ele->may_send())
+    sub = Type::make_channel_type(false, true, ele->element_type());
+  else
+    sub = this->reassociate_chan_direction(ele, location);
+  return Type::make_channel_type(false, true, sub);
+}
+
 // Statement =
 //     Declaration | LabeledStmt | SimpleStmt |
 //     GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
index 3139f7e..fb5c1f1 100644 (file)
@@ -14,6 +14,7 @@ class Named_object;
 class Type;
 class Typed_identifier;
 class Typed_identifier_list;
+class Channel_type;
 class Function_type;
 class Block;
 class Expression;
@@ -229,6 +230,7 @@ class Parse
   bool expression_may_start_here();
   Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
                         bool* is_type_switch);
+  Type* reassociate_chan_direction(Channel_type*, Location);
   Expression* qualified_expr(Expression*, Location);
   Expression* id_to_expression(const std::string&, Location);
   void statement(Label*);