1 #include <ail/file.hpp>
2 #include <ail/string.hpp>
3 #include <fridh/parser.hpp>
4 #include <fridh/lexer.hpp>
13 bool parser::process_module(std::string
const & path
, std::string
const & name
, module
& output
, std::string
& error_message
)
16 if(!ail::read_file(path
, content
))
18 error_message
= "Unable to read file \"" + path
+ "\"";
23 bool success
= translate_data(module_output
, content
, name
, error_message
);
30 bool parser::name_is_used(std::string
const & name
)
32 return current_node
->exists(name
);
35 std::string
const & parser::get_declaration_name()
37 return *lines
[line_offset
].lexemes
[1].string
;
40 void parser::name_collision_check()
42 std::string
const & name
= get_declaration_name();
43 if(name_is_used(name
))
44 error("Name \"" + name
+ "\" has already been used by another function or class in the current scope");
47 symbol_tree_node
& parser::add_name(symbol::type symbol_type
)
49 std::string
const & name
= get_declaration_name();
50 symbol_tree_node
* & new_node_pointer
= current_node
->children
[name
];
51 new_node_pointer
= new symbol_tree_node
;
52 symbol_tree_node
& new_node
= *new_node_pointer
;
53 new_node
= symbol_tree_node(symbol_type
);
54 new_node
.parent
= current_node
;
55 current_node
= &new_node
;
59 void parser::process_body(executable_units
* output
)
64 bool is_class
= (output
== 0);
69 while(line_offset
< line_end
)
73 end
= process_line(0);
76 executable_unit new_unit
;
77 process_line(&new_unit
);
78 output
->push_back(new_unit
);
82 if(indentation_level
> 0)
86 current_node
= current_node
->parent
;
92 bool parser::process_class()
94 lexeme_container
& lexemes
= lines
[line_offset
].lexemes
;
95 if(!(lexemes
.size() == 2 && lexemes
[0].type
== lexeme_type::class_operator
&& lexemes
[1].type
== lexeme_type::name
))
98 name_collision_check();
100 add_name(symbol::class_symbol
);
106 bool parser::process_function(function
* output
)
108 lexeme_container
& lexemes
= lines
[line_offset
].lexemes
;
109 if(!(lexemes
.size() >= 2 && lexemes
[0].type
== lexeme_type::function_declaration
))
112 for(std::size_t i
= 1, end
= lexemes
.size(); i
< end
; i
++)
113 if(lexemes
[i
].type
!= lexeme_type::name
)
114 error("Encountered an invalid lexeme type in a function declaration - at this point only names are permitted");
116 name_collision_check();
118 function
* current_function
;
120 current_function
= output
;
122 current_function
= add_name(symbol::class_symbol
).function_pointer
;
124 for(std::size_t i
= 2, end
= lexemes
.size(); i
< end
; i
++)
125 current_function
->arguments
.push_back(*lexemes
[i
].string
);
127 process_body(¤t_function
->body
);
131 void parser::process_offset_atomic_statement(parse_tree_node
& output
, std::size_t offset
)
133 lexeme_container
& lexemes
= lines
[line_offset
].lexemes
;
134 parse_tree_nodes nodes
;
135 process_atomic_statement(lexemes
, offset
, nodes
);
140 void parser::process_composite_term(parse_tree_node
& output
)
142 process_offset_atomic_statement(output
, 1);
145 bool parser::process_line(executable_unit
* output
)
147 line_of_code
& current_line
= lines
[line_offset
];
148 if(current_line
.indentation_level
> indentation_level
)
149 error("Unexpected increase in the indentation level");
155 if(!process_function())
156 process_statement(*output
);
159 error("Regular statements and assignments need to be placed within functions");
164 if(line_offset
== line_end
)
166 //end of file -> end of the module entry function block
170 line_of_code
& next_line
= lines
[line_offset
];
173 return next_line
.indentation_level
< indentation_level
;
176 bool parser::translate_data(module
& target_module
, std::string
const & data
, std::string
const & module_name
, std::string
& error_message_output
)
180 lines
= lines_of_code();
181 lexer
current_lexer(data
, lines
);
183 if(!current_lexer
.parse(error_message_output
))
186 current_node
= &target_module
.symbols
;
187 indentation_level
= 0;
188 nested_class_level
= 0;
191 process_body(&target_module
.entry_function
.body
);
195 catch(ail::exception
& exception
)
197 error_message_output
= exception
.get_message();
202 void parser::error(std::string
const & message
)
204 throw ail::exception("Line " + ail::number_to_string(lines
[line_offset
].line
) + ": " + message
);