use std::marker::PhantomData;
use quote::ToTokens;
use syn::{
parse::{discouraged::Speculative, Parse, ParseStream},
Item, Stmt,
};
pub(crate) struct ScriptlikeRust<'a> {
pub(crate) items: Vec<Item>,
pub(crate) statements: Vec<Stmt>,
pub(crate) phantom: PhantomData<&'a ()>,
}
impl<'a> Parse for ScriptlikeRust<'a> {
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
let mut items = Vec::new();
let mut statements = Vec::new();
while !input.is_empty() {
let cursor_snapshot = input.fork();
match input.parse::<Item>().ok() {
Some(item) => match item {
Item::Macro(mut i) => {
match i
.attrs
.iter()
.position(|attr| attr.path.is_ident("expands_only_to_items"))
{
Some(idx) => {
i.attrs.swap_remove(idx);
items.push(Item::Macro(i));
}
None => statements.push(Stmt::Item(Item::Macro(i))),
}
}
_ => items.push(item),
},
None => {
input.advance_to(&cursor_snapshot);
break;
}
}
}
while !input.is_empty() {
match input.parse::<Stmt>() {
Ok(stmt) => statements.push(stmt),
Err(e) => return Err(e),
}
}
Ok(ScriptlikeRust {
items,
statements,
phantom: PhantomData,
})
}
}
impl<'a> ScriptlikeRust<'a> {
pub(crate) fn write_as_main_rs<W>(&self, dest: &mut W) -> std::io::Result<()>
where
W: std::io::Write,
{
for item in self.items.iter() {
match item {
Item::Const(_i) => writeln!(dest, "/* Item::Const */"),
Item::Enum(_i) => writeln!(dest, "/* Item::Enum */"),
Item::ExternCrate(_i) => writeln!(dest, "/* Item::ExternCrate */"),
Item::Fn(_i) => writeln!(dest, "/* Item::Fn */"),
Item::ForeignMod(_i) => writeln!(dest, "/* Item::ForeignMod */"),
Item::Impl(_i) => writeln!(dest, "/* Item::Impl */"),
Item::Macro(_i) => writeln!(dest, "/* Item::Macro */"),
Item::Macro2(_i) => writeln!(dest, "/* Item::Macro2 */"),
Item::Mod(_i) => writeln!(dest, "/* Item::Mod */"),
Item::Static(_i) => writeln!(dest, "/* Item::Static */"),
Item::Struct(_i) => writeln!(dest, "/* Item::Struct */"),
Item::Trait(_i) => writeln!(dest, "/* Item::Trait */"),
Item::TraitAlias(_i) => writeln!(dest, "/* Item::TraitAlias */"),
Item::Type(_i) => writeln!(dest, "/* Item::Type */"),
Item::Union(_i) => writeln!(dest, "/* Item::Union */"),
Item::Use(_i) => writeln!(dest, "/* Item::Use */"),
Item::Verbatim(_i) => writeln!(dest, "/* Item::Verbatim */"),
_ => writeln!(dest, "/* unknown item */"),
}?;
writeln!(dest, "{}", item.into_token_stream())?;
}
writeln!(dest, "fn main(){{")?;
for stmt in self.statements.iter() {
writeln!(dest, "{}", stmt.into_token_stream())?;
}
writeln!(dest, "}}")?;
Ok(())
}
}