gloss 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/gloss/config.rb CHANGED
@@ -8,7 +8,9 @@ require "yaml"
8
8
  module Gloss
9
9
  CONFIG_PATH = ".gloss.yml"
10
10
  Config = OpenStruct.new(default_config: {:frozen_string_literals => true,
11
- :src_dir => "src"}.freeze)
11
+ :src_dir => "src",
12
+ :entrypoint => nil,
13
+ :strict_require => false}.freeze)
12
14
  user_config = (if File.exist?(CONFIG_PATH)
13
15
  YAML.safe_load(File.read(CONFIG_PATH))
14
16
  else
data/lib/gloss/errors.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  ##### This file was generated by Gloss; any changes made here will be overwritten.
4
4
  ##### See src/ to make changes
5
5
 
6
- module Gloss
6
+ module Gloss
7
7
  module Errors
8
8
  class BaseGlossError < StandardError
9
9
  end
data/lib/gloss/logger.rb CHANGED
@@ -22,13 +22,8 @@ nil => nil,
22
22
  @logger = Logger.new((if real_log_level
23
23
  STDOUT
24
24
  else
25
- nil
25
+ IO::NULL
26
26
  end))
27
- formatter = Logger::Formatter.new
28
- @logger.formatter=(proc() { |severity, datetime, progname, msg|
29
- formatter.call(severity, datetime, progname, msg)
30
- })
31
- @logger
32
27
  end)
33
28
  end
