Class: Compiler

Inherits:
Object
  • Object
show all
Defined in:
lib/compiler.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCompiler

Returns a new instance of Compiler.



20
21
22
23
24
# File 'lib/compiler.rb', line 20

def initialize
	@errors = []
	@message_base_id = 0
	@message_id = 0
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



18
19
20
# File 'lib/compiler.rb', line 18

def errors
  @errors
end

#runtimeObject (readonly)

Returns the value of attribute runtime.



18
19
20
# File 'lib/compiler.rb', line 18

def runtime
  @runtime
end

Instance Method Details

#add_error(error) ⇒ Object



285
286
287
# File 'lib/compiler.rb', line 285

def add_error error
	@errors.push error
end

#check_case(type, initial_case, ast) ⇒ Object



257
258
259
260
261
262
263
# File 'lib/compiler.rb', line 257

def check_case type, initial_case, ast
	if type == 'node_nick' and initial_case != ast.nickname[0].char_case
		add_error InitialCaseError.new type, initial_case, ast
	elsif initial_case != ast.name[0].char_case
		add_error InitialCaseError.new type, initial_case, ast
	end
end

#check_type_nodes(member_type_ast, member_type_def) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/compiler.rb', line 230

def check_type_nodes member_type_ast, member_type_def
	return if @runtime == member_type_def.runtime

	@runtime.nodes.each do |n|
		external_node = member_type_def.runtime.nodes.find { |node| n.name == node.name }
		if external_node == nil
			add_error CorrespondingNodeNotFoundError.new member_type_def, n.name
			return
		end

		if external_node.language != n.language
			add_error NodeLanguageMismatchError.new member_type_def, n, external_node
			return
		end
	end
end

#check_type_param_count(ast, expected_count) ⇒ Object



281
282
283
# File 'lib/compiler.rb', line 281

def check_type_param_count ast, expected_count
	add_error TypeParamCountMismatchError.new ast, expected_count if ast.params.length != expected_count
end

#check_type_unique(ast) ⇒ Object



265
266
267
268
269
270
271
272
273
274
# File 'lib/compiler.rb', line 265

def check_type_unique ast
	type_def, _ = self.get_type ast, false
	return if type_def == nil

	if type_def.is_a? BuiltinTypeDef
		add_error BuiltinNameConflictError.new ast
	else
		self.check_unique 'type', type_def, ast
	end
end

#check_unique(type, old_def, new_ast) ⇒ Object



276
277
278
279
# File 'lib/compiler.rb', line 276

def check_unique type, old_def, new_ast
	return if old_def == nil
	add_error DuplicateDefError.new type, old_def.name, old_def.ast, new_ast
end

#compile(filename) ⇒ Object



26
27
28
# File 'lib/compiler.rb', line 26

def compile filename
	@runtime = self.compile_file filename
end

#compile_ast(runtime, ast) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/compiler.rb', line 44

def compile_ast runtime, ast
	@runtime = runtime
	ast.each do |decl|
		begin
			case decl
			when IncludeDecl
				compile_include decl
			when EnumDecl
				compile_enum decl
			when NodeDecl
				compile_node decl
			when StructDecl
				compile_struct decl
			when DirectionDecl
				compile_direction decl
			when SequenceDecl
				compile_sequence decl
			end
		rescue CompilerError => e
			@errors.push e
		end
	end
end

#compile_direction(direction_ast) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/compiler.rb', line 114

def compile_direction direction_ast
	client = @runtime.nodes[direction_ast.client]
	if client == nil
		add_error NodeNotFoundError.new direction_ast, direction_ast.client
		return
	end

	server = @runtime.nodes[direction_ast.server]
	if server == nil
		add_error NodeNotFoundError.new direction_ast, direction_ast.server
		return
	end

	if client == server
		add_error ClientServerSameError.new direction_ast
		return
	end

	@message_base_id += 1000
	@message_id = 0

	old_direction = @runtime.get_direction client, direction_ast.direction, server
	self.check_unique 'direction', old_direction, direction_ast

	direction_def = DirectionDef.new direction_ast, client, server
	direction_ast.messages.each do |message_ast|
		self.check_case 'message', :upper, message_ast
		self.check_unique 'message', direction_def.messages[message_ast.name], message_ast
		direction_def.add_message self.compile_message direction_def, message_ast
	end
	@runtime.add_direction direction_def
end

#compile_enum(enum_ast) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/compiler.rb', line 78

def compile_enum enum_ast
	self.check_case 'enum', :upper, enum_ast
	self.check_type_unique enum_ast
	enum_def = EnumTypeDef.new enum_ast
	enum_ast.elements.each do |element_ast|
		self.check_case 'enum element', :upper, element_ast
		self.check_unique 'enum element', enum_def.elements[element_ast.name], element_ast
		element_def = EnumElementDef.new element_ast
		enum_def.add_element element_def
	end
	@runtime.add_enum enum_def
end

#compile_file(filename) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/compiler.rb', line 30

