1use std::collections::HashMap;
4use std::iter::FromIterator;
5
6use super::code::CodeBlock;
7use super::text::TextBlock;
8use super::{CompileError, CompileErrorKind};
9use crate::parser::Printer;
10
11#[derive(Debug)]
13pub(crate) enum Node<'a> {
14 Text(TextBlock<'a>),
16 Code(CodeBlock<'a>),
18}
19
20#[derive(Debug)]
22pub struct Ast<'a> {
23 nodes: Vec<Node<'a>>,
26}
27
28impl<'a> Ast<'a> {
29 pub(crate) fn new(nodes: Vec<Node<'a>>) -> Self {
31 Ast { nodes }
32 }
33
34 pub(crate) fn code_blocks(&self, language: Option<&str>) -> HashMap<Option<&str>, CodeBlock> {
36 let mut code_blocks = HashMap::new();
37 for node in &self.nodes {
38 if let Node::Code(block) = node {
39 if let Some(language) = language {
42 if let Some(block_language) = &block.language {
43 if language != block_language {
44 continue;
45 }
46 }
47 }
48 code_blocks
49 .entry(block.name.as_ref().map(|x| &x[..])) .and_modify(|existing: &mut CodeBlock<'a>| existing.append(block))
51 .or_insert_with(|| block.clone());
52 }
53 }
54 code_blocks
55 }
56
57 pub(crate) fn print_docs<P: Printer>(&self, printer: &P) -> String {
59 let mut output = String::new();
60 for node in &self.nodes {
61 match node {
62 Node::Text(text_block) => output.push_str(&printer.print_text_block(text_block)),
63 Node::Code(code_block) => output.push_str(
64 &printer
65 .print_code_block(code_block)
66 .split("\n")
67 .map(|line| {
68 if line.is_empty() {
69 line.to_string()
70 } else {
71 format!("{}{}", code_block.indent, line)
72 }
73 })
74 .collect::<Vec<_>>()
75 .join("\n"),
76 ),
77 }
78 }
79 output
80 }
81
82 pub(crate) fn print_code(
84 &self,
85 entrypoint: Option<&str>,
86 language: Option<&str>,
87 ) -> Result<String, CompileError> {
88 let code_blocks = self.code_blocks(language);
89 code_blocks
90 .get(&entrypoint)
91 .map(|entrypoint| entrypoint.compile(&code_blocks))
92 .unwrap_or(Err(CompileError::Single {
93 line_number: 0,
94 kind: CompileErrorKind::MissingEntrypoint,
95 }))
96 }
97}
98
99impl<'a> FromIterator<Node<'a>> for Ast<'a> {
100 fn from_iter<I: IntoIterator<Item = Node<'a>>>(iter: I) -> Self {
101 Self::new(iter.into_iter().collect())
102 }
103}
104
105impl<'a> From<Vec<Node<'a>>> for Ast<'a> {
106 fn from(nodes: Vec<Node<'a>>) -> Self {
107 Self::new(nodes)
108 }
109}