41 {
42 if (program == nullptr) {
43 reportError("Program AST is null", Range{});
44 return false;
45 }
46
47 current_pending_gotos.clear();
48 current_labels_seen.clear();
49
50
51 for (const auto& stmt : program->statements) {
53 if (global_labels.contains(label_def->name.value)) {
54 reportError(std::format("Duplicate label '{}' in global scope",
55 label_def->name.value),
56 label_def->range);
57 }
58 global_labels.insert(label_def->name.value);
59 }
60 }
61
62
63 for (const auto& stmt : program->statements) {
65 if (function_signatures.contains(func_def->name.value)) {
66 for (const auto& existing_sig :
67 function_signatures.at(func_def->name.value)) {
68 if (existing_sig.params.size() == func_def->params.size()) {
69 bool same = true;
70 for (size_t i = 0; i < func_def->params.size(); ++i) {
71 if (existing_sig.params[i].type !=
72 func_def->params[i].type) {
73 same = false;
74 break;
75 }
76 }
77 if (same) {
78 reportError(
79 std::format(
80 "Duplicate function signature for '{}'",
81 func_def->name.value),
82 func_def->range);
83 }
84 }
85 }
86 }
87
88 FunctionSignature sig;
89 sig.name = func_def->name.value;
90 for (const auto& p : func_def->params) {
91 sig.params.push_back({p.name.value, p.type});
92 }
93 sig.range = func_def->range;
94
95 sig.has_return = false;
96 std::optional<bool> returns_value_opt;
97
98 std::function<void(Stmt*)> find_returns = [&](Stmt* s) {
99 if (!s) {
100 return;
101 }
102
104 sig.has_return = true;
105 bool current_has_value = (ret->value != nullptr);
106 if (!returns_value_opt.has_value()) {
107 returns_value_opt = current_has_value;
108 } else if (returns_value_opt.value() != current_has_value) {
109 reportError(
110 std::format(
111 "Function '{}' has inconsistent return "
112 "statements (some with values, some without).",
113 func_def->name.value),
114 ret->range);
115 }
117 for (const auto& inner_s : block->statements) {
118 find_returns(inner_s.get());
119 }
121 find_returns(if_s->then_branch.get());
122 if (if_s->else_branch) {
123 find_returns(if_s->else_branch.get());
124 }
126 find_returns(while_s->body.get());
127 }
128 };
129 for (const auto& s : func_def->body->statements) {
130 find_returns(s.get());
131 }
132 sig.returns_value = returns_value_opt.value_or(false);
133
134 if (func_def->global_decl) {
135 sig.global_mode = func_def->global_decl->mode;
136 for (const auto& g : func_def->global_decl->globals) {
137 sig.specific_globals.insert(g.value);
138 }
139 }
140
141 std::set<std::string> local_vars;
142 for (const auto& p : func_def->params) {
143 local_vars.insert(p.name.value);
144 }
145
146 std::function<void(Stmt*)> collect_local_defs = [&](Stmt* s) {
147 if (!s) {
148 return;
149 }
151 local_vars.insert(assign->name.value);
153 for (const auto& stmt : block->statements) {
154 collect_local_defs(stmt.get());
155 }
157 collect_local_defs(if_stmt->then_branch.get());
158 if (if_stmt->else_branch) {
159 collect_local_defs(if_stmt->else_branch.get());
160 }
162 collect_local_defs(while_stmt->body.get());
163 }
164 };
165 for (const auto& s : func_def->body->statements) {
166 collect_local_defs(s.get());
167 }
168
169 for (const auto& s : func_def->body->statements) {
170 collectUsedGlobalsInStmt(s.get(), sig.used_globals);
171 }
172
173 for (const auto& local_var : local_vars) {
174 sig.used_globals.erase(local_var);
175 }
176
177 function_signatures[sig.name].push_back(sig);
178 function_defs[sig.name].push_back(func_def);
179
182 func_symbol->signature = &function_signatures[sig.name].back();
183 func_def->symbol = func_symbol;
184 }
185 }
186
187
188 for (const auto& stmt : program->statements) {
189 analyzeStmt(stmt.get());
190
191 validateGlobalDependencies(stmt.get());
192
194 if (current_scope == global_scope.get()) {
195 defined_global_vars.insert(assign->name.value);
196 }
197 }
198 }
199
200
201 std::set<std::string> visited;
202 for (const auto& [func_name, _] : function_call_graph) {
203 std::set<std::string> visiting;
204 std::vector<std::string> cycle_path;
205
206 if (detectCycleInCallGraph(func_name, visiting, visited, cycle_path)) {
207
208 std::string cycle_str;
209 for (size_t i = 0; i < cycle_path.size(); ++i) {
210 cycle_str += cycle_path[i];
211 if (i < cycle_path.size() - 1) {
212 cycle_str += " -> ";
213 }
214 }
215 cycle_str += " -> " + cycle_path[0];
216
217 Range first_range;
218 if (function_signatures.contains(cycle_path[0])) {
219 first_range = function_signatures.at(cycle_path[0])[0].range;
220 }
221
222 reportError(std::format("Recursion is not allowed: {}", cycle_str),
223 first_range);
224
225 for (const auto& fn : cycle_path) {
226 if (function_signatures.contains(fn)) {
227 const auto& sig = function_signatures.at(fn)[0];
228 reportError(
229 std::format(
230 " Function '{}' is part of the recursion cycle",
231 fn),
232 sig.range);
233 }
234 }
235
236 break;
237 }
238 }
239
240
241 for (const auto& [name, symbol] : global_scope->getSymbols()) {
242 if (!symbol->is_used) {
243 if (symbol->name == "RESULT" || symbol->name == "_") {
244 continue;
245 }
246
247
248 if (symbol->definition_range.start.line <= library_line_count) {
249 continue;
250 }
251
252 reportWarning(std::format("Unused symbol '{}'", name),
253 symbol->definition_range);
254 }
255 }
256
257
259 reportError("Final result must be assigned to variable 'RESULT'!",
260 Range{});
261 }
262
264 !result_defined_in_global_scope) {
265 reportError(
266 "'RESULT' must be defined in the global scope in Expr mode.",
267 Range{});
268 }
269
271}
auto get_if(Wrapper *wrapper) -> decltype(std::get_if< T >(&wrapper->value))