use super::call_graph::CallGraph;
use crate::Compiler::AST::{QuickFunction, QuickFuncStatement, Expression, Value};
use std::collections::HashSet;
pub struct FunctionCallCollector<'a> {
call_graph: &'a mut CallGraph,
current_function: String,
local_scope_stack: Vec<HashSet<String>>,
}
impl<'a> FunctionCallCollector<'a> {
pub fn new(call_graph: &'a mut CallGraph) -> Self {
FunctionCallCollector {
call_graph,
current_function: String::new(),
local_scope_stack: Vec::new(),
}
}
pub fn analyze_function(&mut self, func: &QuickFunction) {
self.current_function = func.name.clone();
self.call_graph.add_function(func.name.clone());
let function_scope: HashSet<String> = func.parameters
.iter()
.map(|p| p.name.clone())
.collect();
self.local_scope_stack.push(function_scope);
for statement in &func.body {
self.analyze_statement(statement);
}
self.local_scope_stack.pop();
}
fn is_in_local_scope(&self, name: &str) -> bool {
self.local_scope_stack.iter().any(|scope| scope.contains(name))
}
fn add_to_current_scope(&mut self, name: String) {
if let Some(scope) = self.local_scope_stack.last_mut() {
scope.insert(name);
}
}
fn analyze_statement(&mut self, statement: &QuickFuncStatement) {
match statement {
QuickFuncStatement::Return { value, .. } => {
self.analyze_expression(value);
}
QuickFuncStatement::Assignment { variable, value, .. } => {
self.add_to_current_scope(variable.clone());
self.analyze_expression(value);
}
QuickFuncStatement::ArithmeticAssignment { value, .. } => {
self.analyze_expression(value);
}
QuickFuncStatement::If { condition, then_branch, else_branch, .. } => {
self.analyze_expression(condition);
for stmt in then_branch {
self.analyze_statement(stmt);
}
if let Some(else_stmts) = else_branch {
for stmt in else_stmts {
self.analyze_statement(stmt);
}
}
}
QuickFuncStatement::Switch { expression, cases, default_case, .. } => {
self.analyze_expression(expression);
for case in cases {
for stmt in &case.statements {
self.analyze_statement(stmt);
}
}
if let Some(default) = default_case {
for stmt in &default.statements {
self.analyze_statement(stmt);
}
}
}
QuickFuncStatement::Log { value, .. } => {
self.analyze_expression(value);
}
QuickFuncStatement::ExpressionStatement { expression, .. } => {
self.analyze_expression(expression);
}
QuickFuncStatement::ObjectCreation { variable, object, .. } => {
self.add_to_current_scope(variable.clone());
self.analyze_value(object);
}
QuickFuncStatement::VariableDeclaration { variable_name, value, .. } => {
self.add_to_current_scope(variable_name.clone());
self.analyze_expression(value);
}
}
}
fn analyze_expression(&mut self, expr: &Expression) {
match expr {
Expression::QuickFuncCall { name, arguments, .. } => {
if self.is_in_local_scope(name) {
for arg in arguments {
self.analyze_expression(arg);
}
return;
}
self.call_graph.add_edge(
self.current_function.clone(),
name.clone(),
expr.position(),
);
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::ArithmeticOp { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
}
Expression::BitwiseOp { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
}
Expression::ComparisonOp { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
}
Expression::LogicalOp { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
}
Expression::UnaryOp { operand, .. } => {
self.analyze_expression(operand);
}
Expression::Conditional { condition, true_value, false_value, .. } => {
self.analyze_expression(condition);
self.analyze_expression(true_value);
self.analyze_expression(false_value);
}
Expression::Parenthesized { expression, .. } => {
self.analyze_expression(expression);
}
Expression::PropertyAccess { object, .. } => {
self.analyze_expression(object);
}
Expression::IndexAccess { object, index, .. } => {
self.analyze_expression(object);
self.analyze_expression(index);
}
Expression::InstanceMethodCall { instance, arguments, .. } => {
self.analyze_expression(instance);
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::StaticMethodCall { arguments, .. } => {
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::DixFunctionCall { arguments, .. } => {
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::Value { value, .. } => {
self.analyze_value(value);
}
Expression::TypeCast { expression, .. } => {
self.analyze_expression(expression);
}
Expression::FunctionCall { arguments, .. } => {
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::ImportedFunctionCall { arguments, .. } => {
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::QualifiedIdentifier { arguments, .. } => {
if let Some(args) = arguments {
for arg in args {
self.analyze_expression(arg);
}
}
}
Expression::BuiltinFunction { target, arguments, .. } => {
self.analyze_expression(target);
if let Some(args) = arguments {
for arg in args {
self.analyze_expression(arg);
}
}
}
Expression::StaticFunction { arguments, .. } => {
for arg in arguments {
self.analyze_expression(arg);
}
}
Expression::Identifier { .. }
| Expression::EnumAccess { .. }
| Expression::ConfigAccess { .. }
| Expression::ObjectAccess { .. } => {
}
}
}
fn analyze_value(&mut self, value: &Value) {
match value {
Value::Lambda { parameters, body, .. } => {
let lambda_scope: HashSet<String> = parameters.iter().cloned().collect();
self.local_scope_stack.push(lambda_scope);
self.analyze_expression(body);
self.local_scope_stack.pop();
}
Value::Array { values, .. } => {
for elem in values {
self.analyze_value(elem);
}
}
Value::NestedArray { values, .. } => {
for elem in values {
self.analyze_value(elem);
}
}
Value::Object { properties, .. } => {
for prop in properties {
self.analyze_value(&prop.value);
}
}
Value::PrefixedConstructor { arguments, .. } => {
for arg in arguments {
self.analyze_value(arg);
}
}
Value::InterpolatedString { expressions, .. } => {
for expr in expressions {
self.analyze_expression(expr);
}
}
Value::QuickFuncCall { function_name, arguments, .. } => {
if self.is_in_local_scope(function_name) {
for arg in arguments {
self.analyze_expression(arg);
}
return;
}
self.call_graph.add_edge(
self.current_function.clone(),
function_name.clone(),
value.position(),
);
for arg in arguments {
self.analyze_expression(arg);
}
}
Value::Expression { expr, .. } => {
self.analyze_expression(expr);
}
Value::Range { start, end, .. } => {
self.analyze_value(start);
self.analyze_value(end);
}
Value::Integer { .. }
| Value::Long { .. }
| Value::Float { .. }
| Value::Double { .. }
| Value::ScientificNotation { .. }
| Value::HexColor { .. }
| Value::String { .. }
| Value::Boolean { .. }
| Value::Date { .. }
| Value::Timestamp { .. }
| Value::Null { .. }
| Value::EnumValue { .. }
| Value::Identifier { .. }
| Value::ParseError { .. }
| Value::Error { .. }
| Value::Unknown { .. } => {
}
}
}
}