#![warn(missing_docs)]
#![deny(unused_imports)]
#![deny(unused_variables)]
use std::error::Error;
use std::fmt::Write;
use tele_parser::{
AstType, AtRuleNode, DeclarationNode, DimensionNode, FunctionNode, IdentNode, NumberNode,
OperatorNode, PercentageNode, RawNode, RuleSetNode, StatementNode, StringNode, StyleSheetNode,
URLNode, Value,
};
pub trait CodeGenerator {
fn generate(&mut self, ast: AstType) -> Result<(), Box<dyn Error>> {
self.gen_ss_node(&*ast.borrow())
}
fn gen_ss_node(&mut self, ss_node: &StyleSheetNode) -> Result<(), Box<dyn Error>>;
fn gen_rule_set_node(&mut self, rule_set_node: &RuleSetNode) -> Result<(), Box<dyn Error>>;
fn gen_at_rule_node(&mut self, at_rule_node: &AtRuleNode) -> Result<(), Box<dyn Error>>;
fn gen_decl_node(&mut self, at_rule_node: &DeclarationNode) -> Result<(), Box<dyn Error>>;
fn gen_decl_value(&mut self, values: &Vec<Value>, top_level: bool) -> Result<(), Box<dyn Error>> {
for (idx, value) in values.iter().enumerate() {
let is_last = idx == values.len() - 1;
match value {
Value::Ident(node) => self.gen_ident_node(&*node.borrow_mut(), is_last, top_level)?,
Value::Dimension(node) => {
self.gen_dimension_node(&*node.borrow_mut(), is_last, top_level)?
}
Value::Number(node) => self.gen_number_node(&*node.borrow_mut(), is_last, top_level)?,
Value::Operator(node) => self.gen_operator_node(&*node.borrow_mut(), is_last, top_level)?,
Value::Percentage(node) => {
self.gen_percentage_node(&*node.borrow_mut(), is_last, top_level)?
}
Value::String(node) => self.gen_string_node(&*node.borrow_mut(), is_last, top_level)?,
Value::URL(node) => self.gen_url_node(&*node.borrow_mut(), is_last, top_level)?,
Value::Function(node) => self.gen_fn_node(&*node.borrow_mut(), is_last, top_level)?,
Value::Raw(node) => self.gen_raw_node(&*node.borrow_mut(), is_last, top_level)?,
}
}
Ok(())
}
fn gen_ident_node(
&mut self,
ident_node: &IdentNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_dimension_node(
&mut self,
dimension_node: &DimensionNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_number_node(
&mut self,
number_node: &NumberNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_operator_node(
&mut self,
operator_node: &OperatorNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_percentage_node(
&mut self,
percentage_node: &PercentageNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_string_node(
&mut self,
string_node: &StringNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_url_node(
&mut self,
url_node: &URLNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_fn_node(
&mut self,
fn_node: &FunctionNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_raw_node(
&mut self,
raw_node: &RawNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>>;
fn gen_statements(&mut self, statements: &Vec<StatementNode>) -> Result<(), Box<dyn Error>> {
for stat in statements {
match stat {
StatementNode::AtRule(node) => self.gen_at_rule_node(&*node.borrow_mut())?,
StatementNode::RuleSet(node) => self.gen_rule_set_node(&*node.borrow_mut())?,
}
}
Ok(())
}
}
pub struct Codegen<'a, W: Write> {
css: &'a mut W,
line: usize,
column: usize,
indent: usize,
indent_level: usize,
}
impl<'a, W: Write> Codegen<'a, W> {
pub fn new(writer: &'a mut W) -> Self {
Codegen {
css: writer,
line: 0,
column: 1,
indent: 2,
indent_level: 0,
}
}
fn new_line(&mut self) -> Result<(), Box<dyn Error>> {
self.line += 1;
self.css.write_char('\n')?;
for _ in 0..self.indent_level * self.indent {
self.css.write_char(' ')?;
}
Ok(())
}
fn indent(&mut self) {
self.indent_level += 1;
}
fn de_indent(&mut self) {
self.indent_level -= 1;
}
fn gen_value_padding(
&mut self,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
if is_last {
if last_should_padding {
self.css.write_char(';')?;
}
} else {
self.css.write_char(' ')?;
};
Ok(())
}
}
impl<'a, W: Write> CodeGenerator for Codegen<'a, W> {
fn gen_ss_node(&mut self, ss_node: &StyleSheetNode) -> Result<(), Box<dyn Error>> {
self.gen_statements(&ss_node.statements)
}
fn gen_rule_set_node(&mut self, rule_set_node: &RuleSetNode) -> Result<(), Box<dyn Error>> {
self.css.write_str(&rule_set_node.prelude)?;
self.css.write_str(" {")?;
self.indent();
for decl in &rule_set_node.declarations {
self.new_line()?;
self.gen_decl_node(&*decl.borrow())?;
}
self.de_indent();
self.new_line()?;
self.css.write_char('}')?;
Ok(())
}
fn gen_at_rule_node(&mut self, at_rule_node: &AtRuleNode) -> Result<(), Box<dyn Error>> {
self.css.write_char('@')?;
self.css.write_str(&at_rule_node.name)?;
self.css.write_char(' ')?;
self.css.write_str(&at_rule_node.prelude)?;
if at_rule_node.block.len() > 0 {
self.css.write_char('{')?;
self.indent();
self.new_line()?;
self.gen_statements(&at_rule_node.block)?;
self.de_indent();
self.new_line()?;
self.css.write_char('}')?;
} else {
self.css.write_char(';')?;
}
Ok(())
}
fn gen_decl_node(&mut self, decl_node: &DeclarationNode) -> Result<(), Box<dyn Error>> {
self.css.write_str(&decl_node.name)?;
self.css.write_str(": ")?;
self.gen_decl_value(&decl_node.value, true)?;
Ok(())
}
fn gen_ident_node(
&mut self,
ident_node: &IdentNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&ident_node.name)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_dimension_node(
&mut self,
dimension_node: &DimensionNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&dimension_node.value)?;
self.css.write_str(&dimension_node.unit)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_number_node(
&mut self,
number_node: &NumberNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&number_node.value)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_operator_node(
&mut self,
operator_node: &OperatorNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&operator_node.value)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_percentage_node(
&mut self,
percentage_node: &PercentageNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&format!("{}%", percentage_node.value))?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_string_node(
&mut self,
string_node: &StringNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&string_node.value)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_url_node(
&mut self,
url_node: &URLNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&format!("url({})", url_node.value))?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_fn_node(
&mut self,
fn_node: &FunctionNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&format!("{}(", fn_node.name,))?;
self.gen_decl_value(&fn_node.children, false)?;
self.css.write_char(')')?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
fn gen_raw_node(
&mut self,
raw_node: &RawNode,
is_last: bool,
last_should_padding: bool,
) -> Result<(), Box<dyn Error>> {
self.css.write_str(&raw_node.value)?;
self.gen_value_padding(is_last, last_should_padding)?;
Ok(())
}
}