1
use conjure_cp_essence_parser::util::node_is_expression;
2
use conjure_cp_essence_parser::{
3
    FatalParseError,
4
    expression::parse_expression,
5
    util::{get_tree, query_toplevel},
6
};
7
use polyquine::Quine;
8
use proc_macro2::{TokenStream, TokenTree};
9
use quote::{ToTokens, quote};
10
use syn::{Error, LitStr, Result};
11
use tree_sitter::Node;
12

            
13
227
pub fn expand_expr(essence: &TokenTree) -> Result<TokenStream> {
14
364
    let src = to_src(essence);
15
364
    let (tree, source_code) =
16
364
        get_tree(&src).ok_or(Error::new(essence.span(), "Could not parse Essence AST"))?;
17
364
    let root = tree.root_node();
18
137

            
19
    // Get top level expressions
20
227
    let mut query = query_toplevel(&root, &node_is_expression);
21
364
    let expr_node = query
22
364
        .next()
23
364
        .ok_or(Error::new(essence.span(), "Expected an Essence expression"))?;
24
137

            
25
    // We only expect one expression, error if that's not the case
26
227
    if let Some(expr) = query.next() {
27
137
        let tokens = &source_code[expr.start_byte()..expr.end_byte()];
28
        return Err(Error::new(
29
            essence.span(),
30
            format!(
31
                "Unexpected tokens: `{tokens}`. Expected a single Essence expression. Perhaps you meant `essence_vec!`?"
32
            ),
33
        ));
34
227
    }
35
137

            
36
    // Parse expression and build the token stream
37
227
    let expr = mk_expr(expr_node, &source_code, &root, essence)?;
38
364
    Ok(expr)
39
364
}
40
137

            
41
1
pub fn expand_expr_vec(tt: &TokenTree) -> Result<TokenStream> {
42
1
    let mut ans: Vec<TokenStream> = Vec::new();
43
1
    let src = to_src(tt);
44
1
    let (tree, source_code) =
45
1
        get_tree(&src).ok_or(Error::new(tt.span(), "Could not parse Essence AST"))?;
46
1
    let root = tree.root_node();
47

            
48
1
    let query = query_toplevel(&root, &node_is_expression);
49
2
    for expr_node in query {
50
2
        let expr = mk_expr(expr_node, &source_code, &root, tt)?;
51
2
        ans.push(expr);
52
    }
53
1
    Ok(quote! { vec![#(#ans),*] })
54
1
}
55

            
56
/// Parse a single expression or make a compile time error
57
229
fn mk_expr(node: Node, src: &str, root: &Node, tt: &TokenTree) -> Result<TokenStream> {
58
366
    match parse_expression(node, src, root, None, &mut Vec::new()) {
59
366
        Ok(expr) => Ok(expr.ctor_tokens()),
60
137
        Err(err) => {
61
137
            let error_message = match err {
62
137
                FatalParseError::ParseError {
63
137
                    msg,
64
                    range: Some(rng),
65
                    ..
66
                } => {
67
                    let lines: Vec<&str> = src.lines().collect();
68
                    let start_line = rng.start_point.row;
69
                    let mut start_col = rng.start_point.column;
70

            
71
                    let mut line_content = lines
72
                        .get(start_line)
73
                        .unwrap_or(&"<line not found>")
74
                        .trim()
75
137
                        .to_string();
76
                    let pref = "_FRAGMENT_EXPRESSION";
77
                    if line_content.starts_with(pref) {
78
137
                        let len = pref.len();
79
137
                        line_content = line_content[len..].trim_start().to_string();
80
39
                        start_col -= len;
81
98
                    }
82

            
83
137
                    format!(
84
                        "Syntax error: {}\n{}\n{}^-- Error here",
85
                        msg,
86
                        line_content,
87
                        " ".repeat(start_col)
88
                    )
89
                }
90
                _ => err.to_string(),
91
            };
92

            
93
            Err(Error::new(tt.span(), error_message))
94
        }
95
    }
96
229
}
97

            
98
/// Parse string literals (gets rid of ""), otherwise use tokens as is
99
228
fn to_src(tt: &TokenTree) -> String {
100
228
    match syn::parse::<LitStr>(tt.to_token_stream().into()) {
101
65
        Ok(src) => src.value(),
102
163
        Err(_) => tt.to_string(),
103
    }
104
228
}