use rune::{compile, macros, parse, Any};

#[derive(Any, Debug, Clone)]
pub(crate) struct Here {
    #[rune(get, set)]
    pub filename: String,
    #[rune(get, set)]
    pub line: u64,
}

impl Here {
    /// Construct a new Here, use the `here!()` macro to build.
    #[rune::function(path = Self::new)]
    pub(crate) fn new(filename: String, line: u64) -> Here {
        Here { filename, line }
    }
}

impl std::fmt::Display for Here {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.filename, self.line)
    }
}

/// Implementation of the `here!` macro.
#[rune::macro_]
pub fn here(
    cx: &mut macros::MacroContext<'_, '_, '_>,
    stream: &macros::TokenStream,
) -> compile::Result<macros::TokenStream> {
    let mut parser = parse::Parser::from_token_stream(stream, cx.input_span());
    parser.eof()?;

    let output = macros::quote!(Here::new(file!(), line!()));

    Ok(output.into_token_stream(cx)?)
}
