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



283
284
285
# File 'lib/compiler.rb', line 283

def add_error error
	@errors.push error
end

#check_case(type, initial_case, ast) ⇒ Object



255
256
257
258
259
260
261
# File 'lib/compiler.rb', line 255

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



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

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



279
280
281
# File 'lib/compiler.rb', line 279

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



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

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



274
275
276
277
# File 'lib/compiler.rb', line 274

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, read_version) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/compiler.rb', line 26

def compile filename, read_version
	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 if @runtime == nil
	self.compile_ast @runtime, ast, read_version
end

#compile_ast(runtime, ast, read_version) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/compiler.rb', line 39

def compile_ast runtime, ast, read_version
	@runtime = runtime
	@runtime.version = ast.version if read_version
	ast.decls.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



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
137
138
139
140
141
142
143
# File 'lib/compiler.rb', line 111

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

	direction_def = @runtime.get_direction client, direction_ast.direction, server
	if direction_def == nil
		direction_def = DirectionDef.new direction_ast, client, server
	end

	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



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/compiler.rb', line 75

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_include(include_ast) ⇒ Object



64
65
66
67
68
69
70
71
72
73
# File 'lib/compiler.rb', line 64

def compile_include include_ast
	dir = File.dirname @runtime.filename
	filename = include_ast.filename + '.brotorift'
	full_path = File.join dir, filename
	if not File.exists? full_path
		add_error IncludeFileNotFoundError.new filename, include_ast.position
		return
	end
	self.compile full_path, false
end

#compile_message(direction_def, message_ast) ⇒ Object



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

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



88
89
90
91
92
93
94
95
# File 'lib/compiler.rb', line 88

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



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

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



170
171
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
# File 'lib/compiler.rb', line 170

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



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/compiler.rb', line 97

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



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

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



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

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