cdoc_parser/raw/
mod.rs

1mod parser;
2
3pub use parser::*;
4use std::collections::HashMap;
5
6use crate::code_ast::types::CodeContent;
7use crate::common::Span;
8use cowstr::CowStr;
9use serde::{Deserialize, Serialize};
10use std::io::{BufWriter, Write};
11
12#[derive(Debug, PartialEq, Default)]
13pub struct RawDocument {
14    pub(crate) src: Vec<ElementInfo>,
15    pub(crate) input: CowStr,
16    pub(crate) meta: Option<CowStr>,
17    pub(crate) references: HashMap<CowStr, Reference>,
18}
19
20impl RawDocument {
21    pub fn new(input: &str) -> Self {
22        Self {
23            src: vec![],
24            input: CowStr::from(input),
25            meta: None,
26            references: Default::default(),
27        }
28    }
29}
30
31#[derive(Debug, PartialEq, Clone)]
32pub enum Reference {
33    Math(CowStr),
34    Code(CowStr),
35    Command(CowStr, Vec<Parameter>),
36}
37
38#[derive(Debug, PartialEq, Clone)]
39pub enum Element {
40    Markdown(CowStr),
41    Special(Option<CowStr>, Special),
42}
43
44#[derive(Debug, PartialEq, Clone)]
45pub enum Special {
46    Math {
47        inner: CowStr,
48        is_block: bool,
49    },
50    CodeInline {
51        inner: CowStr,
52    },
53    CodeBlock {
54        lvl: usize,
55        inner: CodeContent,
56        attributes: Vec<CowStr>,
57    },
58    Command {
59        function: CowStr,
60        parameters: Vec<Parameter>,
61        body: Option<Vec<ElementInfo>>,
62    },
63    Verbatim {
64        inner: CowStr,
65    },
66}
67
68#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
69pub struct CodeAttr {
70    pub key: Option<CowStr>,
71    pub value: CowStr,
72}
73
74#[derive(Debug, PartialEq, Clone)]
75pub struct ElementInfo {
76    pub(crate) element: Element,
77    pub(crate) span: Span,
78}
79
80#[derive(Debug, PartialEq, Clone)]
81pub struct Parameter {
82    pub key: Option<CowStr>,
83    pub value: Value,
84    pub span: Span,
85}
86
87impl Parameter {
88    pub fn with_value(value: Value, pos: Span) -> Self {
89        Self {
90            key: None,
91            value,
92            span: pos,
93        }
94    }
95
96    pub fn with_key<C: Into<CowStr>>(key: C, value: Value, pos: Span) -> Self {
97        Self {
98            key: Some(key.into()),
99            value,
100            span: pos,
101        }
102    }
103}
104
105#[derive(Debug, PartialEq, Clone)]
106pub enum Value {
107    Flag(CowStr),
108    Content(Vec<ElementInfo>),
109    String(CowStr),
110}
111
112impl ToString for Value {
113    fn to_string(&self) -> String {
114        match self {
115            Value::Flag(k) => format!("Flag: {k}"),
116            Value::Content(_) => "Content".to_string(),
117            Value::String(s) => s.to_string(),
118        }
119    }
120}
121
122#[derive(Clone)]
123pub struct Child {
124    pub elem: Special,
125    pub span: Span,
126    pub label: Option<CowStr>,
127    pub identifier: usize,
128}
129
130pub struct ComposedMarkdown {
131    pub src: CowStr,
132    pub children: Vec<Child>,
133}
134
135impl From<Vec<ElementInfo>> for ComposedMarkdown {
136    fn from(value: Vec<ElementInfo>) -> Self {
137        let mut writer = BufWriter::new(Vec::new());
138        let mut children = Vec::new();
139
140        let mut code_idx = 0;
141        let mut command_idx = 0;
142        let mut math_idx = 0;
143        let mut extra_idx = 0;
144
145        for elem in value.into_iter() {
146            match elem.element {
147                Element::Markdown(s) => {
148                    writer.write_all(s.as_bytes()).unwrap();
149                }
150                Element::Special(label, inner) => {
151                    let idx = code_idx + command_idx + math_idx + extra_idx;
152
153                    let identifier = match inner {
154                        Special::Math { .. } => {
155                            math_idx += 1;
156                            math_idx - 1
157                        }
158                        Special::CodeBlock { lvl, .. } => {
159                            if lvl > 1 {
160                                code_idx += 1;
161                                code_idx - 1
162                            } else {
163                                extra_idx += 1;
164                                0
165                            }
166                        }
167                        Special::Command { .. } => {
168                            command_idx += 1;
169                            command_idx - 1
170                        }
171                        Special::Verbatim { .. } => {
172                            extra_idx += 1;
173                            0
174                        }
175                        Special::CodeInline { .. } => {
176                            extra_idx += 1;
177                            0
178                        }
179                    };
180
181                    children.push(Child {
182                        elem: inner,
183                        span: elem.span,
184                        label,
185                        identifier,
186                    });
187                    write!(&mut writer, "<elem-{}>", idx).unwrap() // Important: Trailing space is necessary as it is eaten by the parser
188                }
189            }
190        }
191
192        ComposedMarkdown {
193            src: CowStr::from(String::from_utf8(writer.into_inner().unwrap()).unwrap()),
194            children,
195        }
196    }
197}