Skip to content

Commit

Permalink
Expand WordUnit::DoubleQuote
Browse files Browse the repository at this point in the history
  • Loading branch information
magicant committed Mar 26, 2022
1 parent e1f2cba commit 0c6c06c
Showing 1 changed file with 153 additions and 3 deletions.
156 changes: 153 additions & 3 deletions yash-semantics/src/expansion/initial/word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use super::super::Error;
use super::Env;
use super::Expand;
use super::Phrase;
use super::QuickExpand::{self, Ready};
use super::QuickExpand::{self, Interim, Ready};
use async_trait::async_trait;
use yash_syntax::syntax::Word;
use yash_syntax::syntax::WordUnit::{self, *};
Expand All @@ -46,6 +46,37 @@ fn expand_single_quote(value: &str) -> Phrase {
Phrase::Field(field)
}

/// Add double quotes around each field in the phrase.
///
/// This function sets the `is_quoted` flag of the characters in the phrase.
fn double_quote(phrase: &mut Phrase) {
const QUOTE: AttrChar = AttrChar {
value: '"',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};

fn quote_field(chars: &mut Vec<AttrChar>) {
for c in chars.iter_mut() {
c.is_quoted = true;
}
chars.reserve_exact(2);
chars.insert(0, QUOTE);
chars.push(QUOTE);
}

match phrase {
Phrase::Char(c) => {
let is_quoted = true;
let c = AttrChar { is_quoted, ..*c };
*phrase = Phrase::Field(vec![QUOTE, c, QUOTE]);
}
Phrase::Field(chars) => quote_field(chars),
Phrase::Full(fields) => fields.iter_mut().for_each(quote_field),
}
}

/// Expands the word unit.
///
/// TODO Elaborate
Expand All @@ -57,7 +88,8 @@ impl Expand for WordUnit {
match self {
Unquoted(text_unit) => text_unit.quick_expand(env),
SingleQuote(value) => Ready(Ok(expand_single_quote(value))),
DoubleQuote(_text) => todo!(),
// TODO Can we call text.quick_expand here?
DoubleQuote(_text) => Interim(()),
Tilde(_name) => todo!(),
}
}
Expand All @@ -66,7 +98,14 @@ impl Expand for WordUnit {
match self {
Unquoted(text_unit) => text_unit.async_expand(env, ()).await,
SingleQuote(_value) => unimplemented!("async_expand not expecting SingleQuote"),
DoubleQuote(_text) => todo!(),
DoubleQuote(text) => {
let mut phrase = match text.quick_expand(env) {
Ready(result) => result,
Interim(interim) => text.async_expand(env, interim).await,
}?;
double_quote(&mut phrase);
Ok(phrase)
}
Tilde(_name) => todo!(),
}
}
Expand Down Expand Up @@ -98,6 +137,95 @@ impl Expand for Word {
mod tests {
use super::*;
use assert_matches::assert_matches;
use futures_util::FutureExt;
use yash_syntax::syntax::Text;
use yash_syntax::syntax::TextUnit;

#[test]
fn double_quote_char() {
let mut phrase = Phrase::Char(AttrChar {
value: 'C',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
});
double_quote(&mut phrase);
let quote = AttrChar {
value: '"',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
let c = AttrChar {
value: 'C',
origin: Origin::SoftExpansion,
is_quoted: true,
is_quoting: false,
};
assert_eq!(phrase, Phrase::Field(vec![quote, c, quote]));
}

#[test]
fn double_quote_field() {
let mut phrase = Phrase::Field(vec![]);
double_quote(&mut phrase);
let quote = AttrChar {
value: '"',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
assert_eq!(phrase, Phrase::Field(vec![quote, quote]));

let i = AttrChar {
value: 'i',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
let f = AttrChar {
value: 'f',
origin: Origin::Literal,
is_quoted: false,
is_quoting: false,
};
phrase = Phrase::Field(vec![i, f]);
double_quote(&mut phrase);
let is_quoted = true;
let i = AttrChar { is_quoted, ..i };
let f = AttrChar { is_quoted, ..f };
assert_eq!(phrase, Phrase::Field(vec![quote, i, f, quote]));
}

#[test]
fn double_quote_full() {
let mut phrase = Phrase::Full(vec![]);
double_quote(&mut phrase);
assert_eq!(phrase, Phrase::zero_fields());

let a = AttrChar {
value: 'a',
origin: Origin::HardExpansion,
is_quoted: false,
is_quoting: false,
};
let b = AttrChar { value: 'b', ..a };
phrase = Phrase::Full(vec![vec![a], vec![b]]);
double_quote(&mut phrase);
let quote = AttrChar {
value: '"',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
let is_quoted = true;
let a = AttrChar { is_quoted, ..a };
let b = AttrChar { is_quoted, ..b };
assert_eq!(
phrase,
Phrase::Full(vec![vec![quote, a, quote], vec![quote, b, quote]])
);
}

#[test]
fn unquoted() {
Expand Down Expand Up @@ -145,4 +273,26 @@ mod tests {
let o = AttrChar { value: 'o', ..d };
assert_eq!(result, Phrase::Field(vec![q, d, o, q]));
}

#[test]
fn async_double_quote() {
let mut env = yash_env::Env::new_virtual();
let mut env = Env::new(&mut env);
let unit = DoubleQuote(Text(vec![TextUnit::Literal('X')]));
assert_matches!(unit.quick_expand(&mut env), Interim(()));
let result = unit.async_expand(&mut env, ()).now_or_never().unwrap();
let quote = AttrChar {
value: '"',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
let x = AttrChar {
value: 'X',
origin: Origin::Literal,
is_quoted: true,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Field(vec![quote, x, quote])));
}
}

0 comments on commit 0c6c06c

Please sign in to comment.