diff --git a/src/extern.rs b/src/extern.rs new file mode 100644 index 0000000..e9d23a9 --- /dev/null +++ b/src/extern.rs @@ -0,0 +1,71 @@ +use crate::{Formatter, Function}; +use std::fmt::Write; +#[derive(Debug, Clone)] +pub enum ExternSymbol { + Function(Function), +} + +/// Defines an extern block. +#[derive(Debug, Clone)] +pub struct Extern { + abi: Option, + symbols: Vec +} + + +impl Extern { + + /// Return a new extern block. + pub fn new() -> Self { + Extern { + abi: None, + symbols: Vec::new() + } + } + + /// Set the ABI for the extern block. + pub fn abi(&mut self, abi: &str) -> &mut Self { + self.abi = Some(abi.to_string()); + self + } + + /// Return a new extern function with the given name. + pub fn function(&mut self, name: &str) -> &mut Function { + let function = Function::new(name); + self.symbols.push(ExternSymbol::Function(function)); + match self.symbols.last_mut().unwrap() { + ExternSymbol::Function(function) => function.no_body(), + } + } + + + /// Push a function to the extern block. + pub fn push_function(&mut self, function: Function) -> &mut Self { + assert!(function.body.is_none(), "Extern functions cannot have bodies"); + self.symbols.push(ExternSymbol::Function(function)); + self + } + + + /// Formats the extern block using the given formatter. + pub fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + if let Some(abi) = &self.abi { + writeln!(f, "extern \"{}\"", abi)?; + } else { + writeln!(f, "extern ")?; + } + + f.block(|x| { + let mut res = Ok(()); + for symbol in &self.symbols { + match symbol { + ExternSymbol::Function(function) => { + res = function.fmt(true, x) + } + } + } + + res + }) + } +} \ No newline at end of file diff --git a/src/function.rs b/src/function.rs index 827ec6c..9c0b7f1 100644 --- a/src/function.rs +++ b/src/function.rs @@ -148,6 +148,12 @@ impl Function { self } + /// Remove the function body. + pub fn no_body(&mut self) -> &mut Self { + self.body = None; + self + } + /// Add a `where` bound to the function. pub fn bound(&mut self, name: &str, ty: T) -> &mut Self where diff --git a/src/item.rs b/src/item.rs index 5f6fb62..87617e4 100644 --- a/src/item.rs +++ b/src/item.rs @@ -2,6 +2,7 @@ use crate::function::Function; use crate::module::Module; use crate::r#enum::Enum; +use crate::r#extern::Extern; use crate::r#impl::Impl; use crate::r#struct::Struct; use crate::r#trait::Trait; @@ -11,6 +12,7 @@ pub enum Item { Module(Module), Struct(Struct), Function(Function), + Extern(Extern), Trait(Trait), Enum(Enum), Impl(Impl), diff --git a/src/lib.rs b/src/lib.rs index 70b8675..83e254d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ mod r#impl; mod r#struct; mod r#trait; mod r#type; - +mod r#extern; pub use associated_type::*; pub use block::*; diff --git a/src/scope.rs b/src/scope.rs index 1312139..ff10d98 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -10,6 +10,7 @@ use crate::item::Item; use crate::module::Module; use crate::r#enum::Enum; +use crate::r#extern::Extern; use crate::r#impl::Impl; use crate::r#struct::Struct; use crate::r#trait::Trait; @@ -163,6 +164,22 @@ impl Scope { self } + /// Push a new extern definition, returning a mutable reference to it. + pub fn new_extern(&mut self) -> &mut Extern { + self.items.push(Item::Extern(Extern::new())); + + match *self.items.last_mut().unwrap() { + Item::Extern(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push an extern definition + pub fn push_extern(&mut self, item: Extern) -> &mut Self { + self.items.push(Item::Extern(item)); + self + } + /// Push a new trait definition, returning a mutable reference to it. pub fn new_trait(&mut self, name: &str) -> &mut Trait { self.push_trait(Trait::new(name)); @@ -253,6 +270,7 @@ impl Scope { Item::Trait(ref v) => v.fmt(fmt)?, Item::Enum(ref v) => v.fmt(fmt)?, Item::Impl(ref v) => v.fmt(fmt)?, + Item::Extern(ref v) => v.fmt(fmt)?, Item::Raw(ref v) => { write!(fmt, "{}\n", v)?; }