2 #include <ail/file.hpp>
3 #include <ail/string.hpp>
4 #include <ail/string.hpp>
5 #include <frith/intermediary.hpp>
6 #include <frith/lexer.hpp>
10 intermediary_translator::intermediary_translator():
15 bool intermediary_translator::load_module(std::string
const & path
, std::string
const & name
, std::string
& error_message
);
18 if(!ail::read_file(path
, content
))
20 error_message
= "Unable to read file \"" + path
+ "\"";
25 bool success
= translate_data(module_output
, content
, error_message
);
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 bool intermediary_translator::name_collision_check()
44 std::string
const & name
= get_declaration_name();
45 bool output
= name_is_used(name
);
47 error("Name \"" + name
+ "\" has already been used by another function or class in the current scope");
51 symbol_tree_node
& intermediary_translator::add_name(symbol::type symbol_type
)
53 std::string
const & name
= get_declaration_name();
54 symbol_tree_node
& new_node
= current_node
->children
[name
];
55 new_node
= symbol_tree_node(symbol_type
);
56 new_node
.parent
= current_node
;
57 current_node
= &new_node
;
61 match_result::type
intermediary_translator::process_body(function
* current_function
)
65 bool is_class
= (current_function
== 0);
72 process_line_result::type result
;
73 result
= process_line(current_function
);
74 if(result
== match_result::error
)
75 return process_line_result::error
;
76 else if(result
== process_line_result::end_of_block
)
82 current_node
= current_node
->parent
;
83 return match_result::match
;
88 match_result::type
intermediary_translator::process_class()
90 lexeme_container
& lexemes
= lines
[line_offset
].lexemes
;
91 if(!(lexemes
.size() == 2 && lexemes
[0].type
== lexeme_type::class_operator
&& lexemes
[1].type
== lexeme_type::name
))
92 return match_result::no_match
;
94 if(name_collision_check())
95 return match_result::error
;
97 add_name(symbol::class_symbol
);
99 return process_body(true);
102 match_result::type
intermediary_translator::process_function()
104 lexeme_container
& lexemes
= lines
[line_offset
].lexemes
;
105 if(!(lexemes
.size() >= 2 && lexemes
[0].type
== lexeme_type::function_declaration
))
106 return match_result::no_match
;
108 for(std::size_t i
= 1, end
= lexemes
.size(); i
< end
; i
++)
110 if(lexemes
[i
].type
!= lexeme_type::name
)
112 error("Encountered an invalid lexeme type in a function declaration - at this point only names are permitted");
113 return match_result::error
;
117 if(name_collision_check())
118 return match_result::error
;
120 function
& current_function
= *add_name(symbol::class_symbol
).function_pointer
;
121 for(std::size_t i
= 2, end
= lexemes
.size(); i
< end
; i
++)
122 current_function
.arguments
.push_back(*lexemes
[i
].string
);
124 return process_body(false);
127 void operator_resolution(parse_tree_nodes
& input
, parse_tree_node
& output
)
129 if(input
.size() != 1)
135 bool got_an_operator
= false;
137 std::size_t extremum_offset
;
139 for(std::size_t i
= 0, end
= input
.size(); i
< end
; i
++)
142 parse_tree_node
& current_node
= input
[i
];
143 if(get_parse_tree_node_precedence(current_node
, precedence
))
148 precedence
> extremum
||
149 (is_right_to_left_operator(current_node
) && precedence
== extremum
)
152 got_an_operator
= true;
153 extremum
= precedence
;
160 throw ail::exception("Failed to perform operator resolution");
162 parse_tree_node
& operator_node
= input
[extremum_offset
];
163 std::size_t next_offset
= extremum_offset
+ 1;
164 switch(operator_node
.type
)
166 case parse_tree_node_type::unary_operator_node
:
167 std::size_t argument_offset
= next_offset
;
168 parse_tree_unary_operator_node
& unary_operator_node
= *operator_node
.unary_operator_pointer
;
169 unary_operator_node
.argument
= input
.at(argument_offset
);
170 input
.erase(input
.begin() + argument_offset
);
173 case parse_tree_node_type::binary_operator_node
:
174 parse_tree_binary_operator_node
& binary_operator_node
= *operator_node
.binary_operator_pointer
;
180 std::copy(input
.begin(), input
.begin() + extremum_offset
, left_side
.begin());
181 std::copy(input
.begin() + next_offset
, input
.end(), right_side
.begin());
183 operator_resolution(left_side
, binary_operator_node
.left_argument
);
184 operator_resolution(right_side
, binary_operator_node
.right_argument
);
186 output
= operator_node
;
189 case parse_tree_node_type::call
:
190 //this is questionable
191 if(extremum_offset
!= 1)
192 throw ail::exception("Invalid call offset encountered during operator resolution");
193 operator_node
.call_pointer
->function
= input
[0];
194 input
.erase(input
.begin());
198 throw ail::exception("Invalid operator node type encountered during operator resolution");
202 bool intermediary_translator::parse_statement(lexeme_container
& lexemes
, std::size_t & offset
, parse_tree_nodes
& output
, bool allow_multi_statements
, lexeme_type::type terminator
)
204 bool got_last_group
= false;
205 lexeme_group::type last_group
;
207 parse_tree_nodes arguments
;
209 void set_last_group(lexeme_group::type new_last_group
)
211 last_group
= new_last_group
;
212 got_last_group
= true;
215 void add_unary_node(lexeme
& current_lexeme
)
217 parse_tree_node unary_operator_node
;
218 lexeme_to_unary_operator_node(current_lexeme
, unary_operator_node
);
219 arguments
.push_back(unary_operator_node
);
222 void add_negation_lexeme()
224 add_unary_node(lexeme(lexeme_type::negation
));
227 void process_node_group()
229 parse_tree_node new_node
;
230 operator_resolution(arguments
, new_node
);
231 output
.push_back(new_node
);
234 for(std::size_t & i
= offset
, end
= lexemes
.size(); i
< end
; i
++)
236 lexeme
& current_lexeme
= lexemes
[i
];
238 if(current_lexeme
.type
== terminator
)
244 switch(current_lexeme
.type
)
246 case lexeme_type::bracket_start
:
248 parse_tree_nodes content
;
249 if(got_last_group
&& last_group
== lexeme_group::argument
)
251 parse_statement(lexemes
, offset
, content
, true, lexeme_type::bracket_end
);
252 parse_tree_node call
;
254 call
.call_pointer
->arguments
= content
;
255 arguments
.push_back(call
);
259 parse_statement(lexemes
, offset
, content
, false, lexeme_type::bracket_end
);
260 arguments
.push_back(content
[0]);
262 set_last_group(lexeme_group::argument
);
266 case lexeme_type::bracket_end
:
267 return error("Unmatched closing bracket");
269 case lexeme_type::array_start
:
271 parse_tree_nodes elements
;
272 parse_statement(lexemes
, offset
, content
, true, lexeme_type::array_end
);
273 arguments
.push_back(parse_tree_node(elements
));
274 set_last_group(lexeme_group::argument
);
278 case lexeme_type::array_end
:
279 return error("Unmatched curled brace");
282 lexeme_group::type group
;
283 if(!get_lexeme_group(current_lexeme
.type
, group
))
284 return error("Invalid lexeme type in statement");
288 case lexeme_group::argument
:
290 if(!allow_multi_statements
&& !got_last_group
&& last_group
== lexeme_group::argument
)
291 return error("Encountered two arguments without an operator between them");
293 parse_tree_node argument_node
;
294 lexeme_to_argument_node(current_lexeme
, argument_node
);
295 arguments
.push_back(argument_node
);
297 if(allow_multi_statements
)
299 process_node_group();
301 got_last_group
= false;
307 case lexeme_group::unary_operator
:
308 if(got_last_group
&& last_group
== lexeme_group::argument
)
309 return error("Encountered an argument followed by an unary operator without a binary operator between them");
310 add_unary_node(current_lexeme
);
313 case lexeme_group::binary_operator
:
318 case lexeme_group::unary_operator
:
319 return error("Encountered a unary operator followed by a binary operator");
321 case lexeme_group::binary_operator
:
322 if(current_lexeme
.type
== lexeme_type::subtraction
)
323 add_negation_lexeme();
325 return error("Encountered two sequential binary operators");
331 if(current_lexeme
.type
== lexeme_type::subtraction
)
332 add_negation_lexeme();
334 return error("Encountered a binary operator in the beginning of a statement");
337 parse_tree_node binary_operator_node
;
338 lexeme_to_binary_operator_node(current_lexeme
, binary_operator_node
);
339 arguments
.push_back(binary_operator_node
);
343 set_last_group(group
);
347 return error("Empty statement");
349 if(last_group
!= lexeme_group::argument
)
350 return error("An operator is missing an argument");
352 process_node_group();
357 bool intermediary_translator::process_statement(function
& current_function
)
361 process_line_result::type
intermediary_translator::process_line(function
* active_function
)
363 line_of_code
& current_line
= lines
[line_offset
];
364 if(current_line
.indentation_level
> indentation
)
366 error("Unexpected increase in the indentation level");
367 return process_line_result::error
;
370 match_result::type result
= process_class();
371 if(result
== match_result::error
)
372 return process_line_result::error
;
373 else if(result
== match_result::no_match
)
377 result
= process_function();
378 if(result
== match_result::error
)
379 return process_line_result::error
;
380 else if(result
== match_result::no_match
)
382 function
& current_function
= *active_function
;
383 if(!process_statement(current_function
))
384 return process_line_result::error
;
389 error("Regular statements and assignments need to be placed within functions");
390 return process_line_result::error
;
396 if(line_offset
== line_end
)
398 //end of file -> end of the module entry function block
399 return process_line_result::end_of_block
;
402 line_of_code
& next_line
= lines
[line_offset
];
404 if(next_line
.indentation_level
< indentation
)
407 return process_line_result::end_of_block
;
410 return process_line_result::ok
;
413 bool intermediary_translator::translate_data(module
& target_module
, std::string
const & data
, std::string
const & module_name
, std::string
& error_message_output
)
415 lines
= std::vector
<line_of_code
>();
416 lexer
current_lexer(data
, lines
, error_message
);
417 if(!current_lexer
.parse())
420 current_node
= &target_module
.symbols
;
421 indentation_level
= 0;
422 nested_class_level
= 0;
424 while(line_offset
< line_end
)
431 bool intermediary_translator::error(std::string
const & message
)
433 error_message
= "Line " + ail::number_to_string(lines
[line_offset
].line
) + ": " + message
;