From 69f84f88c68220279c5317214326e41cfa1806c1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 25 May 2023 03:13:25 +0900 Subject: [PATCH 1/6] prototype rb: Extract instance variables and class variables --- lib/rbs/prototype/rb.rb | 21 +++++++++++++++ test/rbs/rb_prototype_test.rb | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index 646ed9090..ea6d694c4 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -195,6 +195,10 @@ def process(node, decls:, comments:, context:) decls.push member unless decls.include?(member) + each_node def_body.children do |child| + process child, decls: decls, comments: comments, context: context + end + when :ALIAS new_name, old_name = node.children.map { |c| literal_to_symbol(c) } member = AST::Members::Alias.new( @@ -377,6 +381,23 @@ def process(node, decls:, comments:, context:) comment: comments[node.first_lineno - 1] ) + when :IASGN + member = AST::Members::InstanceVariable.new( + name: node.children.first, + type: Types::Bases::Any.new(location: nil), + location: nil, + comment: comments[node.first_lineno - 1] + ) + decls.push member unless decls.include?(member) + + when :CVASGN + member = AST::Members::ClassVariable.new( + name: node.children.first, + type: Types::Bases::Any.new(location: nil), + location: nil, + comment: comments[node.first_lineno - 1] + ) + decls.push member unless decls.include?(member) else process_children(node, decls: decls, comments: comments, context: context) end diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index d0955b754..900353ae3 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -914,6 +914,54 @@ def hello: () -> untyped RBS end + def test_instance_variables + parser = RB.new + + rb = <<-EOR +class Hello + def message(message) + # comment for ivar + @message = message + end +end + EOR + + parser.parse(rb) + + assert_write parser.decls, <<-EOF +class Hello + def message: (untyped message) -> untyped + + # comment for ivar + @message: untyped +end + EOF + end + + def test_class_variables + parser = RB.new + + rb = <<-EOR +class Hello + def message(message) + # comment for cvar + @@message = message + end +end + EOR + + parser.parse(rb) + + assert_write parser.decls, <<-EOF +class Hello + def message: (untyped message) -> untyped + + # comment for cvar + @@message: untyped +end + EOF + end + def test_literal_to_type parser = RBS::Prototype::RB.new [ From ef149620cccfb41993136de8faa71ee38d4e3cae Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 May 2023 01:48:11 +0900 Subject: [PATCH 2/6] prototype rb: Move instance and class variables to the top of the class To generate natural .rbs files, this moves instance and class variable definitions to the top of the class definition. --- lib/rbs/prototype/rb.rb | 11 +++++++++++ sig/prototype/rb.rbs | 2 ++ test/rbs/rb_prototype_test.rb | 8 ++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index ea6d694c4..890019a43 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -126,6 +126,7 @@ def process(node, decls:, comments:, context:) process child, decls: kls.members, comments: comments, context: new_ctx end remove_unnecessary_accessibility_methods! kls.members + sort_members! kls.members when :MODULE module_name, *module_body = node.children @@ -764,6 +765,16 @@ def find_def_index_by_name(decls, name) ] end end + + def sort_members!(decls) + i = 0 + orders = { + AST::Members::ClassVariable => -2, + AST::Members::InstanceVariable => -1, + } + decls.sort_by! { |decl| [orders.fetch(decl.class, 0), i += 1] } + end end end end + diff --git a/sig/prototype/rb.rbs b/sig/prototype/rb.rbs index 199029698..b8a2b7f14 100644 --- a/sig/prototype/rb.rbs +++ b/sig/prototype/rb.rbs @@ -83,6 +83,8 @@ module RBS def is_accessibility?: (decl) -> bool def find_def_index_by_name: (Array[decl] decls, Symbol name) -> [Integer, AST::Members::MethodDefinition | AST::Members::AttrReader | AST::Members::AttrWriter]? + + def sort_members!: (Array[decl] decls) -> void end end end diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index 900353ae3..eac214a6f 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -930,10 +930,10 @@ def message(message) assert_write parser.decls, <<-EOF class Hello - def message: (untyped message) -> untyped - # comment for ivar @message: untyped + + def message: (untyped message) -> untyped end EOF end @@ -954,10 +954,10 @@ def message(message) assert_write parser.decls, <<-EOF class Hello - def message: (untyped message) -> untyped - # comment for cvar @@message: untyped + + def message: (untyped message) -> untyped end EOF end From 4b5e35b572c0cf2db307d1249e8ce99c7ca0a67f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 9 Jun 2023 01:49:42 +0900 Subject: [PATCH 3/6] prototype rb: Convert instance variable inside singleton method to class variable --- lib/rbs/prototype/rb.rb | 24 +++++++++++++++++------- test/rbs/rb_prototype_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index 890019a43..47c0560df 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -196,8 +196,9 @@ def process(node, decls:, comments:, context:) decls.push member unless decls.include?(member) + new_ctx = Context.initial.tap { |ctx| ctx.singleton = kind == :singleton } each_node def_body.children do |child| - process child, decls: decls, comments: comments, context: context + process child, decls: decls, comments: comments, context: new_ctx end when :ALIAS @@ -383,12 +384,21 @@ def process(node, decls:, comments:, context:) ) when :IASGN - member = AST::Members::InstanceVariable.new( - name: node.children.first, - type: Types::Bases::Any.new(location: nil), - location: nil, - comment: comments[node.first_lineno - 1] - ) + if context.singleton || !context.namespace.empty? + member = AST::Members::ClassVariable.new( + name: "@#{node.children.first}".to_sym, + type: Types::Bases::Any.new(location: nil), + location: nil, + comment: comments[node.first_lineno - 1] + ) + else + member = AST::Members::InstanceVariable.new( + name: node.children.first, + type: Types::Bases::Any.new(location: nil), + location: nil, + comment: comments[node.first_lineno - 1] + ) + end decls.push member unless decls.include?(member) when :CVASGN diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index eac214a6f..07f359e48 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -943,6 +943,18 @@ def test_class_variables rb = <<-EOR class Hello + def self.foo + @foo = 42 + end + + class << self + def bar + @bar = 42 + end + end + + @baz = 42 + def message(message) # comment for cvar @@message = message @@ -954,9 +966,19 @@ def message(message) assert_write parser.decls, <<-EOF class Hello + @@foo: untyped + + @@bar: untyped + + @@baz: untyped + # comment for cvar @@message: untyped + def self.foo: () -> untyped + + def self.bar: () -> untyped + def message: (untyped message) -> untyped end EOF From ce531fffa0e30f7170a3d647389192039b2483f5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 16 Jun 2023 02:35:53 +0900 Subject: [PATCH 4/6] prototype rb: Inherit namespace of context on processing DEFN and DEFS Co-authored-by: Masataka Pocke Kuwabara --- lib/rbs/prototype/rb.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index 47c0560df..e37c0d299 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -196,7 +196,7 @@ def process(node, decls:, comments:, context:) decls.push member unless decls.include?(member) - new_ctx = Context.initial.tap { |ctx| ctx.singleton = kind == :singleton } + new_ctx = context.dup.tap { |ctx| ctx.singleton = kind == :singleton } each_node def_body.children do |child| process child, decls: decls, comments: comments, context: new_ctx end From a8691526cb6d45469737ac4d9d1e86c0939fe3c8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 16 Jun 2023 03:18:45 +0900 Subject: [PATCH 5/6] prototype rb: Fix testcase --- lib/rbs/prototype/rb.rb | 2 +- test/rbs/rb_prototype_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index e37c0d299..e8694458e 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -384,7 +384,7 @@ def process(node, decls:, comments:, context:) ) when :IASGN - if context.singleton || !context.namespace.empty? + if context.singleton member = AST::Members::ClassVariable.new( name: "@#{node.children.first}".to_sym, type: Types::Bases::Any.new(location: nil), diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index 07f359e48..829a57c76 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -970,11 +970,11 @@ class Hello @@bar: untyped - @@baz: untyped - # comment for cvar @@message: untyped + @baz: untyped + def self.foo: () -> untyped def self.bar: () -> untyped From f67f8dca04ffc72f218a32fc98e7392a4e45caf8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 16 Jun 2023 03:33:51 +0900 Subject: [PATCH 6/6] prototype rb: Fix to ClassInstanceVariable to represent class instance variable --- lib/rbs/prototype/rb.rb | 7 ++++--- test/rbs/rb_prototype_test.rb | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index e8694458e..588b3fd44 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -385,8 +385,8 @@ def process(node, decls:, comments:, context:) when :IASGN if context.singleton - member = AST::Members::ClassVariable.new( - name: "@#{node.children.first}".to_sym, + member = AST::Members::ClassInstanceVariable.new( + name: node.children.first, type: Types::Bases::Any.new(location: nil), location: nil, comment: comments[node.first_lineno - 1] @@ -779,7 +779,8 @@ def find_def_index_by_name(decls, name) def sort_members!(decls) i = 0 orders = { - AST::Members::ClassVariable => -2, + AST::Members::ClassVariable => -3, + AST::Members::ClassInstanceVariable => -2, AST::Members::InstanceVariable => -1, } decls.sort_by! { |decl| [orders.fetch(decl.class, 0), i += 1] } diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index 829a57c76..e23203f74 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -966,13 +966,13 @@ def message(message) assert_write parser.decls, <<-EOF class Hello - @@foo: untyped - - @@bar: untyped - # comment for cvar @@message: untyped + self.@foo: untyped + + self.@bar: untyped + @baz: untyped def self.foo: () -> untyped