use std::sync::Arc;
use arcstr::{literal, ArcStr};
use imbl::Vector;
use rustc_hash::{FxHashMap, FxHashSet};
use serde::{Deserialize, Serialize};
use crate::{model::{DataRef, Graph, NodeRef, SId, SPath, StofData}, runtime::{instruction::{Instruction, Instructions}, Type, Val}};
pub const MAIN_FUNC_ATTR: ArcStr = literal!("main");
pub const TEST_FUNC_ATTR: ArcStr = literal!("test");
pub const ASYNC_FUNC_ATTR: ArcStr = literal!("async");
pub const UNSELF_FUNC_ATTR: ArcStr = literal!("unself");
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Func {
pub params: Vector<Param>,
pub return_type: Type,
pub attributes: FxHashMap<String, Val>,
pub instructions: Vector<Arc<dyn Instruction>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FuncDoc {
pub func: DataRef,
pub docs: String,
}
impl FuncDoc {
pub fn docs(graph: &Graph, node: &NodeRef) -> FxHashMap<DataRef, String> {
let mut docs = FxHashMap::default();
if let Some(node) = node.node(graph) {
for (_, dref) in &node.data {
if let Some(doc) = graph.get_stof_data::<Self>(dref) {
docs.insert(doc.func.clone(), doc.docs.clone());
}
}
}
docs
}
}
#[typetag::serde(name = "Fn")]
impl StofData for Func {
fn core_data(&self) -> bool {
return true;
}
}
#[typetag::serde(name = "FnDoc")]
impl StofData for FuncDoc {
fn core_data(&self) -> bool {
return true;
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Param {
pub name: SId,
pub param_type: Type,
pub default: Option<Arc<dyn Instruction>>,
}
impl Func {
pub fn new(params: Vector<Param>, return_type: Type, instructions: Instructions, attrs: Option<FxHashMap<String, Val>>) -> Self {
let mut attributes = FxHashMap::default();
if let Some(attr) = attrs {
attributes = attr;
}
Self {
params,
return_type,
instructions: instructions.instructions,
attributes,
}
}
pub fn func_from_path(graph: &Graph, path: &str, start: Option<NodeRef>) -> Option<DataRef> {
let mut spath = SPath::from(path);
if spath.path.is_empty() { return None; }
let func_name = spath.path.pop().unwrap();
if let Some(node) = SPath::node(&graph, spath, start) {
return Self::func(graph, &node, &func_name);
}
None
}
#[inline]
pub fn func(graph: &Graph, node: &NodeRef, func_name: &SId) -> Option<DataRef> {
if let Some(node) = node.node(graph) {
if let Some(dref) = node.data.get(func_name.as_ref()) {
if dref.type_of::<Self>(&graph) {
return Some(dref.clone());
}
}
}
None
}
pub fn functions(graph: &Graph, node: &NodeRef, attrs: &Option<FxHashSet<String>>, recursive: bool) -> FxHashSet<DataRef> {
let mut funcs = FxHashSet::default();
if let Some(node) = node.node(&graph) {
for (_name, dref) in &node.data {
if let Some(func) = graph.get_stof_data::<Self>(dref) {
if let Some(attrs) = &attrs {
for att in attrs {
if func.attributes.contains_key(att) {
funcs.insert(dref.clone());
break;
}
}
} else {
funcs.insert(dref.clone());
}
}
}
if recursive {
for child in &node.children {
for dref in Self::functions(graph, child, attrs, recursive) {
funcs.insert(dref);
}
}
}
}
funcs
}
pub fn all_functions(graph: &Graph, attrs: &Option<FxHashSet<String>>) -> FxHashSet<DataRef> {
let mut funcs = FxHashSet::default();
for root in &graph.roots {
for dref in Self::functions(graph, root, attrs, true) {
funcs.insert(dref);
}
}
funcs
}
pub fn main_functions(graph: &Graph) -> FxHashSet<DataRef> {
let mut set = FxHashSet::default();
set.insert(MAIN_FUNC_ATTR.to_string());
Self::all_functions(graph, &Some(set))
}
pub fn test_functions(graph: &Graph) -> FxHashSet<DataRef> {
let mut set = FxHashSet::default();
set.insert(TEST_FUNC_ATTR.to_string());
Self::all_functions(graph, &Some(set))
}
}