subscript_compiler/frontend/pass/
to_html.rs

1//! Frontend AST to HTML AST conversion.
2use std::iter::FromIterator;
3use std::collections::{HashSet, HashMap};
4use std::rc::Rc;
5use std::borrow::Cow;
6use crate::frontend::data::*;
7use crate::frontend::ast::*;
8use crate::frontend::pass;
9
10use crate::codegen::html;
11
12/// Ensure that `Node` is first canonicalized!
13/// - I.e. make sure the inputs have been passes through the `html_canonicalization` function.
14pub(crate) fn node_to_html<'a>(node: Node<'a>) -> html::Node<'a> {
15    fn enclosure<'a>(
16        start: &'a str,
17        children: Vec<Node<'a>>,
18        end: &'a str,
19    ) -> html::Node<'a> {
20        html::Node::Fragment(
21            vec![
22                vec![html::Node::new_text(start)],
23                children.into_iter().map(node_to_html).collect::<Vec<_>>(),
24                vec![html::Node::new_text(end)],
25            ].concat()
26        )
27    }
28    fn enclosure_cow<'a>(
29        start: Atom<'a>,
30        children: Vec<Node<'a>>,
31        end: Option<Atom<'a>>,
32    ) -> html::Node<'a> {
33        let end = match end {
34            Some(x) => x,
35            None => Cow::Owned(String::new()),
36        };
37        html::Node::Fragment(
38            vec![
39                vec![html::Node::Text(Text(start))],
40                children.into_iter().map(node_to_html).collect::<Vec<_>>(),
41                vec![html::Node::Text(Text(end))],
42            ].concat()
43        )
44    }
45    fn map_children<'a>(children: Vec<Node<'a>>) -> Vec<html::Node<'a>> {
46        children.into_iter().map(node_to_html).collect::<Vec<_>>()
47    }
48    fn to_html_attributes<'a>(parameters: Vec<Node<'a>>) -> HashMap<Text<'a>, Text<'a>> {
49        parameters
50            .into_iter()
51            .filter_map(|node| -> Option<Text<'a>> {
52                match node {
53                    Node::String(Ann{data: txt, ..}) if !txt.trim().is_empty() => {
54                        Some(Text(txt))
55                    }
56                    _ => None
57                }
58            })
59            .map(|x| -> (Text<'a>, Text<'a>) {
60                if let Some((l, r)) = x.0.split_once("=") {
61                    (Text(Cow::Owned(l.to_owned())), Text(Cow::Owned(r.to_owned())))
62                } else {
63                    (x, Text(Cow::Borrowed("")))
64                }
65            })
66            .collect::<HashMap<_, _>>()
67    }
68    match node {
69        Node::Tag(node) => {
70            html::Node::Element(html::Element {
71                name: Text(node.name.data),
72                attributes: node.parameters
73                    .map(to_html_attributes)
74                    .unwrap_or_default(),
75                children: map_children(node.children),
76            })
77        },
78        Node::Enclosure(Ann{data: Enclosure {
79            kind: EnclosureKind::CurlyBrace,
80            children
81        }, ..}) => {
82            enclosure(
83                "{",
84                children,
85                "}"
86            )
87        },
88        Node::Enclosure(Ann{data: Enclosure {
89            kind: EnclosureKind::Parens,
90            children
91        }, ..}) => {
92            enclosure(
93                "(",
94                children,
95                ")"
96            )
97        },
98        Node::Enclosure(Ann{data: Enclosure {
99            kind: EnclosureKind::Fragment,
100            children
101        }, ..}) => {
102            html::Node::Fragment(map_children(children))
103        },
104        Node::Enclosure(Ann{data: Enclosure {
105            kind: EnclosureKind::SquareParen,
106            children
107        }, ..}) => {
108            enclosure(
109                "[",
110                children,
111                "]"
112            )
113        },
114        Node::Enclosure(Ann{data: Enclosure {
115            kind: EnclosureKind::Error{open, close},
116            children
117        }, ..}) => {
118            enclosure_cow(
119                open,
120                children,
121                close
122            )
123        },
124        Node::Ident(Ann{data, ..}) => {
125            html::Node::Text(Text::new("\\").append(Text(data)))
126        },
127        Node::String(Ann{data, ..}) => {
128            html::Node::Text(Text(data))
129        },
130        Node::InvalidToken(Ann{data, ..}) => {
131            html::Node::Text(Text(data))
132        }
133    }
134}
135
136