Skip to main content

seqc/ffi/
bindings.rs

1//! Resolved FFI bindings ready for codegen: the `FfiBindings` registry plus
2//! the per-function info generated from a manifest.
3
4use std::collections::HashMap;
5
6use crate::types::Effect;
7
8use super::manifest::{FfiArg, FfiManifest, FfiReturn};
9
10// ============================================================================
11// FFI Code Generation
12// ============================================================================
13
14/// Resolved FFI bindings ready for code generation
15#[derive(Debug, Clone)]
16pub struct FfiBindings {
17    /// Map from Seq word name to C function info
18    pub functions: HashMap<String, FfiFunctionInfo>,
19    /// Linker flags to add
20    pub linker_flags: Vec<String>,
21}
22
23/// Information about an FFI function for code generation
24#[derive(Debug, Clone)]
25pub struct FfiFunctionInfo {
26    /// C function name
27    pub c_name: String,
28    /// Seq word name
29    pub seq_name: String,
30    /// Stack effect for type checking
31    pub effect: Effect,
32    /// Arguments
33    pub args: Vec<FfiArg>,
34    /// Return specification
35    pub return_spec: Option<FfiReturn>,
36}
37
38impl FfiBindings {
39    /// Create empty bindings
40    pub fn new() -> Self {
41        FfiBindings {
42            functions: HashMap::new(),
43            linker_flags: Vec::new(),
44        }
45    }
46
47    /// Add bindings from a manifest
48    pub fn add_manifest(&mut self, manifest: &FfiManifest) -> Result<(), String> {
49        // Add linker flags
50        self.linker_flags.extend(manifest.linker_flags());
51
52        // Add function bindings
53        for func in manifest.functions() {
54            let effect = func.effect()?;
55            let info = FfiFunctionInfo {
56                c_name: func.c_name.clone(),
57                seq_name: func.seq_name.clone(),
58                effect,
59                args: func.args.clone(),
60                return_spec: func.return_spec.clone(),
61            };
62
63            if self.functions.contains_key(&func.seq_name) {
64                return Err(format!(
65                    "FFI function '{}' is already defined",
66                    func.seq_name
67                ));
68            }
69
70            self.functions.insert(func.seq_name.clone(), info);
71        }
72
73        Ok(())
74    }
75
76    /// Check if a word is an FFI function
77    pub fn is_ffi_function(&self, name: &str) -> bool {
78        self.functions.contains_key(name)
79    }
80
81    /// Get all FFI function names for AST validation
82    pub fn function_names(&self) -> Vec<&str> {
83        self.functions.keys().map(|s| s.as_str()).collect()
84    }
85}
86
87impl Default for FfiBindings {
88    fn default() -> Self {
89        Self::new()
90    }
91}