use crate::lexer::Kind;
use crate::parser::Node;
use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq)]
pub struct Generator {
pub ast: Node,
pub conditions: Vec<String>,
}
impl Generator {
pub fn new(ast: Node) -> Generator {
Generator {
ast,
conditions: vec![],
}
}
pub fn generate_fre(&mut self) -> String {
let root = self.ast.clone();
return self.generate_node(root);
}
pub fn generate_node(&mut self, node: Node) -> String {
let token = node.token;
let mut directs = VecDeque::new();
let mut code = "".to_string();
match token.kind {
Kind::OpenTag(name) => {
let tag = self.camel_case(name);
code = format!("{}<{}", code, tag);
for attr in token.attributes.unwrap() {
if let Kind::Attribute(name, value) = attr.kind {
let prop = self.wried_prop(name);
let expression = self.parse_expression(value);
match prop.as_str() {
"wx:key" => code = format!("{} {}=\"{}\"", code, "key", expression),
"wx:if" | "wx:elseif" | "wx:else" => {
directs.push_back((prop, expression));
}
"wx:for" => directs.push_front((prop, expression)),
_ => code = format!("{} {}=\"{}\"", code, prop, expression),
}
}
}
code += ">";
for child in node.children.unwrap() {
let str = self.generate_node(child);
if str == "" {
println!("{:#?}", self.conditions)
}
code = format!("{}{}", code, str);
}
code = format!("{}</{}>", code, tag);
}
Kind::SelfCloseTag(name) => {
let tag = self.first_upper(name);
code = format!("{}<{}", code, tag);
for attr in token.attributes.unwrap() {
if let Kind::Attribute(name, value) = attr.kind {
let prop = self.wried_prop(name);
let expression = self.parse_expression(value);
match prop.as_str() {
"wx:key" => code = format!("{} {}=\"{}\"", code, "key", expression),
"wx:if" | "wx:elseif" | "wx:else" => {
directs.push_back((prop, expression));
}
"wx:for" => directs.push_front((prop, expression)),
_ => code = format!("{} {}=\"{}\"", code, prop, expression),
}
}
}
code += "/>";
}
Kind::Text(text) => {
let expression = self.parse_expression_text(text);
code = format!("{}{}", code, expression);
}
_ => {}
};
let c = self.generate_directs(directs, code);
return c;
}
pub fn generate_directs(
&mut self,
directs: VecDeque<(String, String)>,
mut code: String,
) -> String {
let d = match self.conditions.last() {
Some(d) => d.clone(),
None => "".to_string(),
};
let len = directs.len();
for direct in directs {
match direct.0.as_str() {
"wx:if" => {
if d == "" || d == "else" {
self.conditions.push("if".to_string());
}
code = format!("{{{}?{}:", direct.1, code);
}
"wx:elseif" => {
if d == "if" {
self.conditions.push("elseif".to_string());
}
code = format!("{}?{}:", direct.1, code);
}
"wx:else" => {
if d == "if" || d == "elseif" {
self.conditions.push("else".to_string());
}
println!("{:#?}", direct.1);
code = format!("{}?{}:null}}", direct.1, code);
}
"wx:for" => {
code = format!("{{{}.map((item)=>{})}}", direct.1, code);
if len > 0 {
code = format!("<>{}</>", code)
}
}
_ => {}
}
}
return code;
}
}
impl Generator {
fn first_upper(&mut self, s: String) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
}
fn wried_prop(&mut self, p: String) -> String {
if p.starts_with("bind") {
let n = p.replace("bind", "");
return format!(
"on{}",
match n.as_str() {
"tap" => "click".to_string(),
"confirm" => "keydown".to_string(),
_ => n,
}
);
} else {
p
}
}
fn camel_case(&mut self, s: String) -> String {
let arr: Vec<&str> = s.split("-").collect();
let mut out = "".to_string();
for s in arr {
out = format!("{}{}", out, self.first_upper(s.to_string()));
}
out
}
fn parse_expression(&mut self, e: String) -> String {
return e.replace("{{", "").replace("}}", "");
}
fn parse_expression_text(&mut self, e: String) -> String {
let mut out = "".to_string();
let mut once = true;
let text = e.replace("{{", "{").replace("}}", "}").replace("\n", "");
for s in text.chars() { if s == ' ' {
if once == true {
once = false;
out.push(s);
}
} else {
once = true;
out.push(s)
}
}
return out;
}
}