diff --git a/NEWS.md b/NEWS.md
index 7157700816c3e8..7534539a21d2c9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -63,7 +63,7 @@ Note: We're only listing outstanding class updates.
* IO
- * `IO.select` accepts +Float::INFINITY+ as a timeout argument.
+ * `IO.select` accepts `Float::INFINITY` as a timeout argument.
[[Feature #20610]]
* Math
diff --git a/dir.c b/dir.c
index b934f2795c90e0..25ed59c668fab6 100644
--- a/dir.c
+++ b/dir.c
@@ -1480,7 +1480,7 @@ rb_dir_getwd_ospath(void)
VALUE cwd;
VALUE path_guard;
- path_guard = rb_imemo_tmpbuf_auto_free_pointer();
+ path_guard = rb_imemo_tmpbuf_new();
path = ruby_getcwd();
rb_imemo_tmpbuf_set_ptr(path_guard, path);
#ifdef __APPLE__
diff --git a/imemo.c b/imemo.c
index 02cba387bd22be..7cec33bc1edf00 100644
--- a/imemo.c
+++ b/imemo.c
@@ -48,23 +48,23 @@ rb_imemo_new(enum imemo_type type, VALUE v0, size_t size)
return (VALUE)obj;
}
-static rb_imemo_tmpbuf_t *
+VALUE
rb_imemo_tmpbuf_new(void)
{
- return IMEMO_NEW(rb_imemo_tmpbuf_t, imemo_tmpbuf, 0);
+ VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
+ NEWOBJ_OF(obj, rb_imemo_tmpbuf_t, 0, flags, sizeof(rb_imemo_tmpbuf_t), NULL);
+
+ return (VALUE)obj;
}
void *
rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
{
- void *ptr;
- rb_imemo_tmpbuf_t *tmpbuf;
-
/* Keep the order; allocate an empty imemo first then xmalloc, to
* get rid of potential memory leak */
- tmpbuf = rb_imemo_tmpbuf_new();
+ rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
*store = (VALUE)tmpbuf;
- ptr = ruby_xmalloc(size);
+ void *ptr = ruby_xmalloc(size);
tmpbuf->ptr = ptr;
tmpbuf->cnt = cnt;
@@ -97,7 +97,7 @@ rb_free_tmp_buffer(volatile VALUE *store)
rb_imemo_tmpbuf_t *
rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
{
- rb_imemo_tmpbuf_t *tmpbuf = rb_imemo_tmpbuf_new();
+ rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
tmpbuf->ptr = buf;
tmpbuf->next = old_heap;
tmpbuf->cnt = cnt;
diff --git a/internal/imemo.h b/internal/imemo.h
index de39102432ea84..de617d94c1bf5c 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -132,16 +132,15 @@ struct MEMO {
#ifndef RUBY_RUBYPARSER_H
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
#endif
+VALUE rb_imemo_tmpbuf_new(void);
rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
static inline enum imemo_type imemo_type(VALUE imemo);
static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type);
static inline bool imemo_throw_data_p(VALUE imemo);
static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer(void);
static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v);
static inline void *rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str);
static inline void MEMO_V1_SET(struct MEMO *m, VALUE v);
static inline void MEMO_V2_SET(struct MEMO *m, VALUE v);
@@ -200,12 +199,6 @@ rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data)
return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
}
-static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer(void)
-{
- return rb_imemo_new(imemo_tmpbuf, 0, sizeof(rb_imemo_tmpbuf_t));
-}
-
static inline void *
RB_IMEMO_TMPBUF_PTR(VALUE v)
{
@@ -220,7 +213,7 @@ rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr)
}
static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str)
+rb_imemo_tmpbuf_new_from_an_RString(VALUE str)
{
const void *src;
VALUE imemo;
@@ -230,7 +223,7 @@ rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str)
StringValue(str);
/* create tmpbuf to keep the pointer before xmalloc */
- imemo = rb_imemo_tmpbuf_auto_free_pointer();
+ imemo = rb_imemo_tmpbuf_new();
tmpbuf = (rb_imemo_tmpbuf_t *)imemo;
len = RSTRING_LEN(str);
src = RSTRING_PTR(str);
diff --git a/lib/optparse.rb b/lib/optparse.rb
index 06e33db1f533c4..ea6844b9558e5c 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -1855,7 +1855,7 @@ def permute(*argv, **keywords)
#
def permute!(argv = default_argv, **keywords)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
@@ -1908,13 +1908,16 @@ def getopts(*args, symbolize_names: false, **keywords)
single_options, *long_options = *args
result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
single_options.scan(/(.)(:)?/) do |opt, val|
if val
- result[opt] = nil
+ setter[opt, nil]
define("-#{opt} VAL")
else
- result[opt] = false
+ setter[opt, false]
define("-#{opt}")
end
end if single_options
@@ -1923,16 +1926,16 @@ def getopts(*args, symbolize_names: false, **keywords)
arg, desc = arg.split(';', 2)
opt, val = arg.split(':', 2)
if val
- result[opt] = val.empty? ? nil : val
+ setter[opt, (val unless val.empty?)]
define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
else
- result[opt] = false
+ setter[opt, false]
define("--#{opt}", *[desc].compact)
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, setter, **keywords)
+ result
end
#
@@ -1982,7 +1985,7 @@ def complete(typ, opt, icase = false, *pat) # :nodoc:
visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
}
exc = ambiguous ? AmbiguousOption : InvalidOption
- raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
private :complete
@@ -2273,9 +2276,10 @@ def recover(argv)
argv
end
+ DIR = File.join(__dir__, '')
def self.filter_backtrace(array)
unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ array.delete_if {|bt| bt.start_with?(DIR)}
end
array
end
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
index ac538a2e97ae43..2ca7da0bf2a5d5 100644
--- a/lib/prism/translation/ruby_parser.rb
+++ b/lib/prism/translation/ruby_parser.rb
@@ -152,7 +152,7 @@ def visit_assoc_splat_node(node)
# ^^
# ```
def visit_back_reference_read_node(node)
- s(node, :back_ref, node.name.name.delete_prefix("$").to_sym)
+ s(node, :back_ref, node.name.to_s.delete_prefix("$").to_sym)
end
# ```
diff --git a/numeric.c b/numeric.c
index 89cff8a730fc9c..de5b02aaf9eb41 100644
--- a/numeric.c
+++ b/numeric.c
@@ -6455,7 +6455,7 @@ Init_Numeric(void)
*
* If the platform supports denormalized numbers,
* there are numbers between zero and Float::MIN.
- * 0.0.next_float returns the smallest positive floating point number
+ * +0.0.next_float+ returns the smallest positive floating point number
* including denormalized numbers.
*/
rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
diff --git a/prism/prism.c b/prism/prism.c
index 06419d13789e45..2e202c37456ea5 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -18491,20 +18491,28 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return (pm_node_t *) node;
}
case PM_TOKEN_CHARACTER_LITERAL: {
- parser_lex(parser);
-
- pm_token_t opening = parser->previous;
- opening.type = PM_TOKEN_STRING_BEGIN;
- opening.end = opening.start + 1;
-
- pm_token_t content = parser->previous;
- content.type = PM_TOKEN_STRING_CONTENT;
- content.start = content.start + 1;
-
pm_token_t closing = not_provided(parser);
- pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
+ pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(
+ parser,
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_BEGIN,
+ .start = parser->current.start,
+ .end = parser->current.start + 1
+ },
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->current.start + 1,
+ .end = parser->current.end
+ },
+ &closing
+ );
+
pm_node_flag_set(node, parse_unescaped_encoding(parser));
+ // Skip past the character literal here, since now we have handled
+ // parser->explicit_encoding correctly.
+ parser_lex(parser);
+
// Characters can be followed by strings in which case they are
// automatically concatenated.
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
diff --git a/process.c b/process.c
index da9ce74027ce3c..0fb727db8af9f8 100644
--- a/process.c
+++ b/process.c
@@ -2635,7 +2635,7 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VAL
}
rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve. */
eargp->invoke.cmd.argv_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
+ rb_imemo_tmpbuf_new_from_an_RString(argv_str);
}
RB_GC_GUARD(execarg_obj);
}
@@ -2726,7 +2726,7 @@ open_func(void *ptr)
static void
rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
{
- VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ VALUE tmpbuf = rb_imemo_tmpbuf_new();
rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
eargp->dup2_tmpbuf = tmpbuf;
}
@@ -2830,7 +2830,7 @@ rb_execarg_parent_start1(VALUE execarg_obj)
p = NULL;
rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
eargp->envp_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
+ rb_imemo_tmpbuf_new_from_an_RString(envp_str);
eargp->envp_buf = envp_buf;
/*
diff --git a/string.c b/string.c
index 8d27248020cded..834641cfdbf0c1 100644
--- a/string.c
+++ b/string.c
@@ -10744,20 +10744,79 @@ rb_str_hex(VALUE str)
* call-seq:
* oct -> integer
*
- * Interprets the leading substring of +self+ as a string of octal digits
- * (with an optional sign) and returns the corresponding number;
- * returns zero if there is no such leading substring:
+ * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
+ * returns their value as an integer.
*
- * '123'.oct # => 83
- * '-377'.oct # => -255
- * '0377non-numeric'.oct # => 255
- * 'non-numeric'.oct # => 0
+ * In brief:
*
- * If +self+ starts with 0, radix indicators are honored;
- * see Kernel#Integer.
+ * # Interpreted as octal.
+ * '777'.oct # => 511
+ * '777x'.oct # => 511
+ * '0777'.oct # => 511
+ * '0o777'.oct # => 511
+ * '-777'.oct # => -511
+ * # Not interpreted as octal.
+ * '0b111'.oct # => 7 # Interpreted as binary.
+ * '0d999'.oct # => 999 # Interpreted as decimal.
+ * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
*
- * Related: String#hex.
+ * The leading substring is interpreted as octal when it begins with:
*
+ * - One or more character representing octal digits
+ * (each in the range '0'..'7');
+ * the string to be interpreted ends at the first character that does not represent an octal digit:
+ *
+ * '7'.oct @ => 7
+ * '11'.oct # => 9
+ * '777'.oct # => 511
+ * '0777'.oct # => 511
+ * '7778'.oct # => 511
+ * '777x'.oct # => 511
+ *
+ * - '0o', followed by one or more octal digits:
+ *
+ * '0o777'.oct # => 511
+ * '0o7778'.oct # => 511
+ *
+ * The leading substring is _not_ interpreted as octal when it begins with:
+ *
+ * - '0b', followed by one or more characters representing binary digits
+ * (each in the range '0'..'1');
+ * the string to be interpreted ends at the first character that does not represent a binary digit.
+ * the string is interpreted as binary digits (base 2):
+ *
+ * '0b111'.oct # => 7
+ * '0b1112'.oct # => 7
+ *
+ * - '0d', followed by one or more characters representing decimal digits
+ * (each in the range '0'..'9');
+ * the string to be interpreted ends at the first character that does not represent a decimal digit.
+ * the string is interpreted as decimal digits (base 10):
+ *
+ * '0d999'.oct # => 999
+ * '0d999x'.oct # => 999
+ *
+ * - '0x', followed by one or more characters representing hexadecimal digits
+ * (each in one of the ranges '0'..'9', 'a'..'f', or 'A'..'F');
+ * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
+ * the string is interpreted as hexadecimal digits (base 16):
+ *
+ * '0xfff'.oct # => 4095
+ * '0xfffg'.oct # => 4095
+ *
+ * Any of the above may prefixed with '-', which negates the interpreted value:
+ *
+ * '-777'.oct # => -511
+ * '-0777'.oct # => -511
+ * '-0b111'.oct # => -7
+ * '-0xfff'.oct # => -4095
+ *
+ * For any substring not described above, returns zero:
+ *
+ * 'foo'.oct # => 0
+ * ''.oct # => 0
+ *
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
*/
static VALUE
diff --git a/test/prism/fixtures/character_literal.txt b/test/prism/fixtures/character_literal.txt
new file mode 100644
index 00000000000000..920332123f13ac
--- /dev/null
+++ b/test/prism/fixtures/character_literal.txt
@@ -0,0 +1,2 @@
+# encoding: Windows-31J
+p ?\u3042""
diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb
index bcaed7979150bc..b21ad81391ed1e 100644
--- a/test/prism/ruby/ruby_parser_test.rb
+++ b/test/prism/ruby/ruby_parser_test.rb
@@ -16,6 +16,7 @@
module Prism
class RubyParserTest < TestCase
todos = [
+ "character_literal.txt",
"encoding_euc_jp.txt",
"regex_char_width.txt",
"seattlerb/masgn_colon3.txt",
diff --git a/util.c b/util.c
index 3e8ae590a8d54e..4caa324849af31 100644
--- a/util.c
+++ b/util.c
@@ -529,7 +529,7 @@ ruby_strdup(const char *str)
char *
ruby_getcwd(void)
{
- VALUE guard = rb_imemo_tmpbuf_auto_free_pointer();
+ VALUE guard = rb_imemo_tmpbuf_new();
int size = 200;
char *buf = xmalloc(size);