From f178ff39334ac2fb33de0d6c3e6ec8fb7714e8da Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 9 Oct 2022 16:08:09 +0900 Subject: Allow abbreviated dump options with additional options --- ruby.c | 50 +++++++++++++++++++++++++++++++++++++------ test/ruby/test_rubyoptions.rb | 5 +++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/ruby.c b/ruby.c index cddd9c0e3d..752498f66c 100644 --- a/ruby.c +++ b/ruby.c @@ -156,6 +156,9 @@ enum dump_flag_bits { dump_version_v, dump_error_tolerant, EACH_DUMPS(DEFINE_DUMP, COMMA), + dump_error_tolerant_bits = (DUMP_BIT(yydebug) | + DUMP_BIT(parsetree) | + DUMP_BIT(parsetree_with_comment)), dump_exit_bits = (DUMP_BIT(yydebug) | DUMP_BIT(syntax) | DUMP_BIT(parsetree) | DUMP_BIT(parsetree_with_comment) | DUMP_BIT(insns) | DUMP_BIT(insns_without_opt)) @@ -900,14 +903,16 @@ name_match_p(const char *name, const char *str, size_t len) if (len == 0) return 0; while (1) { while (TOLOWER(*str) == *name) { - if (!--len || !*++str) return 1; + if (!--len) return 1; ++name; + ++str; } if (*str != '-' && *str != '_') return 0; while (ISALNUM(*name)) name++; if (*name != '-' && *name != '_') return 0; ++name; ++str; + if (--len == 0) return 1; } } @@ -1013,16 +1018,49 @@ debug_option(const char *str, int len, void *arg) rb_warn("debug features are [%.*s].", (int)strlen(list), list); } +static int +memtermspn(const char *str, char term, int len) +{ + RUBY_ASSERT(len >= 0); + if (len <= 0) return 0; + const char *next = memchr(str, term, len); + return next ? (int)(next - str) : len; +} + +static const char additional_opt_sep = '+'; + +static unsigned int +dump_additional_option(const char *str, int len, unsigned int bits, const char *name) +{ + int w; + for (; len-- > 0 && *str++ == additional_opt_sep; len -= w, str += w) { + w = memtermspn(str, additional_opt_sep, len); +#define SET_ADDITIONAL(bit) if (NAME_MATCH_P(#bit, str, w)) { \ + if (bits & DUMP_BIT(bit)) \ + rb_warn("duplicate option to dump %s: `%.*s'", name, w, str); \ + bits |= DUMP_BIT(bit); \ + continue; \ + } + if (dump_error_tolerant_bits & bits) { + SET_ADDITIONAL(error_tolerant); + } + rb_warn("don't know how to dump %s with `%.*s'", name, w, str); + } + return bits; +} + static void dump_option(const char *str, int len, void *arg) { static const char list[] = EACH_DUMPS(LITERAL_NAME_ELEMENT, ", "); -#define NAME_MATCH_TOLERANT_P(name) (len >= 15 && NAME_MATCH_P(#name "+error-tolerant", str, len)) - if (NAME_MATCH_TOLERANT_P(yydebug) || NAME_MATCH_TOLERANT_P(parsetree) || NAME_MATCH_TOLERANT_P(parsetree_with_comment)) { - *(unsigned int *)arg |= DUMP_BIT(error_tolerant); - len -= 15; + int w = memtermspn(str, additional_opt_sep, len); + +#define SET_WHEN_DUMP(bit) \ + if (NAME_MATCH_P(#bit, (str), (w))) { \ + *(unsigned int *)arg |= \ + dump_additional_option(str + w, len - w, DUMP_BIT(bit), #bit); \ + return; \ } -#define SET_WHEN_DUMP(bit) SET_WHEN(#bit, DUMP_BIT(bit), str, len) EACH_DUMPS(SET_WHEN_DUMP, ;); rb_warn("don't know how to dump `%.*s',", len, str); rb_warn("but only [%.*s].", (int)strlen(list), list); diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index cf6829cf88..0198bbd900 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -1001,8 +1001,7 @@ class TestRubyOptions < Test::Unit::TestCase stderr = [] Tempfile.create(%w"bug10435- .rb") do |script| dir, base = File.split(script.path) - script.puts "abort ':run'" - script.close + File.write(script, "abort ':run'\n") opts = ['-C', dir, '-r', "./#{base}", *opt] _, e = assert_in_out_err([*opts, '-ep'], "", //) stderr.concat(e) if e @@ -1026,6 +1025,8 @@ class TestRubyOptions < Test::Unit::TestCase def test_dump_parsetree_with_rflag assert_norun_with_rflag('--dump=parsetree') assert_norun_with_rflag('--dump=parsetree', '-e', '#frozen-string-literal: true') + assert_norun_with_rflag('--dump=parsetree+error_tolerant') + assert_norun_with_rflag('--dump=parse+error_tolerant') end def test_dump_insns_with_rflag -- cgit v1.2.3