diff --git a/config.yml b/config.yml index feb9a40a0..8551779f3 100644 --- a/config.yml +++ b/config.yml @@ -784,6 +784,30 @@ nodes: - name: type_name_location c_type: rbs_location_range optional: true + - name: RBS::AST::Ruby::Annotations::ModuleSelfAnnotation + rust_name: ModuleSelfAnnotationNode + fields: + - name: prefix_location + c_type: rbs_location_range + - name: keyword_location + c_type: rbs_location_range + - name: colon_location + c_type: rbs_location_range + - name: name + c_type: rbs_type_name + - name: args + c_type: rbs_node_list + - name: open_bracket_location + c_type: rbs_location_range + optional: true + - name: close_bracket_location + c_type: rbs_location_range + optional: true + - name: args_comma_locations + c_type: rbs_location_range_list + - name: comment_location + c_type: rbs_location_range + optional: true - name: RBS::AST::Ruby::Annotations::ParamTypeAnnotation rust_name: ParamTypeAnnotationNode fields: diff --git a/docs/inline.md b/docs/inline.md index bfa1ca3ae..e9c976142 100644 --- a/docs/inline.md +++ b/docs/inline.md @@ -123,10 +123,38 @@ end This creates the types `::API`, `::API::V1`, and `::API::V1::Resources`. +### `module-self` constraint + +The `module-self` constraint declares which classes or modules the module can be mixed into. + +```ruby +# @rbs module-self: _Each[String] +module Enumerable2 +end +``` + +This is equivalent to `module Enumerable2 : _Each[String]` in RBS, meaning `Enumerable2` can only be included in classes that satisfy the `_Each[String]` interface. + +Multiple `module-self` constraints can be declared with separate annotations: + +```ruby +# @rbs module-self: _Each[String] +# @rbs module-self: Comparable +module StringCollection +end +``` + +You can add a description after `--`: + +```ruby +# @rbs module-self: Minitest::Test -- depending on assertion methods +module TestHelper +end +``` + ### Current Limitations - Generic module definitions are not supported -- Module self-type constraints are not supported ## Method Definitions diff --git a/ext/rbs_extension/ast_translation.c b/ext/rbs_extension/ast_translation.c index cba77e3a3..c0e0ecb9b 100644 --- a/ext/rbs_extension/ast_translation.c +++ b/ext/rbs_extension/ast_translation.c @@ -947,6 +947,27 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan &h ); } + case RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION: { + rbs_ast_ruby_annotations_module_self_annotation_t *node = (rbs_ast_ruby_annotations_module_self_annotation_t *) instance; + + VALUE h = rb_hash_new(); + rb_hash_aset(h, ID2SYM(rb_intern("location")), rbs_location_range_to_ruby_location(ctx, node->base.location)); + rb_hash_aset(h, ID2SYM(rb_intern("prefix_location")), rbs_location_range_to_ruby_location(ctx, node->prefix_location)); + rb_hash_aset(h, ID2SYM(rb_intern("keyword_location")), rbs_location_range_to_ruby_location(ctx, node->keyword_location)); + rb_hash_aset(h, ID2SYM(rb_intern("colon_location")), rbs_location_range_to_ruby_location(ctx, node->colon_location)); + rb_hash_aset(h, ID2SYM(rb_intern("name")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->name)); // rbs_type_name + rb_hash_aset(h, ID2SYM(rb_intern("args")), rbs_node_list_to_ruby_array(ctx, node->args)); + rb_hash_aset(h, ID2SYM(rb_intern("open_bracket_location")), rbs_location_range_to_ruby_location(ctx, node->open_bracket_location)); // optional + rb_hash_aset(h, ID2SYM(rb_intern("close_bracket_location")), rbs_location_range_to_ruby_location(ctx, node->close_bracket_location)); // optional + rb_hash_aset(h, ID2SYM(rb_intern("args_comma_locations")), rbs_location_range_list_to_ruby_array(ctx, node->args_comma_locations)); + rb_hash_aset(h, ID2SYM(rb_intern("comment_location")), rbs_location_range_to_ruby_location(ctx, node->comment_location)); // optional + + return CLASS_NEW_INSTANCE( + RBS_AST_Ruby_Annotations_ModuleSelfAnnotation, + 1, + &h + ); + } case RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION: { rbs_ast_ruby_annotations_node_type_assertion_t *node = (rbs_ast_ruby_annotations_node_type_assertion_t *) instance; diff --git a/ext/rbs_extension/class_constants.c b/ext/rbs_extension/class_constants.c index 789f216bf..0445a6d25 100644 --- a/ext/rbs_extension/class_constants.c +++ b/ext/rbs_extension/class_constants.c @@ -54,6 +54,7 @@ VALUE RBS_AST_Ruby_Annotations_DoubleSplatParamTypeAnnotation; VALUE RBS_AST_Ruby_Annotations_InstanceVariableAnnotation; VALUE RBS_AST_Ruby_Annotations_MethodTypesAnnotation; VALUE RBS_AST_Ruby_Annotations_ModuleAliasAnnotation; +VALUE RBS_AST_Ruby_Annotations_ModuleSelfAnnotation; VALUE RBS_AST_Ruby_Annotations_NodeTypeAssertion; VALUE RBS_AST_Ruby_Annotations_ParamTypeAnnotation; VALUE RBS_AST_Ruby_Annotations_ReturnTypeAnnotation; @@ -147,6 +148,7 @@ void rbs__init_constants(void) { IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_InstanceVariableAnnotation, RBS_AST_Ruby_Annotations, "InstanceVariableAnnotation"); IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_MethodTypesAnnotation, RBS_AST_Ruby_Annotations, "MethodTypesAnnotation"); IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ModuleAliasAnnotation, RBS_AST_Ruby_Annotations, "ModuleAliasAnnotation"); + IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ModuleSelfAnnotation, RBS_AST_Ruby_Annotations, "ModuleSelfAnnotation"); IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_NodeTypeAssertion, RBS_AST_Ruby_Annotations, "NodeTypeAssertion"); IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ParamTypeAnnotation, RBS_AST_Ruby_Annotations, "ParamTypeAnnotation"); IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ReturnTypeAnnotation, RBS_AST_Ruby_Annotations, "ReturnTypeAnnotation"); diff --git a/ext/rbs_extension/class_constants.h b/ext/rbs_extension/class_constants.h index 9b9abdc18..1a3e2afa8 100644 --- a/ext/rbs_extension/class_constants.h +++ b/ext/rbs_extension/class_constants.h @@ -62,6 +62,7 @@ extern VALUE RBS_AST_Ruby_Annotations_DoubleSplatParamTypeAnnotation; extern VALUE RBS_AST_Ruby_Annotations_InstanceVariableAnnotation; extern VALUE RBS_AST_Ruby_Annotations_MethodTypesAnnotation; extern VALUE RBS_AST_Ruby_Annotations_ModuleAliasAnnotation; +extern VALUE RBS_AST_Ruby_Annotations_ModuleSelfAnnotation; extern VALUE RBS_AST_Ruby_Annotations_NodeTypeAssertion; extern VALUE RBS_AST_Ruby_Annotations_ParamTypeAnnotation; extern VALUE RBS_AST_Ruby_Annotations_ReturnTypeAnnotation; diff --git a/include/rbs/ast.h b/include/rbs/ast.h index 4b0b4445d..eff24425e 100644 --- a/include/rbs/ast.h +++ b/include/rbs/ast.h @@ -97,44 +97,45 @@ enum rbs_node_type { RBS_AST_RUBY_ANNOTATIONS_INSTANCE_VARIABLE_ANNOTATION = 36, RBS_AST_RUBY_ANNOTATIONS_METHOD_TYPES_ANNOTATION = 37, RBS_AST_RUBY_ANNOTATIONS_MODULE_ALIAS_ANNOTATION = 38, - RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION = 39, - RBS_AST_RUBY_ANNOTATIONS_PARAM_TYPE_ANNOTATION = 40, - RBS_AST_RUBY_ANNOTATIONS_RETURN_TYPE_ANNOTATION = 41, - RBS_AST_RUBY_ANNOTATIONS_SKIP_ANNOTATION = 42, - RBS_AST_RUBY_ANNOTATIONS_SPLAT_PARAM_TYPE_ANNOTATION = 43, - RBS_AST_RUBY_ANNOTATIONS_TYPE_APPLICATION_ANNOTATION = 44, - RBS_AST_STRING = 45, - RBS_AST_TYPE_PARAM = 46, - RBS_METHOD_TYPE = 47, - RBS_NAMESPACE = 48, - RBS_SIGNATURE = 49, - RBS_TYPE_NAME = 50, - RBS_TYPES_ALIAS = 51, - RBS_TYPES_BASES_ANY = 52, - RBS_TYPES_BASES_BOOL = 53, - RBS_TYPES_BASES_BOTTOM = 54, - RBS_TYPES_BASES_CLASS = 55, - RBS_TYPES_BASES_INSTANCE = 56, - RBS_TYPES_BASES_NIL = 57, - RBS_TYPES_BASES_SELF = 58, - RBS_TYPES_BASES_TOP = 59, - RBS_TYPES_BASES_VOID = 60, - RBS_TYPES_BLOCK = 61, - RBS_TYPES_CLASS_INSTANCE = 62, - RBS_TYPES_CLASS_SINGLETON = 63, - RBS_TYPES_FUNCTION = 64, - RBS_TYPES_FUNCTION_PARAM = 65, - RBS_TYPES_INTERFACE = 66, - RBS_TYPES_INTERSECTION = 67, - RBS_TYPES_LITERAL = 68, - RBS_TYPES_OPTIONAL = 69, - RBS_TYPES_PROC = 70, - RBS_TYPES_RECORD = 71, - RBS_TYPES_RECORD_FIELD_TYPE = 72, - RBS_TYPES_TUPLE = 73, - RBS_TYPES_UNION = 74, - RBS_TYPES_UNTYPED_FUNCTION = 75, - RBS_TYPES_VARIABLE = 76, + RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION = 39, + RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION = 40, + RBS_AST_RUBY_ANNOTATIONS_PARAM_TYPE_ANNOTATION = 41, + RBS_AST_RUBY_ANNOTATIONS_RETURN_TYPE_ANNOTATION = 42, + RBS_AST_RUBY_ANNOTATIONS_SKIP_ANNOTATION = 43, + RBS_AST_RUBY_ANNOTATIONS_SPLAT_PARAM_TYPE_ANNOTATION = 44, + RBS_AST_RUBY_ANNOTATIONS_TYPE_APPLICATION_ANNOTATION = 45, + RBS_AST_STRING = 46, + RBS_AST_TYPE_PARAM = 47, + RBS_METHOD_TYPE = 48, + RBS_NAMESPACE = 49, + RBS_SIGNATURE = 50, + RBS_TYPE_NAME = 51, + RBS_TYPES_ALIAS = 52, + RBS_TYPES_BASES_ANY = 53, + RBS_TYPES_BASES_BOOL = 54, + RBS_TYPES_BASES_BOTTOM = 55, + RBS_TYPES_BASES_CLASS = 56, + RBS_TYPES_BASES_INSTANCE = 57, + RBS_TYPES_BASES_NIL = 58, + RBS_TYPES_BASES_SELF = 59, + RBS_TYPES_BASES_TOP = 60, + RBS_TYPES_BASES_VOID = 61, + RBS_TYPES_BLOCK = 62, + RBS_TYPES_CLASS_INSTANCE = 63, + RBS_TYPES_CLASS_SINGLETON = 64, + RBS_TYPES_FUNCTION = 65, + RBS_TYPES_FUNCTION_PARAM = 66, + RBS_TYPES_INTERFACE = 67, + RBS_TYPES_INTERSECTION = 68, + RBS_TYPES_LITERAL = 69, + RBS_TYPES_OPTIONAL = 70, + RBS_TYPES_PROC = 71, + RBS_TYPES_RECORD = 72, + RBS_TYPES_RECORD_FIELD_TYPE = 73, + RBS_TYPES_TUPLE = 74, + RBS_TYPES_UNION = 75, + RBS_TYPES_UNTYPED_FUNCTION = 76, + RBS_TYPES_VARIABLE = 77, RBS_AST_SYMBOL, }; @@ -633,6 +634,20 @@ typedef struct rbs_ast_ruby_annotations_module_alias_annotation { rbs_location_range type_name_location; /* Optional */ } rbs_ast_ruby_annotations_module_alias_annotation_t; +typedef struct rbs_ast_ruby_annotations_module_self_annotation { + rbs_node_t base; + + rbs_location_range prefix_location; + rbs_location_range keyword_location; + rbs_location_range colon_location; + struct rbs_type_name *name; + struct rbs_node_list *args; + rbs_location_range open_bracket_location; /* Optional */ + rbs_location_range close_bracket_location; /* Optional */ + rbs_location_range_list_t *args_comma_locations; + rbs_location_range comment_location; /* Optional */ +} rbs_ast_ruby_annotations_module_self_annotation_t; + typedef struct rbs_ast_ruby_annotations_node_type_assertion { rbs_node_t base; @@ -980,6 +995,7 @@ rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *rbs_ast_ruby_anno rbs_ast_ruby_annotations_instance_variable_annotation_t *rbs_ast_ruby_annotations_instance_variable_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_ast_symbol_t *ivar_name, rbs_location_range ivar_name_location, rbs_location_range colon_location, rbs_node_t *type, rbs_location_range comment_location); rbs_ast_ruby_annotations_method_types_annotation_t *rbs_ast_ruby_annotations_method_types_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *overloads, rbs_location_range_list_t *vertical_bar_locations, rbs_location_range dot3_location); rbs_ast_ruby_annotations_module_alias_annotation_t *rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *type_name, rbs_location_range type_name_location); +rbs_ast_ruby_annotations_module_self_annotation_t *rbs_ast_ruby_annotations_module_self_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_location_range colon_location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range open_bracket_location, rbs_location_range close_bracket_location, rbs_location_range_list_t *args_comma_locations, rbs_location_range comment_location); rbs_ast_ruby_annotations_node_type_assertion_t *rbs_ast_ruby_annotations_node_type_assertion_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_t *type); rbs_ast_ruby_annotations_param_type_annotation_t *rbs_ast_ruby_annotations_param_type_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *param_type, rbs_location_range comment_location); rbs_ast_ruby_annotations_return_type_annotation_t *rbs_ast_ruby_annotations_return_type_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range return_location, rbs_location_range colon_location, rbs_node_t *return_type, rbs_location_range comment_location); diff --git a/include/rbs/lexer.h b/include/rbs/lexer.h index 4f182ba1e..6b5c533e8 100644 --- a/include/rbs/lexer.h +++ b/include/rbs/lexer.h @@ -70,6 +70,7 @@ enum RBSTokenType { kATRBS, /* @rbs */ kSKIP, /* skip */ kRETURN, /* return */ + kMODULESELF, /* module-self */ tLIDENT, /* Identifiers starting with lower case */ tUIDENT, /* Identifiers starting with upper case */ diff --git a/lib/rbs/ast/ruby/annotations.rb b/lib/rbs/ast/ruby/annotations.rb index 9c3ee0bc8..ae9de3b59 100644 --- a/lib/rbs/ast/ruby/annotations.rb +++ b/lib/rbs/ast/ruby/annotations.rb @@ -353,6 +353,48 @@ def type_fingerprint end end + class ModuleSelfAnnotation < Base + attr_reader :keyword_location, :colon_location, :name, :args, :open_bracket_location, :close_bracket_location, :args_comma_locations, :comment_location + + def initialize(location:, prefix_location:, keyword_location:, colon_location:, name:, args:, open_bracket_location:, close_bracket_location:, args_comma_locations:, comment_location:) + super(location, prefix_location) + @keyword_location = keyword_location + @colon_location = colon_location + @name = name + @args = args + @open_bracket_location = open_bracket_location + @close_bracket_location = close_bracket_location + @args_comma_locations = args_comma_locations + @comment_location = comment_location + end + + def map_type_name + mapped_args = args.map { |type| type.map_type_name { yield _1 } } + + self.class.new( + location:, + prefix_location:, + keyword_location:, + colon_location:, + name: yield(name), + args: mapped_args, + open_bracket_location:, + close_bracket_location:, + args_comma_locations:, + comment_location: + ) #: self + end + + def type_fingerprint + [ + "annots/module_self", + name.to_s, + args.map(&:to_s), + comment_location&.source + ] + end + end + class BlockParamTypeAnnotation < Base attr_reader :ampersand_location, :name_location, :colon_location, :question_location, :type_location, :type, :comment_location diff --git a/lib/rbs/ast/ruby/declarations.rb b/lib/rbs/ast/ruby/declarations.rb index a752afd69..4651db0c5 100644 --- a/lib/rbs/ast/ruby/declarations.rb +++ b/lib/rbs/ast/ruby/declarations.rb @@ -137,7 +137,17 @@ def each_decl(&block) def type_params = [] - def self_types = [] + def self_types + members.filter_map do |member| + if member.is_a?(Members::ModuleSelfMember) + AST::Declarations::Module::Self.new( + name: member.name, + args: member.args, + location: member.location + ) + end + end + end def location rbs_location(node.location) diff --git a/lib/rbs/ast/ruby/members.rb b/lib/rbs/ast/ruby/members.rb index 878baa39b..2cbb22a35 100644 --- a/lib/rbs/ast/ruby/members.rb +++ b/lib/rbs/ast/ruby/members.rb @@ -717,6 +717,34 @@ def type_fingerprint ] end end + + class ModuleSelfMember < Base + attr_reader :annotation + + def initialize(buffer, annotation) + super(buffer) + @annotation = annotation + end + + def name + annotation.name + end + + def args + annotation.args + end + + def location + annotation.location + end + + def type_fingerprint + [ + "members/module_self", + annotation.type_fingerprint + ] + end + end end end end diff --git a/lib/rbs/environment.rb b/lib/rbs/environment.rb index b600260b7..ad06efea6 100644 --- a/lib/rbs/environment.rb +++ b/lib/rbs/environment.rb @@ -854,6 +854,12 @@ def resolve_ruby_member(resolver, member, context:) member.buffer, resolved_annotation ) + when AST::Ruby::Members::ModuleSelfMember + resolved_annotation = member.annotation.map_type_name {|name| absolute_type_name(resolver, nil, name, context: context) } + AST::Ruby::Members::ModuleSelfMember.new( + member.buffer, + resolved_annotation + ) else raise "Unknown member type: #{member.class}" end diff --git a/lib/rbs/inline_parser.rb b/lib/rbs/inline_parser.rb index aa92c58a1..0bb1cf013 100644 --- a/lib/rbs/inline_parser.rb +++ b/lib/rbs/inline_parser.rb @@ -134,6 +134,32 @@ def visit_module_node(node) end module_decl = AST::Ruby::Declarations::ModuleDecl.new(buffer, module_name, node) + + if leading_ref = comments.leading_block(node) + unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation] + + leading_ref.block.each_paragraph([]) do |paragraph| + case paragraph + when AST::Ruby::Annotations::ModuleSelfAnnotation + module_decl.members << AST::Ruby::Members::ModuleSelfMember.new(buffer, paragraph) + when Location + # Skip + when AST::Ruby::CommentBlock::AnnotationSyntaxError + unused_annotations << paragraph + when AST::Ruby::Annotations::SkipAnnotation + # Already handled by skip_node? + else + unused_annotations << paragraph + end + end + + unless unused_annotations.empty? + report_unused_annotation(*unused_annotations) + end + + leading_ref.associate! + end + insert_declaration(module_decl) visit_class_or_module_body(module_decl, node) end diff --git a/sig/ast/ruby/annotations.rbs b/sig/ast/ruby/annotations.rbs index ac3c25e88..c058516ba 100644 --- a/sig/ast/ruby/annotations.rbs +++ b/sig/ast/ruby/annotations.rbs @@ -7,6 +7,7 @@ module RBS | SkipAnnotation | ReturnTypeAnnotation | InstanceVariableAnnotation + | ModuleSelfAnnotation | ParamTypeAnnotation | SplatParamTypeAnnotation | DoubleSplatParamTypeAnnotation @@ -237,6 +238,54 @@ module RBS def type_fingerprint: () -> untyped end + # `@rbs module-self: NAME[ARGS] -- comment` annotation in leading comments + # + # ``` + # @rbs module-self: _Each[String, Integer] -- comment + # ^^^^ -- prefix_location + # ^^^^^^^^^^^ -- keyword_location + # ^ -- colon_location + # ^ -- open_bracket_location + # ^ -- args_comma_locations[0] + # ^ -- close_bracket_location + # ^^^^^^^^^^ -- comment_location + # ``` + # + class ModuleSelfAnnotation < Base + attr_reader keyword_location: Location + + attr_reader colon_location: Location + + attr_reader name: TypeName + + attr_reader args: Array[Types::t] + + attr_reader open_bracket_location: Location? + + attr_reader close_bracket_location: Location? + + attr_reader args_comma_locations: Array[Location] + + attr_reader comment_location: Location? + + def initialize: ( + location: Location, + prefix_location: Location, + keyword_location: Location, + colon_location: Location, + name: TypeName, + args: Array[Types::t], + open_bracket_location: Location?, + close_bracket_location: Location?, + args_comma_locations: Array[Location], + comment_location: Location?, + ) -> void + + def map_type_name: () { (TypeName) -> TypeName } -> self + + def type_fingerprint: () -> untyped + end + class ParamTypeAnnotation < Base attr_reader name_location: Location diff --git a/sig/ast/ruby/members.rbs b/sig/ast/ruby/members.rbs index bdfb16201..19d8b35d6 100644 --- a/sig/ast/ruby/members.rbs +++ b/sig/ast/ruby/members.rbs @@ -16,6 +16,7 @@ module RBS | IncludeMember | ExtendMember | PrependMember | AttrReaderMember | AttrWriterMember | AttrAccessorMember | InstanceVariableMember + | ModuleSelfMember class MethodTypeAnnotation class DocStyle @@ -172,6 +173,20 @@ module RBS def type_fingerprint: () -> untyped end + + class ModuleSelfMember < Base + attr_reader annotation: Annotations::ModuleSelfAnnotation + + def initialize: (Buffer, Annotations::ModuleSelfAnnotation) -> void + + def name: () -> TypeName + + def args: () -> Array[Types::t] + + def location: () -> Location + + def type_fingerprint: () -> untyped + end end end end diff --git a/src/ast.c b/src/ast.c index 3eff42853..ba5885ffa 100644 --- a/src/ast.c +++ b/src/ast.c @@ -89,6 +89,8 @@ const char *rbs_node_type_name(rbs_node_t *node) { return "RBS::AST::Ruby::Annotations::MethodTypesAnnotation"; case RBS_AST_RUBY_ANNOTATIONS_MODULE_ALIAS_ANNOTATION: return "RBS::AST::Ruby::Annotations::ModuleAliasAnnotation"; + case RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION: + return "RBS::AST::Ruby::Annotations::ModuleSelfAnnotation"; case RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION: return "RBS::AST::Ruby::Annotations::NodeTypeAssertion"; case RBS_AST_RUBY_ANNOTATIONS_PARAM_TYPE_ANNOTATION: @@ -1016,6 +1018,28 @@ rbs_ast_ruby_annotations_module_alias_annotation_t *rbs_ast_ruby_annotations_mod return instance; } #line 140 "prism/templates/src/ast.c.erb" +rbs_ast_ruby_annotations_module_self_annotation_t *rbs_ast_ruby_annotations_module_self_annotation_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_location_range colon_location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range open_bracket_location, rbs_location_range close_bracket_location, rbs_location_range_list_t *args_comma_locations, rbs_location_range comment_location) { + rbs_ast_ruby_annotations_module_self_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_module_self_annotation_t); + + *instance = (rbs_ast_ruby_annotations_module_self_annotation_t) { + .base = (rbs_node_t) { + .type = RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION, + .location = location, + }, + .prefix_location = prefix_location, + .keyword_location = keyword_location, + .colon_location = colon_location, + .name = name, + .args = args, + .open_bracket_location = open_bracket_location, + .close_bracket_location = close_bracket_location, + .args_comma_locations = args_comma_locations, + .comment_location = comment_location, + }; + + return instance; +} +#line 140 "prism/templates/src/ast.c.erb" rbs_ast_ruby_annotations_node_type_assertion_t *rbs_ast_ruby_annotations_node_type_assertion_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_t *type) { rbs_ast_ruby_annotations_node_type_assertion_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_node_type_assertion_t); diff --git a/src/lexer.c b/src/lexer.c index 5941be2a3..4c6eaf878 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -166,7 +166,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } yy1: rbs_skip(lexer); -#line 151 "src/lexer.re" +#line 152 "src/lexer.re" { return rbs_next_eof_token(lexer); } @@ -174,7 +174,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { yy2: rbs_skip(lexer); yy3: -#line 152 "src/lexer.re" +#line 153 "src/lexer.re" { return rbs_next_token(lexer, ErrorToken); } @@ -185,7 +185,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { if (yych == '\t') goto yy4; if (yych == ' ') goto yy4; yy5: -#line 150 "src/lexer.re" +#line 151 "src/lexer.re" { return rbs_next_token(lexer, tTRIVIA); } @@ -572,7 +572,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy38: -#line 136 "src/lexer.re" +#line 137 "src/lexer.re" { return rbs_next_token(lexer, tUIDENT); } @@ -621,7 +621,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy43: -#line 139 "src/lexer.re" +#line 140 "src/lexer.re" { return rbs_next_token(lexer, tULLIDENT); } @@ -655,7 +655,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { goto yy54; } yy47: -#line 135 "src/lexer.re" +#line 136 "src/lexer.re" { return rbs_next_token(lexer, tLIDENT); } @@ -836,7 +836,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } yy71: rbs_skip(lexer); -#line 113 "src/lexer.re" +#line 114 "src/lexer.re" { return rbs_next_token(lexer, tDQSTRING); } @@ -877,7 +877,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy74: -#line 146 "src/lexer.re" +#line 147 "src/lexer.re" { return rbs_next_token(lexer, tGIDENT); } @@ -920,7 +920,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { yy79: rbs_skip(lexer); yy80: -#line 114 "src/lexer.re" +#line 115 "src/lexer.re" { return rbs_next_token(lexer, tSQSTRING); } @@ -970,7 +970,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { if (yych == '=') goto yy90; if (yych == '~') goto yy90; yy87: -#line 133 "src/lexer.re" +#line 134 "src/lexer.re" { return rbs_next_token(lexer, tSYMBOL); } @@ -1116,7 +1116,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy100: -#line 129 "src/lexer.re" +#line 130 "src/lexer.re" { return rbs_next_token(lexer, tSYMBOL); } @@ -1172,7 +1172,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy108: -#line 143 "src/lexer.re" +#line 144 "src/lexer.re" { return rbs_next_token(lexer, tAIDENT); } @@ -1184,14 +1184,14 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { goto yy107; yy110: rbs_skip(lexer); -#line 140 "src/lexer.re" +#line 141 "src/lexer.re" { return rbs_next_token(lexer, tBANGIDENT); } #line 1041 "src/lexer.c" yy111: rbs_skip(lexer); -#line 141 "src/lexer.re" +#line 142 "src/lexer.re" { return rbs_next_token(lexer, tEQIDENT); } @@ -1226,7 +1226,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy115: -#line 137 "src/lexer.re" +#line 138 "src/lexer.re" { return rbs_next_token(lexer, tULLIDENT); } @@ -1251,7 +1251,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy117: -#line 138 "src/lexer.re" +#line 139 "src/lexer.re" { return rbs_next_token(lexer, tULIDENT); } @@ -1292,7 +1292,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy122: -#line 100 "src/lexer.re" +#line 101 "src/lexer.re" { return rbs_next_token(lexer, kAS); } @@ -1519,7 +1519,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { #line 1355 "src/lexer.c" yy156: rbs_skip(lexer); -#line 115 "src/lexer.re" +#line 116 "src/lexer.re" { return rbs_next_token(lexer, tDQSYMBOL); } @@ -1560,7 +1560,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy159: -#line 132 "src/lexer.re" +#line 133 "src/lexer.re" { return rbs_next_token(lexer, tSYMBOL); } @@ -1571,7 +1571,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { yy161: rbs_skip(lexer); yy162: -#line 116 "src/lexer.re" +#line 117 "src/lexer.re" { return rbs_next_token(lexer, tSQSYMBOL); } @@ -1630,7 +1630,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy168: -#line 130 "src/lexer.re" +#line 131 "src/lexer.re" { return rbs_next_token(lexer, tSYMBOL); } @@ -1654,7 +1654,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy171: -#line 144 "src/lexer.re" +#line 145 "src/lexer.re" { return rbs_next_token(lexer, tA2IDENT); } @@ -1821,7 +1821,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy192: -#line 86 "src/lexer.re" +#line 87 "src/lexer.re" { return rbs_next_token(lexer, kNIL); } @@ -1846,7 +1846,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy194: -#line 87 "src/lexer.re" +#line 88 "src/lexer.re" { return rbs_next_token(lexer, kOUT); } @@ -1906,7 +1906,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy203: -#line 93 "src/lexer.re" +#line 94 "src/lexer.re" { return rbs_next_token(lexer, kTOP); } @@ -1951,7 +1951,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy209: -#line 99 "src/lexer.re" +#line 100 "src/lexer.re" { return rbs_next_token(lexer, kUSE); } @@ -2064,7 +2064,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy221: -#line 131 "src/lexer.re" +#line 132 "src/lexer.re" { return rbs_next_token(lexer, tSYMBOL); } @@ -2088,7 +2088,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy224: -#line 102 "src/lexer.re" +#line 103 "src/lexer.re" { return rbs_next_token(lexer, kATRBS); } @@ -2208,7 +2208,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy242: -#line 91 "src/lexer.re" +#line 92 "src/lexer.re" { return rbs_next_token(lexer, kSELF); } @@ -2238,7 +2238,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy245: -#line 103 "src/lexer.re" +#line 104 "src/lexer.re" { return rbs_next_token(lexer, kSKIP); } @@ -2263,7 +2263,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy247: -#line 94 "src/lexer.re" +#line 95 "src/lexer.re" { return rbs_next_token(lexer, kTRUE); } @@ -2288,7 +2288,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy249: -#line 95 "src/lexer.re" +#line 96 "src/lexer.re" { return rbs_next_token(lexer, kTYPE); } @@ -2323,7 +2323,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy253: -#line 98 "src/lexer.re" +#line 99 "src/lexer.re" { return rbs_next_token(lexer, kVOID); } @@ -2662,7 +2662,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy294: -#line 90 "src/lexer.re" +#line 91 "src/lexer.re" { return rbs_next_token(lexer, kPUBLIC); } @@ -2687,7 +2687,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy296: -#line 104 "src/lexer.re" +#line 105 "src/lexer.re" { return rbs_next_token(lexer, kRETURN); } @@ -2784,6 +2784,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { rbs_skip(lexer); yych = rbs_peek(lexer); if (yych == 'a') goto yy328; + if (yych == 's') goto yy329; goto yy70; yy311: rbs_skip(lexer); @@ -2805,11 +2806,11 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy312: -#line 88 "src/lexer.re" +#line 89 "src/lexer.re" { return rbs_next_token(lexer, kPREPEND); } -#line 2578 "src/lexer.c" +#line 2579 "src/lexer.c" yy313: rbs_skip(lexer); yych = rbs_peek(lexer); @@ -2830,20 +2831,20 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy314: -#line 89 "src/lexer.re" +#line 90 "src/lexer.re" { return rbs_next_token(lexer, kPRIVATE); } -#line 2601 "src/lexer.c" +#line 2602 "src/lexer.c" yy315: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'o') goto yy329; + if (yych == 'o') goto yy330; goto yy54; yy316: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'e') goto yy330; + if (yych == 'e') goto yy331; goto yy54; yy317: rbs_skip(lexer); @@ -2865,11 +2866,11 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy318: -#line 97 "src/lexer.re" +#line 98 "src/lexer.re" { return rbs_next_token(lexer, kUNTYPED); } -#line 2634 "src/lexer.c" +#line 2635 "src/lexer.c" yy319: rbs_skip(lexer); yych = rbs_peek(lexer); @@ -2890,30 +2891,30 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } yy320: -#line 101 "src/lexer.re" +#line 102 "src/lexer.re" { return rbs_next_token(lexer, k__TODO__); } -#line 2657 "src/lexer.c" +#line 2658 "src/lexer.c" yy321: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'e') goto yy331; + if (yych == 'e') goto yy332; goto yy54; yy322: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'd') goto yy332; + if (yych == 'd') goto yy333; goto yy54; yy323: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 't') goto yy333; + if (yych == 't') goto yy334; goto yy54; yy324: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'i') goto yy334; + if (yych == 'i') goto yy335; goto yy70; yy325: rbs_skip(lexer); @@ -2939,48 +2940,53 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { { return rbs_next_token(lexer, kINSTANCE); } -#line 2700 "src/lexer.c" +#line 2701 "src/lexer.c" yy327: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'e') goto yy335; + if (yych == 'e') goto yy336; goto yy54; yy328: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'l') goto yy337; + if (yych == 'l') goto yy338; goto yy70; yy329: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'n') goto yy338; - goto yy54; + if (yych == 'e') goto yy339; + goto yy70; yy330: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'd') goto yy340; + if (yych == 'n') goto yy340; goto yy54; yy331: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 's') goto yy342; + if (yych == 'd') goto yy342; goto yy54; yy332: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'e') goto yy343; + if (yych == 's') goto yy344; goto yy54; yy333: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'e') goto yy344; + if (yych == 'e') goto yy345; goto yy54; yy334: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'a') goto yy345; - goto yy70; + if (yych == 'e') goto yy346; + goto yy54; yy335: + rbs_skip(lexer); + yych = rbs_peek(lexer); + if (yych == 'a') goto yy347; + goto yy70; + yy336: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -2992,25 +2998,30 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy336; + if (yych <= '@') goto yy337; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy336; + if (yych == '`') goto yy337; if (yych <= 'z') goto yy53; } } - yy336: + yy337: #line 83 "src/lexer.re" { return rbs_next_token(lexer, kINTERFACE); } -#line 2763 "src/lexer.c" - yy337: +#line 2769 "src/lexer.c" + yy338: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'i') goto yy346; + if (yych == 'i') goto yy348; goto yy70; - yy338: + yy339: + rbs_skip(lexer); + yych = rbs_peek(lexer); + if (yych == 'l') goto yy349; + goto yy70; + yy340: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -3022,20 +3033,20 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy339; + if (yych <= '@') goto yy341; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy339; + if (yych == '`') goto yy341; if (yych <= 'z') goto yy53; } } - yy339: -#line 92 "src/lexer.re" + yy341: +#line 93 "src/lexer.re" { return rbs_next_token(lexer, kSINGLETON); } -#line 2791 "src/lexer.c" - yy340: +#line 2802 "src/lexer.c" + yy342: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -3047,50 +3058,55 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy341; + if (yych <= '@') goto yy343; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy341; + if (yych == '`') goto yy343; if (yych <= 'z') goto yy53; } } - yy341: -#line 96 "src/lexer.re" + yy343: +#line 97 "src/lexer.re" { return rbs_next_token(lexer, kUNCHECKED); } -#line 2814 "src/lexer.c" - yy342: +#line 2825 "src/lexer.c" + yy344: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 's') goto yy347; + if (yych == 's') goto yy350; goto yy54; - yy343: + yy345: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'r') goto yy348; + if (yych == 'r') goto yy351; goto yy54; - yy344: + yy346: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'r') goto yy350; + if (yych == 'r') goto yy353; goto yy54; - yy345: + yy347: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 's') goto yy352; + if (yych == 's') goto yy355; goto yy70; - yy346: + yy348: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'a') goto yy353; + if (yych == 'a') goto yy356; goto yy70; - yy347: + yy349: + rbs_skip(lexer); + yych = rbs_peek(lexer); + if (yych == 'f') goto yy357; + goto yy70; + yy350: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'o') goto yy354; + if (yych == 'o') goto yy358; goto yy54; - yy348: + yy351: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -3102,20 +3118,20 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy349; + if (yych <= '@') goto yy352; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy349; + if (yych == '`') goto yy352; if (yych <= 'z') goto yy53; } } - yy349: + yy352: #line 70 "src/lexer.re" { return rbs_next_token(lexer, kATTRREADER); } -#line 2867 "src/lexer.c" - yy350: +#line 2883 "src/lexer.c" + yy353: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -3127,44 +3143,51 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy351; + if (yych <= '@') goto yy354; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy351; + if (yych == '`') goto yy354; if (yych <= 'z') goto yy53; } } - yy351: + yy354: #line 71 "src/lexer.re" { return rbs_next_token(lexer, kATTRWRITER); } -#line 2890 "src/lexer.c" - yy352: +#line 2906 "src/lexer.c" + yy355: rbs_skip(lexer); #line 75 "src/lexer.re" { return rbs_next_token(lexer, kCLASSALIAS); } -#line 2895 "src/lexer.c" - yy353: +#line 2911 "src/lexer.c" + yy356: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 's') goto yy355; + if (yych == 's') goto yy359; goto yy70; - yy354: + yy357: + rbs_skip(lexer); +#line 86 "src/lexer.re" + { + return rbs_next_token(lexer, kMODULESELF); + } +#line 2921 "src/lexer.c" + yy358: rbs_skip(lexer); yych = rbs_peek(lexer); - if (yych == 'r') goto yy356; + if (yych == 'r') goto yy360; goto yy54; - yy355: + yy359: rbs_skip(lexer); #line 85 "src/lexer.re" { return rbs_next_token(lexer, kMODULEALIAS); } -#line 2910 "src/lexer.c" - yy356: +#line 2931 "src/lexer.c" + yy360: rbs_skip(lexer); yych = rbs_peek(lexer); if (yych <= '=') { @@ -3176,19 +3199,19 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { } } else { if (yych <= '^') { - if (yych <= '@') goto yy357; + if (yych <= '@') goto yy361; if (yych <= 'Z') goto yy53; } else { - if (yych == '`') goto yy357; + if (yych == '`') goto yy361; if (yych <= 'z') goto yy53; } } - yy357: + yy361: #line 69 "src/lexer.re" { return rbs_next_token(lexer, kATTRACCESSOR); } -#line 2933 "src/lexer.c" +#line 2954 "src/lexer.c" } -#line 153 "src/lexer.re" +#line 154 "src/lexer.re" } diff --git a/src/lexer.re b/src/lexer.re index ee55e9305..0604816c3 100644 --- a/src/lexer.re +++ b/src/lexer.re @@ -83,6 +83,7 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer) { "interface" { return rbs_next_token(lexer, kINTERFACE); } "module" { return rbs_next_token(lexer, kMODULE); } "module-alias" { return rbs_next_token(lexer, kMODULEALIAS); } + "module-self" { return rbs_next_token(lexer, kMODULESELF); } "nil" { return rbs_next_token(lexer, kNIL); } "out" { return rbs_next_token(lexer, kOUT); } "prepend" { return rbs_next_token(lexer, kPREPEND); } diff --git a/src/lexstate.c b/src/lexstate.c index a4372bde4..d65671e5f 100644 --- a/src/lexstate.c +++ b/src/lexstate.c @@ -68,6 +68,7 @@ static const char *RBS_TOKENTYPE_NAMES[] = { "kATRBS", /* @rbs */ "kSKIP", /* skip */ "kRETURN", /* return */ + "kMODULESELF", /* module-self */ "tLIDENT", /* Identifiers starting with lower case */ "tUIDENT", /* Identifiers starting with upper case */ diff --git a/src/parser.c b/src/parser.c index 5f36e2f43..809debecf 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4052,6 +4052,60 @@ static bool parse_inline_leading_annotation(rbs_parser_t *parser, rbs_ast_ruby_a ); return true; } + case kMODULESELF: { + rbs_parser_advance(parser); + rbs_range_t keyword_range = parser->current_token.range; + + ADVANCE_ASSERT(parser, pCOLON); + rbs_range_t colon_range = parser->current_token.range; + + rbs_parser_advance(parser); + + rbs_range_t name_range; + rbs_type_name_t *type_name = NULL; + if (!parse_type_name(parser, (TypeNameKind) (CLASS_NAME | INTERFACE_NAME), &name_range, &type_name)) { + return false; + } + + rbs_node_list_t *args = rbs_node_list_new(ALLOCATOR()); + rbs_location_range open_bracket_loc = RBS_LOCATION_NULL_RANGE; + rbs_location_range close_bracket_loc = RBS_LOCATION_NULL_RANGE; + rbs_location_range_list_t *args_comma_locations = rbs_location_range_list_new(ALLOCATOR()); + if (parser->next_token.type == pLBRACKET) { + rbs_parser_advance(parser); + open_bracket_loc = RBS_RANGE_LEX2AST(parser->current_token.range); + CHECK_PARSE(parse_type_list_with_commas(parser, pRBRACKET, args, args_comma_locations, true, false, false)); + rbs_parser_advance(parser); + close_bracket_loc = RBS_RANGE_LEX2AST(parser->current_token.range); + } + + rbs_location_range comment_loc = RBS_LOCATION_NULL_RANGE; + if (!parse_inline_comment(parser, &comment_loc)) { + return false; + } + + rbs_range_t full_range = { + .start = rbs_range.start, + .end = parser->current_token.range.end + }; + + rbs_location_range full_loc = RBS_RANGE_LEX2AST(full_range); + + *annotation = (rbs_ast_ruby_annotations_t *) rbs_ast_ruby_annotations_module_self_annotation_new( + ALLOCATOR(), + full_loc, + RBS_RANGE_LEX2AST(rbs_range), + RBS_RANGE_LEX2AST(keyword_range), + RBS_RANGE_LEX2AST(colon_range), + type_name, + args, + open_bracket_loc, + close_bracket_loc, + args_comma_locations, + comment_loc + ); + return true; + } default: { rbs_parser_set_error(parser, parser->next_token, true, "unexpected token for @rbs annotation"); return false; diff --git a/test/rbs/definition_builder_test.rb b/test/rbs/definition_builder_test.rb index 04dabddf4..84d9e2b5f 100644 --- a/test/rbs/definition_builder_test.rb +++ b/test/rbs/definition_builder_test.rb @@ -3844,4 +3844,65 @@ def bar = "" end end end + + def test_inline_decl__module_self + SignatureManager.new do |manager| + manager.files[Pathname("foo.rbs")] = <<~RBS + interface _StringConvertible + def to_str: () -> String + end + RBS + + manager.add_ruby_file("a.rb", <<~RUBY) + # @rbs module-self: _StringConvertible + module M + # @rbs () -> String + def display + to_str + end + end + RUBY + + manager.build do |env| + builder = DefinitionBuilder.new(env: env) + + builder.build_instance(type_name("::M")).tap do |definition| + assert_equal Set[:to_str, :display], Set.new(definition.methods.keys) + assert_method_definition definition.methods[:to_str], ["() -> ::String"], accessibility: :public + assert_method_definition definition.methods[:display], ["() -> ::String"], accessibility: :public + end + end + end + end + + def test_inline_decl__module_self_multiple + SignatureManager.new do |manager| + manager.files[Pathname("foo.rbs")] = <<~RBS + interface _Each[T] + def each: () { (T) -> void } -> void + end + + interface _Size + def size: () -> Integer + end + RBS + + manager.add_ruby_file("a.rb", <<~RUBY) + # @rbs module-self: _Each[String] + # @rbs module-self: _Size + module M + end + RUBY + + manager.build do |env| + builder = DefinitionBuilder.new(env: env) + + builder.build_instance(type_name("::M")).tap do |definition| + assert_equal Set[:each, :size], Set.new(definition.methods.keys) + assert_method_definition definition.methods[:each], ["() { (::String) -> void } -> void"], accessibility: :public + assert_method_definition definition.methods[:size], ["() -> ::Integer"], accessibility: :public + end + end + end + end end diff --git a/test/rbs/inline_annotation_parsing_test.rb b/test/rbs/inline_annotation_parsing_test.rb index f067f1f1e..b76c8533c 100644 --- a/test/rbs/inline_annotation_parsing_test.rb +++ b/test/rbs/inline_annotation_parsing_test.rb @@ -498,4 +498,65 @@ def test_error__block_type_annotation assert_match(/pLBRACE/, error.message) assert_equal "{", error.location.source end + + def test_parse__module_self + Parser.parse_inline_leading_annotation("@rbs module-self: _Each[String]", 0...).tap do |annot| + assert_instance_of AST::Ruby::Annotations::ModuleSelfAnnotation, annot + assert_equal "@rbs module-self: _Each[String]", annot.location.source + assert_equal "@rbs", annot.prefix_location.source + assert_equal "module-self", annot.keyword_location.source + assert_equal ":", annot.colon_location.source + assert_equal "_Each", annot.name.to_s + assert_equal 1, annot.args.size + assert_equal "String", annot.args[0].location.source + assert_equal "[", annot.open_bracket_location.source + assert_equal "]", annot.close_bracket_location.source + assert_equal [], annot.args_comma_locations + assert_nil annot.comment_location + end + + Parser.parse_inline_leading_annotation("@rbs module-self: _Hash[String, Integer]", 0...).tap do |annot| + assert_instance_of AST::Ruby::Annotations::ModuleSelfAnnotation, annot + assert_equal "@rbs module-self: _Hash[String, Integer]", annot.location.source + assert_equal "_Hash", annot.name.to_s + assert_equal 2, annot.args.size + assert_equal "String", annot.args[0].location.source + assert_equal "Integer", annot.args[1].location.source + assert_equal "[", annot.open_bracket_location.source + assert_equal "]", annot.close_bracket_location.source + assert_equal 1, annot.args_comma_locations.size + assert_equal ",", annot.args_comma_locations[0].source + end + + Parser.parse_inline_leading_annotation("@rbs module-self: Comparable", 0...).tap do |annot| + assert_instance_of AST::Ruby::Annotations::ModuleSelfAnnotation, annot + assert_equal "@rbs module-self: Comparable", annot.location.source + assert_equal "Comparable", annot.name.to_s + assert_equal 0, annot.args.size + assert_nil annot.open_bracket_location + assert_nil annot.close_bracket_location + assert_equal [], annot.args_comma_locations + assert_nil annot.comment_location + end + + Parser.parse_inline_leading_annotation("@rbs module-self: Minitest::Test -- depending on assertion methods", 0...).tap do |annot| + assert_instance_of AST::Ruby::Annotations::ModuleSelfAnnotation, annot + assert_equal "@rbs module-self: Minitest::Test -- depending on assertion methods", annot.location.source + assert_equal "Minitest::Test", annot.name.to_s + assert_equal 0, annot.args.size + assert_nil annot.open_bracket_location + assert_nil annot.close_bracket_location + assert_equal "-- depending on assertion methods", annot.comment_location.source + end + end + + def test_error__module_self + assert_raises RBS::ParsingError do + Parser.parse_inline_leading_annotation("@rbs module-self:", 0...) + end + + assert_raises RBS::ParsingError do + Parser.parse_inline_leading_annotation("@rbs module-self: foo", 0...) + end + end end diff --git a/test/rbs/inline_parser_test.rb b/test/rbs/inline_parser_test.rb index 7dc1c1f6e..2cb3db53d 100644 --- a/test/rbs/inline_parser_test.rb +++ b/test/rbs/inline_parser_test.rb @@ -1564,6 +1564,58 @@ def foo end end + def test_parse__module_self + result = parse(<<~RUBY) + # @rbs module-self: _Each[String] + module Enumerable2 + end + RUBY + + assert_empty result.diagnostics + + result.declarations[0].tap do |decl| + assert_instance_of RBS::AST::Ruby::Declarations::ModuleDecl, decl + assert_equal RBS::TypeName.parse("Enumerable2"), decl.module_name + + assert_equal 1, decl.members.size + assert_equal 1, decl.self_types.size + + decl.members[0].tap do |member| + assert_instance_of RBS::AST::Ruby::Members::ModuleSelfMember, member + assert_equal "_Each", member.name.to_s + assert_equal 1, member.args.size + assert_equal "String", member.args[0].to_s + end + end + end + + def test_parse__module_self_multiple + result = parse(<<~RUBY) + # @rbs module-self: _Each[String] + # @rbs module-self: Comparable + module StringCollection + end + RUBY + + assert_empty result.diagnostics + + result.declarations[0].tap do |decl| + assert_instance_of RBS::AST::Ruby::Declarations::ModuleDecl, decl + + assert_equal 2, decl.self_types.size + + decl.self_types[0].tap do |member| + assert_equal "_Each", member.name.to_s + assert_equal 1, member.args.size + end + + decl.self_types[1].tap do |member| + assert_equal "Comparable", member.name.to_s + assert_equal 0, member.args.size + end + end + end + def test_parse__constant_declaration_basic result = parse(<<~RUBY) class Example