diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 665c7cc0c35007..50ab433c7d06d3 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -93,7 +93,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@d858f8113943481093e02986a7586a4819a3bfd6 # v2.71.2 + - uses: taiki-e/install-action@7a562dfa955aa2e4d5b0fd6ebd57ff9715c07b0b # v2.73.0 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index fd7605367ee83d..6f29b89a27c165 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -119,7 +119,7 @@ jobs: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@d858f8113943481093e02986a7586a4819a3bfd6 # v2.71.2 + - uses: taiki-e/install-action@7a562dfa955aa2e4d5b0fd6ebd57ff9715c07b0b # v2.73.0 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/NEWS.md b/NEWS.md index 920c6d181ddfea..bf49b0358f0711 100644 --- a/NEWS.md +++ b/NEWS.md @@ -70,11 +70,11 @@ releases. * RubyGems 4.1.0.dev * bundler 4.1.0.dev * json 2.19.3 - * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2] + * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3] * openssl 4.0.1 * 4.0.0 to [v4.0.1][openssl-v4.0.1] * prism 1.9.0 - * 1.8.0 to [v1.8.1][prism-v1.8.1], [v1.9.0][prism-v1.9.0] + * 1.8.1 to [v1.9.0][prism-v1.9.0] * resolv 0.7.1 * 0.7.0 to [v0.7.1][resolv-v0.7.1] * stringio 3.2.1.dev @@ -88,20 +88,22 @@ releases. ### The following bundled gems are updated. -* minitest 6.0.2 +* minitest 6.0.3 * test-unit 3.7.7 * 3.7.5 to [3.7.6][test-unit-3.7.6], [3.7.7][test-unit-3.7.7] * net-imap 0.6.3 * 0.6.2 to [v0.6.3][net-imap-v0.6.3] -* rbs 4.0.0 - * 3.10.0 to [v3.10.1][rbs-v3.10.1], [v3.10.2][rbs-v3.10.2], [v3.10.3][rbs-v3.10.3], [v4.0.0.dev.5][rbs-v4.0.0.dev.5], [v4.0.0][rbs-v4.0.0] +* rbs 4.0.2 + * 3.10.0 to [v3.10.1][rbs-v3.10.1], [v3.10.2][rbs-v3.10.2], [v3.10.3][rbs-v3.10.3], [v3.10.4][rbs-v3.10.4], [v4.0.0.dev.5][rbs-v4.0.0.dev.5], [v4.0.0][rbs-v4.0.0], [v4.0.2][rbs-v4.0.2] * mutex_m 0.3.0 +* bigdecimal 4.1.1 + * 4.0.1 to [v4.1.0][bigdecimal-v4.1.0], [v4.1.1][bigdecimal-v4.1.1] * resolv-replace 0.2.0 * 0.1.1 to [v0.2.0][resolv-replace-v0.2.0] * syslog 0.4.0 * 0.3.0 to [v0.4.0][syslog-v0.4.0] -* repl_type_completor 0.1.14 - * 0.1.12 to [v0.1.13][repl_type_completor-v0.1.13], [v0.1.14][repl_type_completor-v0.1.14] +* repl_type_completor 0.1.15 + * 0.1.12 to [v0.1.13][repl_type_completor-v0.1.13], [v0.1.14][repl_type_completor-v0.1.14], [v0.1.15][repl_type_completor-v0.1.15] * pstore 0.2.1 * 0.2.0 to [v0.2.1][pstore-v0.2.1] * rdoc 7.2.0 @@ -167,30 +169,36 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [rdoc-v7.0.1]: https://github.com/ruby/rdoc/releases/tag/v7.0.1 [rdoc-v7.0.2]: https://github.com/ruby/rdoc/releases/tag/v7.0.2 [rdoc-v7.0.3]: https://github.com/ruby/rdoc/releases/tag/v7.0.3 +[prism-v1.8.1]: https://github.com/ruby/prism/releases/tag/v1.8.1 +[zlib-v3.2.3]: https://github.com/ruby/zlib/releases/tag/v3.2.3 +[pstore-v0.2.1]: https://github.com/ruby/pstore/releases/tag/v0.2.1 [json-v2.18.1]: https://github.com/ruby/json/releases/tag/v2.18.1 [json-v2.19.0]: https://github.com/ruby/json/releases/tag/v2.19.0 [json-v2.19.1]: https://github.com/ruby/json/releases/tag/v2.19.1 [json-v2.19.2]: https://github.com/ruby/json/releases/tag/v2.19.2 +[json-v2.19.3]: https://github.com/ruby/json/releases/tag/v2.19.3 [openssl-v4.0.1]: https://github.com/ruby/openssl/releases/tag/v4.0.1 -[prism-v1.8.1]: https://github.com/ruby/prism/releases/tag/v1.8.1 [prism-v1.9.0]: https://github.com/ruby/prism/releases/tag/v1.9.0 [resolv-v0.7.1]: https://github.com/ruby/resolv/releases/tag/v0.7.1 [strscan-v3.1.7]: https://github.com/ruby/strscan/releases/tag/v3.1.7 [timeout-v0.6.1]: https://github.com/ruby/timeout/releases/tag/v0.6.1 -[zlib-v3.2.3]: https://github.com/ruby/zlib/releases/tag/v3.2.3 [test-unit-3.7.6]: https://github.com/test-unit/test-unit/releases/tag/3.7.6 [test-unit-3.7.7]: https://github.com/test-unit/test-unit/releases/tag/3.7.7 [net-imap-v0.6.3]: https://github.com/ruby/net-imap/releases/tag/v0.6.3 [rbs-v3.10.1]: https://github.com/ruby/rbs/releases/tag/v3.10.1 [rbs-v3.10.2]: https://github.com/ruby/rbs/releases/tag/v3.10.2 [rbs-v3.10.3]: https://github.com/ruby/rbs/releases/tag/v3.10.3 +[rbs-v3.10.4]: https://github.com/ruby/rbs/releases/tag/v3.10.4 [rbs-v4.0.0.dev.5]: https://github.com/ruby/rbs/releases/tag/v4.0.0.dev.5 [rbs-v4.0.0]: https://github.com/ruby/rbs/releases/tag/v4.0.0 +[rbs-v4.0.2]: https://github.com/ruby/rbs/releases/tag/v4.0.2 +[bigdecimal-v4.1.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.0 +[bigdecimal-v4.1.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.1 [resolv-replace-v0.2.0]: https://github.com/ruby/resolv-replace/releases/tag/v0.2.0 [syslog-v0.4.0]: https://github.com/ruby/syslog/releases/tag/v0.4.0 [repl_type_completor-v0.1.13]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.13 [repl_type_completor-v0.1.14]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.14 -[pstore-v0.2.1]: https://github.com/ruby/pstore/releases/tag/v0.2.1 +[repl_type_completor-v0.1.15]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.15 [rdoc-v7.1.0]: https://github.com/ruby/rdoc/releases/tag/v7.1.0 [rdoc-v7.2.0]: https://github.com/ruby/rdoc/releases/tag/v7.2.0 [win32ole-v1.9.3]: https://github.com/ruby/win32ole/releases/tag/v1.9.3 diff --git a/gems/bundled_gems b/gems/bundled_gems index 9d3fcd095e6941..f9075621666abd 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -6,7 +6,7 @@ # - revision: revision in repository-url to test # if `revision` is not given, "v"+`version` or `version` will be used. -minitest 6.0.2 https://github.com/minitest/minitest +minitest 6.0.3 https://github.com/minitest/minitest power_assert 3.0.1 https://github.com/ruby/power_assert rake 13.3.1 https://github.com/ruby/rake test-unit 3.7.7 https://github.com/test-unit/test-unit @@ -16,14 +16,14 @@ net-imap 0.6.3 https://github.com/ruby/net-imap net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.3 https://github.com/ruby/matrix prime 0.1.4 https://github.com/ruby/prime -rbs 4.0.2 https://github.com/ruby/rbs +rbs 4.0.2 https://github.com/ruby/rbs 36a7e8e38df9efd33db83c3f30f0308bdeb84bd9 typeprof 0.31.1 https://github.com/ruby/typeprof debug 1.11.1 https://github.com/ruby/debug 2897edad6d2c2eeb49ffe915192c54572dbe6c82 racc 1.8.1 https://github.com/ruby/racc mutex_m 0.3.0 https://github.com/ruby/mutex_m getoptlong 0.2.1 https://github.com/ruby/getoptlong base64 0.3.0 https://github.com/ruby/base64 -bigdecimal 4.0.1 https://github.com/ruby/bigdecimal +bigdecimal 4.1.1 https://github.com/ruby/bigdecimal observer 0.1.2 https://github.com/ruby/observer abbrev 0.1.2 https://github.com/ruby/abbrev resolv-replace 0.2.0 https://github.com/ruby/resolv-replace diff --git a/hash.c b/hash.c index 773df7e78d8c7f..79dbd5d8e90f0a 100644 --- a/hash.c +++ b/hash.c @@ -5012,6 +5012,8 @@ hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash)) * proc.call(:foo) # => 0 * proc.call(:bar) # => 1 * proc.call(:nosuch) # => nil + * h.default_proc = proc { |hash, key| "Missing key: #{key}" } # This affect the existing proc object + * proc.call(:nosuch) # => "Missing key: #{nosuch}" * * Related: see {Methods for Converting}[rdoc-ref:Hash@Methods+for+Converting]. */ diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb index 2f66bab97ee5b8..dd443e207f1da1 100644 --- a/lib/prism/translation/ripper.rb +++ b/lib/prism/translation/ripper.rb @@ -28,7 +28,6 @@ module Translation # - on_lbracket # - on_lparen # - on_nl - # - on_op # - on_operator_ambiguous # - on_rbrace # - on_rbracket @@ -647,6 +646,10 @@ def visit_alias_global_variable_node(node) # ^^^^^^^^^ def visit_alternation_pattern_node(node) left = visit_pattern_node(node.left) + + bounds(node.operator_loc) + on_op("|") + right = visit_pattern_node(node.right) bounds(node.location) @@ -667,10 +670,14 @@ def visit_alternation_pattern_node(node) # ^^^^^^^ def visit_and_node(node) left = visit(node.left) + + bounds(node.operator_loc) if node.operator == "and" - bounds(node.operator_loc) on_kw("and") + else + on_op("&&") end + right = visit(node.right) bounds(node.location) @@ -844,6 +851,9 @@ def visit_array_pattern_node(node) requireds = visit_all(node.requireds) if node.requireds.any? rest = if (rest_node = node.rest).is_a?(SplatNode) + bounds(rest_node.operator_loc) + on_op("*") + if rest_node.expression.nil? bounds(rest_node.location) on_var_field(nil) @@ -869,6 +879,12 @@ def visit_arguments_node(node) # ^^^^ def visit_assoc_node(node) key = visit(node.key) + + if node.operator_loc + bounds(node.operator_loc) + on_op("=>") + end + value = visit(node.value) bounds(node.location) @@ -881,6 +897,9 @@ def visit_assoc_node(node) # { **foo } # ^^^^^ def visit_assoc_splat_node(node) + bounds(node.operator_loc) + on_op("**") + value = visit(node.value) bounds(node.location) @@ -974,6 +993,8 @@ def visit_begin_node(node) # foo(&bar) # ^^^^ def visit_block_argument_node(node) + bounds(node.operator_loc) + on_op("&") visit(node.expression) end @@ -987,13 +1008,13 @@ def visit_block_local_variable_node(node) # Visit a BlockNode. def visit_block_node(node) braces = node.opening == "{" - parameters = visit(node.parameters) - unless braces bounds(node.opening_loc) on_kw("do") end + parameters = visit(node.parameters) + body = case node.body when nil @@ -1032,6 +1053,9 @@ def visit_block_node(node) # def foo(&bar); end # ^^^^ def visit_block_parameter_node(node) + bounds(node.operator_loc) + on_op("&") + if node.name_loc.nil? bounds(node.location) on_blockarg(nil) @@ -1046,6 +1070,9 @@ def visit_block_parameter_node(node) # A block's parameters. def visit_block_parameters_node(node) + bounds(node.opening_loc) + on_op("|") + parameters = if node.parameters.nil? on_params(nil, nil, nil, nil, nil, nil, nil) @@ -1060,6 +1087,9 @@ def visit_block_parameters_node(node) false end + bounds(node.closing_loc) + on_op("|") + bounds(node.location) on_block_var(parameters, locals) end @@ -1126,6 +1156,9 @@ def visit_call_node(node) end end + bounds(node.equal_loc) + on_op("=") + bounds(node.location) call = on_aref_field(receiver, arguments) value = visit_write_value(last_argument) @@ -1133,13 +1166,15 @@ def visit_call_node(node) bounds(last_argument.location) on_assign(call, value) when :-@, :+@, :~ - receiver = visit(node.receiver) + bounds(node.message_loc) + on_op(node.message) + receiver = visit(node.receiver) bounds(node.location) on_unary(node.name, receiver) when :! + bounds(node.message_loc) if node.message == "not" - bounds(node.message_loc) on_kw("not") receiver = @@ -1150,6 +1185,8 @@ def visit_call_node(node) bounds(node.location) on_unary(:not, receiver) else + on_op("!") + receiver = visit(node.receiver) bounds(node.location) @@ -1157,6 +1194,10 @@ def visit_call_node(node) end when *BINARY_OPERATORS receiver = visit(node.receiver) + + bounds(node.message_loc) + on_op(node.message) + value = visit(node.arguments.arguments.first) bounds(node.location) @@ -1203,6 +1244,11 @@ def visit_call_node(node) visit_token(node.message, false) end + if node.equal_loc + bounds(node.equal_loc) + on_op("=") + end + if node.name.end_with?("=") && !node.message.end_with?("=") && !node.arguments.nil? && node.block.nil? value = visit_write_value(node.arguments.arguments.first) @@ -1354,6 +1400,9 @@ def visit_call_target_node(node) if node.call_operator == "::" receiver = visit(node.receiver) + bounds(node.call_operator_loc) + on_op("::") + bounds(node.message_loc) message = visit_token(node.message) @@ -1377,6 +1426,10 @@ def visit_call_target_node(node) # ^^^^^^^^^^ def visit_capture_pattern_node(node) value = visit(node.value) + + bounds(node.operator_loc) + on_op("=>") + target = visit(node.target) bounds(node.location) @@ -1447,6 +1500,11 @@ def visit_class_node(node) visit(node.constant_path) end + if node.inheritance_operator_loc + bounds(node.inheritance_operator_loc) + on_op("<") + end + superclass = visit(node.superclass) bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?) @@ -1472,6 +1530,10 @@ def visit_class_variable_read_node(node) def visit_class_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_cvar(node.name.to_s)) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -1542,6 +1604,10 @@ def visit_constant_read_node(node) def visit_constant_write_node(node) bounds(node.name_loc) target = on_var_field(on_const(node.name.to_s)) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -1601,6 +1667,11 @@ def visit_constant_target_node(node) # ^^^^^^^^ def visit_constant_path_node(node) if node.parent.nil? + if node.delimiter_loc + bounds(node.delimiter_loc) + on_op("::") + end + bounds(node.name_loc) child = on_const(node.name.to_s) @@ -1609,6 +1680,9 @@ def visit_constant_path_node(node) else parent = visit(node.parent) + bounds(node.delimiter_loc) + on_op("::") + bounds(node.name_loc) child = on_const(node.name.to_s) @@ -1624,6 +1698,10 @@ def visit_constant_path_node(node) # ^^^^^^^^ ^^^^^^^^ def visit_constant_path_write_node(node) target = visit_constant_path_write_node_target(node.target) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -1633,6 +1711,11 @@ def visit_constant_path_write_node(node) # Visit a constant path that is part of a write node. private def visit_constant_path_write_node_target(node) if node.parent.nil? + if node.delimiter_loc + bounds(node.delimiter_loc) + on_op("::") + end + bounds(node.name_loc) child = on_const(node.name.to_s) @@ -1641,6 +1724,9 @@ def visit_constant_path_write_node(node) else parent = visit(node.parent) + bounds(node.delimiter_loc) + on_op("::") + bounds(node.name_loc) child = on_const(node.name.to_s) @@ -1726,6 +1812,11 @@ def visit_def_node(node) parameters = on_paren(parameters) end + if node.equal_loc + bounds(node.equal_loc) + on_op("=") + end + bodystmt = if node.equal_loc.nil? visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body) @@ -1864,6 +1955,10 @@ def visit_false_node(node) # ^^^^^^^^^^^ def visit_find_pattern_node(node) constant = visit(node.constant) + + bounds(node.left.operator_loc) + on_op("*") + left = if node.left.expression.nil? bounds(node.left.location) @@ -1873,6 +1968,10 @@ def visit_find_pattern_node(node) end requireds = visit_all(node.requireds) if node.requireds.any? + + bounds(node.right.operator_loc) + on_op("*") + right = if node.right.expression.nil? bounds(node.right.location) @@ -1889,6 +1988,10 @@ def visit_find_pattern_node(node) # ^^^^^^^^^^ def visit_flip_flop_node(node) left = visit(node.left) + + bounds(node.operator_loc) + on_op(node.operator) + right = visit(node.right) bounds(node.location) @@ -1939,6 +2042,7 @@ def visit_for_node(node) # ^^^ def visit_forwarding_arguments_node(node) bounds(node.location) + on_op("...") on_args_forward end @@ -1946,6 +2050,7 @@ def visit_forwarding_arguments_node(node) # ^^^ def visit_forwarding_parameter_node(node) bounds(node.location) + on_op("...") on_args_forward end @@ -1984,6 +2089,10 @@ def visit_global_variable_read_node(node) def visit_global_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_gvar(node.name.to_s)) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -2080,6 +2189,8 @@ def visit_hash_pattern_node(node) rest = case node.rest when AssocSplatNode + bounds(node.rest.operator_loc) + on_op("**") visit(node.rest.value) when NoKeywordsParameterNode bounds(node.rest.location) @@ -2101,7 +2212,15 @@ def visit_hash_pattern_node(node) def visit_if_node(node) if node.then_keyword == "?" predicate = visit(node.predicate) + + bounds(node.then_keyword_loc) + on_op("?") + truthy = visit(node.statements.body.first) + + bounds(node.subsequent.else_keyword_loc) + on_op(":") + falsy = visit(node.subsequent.statements.body.first) bounds(node.location) @@ -2261,6 +2380,10 @@ def visit_instance_variable_read_node(node) def visit_instance_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_ivar(node.name.to_s)) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -2464,6 +2587,9 @@ def visit_keyword_hash_node(node) # def foo(**); end # ^^ def visit_keyword_rest_parameter_node(node) + bounds(node.operator_loc) + on_op("**") + if node.name_loc.nil? bounds(node.location) on_kwrest_param(nil) @@ -2559,6 +2685,10 @@ def visit_local_variable_read_node(node) def visit_local_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_ident(node.name_loc.slice)) + + bounds(node.operator_loc) + on_op("=") + value = visit_write_value(node.value) bounds(node.location) @@ -2644,6 +2774,10 @@ def visit_match_predicate_node(node) # ^^^^^^^^^^ def visit_match_required_node(node) value = visit(node.value) + + bounds(node.operator_loc) + on_op("=>") + pattern = on_in(visit_pattern_node(node.pattern), nil, nil) on_case(value, pattern) @@ -2744,6 +2878,9 @@ def visit_multi_write_node(node) bounds(node.location) targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true) + bounds(node.operator_loc) + on_op("=") + unless node.lparen_loc.nil? bounds(node.lparen_loc) targets = on_mlhs_paren(targets) @@ -2785,6 +2922,8 @@ def visit_nil_node(node) # def foo(&nil); end # ^^^^ def visit_no_block_parameter_node(node) + bounds(node.operator_loc) + on_op("&") bounds(node.keyword_loc) on_kw("nil") bounds(node.location) @@ -2794,6 +2933,8 @@ def visit_no_block_parameter_node(node) # def foo(**nil); end # ^^^^^ def visit_no_keywords_parameter_node(node) + bounds(node.operator_loc) + on_op("**") bounds(node.keyword_loc) on_kw("nil") bounds(node.location) @@ -2829,6 +2970,10 @@ def visit_optional_keyword_parameter_node(node) def visit_optional_parameter_node(node) bounds(node.name_loc) name = visit_token(node.name.to_s) + + bounds(node.operator_loc) + on_op("=") + value = visit(node.value) [name, value] @@ -2838,10 +2983,14 @@ def visit_optional_parameter_node(node) # ^^^^^^ def visit_or_node(node) left = visit(node.left) + + bounds(node.operator_loc) if node.operator == "or" - bounds(node.operator_loc) on_kw("or") + else + on_op("||") end + right = visit(node.right) bounds(node.location) @@ -2892,6 +3041,9 @@ def visit_parentheses_node(node) # foo => ^(bar) # ^^^^^^ def visit_pinned_expression_node(node) + bounds(node.operator_loc) + on_op("^") + expression = visit(node.expression) bounds(node.location) @@ -2901,6 +3053,9 @@ def visit_pinned_expression_node(node) # foo = 1 and bar => ^foo # ^^^^ def visit_pinned_variable_node(node) + bounds(node.operator_loc) + on_op("^") + visit(node.variable) end @@ -2954,6 +3109,10 @@ def visit_program_node(node) # ^^^^ def visit_range_node(node) left = visit(node.left) + + bounds(node.operator_loc) + on_op(node.operator) + right = visit(node.right) bounds(node.location) @@ -3070,6 +3229,11 @@ def visit_rescue_node(node) end end + if node.operator_loc + bounds(node.operator_loc) + on_op("=>") + end + reference = visit(node.reference) statements = if node.statements.nil? @@ -3091,6 +3255,9 @@ def visit_rescue_node(node) # def foo(*); end # ^ def visit_rest_parameter_node(node) + bounds(node.operator_loc) + on_op("*") + if node.name_loc.nil? bounds(node.location) on_rest_param(nil) @@ -3145,6 +3312,8 @@ def visit_shareable_constant_node(node) def visit_singleton_class_node(node) bounds(node.class_keyword_loc) on_kw("class") + bounds(node.operator_loc) + on_op("<<") expression = visit(node.expression) bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body) @@ -3186,6 +3355,8 @@ def visit_source_line_node(node) # def foo(*); bar(*); end # ^ def visit_splat_node(node) + bounds(node.operator_loc) + on_op("*") visit(node.expression) end @@ -3676,6 +3847,9 @@ def visit_number_node(node) location = node.location if slice[0] == "-" + bounds(location.copy(length: 1)) + on_op("-") + bounds(location.copy(start_offset: location.start_offset + 1)) value = yield slice[1..-1] diff --git a/lib/resolv.rb b/lib/resolv.rb index 9720b52c00fef3..6b58f92813b435 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -3268,7 +3268,7 @@ class Size # Regular expression LOC size must match. - Regex = /^(\d+\.*\d*)[m]$/ + Regex = /\A0*(\d{1,8}(?:\.\d+)?)m\z/ ## # Creates a new LOC::Size from +arg+ which may be: @@ -3281,13 +3281,14 @@ def self.create(arg) when Size return arg when String - scalar = '' - if Regex =~ arg - scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C") - else + unless Regex =~ arg raise ArgumentError.new("not a properly formed Size string: " + arg) end - return Size.new(scalar) + unless (0.0...1e8) === (scalar = $1.to_f) + raise ArgumentError.new("out of range as Size: #{arg}") + end + str = (scalar * 100).to_i.to_s + return new([(str[0].to_i << 4) + (str.bytesize-1)].pack("C")) else raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}") end @@ -3304,8 +3305,8 @@ def initialize(scalar) attr_reader :scalar def to_s # :nodoc: - s = @scalar.unpack("H2").join.to_s - return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m" + s, = @scalar.unpack("C") + return "#{(s >> 4) * (10.0 ** ((s & 0xf) - 2))}m" end def inspect # :nodoc: @@ -3333,7 +3334,10 @@ class Coord # Regular expression LOC Coord must match. - Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/ + Regex = /\A0*(\d{1,3})\s([0-5]?\d)\s([0-5]?\d(?:\.\d+)?)\s([NESW])\z/ + + # Bias for the equator/prime meridian, in thousandths of a second of arc. + Bias = 1 << 31 ## # Creates a new LOC::Coord from +arg+ which may be: @@ -3346,17 +3350,19 @@ def self.create(arg) when Coord return arg when String - coordinates = '' - if Regex =~ arg && $1.to_f < 180 - m = $~ - hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1 - coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) + - (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N") - orientation = m[4][/[NS]/] ? 'lat' : 'lon' - else + unless m = Regex.match(arg) raise ArgumentError.new("not a properly formed Coord string: " + arg) end - return Coord.new(coordinates,orientation) + + arc = (m[1].to_i * 3_600_000) + (m[2].to_i * 60_000) + (m[3].to_f * 1_000).to_i + dir = m[4] + lat = dir[/[NS]/] + unless arc <= (lat ? 324_000_000 : 648_000_000) # (lat ? 90 : 180) * 3_600_000 + raise ArgumentError.new("out of range as Coord: #{arg}") + end + + hemi = dir[/[NE]/] ? 1 : -1 + return new([arc * hemi + Bias].pack("N"), lat ? "lat" : "lon") else raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}") end @@ -3364,10 +3370,10 @@ def self.create(arg) # Internal use; use self.create. def initialize(coordinates,orientation) - unless coordinates.kind_of?(String) + unless coordinates.kind_of?(String) and coordinates.bytesize == 4 raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}") end - unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/] + unless orientation == "lon" || orientation == "lat" raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"') end @coordinates = coordinates @@ -3384,22 +3390,17 @@ def initialize(coordinates,orientation) attr_reader :orientation def to_s # :nodoc: - c = @coordinates.unpack("N").join.to_i - val = (c - (2**31)).abs - fracsecs = (val % 1e3).to_i.to_s - val = val / 1e3 - secs = (val % 60).to_i.to_s - val = val / 60 - mins = (val % 60).to_i.to_s - degs = (val / 60).to_i.to_s - posi = (c >= 2**31) - case posi - when true - hemi = @orientation[/^lat$/] ? "N" : "E" + c, = @coordinates.unpack("N") + val = (c -= Bias).abs + val, fracsecs = val.divmod(1000) + val, secs = val.divmod(60) + degs, mins = val.divmod(60) + hemi = if c.negative? + @orientation == "lon" ? "W" : "S" else - hemi = @orientation[/^lon$/] ? "W" : "S" + @orientation == "lat" ? "N" : "E" end - return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi + format("%d %02d %02d.%03d %s", degs, mins, secs, fracsecs, hemi) end def inspect # :nodoc: @@ -3427,7 +3428,10 @@ class Alt # Regular expression LOC Alt must match. - Regex = /^([+-]*\d+\.*\d*)[m]$/ + Regex = /\A([+-]?0*\d{1,8}(?:\.\d+)?)m\z/ + + # Bias to a base of 100,000m below the WGS 84 reference spheroid. + Bias = 100_000_00 ## # Creates a new LOC::Alt from +arg+ which may be: @@ -3440,13 +3444,14 @@ def self.create(arg) when Alt return arg when String - altitude = '' - if Regex =~ arg - altitude = [($1.to_f*(1e2))+(1e7)].pack("N") - else + unless Regex =~ arg raise ArgumentError.new("not a properly formed Alt string: " + arg) end - return Alt.new(altitude) + altitude = ($1.to_f * 100).to_i + Bias + unless (0...0x1_0000_0000) === altitude + raise ArgumentError.new("out of raise as Alt: #{arg}") + end + return new([altitude].pack("N")) else raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}") end @@ -3463,8 +3468,8 @@ def initialize(altitude) attr_reader :altitude def to_s # :nodoc: - a = @altitude.unpack("N").join.to_i - return ((a.to_f/1e2)-1e5).to_s + "m" + a, = @altitude.unpack("N") + return "#{(a - Bias).fdiv(100)}m" end def inspect # :nodoc: diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index 0053e0d8459cf9..5df3b58202791c 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -1741,8 +1741,9 @@ def create_temporary_dir(dir) expect(bundled_app("#{gem_name}/ext/#{gem_name}/build.rs")).to exist end - it "includes rake-compiler constraint" do + it "includes rake-compiler and rb_sys gems constraint" do expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"') + expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "rb_sys"') end it "depends on compile task for build" do diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 1d20bceb40d6dc..6abe1bb2e5e50b 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -137,20 +137,22 @@ def test_lex_ignored_missing_heredoc_end end # Events that are currently not emitted - UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end lbrace lbracket lparen nl op rbrace rbracket rparen semicolon sp words_sep ignored_sp] + UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end lbrace lbracket lparen nl rbrace rbracket rparen semicolon sp words_sep ignored_sp] SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS # Events that assert against their line/column - CHECK_LOCATION_EVENTS = %i[kw] + CHECK_LOCATION_EVENTS = %i[kw op] IGNORE_FOR_SORT_EVENTS = %i[ stmts_new stmts_add bodystmt void_stmt args_new args_add args_add_star args_add_block arg_paren method_add_arg - mlhs_new mlhs_add_star + mlhs_new mlhs_add mlhs_add_star mlhs_add_post + mrhs_new mrhs_add mrhs_add_star mrhs_new_from_args word_new words_new symbols_new qwords_new qsymbols_new xstring_new regexp_new words_add symbols_add qwords_add qsymbols_add regexp_end tstring_end heredoc_end call command fcall vcall field aref_field var_field var_ref block_var ident params string_content heredoc_dedent unary binary dyna_symbol + excessed_comma rest_param comment magic_comment embdoc embdoc_beg embdoc_end arg_ambiguous ] SORT_IGNORE = { @@ -189,7 +191,6 @@ def test_lex_ignored_missing_heredoc_end const_path_ref: ["unparser/corpus/literal/defs.txt"], do_block: ["whitequark/super_block.txt"], embexpr_end: ["seattlerb/str_interp_ternary_or_label.txt"], - rest_param: ["whitequark/send_lambda.txt"], top_const_field: [ "seattlerb/const_3_op_asgn_or.txt", "seattlerb/const_op_asgn_and1.txt", @@ -197,13 +198,9 @@ def test_lex_ignored_missing_heredoc_end "whitequark/const_op_asgn.txt", ], mlhs_paren: ["unparser/corpus/literal/for.txt"], - mlhs_add: [ - "whitequark/for_mlhs.txt", - ], kw: [ "defined.txt", "for.txt", - "seattlerb/block_kw__required.txt", "seattlerb/case_in_42.txt", "seattlerb/case_in_67.txt", "seattlerb/case_in_86_2.txt", @@ -220,6 +217,11 @@ def test_lex_ignored_missing_heredoc_end "whitequark/super_block.txt", "write_command_operator.txt", ], + op: [ + "ranges.txt", + "ternary_operator.txt", + "whitequark/args_args_assocs.txt", + ] } SORT_IGNORE.default = [] SORT_EVENTS = SUPPORTED_EVENTS - IGNORE_FOR_SORT_EVENTS @@ -235,6 +237,7 @@ def initialize(...) def sorted_events @events.select do |e,| next false if e == :kw && @events.any? { |e,| e == :if_mod || e == :while_mod || e == :until_mod || e == :rescue || e == :rescue_mod || e == :while || e == :ensure } + next false if e == :op && @events.any? { |e,| e == :const_path_field || e == :const_ref || e == :top_const_field || e == :top_const_ref } SORT_EVENTS.include?(e) && !SORT_IGNORE[e].include?(filename) end end diff --git a/test/resolv/test_resource.rb b/test/resolv/test_resource.rb index 434380236e6721..3a1c9ae3c3ea41 100644 --- a/test/resolv/test_resource.rb +++ b/test/resolv/test_resource.rb @@ -20,10 +20,6 @@ def test_hash assert_equal(@name1.hash, @name2.hash, bug10857) end - def test_coord - Resolv::LOC::Coord.create('1 2 1.1 N') - end - def test_srv_no_compress # Domain name in SRV RDATA should not be compressed issue29 = 'https://github.com/ruby/resolv/issues/29' @@ -33,6 +29,76 @@ def test_srv_no_compress end end +class TestResolvResourceLOC < Test::Unit::TestCase + def test_size_create + assert_size("0.0m", 0, 0) + assert_size("0.01m", 1, 0) + assert_size("0.09m", 9, 0) + assert_size("0.11m", 1, 1) + assert_size("1.0m", 1, 2) + assert_size("1234.56m", 1, 5) + assert_size("12345678.90m", 1, 9) + assert_size("98765432.10m", 9, 9) + assert_raise(ArgumentError) {Resolv::LOC::Size.create("100000000.00m")} + end + + private def assert_size(input, base, power) + size = Resolv::LOC::Size.create(input) + assert_equal([(base << 4) + power], size.scalar.unpack("C")) + assert_equal(size, Resolv::LOC::Size.create(size.to_s)) + end + + def test_coord + assert_coord('1 2 1.1 N', 'lat', 0x8038c78c) + assert_coord('42 21 43.952 N', 'lat', 0x89170690) + assert_coord('71 5 6.344 W', 'lon', 0x70bf2dd8) + assert_coord('52 14 05.000 N', 'lat', 0x8b3556c8) + assert_coord('90 0 0.000 N', 'lat', 0x934fd900) + assert_coord('90 0 0.000 S', 'lat', 0x6cb02700) + assert_coord('00 8 50.000 E', 'lon', 0x80081650) + assert_coord('0 8 50.001 E', 'lon', 0x80081651) + assert_coord('32 07 19.000 S', 'lat', 0x791b7d28) + assert_coord('116 02 25.000 E', 'lon', 0x98e64868) + assert_coord('116 02 25.000 W', 'lon', 0x6719b798) + assert_coord('180 00 00.000 E', 'lon', 0xa69fb200) + assert_coord('180 00 00.000 W', 'lon', 0x59604e00) + assert_raise(ArgumentError) {Resolv::LOC::Coord.create('90 0 0.001 N')} + assert_raise(ArgumentError) {Resolv::LOC::Coord.create('90 0 0.001 S')} + assert_raise(ArgumentError) {Resolv::LOC::Coord.create('180 0 0.001 E')} + assert_raise(ArgumentError) {Resolv::LOC::Coord.create('180 0 0.001 W')} + end + + private def assert_coord(input, orientation, coordinate) + coord = Resolv::LOC::Coord.create(input) + + assert_equal(orientation, coord.orientation) + assert_equal([coordinate].pack("N"), coord.coordinates) + assert_equal(coord, Resolv::LOC::Coord.create(coord.to_s)) + end + + def test_alt + assert_alt("0.0m", 0) + assert_alt("+0.0m", 0) + assert_alt("-0.0m", 0) + assert_alt("+0.01m", 1) + assert_alt("1.0m", 100) + assert_alt("+1.0m", 100) + assert_alt("100000.0m", +10000000) + assert_alt("+100000.0m", +10000000) + assert_alt("-100000.0m", -10000000) + assert_alt("+42849672.95m", 0xffff_ffff-100_000_00) + assert_raise(ArgumentError) {Resolv::LOC::Alt.create("-100000.01m")} + assert_raise(ArgumentError) {Resolv::LOC::Alt.create("+42849672.96m")} + end + + private def assert_alt(input, altitude) + alt = Resolv::LOC::Alt.create(input) + + assert_equal([altitude + 1e7].pack("N"), alt.altitude) + assert_equal(alt, Resolv::LOC::Alt.create(alt.to_s)) + end +end + class TestResolvResourceCAA < Test::Unit::TestCase def test_caa_roundtrip raw_msg = "\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x03new\x07example\x03com\x00\x01\x01\x00\x01\x00\x00\x00\x00\x00\x16\x00\x05issueca1.example.net\xC0\x0C\x01\x01\x00\x01\x00\x00\x00\x00\x00\x0C\x80\x03tbsUnknown".b diff --git a/tool/update-bundled_gems.rb b/tool/update-bundled_gems.rb index c25ec6e08a10a0..565a522aa04776 100755 --- a/tool/update-bundled_gems.rb +++ b/tool/update-bundled_gems.rb @@ -12,33 +12,34 @@ output.print date.strftime("latest_date=%F") if date } if gem = $F[0] - next if pinned.include?(gem) - ver = Gem::Version.new($F[1]) - (gem, src), = Gem::SpecFetcher.fetcher.detect(:latest) {|s| - s.platform == "ruby" && s.name == gem - } - if gem.version > ver - gem = src.fetch_spec(gem) - if ENV["UPDATE_BUNDLED_GEMS_ALL"] - uri = gem.metadata["source_code_uri"] || gem.homepage - uri = uri.sub(%r[\Ahttps://github\.com/[^/]+/[^/]+\K/tree/.*], "").chomp(".git") - else - uri = $F[2] - end - if (!date or gem.date && gem.date > date) and gem.date.to_i != 315_619_200 - # DEFAULT_SOURCE_DATE_EPOCH is meaningless - date = gem.date - end - if $F[3] - if $F[3].include?($F[1]) - $F[3][$F[1]] = gem.version.to_s - elsif Gem::Version.new($F[1]) != gem.version and /\A\h+\z/ =~ $F[3] - $F[3..-1] = [] + unless pinned.include?(gem) + ver = Gem::Version.new($F[1]) + (gem, src), = Gem::SpecFetcher.fetcher.detect(:latest) {|s| + s.platform == "ruby" && s.name == gem + } + if gem.version > ver + gem = src.fetch_spec(gem) + if ENV["UPDATE_BUNDLED_GEMS_ALL"] + uri = gem.metadata["source_code_uri"] || gem.homepage + uri = uri.sub(%r[\Ahttps://github\.com/[^/]+/[^/]+\K/tree/.*], "").chomp(".git") + else + uri = $F[2] + end + if (!date or gem.date && gem.date > date) and gem.date.to_i != 315_619_200 + # DEFAULT_SOURCE_DATE_EPOCH is meaningless + date = gem.date + end + if $F[3] + if $F[3].include?($F[1]) + $F[3][$F[1]] = gem.version.to_s + elsif Gem::Version.new($F[1]) != gem.version and /\A\h+\z/ =~ $F[3] + $F[3..-1] = [] + end end + f = [gem.name, gem.version.to_s, uri, *$F[3..-1]] + $_.gsub!(/\S+\s*(?=\s|$)/) {|s| (f.shift || "").ljust(s.size)} + $_ = [$_, *f].join(" ") unless f.empty? + $_.rstrip! end - f = [gem.name, gem.version.to_s, uri, *$F[3..-1]] - $_.gsub!(/\S+\s*(?=\s|$)/) {|s| (f.shift || "").ljust(s.size)} - $_ = [$_, *f].join(" ") unless f.empty? - $_.rstrip! end end