34
29
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##### This file was generated by Gloss; any changes made here will be overwritten.
4
+ ##### See src/ to make changes
5
+
6
+ require "rubygems/gem_runner"
7
+ module Gloss
8
+ OUTPUT_BY_PATH = Hash.new
9
+ class ProgLoader
10
+ def initialize()
11
+ entrypoint = Config.entrypoint
12
+ (if entrypoint.==(nil) || entrypoint.==("")
13
+ throw(:"error", "Entrypoint is not yet set in .gloss.yml")
14
+ end)
15
+ @files_to_process = [Utils.absolute_path(Config.entrypoint), Utils.absolute_path(File.join(__dir__ || "", "..", "..", "sig", "core.rbs"))]
16
+ @processed_files = Set.new
17
+ @type_checker = TypeChecker.new
18
+ end
19
+ def run()
20
+ @files_to_process.each() { |path_string|
21
+ unless @processed_files.member?(path_string) || OUTPUT_BY_PATH.[](path_string)
22
+ Gloss.logger
23
+ .debug("Loading #{path_string}")
24
+ path = Utils.absolute_path(path_string)
25
+ file_contents = File.open(path)
26
+ .read
27
+ contents_tree = Parser.new(file_contents)
28
+ .run
29
+ on_new_file_referenced = proc() { |pa, relative|
30
+ (if relative
31
+ handle_require_relative(pa)
32
+ else
33
+ handle_require(pa)
34
+ end)
35
+ }
36
+ OUTPUT_BY_PATH.[]=(path_string, Visitor.new(contents_tree, @type_checker, on_new_file_referenced)
37
+ .run)
38
+ @processed_files.add(path_string)
39
+ end
40
+ }
41
+ @type_checker
42
+ end
43
+ STDLIB_TYPE_DEPENDENCIES = {"yaml" => ["pstore", "dbm"],
44
+ "rbs" => ["logger", "set", "tsort"],
45
+ "logger" => ["monitor"]}
46
+ private def handle_require(path)
47
+ (if path.start_with?(".")
48
+ base = File.join(Dir.pwd, path)
49
+ fp = base.+(".gl")
50
+ (if File.exist?(fp)
51
+ @files_to_process.<<(fp)
52
+ end)
53
+ return
54
+ end)
55
+ full = File.absolute_path("#{File.join(Config.src_dir, "lib", path)}.gl")
56
+ pathn = Pathname.new(full)
57
+ (if pathn.file?
58
+ @files_to_process.<<(pathn.to_s)
59
+ else
60
+ pathn = Pathname.new("#{File.join(Dir.pwd, "sig", path)}.rbs")
61
+ gem_path = Utils.gem_path_for(path)
62
+ (if gem_path
63
+ sig_files = Dir.glob(File.absolute_path(File.join(gem_path, "..", "..", "sig", "**", "*.rbs")))
64
+ (if sig_files.length
65
+ .positive?
66
+ sig_files.each() { |fp|
67
+ @type_checker.load_sig_path(fp)
68
+ }
69
+ @processed_files.add(path)
70
+ rbs_type_deps = STDLIB_TYPE_DEPENDENCIES.fetch(path) { ||
71
+ nil }
72
+ (if rbs_type_deps
73
+ rbs_type_deps.each() { |d|
74
+ handle_require(d)
75
+ }
76
+ end)
77
+ return
78
+ end)
79
+ end)
80
+ (if pathn.file?
81
+ @type_checker.load_sig_path(pathn.to_s)
82
+ @processed_files.add(pathn.to_s)
83
+ else
84
+ rbs_stdlib_dir = File.absolute_path(File.join(@type_checker.rbs_gem_dir, "..", "..", "stdlib", path))
85
+ (if Pathname.new(rbs_stdlib_dir)
86
+ .exist?
87
+ load_rbs_from_require_path(path)
88
+ rbs_type_deps = STDLIB_TYPE_DEPENDENCIES.fetch(path) { ||
89
+ nil }
90
+ (if rbs_type_deps
91
+ rbs_type_deps.each() { |d|
92
+ load_rbs_from_require_path(d)
93
+ }
94
+ end)
95
+ else
96
+ (if Config.strict_require
97
+ throw(:"error", "Cannot resolve require path for #{path}")
98
+ else
99
+ Gloss.logger
100
+ .debug("No path found for #{path}")
101
+ end)
102
+ end)
103
+ end)
104
+ end)
105
+ end
106
+ private def handle_require_relative(path)
107
+ base = File.join(@filepath, "..", path)
108
+ # @type var pn: String?
109
+ pn = nil
110
+ Gem.suffixes
111
+ .each() { |ext|
112
+ full = File.absolute_path(base.+(ext))
113
+ (if File.exist?(full)
114
+ pn = full
115
+ end)
116
+ }
117
+ (if pn
118
+ unless @files_to_process.include?(pn)
119
+ @files_to_process.<<(pn)
120
+ end
121
+ else
122
+ (if Config.strict_require
123
+ throw(:"error", "Cannot resolve require path for #{pn}")
124
+ else
125
+ Gloss.logger
126
+ .debug("No path found for #{path}")
127
+ end)
128
+ end)
129
+ end
130
+ private def rbs_stdlib_path_for(libr)
131
+ File.absolute_path(File.join(@type_checker.rbs_gem_dir, "..", "..", "stdlib", libr))
132
+ end
133
+ private def load_rbs_from_require_path(path)
134
+ Dir.glob(File.join(rbs_stdlib_path_for(path), "**", "*.rbs"))
135
+ .each() { |fp|
136
+ @type_checker.load_sig_path(fp)
137
+ @processed_files.add(fp)
138
+ }
139
+ end
140
+ end
141
+ end
data/lib/gloss/scope.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  ##### This file was generated by Gloss; any changes made here will be overwritten.
4
4
  ##### See src/ to make changes
5
5
 
6
- module Gloss
6
+ module Gloss
7
7
  class Scope < Hash
8
8
  def [](k)
