-
Notifications
You must be signed in to change notification settings - Fork 177
Add Prism.node_for(Method|UnboundMethod|Proc) to get a Prism node for a callable #3808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
eregon
wants to merge
7
commits into
ruby:main
Choose a base branch
from
eregon:node_for
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
561b96f
Fix docs of opening_loc/closing_loc of BlockNode
eregon 32f6087
Add Prism.node_for(Method|UnboundMethod|Proc) to get a Prism node for…
eregon 77599d1
Use Prism::Node#tunnel to optimize search in Prism.node_for
eregon 50f2c89
Simplify and optimize Prism::Node#tunnel
eregon eb46068
Add Prism::Source#line_to_byte_offset and replace direct accesses to …
eregon 8a02eed
CRuby currently returns the source_location columns in bytes and not …
eregon f004e7d
Remove currently-unused Prism::Source#line_and_character_column_to_by…
eregon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # A separate file because 2.7 can't parse this | ||
| module Prism | ||
| class NodeForTest < TestCase | ||
| def inline_method = 42 | ||
| INLINE_LOCATION_AND_FILE = [[__LINE__-1, 4, __LINE__-1, 26], __FILE__] | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| # frozen_string_literal: true | ||
| # typed: ignore | ||
|
|
||
| require_relative "../test_helper" | ||
|
|
||
| # Needs Prism.parse_file(file, version: "current") | ||
| return if RUBY_VERSION < "3.3" | ||
|
|
||
| require_relative 'inline_method' | ||
|
|
||
| module Prism | ||
| class NodeForTest < TestCase | ||
| INDENT = ' ' * 4 | ||
|
|
||
| def m(foo) | ||
| 42 | ||
| end | ||
| M_LOCATION = [__LINE__-3, 4, __LINE__-1, 7] | ||
|
|
||
| def été; 42; end | ||
| UTF8_LOCATION = [__LINE__-1, 4, __LINE__-1, 22] | ||
|
|
||
| define_method(:define_method_method) { 42 } | ||
| DEFINE_METHOD_LOCATION = [__LINE__-1, 41, __LINE__-1, 47] | ||
|
|
||
| def return_block(&block) | ||
| block | ||
| end | ||
|
|
||
| iter = Object.new | ||
| def iter.each(&block) | ||
| block.call(block) | ||
| end | ||
|
|
||
| for pr in iter | ||
| 42 | ||
| end | ||
| FOR_BODY_PROC = pr | ||
| FOR_BODY_PROC_LOCATION = [__LINE__-4, 4, __LINE__-2, 7] | ||
|
|
||
| def with_location(callable, locs, file = __FILE__) | ||
| source_location = [file, *locs] | ||
| if RUBY_VERSION >= "4.1" | ||
| assert_equal callable.source_location, source_location | ||
| else | ||
| callable.define_singleton_method(:source_location) { source_location } | ||
| end | ||
| callable | ||
| end | ||
|
|
||
| def test_def_method | ||
| node = Prism.node_for(with_location(NodeForTest.instance_method(:m), M_LOCATION)) | ||
| assert_instance_of(Prism::DefNode, node) | ||
| assert_equal "def m(foo)\n#{INDENT} 42\n#{INDENT}end", node.slice | ||
|
|
||
| node = Prism.node_for(with_location(method(:m), M_LOCATION)) | ||
| assert_instance_of(Prism::DefNode, node) | ||
| assert_equal "def m(foo)\n 42\n end", node.slice | ||
| end | ||
|
|
||
| def test_def_method_utf8 | ||
| node = Prism.node_for(with_location(method(:été), UTF8_LOCATION)) | ||
| assert_instance_of(Prism::DefNode, node) | ||
| assert_equal "def été; 42; end", node.slice | ||
| end | ||
|
|
||
| def test_inline_method | ||
| node = Prism.node_for(with_location(method(:inline_method), *INLINE_LOCATION_AND_FILE)) | ||
| assert_instance_of(Prism::DefNode, node) | ||
| assert_equal "def inline_method = 42", node.slice | ||
| end | ||
|
|
||
| def test_define_method | ||
| node = Prism.node_for(with_location(method(:define_method_method), DEFINE_METHOD_LOCATION)) | ||
| assert_instance_of(Prism::CallNode, node) | ||
| assert_equal "define_method(:define_method_method) { 42 }", node.slice | ||
| assert_equal "{ 42 }", node.block.slice | ||
| end | ||
|
|
||
| def test_lambda | ||
| node = Prism.node_for(with_location(-> { 42 }, [__LINE__, 42, __LINE__, 51])) | ||
| assert_instance_of(Prism::LambdaNode, node) | ||
| assert_equal "-> { 42 }", node.slice | ||
| assert_equal "{ 42 }", node.opening_loc.join(node.closing_loc).slice | ||
|
|
||
| node = Prism.node_for(with_location(lambda { 42 }, [__LINE__, 49, __LINE__, 55])) | ||
| assert_instance_of(Prism::CallNode, node) | ||
| assert_equal "lambda { 42 }", node.slice | ||
| assert_equal "{ 42 }", node.block.slice | ||
| end | ||
|
|
||
| def test_proc | ||
| node = Prism.node_for(with_location(proc { 42 }, [__LINE__, 47, __LINE__, 53])) | ||
| assert_instance_of(Prism::CallNode, node) | ||
| assert_equal "proc { 42 }", node.slice | ||
| assert_equal "{ 42 }", node.block.slice | ||
|
|
||
| node = Prism.node_for(with_location(return_block { 42 }, [__LINE__, 55, __LINE__, 61])) | ||
| assert_instance_of(Prism::CallNode, node) | ||
| assert_equal "return_block { 42 }", node.slice | ||
| assert_equal "{ 42 }", node.block.slice | ||
|
|
||
| heredoc_proc = proc { <<~END } | ||
| heredoc | ||
| END | ||
| node = Prism.node_for(with_location(heredoc_proc, [__LINE__-3, 26, __LINE__-3, 36])) | ||
| assert_instance_of(Prism::CallNode, node) | ||
| assert_equal "proc { <<~END }", node.slice | ||
| assert_equal "heredoc\n", node.block.body.body.first.unescaped | ||
| end | ||
|
|
||
| def test_method_to_proc | ||
| node = Prism.node_for(with_location(method(:inline_method).to_proc, *INLINE_LOCATION_AND_FILE)) | ||
| assert_instance_of(Prism::DefNode, node) | ||
| assert_equal "def inline_method = 42", node.slice | ||
| end | ||
|
|
||
| def test_for | ||
| node = Prism.node_for(with_location(FOR_BODY_PROC, FOR_BODY_PROC_LOCATION)) | ||
| assert_instance_of(Prism::ForNode, node) | ||
| assert_equal "for pr in iter\n#{INDENT} 42\n#{INDENT}end", node.slice | ||
| assert_equal "42", node.statements.slice | ||
| end | ||
|
|
||
| def test_eval | ||
| l = with_location(eval("-> { 42 }"), [1, 0, 1, 9], "(eval at #{__FILE__}:#{__LINE__})") | ||
| e = assert_raise(ArgumentError) { Prism.node_for(l) } | ||
| assert_include e.message, 'eval' | ||
|
|
||
| l = eval "-> { 42 }", nil, __FILE__, __LINE__ | ||
| l = with_location(l, [__LINE__-1, 0, __LINE__-1, 9]) | ||
| e = assert_raise(ArgumentError) { Prism.node_for(l) } | ||
| assert_include e.message, 'Could not find node' | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require_relative "../test_helper" | ||
|
|
||
| module Prism | ||
| class SourceTest < TestCase | ||
| def test_line_to_byte_offset | ||
| parse_result = Prism.parse(<<~SRC) | ||
| abcd | ||
| efgh | ||
| ijkl | ||
| SRC | ||
| source = parse_result.source | ||
|
|
||
| assert_equal 0, source.line_to_byte_offset(1) | ||
| assert_equal 5, source.line_to_byte_offset(2) | ||
| assert_equal 10, source.line_to_byte_offset(3) | ||
| assert_equal 15, source.line_to_byte_offset(4) | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(5) } | ||
| assert_equal "line 5 is out of range", e.message | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(0) } | ||
| assert_equal "line 0 is out of range", e.message | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(-1) } | ||
| assert_equal "line -1 is out of range", e.message | ||
| end | ||
|
|
||
| def test_line_to_byte_offset_with_start_line | ||
| parse_result = Prism.parse(<<~SRC, line: 11) | ||
| abcd | ||
| efgh | ||
| ijkl | ||
| SRC | ||
| source = parse_result.source | ||
|
|
||
| assert_equal 0, source.line_to_byte_offset(11) | ||
| assert_equal 5, source.line_to_byte_offset(12) | ||
| assert_equal 10, source.line_to_byte_offset(13) | ||
| assert_equal 15, source.line_to_byte_offset(14) | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(15) } | ||
| assert_equal "line 15 is out of range", e.message | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(10) } | ||
| assert_equal "line 10 is out of range", e.message | ||
| e = assert_raise(ArgumentError) { source.line_to_byte_offset(9) } | ||
| assert_equal "line 9 is out of range", e.message | ||
| end | ||
| end | ||
| end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.