aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/parse
diff options
context:
space:
mode:
authorSimplyTheOther <simplytheother@gmail.com>2020-10-01 14:55:15 +0800
committerPhilip Herron <philip.herron@embecosm.com>2020-11-28 21:13:21 +0000
commit2ed062a0be3e2c6e7bd50d25d9ede336fad7be38 (patch)
tree3eb122d4ae25035a067ddaf78576541a75fdf9b7 /gcc/rust/parse
parent4cfd93746242dc6e73f4fa71520bb361a2d6de4a (diff)
downloadgcc-2ed062a0be3e2c6e7bd50d25d9ede336fad7be38.zip
gcc-2ed062a0be3e2c6e7bd50d25d9ede336fad7be38.tar.gz
gcc-2ed062a0be3e2c6e7bd50d25d9ede336fad7be38.tar.bz2
Improved parsing of MatchExpr (and AST structure)
Fixed compilation errors Fixed accidental break out of loop when expr_with_block when parsing match expr
Diffstat (limited to 'gcc/rust/parse')
-rw-r--r--gcc/rust/parse/rust-parse-impl.h128
-rw-r--r--gcc/rust/parse/rust-parse.h3
2 files changed, 103 insertions, 28 deletions
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 286d7a4..468312e 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -3895,7 +3895,8 @@ Parser<ManagedTokenSource>::parse_struct (
lexer.skip_token ();
// parse struct fields, if any
- std::vector<AST::StructField> struct_fields = parse_struct_fields ();
+ std::vector<AST::StructField> struct_fields
+ = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
if (!skip_token (RIGHT_CURLY))
{
@@ -3938,42 +3939,69 @@ Parser<ManagedTokenSource>::parse_struct_fields ()
// Return empty field list if no field there
if (initial_field.is_error ())
- {
- return fields;
- }
+ return fields;
fields.push_back (std::move (initial_field));
- // maybe think of a better control structure here - do-while with an initial
- // error state? basically, loop through field list until can't find any more
- // params
- while (true)
+ while (lexer.peek_token ()->get_id () == COMMA)
{
- if (lexer.peek_token ()->get_id () != COMMA)
+ lexer.skip_token ();
+
+ AST::StructField field = parse_struct_field ();
+
+ if (field.is_error ())
{
+ // would occur with trailing comma, so allowed
break;
}
- // skip comma if applies
+ fields.push_back (std::move (field));
+ }
+
+ fields.shrink_to_fit ();
+ return fields;
+ // TODO: template if possible (parse_non_ptr_seq)
+}
+
+// Parses struct fields in struct declarations.
+template <typename ManagedTokenSource>
+template <typename EndTokenPred>
+std::vector<AST::StructField>
+Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
+{
+ std::vector<AST::StructField> fields;
+
+ AST::StructField initial_field = parse_struct_field ();
+
+ // Return empty field list if no field there
+ if (initial_field.is_error ())
+ return fields;
+
+ fields.push_back (std::move (initial_field));
+
+ while (lexer.peek_token ()->get_id () == COMMA)
+ {
lexer.skip_token ();
- AST::StructField field = parse_struct_field ();
+ if (is_end_tok (lexer.peek_token ()->get_id ()))
+ break;
- if (!field.is_error ())
- {
- fields.push_back (std::move (field));
- }
- else
+ AST::StructField field = parse_struct_field ();
+ if (field.is_error ())
{
- // this would occur with a trailing comma, which is allowed
- break;
+ /* TODO: should every field be ditched just because one couldn't be
+ * parsed? */
+ rust_error_at (lexer.peek_token ()->get_locus (),
+ "failed to parse struct field in struct fields");
+ return {};
}
+
+ fields.push_back (std::move (field));
}
+ fields.shrink_to_fit ();
return fields;
-
- // TODO: this shares basically all code with function params and tuple fields
- // - templates?
+ // TODO: template if possible (parse_non_ptr_seq)
}
// Parses a single struct field (in a struct definition). Does not parse commas.
@@ -4257,7 +4285,8 @@ Parser<ManagedTokenSource>::parse_enum_item ()
// struct enum item
lexer.skip_token ();
- std::vector<AST::StructField> struct_fields = parse_struct_fields ();
+ std::vector<AST::StructField> struct_fields
+ = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
if (!skip_token (RIGHT_CURLY))
{
@@ -4326,7 +4355,8 @@ Parser<ManagedTokenSource>::parse_union (
/* parse union inner items as "struct fields" because hey, syntax reuse. Spec
* said so. */
- std::vector<AST::StructField> union_fields = parse_struct_fields ();
+ std::vector<AST::StructField> union_fields
+ = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
if (!skip_token (RIGHT_CURLY))
{
@@ -8017,18 +8047,20 @@ Parser<ManagedTokenSource>::parse_match_expr (
std::vector<AST::Attribute> inner_attrs = parse_inner_attributes ();
// parse match arms (if they exist)
- std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
+ // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
+ std::vector<AST::MatchCase> match_arms;
- // FIXME: absolute worst control structure ever
// parse match cases
- while (true)
+ while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
{
// parse match arm itself, which is required
AST::MatchArm arm = parse_match_arm ();
if (arm.is_error ())
{
- // not necessarily an error
- break;
+ // TODO is this worth throwing everything away?
+ rust_error_at (lexer.peek_token ()->get_locus (),
+ "failed to parse match arm in match arms");
+ return nullptr;
}
if (!skip_token (MATCH_ARROW))
@@ -8038,6 +8070,45 @@ Parser<ManagedTokenSource>::parse_match_expr (
return nullptr;
}
+ std::unique_ptr<AST::Expr> expr = parse_expr ();
+ if (expr == nullptr)
+ {
+ rust_error_at (lexer.peek_token ()->get_locus (),
+ "failed to parse expr in match arm in match expr");
+ // skip somewhere?
+ return nullptr;
+ }
+ bool is_expr_without_block = expr->is_expr_without_block ();
+
+ // construct match case expr and add to cases
+ match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr)));
+
+ // handle comma presence
+ if (lexer.peek_token ()->get_id () != COMMA)
+ {
+ if (!is_expr_without_block)
+ {
+ // allowed even if not final case
+ continue;
+ }
+ else if (is_expr_without_block
+ && lexer.peek_token ()->get_id () != RIGHT_CURLY)
+ {
+ // not allowed if not final case
+ rust_error_at (lexer.peek_token ()->get_locus (),
+ "exprwithoutblock requires comma after match case "
+ "expression in match arm (if not final case)");
+ return nullptr;
+ }
+ else
+ {
+ // otherwise, must be final case, so fine
+ break;
+ }
+ }
+ lexer.skip_token ();
+
+#if 0
// branch on next token - if '{', block expr, otherwise just expr
if (lexer.peek_token ()->get_id () == LEFT_CURLY)
{
@@ -8089,6 +8160,7 @@ Parser<ManagedTokenSource>::parse_match_expr (
}
lexer.skip_token ();
}
+#endif
}
if (!skip_token (RIGHT_CURLY))
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index b2de05e..e2f3a78 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -189,6 +189,8 @@ private:
std::unique_ptr<AST::Struct>
parse_struct (AST::Visibility vis, std::vector<AST::Attribute> outer_attrs);
std::vector<AST::StructField> parse_struct_fields ();
+ template <typename EndTokenPred>
+ std::vector<AST::StructField> parse_struct_fields (EndTokenPred is_end_token);
AST::StructField parse_struct_field ();
std::vector<AST::TupleField> parse_tuple_fields ();
AST::TupleField parse_tuple_field ();
@@ -528,6 +530,7 @@ private:
= std::vector<AST::Attribute> (),
bool pratt_parse = false);
std::unique_ptr<AST::StructExprField> parse_struct_expr_field ();
+ bool will_be_expr_with_block ();
// Type-related
std::unique_ptr<AST::Type> parse_type ();