topazc
semantic.cpp
Go to the documentation of this file.
1
6
11#include <algorithm>
12#include <climits>
13#include <fstream>
14
16 for (const AST::StmtPtr& stmt : stmts) {
17 analyze_stmt(*stmt);
18 }
19}
20
22 if (auto vds = dynamic_cast<AST::VarDeclStmt*>(&stmt)) {
24 }
25 else if (auto vas = dynamic_cast<AST::VarAsgnStmt*>(&stmt)) {
27 throw_exception(SUB_SEMANTIC, "Assignment of variable cannot be in global or module space", stmt.line, file_name, is_debug);
28 }
30 }
31 else if (auto fds = dynamic_cast<AST::FuncDeclStmt*>(&stmt)) {
33 }
34 else if (auto fcs = dynamic_cast<AST::FuncCallStmt*>(&stmt)) {
36 throw_exception(SUB_SEMANTIC, "Calling of function cannot be in global or module space", stmt.line, file_name, is_debug);
37 }
39 }
40 else if (auto rs = dynamic_cast<AST::ReturnStmt*>(&stmt)) {
42 }
43 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&stmt)) {
45 throw_exception(SUB_SEMANTIC, "Control flow cannot be in global or module space", stmt.line, file_name, is_debug);
46 }
48 }
49 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&stmt)) {
51 throw_exception(SUB_SEMANTIC, "While loop cannot be in global or module space", stmt.line, file_name, is_debug);
52 }
54 }
55 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&stmt)) {
57 throw_exception(SUB_SEMANTIC, "Do-while loop cannot be in global or module space", stmt.line, file_name, is_debug);
58 }
60 }
61 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&stmt)) {
63 throw_exception(SUB_SEMANTIC, "For loop cannot be in global or module space", stmt.line, file_name, is_debug);
64 }
66 }
67 else if (auto bs = dynamic_cast<AST::BreakStmt*>(&stmt)) {
69 }
70 else if (auto cs = dynamic_cast<AST::ContinueStmt*>(&stmt)) {
72 }
73 else if (auto ms = dynamic_cast<AST::ModuleStmt*>(&stmt)) {
75 }
76 else if (auto ums = dynamic_cast<AST::UseModuleStmt*>(&stmt)) {
78 }
79 else if (auto es = dynamic_cast<AST::ExternStmt*>(&stmt)) {
81 }
82 else {
83 throw_exception(SUB_SEMANTIC, "Unsupported statement. Please check your Topaz compiler version and fix the problematic section of the code", stmt.line, file_name, is_debug);
84 }
85}
86
89 std::stringstream ss;
90 ss << "Variable \033[0m'" << vds.name << "'\033[31m cannot have access modifier outside the module";
92 }
93 if (vds.type.type == AST::TYPE_NOTH && vds.type.is_ptr) {
94 throw_exception(SUB_SEMANTIC, "You can't define a variable with the type \033[0m'noth*'\033[31m - it's unsafe!", vds.line, file_name, is_debug);
95 }
96 std::unique_ptr<Value> value = get_variable_value(vds.name);
97 if (value != nullptr) {
98 std::stringstream ss;
99 ss << "Variable \033[0m'" << vds.name << "'\033[31m already exists";
101 }
102 AST::Type var_type = vds.type;
103 Value var_val = Value(var_type, get_default_val_by_type(var_type, vds.line), false, false);
104 if (vds.expr != nullptr) {
105 var_val = analyze_expr(*vds.expr);
106 }
107 if (is_func_arg) {
108 var_val.is_value_unknown = true;
109 var_val.is_literal = false;
110 }
111 bool ok = false;
112 if (var_type.type >= AST::TYPE_CHAR && var_type.type <= AST::TYPE_LONG &&
113 var_val.type.type >= AST::TYPE_CHAR && var_val.type.type <= AST::TYPE_LONG) {
114 if (!var_val.is_value_unknown && var_val.is_literal && !var_type.is_ptr) {
115 double var_val_val;
116 size_t max_val;
117 switch (var_val.type.type) {
118 case AST::TYPE_CHAR:
119 var_val_val = std::get<1>(var_val.value.value);
120 break;
121 case AST::TYPE_SHORT:
122 var_val_val = std::get<2>(var_val.value.value);
123 break;
124 case AST::TYPE_INT:
125 var_val_val = std::get<3>(var_val.value.value);
126 break;
127 case AST::TYPE_LONG:
128 var_val_val = std::get<4>(var_val.value.value);
129 break;
130 }
131 switch (var_type.type) {
132 case AST::TYPE_CHAR:
133 max_val = CHAR_MAX;
134 break;
135 case AST::TYPE_SHORT:
136 max_val = INT16_MAX;
137 break;
138 case AST::TYPE_INT:
139 max_val = INT_MAX;
140 break;
141 case AST::TYPE_LONG:
142 max_val = INT64_MAX;
143 break;
144 }
145 if (var_val_val >= 0 && var_val_val <= max_val) {
146 ok = true;
147 var_val.type = var_type;
148 }
149 else if (var_val_val < 0 && std::abs(var_val_val) <= max_val + 1) {
150 ok = true;
151 var_val.type = var_type;
152 }
153 else {
154 std::stringstream ss;
155 ss << "Value of expression is does not fit into the variable type: \033[0m'" << var_type.to_str() << " (from " << (long)(-(max_val + 1)) << " to "
156 << max_val << ")'\033[31m, passed value: \033[0m'" << var_val_val << "'\033[31m";
158 }
159 }
160 }
161 if (!ok && !has_common_type(var_val.type, var_type)) {
162 std::stringstream ss;
163 ss << "Type mismatch: an expression of the type \033[0m'" << var_val.type.to_str() << "'\033[31m, but the type is expected \033[0m'" << var_type.to_str() << "'\033[31m";
165 }
166 var_val = implicitly_cast(var_val, var_type, vds.line);
167 variables.top().emplace(vds.name, var_val);
168}
169
171 std::unique_ptr<Value> var_val = get_variable_value(vas.name);
172 if (var_val == nullptr) {
173 std::stringstream ss;
174 ss << "Variable \033[0m'" << vas.name << "'\033[31m does not exists";
176 }
177 if (var_val->type.is_const) {
178 std::stringstream ss;
179 ss << "Variable \033[0m'" << vas.name << "'\033[31m is a constant";
181 }
182 AST::Type var_type = var_val->type;
183 Value new_val = analyze_expr(*vas.expr);
184 bool ok = false;
185 if (var_type.type >= AST::TYPE_CHAR && var_type.type <= AST::TYPE_LONG &&
186 new_val.type.type >= AST::TYPE_CHAR && new_val.type.type <= AST::TYPE_LONG) {
187 if (!new_val.is_value_unknown && new_val.is_literal && !var_type.is_ptr) {
188 double new_val_val;
189 size_t max_val;
190 switch (new_val.type.type) {
191 case AST::TYPE_CHAR:
192 new_val_val = std::get<1>(new_val.value.value);
193 break;
194 case AST::TYPE_SHORT:
195 new_val_val = std::get<2>(new_val.value.value);
196 break;
197 case AST::TYPE_INT:
198 new_val_val = std::get<3>(new_val.value.value);
199 break;
200 case AST::TYPE_LONG:
201 new_val_val = std::get<4>(new_val.value.value);
202 break;
203 }
204 switch (var_type.type) {
205 case AST::TYPE_CHAR:
206 max_val = CHAR_MAX;
207 break;
208 case AST::TYPE_SHORT:
209 max_val = INT16_MAX;
210 break;
211 case AST::TYPE_INT:
212 max_val = INT_MAX;
213 break;
214 case AST::TYPE_LONG:
215 max_val = INT64_MAX;
216 break;
217 }
218 if (new_val_val >= 0 && new_val_val <= max_val) {
219 ok = true;
220 new_val.type = var_type;
221 }
222 else if (new_val_val < 0 && std::abs(new_val_val) <= max_val + 1) {
223 ok = true;
224 new_val.type = var_type;
225 }
226 else {
227 std::stringstream ss;
228 ss << "Value of expression is does not fit into the variable type: \033[0m'" << var_type.to_str() << " (from " << (long)(-(max_val + 1)) << " to "
229 << max_val << ")'\033[31m, passed value: \033[0m'" << new_val_val << "'\033[31m";
231 }
232 }
233 }
234 if (!ok && !has_common_type(new_val.type, var_type)) {
235 std::stringstream ss;
236 ss << "Type mismatch: an expression of the type \033[0m'" << new_val.type.to_str() << "'\033[31m, but the type is expected \033[0m'" << var_type.to_str() << "'\033[31m";
238 }
239}
240
243 std::stringstream ss;
244 ss << "Function \033[0m'" << fds.ret_type.to_str() << ' ' << get_mangled_name(fds.name) << '(';
245 for (size_t i = 0; i < fds.args.size(); i++) {
246 ss << fds.args[i].type.to_str();
247 if (i < fds.args.size() - 1) {
248 ss << ", ";
249 }
250 }
251 ss << ")'\033[31m cannot have access modifier outside the module";
253 }
254
255 Space previous_space = current_space;
257
258 if (fds.ret_type.type == AST::TYPE_NOTH && fds.ret_type.is_ptr) {
259 throw_exception(SUB_SEMANTIC, "You can't define a function with the type \033[0m'noth*'\033[31m - it's unsafe!", fds.line, file_name, is_debug);
260 }
261
262 auto func_candidates = get_function_candidates(get_mangled_name(fds.name));
263 if (!func_candidates.empty()) {
264 bool ok = false; // Can you define this function (true) or not (false)
265 for (auto& candidate : func_candidates) {
266 if (candidate->args.size() != fds.args.size()) {
267 ok = true;
268 }
269 else {
270 size_t coincidences = 0;
271 for (size_t i = 0; i < candidate->args.size(); i++) {
272 if (candidate->args[i].type == fds.args[i].type) {
273 coincidences++;
274 }
275 }
276 if (coincidences == candidate->args.size()) {
277 ok = false;
278 break;
279 }
280 else {
281 ok = true;
282 }
283 }
284 }
285 if (!ok) {
286 std::stringstream ss;
287 ss << "Function \033[0m'" << fds.ret_type.to_str() << ' ' << get_mangled_name(fds.name) << '(';
288 for (size_t i = 0; i < fds.args.size(); i++) {
289 ss << fds.args[i].type.to_str();
290 if (i < fds.args.size() - 1) {
291 ss << ", ";
292 }
293 }
294 ss << ")'\033[31m already exists";
296 }
297 }
298 AST::Type ret_type = fds.ret_type;
299 variables.push({});
300 functions_ret_types.push(ret_type);
301 std::shared_ptr<FunctionInfo> new_func = std::make_shared<FunctionInfo>(ret_type, std::move(fds.args), std::move(fds.block));
302 if (func_candidates.empty()) {
303 functions.emplace(get_mangled_name(fds.name), std::vector<std::shared_ptr<FunctionInfo>>{new_func});
304 }
305 else {
306 functions.at(get_mangled_name(fds.name)).push_back(new_func);
307 }
308 for (auto& arg : new_func->args) {
309 analyze_var_decl_stmt(*std::make_unique<AST::VarDeclStmt>(AST::ACCESS_NONE, arg.type, nullptr, arg.name, fds.line), true);
310 }
311 bool have_ret_in_global = false;
312 for (auto& stmt : new_func->block) {
313 analyze_stmt(*stmt);
314 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
315 have_ret_in_global = true;
316 }
317 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
319 if (val != nullptr) {
320 have_ret_in_global = true;
321 }
322 }
323 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
325 if (val != nullptr) {
326 have_ret_in_global = true;
327 }
328 }
329 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
331 if (val != nullptr) {
332 have_ret_in_global = true;
333 }
334 }
335 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
337 if (val != nullptr) {
338 have_ret_in_global = true;
339 }
340 }
341 }
342 if (!fds.block.empty() && !have_ret_in_global && ret_type.type != AST::TYPE_NOTH) {
343 std::stringstream ss;
344 ss << "Non-nothing function must be have return statement in the global space in the body of function. Please add or move return statement to the global space in the body of function";
346 }
348 variables.pop();
349
350 current_space = previous_space;
351}
352
354 auto func_candidates = get_function_candidates(get_mangled_name(fcs.name));
355 if (func_candidates.empty()) {
356 func_candidates = get_function_candidates(fcs.name);
357 if (func_candidates.empty()) {
358 std::stringstream ss;
359 ss << "Function \033[0m'" << get_mangled_name(fcs.name) << '(';
360 for (size_t i = 0; i < fcs.args.size(); i++) {
361 ss << analyze_expr(*fcs.args[i]).type.to_str();
362 if (i < fcs.args.size() - 1) {
363 ss << ", ";
364 }
365 }
366 ss << ")'\033[31m does not exists";
368 }
369 }
370 bool found = false;
371 size_t coincidences = 0;
372 for (auto& candidate : func_candidates) {
373 for (size_t i = 0; i < candidate->args.size(); i++) {
374 if (fcs.args.size() != candidate->args.size()) {
375 continue;
376 }
377 Value arg_val = analyze_expr(*fcs.args[i]);
378 if (has_common_type(arg_val.type, candidate->args[i].type)) {
379 coincidences++;
380 }
381 }
382 if (coincidences == candidate->args.size()) {
383 found = true;
384 break;
385 }
386 }
387 if (!found) {
388 std::stringstream ss;
389 ss << "Function \033[0m'" << get_mangled_name(fcs.name) << "'\033[31m does not have needed candidate.\nExists candidates:\n\033[0m";
390 size_t index = 0;
391 for (auto& candidate : func_candidates) {
392 ss << candidate->ret_type.to_str() << ' ' << get_mangled_name(fcs.name) << '(';
393 for (size_t i = 0; i < candidate->args.size(); i++) {
394 ss << candidate->args[i].type.to_str();
395 if (i < candidate->args.size() - 1) {
396 ss << ", ";
397 }
398 }
399 ss << ')';
400 if (index < func_candidates.size() - 1) {
401 ss << '\n';
402 }
403 index++;
404 }
405 ss << "\033[31m";
407 }
408 analyze_func_call_expr(*std::make_unique<AST::FuncCallExpr>(fcs.name, std::move(fcs.args), fcs.line));
409}
410
412 if (functions_ret_types.empty()) {
413 throw_exception(SUB_SEMANTIC, "\033[0m'return'\033[31m statement must be in a function", rs.line, file_name, is_debug);
414 }
415 if (rs.expr != nullptr) {
416 Value val = analyze_expr(*rs.expr);
417 if (!has_common_type(val.type, functions_ret_types.top())) {
418 std::stringstream ss;
419 ss << "Type mismatch: an expression of the type \033[0m'" << val.type.to_str() << "'\033[31m, but the type is expected \033[0m'" << functions_ret_types.top().to_str() << "'\033[31m";
421 }
422 }
423 else {
424 if (functions_ret_types.top().type != AST::TYPE_NOTH) {
425 throw_exception(SUB_SEMANTIC, "Nothing-type function cannot return values", rs.line, file_name, is_debug);
426 }
427 }
428}
429
431 Value cond_val = analyze_expr(*ies.cond);
432 if (cond_val.type.type != AST::TYPE_BOOL) {
433 std::stringstream ss;
434 ss << "Type mismatch: the condition of the \033[0m'if'\033[31m operator must be of type \033[0m'bool'\033[31m, but got \033[0m'" << cond_val.type.to_str() << "'\033[31m";
436 }
437 variables.push({});
438 for (auto& stmt : ies.then_block) {
439 analyze_stmt(*stmt);
440 }
441 variables.pop();
442 variables.push({});
443 if (ies.else_block.size() != 0) {
444 for (auto& stmt : ies.else_block) {
445 analyze_stmt(*stmt);
446 }
447 }
448 variables.pop();
449}
450
452 Value cond_val = analyze_expr(*wcs.cond);
453 if (cond_val.type.type != AST::TYPE_BOOL) {
454 std::stringstream ss;
455 ss << "Type mismatch: the condition of the \033[0m'while'\033[31m cycle must be of type \033[0m'bool'\033[31m, but got \033[0m'" << cond_val.type.to_str() << "'\033[31m";
457 }
458 variables.push({});
460 for (auto& stmt : wcs.block) {
461 analyze_stmt(*stmt);
462 }
464 variables.pop();
465}
466
468 Value cond_val = analyze_expr(*dwcs.cond);
469 if (cond_val.type.type != AST::TYPE_BOOL) {
470 std::stringstream ss;
471 ss << "Type mismatch: the condition of the \033[0m'do-while'\033[31m cycle must be of type \033[0m'bool'\033[31m, but got \033[0m'" << cond_val.type.to_str() << "'\033[31m";
473 }
474 variables.push({});
476 for (auto& stmt : dwcs.block) {
477 analyze_stmt(*stmt);
478 }
480 variables.pop();
481}
482
484 if (!dynamic_cast<AST::VarDeclStmt*>(&*fcs.indexator) && !dynamic_cast<AST::VarAsgnStmt*>(&*fcs.indexator)) {
485 throw_exception(SUB_SEMANTIC, "Indexator statement in \033[0m'for'\033[31m cycle must be a variable definition/assignment", fcs.indexator->line, file_name, is_debug);
486 }
487
488 variables.push({});
490 Value cond_val = analyze_expr(*fcs.cond);
491 if (cond_val.type.type != AST::TYPE_BOOL) {
492 std::stringstream ss;
493 ss << "Type mismatch: the condition of the \033[0m'for'\033[31m cycle must be of type \033[0m'bool'\033[31m, but got \033[0m'" << cond_val.type.to_str() << "'\033[31m";
495 }
498 for (auto& stmt : fcs.block) {
499 analyze_stmt(*stmt);
500 }
502 variables.pop();
503}
504
506 if (depth_of_loops == 0) {
507 throw_exception(SUB_SEMANTIC, "\033[0m'break'\033[31m statement must be in a cycle", bs.line, file_name, is_debug);
508 }
509}
510
512 if (depth_of_loops == 0) {
513 throw_exception(SUB_SEMANTIC, "\033[0m'continue'\033[31m statement must be in a cycle", cs.line, file_name, is_debug);
514 }
515}
516
519 std::stringstream ss;
520 ss << "Module \033[0m'" << ms.name << "'\033[31m cannot have access modifier outside the module";
522 }
523
524 Space previous_space = current_space;
526
527 variables.push({});
528 if (modules.find(get_mangled_name(ms.name)) != modules.end()) {
529 std::stringstream ss;
530 ss << "Module \033[0m'" << ms.name << "'\033[31m already exists";
532 }
533 modules.emplace(get_mangled_name(ms.name), new ModuleInfo());
534 ModuleInfo *module = modules.find(get_mangled_name(ms.name))->second;
535 current_path.push(PathPart{.name=ms.name, .object=PathPart::OBJ_MODULE});
536 for (auto& stmt : ms.block) {
537 if (auto sms = dynamic_cast<AST::ModuleStmt*>(&*stmt)) {
539 module->modules.emplace(sms->name, std::make_pair(sms->access, new ModuleInfo()));
540 ModuleInfo *submodule = module->modules.find(sms->name)->second.second;
541 submodule->functions = modules.find(get_mangled_name(sms->name))->second->functions;
542 submodule->modules = modules.find(get_mangled_name(sms->name))->second->modules;
543 }
544 else if (auto fds = dynamic_cast<AST::FuncDeclStmt*>(&*stmt)) {
545 module->functions.emplace(fds->name, std::make_pair(fds->access, get_mangled_name(fds->name)));
547 }
548 }
549 current_path.pop();
550 variables.pop();
551
552 current_space = previous_space;
553}
554
556 std::string all_name;
557 for (size_t i = 0; i < ums.path.size(); i++) {
558 all_name += ums.path[i];
559 if (i != ums.path.size() - 1) {
560 all_name += "-";
561 }
562 }
563 bool found = false;
564 if (modules.find(all_name) != modules.end()) {
565 found = true;
566 }
567 if (!found) {
568 std::filesystem::path path_to_mod_without_ext;
569 for (size_t i = 0; i < ums.path.size(); i++) {
570 path_to_mod_without_ext += "/" + ums.path[i];
571 }
572 std::filesystem::path path_to_mod_without_ext_in_libs = libs_path + path_to_mod_without_ext.string();
573 std::string path_to_mod_without_ext_in_libs_as_str = path_to_mod_without_ext_in_libs.string();
574 std::ifstream file;
575 if (std::filesystem::is_directory(path_to_mod_without_ext_in_libs_as_str)) {
576 if (std::filesystem::exists(path_to_mod_without_ext_in_libs_as_str + "/main.tp")) {
577 file = std::ifstream(path_to_mod_without_ext_in_libs_as_str + "/main.tp");
578 if (!file.is_open()) {
579 std::stringstream ss;
580 ss << "Module \033[0m'" << all_name << "'\033[31m does not exists";
582 }
583 std::ostringstream content;
584 content << file.rdbuf();
585 file.close();
586 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str + "/main.tp", is_debug);
587 std::vector<Token> tokens = lex.tokenize();
588 Parser parser(tokens, is_debug);
589 std::vector<AST::StmtPtr> stmts = parser.parse();
590 SemanticAnalyzer semantic(stmts, libs_path, path_to_mod_without_ext_in_libs_as_str + "/main.tp", is_debug);
591 semantic.analyze();
592 std::map<std::string, ModuleInfo*> modules = semantic.get_modules();
593 if (modules.find(all_name) == modules.end()) {
594 std::stringstream ss;
595 ss << "File \033[0m'" << path_to_mod_without_ext_in_libs_as_str + "/main.tp" << "'\033[31m does not have a module with name \033[0m'" << all_name << "'\033[31m inside";
597 }
598 size_t current_path_size = current_path.size();
599 for (auto& module : modules) {
600 this->modules.emplace(module.first, module.second);
601 std::vector<PathPart> resolved_name = get_resolved_name(module.first);
602 current_path.push({resolved_name.back().name, PathPart::OBJ_MODULE});
603 auto functions = semantic.get_functions();
604 for (auto& func : module.second->functions) {
605 this->functions.emplace(get_mangled_name(func.first), std::move(functions.at(get_mangled_name(func.first))));
606 }
607 }
608 for (size_t i = current_path.size() - current_path_size; i > 0; i--) {
609 current_path.pop();
610 }
611 }
612 else {
613 std::stringstream ss;
614 ss << "Module \033[0m'" << all_name << "'\033[31m does not exists";
616 }
617 }
618 else {
619 std::string path_to_file;
620 for (const auto& entry : std::filesystem::recursive_directory_iterator(libs_path)) {
621 if (entry.path().filename() == ums.path.back() + ".tp" && !std::filesystem::is_directory(entry.path())) {
622 path_to_file = entry.path();
623 file = std::ifstream(path_to_file);
624 break;
625 }
626 }
627 if (!file.is_open()) {
628 std::stringstream ss;
629 ss << "Module \033[0m'" << all_name << "'\033[31m does not exists";
631 }
632 std::ostringstream content;
633 content << file.rdbuf();
634 file.close();
635 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str + ".tp", is_debug);
636 std::vector<Token> tokens = lex.tokenize();
637 Parser parser(tokens, is_debug);
638 std::vector<AST::StmtPtr> stmts = parser.parse();
639 SemanticAnalyzer semantic(stmts, libs_path, path_to_mod_without_ext_in_libs_as_str + ".tp", is_debug);
640 semantic.analyze();
641 std::map<std::string, ModuleInfo*> modules = semantic.get_modules();
642 if (modules.find(all_name) == modules.end()) {
643 std::stringstream ss;
644 ss << "File \033[0m'" << path_to_file << "'\033[31m does not have a module with name \033[0m'" << all_name << "'\033[31m inside";
646 }
647 size_t current_path_size = current_path.size();
648 for (auto& module : modules) {
649 this->modules.emplace(module.first, module.second);
650 std::vector<PathPart> resolved_name = get_resolved_name(module.first);
651 current_path.push({resolved_name.back().name, PathPart::OBJ_MODULE});
652 auto functions = semantic.get_functions();
653 for (auto& func : module.second->functions) {
654 this->functions.emplace(get_mangled_name(func.first), std::move(functions.at(get_mangled_name(func.first))));
655 }
656 }
657 for (size_t i = current_path.size() - current_path_size; i > 0; i--) {
658 current_path.pop();
659 }
660 }
661 }
662 if (std::find(names_of_imported_modules.begin(), names_of_imported_modules.end(), all_name) != names_of_imported_modules.end()) {
663 std::stringstream ss;
664 ss << "Module \033[0m'" << ums.path.back() << "'\033[31m already imported";
666 }
667 names_of_imported_modules.push_back(all_name);
668}
669
672 std::stringstream ss;
673 ss << "Specified language name for extern calling (\033[0m'" << es.lang_name_lit << "'\033[31m) is unsupported";
675 }
676 for (auto& stmt : es.block) {
677 analyze_stmt(*stmt);
678 }
679}
680
682 if (auto lit = dynamic_cast<AST::Literal*>(&expr)) {
683 return analyze_literal_expr(*lit);
684 }
685 else if (auto be = dynamic_cast<AST::BinaryExpr*>(&expr)) {
686 return analyze_binary_expr(*be);
687 }
688 else if (auto ue = dynamic_cast<AST::UnaryExpr*>(&expr)) {
689 return analyze_unary_expr(*ue);
690 }
691 else if (auto ve = dynamic_cast<AST::VarExpr*>(&expr)) {
692 return analyze_var_expr(*ve);
693 }
694 else if (auto fce = dynamic_cast<AST::FuncCallExpr*>(&expr)) {
695 return analyze_func_call_expr(*fce);
696 }
697 else if (auto oce = dynamic_cast<AST::ChainObjects*>(&expr)) {
698 return analyze_obj_chain_expr(*oce);
699 }
700 else {
701 throw_exception(SUB_SEMANTIC, "An unsupported expression was encountered during compilation. Please check your Topaz compiler version and fix the problematic section of the code", expr.line, file_name, is_debug);
702 }
703}
704
708
710 Value left_val = analyze_expr(*be.left_expr);
711 Value right_val = analyze_expr(*be.right_expr);
712
713 AST::Type left_type = left_val.type;
714 AST::Type right_type = right_val.type;
715
716 AST::Type output_type = get_common_type(left_type, right_type, be.line);
717
718 if (left_type.type >= AST::TYPE_BOOL && left_type.type <= AST::TYPE_DOUBLE && right_type.type > AST::TYPE_DOUBLE ||
719 right_type.type >= AST::TYPE_BOOL && right_type.type <= AST::TYPE_DOUBLE && left_type.type > AST::TYPE_DOUBLE) {
720 std::stringstream ss;
721 ss << "Type mismatch: it is not possible to use the binary \033[0m'" << be.op.value <<"'\033[31m operator with \033[0m'" << left_type.to_str() << "'\033[31m and \033[0m'" << right_type.to_str() <<"'\033[31m types";
723 }
724 else {
725 if (left_type.type == AST::TYPE_STRING_LIT && right_type.type == AST::TYPE_STRING_LIT) {
726 if (be.op.type != TOK_OP_PLUS) {
727 std::stringstream ss;
728 ss << "Type mismatch: it is not possible to use the binary \033[0m'" << be.op.value <<"'\033[31m operator with \033[0m'" << left_type.to_str() << "'\033[31m and \033[0m'" << right_type.to_str() <<"'\033[31m types";
730 }
731 return Value(AST::Type(AST::TYPE_STRING_LIT, "string"), std::get<7>(left_val.value.value) + std::get<7>(right_val.value.value), left_val.is_value_unknown || right_val.is_value_unknown, left_val.is_literal && right_val.is_literal);
732 }
733 switch (be.op.type) {
734 #define VALUE(op, type) Value(output_type, static_cast<type>(binary_two_variants(left_val, right_val, op, be.line)), left_val.is_value_unknown || right_val.is_value_unknown, left_val.is_literal && right_val.is_literal)
735 case TOK_OP_PLUS:
736 case TOK_OP_MINUS:
737 case TOK_OP_MULT:
738 case TOK_OP_DIV:
739 case TOK_OP_MODULO:
740 if (be.op.type >= TOK_OP_PLUS && be.op.type <= TOK_OP_MODULO &&
741 (be.op.type != TOK_OP_PLUS || left_type.type != AST::TYPE_STRING_LIT || right_type.type != AST::TYPE_STRING_LIT) &&
742 (left_type.type > AST::TYPE_DOUBLE || right_type.type > AST::TYPE_DOUBLE)) {
743 std::stringstream ss;
744 ss << "Type mismatch: it is not possible to use the binary \033[0m'" << be.op.value <<"'\033[31m operator with \033[0m'" << left_type.to_str() << "'\033[31m and \033[0m'" << right_type.to_str() <<"'\033[31m types";
746 }
747 case TOK_OP_EQ_EQ:
748 case TOK_OP_NOT_EQ_EQ:
749 case TOK_OP_GT:
750 case TOK_OP_GT_EQ:
751 case TOK_OP_LS:
752 case TOK_OP_LS_EQ:
753 if (be.op.type >= TOK_OP_EQ_EQ) {
754 output_type = AST::Type(AST::TYPE_BOOL, "bool");
755 }
756 if (be.op.type > TOK_OP_NOT_EQ_EQ && (left_type.type > AST::TYPE_DOUBLE || left_type.type == AST::TYPE_BOOL || right_type.type > AST::TYPE_DOUBLE || right_type.type == AST::TYPE_BOOL)) {
757 std::stringstream ss;
758 ss << "Type mismatch: it is not possible to use the binary \033[0m'" << be.op.value <<"'\033[31m operator with \033[0m'" << left_type.to_str() << "'\033[31m and \033[0m'" << right_type.to_str() <<"'\033[31m types";
760 }
761 case TOK_OP_L_AND:
762 case TOK_OP_L_OR:
763 if (be.op.type >= TOK_OP_L_AND && be.op.type <= TOK_OP_L_OR && (left_type.type != AST::TYPE_BOOL || right_type.type != AST::TYPE_BOOL)) {
764 std::stringstream ss;
765 ss << "Type mismatch: it is not possible to use the binary \033[0m'" << be.op.value <<"'\033[31m operator with \033[0m'" << left_type.to_str() << "'\033[31m and \033[0m'" << right_type.to_str() <<"'\033[31m types";
767 }
768 if (left_val.is_value_unknown || right_val.is_value_unknown) {
769 return Value(output_type, 0, left_val.is_value_unknown || right_val.is_value_unknown, left_val.is_literal && right_val.is_literal);
770 }
771 switch (output_type.type) {
772 case AST::TYPE_BOOL:
773 return VALUE(be.op.type, bool);
774 case AST::TYPE_CHAR:
775 return VALUE(be.op.type, char);
776 case AST::TYPE_SHORT:
777 return VALUE(be.op.type, short);
778 case AST::TYPE_INT:
779 return VALUE(be.op.type, int);
780 case AST::TYPE_LONG:
781 return VALUE(be.op.type, long);
782 case AST::TYPE_FLOAT:
783 return VALUE(be.op.type, float);
784 case AST::TYPE_DOUBLE:
785 return VALUE(be.op.type, double);
786 }
787 default: {}
788 #undef VALUE
789 }
790 }
791}
792
794 Value val = analyze_expr(*ue.expr);
795 AST::Type type = val.type;
796
797 if (val.is_value_unknown) {
798 return Value(type, 0, val.is_value_unknown, val.is_literal);
799 }
800
801 switch (ue.op.type) {
802 #define VALUE(op, needed_type) Value(type, static_cast<needed_type>(unary_two_variants(val, op, ue.line)), val.is_value_unknown, val.is_literal)
803 case TOK_OP_MINUS:
804 if (ue.op.type == TOK_OP_MINUS && (type.type > AST::TYPE_DOUBLE || type.type == AST::TYPE_BOOL)) {
805 std::stringstream ss;
806 ss << "Type mismatch: it is not possible to use the unary \033[0m'" << ue.op.value <<"'\033[31m operator with \033[0m'" << type.to_str() << "'\033[31m type";
808 }
809 case TOK_OP_L_NOT:
810 if (ue.op.type == TOK_OP_L_NOT && type.type != AST::TYPE_BOOL) {
811 std::stringstream ss;
812 ss << "Type mismatch: it is not possible to use the unary \033[0m'" << ue.op.value <<"'\033[31m operator with \033[0m'" << type.to_str() << "'\033[31m type";
814 }
815 case TOK_OP_MULT:
816 if (ue.op.type == TOK_OP_MULT) {
817 if (!type.is_ptr) {
818 throw_exception(SUB_SEMANTIC, "The dereference operator can ONLY be used for pointers", ue.line, file_name, is_debug);
819 }
820 type.is_ptr = false;
821 }
822 case TOK_OP_REF:
823 if (ue.op.type == TOK_OP_REF) {
824 if (!dynamic_cast<AST::VarExpr*>(&*ue.expr)) {
825 throw_exception(SUB_SEMANTIC, "The reference operator can ONLY be used for objects allocated in memory", ue.line, file_name, is_debug);
826 }
827 if (val.type.is_ptr) {
828 throw_exception(SUB_SEMANTIC, "The reference operator cannot be used for a pointer", ue.line, file_name, is_debug);
829 }
830 type.is_ptr = true;
831 }
832 switch (type.type) {
833 case AST::TYPE_BOOL:
834 return VALUE(ue.op.type, bool);
835 case AST::TYPE_CHAR:
836 return VALUE(ue.op.type, char);
837 case AST::TYPE_SHORT:
838 return VALUE(ue.op.type, short);
839 case AST::TYPE_INT:
840 return VALUE(ue.op.type, int);
841 case AST::TYPE_LONG:
842 return VALUE(ue.op.type, long);
843 case AST::TYPE_FLOAT:
844 return VALUE(ue.op.type, float);
845 case AST::TYPE_DOUBLE:
846 return VALUE(ue.op.type, double);
847 }
848 default: {}
849 #undef VALUE
850 }
851}
852
854 std::unique_ptr<Value> var = get_variable_value(ve.name);
855 if (var == nullptr) {
856 if (modules.find(get_mangled_name(ve.name)) != modules.end()) {
858 }
859 std::stringstream ss;
860 ss << "Variable \033[0m'" << ve.name << "'\033[31m does not exists";
862 }
863 return *var;
864}
865
867 auto func_candidates = get_function_candidates(get_mangled_name(fce.name));
868 if (func_candidates.empty()) {
869 func_candidates = get_function_candidates(fce.name);
870 if (func_candidates.empty()) {
871 std::stringstream ss;
872 ss << "Function \033[0m'" << get_mangled_name(fce.name) << '(';
873 for (size_t i = 0; i < fce.args.size(); i++) {
874 ss << analyze_expr(*fce.args[i]).type.to_str();
875 if (i < fce.args.size() - 1) {
876 ss << ", ";
877 }
878 }
879 ss << ")'\033[31m does not exists";
881 }
882 }
883 bool found = false;
884 size_t last_score = SIZE_MAX;
885 size_t best_candidate_index = 0;
886 for (size_t candidate_index = 0; candidate_index < func_candidates.size(); candidate_index++) {
887 size_t score = 0;
888 size_t coincidences = 0;
889 auto candidate = func_candidates[candidate_index];
890 for (size_t i = 0; i < candidate->args.size(); i++) {
891 if (fce.args.size() != candidate->args.size()) {
892 continue;
893 }
894 Value arg_val = analyze_expr(*fce.args[i]);
895 if (has_common_type(arg_val.type, candidate->args[i].type)) {
896 if (arg_val.type != candidate->args[i].type) {
897 if (arg_val.type.type <= AST::TYPE_LONG && candidate->args[i].type.type <= AST::TYPE_LONG) {
898 score++;
899 }
900 else if (arg_val.type.type >= AST::TYPE_FLOAT && arg_val.type.type <= AST::TYPE_DOUBLE
901 && candidate->args[i].type.type >= AST::TYPE_FLOAT && candidate->args[i].type.type <= AST::TYPE_DOUBLE) {
902 score++;
903 }
904 else if (arg_val.type.type >= AST::TYPE_FLOAT && arg_val.type.type <= AST::TYPE_DOUBLE
905 && candidate->args[i].type.type >= AST::TYPE_FLOAT && candidate->args[i].type.type <= AST::TYPE_DOUBLE) {
906 score++;
907 }
908 else if (arg_val.type.type <= AST::TYPE_DOUBLE && candidate->args[i].type.type <= AST::TYPE_DOUBLE) {
909 score += 2;
910 }
911 }
912 coincidences++;
913 }
914 else {
915 score += 99;
916 }
917
918 }
919 if (score <= last_score) {
920 best_candidate_index = candidate_index;
921 last_score = score;
922 }
923 if (coincidences == candidate->args.size()) {
924 found = true;
925 }
926 }
927 if (!found) {
928 std::stringstream ss;
929 ss << "Function \033[0m'" << get_mangled_name(fce.name) << '(';
930 for (size_t i = 0; i < fce.args.size(); i++) {
931 ss << analyze_expr(*fce.args[i]).type.to_str();
932 if (i < fce.args.size() - 1) {
933 ss << ", ";
934 }
935 }
936 ss << ")'\033[31m does not have needed candidate.\nExists candidates:\n\033[0m";
937 size_t index = 0;
938 for (auto& candidate : func_candidates) {
939 ss << candidate->ret_type.to_str() << ' ' << get_mangled_name(fce.name) << '(';
940 for (size_t i = 0; i < candidate->args.size(); i++) {
941 ss << candidate->args[i].type.to_str();
942 if (i < candidate->args.size() - 1) {
943 ss << ", ";
944 }
945 }
946 ss << ')';
947 if (index < func_candidates.size() - 1) {
948 ss << '\n';
949 }
950 index++;
951 }
952 ss << "\033[31m";
954 }
955
956 size_t index = 0;
957 auto best_candidate = func_candidates[best_candidate_index];
958 for (auto& arg : fce.args) {
959 AST::Type arg_type = analyze_expr(*arg).type;
960 if (!has_common_type(arg_type, best_candidate->args[index].type)) {
961 std::stringstream ss;
962 ss << "In the " << index + 1 << "th argument: Type mismatch: an expression of the type \033[0m'" << arg_type.to_str() << "'\033[31m, but the type is expected \033[0m'" << best_candidate->args[index].type.to_str() << "'\033[31m";
964 }
965 index++;
966 }
967 return get_function_return_value(best_candidate, fce);
968}
969
971 Value value = analyze_expr(*co.chain[0]); // Value of target object
972 for (size_t i = 1; i < co.chain.size(); i++) {
973 value = analyze_obj_from_chain(value, *co.chain[i]);
974 }
975 if (value.type.type == AST::TYPE_MODULE) {
976 throw_exception(SUB_SEMANTIC, "Cannot specify module as expression", co.line, file_name, is_debug);
977 }
978 return value;
979}
980
982 if (auto fce = dynamic_cast<AST::FuncCallExpr*>(&obj)) {
983 if (target.type.type == AST::TYPE_MODULE) {
984 ModuleInfo *info = modules.find(target.type.name)->second;
985 if (info == nullptr) {
986 std::stringstream ss;
987 ss << "Module \033[0m'" << target.type.name << "'\033[31m does not exists";
988 throw_exception(SUB_SEMANTIC, ss.str(), fce->line, file_name, is_debug);
989 }
990 if (info->functions.find(fce->name) == info->functions.end()) {
991 std::stringstream ss;
992 ss << "Function \033[0m'" << get_mangled_name(fce->name) << '(';
993 for (size_t i = 0; i < fce->args.size(); i++) {
994 ss << analyze_expr(*fce->args[i]).type.to_str();
995 if (i < fce->args.size() - 1) {
996 ss << ", ";
997 }
998 }
999 ss << ")'\033[31m does not exists in module \033[0m'" << target.type.name << "'\033[31m";
1000 throw_exception(SUB_SEMANTIC, ss.str(), fce->line, file_name, is_debug);
1001 }
1002 if (info->functions.at(fce->name).first != AST::ACCESS_PUBLIC) {
1003 std::stringstream ss;
1004 ss << "Function \033[0m'" << get_mangled_name(fce->name) << '(';
1005 for (size_t i = 0; i < fce->args.size(); i++) {
1006 ss << analyze_expr(*fce->args[i]).type.to_str();
1007 if (i < fce->args.size() - 1) {
1008 ss << ", ";
1009 }
1010 }
1011 ss << ")'\033[31m in module \033[0m'" << target.type.name << "'\033[31m is private member";
1012 throw_exception(SUB_SEMANTIC, ss.str(), fce->line, file_name, is_debug);
1013 }
1015 Value value = analyze_func_call_expr(*fce);
1016 current_path.pop();
1017 return value;
1018 }
1019 }
1020 else if (auto ve = dynamic_cast<AST::VarExpr*>(&obj)) {
1021 ModuleInfo *info = modules.find(target.type.name)->second;
1022 if (info == nullptr) {
1023 std::stringstream ss;
1024 ss << "Module \033[0m'" << target.type.name << "'\033[31m does not exists";
1025 throw_exception(SUB_SEMANTIC, ss.str(), fce->line, file_name, is_debug);
1026 }
1027 if (info->modules.find(ve->name) != info->modules.end()) {
1028 if (info->modules.at(ve->name).first != AST::ACCESS_PUBLIC) {
1029 std::stringstream ss;
1030 ss << "Module \033[0m'" << ve->name << "'\033[31m in module \033[0m'" << target.type.name << "'\033[31m is private member";
1031 throw_exception(SUB_SEMANTIC, ss.str(), ve->line, file_name, is_debug);
1032 }
1033 target.type.name += "-" + ve->name;
1034 return target;
1035 }
1036 std::stringstream ss;
1037 ss << "Module \033[0m'" << ve->name << "'\033[31m does not exists in module \033[0m'" << target.type.name << "'\033[31m";
1038 throw_exception(SUB_SEMANTIC, ss.str(), ve->line, file_name, is_debug);
1039 }
1040 else {
1041 std::stringstream ss;
1042 ss << "Module \033[0m'" << target.type.name << "'\033[31m does not have passed object type";
1043 throw_exception(SUB_SEMANTIC, ss.str(), fce->line, file_name, is_debug);
1044 }
1045}
1046
1048 variables.push({});
1049 functions_ret_types.push(func->ret_type);
1050 for (size_t i = 0; i < fce.args.size(); i++) {
1051 Value val = analyze_expr(*fce.args[i]);
1052 val.type = func->args[i].type;
1053 val.is_value_unknown = true;
1054 val.is_literal = false;
1055 variables.top().emplace(func->args[i].name, val);
1056 }
1057 for (auto& stmt : func->block) {
1058 analyze_stmt(*stmt);
1059 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1060 Value val = analyze_expr(*rs->expr);
1061 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1062 variables.pop();
1063 functions_ret_types.pop();
1064 return val;
1065 }
1066 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1068 if (val != nullptr) {
1069 variables.pop();
1070 functions_ret_types.pop();
1071 return *val;
1072 }
1073 }
1074 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1076 if (val != nullptr) {
1077 variables.pop();
1078 functions_ret_types.pop();
1079 return *val;
1080 }
1081 }
1082 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1084 if (val != nullptr) {
1085 variables.pop();
1086 functions_ret_types.pop();
1087 return *val;
1088 }
1089 }
1090 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1092 if (val != nullptr) {
1093 variables.pop();
1094 functions_ret_types.pop();
1095 return *val;
1096 }
1097 }
1098 }
1099 if (!func->block.empty()) {
1100 std::stringstream ss;
1101 ss << "Not all paths returns value in function \033[0m'" << fce.name << "'\033[31m. Please add \033[0m'return'\033[31m statement into the end of the function";
1103 }
1104 return Value(func->ret_type, 0, true, false);
1105}
1106
1108 Value cond_val = analyze_expr(*ies.cond);
1109 if (cond_val.is_literal && !cond_val.is_value_unknown && std::get<bool>(cond_val.value.value) == true) {
1110 for (auto& stmt : ies.then_block) {
1111 analyze_stmt(*stmt);
1112 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1113 static Value val = analyze_expr(*rs->expr);
1114 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1115 return &val;
1116 }
1117 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1119 }
1120 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1122 }
1123 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1125 }
1126 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1128 }
1129 }
1130 }
1131 else if (cond_val.is_literal && !cond_val.is_value_unknown && std::get<bool>(cond_val.value.value) == false) {
1132 for (auto& stmt : ies.else_block) {
1133 analyze_stmt(*stmt);
1134 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1135 static Value val = analyze_expr(*rs->expr);
1136 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1137 return &val;
1138 }
1139 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1141 }
1142 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1144 }
1145 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1147 }
1148 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1150 }
1151 }
1152 }
1153 return nullptr;
1154}
1155
1158 Value cond_val = analyze_expr(*wcs.cond);
1159 if (cond_val.is_literal && !cond_val.is_value_unknown && std::get<bool>(cond_val.value.value) == true) {
1160 for (auto& stmt : wcs.block) {
1161 analyze_stmt(*stmt);
1162 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1163 static Value val = analyze_expr(*rs->expr);
1164 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1166 return &val;
1167 }
1168 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1171 }
1172 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1175 }
1176 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1179 }
1180 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1183 }
1184 }
1185 }
1187 return nullptr;
1188}
1189
1192 for (auto& stmt : dwcs.block) {
1193 analyze_stmt(*stmt);
1194 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1195 static Value val = analyze_expr(*rs->expr);
1196 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1198 return &val;
1199 }
1200 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1203 }
1204 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1207 }
1208 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1211 }
1212 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1215 }
1216 }
1218 return nullptr;
1219}
1220
1223 variables.push({});
1224 analyze_stmt(*fcs.indexator);
1225 Value cond_val = analyze_expr(*fcs.cond);
1226 if (cond_val.is_literal && !cond_val.is_value_unknown && std::get<bool>(cond_val.value.value) == true) {
1227 for (auto& stmt : fcs.block) {
1228 analyze_stmt(*stmt);
1229 if (auto rs = dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
1230 static Value val = analyze_expr(*rs->expr);
1231 val = implicitly_cast(val, functions_ret_types.top(), rs->line);
1232 variables.pop();
1234 return &val;
1235 }
1236 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&*stmt)) {
1237 variables.pop();
1240 }
1241 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&*stmt)) {
1242 variables.pop();
1245 }
1246 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&*stmt)) {
1247 variables.pop();
1250 }
1251 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&*stmt)) {
1252 variables.pop();
1255 }
1256 }
1257 }
1258 variables.pop();
1260 return nullptr;
1261}
1262
1264 switch (type.type) {
1265 case AST::TYPE_BOOL:
1266 return AST::Value(false);
1267 case AST::TYPE_CHAR:
1268 return AST::Value('\0');
1269 case AST::TYPE_SHORT:
1270 return AST::Value(static_cast<short>(0));
1271 case AST::TYPE_INT:
1272 return AST::Value(0);
1273 case AST::TYPE_LONG:
1274 return AST::Value(0L);
1275 case AST::TYPE_FLOAT:
1276 return AST::Value(0.0F);
1277 case AST::TYPE_DOUBLE:
1278 return AST::Value(0.0);
1279 default:
1280 std::stringstream ss;
1281 ss << "Cannot generate default value for \033[0m'" << type.to_str() << "'\033[31m type";
1283 }
1284}
1285
1286std::unique_ptr<SemanticAnalyzer::Value> SemanticAnalyzer::get_variable_value(std::string name) {
1287 auto vars = variables;
1288 while (!vars.empty()) {
1289 auto vars_it = vars.top().find(name);
1290 if (vars_it != vars.top().end()) {
1291 return std::make_unique<Value>(vars_it->second);
1292 }
1293 vars.pop();
1294 }
1295 return nullptr;
1296}
1297
1298std::vector<std::shared_ptr<SemanticAnalyzer::FunctionInfo>> SemanticAnalyzer::get_function_candidates(std::string name) {
1299 auto func_it = functions.find(name);
1300 if (func_it != functions.end()) {
1301 return func_it->second;
1302 }
1303 return {};
1304}
1305
1307 if (left == right) {
1308 return true;
1309 }
1310 if (left.type == AST::TYPE_STRING_LIT && right.type == AST::TYPE_CHAR && right.is_ptr) {
1311 return true;
1312 }
1313 if (!left.is_ptr && !right.is_ptr) {
1315 std::find(implicitly_cast_allowed_types[left.type].begin(), implicitly_cast_allowed_types[left.type].end(), right.type) != implicitly_cast_allowed_types[left.type].end()) {
1316 return true;
1317 }
1318 }
1319 return false;
1320}
1321
1323 if (left.type == right.type) {
1324 return left;
1325 }
1326
1327 if (left.type == AST::TYPE_STRING_LIT && right.type == AST::TYPE_CHAR && right.is_ptr) {
1328 return left;
1329 }
1330
1331 if (has_common_type(left, right)) {
1332 return AST::Type(*std::find(implicitly_cast_allowed_types[left.type].begin(), implicitly_cast_allowed_types[left.type].end(), right.type).base(), right.name, right.is_const, right.is_ptr, right.is_nullable);
1333 }
1334 if (has_common_type(right, left)) {
1335 return AST::Type(*std::find(implicitly_cast_allowed_types[right.type].begin(), implicitly_cast_allowed_types[right.type].end(), left.type).base(), left.name, left.is_const, left.is_ptr, left.is_nullable);
1336 }
1337
1338 std::stringstream ss;
1339 ss << "Type mismatch: there is no common type for \033[0m'" << left.to_str() << "'\033[31m and \033[0m'" << right.to_str() << "'\033[31m";
1341}
1342
1344 AST::Type output_type = get_common_type(val.type, type, line);
1345 Value res = Value(output_type, 0, val.is_value_unknown, val.is_literal);
1346
1347 double val_from_variant = 0;
1348 switch (val.value.value.index()) {
1349 case 0:
1350 val_from_variant = std::get<0>(val.value.value);
1351 break;
1352 case 1:
1353 val_from_variant = std::get<1>(val.value.value);
1354 break;
1355 case 2:
1356 val_from_variant = std::get<2>(val.value.value);
1357 break;
1358 case 3:
1359 val_from_variant = std::get<3>(val.value.value);
1360 break;
1361 case 4:
1362 val_from_variant = std::get<4>(val.value.value);
1363 break;
1364 case 5:
1365 val_from_variant = std::get<5>(val.value.value);
1366 break;
1367 case 6:
1368 val_from_variant = std::get<6>(val.value.value);
1369 break;
1370 }
1371 switch (type.type) {
1372 #define VALUE(type) static_cast<type>(val_from_variant)
1373 case AST::TYPE_BOOL:
1374 res.value.value = VALUE(bool);
1375 break;
1376 case AST::TYPE_CHAR:
1377 res.value.value = VALUE(char);
1378 break;
1379 case AST::TYPE_SHORT:
1380 res.value.value = VALUE(short);
1381 break;
1382 case AST::TYPE_INT:
1383 res.value.value = VALUE(int);
1384 break;
1385 case AST::TYPE_LONG:
1386 res.value.value = VALUE(long);
1387 break;
1388 case AST::TYPE_FLOAT:
1389 res.value.value = VALUE(float);
1390 break;
1391 case AST::TYPE_DOUBLE:
1392 res.value.value = VALUE(double);
1393 break;
1394 #undef VALUE
1395 }
1396
1397 return res;
1398}
1399
1400double SemanticAnalyzer::binary_two_variants(Value left, Value right, TokenType op, uint32_t line) {
1401 if (left.is_value_unknown || right.is_value_unknown) {
1402 return 0;
1403 }
1404
1405 double left_val = 0;
1406 double right_val = 0;
1407 switch (left.value.value.index()) {
1408 case 0:
1409 left_val = std::get<0>(left.value.value);
1410 break;
1411 case 1:
1412 left_val = std::get<1>(left.value.value);
1413 break;
1414 case 2:
1415 left_val = std::get<2>(left.value.value);
1416 break;
1417 case 3:
1418 left_val = std::get<3>(left.value.value);
1419 break;
1420 case 4:
1421 left_val = std::get<4>(left.value.value);
1422 break;
1423 case 5:
1424 left_val = std::get<5>(left.value.value);
1425 break;
1426 case 6:
1427 left_val = std::get<6>(left.value.value);
1428 break;
1429 }
1430 switch (right.value.value.index()) {
1431 case 0:
1432 right_val = std::get<0>(right.value.value);
1433 break;
1434 case 1:
1435 right_val = std::get<1>(right.value.value);
1436 break;
1437 case 2:
1438 right_val = std::get<2>(right.value.value);
1439 break;
1440 case 3:
1441 right_val = std::get<3>(right.value.value);
1442 break;
1443 case 4:
1444 right_val = std::get<4>(right.value.value);
1445 break;
1446 case 5:
1447 right_val = std::get<5>(right.value.value);
1448 break;
1449 case 6:
1450 right_val = std::get<6>(right.value.value);
1451 break;
1452 }
1453 switch (op) {
1454 case TOK_OP_PLUS:
1455 return left_val + right_val;
1456 case TOK_OP_MINUS:
1457 return left_val - right_val;
1458 case TOK_OP_MULT:
1459 return left_val * right_val;
1460 case TOK_OP_DIV:
1461 if (!right.is_value_unknown && right_val == 0) {
1462 throw_exception(SUB_SEMANTIC, "Division by zero", line, file_name, is_debug);
1463 }
1464 return left_val / right_val;
1465 case TOK_OP_MODULO:
1466 return std::fmod(left_val, right_val);
1467 case TOK_OP_EQ_EQ:
1468 return static_cast<bool>(left_val == right_val);
1469 case TOK_OP_NOT_EQ_EQ:
1470 return static_cast<bool>(left_val != right_val);
1471 case TOK_OP_GT:
1472 return static_cast<bool>(left_val > right_val);
1473 case TOK_OP_GT_EQ:
1474 return static_cast<bool>(left_val >= right_val);
1475 case TOK_OP_LS:
1476 return static_cast<bool>(left_val < right_val);
1477 case TOK_OP_LS_EQ:
1478 return static_cast<bool>(left_val <= right_val);
1479 case TOK_OP_L_AND:
1480 return static_cast<bool>(left_val && right_val);
1481 case TOK_OP_L_OR:
1482 return static_cast<bool>(left_val || right_val);
1483 default:
1484 std::stringstream ss;
1485 ss << "Unsupported binary operator: \033[0m'" << op << "'";
1487 }
1488}
1489
1490double SemanticAnalyzer::unary_two_variants(Value value, TokenType op, uint32_t line) {
1491 double val = 0;
1492 switch (value.value.value.index()) {
1493 case AST::TYPE_BOOL:
1494 val = std::get<0>(value.value.value);
1495 break;
1496 case AST::TYPE_CHAR:
1497 val = std::get<1>(value.value.value);
1498 break;
1499 case AST::TYPE_SHORT:
1500 val = std::get<2>(value.value.value);
1501 break;
1502 case AST::TYPE_INT:
1503 val = std::get<3>(value.value.value);
1504 break;
1505 case AST::TYPE_LONG:
1506 val = std::get<4>(value.value.value);
1507 break;
1508 case AST::TYPE_FLOAT:
1509 val = std::get<5>(value.value.value);
1510 break;
1511 case AST::TYPE_DOUBLE:
1512 val = std::get<6>(value.value.value);
1513 break;
1514 }
1515 switch (op) {
1516 case TOK_OP_MINUS:
1517 if (value.type.is_ptr) {
1518 throw_exception(SUB_SEMANTIC, "The unary operator \033[0m'-'\033[31m cannot be used for a pointer", line, file_name, is_debug);
1519 }
1520 return -val;
1521 case TOK_OP_L_NOT:
1522 if (value.type.is_ptr) {
1523 throw_exception(SUB_SEMANTIC, "The unary operator \033[0m'!'\033[31m cannot be used for a pointer", line, file_name, is_debug);
1524 }
1525 return static_cast<bool>(!val);
1526 case TOK_OP_MULT:
1527 return val;
1528 case TOK_OP_REF:
1529 return val;
1530 default:
1531 std::stringstream ss;
1532 ss << "Unsupported unary operator: \033[0m'" << op << "'";
1534 }
1535}
1536
1537std::string SemanticAnalyzer::get_mangled_name(std::string base_name) {
1538 std::string res;
1539 auto path = current_path;
1540 while (!path.empty()) {
1541 PathPart part = path.top();
1542 if (part.object == PathPart::OBJ_MODULE) {
1543 res = part.name + "-" + res;
1544 }
1545 else {
1546 res = part.name + "#" + res;
1547 }
1548 path.pop();
1549 }
1550 return res + base_name;
1551}
1552
1553std::vector<SemanticAnalyzer::PathPart> SemanticAnalyzer::get_resolved_name(std::string mangled_name) {
1554 std::vector<PathPart> res;
1555 std::string name;
1556 for (const char c : mangled_name) {
1557 if (c == '-') {
1558 res.push_back({name, PathPart::OBJ_MODULE});
1559 name = "";
1560 }
1561 else if (c == '#') {
1562 res.push_back({name, PathPart::OBJ_CLASS});
1563 name = "";
1564 }
1565 else {
1566 name += c;
1567 }
1568 }
1569 res.push_back({name, PathPart::OBJ_MODULE});
1570 return res;
1571}
Binary expression container.
Definition ast.hpp:219
ExprPtr right_expr
Definition ast.hpp:223
ExprPtr left_expr
Definition ast.hpp:222
Statement of break.
Definition ast.hpp:401
Chain of objects expression container.
Definition ast.hpp:273
std::vector< ExprPtr > chain
Definition ast.hpp:275
Statement of break.
Definition ast.hpp:410
Statement of do-while cycle.
Definition ast.hpp:375
std::vector< StmtPtr > block
Definition ast.hpp:378
Base class of expression.
Definition ast.hpp:117
uint32_t line
Definition ast.hpp:119
Statement of extern calls.
Definition ast.hpp:444
std::vector< StmtPtr > block
Definition ast.hpp:447
std::string lang_name_lit
Definition ast.hpp:446
Statement of for cycle.
Definition ast.hpp:387
StmtPtr indexator
Definition ast.hpp:389
StmtPtr iteration
Definition ast.hpp:391
ExprPtr cond
Definition ast.hpp:390
std::vector< StmtPtr > block
Definition ast.hpp:392
Function calling expression container.
Definition ast.hpp:261
std::string name
Definition ast.hpp:263
std::vector< ExprPtr > args
Definition ast.hpp:264
Statement of functions calling.
Definition ast.hpp:328
std::vector< ExprPtr > args
Definition ast.hpp:331
std::string name
Definition ast.hpp:330
Statement of functions declaration.
Definition ast.hpp:313
std::vector< StmtPtr > block
Definition ast.hpp:319
std::vector< Argument > args
Definition ast.hpp:317
AccessModifier access
Definition ast.hpp:315
std::string name
Definition ast.hpp:316
Statement of control flow operator.
Definition ast.hpp:351
ExprPtr cond
Definition ast.hpp:353
std::vector< StmtPtr > else_block
Definition ast.hpp:355
std::vector< StmtPtr > then_block
Definition ast.hpp:354
Base class of literal.
Definition ast.hpp:133
Type type
Definition ast.hpp:135
Value value
Definition ast.hpp:136
Statement of module definition.
Definition ast.hpp:419
AccessModifier access
Definition ast.hpp:421
std::string name
Definition ast.hpp:423
std::vector< StmtPtr > block
Definition ast.hpp:424
Statement of 'return'.
Definition ast.hpp:340
ExprPtr expr
Definition ast.hpp:342
Base class of statement.
Definition ast.hpp:106
uint32_t line
Definition ast.hpp:108
Unary expression container.
Definition ast.hpp:234
ExprPtr expr
Definition ast.hpp:237
Statement of import the module.
Definition ast.hpp:433
std::vector< std::string > path
Definition ast.hpp:435
Statement of assignment of variable.
Definition ast.hpp:300
std::string name
Definition ast.hpp:302
ExprPtr expr
Definition ast.hpp:303
Statement of variable declaration.
Definition ast.hpp:286
ExprPtr expr
Definition ast.hpp:290
std::string name
Definition ast.hpp:291
AccessModifier access
Definition ast.hpp:288
Variable expression container.
Definition ast.hpp:248
std::string name
Definition ast.hpp:250
Statement of while cycle.
Definition ast.hpp:363
std::vector< StmtPtr > block
Definition ast.hpp:366
Lexer class.
Definition lexer.hpp:15
std::vector< Token > tokenize()
Method for tokenizing source code.
Definition lexer.cpp:10
Parser class.
Definition parser.hpp:14
std::vector< AST::StmtPtr > parse()
Method for parsing tokens into AST tree.
Definition parser.cpp:10
Value * get_function_return_value_from_do_while_cycle(AST::DoWhileCycleStmt &dwcs)
Method for evaluating and returning function returned value from do-while cycle.
std::string get_mangled_name(std::string base_name)
Method for getting mangled name.
Value implicitly_cast(Value val, AST::Type type, uint32_t line)
Method for getting implicitly casted value between two values.
void analyze_break_stmt(AST::BreakStmt &bs)
Method for analyze break statement.
Definition semantic.cpp:505
void analyze_return_stmt(AST::ReturnStmt &rs)
Method for analyze 'return' statement.
Definition semantic.cpp:411
SemanticAnalyzer(std::vector< AST::StmtPtr > &s, std::string lp, std::string fn, bool id)
Definition semantic.hpp:102
Value analyze_unary_expr(AST::UnaryExpr &ue)
Method for analyze unary expression.
Definition semantic.cpp:793
std::map< AST::TypeValue, std::vector< AST::TypeValue > > implicitly_cast_allowed_types
Definition semantic.hpp:31
void analyze()
Method for analyze all statements.
Definition semantic.cpp:15
Value * get_function_return_value_from_for_cycle(AST::ForCycleStmt &fcs)
Method for evaluating and returning function returned value from for cycle.
AST::Value get_default_val_by_type(AST::Type type, uint32_t line)
Method for getting default value by type.
std::map< std::string, ModuleInfo * > modules
Definition semantic.hpp:82
std::vector< AST::StmtPtr > & stmts
Definition semantic.hpp:19
Value analyze_obj_chain_expr(AST::ChainObjects &co)
Method for analyze chain of objects expression.
Definition semantic.cpp:970
void analyze_if_else_stmt(AST::IfElseStmt &ies)
Method for analyze control flow operators.
Definition semantic.cpp:430
void analyze_func_decl_stmt(AST::FuncDeclStmt &fds)
Method for analyze function declaration.
Definition semantic.cpp:241
void analyze_var_decl_stmt(AST::VarDeclStmt &vds, bool is_func_arg=false)
Method for analyze variable declaration.
Definition semantic.cpp:87
std::vector< std::string > allowed_langs_for_extern
Definition semantic.hpp:67
void analyze_var_asgn_stmt(AST::VarAsgnStmt &vas)
Method for analyze variable assignment.
Definition semantic.cpp:170
unsigned depth_of_loops
Definition semantic.hpp:66
void analyze_use_module_stmt(AST::UseModuleStmt &ums)
Method for analyze import the module.
Definition semantic.cpp:555
std::unique_ptr< Value > get_variable_value(std::string name)
Method for getting value of variable from view scope of variables table.
std::map< std::string, ModuleInfo * > get_modules() const
Method for getting modules from semantic.
Definition semantic.hpp:120
AST::Type get_common_type(AST::Type left, AST::Type right, uint32_t line)
Method for getting common type between two types.
void analyze_extern_stmt(AST::ExternStmt &es)
Method for analyze extern calls.
Definition semantic.cpp:670
Value analyze_func_call_expr(AST::FuncCallExpr &fce)
Method for analyze function calling expression.
Definition semantic.cpp:866
std::vector< std::shared_ptr< FunctionInfo > > get_function_candidates(std::string name)
Method for getting function candidates from functions table.
std::map< std::string, std::vector< std::shared_ptr< FunctionInfo > > > functions
Definition semantic.hpp:64
std::string file_name
Definition semantic.hpp:17
Value analyze_expr(AST::Expr &expr)
Method for analyze expression.
Definition semantic.cpp:681
bool has_common_type(AST::Type left, AST::Type right)
Method for determining whether two types have a common type.
void analyze_do_while_cycle_stmt(AST::DoWhileCycleStmt &dwcs)
Method for analyze do-while cycle.
Definition semantic.cpp:467
void analyze_while_cycle_stmt(AST::WhileCycleStmt &wcs)
Method for analyze while cycle.
Definition semantic.cpp:451
double binary_two_variants(Value left, Value right, TokenType op, uint32_t line)
Method for evaluating binary operations on two values from std::variant.
std::string libs_path
Definition semantic.hpp:16
Value get_function_return_value(std::shared_ptr< FunctionInfo > func, AST::FuncCallExpr &fce)
Method for evaluating and returning function returned value.
std::stack< PathPart > current_path
Definition semantic.hpp:99
void analyze_continue_stmt(AST::ContinueStmt &cs)
Method for analyze continue statement.
Definition semantic.cpp:511
void analyze_stmt(AST::Stmt &stmt)
Method for analyze one statement.
Definition semantic.cpp:21
Value analyze_literal_expr(AST::Literal &lit)
Method for analyze literal.
Definition semantic.cpp:705
std::vector< std::string > names_of_imported_modules
Definition semantic.hpp:83
void analyze_for_cycle_stmt(AST::ForCycleStmt &fcs)
Method for analyze for cycle.
Definition semantic.cpp:483
Value * get_function_return_value_from_while_cycle(AST::WhileCycleStmt &wcs)
Method for evaluating and returning function returned value from while cycle.
Space
Current space (in global, in module or in function).
Definition semantic.hpp:25
void analyze_module_stmt(AST::ModuleStmt &ms)
Method for analyze module definition.
Definition semantic.cpp:517
std::map< std::string, std::vector< std::shared_ptr< FunctionInfo > > > get_functions() const
Method for getting functions from semantic.
Definition semantic.hpp:129
enum SemanticAnalyzer::Space current_space
std::vector< PathPart > get_resolved_name(std::string mangled_name)
Method for getting resolved name by mangled name.
void analyze_func_call_stmt(AST::FuncCallStmt &fcs)
Method for analyze function calling.
Definition semantic.cpp:353
Value analyze_obj_from_chain(Value target, AST::Expr &obj)
Method for analyze object from chain of objects expression.
Definition semantic.cpp:981
std::stack< std::map< std::string, Value > > variables
Definition semantic.hpp:52
Value * get_function_return_value_from_if_else(AST::IfElseStmt &ies)
Method for evaluating and returning function returned value from control flow operators.
double unary_two_variants(Value value, TokenType op, uint32_t line)
Method for evaluating unary operations on two values from std::variant.
Value analyze_binary_expr(AST::BinaryExpr &be)
Method for analyze binary expression.
Definition semantic.cpp:709
Value analyze_var_expr(AST::VarExpr &ve)
Method for analyze variable expression.
Definition semantic.cpp:853
std::stack< AST::Type > functions_ret_types
Definition semantic.hpp:65
void throw_exception(SubsystemType type, std::string msg, uint32_t line, std::string file_name, bool is_debug)
Function for throwing exception.
Definition exception.cpp:30
Header file for defining thrown exceptions by the compiler.
@ SUB_SEMANTIC
Definition exception.hpp:17
Header file for defining the lexer.
@ ACCESS_PUBLIC
Definition ast.hpp:100
@ ACCESS_NONE
Definition ast.hpp:98
std::unique_ptr< Stmt > StmtPtr
Definition ast.hpp:125
@ TYPE_STRING_LIT
Definition ast.hpp:28
@ TYPE_INT
Definition ast.hpp:23
@ TYPE_MODULE
Definition ast.hpp:31
@ TYPE_CHAR
Definition ast.hpp:21
@ TYPE_FLOAT
Definition ast.hpp:25
@ TYPE_BOOL
Definition ast.hpp:20
@ TYPE_LONG
Definition ast.hpp:24
@ TYPE_DOUBLE
Definition ast.hpp:26
@ TYPE_NOTH
Definition ast.hpp:27
@ TYPE_SHORT
Definition ast.hpp:22
Header file for defining parser.
#define VALUE(op, type)
Header file for defining semantic analyzer.
Structure for describing the type.
Definition ast.hpp:37
std::string name
Definition ast.hpp:39
bool is_nullable
Definition ast.hpp:42
bool is_ptr
Definition ast.hpp:41
bool is_const
Definition ast.hpp:40
TypeValue type
Definition ast.hpp:38
std::string to_str()
Method for convert type to string.
Definition ast.hpp:61
Structure for describing the value.
Definition ast.hpp:71
std::variant< bool, char8_t, int16_t, int32_t, int64_t, float_t, double_t, std::string > value
Definition ast.hpp:72
Structure of information about module.
Definition semantic.hpp:77
std::map< std::string, std::pair< AST::AccessModifier, ModuleInfo * > > modules
Definition semantic.hpp:78
std::map< std::string, std::pair< AST::AccessModifier, std::string > > functions
Definition semantic.hpp:79
Structure of part of path to object.
Definition semantic.hpp:88
enum SemanticAnalyzer::PathPart::Object object
Structure of value.
Definition semantic.hpp:43
std::string value
Definition token.hpp:94
TokenType type
Definition token.hpp:93
TokenType
All tokens types.
Definition token.hpp:14
@ TOK_OP_DIV
Definition token.hpp:60
@ TOK_OP_EQ_EQ
Definition token.hpp:65
@ TOK_OP_LS
Definition token.hpp:69
@ TOK_OP_GT_EQ
Definition token.hpp:68
@ TOK_OP_NOT_EQ_EQ
Definition token.hpp:66
@ TOK_OP_L_OR
Definition token.hpp:73
@ TOK_OP_PLUS
Definition token.hpp:52
@ TOK_OP_L_NOT
Definition token.hpp:71
@ TOK_OP_L_AND
Definition token.hpp:72
@ TOK_OP_MODULO
Definition token.hpp:62
@ TOK_OP_MULT
Definition token.hpp:58
@ TOK_OP_REF
Definition token.hpp:74
@ TOK_OP_GT
Definition token.hpp:67
@ TOK_OP_MINUS
Definition token.hpp:55
@ TOK_OP_LS_EQ
Definition token.hpp:70