use crate::nodes::{
Identifier, LiteralExpression, LiteralTable, StringExpression, Token, Trivia,
TupleArgumentsTokens,
};
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Attributes {
attributes: Vec<Attribute>,
}
impl Attributes {
pub fn new() -> Self {
Self {
attributes: Vec::new(),
}
}
pub fn with_attribute(mut self, attribute: impl Into<Attribute>) -> Self {
self.attributes.push(attribute.into());
self
}
pub fn append_attribute(&mut self, attribute: impl Into<Attribute>) {
let attribute = attribute.into();
if let Attribute::Group(list) = &attribute {
if list.is_empty() {
return;
}
}
self.attributes.push(attribute);
}
pub fn iter_attributes(&self) -> impl Iterator<Item = &Attribute> {
self.attributes.iter()
}
pub fn iter_mut_attributes(&mut self) -> impl Iterator<Item = &mut Attribute> {
self.attributes.iter_mut()
}
pub fn clear_attributes(&mut self) {
self.attributes.clear();
}
pub fn is_empty(&self) -> bool {
self.attributes.is_empty()
}
pub fn len(&self) -> usize {
self.attributes.len()
}
pub fn has_attribute(&self, name: &str) -> bool {
self.attributes.iter().any(|attr| match attr {
Attribute::Name(named) => named.get_identifier().get_name() == name,
Attribute::Group(group) => group.has_attribute(name),
})
}
pub fn filter_attributes<F>(&mut self, predicate: F)
where
F: Fn(&Attribute) -> bool,
{
self.attributes.retain(predicate);
}
pub fn filter_mut_attributes<F>(&mut self, predicate: F)
where
F: FnMut(&mut Attribute) -> bool,
{
self.attributes.retain_mut(predicate);
}
super::impl_token_fns!(iter = [attributes]);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Attribute {
Name(NamedAttribute),
Group(AttributeGroup),
}
impl Attribute {
pub fn clear_comments(&mut self) {
match self {
Self::Name(name) => name.clear_comments(),
Self::Group(list) => list.clear_comments(),
}
}
pub fn clear_whitespaces(&mut self) {
match self {
Self::Name(name) => name.clear_whitespaces(),
Self::Group(list) => list.clear_whitespaces(),
}
}
pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
match self {
Self::Name(name) => name.replace_referenced_tokens(code),
Self::Group(list) => list.replace_referenced_tokens(code),
}
}
pub(crate) fn shift_token_line(&mut self, amount: isize) {
match self {
Self::Name(name) => name.shift_token_line(amount),
Self::Group(list) => list.shift_token_line(amount),
}
}
pub(crate) fn filter_comments(&mut self, filter: impl Fn(&Trivia) -> bool) {
match self {
Self::Name(name) => name.filter_comments(filter),
Self::Group(list) => list.filter_comments(filter),
}
}
}
impl From<AttributeGroup> for Attribute {
fn from(v: AttributeGroup) -> Self {
Self::Group(v)
}
}
impl From<AttributeGroupElement> for Attribute {
fn from(v: AttributeGroupElement) -> Self {
Self::Group(AttributeGroup::new(v))
}
}
impl From<NamedAttribute> for Attribute {
fn from(v: NamedAttribute) -> Self {
Self::Name(v)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NamedAttribute {
name: Identifier,
token: Option<Token>,
}
impl NamedAttribute {
pub fn new(name: impl Into<Identifier>) -> Self {
Self {
name: name.into(),
token: None,
}
}
pub fn with_token(mut self, token: Token) -> Self {
self.token = Some(token);
self
}
#[inline]
pub fn set_token(&mut self, token: Token) {
self.token = Some(token);
}
#[inline]
pub fn get_token(&self) -> Option<&Token> {
self.token.as_ref()
}
#[inline]
pub fn get_identifier(&self) -> &Identifier {
&self.name
}
#[inline]
pub fn mutate_identifier(&mut self) -> &mut Identifier {
&mut self.name
}
super::impl_token_fns!(target = [name] iter = [token]);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttributeGroup {
attributes: Vec<AttributeGroupElement>,
tokens: Option<AttributeGroupTokens>,
}
impl AttributeGroup {
pub fn new(attribute: impl Into<AttributeGroupElement>) -> Self {
Self {
attributes: vec![attribute.into()],
tokens: None,
}
}
pub fn with_attribute(mut self, attribute: impl Into<AttributeGroupElement>) -> Self {
self.attributes.push(attribute.into());
self
}
pub fn append_attribute(&mut self, attribute: impl Into<AttributeGroupElement>) {
self.attributes.push(attribute.into());
}
pub fn iter_attributes(&self) -> impl Iterator<Item = &AttributeGroupElement> {
self.attributes.iter()
}
pub fn iter_mut_attributes(&mut self) -> impl Iterator<Item = &mut AttributeGroupElement> {
self.attributes.iter_mut()
}
pub fn with_tokens(mut self, tokens: AttributeGroupTokens) -> Self {
self.tokens = Some(tokens);
self
}
pub fn set_tokens(&mut self, tokens: AttributeGroupTokens) {
self.tokens = Some(tokens);
}
pub fn get_tokens(&self) -> Option<&AttributeGroupTokens> {
self.tokens.as_ref()
}
pub fn mutate_tokens(&mut self) -> Option<&mut AttributeGroupTokens> {
self.tokens.as_mut()
}
pub fn is_empty(&self) -> bool {
self.attributes.is_empty()
}
pub fn len(&self) -> usize {
self.attributes.len()
}
pub fn has_attribute(&self, name: &str) -> bool {
self.attributes
.iter()
.any(|elem| elem.name().get_name() == name)
}
pub fn remove(&mut self, index: usize) {
if index < self.attributes.len() {
self.attributes.remove(index);
if let Some(tokens) = &mut self.tokens {
if index < tokens.separators.len() {
tokens.separators.remove(index);
}
}
}
}
pub fn filter_attributes<F>(&mut self, mut predicate: F)
where
F: FnMut(&AttributeGroupElement) -> bool,
{
let mut i = 0;
while i < self.attributes.len() {
if predicate(&self.attributes[i]) {
i += 1;
} else {
self.remove(i);
}
}
}
pub fn filter_mut_attributes<F>(&mut self, mut predicate: F)
where
F: FnMut(&mut AttributeGroupElement) -> bool,
{
let mut i = 0;
while i < self.attributes.len() {
if predicate(&mut self.attributes[i]) {
i += 1;
} else {
self.remove(i);
}
}
}
super::impl_token_fns!(iter = [tokens, attributes]);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttributeGroupTokens {
pub opening_attribute_list: Token,
pub closing_bracket: Token,
pub separators: Vec<Token>,
}
impl AttributeGroupTokens {
super::impl_token_fns!(
target = [opening_attribute_list, closing_bracket]
iter = [separators]
);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttributeGroupElement {
name: Identifier,
arguments: Option<AttributeArguments>,
}
impl AttributeGroupElement {
pub fn new(name: impl Into<Identifier>) -> Self {
Self {
name: name.into(),
arguments: None,
}
}
pub fn with_arguments(mut self, arguments: impl Into<AttributeArguments>) -> Self {
self.arguments = Some(arguments.into());
self
}
pub fn name(&self) -> &Identifier {
&self.name
}
pub fn mutate_name(&mut self) -> &mut Identifier {
&mut self.name
}
pub fn get_arguments(&self) -> Option<&AttributeArguments> {
self.arguments.as_ref()
}
pub fn mutate_arguments(&mut self) -> Option<&mut AttributeArguments> {
self.arguments.as_mut()
}
pub fn set_arguments(&mut self, arguments: impl Into<AttributeArguments>) {
self.arguments = Some(arguments.into());
}
pub fn remove_arguments(&mut self) {
self.arguments = None;
}
super::impl_token_fns!(target = [name] iter = [arguments]);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AttributeArguments {
Tuple(AttributeTupleArguments),
String(StringExpression),
Table(LiteralTable),
}
impl AttributeArguments {
pub fn clear_comments(&mut self) {
match self {
Self::Tuple(tuple) => tuple.clear_comments(),
Self::String(string) => string.clear_comments(),
Self::Table(table) => table.clear_comments(),
}
}
pub fn clear_whitespaces(&mut self) {
match self {
Self::Tuple(tuple) => tuple.clear_whitespaces(),
Self::String(string) => string.clear_whitespaces(),
Self::Table(table) => table.clear_whitespaces(),
}
}
pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
match self {
Self::Tuple(tuple) => tuple.replace_referenced_tokens(code),
Self::String(string) => string.replace_referenced_tokens(code),
Self::Table(table) => table.replace_referenced_tokens(code),
}
}
pub(crate) fn shift_token_line(&mut self, amount: isize) {
match self {
Self::Tuple(tuple) => tuple.shift_token_line(amount),
Self::String(string) => string.shift_token_line(amount),
Self::Table(table) => table.shift_token_line(amount),
}
}
pub(crate) fn filter_comments(&mut self, filter: impl Fn(&Trivia) -> bool) {
match self {
Self::Tuple(tuple) => tuple.filter_comments(filter),
Self::String(string) => string.filter_comments(filter),
Self::Table(table) => table.filter_comments(filter),
}
}
}
impl From<LiteralTable> for AttributeArguments {
fn from(v: LiteralTable) -> Self {
Self::Table(v)
}
}
impl From<StringExpression> for AttributeArguments {
fn from(v: StringExpression) -> Self {
Self::String(v)
}
}
impl From<AttributeTupleArguments> for AttributeArguments {
fn from(v: AttributeTupleArguments) -> Self {
Self::Tuple(v)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AttributeTupleArguments {
values: Vec<LiteralExpression>,
tokens: Option<TupleArgumentsTokens>,
}
impl AttributeTupleArguments {
pub fn with_value(mut self, value: impl Into<LiteralExpression>) -> Self {
self.push(value.into());
self
}
pub fn push(&mut self, argument: impl Into<LiteralExpression>) {
let argument = argument.into();
let initial_len = self.values.len();
self.values.push(argument);
if initial_len != 0 {
if let Some(tokens) = &mut self.tokens {
if tokens.commas.len() == initial_len - 1 {
tokens.commas.push(Token::from_content(","));
}
}
}
}
pub fn insert(&mut self, index: usize, argument: impl Into<LiteralExpression>) {
if index >= self.values.len() {
self.push(argument.into());
} else {
self.values.insert(index, argument.into());
if let Some(tokens) = &mut self.tokens {
if index <= tokens.commas.len() {
tokens.commas.insert(index, Token::from_content(","));
}
}
}
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn iter_values(&self) -> impl Iterator<Item = &LiteralExpression> {
self.values.iter()
}
pub fn iter_mut_values(&mut self) -> impl Iterator<Item = &mut LiteralExpression> {
self.values.iter_mut()
}
pub fn get_tokens(&self) -> Option<&TupleArgumentsTokens> {
self.tokens.as_ref()
}
pub fn set_tokens(&mut self, tokens: TupleArgumentsTokens) {
self.tokens = Some(tokens);
}
pub fn with_tokens(mut self, tokens: TupleArgumentsTokens) -> Self {
self.tokens = Some(tokens);
self
}
super::impl_token_fns!(iter = [tokens]);
}