diff options
-rwxr-xr-x | lib/exe/bundle | 47 | ||||
-rwxr-xr-x | lib/exe/bundler | 4 | ||||
-rwxr-xr-x | lib/exe/irb | 11 | ||||
-rwxr-xr-x | lib/exe/racc | 306 | ||||
-rwxr-xr-x | lib/exe/racc2y | 195 | ||||
-rwxr-xr-x | lib/exe/rdoc | 44 | ||||
-rwxr-xr-x | lib/exe/ri | 12 | ||||
-rwxr-xr-x | lib/exe/y2racc | 339 | ||||
-rw-r--r-- | test/ruby/test_keyword.rb | 9 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | vm_method.c | 2 |
11 files changed, 969 insertions, 2 deletions
diff --git a/lib/exe/bundle b/lib/exe/bundle new file mode 100755 index 0000000000..b3b1b691d8 --- /dev/null +++ b/lib/exe/bundle @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Exit cleanly from an early interrupt +Signal.trap("INT") do + Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) + exit 1 +end + +base_path = File.expand_path("../lib", __dir__) + +if File.exist?(base_path) + require_relative "../lib/bundler" +else + require "bundler" +end + +# Check if an older version of bundler is installed +$LOAD_PATH.each do |path| + next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9 + err = String.new + err << "Looks like you have a version of bundler that's older than 0.9.\n" + err << "Please remove your old versions.\n" + err << "An easy way to do this is by running `gem cleanup bundler`." + abort(err) +end + +if File.exist?(base_path) + require_relative "../lib/bundler/friendly_errors" +else + require "bundler/friendly_errors" +end + +Bundler.with_friendly_errors do + if File.exist?(base_path) + require_relative "../lib/bundler/cli" + else + require "bundler/cli" + end + + # Allow any command to use --help flag to show help for that command + help_flags = %w[--help -h] + help_flag_used = ARGV.any? {|a| help_flags.include? a } + args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV + + Bundler::CLI.start(args, :debug => true) +end diff --git a/lib/exe/bundler b/lib/exe/bundler new file mode 100755 index 0000000000..d9131fe834 --- /dev/null +++ b/lib/exe/bundler @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +load File.expand_path("../bundle", __FILE__) diff --git a/lib/exe/irb b/lib/exe/irb new file mode 100755 index 0000000000..c64ee85fbd --- /dev/null +++ b/lib/exe/irb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# +# irb.rb - interactive ruby +# $Release Version: 0.9.6 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# + +require "irb" + +IRB.start(__FILE__) diff --git a/lib/exe/racc b/lib/exe/racc new file mode 100755 index 0000000000..5656b25e42 --- /dev/null +++ b/lib/exe/racc @@ -0,0 +1,306 @@ +#!/usr/bin/env ruby +# +# $Id$ +# +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# see the file "COPYING". + +require 'racc/static' +require 'optparse' + +def main + output = nil + debug_parser = false + make_logfile = false + logfilename = nil + make_executable = false + rubypath = nil + embed_runtime = false + debug_flags = Racc::DebugFlags.new + line_convert = true + line_convert_all = false + omit_action_call = true + superclass = nil + check_only = false + verbose = false + profiler = RaccProfiler.new(false) + + parser = OptionParser.new + parser.banner = "Usage: #{File.basename($0)} [options] <input>" + parser.on('-o', '--output-file=PATH', + 'output file name [<input>.tab.rb]') {|name| + output = name + } + parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl| + debug_parser = fl + } + parser.on('-g', 'Equivalent to -t (obsolete).') {|fl| + $stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE + debug_parser = fl + } + parser.on('-v', '--verbose', + 'Creates <filename>.output log file.') {|fl| + make_logfile = fl + } + parser.on('-O', '--log-file=PATH', + 'Log file name [<input>.output]') {|path| + make_logfile = true + logfilename = path + } + parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path| + executable = true + rubypath = (path == 'ruby' ? nil : path) + } + parser.on('-E', '--embedded', "Embeds Racc runtime in output.") { + embed_runtime = true + } + parser.on('--line-convert-all', 'Converts line numbers of user codes.') { + line_convert_all = true + } + parser.on('-l', '--no-line-convert', 'Never convert line numbers.') { + line_convert = false + line_convert_all = false + } + parser.on('-a', '--no-omit-actions', 'Never omit actions.') { + omit_action_call = false + } + parser.on('--superclass=CLASSNAME', + 'Uses CLASSNAME instead of Racc::Parser.') {|name| + superclass = name + } + parser.on('--runtime=FEATURE', + "Uses FEATURE instead of 'racc/parser'") {|feat| + runtime = feature + } + parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl| + check_only = fl + } + parser.on('-S', '--output-status', 'Outputs internal status time to time.') { + verbose = true + } + parser.on('-P', 'Enables generator profile') { + profiler = RaccProfiler.new(true) + } + parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags| + debug_flags = Racc::DebugFlags.parse_option_string(flags) + } + #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') { + # Racc.const_set :Racc_No_Extentions, true + #} + parser.on('--version', 'Prints version and quit.') { + puts "racc version #{Racc::Version}" + exit 0 + } + parser.on('--runtime-version', 'Prints runtime version and quit.') { + printf "racc runtime version %s (rev. %s); %s\n", + Racc::Parser::Racc_Runtime_Version, + Racc::Parser::Racc_Runtime_Revision, + if Racc::Parser.racc_runtime_type == 'ruby' + sprintf('ruby core version %s (rev. %s)', + Racc::Parser::Racc_Runtime_Core_Version_R, + Racc::Parser::Racc_Runtime_Core_Revision_R) + else + sprintf('c core version %s (rev. %s)', + Racc::Parser::Racc_Runtime_Core_Version_C, + Racc::Parser::Racc_Runtime_Core_Revision_C) + end + exit 0 + } + parser.on('--copyright', 'Prints copyright and quit.') { + puts Racc::Copyright + exit 0 + } + parser.on('--help', 'Prints this message and quit.') { + puts parser.help + exit 1 + } + begin + parser.parse! + rescue OptionParser::ParseError => err + $stderr.puts err.message + $stderr.puts parser.help + exit 1 + end + if ARGV.empty? + $stderr.puts 'no input' + exit 1 + end + if ARGV.size > 1 + $stderr.puts 'too many input' + exit 1 + end + input = ARGV[0] + + begin + $stderr.puts 'Parsing grammar file...' if verbose + result = profiler.section('parse') { + parser = Racc::GrammarFileParser.new(debug_flags) + parser.parse(File.read(input), File.basename(input)) + } + if check_only + $stderr.puts 'syntax ok' + exit 0 + end + + $stderr.puts 'Generating LALR states...' if verbose + states = profiler.section('nfa') { + Racc::States.new(result.grammar).nfa + } + + $stderr.puts "Resolving #{states.size} states..." if verbose + profiler.section('dfa') { + states.dfa + } + + $stderr.puts 'Creating parser file...' if verbose + params = result.params.dup + # Overwrites parameters given by a grammar file with command line options. + params.superclass = superclass if superclass + params.omit_action_call = true if omit_action_call + # From command line option + if make_executable + params.make_executable = true + params.interpreter = rubypath + end + params.debug_parser = debug_parser + params.convert_line = line_convert + params.convert_line_all = line_convert_all + params.embed_runtime = embed_runtime + profiler.section('generation') { + generator = Racc::ParserFileGenerator.new(states, params) + generator.generate_parser_file(output || make_filename(input, '.tab.rb')) + } + + if make_logfile + profiler.section('logging') { + $stderr.puts 'Creating log file...' if verbose + logfilename ||= make_filename(output || File.basename(input), '.output') + File.open(logfilename, 'w') {|f| + Racc::LogFileGenerator.new(states, debug_flags).output f + } + } + end + if debug_flags.status_logging + log_useless states.grammar + log_conflict states + else + report_useless states.grammar + report_conflict states + end + + profiler.report + rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err + raise if $DEBUG or debug_flags.any? + lineno = err.message.slice(/\A\d+:/).to_s + $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}" + exit 1 + end +end + +def make_filename(path, suffix) + path.sub(/(?:\..*?)?\z/, suffix) +end + +def report_conflict(states) + if states.should_report_srconflict? + $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts" + end + if states.rrconflict_exist? + $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts" + end +end + +def log_conflict(states) + logging('w') {|f| + f.puts "ex#{states.grammar.n_expected_srconflicts}" + if states.should_report_srconflict? + f.puts "sr#{states.n_srconflicts}" + end + if states.rrconflict_exist? + f.puts "rr#{states.n_rrconflicts}" + end + } +end + +def report_useless(grammar) + if grammar.useless_nonterminal_exist? + $stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals" + end + if grammar.useless_rule_exist? + $stderr.puts "#{grammar.n_useless_rules} useless rules" + end + if grammar.start.useless? + $stderr.puts 'fatal: start symbol does not derive any sentence' + end +end + +def log_useless(grammar) + logging('a') {|f| + if grammar.useless_nonterminal_exist? + f.puts "un#{grammar.n_useless_nonterminals}" + end + if grammar.useless_rule_exist? + f.puts "ur#{grammar.n_useless_rules}" + end + } +end + +def logging(mode, &block) + File.open("log/#{File.basename(ARGV[0])}", mode, &block) +end + +class RaccProfiler + def initialize(really) + @really = really + @log = [] + unless ::Process.respond_to?(:times) + # Ruby 1.6 + @class = ::Time + else + @class = ::Process + end + end + + def section(name) + if @really + t1 = @class.times.utime + result = yield + t2 = @class.times.utime + @log.push [name, t2 - t1] + result + else + yield + end + end + + def report + return unless @really + f = $stderr + total = cumulative_time() + f.puts '--task-----------+--sec------+---%-' + @log.each do |name, time| + f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i + end + f.puts '-----------------+-----------+-----' + f.printf "%-20s%s\n", 'total', pjust(total,4,4) + end + + private + + def cumulative_time + t = @log.inject(0) {|sum, (name, time)| sum + time } + t == 0 ? 0.01 : t + end + + def pjust(num, i, j) + m = /(\d+)(\.\d+)?/.match(num.to_s) + str = m[1].rjust(i) + str.concat m[2].ljust(j+1)[0,j+1] if m[2] + str + end +end + +main diff --git a/lib/exe/racc2y b/lib/exe/racc2y new file mode 100755 index 0000000000..f88d73ed2c --- /dev/null +++ b/lib/exe/racc2y @@ -0,0 +1,195 @@ +#!/usr/local/bin/ruby +# +# $Id$ +# +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is feee software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# For details of the LGPL, see the file "COPYING". +# + +require 'racc/grammarfileparser' +require 'racc/info' +require 'optparse' + +def main + @with_action = true + with_header = false + with_inner = false + with_footer = false + output = nil + parser = OptionParser.new + parser.banner = "Usage: #{File.basename($0)} [-AHIF] [-oFILENAME] GRAMMARFILE" + parser.on('-o', '--output=FILENAME', 'output file name [<input>.yacc]') {|name| + output = name + } + parser.on('-A', '--without-action', 'Does not include actions.') { + @with_action = false + } + parser.on('-H', '--with-header', 'Includes header part.') { + with_header = true + } + parser.on('-I', '--with-inner', 'Includes inner part.') { + with_inner = true + } + parser.on('-F', '--with-footer', 'Includes footer part.') { + with_footer = true + } + parser.on('--version', 'Prints version and quit.') { + puts "racc2y version #{Racc::Version}" + exit 0 + } + parser.on('--copyright', 'Prints copyright and quit.') { + puts Racc::Copyright + exit 0 + } + parser.on('--help', 'Prints this message and quit.') { + puts parser.help + exit 1 + } + begin + parser.parse! + rescue OptionParser::ParseError => err + $stderr.puts err.message + $stderr.puts parser.help + exit 1 + end + if ARGV.empty? + $stderr.puts "no input file" + exit 1 + end + unless ARGV.size == 1 + $stderr.puts "too many inputs" + exit 1 + end + input = ARGV[0] + + begin + result = Racc::GrammarFileParser.parse_file(input) + result.grammar.init + File.open(output || "#{input}.yacc", 'w') {|f| + f.puts "/* generated from #{input} */" + if with_header + f.puts + f.puts '%{' + print_user_codes f, result.params.header + f.puts '%}' + end + f.puts + print_terminals f, result.grammar + f.puts + print_precedence_table f, precedence_table(result.grammar) + f.puts + f.puts '%%' + print_grammar f, result.grammar + f.puts '%%' + if with_inner + f.puts '/*---- inner ----*/' + print_user_codes f, result.params.inner + end + if with_footer + f.puts '/*---- footer ----*/' + print_user_codes f, result.params.footer + end + } + rescue SystemCallError => err + $stderr.puts err.message + exit 1 + end +end + +def print_terminals(f, grammar) + init_indent = '%token'.size + f.print '%token' + columns = init_indent + grammar.symboltable.each_terminal do |t| + next unless t.terminal? + next if t.dummy? + next if t == grammar.symboltable.anchor + next if t == grammar.symboltable.error + unless t.value.kind_of?(String) + if columns > 60 + f.puts + f.print ' ' * init_indent + columns = init_indent + end + columns += f.write(" #{yacc_symbol(t)}") + end + end + f.puts +end + +def precedence_table(grammar) + table = [] + grammar.symboltable.select {|sym| sym.precedence }.each do |sym| + (table[sym.prec] ||= [sym.assoc]).push sym + end + table.compact +end + +def print_precedence_table(f, table) + return if table.empty? + f.puts '/* precedance table */' + table.each do |syms| + assoc = syms.shift + f.printf '%%%-8s ', assoc.to_s.downcase + f.puts syms.map {|s| yacc_symbol(s) }.join(' ') + end + f.puts +end + +def print_grammar(f, grammar) + prev_target = nil + indent = 10 + embactions = [] + grammar.each do |rule| + if rule.target.dummy? + embactions.push rule.action unless rule.action.empty? + next + end + if rule.target == prev_target + f.print ' ' * indent, '|' + else + prev_target = rule.target + f.printf "\n%-10s:", yacc_symbol(prev_target) + end + rule.symbols.each do |s| + if s.dummy? # target of dummy rule for embedded action + f.puts + print_action f, embactions.shift, indent + f.print ' ' * (indent + 1) + else + f.print ' ', yacc_symbol(s) + end + end + if rule.specified_prec + f.print ' %prec ', yacc_symbol(rule.specified_prec) + end + f.puts + unless rule.action.empty? + print_action f, rule.action, indent + end + end +end + +def print_action(f, action, indent) + return unless @with_action + f.print ' ' * (indent + 4), "{\n" + f.print ' ' * (indent + 6), action.source.text.strip, "\n" + f.print ' ' * (indent + 4) , "}\n" +end + +def print_user_codes(f, srcs) + return if srcs.empty? + srcs.each do |src| + f.puts src.text + end +end + +def yacc_symbol(s) + s.to_s.gsub('"', "'") +end + +main diff --git a/lib/exe/rdoc b/lib/exe/rdoc new file mode 100755 index 0000000000..aaa23292df --- /dev/null +++ b/lib/exe/rdoc @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby +# +# RDoc: Documentation tool for source code +# (see lib/rdoc/rdoc.rb for more information) +# +# Copyright (c) 2003 Dave Thomas +# Released under the same terms as Ruby + +begin + gem 'rdoc' +rescue NameError => e # --disable-gems + raise unless e.name == :gem +rescue Gem::LoadError +end + +require 'rdoc/rdoc' + +begin + r = RDoc::RDoc.new + r.document ARGV +rescue Errno::ENOSPC + $stderr.puts 'Ran out of space creating documentation' + $stderr.puts + $stderr.puts 'Please free up some space and try again' +rescue SystemExit + raise +rescue Exception => e + if $DEBUG_RDOC then + $stderr.puts e.message + $stderr.puts "#{e.backtrace.join "\n\t"}" + $stderr.puts + elsif Interrupt === e then + $stderr.puts + $stderr.puts 'Interrupted' + else + $stderr.puts "uh-oh! RDoc had a problem:" + $stderr.puts e.message + $stderr.puts + $stderr.puts "run with --debug for full backtrace" + end + + exit 1 +end + diff --git a/lib/exe/ri b/lib/exe/ri new file mode 100755 index 0000000000..7fbed0c099 --- /dev/null +++ b/lib/exe/ri @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby + +begin + gem 'rdoc' +rescue NameError => e # --disable-gems + raise unless e.name == :gem +rescue Gem::LoadError +end + +require 'rdoc/ri/driver' + +RDoc::RI::Driver.run ARGV diff --git a/lib/exe/y2racc b/lib/exe/y2racc new file mode 100755 index 0000000000..7933f94153 --- /dev/null +++ b/lib/exe/y2racc @@ -0,0 +1,339 @@ +#!/usr/local/bin/ruby +# +# $Id$ +# +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# For details of the GNU LGPL, see the file "COPYING". +# + +require 'racc/info' +require 'strscan' +require 'forwardable' +require 'optparse' + +def main + @with_action = true + @with_header = false + @with_usercode = false + cname = 'MyParser' + input = nil + output = nil + parser = OptionParser.new + parser.banner = "Usage: #{File.basename($0)} [-Ahu] [-c <classname>] [-o <filename>] <input>" + parser.on('-o', '--output=FILENAME', 'output file name [<input>.racc]') {|name| + output = name + } + parser.on('-c', '--classname=NAME', "Name of the parser class. [#{cname}]") {|name| + cname = name + } + parser.on('-A', '--without-action', 'Does not include actions.') { + @with_action = false + } + parser.on('-h', '--with-header', 'Includes header (%{...%}).') { + @with_header = true + } + parser.on('-u', '--with-user-code', 'Includes user code.') { + @with_usercode = true + } + parser.on('--version', 'Prints version and quit.') { + puts "y2racc version #{Racc::Version}" + exit 0 + } + parser.on('--copyright', 'Prints copyright and quit.') { + puts Racc::Copyright + exit 0 + } + parser.on('--help', 'Prints this message and quit.') { + puts parser.help + exit 1 + } + begin + parser.parse! + rescue OptionParser::ParseError => err + $stderr.puts err.message + $stderr.puts parser.help + exit 1 + end + if ARGV.empty? + $stderr.puts 'no input' + exit 1 + end + if ARGV.size > 1 + $stderr.puts 'too many input' + exit 1 + end + input = ARGV[0] + + begin + result = YaccFileParser.parse_file(input) + File.open(output || "#{input}.racc", 'w') {|f| + convert cname, result, f + } + rescue SystemCallError => err + $stderr.puts err.message + exit 1 + end +end + +def convert(classname, result, f) + init_indent = 'token'.size + f.puts %<# Converted from "#{result.filename}" by y2racc version #{Racc::Version}> + f.puts + f.puts "class #{classname}" + unless result.terminals.empty? + f.puts + f.print 'token' + columns = init_indent + result.terminals.each do |t| + if columns > 60 + f.puts + f.print ' ' * init_indent + columns = init_indent + end + columns += f.write(" #{t}") + end + f.puts + end + unless result.precedence_table.empty? + f.puts + f.puts 'preclow' + result.precedence_table.each do |assoc, toks| + f.printf " %-8s %s\n", assoc, toks.join(' ') unless toks.empty? + end + f.puts 'prechigh' + end + if result.start + f.puts + f.puts "start #{@start}" + end + + f.puts + f.puts 'rule' + texts = @with_action ? result.grammar : result.grammar_without_actions + texts.each do |text| + f.print text + end + + if @with_header and result.header + f.puts + f.puts '---- header' + f.puts result.header + end + if @with_usercode and result.usercode + f.puts + f.puts '---- footer' + f.puts result.usercode + end +end + +class ParseError < StandardError; end + +class StringScanner_withlineno + def initialize(src) + @s = StringScanner.new(src) + @lineno = 1 + end + + extend Forwardable + def_delegator "@s", :eos? + def_delegator "@s", :rest + + attr_reader :lineno + + def scan(re) + advance_lineno(@s.scan(re)) + end + + def scan_until(re) + advance_lineno(@s.scan_until(re)) + end + + def skip(re) + str = advance_lineno(@s.scan(re)) + str ? str.size : nil + end + + def getch + advance_lineno(@s.getch) + end + + private + + def advance_lineno(str) + @lineno += str.count("\n") if str + str + end +end + +class YaccFileParser + + Result = Struct.new(:terminals, :precedence_table, :start, + :header, :grammar, :usercode, :filename) + class Result # reopen + def initialize + super + self.terminals = [] + self.precedence_table = [] + self.start = nil + self.grammar = [] + self.header = nil + self.usercode = nil + self.filename = nil + end + + def grammar_without_actions + grammar().map {|text| text[0,1] == '{' ? '{}' : text } + end + end + + def YaccFileParser.parse_file(filename) + new().parse(File.read(filename), filename) + end + + def parse(src, filename = '-') + @result = Result.new + @filename = filename + @result.filename = filename + s = StringScanner_withlineno.new(src) + parse_header s + parse_grammar s + @result + end + + private + + COMMENT = %r</\*[^*]*\*+(?:[^/*][^*]*\*+)*/> + CHAR = /'((?:[^'\\]+|\\.)*)'/ + STRING = /"((?:[^"\\]+|\\.)*)"/ + + def parse_header(s) + skip_until_percent s + until s.eos? + case + when t = s.scan(/left/) + @result.precedence_table.push ['left', scan_symbols(s)] + when t = s.scan(/right/) + @result.precedence_table.push ['right', scan_symbols(s)] + when t = s.scan(/nonassoc/) + @result.precedence_table.push ['nonassoc', scan_symbols(s)] + when t = s.scan(/token/) + list = scan_symbols(s) + list.shift if /\A<(.*)>\z/ =~ list[0] + @result.terminals.concat list + when t = s.scan(/start/) + @result.start = scan_symbols(s)[0] + when s.skip(%r<(?: + type | union | expect | thong | binary | + semantic_parser | pure_parser | no_lines | + raw | token_table + )\b>x) + skip_until_percent s + when s.skip(/\{/) # header (%{...%}) + str = s.scan_until(/\%\}/) + str.chop! + str.chop! + @result.header = str + skip_until_percent s + when s.skip(/\%/) # grammar (%%...) + return + else + raise ParseError, "#{@filename}:#{s.lineno}: scan error" + end + end + end + + def skip_until_percent(s) + until s.eos? + s.skip /[^\%\/]+/ + next if s.skip(COMMENT) + return if s.getch == '%' + end + end + + def scan_symbols(s) + list = [] + until s.eos? + s.skip /\s+/ + if s.skip(COMMENT) + ; + elsif t = s.scan(CHAR) + list.push t + elsif t = s.scan(STRING) + list.push t + elsif s.skip(/\%/) + break + elsif t = s.scan(/\S+/) + list.push t + else + raise ParseError, "#{@filename}:#{@lineno}: scan error" + end + end + list + end + + def parse_grammar(s) + buf = [] + until s.eos? + if t = s.scan(/[^%'"{\/]+/) + buf.push t + break if s.eos? + end + if s.skip(/\{/) + buf.push scan_action(s) + elsif t = s.scan(/'(?:[^'\\]+|\\.)*'/) then buf.push t + elsif t = s.scan(/"(?:[^"\\]+|\\.)*"/) then buf.push t + elsif t = s.scan(COMMENT) then buf.push t + elsif s.skip(/%prec\b/) then buf.push '=' + elsif s.skip(/%%/) + @result.usercode = s.rest + break + else + buf.push s.getch + end + end + @result.grammar = buf + end + + def scan_action(s) + buf = '{' + nest = 1 + until s.eos? + if t = s.scan(%r<[^/{}'"]+>) + buf << t + break if s.eos? + elsif t = s.scan(COMMENT) + buf << t + elsif t = s.scan(CHAR) + buf << t + elsif t = s.scan(STRING) + buf << t + else + c = s.getch + buf << c + case c + when '{' + nest += 1 + when '}' + nest -= 1 + return buf if nest == 0 + end + end + end + $stderr.puts "warning: unterminated action in #{@filename}" + buf + end + +end + +unless Object.method_defined?(:funcall) + class Object + alias funcall __send__ + end +end + + +main diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index e9be530754..ab3c11e149 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -2741,6 +2741,11 @@ class TestKeywordArguments < Test::Unit::TestCase baz(*args) end + define_method(:block_splat) {|*args| } + ruby2_keywords :block_splat, def foo_bar_after_bmethod(*args) + bar(*args) + end + ruby2_keywords def foo_baz2(*args) baz(*args) baz(*args) @@ -2876,6 +2881,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal([1, h1], o.foo(:foo_baz, 1, :a=>1)) assert_equal([[1], h1], o.foo_foo_bar(1, :a=>1)) assert_equal([1, h1], o.foo_foo_baz(1, :a=>1)) + assert_equal([[1], h1], o.foo_bar_after_bmethod(1, :a=>1)) assert_equal([[1], h1], o.foo(:bar, 1, **h1)) assert_equal([1, h1], o.foo(:baz, 1, **h1)) @@ -2891,6 +2897,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal([1, h1], o.foo(:foo_baz, 1, **h1)) assert_equal([[1], h1], o.foo_foo_bar(1, **h1)) assert_equal([1, h1], o.foo_foo_baz(1, **h1)) + assert_equal([[1], h1], o.foo_bar_after_bmethod(1, **h1)) assert_equal([[h1], {}], o.foo(:bar, h1, **{})) assert_equal([h1], o.foo(:baz, h1, **{})) @@ -2906,6 +2913,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal([h1], o.foo(:foo_baz, h1, **{})) assert_equal([[h1], {}], o.foo_foo_bar(h1, **{})) assert_equal([h1], o.foo_foo_baz(h1, **{})) + assert_equal([[h1], {}], o.foo_bar_after_bmethod(h1, **{})) assert_warn(/Using the last argument as keyword parameters is deprecated.*The called method `bar'/m) do assert_equal([[1], h1], o.foo(:bar, 1, h1)) @@ -2923,6 +2931,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal([[1], h1], o.foo_bar(1, h1)) end assert_equal([1, h1], o.foo_baz(1, h1)) + assert_equal([[1], h1], o.foo_bar_after_bmethod(1, h1)) assert_equal([[1, h1, 1], {}], o.foo_mod(:bar, 1, :a=>1)) assert_equal([1, h1, 1], o.foo_mod(:baz, 1, :a=>1)) @@ -2,7 +2,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 3 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 159 +#define RUBY_PATCHLEVEL 160 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 2 diff --git a/vm_method.c b/vm_method.c index 779ef460a4..efe71601d1 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1864,7 +1864,7 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module) else { rb_warn("Skipping set of ruby2_keywords flag for %s (method accepts keywords or method does not accept argument splat)", rb_id2name(name)); } - return Qnil; + break; } } /* fallthrough */ |