mycroft_macros_impl/
lib.rs

1//! `mycroft-macros` exports the nightly-only procedural macro interface to the mycroft compiler.
2//! To use it, invoke `mycroft_program! { "MYCROFT CODE HERE" }` in your library.
3extern crate combine;
4extern crate mycroft;
5extern crate proc_macro;
6#[macro_use]
7extern crate proc_macro_hack;
8extern crate quote;
9extern crate syn;
10
11use combine::Parser;
12
13fn compile(prog: &str) -> String {
14    let prog = match mycroft::parse::program().parse(prog) {
15        Ok((p, "")) => p,
16        Ok((_, trail)) => panic!("Trailing code in mycroft program: {}", trail),
17        Err(e) => panic!("Parse error in mycroft program: {}", e),
18    };
19    let ir = mycroft::ir::Program::from_ast(prog)
20        .unwrap_or_else(|e| panic!("Error raising mycroft program to IR: {}", e));
21    mycroft::codegen::program(&ir).to_string()
22}
23
24fn input_explanation<T, R>(_: R) -> T {
25    panic!("Input to 'mycroft_program!' must be a mycroft program as a string literal.")
26}
27
28proc_macro_item_impl! {
29/// Transforms a mycroft program into a module by invoking the mycroft compiler.
30pub fn mycroft_program_impl(input: &str) -> String {
31    let expr = syn::parse_expr(input).unwrap_or_else(input_explanation);
32    let prog_str = match expr.node {
33        syn::ExprKind::Lit(syn::Lit::Str(s, _)) => s,
34        _ => input_explanation(()),
35    };
36    compile(prog_str.as_str())
37}
38}
39
40fn input_explanation_file<T>(s: String) -> T {
41    panic!("Expected file name as a string, got {}", s)
42}
43
44proc_macro_item_impl! {
45/// Transforms a mycroft program from a set of files into a module by invoking the mycroft
46/// compiler.
47pub fn mycroft_files_impl(input: &str) -> String {
48    use std::io::prelude::*;
49    use std::fs::File;
50    let prog_str = input
51        .split(',')
52        .map(|file_name_str| {
53            let expr = syn::parse_expr(file_name_str).unwrap_or_else(input_explanation_file);
54            let file_name = match expr.node {
55                syn::ExprKind::Lit(syn::Lit::Str(s, _)) => s,
56                e => input_explanation_file(format!("{:?}", e)),
57            };
58            let mut fd = File::open(&file_name).expect(&format!(
59                "Could not read mycroft program file: {}",
60                file_name
61            ));
62            let mut contents = String::new();
63            fd.read_to_string(&mut contents).expect(&format!(
64                "Could not read mycroft program file: {}",
65                file_name
66            ));
67            contents
68        })
69        .collect::<Vec<_>>()
70        .join("\n");
71    compile(prog_str.as_str())
72}
73}