dfir_datalog/
lib.rs

1use dfir_datalog_core::diagnostic::Diagnostic;
2use dfir_datalog_core::{dfir_graph_to_program, gen_dfir_graph};
3use proc_macro2::Span;
4use quote::{ToTokens, quote};
5
6/// Generate a graph instance from [Datalog](https://en.wikipedia.org/wiki/Datalog) code.
7///
8/// This uses a variant of Datalog that is similar to [Dedalus](https://www2.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.pdf).
9///
10/// For examples, see [the datalog tests in the repo](https://github.com/hydro-project/hydro/blob/main/dfir_rs/tests/datalog_frontend.rs).
11// TODO(mingwei): rustdoc examples inline.
12#[proc_macro]
13pub fn datalog(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
14    let item = proc_macro2::TokenStream::from(item);
15    let literal: proc_macro2::Literal = syn::parse_quote! {
16        #item
17    };
18
19    const DFIR_CRATE: &str = "dfir_rs";
20
21    let dfir_crate = proc_macro_crate::crate_name(DFIR_CRATE)
22        .unwrap_or_else(|_| panic!("`{}` should be present in `Cargo.toml`", DFIR_CRATE));
23    let root = match dfir_crate {
24        proc_macro_crate::FoundCrate::Itself => {
25            let ident = syn::Ident::new(DFIR_CRATE, Span::call_site());
26            quote! { #ident }
27        }
28        proc_macro_crate::FoundCrate::Name(name) => {
29            let ident = syn::Ident::new(&name, Span::call_site());
30            quote! { #ident }
31        }
32    };
33
34    match gen_dfir_graph(literal) {
35        Ok(graph) => {
36            let program = dfir_graph_to_program(graph, root);
37            program.to_token_stream().into()
38        }
39        Err(diagnostics) => {
40            let diagnostic_tokens = Diagnostic::try_emit_all(diagnostics.iter())
41                .err()
42                .unwrap_or_default();
43            proc_macro::TokenStream::from(quote! {
44                {
45                    #diagnostic_tokens
46                    dfir_rs::scheduled::graph::Dfir::new()
47                }
48            })
49        }
50    }
51}