template_compiler/
parse.rs

1use std::{sync::Arc, iter::Peekable};
2
3use anyhow::Result;
4use miette::{NamedSource, SourceSpan};
5
6use crate::tokens::{Token, Tokenizer};
7
8#[derive(Debug)]
9pub struct M<T> {
10    pub span: SourceSpan,
11    pub value: T,
12}
13
14impl<T> M<T> {
15    pub fn new(value: T, span: SourceSpan) -> Self {
16        M { span, value }
17    }
18}
19
20#[derive(Debug)]
21pub struct FileData<'source> {
22    pub source: Arc<NamedSource>,
23    pub contents: Vec<Node<'source>>,
24}
25
26#[derive(Debug)]
27pub enum Node<'source> {
28    Text {
29        index: usize,
30        text: M<&'source str>,
31    },
32    Parameter {
33        name: M<&'source str>,
34    },
35    Conditional {
36        if_kwd: SourceSpan,
37        cond_ident: M<&'source str>,
38        contents: Vec<Node<'source>>,
39        endif_kwd: SourceSpan,
40    },
41}
42
43pub fn parse_file<'source>(
44    source: Arc<NamedSource>,
45    text: &'source str,
46) -> Result<FileData<'source>> {
47    let tokens = Tokenizer::new(source.clone(), text).tokenize()?;
48    let mut token_iter = tokens.into_iter().peekable();
49
50    let contents = parse_tokens(source.clone(), &mut token_iter)?;
51
52    Ok(FileData { source, contents })
53}
54
55fn parse_tokens<'source, Iter>(source: Arc<NamedSource>, token_iter: &mut Peekable<Iter>) -> Result<Vec<Node<'source>>>
56where
57    Iter: Iterator<Item = (SourceSpan, Token<'source>)>,
58{
59    let mut contents = Vec::new();
60
61    while let Some((span, token)) = token_iter.next() {
62        match token {
63            Token::CommandStart => {
64                if token_iter.peek().unwrap().1 == Token::EndIf {
65                    return Ok(contents);
66                }
67
68                let if_kwd = match_token(token_iter, Token::If)?;
69                let cond_ident = match_ident(token_iter)?;
70                match_token(token_iter, Token::CommandEnd)?;
71
72                let if_contents = parse_tokens(source.clone(), token_iter)?;
73
74                let endif_kwd = match_token(token_iter, Token::EndIf)?;
75                match_token(token_iter, Token::CommandEnd)?;
76
77                contents.push(Node::Conditional {
78                    if_kwd,
79                    cond_ident,
80                    contents: if_contents,
81                    endif_kwd,
82                })
83            }
84            Token::ParamStart => {
85                let name = match_ident(token_iter)?;
86                contents.push(Node::Parameter { name });
87                match_token(token_iter, Token::ParamEnd)?;
88            }
89            Token::Text { index, text } => {
90                contents.push(Node::Text {
91                    index,
92                    text: M::new(text, span),
93                });
94            }
95            _ => todo!(),
96        }
97    }
98
99    Ok(contents)
100}
101
102fn match_token<'source, Iter>(token_iter: &mut Iter, token: Token<'source>) -> Result<SourceSpan>
103where
104    Iter: Iterator<Item = (SourceSpan, Token<'source>)>,
105{
106    match token_iter.next() {
107        Some((span, t)) if t == token => Ok(span),
108        Some(st) => { dbg!(st); todo!() },
109        None => todo!("error"),
110    }
111}
112
113fn match_ident<'source, Iter>(token_iter: &mut Iter) -> Result<M<&'source str>>
114where
115    Iter: Iterator<Item = (SourceSpan, Token<'source>)>,
116{
117    match token_iter.next() {
118        Some((span, Token::Identifier { name })) => Ok(M::new(name, span)),
119        Some(_) => todo!("error"),
120        None => todo!("error"),
121    }
122}