-
Notifications
You must be signed in to change notification settings - Fork 21
/
name.rb
136 lines (121 loc) · 4.19 KB
/
name.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module Rubex
module AST
module Expression
# Singular name node with no sub expressions.
class Name < Base
def initialize(name)
@name = name
end
# Used when the node is a LHS of an assign statement.
def analyse_declaration(_rhs, local_scope)
@entry = local_scope.find @name
unless @entry
local_scope.add_ruby_obj(name: @name, c_name: Rubex::VAR_PREFIX + @name, value: @rhs)
@entry = local_scope[@name]
end
@type = @entry.type
end
def analyse_for_target_type(target_type, local_scope)
@entry = local_scope.find @name
if @entry&.type&.c_function? && target_type.c_function_ptr?
@type = @entry.type
else
analyse_types local_scope
end
end
# Analyse a Name node. This can either be a variable name or a method call
# without parenthesis. Code in this method that creates a RubyMethodCall
# node primarily exists because in Ruby methods without arguments can
# be called without parentheses. These names can potentially be Ruby
# methods that are not visible to Rubex, but are present in the Ruby
# run time. For example, a program like this:
#
# def foo
# bar
# #^^^ this is a name node
# end
def analyse_types(local_scope)
@entry = local_scope.find @name
unless @entry
if ruby_constant?
analyse_as_ruby_constant local_scope
else
add_as_ruby_method_to_scope local_scope
end
end
assign_type_based_on_whether_wrapped_type
analyse_as_ruby_method(local_scope) if @entry.type.ruby_method?
analyse_as_c_function(local_scope) if @entry.type.c_function?
if @name.is_a?(Expression::Base)
@name.allocate_temps local_scope
@name.release_temps local_scope
end
super
end
def analyse_as_c_function(local_scope)
@name = Rubex::AST::Expression::CFunctionCall.new(
Expression::Self.new, @name,
Expression::ActualArgList.new([])
)
@name.analyse_types(local_scope)
end
def generate_evaluation_code(code, local_scope)
if @name.respond_to? :generate_evaluation_code
@name.generate_evaluation_code code, local_scope
end
end
def generate_disposal_code(code)
if @name.respond_to? :generate_disposal_code
@name.generate_disposal_code code
end
end
def generate_assignment_code(rhs, code, local_scope)
code << "#{c_code(local_scope)} = #{rhs.c_code(local_scope)};"
code.nl
rhs.generate_disposal_code code
end
def c_code(local_scope)
code = super
code <<
if @name.is_a?(Rubex::AST::Expression::Base)
@name.c_code(local_scope)
else
@entry.c_name
end
code
end
private
def ruby_constant?
@name[0].match(/[A-Z]/)
end
def analyse_as_ruby_constant(local_scope)
@name = Expression::RubyConstant.new @name
@name.analyse_types local_scope
@entry = @name.entry
end
def add_as_ruby_method_to_scope(local_scope)
@entry = local_scope.add_ruby_method(
name: @name,
c_name: @name,
extern: true,
scope: nil,
arg_list: Expression::ActualArgList.new([])
)
end
def analyse_as_ruby_method(local_scope)
@name = Rubex::AST::Expression::RubyMethodCall.new(
Expression::Self.new, @name, Expression::ActualArgList.new([])
)
@name.analyse_types local_scope
end
def assign_type_based_on_whether_wrapped_type
if @entry.type.alias_type? || @entry.type.ruby_method? || @entry.type.c_function?
@type = @entry.type.type
else
@type = @entry.type
end
end
end
end
end
end