diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-ast-full-test.cc | 6 | ||||
-rw-r--r-- | gcc/rust/ast/rust-macro.h | 9 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 117 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.h | 25 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 9 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro6.rs | 11 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro7.rs | 13 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro8.rs | 12 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/macros7.rs | 26 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/macros8.rs | 25 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/macros9.rs | 26 |
11 files changed, 265 insertions, 14 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc index 3a1e295..5244501 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -2446,13 +2446,13 @@ MacroMatchRepetition::as_string () const str += "\n Op: "; switch (op) { - case ASTERISK: + case ANY: str += "*"; break; - case PLUS: + case ONE_OR_MORE: str += "+"; break; - case QUESTION_MARK: + case ZERO_OR_ONE: str += "?"; break; case NONE: diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index b5370d8..995b255 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -134,9 +134,9 @@ public: enum MacroRepOp { NONE, - ASTERISK, - PLUS, - QUESTION_MARK + ANY, + ONE_OR_MORE, + ZERO_OR_ONE, }; private: @@ -206,6 +206,9 @@ public: return MacroMatchType::Repetition; } + MacroRepOp get_op () const { return op; } + std::vector<std::unique_ptr<MacroMatch> > &get_matches () { return matches; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index dcfec7c..6885929 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -3520,6 +3520,7 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, for (auto &match : matcher.get_matches ()) { size_t offs_begin = source.get_offs (); + switch (match->get_macro_match_type ()) { case AST::MacroMatch::MacroMatchType::Fragment: { @@ -3598,12 +3599,122 @@ MacroExpander::match_token (Parser<MacroInvocLexer> &parser, AST::Token &token) } bool +MacroExpander::match_n_matches ( + Parser<MacroInvocLexer> &parser, + std::vector<std::unique_ptr<AST::MacroMatch>> &matches, size_t &match_amount, + size_t lo_bound, size_t hi_bound) +{ + match_amount = 0; + + const MacroInvocLexer &source = parser.get_token_source (); + while (true) + { + // If the current token is a closing macro delimiter, break away. + // TODO: Is this correct? + auto t_id = parser.peek_current_token ()->get_id (); + if (t_id == RIGHT_PAREN || t_id == RIGHT_SQUARE || t_id == RIGHT_CURLY) + break; + + bool valid_current_match = false; + for (auto &match : matches) + { + size_t offs_begin = source.get_offs (); + switch (match->get_macro_match_type ()) + { + case AST::MacroMatch::MacroMatchType::Fragment: { + AST::MacroMatchFragment *fragment + = static_cast<AST::MacroMatchFragment *> (match.get ()); + valid_current_match = match_fragment (parser, *fragment); + + // matched fragment get the offset in the token stream + size_t offs_end = source.get_offs (); + sub_stack.peek ().insert ( + {fragment->get_ident (), + {fragment->get_ident (), offs_begin, offs_end}}); + } + break; + + case AST::MacroMatch::MacroMatchType::Tok: { + AST::Token *tok = static_cast<AST::Token *> (match.get ()); + valid_current_match = match_token (parser, *tok); + } + break; + + case AST::MacroMatch::MacroMatchType::Repetition: { + AST::MacroMatchRepetition *rep + = static_cast<AST::MacroMatchRepetition *> (match.get ()); + valid_current_match = match_repetition (parser, *rep); + } + break; + + case AST::MacroMatch::MacroMatchType::Matcher: { + AST::MacroMatcher *m + = static_cast<AST::MacroMatcher *> (match.get ()); + valid_current_match = match_matcher (parser, *m); + } + break; + } + } + // If we've encountered an error once, stop trying to match more + // repetitions + if (!valid_current_match) + break; + + match_amount++; + + // Break early if we notice there's too many expressions already + if (hi_bound && match_amount > hi_bound) + break; + } + + // Check if the amount of matches we got is valid: Is it more than the lower + // bound and less than the higher bound? + if (!hi_bound) // infinite amount, no upper bound + return match_amount >= lo_bound; + else + return match_amount >= lo_bound && match_amount <= hi_bound; +} + +bool MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser, AST::MacroMatchRepetition &rep) { - // TODO - gcc_unreachable (); - return false; + size_t match_amount = 0; + bool res = false; + + std::string lo_str; + std::string hi_str; + switch (rep.get_op ()) + { + case AST::MacroMatchRepetition::MacroRepOp::ANY: + lo_str = "0"; + hi_str = "+inf"; + res = match_n_matches (parser, rep.get_matches (), match_amount); + break; + case AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE: + lo_str = "1"; + hi_str = "+inf"; + res = match_n_matches (parser, rep.get_matches (), match_amount, 1); + break; + case AST::MacroMatchRepetition::MacroRepOp::ZERO_OR_ONE: + lo_str = "0"; + hi_str = "1"; + res = match_n_matches (parser, rep.get_matches (), match_amount, 0, 1); + break; + default: + gcc_unreachable (); + } + + if (!res) + rust_error_at (rep.get_match_locus (), + "invalid amount of matches for macro invocation. Expected " + "between %s and %s, got %lu", + lo_str.c_str (), hi_str.c_str (), match_amount); + + rust_debug_loc (rep.get_match_locus (), "%s matched %lu times", + res ? "successfully" : "unsuccessfully", match_amount); + + return res; } AST::ASTFragment diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index d8a2d50..d49c775 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -193,6 +193,31 @@ struct MacroExpander bool match_matcher (Parser<MacroInvocLexer> &parser, AST::MacroMatcher &matcher); + /** + * Match any amount of matches + * + * @param parser Parser to use for matching + * @param matches All consecutive matches to identify + * @param match_amount Reference in which to store the ammount of succesful + * and valid matches + * + * @param lo_bound Lower bound of the matcher. When specified, the matcher + * will only succeed if it parses at *least* `lo_bound` fragments. If + * unspecified, the matcher could succeed when parsing 0 fragments. + * + * @param hi_bound Higher bound of the matcher. When specified, the matcher + * will only succeed if it parses *less than* `hi_bound` fragments. If + * unspecified, the matcher could succeed when parsing an infinity of + * fragments. + * + * @return true if matching was successful and within the given limits, false + * otherwise + */ + bool match_n_matches (Parser<MacroInvocLexer> &parser, + std::vector<std::unique_ptr<AST::MacroMatch>> &matches, + size_t &match_amount, size_t lo_bound = 0, + size_t hi_bound = 0); + static std::vector<std::unique_ptr<AST::Token>> substitute_tokens (std::vector<std::unique_ptr<AST::Token>> &input, std::vector<std::unique_ptr<AST::Token>> ¯o, diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 2260a95..af8f625 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -1991,20 +1991,19 @@ Parser<ManagedTokenSource>::parse_macro_match_repetition () // parse repetition operator t = lexer.peek_token (); - AST::MacroMatchRepetition::MacroRepOp op - = AST::MacroMatchRepetition::ASTERISK; + AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE; switch (t->get_id ()) { case ASTERISK: - op = AST::MacroMatchRepetition::ASTERISK; + op = AST::MacroMatchRepetition::ANY; lexer.skip_token (); break; case PLUS: - op = AST::MacroMatchRepetition::PLUS; + op = AST::MacroMatchRepetition::ONE_OR_MORE; lexer.skip_token (); break; case QUESTION_MARK: - op = AST::MacroMatchRepetition::QUESTION_MARK; + op = AST::MacroMatchRepetition::ZERO_OR_ONE; lexer.skip_token (); break; default: diff --git a/gcc/testsuite/rust/compile/macro6.rs b/gcc/testsuite/rust/compile/macro6.rs new file mode 100644 index 0000000..e59155c --- /dev/null +++ b/gcc/testsuite/rust/compile/macro6.rs @@ -0,0 +1,11 @@ +macro_rules! zero_or_one { + ($($a:literal)?) => { // { dg-error "invalid amount of matches for macro invocation. Expected between 0 and 1, got 2" } + f() + } +} + +fn main() { + zero_or_one!(); + zero_or_one!(14); + zero_or_one!(125 12 "gcc"); // { dg-error "Failed to match any rule within macro" } +} diff --git a/gcc/testsuite/rust/compile/macro7.rs b/gcc/testsuite/rust/compile/macro7.rs new file mode 100644 index 0000000..b57c5cb --- /dev/null +++ b/gcc/testsuite/rust/compile/macro7.rs @@ -0,0 +1,13 @@ +fn f() {} + +macro_rules! one_or_more { + ($($a:literal)+) => { // { dg-error "invalid amount of matches for macro invocation" } + f() + } +} + +fn main() { + one_or_more!(1 1 1 1 1 1 1 1 1 1 1 "rust" 'c'); + one_or_more!(1); + one_or_more!(); // { dg-error "Failed to match any rule within macro" } +} diff --git a/gcc/testsuite/rust/compile/macro8.rs b/gcc/testsuite/rust/compile/macro8.rs new file mode 100644 index 0000000..756d5b0 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro8.rs @@ -0,0 +1,12 @@ +fn f() {} + +macro_rules! expr { + ($($a:expr)?) => { + f() + } +} + +fn main() { + expr!(); + expr!(14); +} diff --git a/gcc/testsuite/rust/execute/torture/macros7.rs b/gcc/testsuite/rust/execute/torture/macros7.rs new file mode 100644 index 0000000..c1e13e3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros7.rs @@ -0,0 +1,26 @@ +// { dg-output "any\nany\nany\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "any\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { printf(c_p); } +} + +macro_rules! any { + ($($a:expr)*) => { + f() + } +} + +fn main() -> i32 { + any!(); + any!(a + b); + any!(a + b 14 "gcc"); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros8.rs b/gcc/testsuite/rust/execute/torture/macros8.rs new file mode 100644 index 0000000..2f1e238 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros8.rs @@ -0,0 +1,25 @@ +// { dg-output "zo1\nzo1\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "zo1\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { printf(c_p); } +} + +macro_rules! zero_or_one { + ($($a:expr)?) => { + f() + } +} + +fn main() -> i32 { + zero_or_one!(); + zero_or_one!(f()); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros9.rs b/gcc/testsuite/rust/execute/torture/macros9.rs new file mode 100644 index 0000000..22dec2a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros9.rs @@ -0,0 +1,26 @@ +// { dg-output "oom\noom\noom\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "oom\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { printf(c_p); } +} + +macro_rules! one_or_more { + ($($a:expr)+) => { + f() + } +} + +fn main() -> i32 { + one_or_more!(f()); + one_or_more!(f() f()); + one_or_more!(f() f() 15 + 12); + + 0 +} |