while (true)
{
ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink,
- may_be_composite_lit, NULL));
+ may_be_composite_lit, NULL, NULL));
const Token* token = this->peek_token();
if (!token->is_op(OPERATOR_COMMA))
else
{
if (!token->is_op(OPERATOR_ELLIPSIS))
- length = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ length = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
else if (may_use_ellipsis)
{
// An ellipsis is used in composite literals to represent a
bool is_type_switch = false;
Expression* expr = this->expression(PRECEDENCE_NORMAL, false,
may_be_composite_lit,
- &is_type_switch);
+ &is_type_switch, NULL);
if (is_type_switch)
{
p_type_switch->found = true;
// If MAY_BE_SINK is true, this operand may be "_".
+// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
+// if the entire expression is in parentheses.
+
Expression*
-Parse::operand(bool may_be_sink)
+Parse::operand(bool may_be_sink, bool* is_parenthesized)
{
const Token* token = this->peek_token();
Expression* ret;
if (token->is_op(OPERATOR_LPAREN))
{
this->advance_token();
- ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL);
+ ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL,
+ NULL);
if (!this->peek_token()->is_op(OPERATOR_RPAREN))
error_at(this->location(), "missing %<)%>");
else
this->advance_token();
+ if (is_parenthesized != NULL)
+ *is_parenthesized = true;
return ret;
}
else if (token->is_op(OPERATOR_LSQUARE))
this->unget_token(Token::make_identifier_token(identifier,
is_exported,
location));
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ val = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
+ NULL);
}
}
else if (!token->is_op(OPERATOR_LCURLY))
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
else
{
// This must be a composite literal inside another composite
vals->push_back(val);
if (!token->is_op(OPERATOR_LCURLY))
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
else
{
// This must be a composite literal inside another
// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
// guard (var := expr.("type") using the literal keyword "type").
+// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
+// if the entire expression is in parentheses.
+
Expression*
Parse::primary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch)
+ bool* is_type_switch, bool* is_parenthesized)
{
Location start_loc = this->location();
- bool is_parenthesized = this->peek_token()->is_op(OPERATOR_LPAREN);
+ bool operand_is_parenthesized = false;
+ bool whole_is_parenthesized = false;
+
+ Expression* ret = this->operand(may_be_sink, &operand_is_parenthesized);
- Expression* ret = this->operand(may_be_sink);
+ whole_is_parenthesized = operand_is_parenthesized;
// An unknown name followed by a curly brace must be a composite
// literal, and the unknown name must be a type.
if (may_be_composite_lit
- && !is_parenthesized
+ && !operand_is_parenthesized
&& ret->unknown_expression() != NULL
&& this->peek_token()->is_op(OPERATOR_LCURLY))
{
{
if (this->peek_token()->is_op(OPERATOR_LCURLY))
{
+ whole_is_parenthesized = false;
if (!may_be_composite_lit)
{
Type* t = ret->type();
_("parentheses required around this composite literal "
"to avoid parsing ambiguity"));
}
- else if (is_parenthesized)
+ else if (operand_is_parenthesized)
error_at(start_loc,
"cannot parenthesize type in composite literal");
ret = this->composite_lit(ret->type(), 0, ret->location());
}
else if (this->peek_token()->is_op(OPERATOR_LPAREN))
{
+ whole_is_parenthesized = false;
Location loc = this->location();
this->advance_token();
Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
- NULL);
+ NULL, NULL);
if (this->peek_token()->is_op(OPERATOR_COMMA))
this->advance_token();
if (this->peek_token()->is_op(OPERATOR_ELLIPSIS))
{
const Token* token = this->peek_token();
if (token->is_op(OPERATOR_LPAREN))
- ret = this->call(this->verify_not_sink(ret));
+ {
+ whole_is_parenthesized = false;
+ ret = this->call(this->verify_not_sink(ret));
+ }
else if (token->is_op(OPERATOR_DOT))
{
+ whole_is_parenthesized = false;
ret = this->selector(this->verify_not_sink(ret), is_type_switch);
if (is_type_switch != NULL && *is_type_switch)
break;
}
else if (token->is_op(OPERATOR_LSQUARE))
- ret = this->index(this->verify_not_sink(ret));
+ {
+ whole_is_parenthesized = false;
+ ret = this->index(this->verify_not_sink(ret));
+ }
else
break;
}
+ if (whole_is_parenthesized && is_parenthesized != NULL)
+ *is_parenthesized = true;
+
return ret;
}
Expression* start;
if (!this->peek_token()->is_op(OPERATOR_COLON))
- start = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ start = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
else
{
mpz_t zero;
if (this->advance_token()->is_op(OPERATOR_RSQUARE))
end = Expression::make_nil(this->location());
else
- end = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ end = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
}
if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
error_at(this->location(), "missing %<]%>");
// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
// guard (var := expr.("type") using the literal keyword "type").
+// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
+// if the entire expression is in parentheses.
+
Expression*
Parse::expression(Precedence precedence, bool may_be_sink,
- bool may_be_composite_lit, bool* is_type_switch)
+ bool may_be_composite_lit, bool* is_type_switch,
+ bool *is_parenthesized)
{
Expression* left = this->unary_expr(may_be_sink, may_be_composite_lit,
- is_type_switch);
+ is_type_switch, is_parenthesized);
while (true)
{
return left;
}
+ if (is_parenthesized != NULL)
+ *is_parenthesized = false;
+
Operator op = token->op();
Location binop_location = token->location();
left = this->verify_not_sink(left);
Expression* right = this->expression(right_precedence, false,
may_be_composite_lit,
- NULL);
+ NULL, NULL);
left = Expression::make_binary(op, left, right, binop_location);
}
}
// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
// guard (var := expr.("type") using the literal keyword "type").
+// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
+// if the entire expression is in parentheses.
+
Expression*
Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch)
+ bool* is_type_switch, bool* is_parenthesized)
{
const Token* token = this->peek_token();
if (this->advance_token()->is_keyword(KEYWORD_CHAN))
{
Expression* expr = this->primary_expr(false, may_be_composite_lit,
- NULL);
+ NULL, NULL);
if (expr->is_error_expression())
return expr;
else if (!expr->is_type_expression())
Operator op = token->op();
this->advance_token();
- Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
+ Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL,
+ NULL);
if (expr->is_error_expression())
;
else if (op == OPERATOR_MULT && expr->is_type_expression())
}
else
return this->primary_expr(may_be_sink, may_be_composite_lit,
- is_type_switch);
+ is_type_switch, is_parenthesized);
}
// This is called for the obscure case of
may_be_composite_lit,
(p_type_switch == NULL
? NULL
- : &p_type_switch->found));
+ : &p_type_switch->found),
+ NULL);
if (p_type_switch != NULL && p_type_switch->found)
{
p_type_switch->name.clear();
go_assert(this->peek_token()->is_op(OPERATOR_CHANOP));
Location loc = this->location();
this->advance_token();
- Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
+ NULL);
Statement* s = Statement::make_send_statement(channel, val, loc);
this->gogo_->add_statement(s);
}
bool is_go = this->peek_token()->is_keyword(KEYWORD_GO);
Location stat_location = this->location();
- const Token* token = this->advance_token();
+ this->advance_token();
Location expr_location = this->location();
- bool is_parenthesized = token->is_op(OPERATOR_LPAREN);
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ bool is_parenthesized = false;
+ Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
+ &is_parenthesized);
Call_expression* call_expr = expr->call_expression();
if (is_parenthesized || call_expr == NULL)
{
cond = Expression::make_error(this->location());
}
if (cond == NULL)
- cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
+ cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL, NULL);
}
this->gogo_->start_block(this->location());
if (switch_val == NULL && !type_switch.found)
{
switch_val = this->expression(PRECEDENCE_NORMAL, false, false,
- &type_switch.found);
+ &type_switch.found, NULL);
if (type_switch.found)
{
type_switch.name.clear();
error_at(token_loc, "invalid variable name");
this->advance_token();
this->expression(PRECEDENCE_NORMAL, false, false,
- &type_switch.found);
+ &type_switch.found, NULL);
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
this->advance_token();
if (!this->peek_token()->is_op(OPERATOR_LCURLY))
// case rv := <-c:
this->advance_token();
Expression* e = this->expression(PRECEDENCE_NORMAL, false, false,
- NULL);
+ NULL, NULL);
Receive_expression* re = e->receive_expression();
if (re == NULL)
{
// case rv, rc := <-c:
this->advance_token();
Expression* e = this->expression(PRECEDENCE_NORMAL, false,
- false, NULL);
+ false, NULL, NULL);
Receive_expression* re = e->receive_expression();
if (re == NULL)
{
Expression* e;
if (saw_comma || !this->peek_token()->is_op(OPERATOR_CHANOP))
- e = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
+ e = this->expression(PRECEDENCE_NORMAL, true, true, NULL, NULL);
else
{
// case <-c:
*is_send = false;
this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
// The next token should be ':'. If it is '<-', then we have
// case <-c <- v:
}
*is_send = false;
this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
if (saw_comma)
{
// case v, e = <-c:
*is_send = true;
*channel = this->verify_not_sink(e);
this->advance_token();
- *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
return true;
}
return;
}
else
- *cond = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ *cond = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
error_at(this->location(), "expected semicolon");
else
error_at(this->location(), "too many variables for range clause");
this->advance_token();
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
+ Expression* expr = this->expression(PRECEDENCE_NORMAL, false, false, NULL,
+ NULL);
p_range_clause->range = expr;
bool any_new = false;
this->advance_token();
p_range_clause->range = this->expression(PRECEDENCE_NORMAL, false, false,
- NULL);
+ NULL, NULL);
p_range_clause->index = vals->front();
if (vals->size() == 1)