def compile_file filename
	content = File.read filename, encoding: 'utf-8'
	tokens = Lexer::lex content, filename
	begin
		ast = Parser::parse tokens
	rescue RLTK::NotInLanguage => e
		add_error UnexpectedTokenError.new e.current
		return
	end
	runtime = Runtime.new filename
	self.compile_ast runtime, ast
	runtime
end

#compile_include(include_ast) ⇒ Object



68
69
70
71
72
73
74
75
76
# File 'lib/compiler.rb', line 68

def compile_include include_ast
	filename = include_ast.filename + '.b'
	if not File.exists? filename
		add_error IncludeFileNotFoundError.new filename, include_ast.position
		return
	end
	include_runtime = self.compile_file filename
	@runtime.add_include include_runtime
end

#compile_message(direction_def, message_ast) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/compiler.rb', line 147

def compile_message direction_def, message_ast
	@message_id += 1
	message_def = MessageDef.new message_ast, @message_base_id + @message_id
	message_ast.members.each do |member_ast|
		self.check_case 'message member', :lower, member_ast
		self.check_unique 'message member', message_def.get_member(member_ast.name), member_ast

		nodes_to_check = [direction_def.client, direction_def.server]
		member_type_def = self.get_member_type nodes_to_check, member_ast.type
		member_def = MemberDef.new member_ast, member_type_def
		message_def.add_member member_def
	end
	message_def
end

#compile_node(node_ast) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/compiler.rb', line 91

def compile_node node_ast
	self.check_case 'node', :upper, node_ast
	self.check_case 'node_nick', :upper, node_ast
	self.check_unique 'node', @runtime.nodes[node_ast.name], node_ast
	self.check_unique 'node', @runtime.nodes[node_ast.nickname], node_ast
	node_def = NodeDef.new node_ast
	@runtime.add_node node_def
end

#compile_sequence(sequence_ast) ⇒ Object



162
163
164
165
166
167
168
169
170
# File 'lib/compiler.rb', line 162

def compile_sequence sequence_ast
	self.check_case 'sequence', :upper, sequence_ast
	self.check_unique 'sequence', @runtime.get_sequence(sequence_ast.name), sequence_ast
	sequence_def = SequenceDef.new sequence_ast
	sequence_ast.steps.each do |step_ast|
		sequence_def.add_step self.compile_step step_ast
	end
	@runtime.add_sequence sequence_def
end

#compile_step(step_ast) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/compiler.rb', line 172

def compile_step step_ast
	client = @runtime.nodes[step_ast.client]
	if client == nil
		add_error NodeNotFoundError.new step_ast, step_ast.client
		return nil
	end

	server = @runtime.nodes[step_ast.server]
	if server == nil
		add_error NodeNotFoundError.new step_ast, step_ast.server
		return nil
	end

	if client == server
		add_error ClientServerSameError.new step_ast
		return nil
	end

	direction_def = @runtime.get_direction client, step_ast.direction, server
	if direction_def == nil
		add_error DirectionNotFoundError.new step_ast, client, step_ast.direction, server
		return nil
	end

	message_def = direction_def.messages[step_ast.message]
	if message_def == nil
		add_error MessageNotFoundError.new step_ast, direction_def
		return nil
	end

	StepDef.new step_ast, direction_def, message_def
end

#compile_struct(struct_ast) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/compiler.rb', line 100

def compile_struct struct_ast
	self.check_case 'struct', :upper, struct_ast
	self.check_type_unique struct_ast
	struct_def = StructTypeDef.new struct_ast
	struct_ast.members.each do |member_ast|
		self.check_case 'struct member', :lower, member_ast
		self.check_unique 'struct member', struct_def.get_member(member_ast.name), member_ast
		member_type_def = self.get_member_type @runtime.nodes.values, member_ast.type
		member_def = MemberDef.new member_ast, member_type_def
		struct_def.add_member member_def
	end
	@runtime.add_struct struct_def
end

#get_member_type(nodes_to_check, member_type_ast) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/compiler.rb', line 205

def get_member_type nodes_to_check, member_type_ast
	type_def, runtime = self.get_type member_type_ast, true
	return nil if type_def == nil

	params = []
	case type_def.name
	when 'List'
		self.check_type_param_count member_type_ast, 1
		params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
	when 'Set'
		self.check_type_param_count member_type_ast, 1
		params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
	when 'Map'
		self.check_type_param_count member_type_ast, 2
		params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
		params.push self.get_member_type nodes_to_check, member_type_ast.params[1]
	else
		self.check_type_param_count member_type_ast, 0
	end

	member_type_def = TypeInstanceDef.new member_type_ast, type_def, params, runtime
	self.check_type_nodes member_type_ast, member_type_def
	member_type_def
end

#get_type(ast, raise_error) ⇒ Object



247
248
249
250
251
252
253
254
255
# File 'lib/compiler.rb', line 247

def get_type ast, raise_error
	return nil if ast == nil
	
	type_def, runtime = @runtime.get_type ast.name
	return type_def, runtime if type_def != nil

	add_error TypeNotFoundError.new ast, ast.name if raise_error
	return type_def, runtime
end