Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/syntax/pattern_matching.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ The "rest" part of a pattern also can be bound to a variable:

case {a: 1, b: 2}
in {a: } | Array
# ^ SyntaxError (variable capture in alternative pattern)
"matched: #{a}"
else
"not matched"
end
# SyntaxError (illegal variable in alternative pattern (a))

Variables that start with <code>_</code> are the only exclusions from this rule:

Expand Down
1 change: 0 additions & 1 deletion ext/json/parser/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
have_func("strnlen", "string.h") # Missing on Solaris 10

append_cflags("-std=c99")

Expand Down
9 changes: 0 additions & 9 deletions ext/json/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,15 +296,6 @@ static void rvalue_stack_eagerly_release(VALUE handle)
}
}


#ifndef HAVE_STRNLEN
static size_t strnlen(const char *s, size_t maxlen)
{
char *p;
return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
}
#endif

static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
{
int len = 1;
Expand Down
12 changes: 4 additions & 8 deletions gc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,10 @@ def self.count
# - +:time+:
# The total time spent in garbage collections (in milliseconds).
# - +:heap_allocated_pages+:
# The total number of +:heap_eden_pages+ + +:heap_tomb_pages+.
# The total number of allocated pages.
# - +:heap_empty_pages+:
# - +:heap_allocated_pages+:
# The number of pages with no live objects, and that could be released to the system.
# - +:heap_sorted_length+:
# The number of pages that can fit into the buffer that holds references to all pages.
# - +:heap_allocatable_pages+:
Expand All @@ -210,8 +213,6 @@ def self.count
# The total number of objects marked in the last \GC.
# - +:heap_eden_pages+:
# The total number of pages which contain at least one live slot.
# - +:heap_tomb_pages+:
# The total number of pages which do not contain any live slots.
# - +:total_allocated_pages+:
# The cumulative number of pages allocated since application start.
# - +:total_freed_pages+:
Expand Down Expand Up @@ -374,11 +375,6 @@ def self.stat hash_or_key = nil
# The number of pages in the eden heap.
# - +:heap_eden_slots+:
# The total number of slots in all of the pages in the eden heap.
# - +:heap_tomb_pages+:
# The number of pages in the tomb heap. The tomb heap only contains pages
# that do not have any live objects.
# - +:heap_tomb_slots+:
# The total number of slots in all of the pages in the tomb heap.
# - +:total_allocated_pages+:
# The total number of pages that have been allocated in the heap.
# - +:total_freed_pages+:
Expand Down
13 changes: 8 additions & 5 deletions lib/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class << Time
#
# You must require 'time' to use this method.
#
def zone_offset(zone, year=self.now.year)
def zone_offset(zone, year=nil)
off = nil
zone = zone.upcase
if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone
Expand All @@ -89,10 +89,13 @@ def zone_offset(zone, year=self.now.year)
off = zone.to_i * 3600
elsif ZoneOffset.include?(zone)
off = ZoneOffset[zone] * 3600
elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
off = t.utc_offset
elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
off = t.utc_offset
else
year ||= self.now.year
if ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
off = t.utc_offset
elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
off = t.utc_offset
end
end
off
end
Expand Down
58 changes: 22 additions & 36 deletions prism_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2288,7 +2288,7 @@ pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node,
// A forward declaration because this is the recursive function that handles
// compiling a pattern. It can be reentered by nesting patterns, as in the case
// of arrays or hashes.
static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index);
static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index);

/**
* This function generates the code to set up the error string and error_p
Expand Down Expand Up @@ -2394,10 +2394,10 @@ pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const
* label.
*/
static int
pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
{
LABEL *matched_label = NEW_LABEL(pm_node_line_number(scope_node->parser, node));
CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PUSH_LABEL(ret, matched_label);
return COMPILE_OK;
}
Expand Down Expand Up @@ -2544,7 +2544,7 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_n
* Compile a pattern matching expression.
*/
static int
pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
{
const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);

Expand Down Expand Up @@ -2604,7 +2604,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN(ret, location, dup);
PUSH_INSN1(ret, location, putobject, INT2FIX(index));
PUSH_SEND(ret, location, idAREF, INT2FIX(1));
CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}

if (cast->rest != NULL) {
Expand All @@ -2617,7 +2617,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_SEND(ret, location, idMINUS, INT2FIX(1));
PUSH_INSN1(ret, location, setn, INT2FIX(4));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
else if (posts_size > 0) {
PUSH_INSN(ret, location, dup);
Expand All @@ -2637,7 +2637,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN1(ret, location, topn, INT2FIX(3));
PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
PUSH_SEND(ret, location, idAREF, INT2FIX(1));
CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}

PUSH_INSN(ret, location, pop);
Expand Down Expand Up @@ -2734,7 +2734,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
}

PUSH_SEND(ret, location, idAREF, INT2FIX(1));
CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, false, base_index + 4));
}

const pm_splat_node_t *left = cast->left;
Expand All @@ -2744,7 +2744,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN1(ret, location, putobject, INT2FIX(0));
PUSH_INSN1(ret, location, topn, INT2FIX(2));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4));
}

RUBY_ASSERT(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE));
Expand All @@ -2757,7 +2757,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
PUSH_INSN1(ret, location, topn, INT2FIX(3));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4);
pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4);
}

