use vize_carton::{Box, String, Vec};
use vize_relief::ast::{
AttributeNode, ConstantType, DirectiveNode, ExpressionNode, PropNode, SimpleExpressionNode,
TextNode,
};
use crate::tokenizer::QuoteType;
use super::{CurrentAttribute, CurrentDirective, Parser};
impl<'a> Parser<'a> {
pub(super) fn on_attrib_name_impl(&mut self, start: usize, end: usize) {
let name = self.get_source(start, end);
self.current_attr = Some(CurrentAttribute {
name: name.into(),
name_start: start,
name_end: end,
value_start: None,
value_end: None,
_marker: std::marker::PhantomData,
});
}
pub(super) fn on_dir_name_impl(&mut self, start: usize, end: usize) {
let raw_name = self.get_source(start, end);
let name = super::callbacks::parse_directive_name(raw_name);
self.current_dir = Some(CurrentDirective {
name: name.into(),
raw_name: raw_name.into(),
name_start: start,
name_end: end,
arg: None,
modifiers: Vec::new_in(self.allocator),
value_start: None,
value_end: None,
_marker: std::marker::PhantomData,
});
}
pub(super) fn on_dir_arg_impl(&mut self, start: usize, end: usize) {
let arg: String = self.get_source(start, end).into();
let is_dynamic = start > 0 && self.source.as_bytes().get(start - 1) == Some(&b'[');
if let Some(ref mut dir) = self.current_dir {
dir.arg = Some((arg, start, end, is_dynamic));
}
}
pub(super) fn on_dir_modifier_impl(&mut self, start: usize, end: usize) {
let modifier: String = self.get_source(start, end).into();
if let Some(ref mut dir) = self.current_dir {
dir.modifiers.push((modifier, start, end));
}
}
pub(super) fn on_attrib_data_impl(&mut self, start: usize, end: usize) {
if let Some(ref mut attr) = self.current_attr {
if attr.value_start.is_none() {
attr.value_start = Some(start);
}
attr.value_end = Some(end);
}
if let Some(ref mut dir) = self.current_dir {
if dir.value_start.is_none() {
dir.value_start = Some(start);
}
dir.value_end = Some(end);
}
}
pub(super) fn on_attrib_entity_impl(&mut self, start: usize, end: usize) {
self.on_attrib_data_impl(start, end);
}
pub(super) fn on_attrib_end_impl(&mut self, quote: QuoteType, end: usize) {
if let Some(attr) = self.current_attr.take() {
self.finish_attribute(attr, quote, end);
}
if let Some(dir) = self.current_dir.take() {
self.finish_directive(dir, quote, end);
}
}
fn finish_attribute(&mut self, attr: CurrentAttribute<'a>, quote: QuoteType, end: usize) {
let loc = self.create_loc(attr.name_start, end);
let name_loc = self.create_loc(attr.name_start, attr.name_end);
let mut attr_node = AttributeNode::new(attr.name.clone(), loc);
attr_node.name_loc = name_loc;
if let (Some(v_start), Some(v_end)) = (attr.value_start, attr.value_end) {
let value_content = self.get_source(v_start, v_end);
let value_loc = self.create_loc(v_start, v_end);
attr_node.value = Some(TextNode::new(value_content, value_loc));
} else if matches!(quote, QuoteType::Double | QuoteType::Single) {
let empty_loc = self.create_loc(end, end);
attr_node.value = Some(TextNode::new("", empty_loc));
}
if let Some(ref mut current) = self.current_element {
let boxed = Box::new_in(attr_node, self.allocator);
current.props.push(PropNode::Attribute(boxed));
}
}
fn finish_directive(&mut self, dir: CurrentDirective<'a>, _quote: QuoteType, end: usize) {
let loc = self.create_loc(dir.name_start, end);
let mut dir_node = DirectiveNode::new(self.allocator, dir.name.clone(), loc);
dir_node.raw_name = Some(dir.raw_name);
let shorthand_exp = if dir.name == "bind" && dir.value_start.is_none() {
if let Some((ref arg_content, arg_start, arg_end, false)) = dir.arg {
Some((vize_carton::camelize(arg_content), arg_start, arg_end))
} else {
None
}
} else {
None
};
if let Some((arg_content, arg_start, arg_end, is_dynamic)) = dir.arg {
let arg_loc = self.create_loc(arg_start, arg_end);
let mut arg_expr = SimpleExpressionNode::new(arg_content, !is_dynamic, arg_loc);
if is_dynamic {
arg_expr.const_type = ConstantType::NotConstant;
}
let arg_boxed = Box::new_in(arg_expr, self.allocator);
dir_node.arg = Some(ExpressionNode::Simple(arg_boxed));
}
for (mod_content, mod_start, mod_end) in dir.modifiers {
let mod_loc = self.create_loc(mod_start, mod_end);
let mod_expr = SimpleExpressionNode::new(mod_content, true, mod_loc);
dir_node.modifiers.push(mod_expr);
}
if let (Some(v_start), Some(v_end)) = (dir.value_start, dir.value_end) {
let exp_content = self.get_source(v_start, v_end);
let exp_loc = self.create_loc(v_start, v_end);
let exp_node = SimpleExpressionNode::new(exp_content, false, exp_loc);
let exp_boxed = Box::new_in(exp_node, self.allocator);
dir_node.exp = Some(ExpressionNode::Simple(exp_boxed));
} else if let Some((camelized, s_start, s_end)) = shorthand_exp {
let exp_loc = self.create_loc(s_start, s_end);
let exp_node = SimpleExpressionNode::new(&*camelized, false, exp_loc);
let exp_boxed = Box::new_in(exp_node, self.allocator);
dir_node.exp = Some(ExpressionNode::Simple(exp_boxed));
dir_node.shorthand = true;
}
if let Some(ref mut current) = self.current_element {
let boxed = Box::new_in(dir_node, self.allocator);
current.props.push(PropNode::Directive(boxed));
}
}
}