[ruby/prism] Split comment

We were previously holding a type field on Comment to tell what
kind of comment it was. Instead, let's just use actual classes for
this.

https://github.com/ruby/prism/commit/e76830ca6e
This commit is contained in:
Kevin Newton 2023-11-03 09:40:19 -04:00 committed by git
parent 1321df773b
commit 4b5f516f2e
4 changed files with 60 additions and 38 deletions

View File

@ -189,45 +189,58 @@ module Prism
end
end
# This represents a comment that was encountered during parsing.
# This represents a comment that was encountered during parsing. It is the
# base class for all comment types.
class Comment
# These are the three types that comments can be from a source file.
#
# :inline comments are the most common. They correspond to comments in the
# source file like this one that start with #.
#
# :embdoc comments are comments that are surrounded by =begin and =end.
#
# :__END__ comments are comments that are after the __END__ keyword in a
# source file.
TYPES = [:inline, :embdoc, :__END__]
# The type of comment that this comment is.
attr_reader :type
# The location of this comment in the source.
attr_reader :location
# Create a new comment object with the given type and location.
def initialize(type, location)
@type = type
# Create a new comment object with the given location.
def initialize(location)
@location = location
end
# Implement the hash pattern matching interface for Comment.
def deconstruct_keys(keys)
{ type: type, location: location }
{ location: location }
end
# Returns true if the comment happens on the same line as other code and
# This can only be true for inline comments.
def trailing?
false
end
end
# InlineComment objects are the most common. They correspond to comments in
# the source file like this one that start with #.
class InlineComment < Comment
# Returns true if this comment happens on the same line as other code and
# false if the comment is by itself.
def trailing?
type == :inline && !location.start_line_slice.strip.empty?
!location.start_line_slice.strip.empty?
end
# Returns a string representation of this comment.
def inspect
"#<Prism::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
"#<Prism::InlineComment @location=#{location.inspect}>"
end
end
# EmbDocComment objects correspond to comments that are surrounded by =begin
# and =end.
class EmbDocComment < Comment
# Returns a string representation of this comment.
def inspect
"#<Prism::EmbDocComment @location=#{location.inspect}>"
end
end
# DATAComment objects correspond to comments that are after the __END__
# keyword in a source file.
class DATAComment < Comment
# Returns a string representation of this comment.
def inspect
"#<Prism::DATAComment @location=#{location.inspect}>"
end
end

View File

@ -10,6 +10,9 @@ VALUE rb_cPrismToken;
VALUE rb_cPrismLocation;
VALUE rb_cPrismComment;
VALUE rb_cPrismInlineComment;
VALUE rb_cPrismEmbDocComment;
VALUE rb_cPrismDATAComment;
VALUE rb_cPrismMagicComment;
VALUE rb_cPrismParseError;
VALUE rb_cPrismParseWarning;
@ -320,21 +323,18 @@ parser_comments(pm_parser_t *parser, VALUE source) {
VALUE type;
switch (comment->type) {
case PM_COMMENT_INLINE:
type = ID2SYM(rb_intern("inline"));
type = rb_cPrismInlineComment;
break;
case PM_COMMENT_EMBDOC:
type = ID2SYM(rb_intern("embdoc"));
type = rb_cPrismEmbDocComment;
break;
case PM_COMMENT___END__:
type = ID2SYM(rb_intern("__END__"));
break;
default:
type = ID2SYM(rb_intern("inline"));
type = rb_cPrismDATAComment;
break;
}
VALUE comment_argv[] = { type, rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
rb_ary_push(comments, rb_class_new_instance(2, comment_argv, rb_cPrismComment));
VALUE comment_argv[] = { rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
rb_ary_push(comments, rb_class_new_instance(1, comment_argv, type));
}
return comments;
@ -933,6 +933,9 @@ Init_prism(void) {
rb_cPrismToken = rb_define_class_under(rb_cPrism, "Token", rb_cObject);
rb_cPrismLocation = rb_define_class_under(rb_cPrism, "Location", rb_cObject);
rb_cPrismComment = rb_define_class_under(rb_cPrism, "Comment", rb_cObject);
rb_cPrismInlineComment = rb_define_class_under(rb_cPrism, "InlineComment", rb_cPrismComment);
rb_cPrismEmbDocComment = rb_define_class_under(rb_cPrism, "EmbDocComment", rb_cPrismComment);
rb_cPrismDATAComment = rb_define_class_under(rb_cPrism, "DATAComment", rb_cPrismComment);
rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);

View File

@ -86,7 +86,13 @@ module Prism
end
def load_comments
load_varint.times.map { Comment.new(Comment::TYPES.fetch(load_varint), load_location) }
load_varint.times.map do
case load_varint
when 0 then InlineComment.new(load_location)
when 1 then EmbDocComment.new(load_location)
when 2 then DATAComment.new(load_location)
end
end
end
def load_metadata

View File

@ -10,7 +10,7 @@ module Prism
assert_comment(
source,
:inline,
InlineComment,
start_offset: 0,
end_offset: 9,
start_line: 1,
@ -29,7 +29,7 @@ module Prism
assert_comment(
source,
:inline,
InlineComment,
start_offset: 10,
end_offset: 21,
start_line: 2,
@ -47,7 +47,7 @@ module Prism
assert_comment(
source,
:__END__,
DATAComment,
start_offset: 0,
end_offset: 16,
start_line: 1,
@ -62,7 +62,7 @@ module Prism
assert_comment(
source,
:__END__,
DATAComment,
start_offset: 0,
end_offset: 18,
start_line: 1,
@ -81,7 +81,7 @@ module Prism
assert_comment(
source,
:embdoc,
EmbDocComment,
start_offset: 0,
end_offset: 20,
start_line: 1,
@ -99,7 +99,7 @@ module Prism
assert_comment(
source,
:embdoc,
EmbDocComment,
start_offset: 0,
end_offset: 24,
start_line: 1,
@ -138,7 +138,7 @@ module Prism
def assert_comment(source, type, start_offset:, end_offset:, start_line:, end_line:, start_column:, end_column:)
result = Prism.parse(source)
assert result.errors.empty?, result.errors.map(&:message).join("\n")
assert_equal type, result.comments.first.type
assert_kind_of type, result.comments.first
location = result.comments.first.location
assert_equal start_offset, location.start_offset, -> { "Expected start_offset to be #{start_offset}" }