PUSH_INSNL(ret, location, jump, find_succeeded_label);
Expand Down Expand Up @@ -2936,7 +2936,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
value = ((const pm_implicit_node_t *) value)->value;
}

CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, false, base_index + 1));
}

PUSH_SEQ(ret, match_values);
Expand Down Expand Up @@ -2964,7 +2964,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
case PM_ASSOC_SPLAT_NODE: {
const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest;
PUSH_INSN(ret, location, dup);
pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1);
pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, false, base_index + 1);
break;
}
default:
Expand Down Expand Up @@ -3009,8 +3009,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
LABEL *match_failed_label = NEW_LABEL(location.line);

PUSH_INSN(ret, location, dup);
CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1));
CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index));
CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, use_deconstructed_cache, base_index + 1));
CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, false, base_index));
PUSH_INSN(ret, location, putnil);

PUSH_LABEL(ret, match_failed_label);
Expand All @@ -3026,20 +3026,6 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node;
pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);

// If this local variable is being written from within an alternation
// pattern, then it cannot actually be added to the local table since
// it's ambiguous which value should be used. So instead we indicate
// this with a compile error.
if (in_alternation_pattern) {
ID id = pm_constant_id_lookup(scope_node, cast->name);
const char *name = rb_id2name(id);

if (name && strlen(name) > 0 && name[0] != '_') {
COMPILE_ERROR(iseq, location.line, "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
return COMPILE_NG;
}
}

PUSH_SETLOCAL(ret, location, index.index, index.level);
PUSH_INSNL(ret, location, jump, matched_label);
break;
Expand All @@ -3055,7 +3041,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// First, we're going to attempt to match against the left pattern. If
// that pattern matches, then we'll skip matching the right pattern.
PUSH_INSN(ret, location, dup);
CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, true, use_deconstructed_cache, base_index + 1));
CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, use_deconstructed_cache, base_index + 1));

// If we get here, then we matched on the left pattern. In this case we
// should pop out the duplicate value that we preemptively added to
Expand All @@ -3068,15 +3054,15 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// If we get here, then we didn't match on the left pattern. In this
// case we attempt to match against the right pattern.
PUSH_LABEL(ret, unmatched_left_label);
CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, true, use_deconstructed_cache, base_index));
CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
break;
}
case PM_PARENTHESES_NODE:
// Parentheses are allowed to wrap expressions in pattern matching and
// they do nothing since they can only wrap individual expressions and
// not groups. In this case we'll recurse back into this same function
// with the body of the parentheses.
return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index);
return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index);
case PM_PINNED_EXPRESSION_NODE:
// Pinned expressions are a way to match against the value of an
// expression that should be evaluated at runtime. This looks like:
Expand Down Expand Up @@ -3137,7 +3123,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// looks like: foo in ^@bar. To compile these, we compile the variable
// that they hold.
const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node;
CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, true, base_index));
break;
}
case PM_IF_NODE:
Expand Down Expand Up @@ -3171,7 +3157,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
statement = cast->statements->body.nodes[0];
}

CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PM_COMPILE_NOT_POPPED(predicate);

if (in_single_pattern) {
Expand Down Expand Up @@ -7878,7 +7864,7 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co
LABEL *next_pattern_label = NEW_LABEL(pattern_location.line);

PUSH_INSN(cond_seq, pattern_location, dup);
pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, false, true, 2);
pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, true, 2);
PUSH_LABEL(cond_seq, next_pattern_label);
LABEL_UNREMOVABLE(next_pattern_label);
}
Expand Down Expand Up @@ -8126,7 +8112,7 @@ pm_compile_match_required_node(rb_iseq_t *iseq, const pm_match_required_node_t *
// through the in_single_pattern parameter. We also indicate that the
// value to compare against is 2 slots from the top of the stack (the
// base_index parameter).
pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, false, true, 2);
pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, true, 2);

// If the pattern did not match the value, then we're going to compile
// in our error handler code. This will determine which error to raise
Expand Down Expand Up @@ -9815,7 +9801,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
LABEL *matched_label = NEW_LABEL(location.line);
LABEL *unmatched_label = NEW_LABEL(location.line);
LABEL *done_label = NEW_LABEL(location.line);
pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, false, true, 2);
pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, true, 2);

// If the pattern did not match, then compile the necessary instructions
// to handle pushing false onto the stack, then jump to the end.
Expand Down
4 changes: 2 additions & 2 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1935,8 +1935,8 @@ str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
long len = RSTRING_LEN(str);

RUBY_ASSERT(STR_EMBED_P(dup));
RUBY_ASSERT(str_embed_capa(dup) >= len + 1);
MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + 1);
RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
STR_SET_LEN(dup, RSTRING_LEN(str));
return str_duplicate_setup_encoding(str, dup, flags);
}
Expand Down
1 change: 0 additions & 1 deletion test/prism/ruby/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ def test_non_prism_builder_class_deprecated
if RUBY_VERSION >= "3.3"
def test_current_parser_for_current_ruby
major, minor = current_major_minor.split(".")
return if major == "3" && minor == "5" # TODO: Remove once ruby-dev becomes 4.0
# Let's just hope there never is a Ruby 3.10 or similar
expected = major.to_i * 10 + minor.to_i
assert_equal(expected, Translation::ParserCurrent.new.version)
Expand Down
Loading