forked from mars/tml
128 lines
3.8 KiB
Rust
128 lines
3.8 KiB
Rust
use crate::dom::Dom;
|
|
use crate::tag::*;
|
|
use lexpr::{Cons, Value};
|
|
use std::str::FromStr;
|
|
|
|
pub struct Parser {
|
|
vals: Vec<Value>,
|
|
}
|
|
|
|
impl Parser {
|
|
pub fn parse(document: &Value) -> Dom {
|
|
let parser = Self::from_value(document);
|
|
|
|
let mut tags = Vec::new();
|
|
|
|
for val in parser.vals.into_iter().rev() {
|
|
let mut parser = Self::from_value(&val);
|
|
|
|
let kind = parser
|
|
.parse_any_tag_kind()
|
|
.as_block()
|
|
.expect("Root tag must be a block tag");
|
|
|
|
let tag = parser.parse_block_tag(kind);
|
|
|
|
tags.push(tag);
|
|
}
|
|
|
|
Dom { tags }
|
|
}
|
|
|
|
pub fn from_value(value: &Value) -> Self {
|
|
let cons = value.as_cons().expect("Must be a cons");
|
|
Self::from_cons(cons)
|
|
}
|
|
|
|
pub fn from_cons(cons: &Cons) -> Self {
|
|
let mut vals = cons.to_vec().0;
|
|
vals.reverse();
|
|
Self { vals }
|
|
}
|
|
|
|
pub fn parse_args(&mut self) -> (Vec<(String, Value)>, Vec<Value>) {
|
|
let args = Vec::new();
|
|
let mut children = std::mem::replace(&mut self.vals, Vec::new());
|
|
children.reverse();
|
|
(args, children)
|
|
}
|
|
|
|
pub fn parse_text_tag(&mut self, kind: TextTagKind) -> TextTag {
|
|
let (_args, children_vals) = self.parse_args();
|
|
|
|
let mut children = Vec::new();
|
|
|
|
for child in children_vals.into_iter() {
|
|
let node = match child {
|
|
Value::Cons(cons) => {
|
|
let mut parser = Self::from_cons(&cons);
|
|
let kind = parser
|
|
.parse_any_tag_kind()
|
|
.as_text()
|
|
.expect("Text tag can only have other text tags as children");
|
|
TextNode::Tag(parser.parse_text_tag(kind))
|
|
}
|
|
Value::String(string) => TextNode::Text(string.to_string()),
|
|
_ => panic!("Text tag child must be a string or a cons"),
|
|
};
|
|
|
|
children.push(node);
|
|
}
|
|
|
|
TextTag { kind, children }
|
|
}
|
|
|
|
pub fn parse_leaf_tag(&mut self, kind: LeafTagKind) -> LeafTag {
|
|
let (_args, children) = self.parse_args();
|
|
|
|
if !children.is_empty() {
|
|
panic!("Leaf tag cannot have children");
|
|
}
|
|
|
|
LeafTag { kind }
|
|
}
|
|
|
|
pub fn parse_block_tag(&mut self, kind: BlockTagKind) -> BlockTag {
|
|
let (_args, children_vals) = self.parse_args();
|
|
|
|
let mut children = Vec::new();
|
|
|
|
for child in children_vals.into_iter() {
|
|
let node = match child {
|
|
Value::Cons(cons) => {
|
|
let mut parser = Self::from_cons(&cons);
|
|
match parser.parse_any_tag_kind() {
|
|
AnyTagKind::Text(kind) => BlockNode::Text(parser.parse_text_tag(kind)),
|
|
AnyTagKind::Leaf(kind) => BlockNode::Leaf(parser.parse_leaf_tag(kind)),
|
|
AnyTagKind::Block(kind) => BlockNode::Block(parser.parse_block_tag(kind)),
|
|
}
|
|
}
|
|
Value::String(string) => BlockNode::Text(TextTag {
|
|
kind: TextTagKind::Plain,
|
|
children: vec![TextNode::Text(string.to_string())],
|
|
}),
|
|
_ => panic!("Block tag child must be either a string or a cons"),
|
|
};
|
|
|
|
children.push(node);
|
|
}
|
|
|
|
BlockTag { kind, children }
|
|
}
|
|
|
|
pub fn parse_any_tag_kind(&mut self) -> AnyTagKind {
|
|
let symbol = self.parse_symbol();
|
|
AnyTagKind::from_str(&symbol).expect("Unrecognized tag")
|
|
}
|
|
|
|
pub fn parse_symbol(&mut self) -> String {
|
|
self.vals
|
|
.pop()
|
|
.as_ref()
|
|
.map(|v| v.as_symbol())
|
|
.flatten()
|
|
.expect("Expected symbol")
|
|
.to_string()
|
|
}
|
|
}
|