Implemented the nullary/unary call operators
[fridhskrift.git] / intermediary / intermediary.cpp
blob0f17662f8a0f1e4a983592ab870651a37f1b36cc
1 #include <stack>
2 #include <ail/file.hpp>
3 #include <ail/string.hpp>
4 #include <ail/string.hpp>
5 #include <fridh/intermediary.hpp>
6 #include <fridh/lexer.hpp>
8 namespace fridh
10 intermediary_translator::intermediary_translator():
11 running(false)
15 bool intermediary_translator::load_module(std::string const & path, std::string const & name, std::string & error_message);
17 std::string content;
18 if(!ail::read_file(path, content))
20 error_message = "Unable to read file \"" + path + "\"";
21 return false;
24 module module_output;
25 bool success = translate_data(module_output, content, error_message);
26 if(!success)
27 return false;
29 return true;
32 bool intermediary_translator::name_is_used(std::string const & name)
34 return current_node->exists(name);
37 std::string const & intermediary_translator::get_declaration_name()
39 return *lines[line_offset][1].string;
42 void intermediary_translator::name_collision_check()
44 std::string const & name = get_declaration_name();
45 if(name_is_used(name))
46 error("Name \"" + name + "\" has already been used by another function or class in the current scope");
49 symbol_tree_node & intermediary_translator::add_name(symbol::type symbol_type)
51 std::string const & name = get_declaration_name();
52 symbol_tree_node & new_node = current_node->children[name];
53 new_node = symbol_tree_node(symbol_type);
54 new_node.parent = current_node;
55 current_node = &new_node;
56 return new_node;
59 void intermediary_translator::process_body(function * current_function)
61 indentation++;
63 bool is_class = (current_function == 0);
65 if(is_class)
66 nested_class_level++;
68 while(true)
70 if(process_line(current_function))
72 if(indentation > 0)
73 indentation--;
74 if(is_class)
75 nested_class_level--;
76 current_node = current_node->parent;
77 break;
82 bool intermediary_translator::process_class()
84 lexeme_container & lexemes = lines[line_offset].lexemes;
85 if(!(lexemes.size() == 2 && lexemes[0].type == lexeme_type::class_operator && lexemes[1].type == lexeme_type::name))
86 return false;
88 name_collision_check();
90 add_name(symbol::class_symbol);
92 process_body(true);
93 return true;
96 bool intermediary_translator::process_function()
98 lexeme_container & lexemes = lines[line_offset].lexemes;
99 if(!(lexemes.size() >= 2 && lexemes[0].type == lexeme_type::function_declaration))
100 return false;
102 for(std::size_t i = 1, end = lexemes.size(); i < end; i++)
103 if(lexemes[i].type != lexeme_type::name)
104 error("Encountered an invalid lexeme type in a function declaration - at this point only names are permitted");
106 name_collision_check();
108 function & current_function = *add_name(symbol::class_symbol).function_pointer;
109 for(std::size_t i = 2, end = lexemes.size(); i < end; i++)
110 current_function.arguments.push_back(*lexemes[i].string);
112 process_body(false);
113 return true;
116 void operator_resolution(parse_tree_nodes & input, parse_tree_node & output)
118 void call_check(std::size_t extremum_offset)
120 if(extremum_offset != 1)
121 throw ail::exception("Invalid call offset encountered during operator resolution");
124 if(input.size() != 1)
126 output = input[0];
127 return;
130 bool got_an_operator = false;
131 word extremum;
132 std::size_t extremum_offset;
134 for(std::size_t i = 0, end = input.size(); i < end; i++)
136 word precedence;
137 parse_tree_node & current_node = input[i];
138 if(get_parse_tree_node_precedence(current_node, precedence))
142 !got_an_operator ||
143 precedence > extremum ||
144 (is_right_to_left_operator(current_node) && precedence == extremum)
147 got_an_operator = true;
148 extremum = precedence;
149 extremum_offset = i;
154 if(!got_an_operator)
155 throw ail::exception("Failed to perform operator resolution");
157 parse_tree_node & operator_node = input[extremum_offset];
158 std::size_t next_offset = extremum_offset + 1;
159 switch(operator_node.type)
161 case parse_tree_node_type::unary_operator_node:
162 std::size_t argument_offset = next_offset;
163 parse_tree_unary_operator_node & unary_operator_node = *operator_node.unary_operator_pointer;
164 unary_operator_node.argument = input.at(argument_offset);
165 input.erase(input.begin() + argument_offset);
166 break;
168 case parse_tree_node_type::binary_operator_node:
169 parse_tree_binary_operator_node & binary_operator_node = *operator_node.binary_operator_pointer;
171 parse_tree_nodes
172 left_side,
173 right_side;
175 std::copy(input.begin(), input.begin() + extremum_offset, left_side.begin());
176 std::copy(input.begin() + next_offset, input.end(), right_side.begin());
178 operator_resolution(left_side, binary_operator_node.left_argument);
179 operator_resolution(right_side, binary_operator_node.right_argument);
181 output = operator_node;
182 break;
184 case parse_tree_node_type::call:
185 //this is questionable
186 call_check(extremum_offset);
187 operator_node.call_pointer->function = input[0];
188 input.erase(input.begin());
189 break;
191 case parse_tree_node_type::call_operator:
192 case parse_tree_node_type::spaced_call_operator:
193 call_check(extremum_offset);
194 operator_node.is_call();
195 operator_node.call_pointer->function = input[0];
196 input.erase(input.begin());
197 if(operator_node.type != parse_tree_node_type::spaced_call_operator && next_offset != input.size())
199 //it's an unary call
200 operator_node.call_pointer->arguments.push_back(input[next_offset]);
201 input.erase(input.end() - 1);
203 break;
205 default:
206 throw ail::exception("Invalid operator node type encountered during operator resolution");
210 void intermediary_translator::parse_statement(lexeme_container & lexemes, std::size_t & offset, parse_tree_nodes & output, bool allow_multi_statements, lexeme_type::type terminator)
212 bool got_last_group = false;
213 lexeme_group::type last_group;
215 parse_tree_nodes arguments;
217 void set_last_group(lexeme_group::type new_last_group)
219 last_group = new_last_group;
220 got_last_group = true;
223 void add_unary_node(lexeme & current_lexeme)
225 parse_tree_node unary_operator_node;
226 lexeme_to_unary_operator_node(current_lexeme, unary_operator_node);
227 arguments.push_back(unary_operator_node);
230 void add_negation_lexeme()
232 add_unary_node(lexeme(lexeme_type::negation));
235 void process_node_group()
237 parse_tree_node new_node;
238 operator_resolution(arguments, new_node);
239 output.push_back(new_node);
242 symbol_prefix::type prefix = symbol_prefix::none;
244 for(std::size_t & i = offset, end = lexemes.size(); i < end; i++)
246 lexeme & current_lexeme = lexemes[i];
248 if(current_lexeme.type == terminator)
250 i++;
251 break;
253 else if(prefix != symbol_prefix::none && current_lexeme.type == lexeme_type::name)
254 error("Invalid use of a symbol prefix");
256 switch(current_lexeme.type)
258 case lexeme_type::scope_operator:
259 prefix = symbol_prefix::scope_operator;
260 continue;
262 case lexeme_type::class_operator:
263 prefix = symbol_prefix::class_operator;
264 continue;
266 case lexeme_type::bracket_start:
268 parse_tree_nodes content;
269 if(got_last_group && last_group == lexeme_group::argument)
271 parse_statement(lexemes, offset, content, true, lexeme_type::bracket_end);
272 parse_tree_node call;
273 call.is_call();
274 call.call_pointer->arguments = content;
275 arguments.push_back(call);
277 else
279 parse_statement(lexemes, offset, content, false, lexeme_type::bracket_end);
280 arguments.push_back(content[0]);
282 set_last_group(lexeme_group::argument);
283 break;
286 case lexeme_type::bracket_end:
287 error("Unmatched closing bracket");
289 case lexeme_type::array_start:
291 parse_tree_nodes elements;
292 parse_statement(lexemes, offset, content, true, lexeme_type::array_end);
293 arguments.push_back(parse_tree_node(elements));
294 set_last_group(lexeme_group::argument);
295 break;
298 case lexeme_type::array_end:
299 error("Unmatched curled brace");
301 case lexeme_type::call_operator:
302 arguments.push_back(parse_tree_node(parse_tree_node_type::call_operator));
303 set_last_group(lexeme_group::call_operator);
304 continue;
306 case lexeme_type::spaced_call_operator:
307 arguments.push_back(parse_tree_node(parse_tree_node_type::spaced_call_operator));
308 set_last_group(lexeme_group::call_operator);
309 continue;
312 lexeme_group::type group;
313 if(!get_lexeme_group(current_lexeme.type, group))
314 error("Invalid lexeme type in statement");
316 switch(group)
318 case lexeme_group::argument:
320 if(!allow_multi_statements && !got_last_group && last_group == lexeme_group::argument)
321 error("Encountered two arguments without an operator between them");
323 parse_tree_node argument_node;
324 lexeme_to_argument_node(current_lexeme, argument_node);
325 if(current_lexeme.type == lexeme_type::name)
327 argument_node.symbol_pointer->type = prefix;
328 if(prefix != symbol_prefix::none)
332 argument_node.type == parse_tree_node_type::binary_operator_node &&
333 argument_node.binary_operator_pointer->type == binary_operator_type::selection
335 error("Encountered a symbol prefix after a selection operator");
336 prefix = symbol_prefix::none;
339 arguments.push_back(argument_node);
341 if(allow_multi_statements)
343 process_node_group();
344 arguments.clear();
345 got_last_group = false;
346 continue;
348 break;
351 case lexeme_group::unary_operator:
352 if(got_last_group && last_group == lexeme_group::argument)
353 error("Encountered an argument followed by an unary operator without a binary operator between them");
354 add_unary_node(current_lexeme);
355 break;
357 case lexeme_group::binary_operator:
358 if(got_last_group)
360 switch(last_group)
362 case lexeme_group::unary_operator:
363 error("Encountered a unary operator followed by a binary operator");
365 case lexeme_group::binary_operator:
366 if(current_lexeme.type == lexeme_type::subtraction)
367 add_negation_lexeme();
368 else
369 error("Encountered two sequential binary operators");
370 break;
373 else
375 if(current_lexeme.type == lexeme_type::subtraction)
376 add_negation_lexeme();
377 else
378 error("Encountered a binary operator in the beginning of a statement");
379 break;
381 parse_tree_node binary_operator_node;
382 lexeme_to_binary_operator_node(current_lexeme, binary_operator_node);
383 arguments.push_back(binary_operator_node);
384 break;
387 set_last_group(group);
390 if(!got_last_group)
391 error("Empty statement");
393 if(last_group != lexeme_group::argument)
394 error("An operator is missing an argument");
396 process_node_group();
399 void intermediary_translator::process_statement(function & current_function)
403 bool intermediary_translator::process_line(function * active_function)
405 line_of_code & current_line = lines[line_offset];
406 if(current_line.indentation_level > indentation)
407 error("Unexpected increase in the indentation level");
409 if(!process_class())
411 if(active_function)
413 if(!process_function())
415 function & current_function = *active_function;
416 process_statement(current_function);
419 else
420 error("Regular statements and assignments need to be placed within functions");
423 line_offset++;
425 if(line_offset == line_end)
427 //end of file -> end of the module entry function block
428 return true;
431 line_of_code & next_line = lines[line_offset];
433 if(next_line.indentation_level < indentation)
435 //end of block
436 return true;
438 else
439 return false;
442 bool intermediary_translator::translate_data(module & target_module, std::string const & data, std::string const & module_name, std::string & error_message_output)
444 lines = std::vector<line_of_code>();
445 lexer current_lexer(data, lines, error_message);
446 if(!current_lexer.parse())
447 return false;
449 current_node = &target_module.symbols;
450 indentation_level = 0;
451 nested_class_level = 0;
453 while(line_offset < line_end)
457 return true;
460 void intermediary_translator::error(std::string const & message)
462 throw ail::exception("Line " + ail::number_to_string(lines[line_offset].line) + ": " + message);