9
9
  fetch(k) { ||
data/lib/gloss/source.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  ##### This file was generated by Gloss; any changes made here will be overwritten.
4
4
  ##### See src/ to make changes
5
5
 
6
- module Gloss
6
+ module Gloss
7
7
  class Source < String
8
8
  def initialize(indent_level)
9
9
  @indent_level = indent_level
@@ -3,21 +3,29 @@
3
3
  ##### This file was generated by Gloss; any changes made here will be overwritten.
4
4
  ##### See src/ to make changes
5
5
 
6
- require "pry-byebug"
6
+ require "set"
7
7
  module Gloss
8
8
  class TypeChecker
9
9
  Project = Struct.new(:"targets")
10
- attr_reader(:"steep_target", :"top_level_decls")
10
+ attr_reader(:"steep_target", :"top_level_decls", :"env", :"rbs_gem_dir")
11
11
  def initialize()
12
12
  @steep_target = Steep::Project::Target.new(name: "gloss", options: Steep::Project::Options.new
13
13
  .tap() { |o|
14
14
  o.allow_unknown_constant_assignment=(true)
15
- }, source_patterns: ["gloss.rb"], ignore_patterns: Array.new, signature_patterns: ["sig"])
16
- @top_level_decls = {}
15
+ }, source_patterns: ["**/*.rb"], ignore_patterns: Array.new, signature_patterns: ["sig"])
16
+ @top_level_decls = Set.new
17
+ @rbs_gem_dir = Utils.gem_path_for("rbs")
18
+ env_loader = RBS::EnvironmentLoader.new
19
+ @env = RBS::Environment.from_loader(env_loader)
20
+ project = Steep::Project.new(steepfile_path: Pathname.new(Config.src_dir)
21
+ .realpath)
22
+ project.targets
23
+ .<<(@steep_target)
24
+ loader = Steep::Project::FileLoader.new(project: project)
17
25
  end
18
- def run(rb_str)
26
+ def run(filepath, rb_str)
19
27
  begin
20
- valid_types = check_types(rb_str)
28
+ valid_types = check_types(filepath, rb_str)
21
29
  rescue ParseError => e
22
30
  throw(:"error", "")
23
31
  rescue => e
@@ -34,10 +42,8 @@ case e
34
42
  when Steep::Diagnostic::Ruby::MethodBodyTypeMismatch
35
43
  "Invalid method body type - expected: #{e.expected}, actual: #{e.actual}"
36
44
  when Steep::Diagnostic::Ruby::IncompatibleArguments
37
- "Invalid argmuents - method type: #{e.method_type}\nmethod name: #{e.method_type
38
- .method_decls
39
- .first
40
- .method_name}"
45
+ "Invalid argmuents - method type: #{e.method_types
46
+ .first}\nmethod name: #{e.method_name}"
41
47
  when Steep::Diagnostic::Ruby::ReturnTypeMismatch
42
48
  "Invalid return type - expected: #{e.expected}, actual: #{e.actual}"
43
49
  when Steep::Diagnostic::Ruby::IncompatibleAssignment
@@ -45,7 +51,7 @@ case e
45
51
  when Steep::Diagnostic::Ruby::UnexpectedBlockGiven
46
52
  "Unexpected block given"
47
53
  else
48
- e.inspect
54
+ "#{e.header_line}\n#{e.inspect}"
49
55
  end
50
56
  }
51
57
  .join("\n")
@@ -53,30 +59,36 @@ case e
53
59
  end
54
60
  true
55
61
  end
56
- def check_types(rb_str)
57
- env_loader = RBS::EnvironmentLoader.new
58
- env = RBS::Environment.from_loader(env_loader)
59
- project = Steep::Project.new(steepfile_path: Pathname.new(Config.src_dir)
60
- .realpath)
61
- project.targets
62
- .<<(@steep_target)
63
- loader = Steep::Project::FileLoader.new(project: project)
64
- loader.load_signatures
65
- @steep_target.add_source("gloss.rb", rb_str)
66
- @top_level_decls.each() { |_, decl|
67
- env.<<(decl)
62
+ def ready_for_checking!()
63
+ @top_level_decls.each() { |decl|
64
+ @env.<<(decl)
68
65
  }
69
- env = env.resolve_type_names
70
- @steep_target.instance_variable_set("@environment", env)
66
+ @env = @env.resolve_type_names
67
+ @steep_target.instance_variable_set("@environment", @env)
68
+ end
69
+ def check_types(filepath, rb_str)
70
+ @steep_target.add_source(filepath, rb_str)
71
+ ready_for_checking!
71
72
  @steep_target.type_check
72
73
  (if @steep_target.status
73
74
  .is_a?(Steep::Project::Target::SignatureErrorStatus)
74
75
  throw(:"error", @steep_target.status
75
76
  .errors
76
77
  .map() { |e|
77
- " SignatureSyntaxError:\n Location: #{e.location}\n Message: \"#{e.exception
78
- .error_value
79
- .value}\"" }
78
+ msg = case e
79
+ when Steep::Diagnostic::Signature::UnknownTypeName
80
+ "Unknown type name: #{e.name
81
+ .name} (#{e.location
82
+ .source
83
+ .[](/^.*$/)})"
84
+ when Steep::Diagnostic::Signature::InvalidTypeApplication
85
+ "Invalid type application: #{e.header_line}"
86
+ when Steep::Diagnostic::Signature::DuplicatedMethodDefinition
87
+ "Duplicated method: #{e.header_line}"
88
+ else
89
+ e.header_line
90
+ end
91
+ " SignatureSyntaxError:\n Location: #{e.location}\n Message: \"#{msg}\"" }
80
92
  .join("\n"))
