tml/src/parse.rs

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()
}
}