Initial SFERA platform baseline

This commit is contained in:
2026-05-16 19:03:49 +03:00
commit 3b845c8fce
282 changed files with 55045 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
use crate::keywords::{is_function_start, is_procedure_start};
use crate::models::{ParsedCall, SourceRange};
use crate::parser::{extract_name_from_header, routine_ended};
pub fn extract_calls(source: &str) -> Vec<ParsedCall> {
let mut result = Vec::new();
let mut current_routine: Option<String> = None;
for (index, line) in source.lines().enumerate() {
let line_no = index + 1;
let trimmed = strip_inline_comment(line).trim();
if is_procedure_start(trimmed) || is_function_start(trimmed) {
current_routine = Some(extract_name_from_header(trimmed));
continue;
}
if routine_ended(trimmed) {
current_routine = None;
continue;
}
let Some(caller) = current_routine.as_ref() else {
continue;
};
if let Some(callee) = simple_call_name(trimmed).or_else(|| condition_call_name(trimmed)) {
result.push(ParsedCall {
caller: caller.clone(),
callee,
source_range: SourceRange {
line_start: line_no,
line_end: line_no,
column_start: 1,
column_end: line.len() + 1,
},
});
}
}
result
}
fn simple_call_name(line: &str) -> Option<String> {
if !line.ends_with(';') || !line.contains('(') || !line.contains(')') || line.contains('.') {
return None;
}
let call_expr = line.split('=').next_back().unwrap_or(line).trim();
let name = call_expr.split('(').next()?.trim();
if name.is_empty() {
return None;
}
Some(name.to_string())
}
fn condition_call_name(line: &str) -> Option<String> {
let lowered = line.to_lowercase();
let is_condition = (lowered.starts_with("если ") && lowered.contains(" тогда"))
|| (lowered.starts_with("if ") && lowered.contains(" then"));
if !is_condition || line.contains('.') {
return None;
}
let before_then = if let Some(index) = lowered.find(" тогда") {
&line[..index]
} else if let Some(index) = lowered.find(" then") {
&line[..index]
} else {
line
};
let name_part = before_then.split('(').next()?.split_whitespace().last()?;
if name_part.eq_ignore_ascii_case("Если") || name_part.eq_ignore_ascii_case("If") {
return None;
}
Some(name_part.to_string())
}
fn strip_inline_comment(line: &str) -> &str {
line.split("//").next().unwrap_or(line)
}