81
93
  end)
82
94
  @steep_target.source_files
@@ -92,5 +104,11 @@ true
92
104
  .is_a?(Steep::Project::Target::TypeCheckStatus) && @steep_target.no_error? && @steep_target.errors
93
105
  .empty?
94
106
  end
107
+ def load_sig_path(path)
108
+ Gloss.logger
109
+ .debug("Loading signature file for #{path}")
110
+ @steep_target.add_signature(path, File.open(path)
111
+ .read)
112
+ end
95
113
  end
96
114
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##### This file was generated by Gloss; any changes made here will be overwritten.
4
+ ##### See src/ to make changes
5
+
6
+ require "rubygems"
7
+ module Gloss
8
+ module Utils
9
+ module_function
10
+ def absolute_path(path)
11
+ pn = Pathname.new(path)
12
+ (if pn.absolute?
13
+ pn.to_s
14
+ else
15
+ ap = File.absolute_path(path)
16
+ (if File.exist?(ap)
17
+ ap
18
+ else
19
+ throw(:"error", "File path #{path} does not exist (also looked for #{ap})")
20
+ end)
21
+ end)
22
+ end
23
+ def gem_path_for(gem_name)
24
+ begin
25
+ Gem.ui
26
+ .instance_variable_set(:"@outs", StringIO.new)
27
+ Gem::GemRunner.new
28
+ .run(["which", gem_name])
29
+ Gem.ui
30
+ .outs
31
+ .string
32
+ rescue SystemExit => e
33
+ nil
34
+ end
35
+ end
36
+ def with_file_header(str)
37
+ "#{Visitor::FILE_HEADER}\n\n#{str}"
38
+ end
39
+ def src_path_to_output_path(src_path)
40
+ src_path.sub("#{Config.src_dir}/", "")
41
+ .sub(/\.gl$/, ".rb")
42
+ end
43
+ end
44
+ end
data/lib/gloss/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  ##### See src/ to make changes
5
5
 
6
6
  module Gloss
7
- VERSION = "0.0.6"
7
+ VERSION = "0.1.0"
8
8
  end
@@ -4,29 +4,24 @@
4
4
  ##### See src/ to make changes
5
5
 
6
6
  module Gloss
7
- module Utils
8
- module_function
9
- def with_file_header(str)
10
- "#{Builder::FILE_HEADER}\n\n#{str}"
11
- end
12
- end
13
- class Builder
7
+ class Visitor
14
8
  FILE_HEADER = " #{(if Config.frozen_string_literals
15
9
  "# frozen_string_literal: true\n"
16
10
  end)}\n ##### This file was generated by Gloss; any changes made here will be overwritten.\n ##### See #{Config.src_dir}/ to make changes"
17
- include Utils
18
11
  attr_reader(:"tree")
19
- def initialize(tree_hash, type_checker = nil)
12
+ def initialize(tree_hash, type_checker = nil, on_new_file_referenced = nil)
13
+ @on_new_file_referenced = on_new_file_referenced
20
14
  @indent_level = 0
21
15
  @inside_macro = false
22
16
  @eval_vars = false
23
17
  @current_scope = nil
24
18
  @tree = tree_hash
25
19
  @type_checker = type_checker
20
+ @after_module_function = false
26
21
  end
27
22
  def run()
28
23
  rb_output = visit_node(@tree)
29
- with_file_header(rb_output)
24
+ Utils.with_file_header(rb_output)
30
25
  end
31
26
  def visit_node(node, scope = Scope.new)
32
27
  src = Source.new(@indent_level)
