Skip to content

Commit

Permalink
Split comment
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kddnewton committed Nov 3, 2023
1 parent ed8d1c0 commit e76830c
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 47 deletions.
19 changes: 11 additions & 8 deletions ext/prism/extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
57 changes: 35 additions & 22 deletions lib/prism/parse_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -189,45 +189,58 @@ def self.null
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

Expand Down
11 changes: 3 additions & 8 deletions rakelib/check_annotations.rake
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
# frozen_string_literal: true

desc "Check that RBS and RBI generated files are valid"
task :check_annotations do
task check_annotations: :compile do
require "prism"
require "rbs"
require "rbs/cli"

# Run `rbs` against the generated file, which checks for valid syntax and any missing constants
puts "Checking RBS annotations"
# output = Bundler.with_original_env { `rbs -I sig/prism.rbs validate` }
begin
cli = RBS::CLI.new(stdout: STDOUT, stderr: STDERR)
cli.run(["-I", "sig", "validate"])
rescue => e
abort(e.message)
end
cli = RBS::CLI.new(stdout: STDOUT, stderr: STDERR)
cli.run(["-I", "sig", "validate"])

# For RBI files, we just use Prism itself to check for valid syntax since they use Ruby compliant syntax
puts "Checking RBI annotations"
Expand Down
2 changes: 1 addition & 1 deletion rakelib/check_manifest.rake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
desc "Perform a sanity check on the gemspec file list"
task :check_manifest => [:templates] do
task check_manifest: :templates do
raw_gemspec = Bundler.load_gemspec("prism.gemspec")

ignore_directories = %w[
Expand Down
14 changes: 14 additions & 0 deletions rbi/prism_static.rbi
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ module Prism
class Comment
sig { returns(Location) }
def location; end

sig { returns(T::Boolean) }
def trailing?; end
end

class InlineComment < Comment
sig { override.returns(T::Boolean) }
def trailing?; end
end

class EmbDocComment < Comment
end

class DATAComment < Comment
end

class Location
Expand Down
11 changes: 11 additions & 0 deletions sig/prism_static.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ module Prism

class Comment
def location: () -> Location
def trailing?: () -> bool
end

class InlineComment < Comment
def trailing?: () -> bool
end

class EmbDocComment < Comment
end

class DATAComment < Comment
end

class Location
Expand Down
8 changes: 7 additions & 1 deletion templates/lib/prism/serialize.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 7 additions & 7 deletions test/prism/comments_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_comment_inline

assert_comment(
source,
:inline,
InlineComment,
start_offset: 0,
end_offset: 9,
start_line: 1,
Expand All @@ -29,7 +29,7 @@ def foo

assert_comment(
source,
:inline,
InlineComment,
start_offset: 10,
end_offset: 21,
start_line: 2,
Expand All @@ -47,7 +47,7 @@ def test_comment___END__

assert_comment(
source,
:__END__,
DATAComment,
start_offset: 0,
end_offset: 16,
start_line: 1,
Expand All @@ -62,7 +62,7 @@ def test_comment___END__crlf

assert_comment(
source,
:__END__,
DATAComment,
start_offset: 0,
end_offset: 18,
start_line: 1,
Expand All @@ -81,7 +81,7 @@ def test_comment_embedded_document

assert_comment(
source,
:embdoc,
EmbDocComment,
start_offset: 0,
end_offset: 20,
start_line: 1,
Expand All @@ -99,7 +99,7 @@ def test_comment_embedded_document_with_content_on_same_line

assert_comment(
source,
:embdoc,
EmbDocComment,
start_offset: 0,
end_offset: 24,
start_line: 1,
Expand Down Expand Up @@ -138,7 +138,7 @@ def bar
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}" }
Expand Down

0 comments on commit e76830c

Please sign in to comment.