litua/
tree.rs

1//! Tree structure of a litua text document
2
3use std::collections::HashMap;
4
5/// `DocumentTree` represents the root element of the Abstract Syntax Tree
6#[derive(Clone,Debug,PartialEq)]
7pub struct DocumentTree(pub DocumentElement);
8
9impl DocumentTree {
10    /// Create a new `DocumentTree`, which consists of one root
11    /// call `document`.
12    pub fn new() -> DocumentTree {
13        DocumentTree(DocumentElement::Function(DocumentFunction {
14            call: "document".to_owned(),
15            args: HashMap::new(),
16            content: Vec::new()
17        }))
18    }
19}
20
21impl Default for DocumentTree {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl<'lua> mlua::ToLua<'lua> for &DocumentTree {
28    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
29        self.0.to_lua(lua)
30    }
31}
32
33/// `DocumentFunction` is a function call in the text document. For example,
34/// ``{text[style=bold] message}`` is a `DocumentFunction` with `name` “text”,
35/// `args` such that `style` is associated with `DocumentNode::Text` “bold”
36/// and `content` is given as `DocumentNode::Text` “message”.
37#[derive(Clone,Debug,PartialEq)]
38pub struct DocumentFunction {
39    pub call: String,
40    pub args: HashMap<String, DocumentNode>,
41    pub content: DocumentNode,
42}
43
44impl DocumentFunction {
45    /// Returns an empty `DocumentFunction` without args or content and `name` is set to “”.
46    pub fn new() -> DocumentFunction {
47        DocumentFunction { call: "".to_owned(), args: HashMap::new(), content: Vec::new() }
48    }
49
50    /// Returns an empty `DocumentElement::Function` without args or content and `name` is set to “”.
51    pub fn empty_element() -> DocumentElement {
52        DocumentElement::Function(Self::new())
53    }
54}
55
56impl Default for DocumentFunction {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62impl<'lua> mlua::ToLua<'lua> for &DocumentFunction {
63    /// Lua representation of a `DocumentFunction`
64    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
65        let node = lua.create_table()?;
66
67        // define call
68        node.set("call", self.call.clone())?;
69
70        // define args
71        let args = lua.create_table()?;
72        for (arg, elements) in self.args.iter() {
73            let lua_value = lua.create_table()?;
74            for (i, element) in elements.iter().enumerate() {
75                lua_value.set(i + 1, element)?;
76            }
77            args.set(arg.as_str(), lua_value)?;
78        }
79        node.set("args", args)?;
80
81        // define content
82        let content = lua.create_table()?;
83        for (i, child) in self.content.iter().enumerate() {
84            content.set(i + 1, child)?;
85        }
86        node.set("content", content)?;
87
88        Ok(mlua::Value::Table(node))
89    }
90}
91
92/// `DocumentElement` is either a function (call with arguments and text content)
93/// or simply Unicode text without association to a function.
94#[derive(Clone,Debug,PartialEq)]
95pub enum DocumentElement {
96    Function(DocumentFunction),
97    Text(String),
98}
99
100impl<'lua> mlua::ToLua<'lua> for &DocumentElement {
101    /// Lua representation of a `DocumentElement`.
102    fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
103        match self {
104            DocumentElement::Function(func) => func.to_lua(lua),
105            DocumentElement::Text(text) => text.clone().to_lua(lua),
106        }
107    }
108}
109
110/// `DocumentNode` is a node establishing a tree.
111/// Each node consists of zero or more elements constituting its children.
112pub type DocumentNode = Vec<DocumentElement>;