@@ -40,21 +35,30 @@ case node.[](:"type")
40
35
  RBS::Namespace.root
41
36
  end)
42
37
  superclass_type = nil
43
- superclass_output = nil
38
+ superclass_output = ""
44
39
  (if node.[](:"superclass")
45
40
  @eval_vars = true
46
41
  superclass_output = visit_node(node.[](:"superclass"))
47
42
  @eval_vars = false
48
- superclass_type = RBS::Parser.parse_type(superclass_output)
43
+ args = Array.new
49
44
  (if node.dig(:"superclass", :"type")
50
45
  .==("Generic")
51
- superclass_output = superclass_output.[](/^[^\[]+/)
46
+ superclass_output = superclass_output.[](/^[^\[]+/) || superclass_output
47
+ args = node.dig(:"superclass", :"args")
48
+ .map() { |n|
49
+ RBS::Parser.parse_type(visit_node(n))
50
+ }
52
51
  end)
52
+ class_name_index = superclass_output.index(/[^(?:::)]+\z/) || 0
53
+ namespace = superclass_output.[](0, class_name_index)
54
+ superclass_name = superclass_output.[](/[^(?:::)]+\z/) || superclass_output
55
+ superclass_type = RBS::AST::Declarations::Class::Super.new(name: RBS::TypeName.new(namespace: method(:"Namespace")
56
+ .call(namespace), name: superclass_name.to_sym), args: args, location: build_location(node))
53
57
  end)
54
- src.write_ln("class #{class_name}#{(if superclass_output
58
+ src.write_ln("class #{class_name}#{unless superclass_output.blank?
55
59
  " < #{superclass_output}"
56
- end)}")
57
- class_type = RBS::AST::Declarations::Class.new(name: RBS::TypeName.new(namespace: current_namespace, name: class_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, super_class: superclass_type, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
60
+ end}")
61
+ class_type = RBS::AST::Declarations::Class.new(name: RBS::TypeName.new(namespace: current_namespace, name: class_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, super_class: superclass_type, members: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
58
62
  old_parent_scope = @current_scope
59
63
  @current_scope = class_type
60
64
  indented(src) { ||
@@ -68,14 +72,13 @@ case node.[](:"type")
68
72
  @current_scope.members
69
73
  .<<(class_type)
70
74
  end)
71
- (if @type_checker
72
- unless @current_scope
73
- @type_checker.top_level_decls
74
- .[]=(class_type.name
75
- .name, class_type)
76
- end
75
+ (if @type_checker && !@current_scope
76
+ @type_checker.top_level_decls
77
+ .add(class_type)
77
78
  end)
78
79
  when "ModuleNode"
80
+ existing_module_function_state = @after_module_function.dup
81
+ @after_module_function = false
79
82
  module_name = visit_node(node.[](:"name"))
80
83
  src.write_ln("module #{module_name}")
81
84
  current_namespace = (if @current_scope
@@ -84,7 +87,7 @@ case node.[](:"type")
84
87
  else
85
88
  RBS::Namespace.root
86
89
  end)
87
- module_type = RBS::AST::Declarations::Module.new(name: RBS::TypeName.new(namespace: current_namespace, name: module_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, self_types: Array.new, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
90
+ module_type = RBS::AST::Declarations::Module.new(name: RBS::TypeName.new(namespace: current_namespace, name: module_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, self_types: Array.new, members: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
88
91
  old_parent_scope = @current_scope
89
92
  @current_scope = module_type
90
93
  indented(src) { ||
@@ -97,14 +100,12 @@ case node.[](:"type")
97
100
  @current_scope.members
98
101
  .<<(module_type)
99
102
  end)
100
- (if @type_checker
101
- unless @current_scope
102
- @type_checker.top_level_decls
103
- .[]=(module_type.name
104
- .name, module_type)
105
- end
103
+ (if @type_checker && !@current_scope
104
+ @type_checker.top_level_decls
105
+ .add(module_type)
106
106
  end)
107
107
  src.write_ln("end")
108
+ @after_module_function = existing_module_function_state
108
109
  when "DefNode"
109
110
  args = render_args(node)
110
111
  receiver = (if node.[](:"receiver")
@@ -118,21 +119,25 @@ case node.[](:"type")
118
119
  return_type = (if node.[](:"return_type")
119
120
  RBS::Types::ClassInstance.new(name: RBS::TypeName.new(name: eval(visit_node(node.[](:"return_type")))
120
121
  .to_s
121
- .to_sym, namespace: RBS::Namespace.root), args: EMPTY_ARRAY, location: node.[](:"location"))
122
+ .to_sym, namespace: RBS::Namespace.root), args: EMPTY_ARRAY, location: build_location(node))
122
123
  else
123
- RBS::Types::Bases::Any.new(location: node.[](:"location"))
124
+ RBS::Types::Bases::Any.new(location: build_location(node))
124
125
  end)
125
126
  method_types = [RBS::MethodType.new(type_params: EMPTY_ARRAY, type: RBS::Types::Function.new(required_positionals: args.dig(:"types", :"required_positionals"), optional_positionals: args.dig(:"types", :"optional_positionals"), rest_positionals: args.dig(:"types", :"rest_positionals"), trailing_positionals: args.dig(:"types", :"trailing_positionals"), required_keywords: args.dig(:"types", :"required_keywords"), optional_keywords: args.dig(:"types", :"optional_keywords"), rest_keywords: args.dig(:"types", :"rest_keywords"), return_type: return_type), block: (if node.[](:"yield_arg_count")
126
- RBS::Types::Block.new(type: RBS::Types::Function.new(required_positionals: Array.new, optional_positionals: Array.new, rest_positionals: nil, trailing_positionals: Array.new, required_keywords: Hash.new, optional_keywords: Hash.new, rest_keywords: nil, return_type: RBS::Types::Bases::Any.new(location: node.[](:"location"))), required: !!node.[](:"block_arg") || node.[](:"yield_arg_count"))
127
+ RBS::Types::Block.new(type: RBS::Types::Function.new(required_positionals: Array.new, optional_positionals: Array.new, rest_positionals: nil, trailing_positionals: Array.new, required_keywords: Hash.new, optional_keywords: Hash.new, rest_keywords: nil, return_type: RBS::Types::Bases::Any.new(location: build_location(node))), required: !!node.[](:"block_arg") || node.[](:"yield_arg_count"))
127
128
  else
128
129
  nil
129
- end), location: node.[](:"location"))]
130
+ end), location: build_location(node))]
130
131
  method_definition = RBS::AST::Members::MethodDefinition.new(name: node.[](:"name")
131
- .to_sym, kind: (if receiver
132
- :"class"
132
+ .to_sym, kind: (if @after_module_function
133
+ :"singleton_instance"
133
134
  else
134
- :"instance"
135
- end), types: method_types, annotations: EMPTY_ARRAY, location: node.[](:"location"), comment: node.[](:"comment"), overload: false)
135
+ (if receiver
136
+ :"singleton"
137
+ else
138
+ :"instance"
139
+ end)
140
+ end), types: method_types, annotations: EMPTY_ARRAY, location: build_location(node), comment: node.[](:"comment"), overload: false)
136
141
  (if @current_scope
137
142
  @current_scope.members
138
143
  .<<(method_definition)
@@ -190,9 +195,18 @@ EMPTY_ARRAY }
190
195
  else
191
196
  nil
192
197
  end)
193
- call = "#{obj}#{node.[](:"name")}#{opening_delimiter}#{args}#{(if has_parens
198
+ name = node.[](:"name")
199
+ call = "#{obj}#{name}#{opening_delimiter}#{args}#{(if has_parens
194
200
  ")"
195
201
  end)}#{block}"
202
+ case name
203
+ when "require_relative"
204
+ (if @on_new_file_referenced
205
+ @on_new_file_referenced.call(name, true)
206
+ end)
207
+ when "module_function"
208
+ @after_module_function = true
209
+ end
196
210
  src.write_ln(call)
197
211
  when "Block"
198
212
  args = render_args(node)
@@ -237,7 +251,11 @@ EMPTY_ARRAY }
237
251
  when "Path"
238
252
  src.write(node.[](:"value"))
239
253
  when "Require"
240
- src.write_ln("require \"#{node.[](:"value")}\"")
254
+ path = node.[](:"value")
255
+ src.write_ln("require \"#{path}\"")
256
+ (if @on_new_file_referenced
257
+ @on_new_file_referenced.call(path, false)
258
+ end)
241
259
  when "Assign", "OpAssign"
242
260
  src.write_ln("#{visit_node(node.[](:"target"))} #{node.[](:"op")}= #{visit_node(node.[](:"value"))
243
261
  .strip}")
@@ -426,7 +444,12 @@ EMPTY_ARRAY }
426
444
  src.write("return#{val}")
427
445
  when "TypeDeclaration"
428
446
  src.write_ln("# @type var #{visit_node(node.[](:"var"))}: #{visit_node(node.[](:"declared_type"))}")
429
- src.write_ln("#{visit_node(node.[](:"var"))} = #{visit_node(node.[](:"value"))}")
447
+ value = (if node.[](:"value")
448
+ " = #{visit_node(node.[](:"value"))}"
449
+ else
450
+ nil
451
+ end)
452
+ src.write_ln("#{visit_node(node.[](:"var"))}#{value}")
430
453
  when "ExceptionHandler"
431
454
  src.write_ln("begin")
432
455
  indented(src) { ||
@@ -483,7 +506,7 @@ EMPTY_ARRAY }
483
506
  name = visit_node(node.[](:"name"))
484
507
  src.write_ln("include #{name}")
485
508
  type = RBS::AST::Members::Include.new(name: method(:"TypeName")
486
- .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
509
+ .call(name), args: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
487
510
  (if @current_scope
488
511
  @current_scope.members
489
512
  .<<(type)
@@ -501,7 +524,7 @@ EMPTY_ARRAY }
501
524
  name = visit_node(node.[](:"name"))
502
525
  src.write_ln("extend #{name}")
503
526
  type = RBS::AST::Members::Extend.new(name: method(:"TypeName")
504
- .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
527
+ .call(name), args: Array.new, annotations: Array.new, location: build_location(node), comment: node.[](:"comment"))
505
528
  (if @current_scope
506
529
  @current_scope.members
507
530
  .<<(type)
@@ -607,34 +630,38 @@ a && a.empty? }
607
630
  .flatten
608
631
  .join(", ")
609
632
  representation = "(#{contents})"
610
- rp.map!() { |a|
633
+ rp_args = rp.map() { |a|
611
634
  RBS::Types::Function::Param.new(name: visit_node(a)
612
- .to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
635
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(a)))
613
636
  }
614
- op.map!() { |a|
637
+ op_args = op.map() { |a|
615
638
  RBS::Types::Function::Param.new(name: visit_node(a)
616
- .to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
639
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(a)))
617
640
  }
618
- rest_p = (if rpa = node.[](:"rest_p_args")
619
- RBS::Types::Function::Param.new(name: visit_node(rpa)
620
- .to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
641
+ rpa = (if rest_p
642
+ RBS::Types::Function::Param.new(name: rest_p.to_sym, type: RBS::Types::Bases::Any.new(location: build_location(node)))
621
643
  else
622
644
  nil
623
645
  end)
624
646
  {:representation => representation,
625
- :types => {:required_positionals => rp,
626
- :optional_positionals => op,
627
- :rest_positionals => rest_p,
647
+ :types => {:required_positionals => rp_args,
648
+ :optional_positionals => op_args,
649
+ :rest_positionals => rpa,
628
650
  :trailing_positionals => EMPTY_ARRAY,
629
651
  :required_keywords => node.[](:"req_kw_args") || EMPTY_HASH,
630
652
  :optional_keywords => node.[](:"opt_kw_args") || EMPTY_HASH,
631
653
  :rest_keywords => (if node.[](:"rest_kw_args")
632
654
  RBS::Types::Function::Param.new(name: visit_node(node.[](:"rest_kw_args"))
633
- .to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
655
+ .to_sym, type: RBS::Types::Bases::Any.new(location: build_location(node)))
634
656
  else
635
657
  nil
636
658
  end)
637
659
  }.freeze}.freeze
638
660
  end
661
+ def build_location(node)
662
+ unless node.[](:"location")
663
+ return nil
664
+ end
665
+ end
639
666
  end
640
667
  end