@@ -55,14 +55,18 @@ def add_usage(location)
5555 end
5656 end
5757
58- # [Array[Local]] The local variables and arguments defined in this
58+ # [Integer] a unique identifier for this environment
59+ attr_reader :id
60+
61+ # [Hash[String, Local]] The local variables and arguments defined in this
5962 # environment
6063 attr_reader :locals
6164
6265 # [Environment | nil] The parent environment
6366 attr_reader :parent
6467
65- def initialize ( parent = nil )
68+ def initialize ( id , parent = nil )
69+ @id = id
6670 @locals = { }
6771 @parent = parent
6872 end
@@ -74,8 +78,14 @@ def initialize(parent = nil)
7478 def add_local_definition ( identifier , type )
7579 name = identifier . value . delete_suffix ( ":" )
7680
77- @locals [ name ] ||= Local . new ( type )
78- @locals [ name ] . add_definition ( identifier . location )
81+ local =
82+ if type == :argument
83+ locals [ name ] ||= Local . new ( type )
84+ else
85+ resolve_local ( name , type )
86+ end
87+
88+ local . add_definition ( identifier . location )
7989 end
8090
8191 # Adding a local usage will either insert a new entry in the locals
@@ -84,28 +94,42 @@ def add_local_definition(identifier, type)
8494 # registered.
8595 def add_local_usage ( identifier , type )
8696 name = identifier . value . delete_suffix ( ":" )
87-
88- @locals [ name ] ||= Local . new ( type )
89- @locals [ name ] . add_usage ( identifier . location )
97+ resolve_local ( name , type ) . add_usage ( identifier . location )
9098 end
9199
92100 # Try to find the local given its name in this environment or any of its
93101 # parents.
94102 def find_local ( name )
95- local = @ locals[ name ]
96- return local unless local . nil?
103+ locals [ name ] || parent &. find_local ( name )
104+ end
97105
98- @parent &.find_local ( name )
106+ private
107+
108+ def resolve_local ( name , type )
109+ local = find_local ( name )
110+
111+ unless local
112+ local = Local . new ( type )
113+ locals [ name ] = local
114+ end
115+
116+ local
99117 end
100118 end
101119
120+ def initialize ( *args , **kwargs , &block )
121+ super
122+ @environment_id = 0
123+ end
124+
102125 def current_environment
103- @current_environment ||= Environment . new
126+ @current_environment ||= Environment . new ( next_environment_id )
104127 end
105128
106- def with_new_environment
129+ def with_new_environment ( parent_environment = nil )
107130 previous_environment = @current_environment
108- @current_environment = Environment . new ( previous_environment )
131+ @current_environment =
132+ Environment . new ( next_environment_id , parent_environment )
109133 yield
110134 ensure
111135 @current_environment = previous_environment
@@ -126,7 +150,7 @@ def visit_module(node)
126150 # invocation itself happens in the same environment.
127151 def visit_method_add_block ( node )
128152 visit ( node . call )
129- with_new_environment { visit ( node . block ) }
153+ with_new_environment ( current_environment ) { visit ( node . block ) }
130154 end
131155
132156 def visit_def ( node )
@@ -213,5 +237,9 @@ def add_argument_definitions(list)
213237 end
214238 end
215239 end
240+
241+ def next_environment_id
242+ @environment_id += 1
243+ end
216244 end
217245end
0 commit comments