use crate::css::fileinfo::FileWeakRef;
use crate::css::node::NodeWeakRef;
use crate::css::value::ValueNode;
use crate::css::var::HandleResult;
use crate::extend::string::StringExtend;
use crate::extend::vec_str::VecCharExtend;
use crate::sourcemap::loc::{Loc, LocMap};
use crate::style_core::context::ParseContext;
use crate::style_core::option::ParseOption;
use crate::style_core::scan::traversal;
use crate::token::lib::Token;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use serde_json::{Map, Value};
use std::fmt::{Debug, Formatter};
use uuid::Uuid;
#[derive(Clone)]
pub struct StyleRuleNode {
pub loc: Option<Loc>,
charlist: Vec<char>,
pub uuid: String,
map: LocMap,
pub fileinfo: FileWeakRef,
pub parent: NodeWeakRef,
pub context: ParseContext,
pub key: Option<String>,
pub value: Option<ValueNode>,
}
impl Serialize for StyleRuleNode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("StyleRuleNode", 5)?;
state.serialize_field("content", &self.charlist.poly())?;
state.serialize_field("loc", &self.loc)?;
state.serialize_field("uuid", &self.uuid)?;
state.serialize_field("key", &self.key)?;
state.serialize_field("value", &self.value)?;
state.end()
}
}
impl Debug for StyleRuleNode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StyleRuleNode")
.field("content", &self.charlist.poly())
.field("loc", &self.loc)
.field("uuid", &self.uuid)
.field("key", &self.key)
.field("value", &self.value)
.finish()
}
}
impl StyleRuleNode {
pub fn new(
charlist: Vec<char>,
loc: Option<Loc>,
parent: NodeWeakRef,
fileinfo: FileWeakRef,
context: ParseContext,
) -> HandleResult<Self> {
let map = if loc.is_none() {
LocMap::new(&charlist)
} else {
LocMap::merge(loc.as_ref().unwrap(), &charlist).0
};
let mut obj = Self {
loc,
charlist,
uuid: Uuid::new_v4().to_string(),
map,
fileinfo,
parent,
context,
key: None,
value: None,
};
match obj.parse() {
Ok(_) => HandleResult::Success(obj),
Err(msg) => HandleResult::Fail(msg),
}
}
pub fn deserializer(
map: &Map<String, Value>,
context: ParseContext,
parent: NodeWeakRef,
fileinfo: FileWeakRef,
) -> Result<Self, String> {
let mut obj = Self {
loc: None,
uuid: "".to_string(),
map: LocMap::new(&[]),
charlist: vec![],
parent: parent.as_ref().cloned(),
fileinfo: fileinfo.as_ref().cloned(),
key: None,
value: None,
context,
};
if let Some(Value::String(content)) = map.get("content") {
obj.charlist = content.to_char_vec();
} else {
return Err("deserializer VarNode has error -> content is empty!".to_string());
}
if let Some(Value::Object(loc)) = map.get("loc") {
obj.loc = Some(Loc::deserializer(loc));
obj.map = LocMap::merge(obj.loc.as_ref().unwrap(), &obj.charlist).0;
} else {
obj.map = LocMap::new(&obj.charlist);
}
if let Some(Value::String(uuid)) = map.get("uuid") {
obj.uuid = uuid.to_string();
} else {
return Err("deserializer VarNode has error -> uuid is empty!".to_string());
}
if let Some(Value::String(key)) = map.get("key") {
obj.key = Some(key.to_string());
} else {
return Err("deserializer VarNode has error -> key is empty!".to_string());
}
if let Some(Value::Object(value_map)) = map.get("value") {
obj.value = Some(ValueNode::deserializer(value_map, parent, fileinfo)?);
}
Ok(obj)
}
pub fn get_options(&self) -> ParseOption {
self.context.lock().unwrap().option.clone()
}
pub fn is_top(&self) -> bool {
self.parent.is_none()
}
pub fn error_msg(&self, index: &usize) -> String {
let error_loc = self.map.get(*index).unwrap();
let char = self.charlist.get(*index).unwrap().to_string();
format!(
"text {}, char {} is not allow, line is {} col is {}",
&self.charlist.poly(),
char,
error_loc.line,
error_loc.col
)
}
pub fn parse_var_ident(&self, start: &usize) -> Result<(String, usize), String> {
let charlist = &self.charlist;
let res = traversal(
Some(*start),
charlist,
&mut (|arg, charword| {
let (index, temp, hasend) = arg;
let (_, char, next) = charword;
if Token::is_token(Some(char)) {
if vec![':', '-'].contains(char) {
if *char == ':' {
*hasend = true;
} else {
temp.push(*char);
}
} else if Token::is_space_token(Some(char)) {
if Token::is_space_token(next) {
return Ok(());
} else if next.is_some() && *next.unwrap() == ':' {
temp.push(*char);
} else {
return Ok(());
}
} else {
return Err(self.error_msg(index));
}
} else {
temp.push(*char);
}
Ok(())
}),
)?;
Ok(res)
}
pub fn parse_var_value(&self, start: &usize) -> Result<(ValueNode, usize), String> {
let end = self.charlist.len() - 1;
let mut trim_start = *start;
while trim_start < self.charlist.len() {
if !Token::is_space_token(Some(self.charlist.get(trim_start).unwrap())) {
break;
}
trim_start += 1;
}
let node = ValueNode::new(
self.charlist[trim_start..end].to_vec(),
self.map.get(*start),
self.parent.clone(),
self.fileinfo.clone(),
)?;
Ok((node, self.charlist.len() - 1))
}
fn parse(&mut self) -> Result<(), String> {
let charlist = &self.charlist.clone();
if charlist.is_empty() {
return Err("var declare text is empty".to_string());
}
traversal(
None,
charlist,
&mut (|arg, _| {
let (index, _, _) = arg;
if self.key.is_none() {
let (key, jump) = self.parse_var_ident(index)?;
*index = jump;
self.key = Some(key);
} else if self.value.is_none() {
let (value, jump) = self.parse_var_value(index)?;
*index = jump;
self.value = Some(value);
} else if self.value.is_some() && self.key.is_some() {
return Err(self.error_msg(index));
}
Ok(())
}),
)?;
Ok(())
}
pub fn code_gen(&self) -> Result<String, String> {
let res = match self.value.as_ref() {
None => "".to_string(),
Some(value) => value.code_gen()?,
};
let code_res = format!("{}: {};", self.key.as_ref().unwrap(), res);
Ok(code_res)
}
}