-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocals.rb
67 lines (54 loc) · 1.39 KB
/
locals.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
require 'set'
Local = Struct.new(:name, :id, :value, keyword_init: true) do
def get
value
end
def set(value)
self.value = value
value
end
end
class Locals
Set = ::Set
UNDEFINED = Object.new
def UNDEFINED.inspect; 'UNDEFINED'; end
def initialize(initial_names)
@set = Set.new
initial_names.reverse_each.with_index(3) do |arg_name, idx|
# unused args (like virtual attribute that holds mlhs value)
# have numeric names
arg_name += 1 if arg_name.is_a?(Integer)
declare(name: arg_name, id: idx).set(Locals::UNDEFINED)
end
end
def declared?(name: nil, id: nil)
!find_if_declared(name: name, id: id).nil?
end
def declare(name: nil, id: nil)
local = Local.new(name: name, id: id, value: nil)
@set << local
local
end
def find_if_declared(name: nil, id: nil)
if name
@set.detect { |var| var.name == name }
elsif id
@set.detect { |var| var.id == id }
else
raise NotImplementedError, "At least one of name:/id: is required"
end
end
def find(name: nil, id: nil)
result = find_if_declared(name: name, id: id)
if result.nil?
raise VM::InternalError, "No local name=#{name.inspect}/id=#{id.inspect}"
end
result
end
def pretty
@set
.map { |local| ["#{local.name}(#{local.id})", local.value] }
.sort_by { |(name, _value)| name }
.to_h
end
end