properly parse and emit bracketed lists

This commit is contained in:
ConnorSkees 2020-03-23 19:56:24 -04:00
parent 9233b1d2ba
commit 981bf27cb8
7 changed files with 83 additions and 42 deletions

View File

@ -18,7 +18,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
Value::List(v, ..) => v,
_ => return Err("Missing argument $channels.".into()),
};
@ -96,7 +96,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
Value::List(v, ..) => v,
_ => return Err("Missing argument $channels.".into()),
};

View File

@ -17,7 +17,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
Value::List(v, ..) => v,
_ => return Err("Missing argument $channels.".into()),
};
@ -139,7 +139,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
Value::List(v, ..) => v,
_ => return Err("Missing argument $channels.".into()),
};

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use num_traits::{One, Signed, ToPrimitive, Zero};
use super::Builtin;
use crate::common::{ListSeparator, QuoteKind};
use crate::common::{Brackets, ListSeparator, QuoteKind};
use crate::unit::Unit;
use crate::value::{Number, Value};
@ -13,7 +13,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Box::new(|args, _| {
max_args!(args, 1);
let len = match arg!(args, 0, "list") {
Value::List(v, _) => Number::from(v.len()),
Value::List(v, ..) => Number::from(v.len()),
_ => Number::one(),
};
Ok(Value::Dimension(len, Unit::None))
@ -24,7 +24,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Box::new(|args, _| {
max_args!(args, 2);
let list = match arg!(args, 0, "list") {
Value::List(v, _) => v,
Value::List(v, ..) => v,
v => vec![v],
};
let n = match arg!(args, 1, "n") {
@ -62,7 +62,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
max_args!(args, 1);
Ok(Value::Ident(
match arg!(args, 0, "list") {
Value::List(_, sep) => sep.name(),
Value::List(_, sep, ..) => sep.name(),
_ => ListSeparator::Space.name(),
}
.to_owned(),
@ -75,7 +75,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Box::new(|args, _| {
max_args!(args, 3);
let (mut list, sep) = match arg!(args, 0, "list") {
Value::List(v, sep) => (v, sep),
Value::List(v, sep, ..) => (v, sep),
v => (vec![v], ListSeparator::Space),
};
let n = match arg!(args, 1, "n") {
@ -107,7 +107,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
list[len - n.abs().to_integer().to_usize().unwrap()] = val;
}
Ok(Value::List(list, sep))
Ok(Value::List(list, sep, Brackets::None))
}),
);
f.insert(
@ -115,7 +115,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Box::new(|args, _| {
max_args!(args, 3);
let (mut list, sep) = match arg!(args, 0, "list") {
Value::List(v, sep) => (v, sep),
Value::List(v, sep, ..) => (v, sep),
v => (vec![v], ListSeparator::Space),
};
let val = arg!(args, 1, "val");
@ -137,16 +137,16 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
list.push(val);
Ok(Value::List(list, sep))
Ok(Value::List(list, sep, Brackets::None))
}),
);
f.insert(
"join".to_owned(),
Box::new(|args, _| {
max_args!(args, 3);
let (mut list1, sep1) = match arg!(args, 0, "list") {
Value::List(v, sep) => (v, sep),
v => (vec![v], ListSeparator::Space),
let (mut list1, sep1, brackets) = match arg!(args, 0, "list") {
Value::List(v, sep, brackets) => (v, sep, brackets),
v => (vec![v], ListSeparator::Space, Brackets::None),
};
let list2 = match arg!(args, 1, "list") {
Value::List(v, ..) => v,
@ -176,7 +176,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
list1.extend(list2);
Ok(Value::List(list1, sep))
Ok(Value::List(list1, sep, brackets))
}),
);
}

View File

@ -383,6 +383,12 @@ impl Display for QuoteKind {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Brackets {
None,
Bracketed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ListSeparator {
Space,

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Write};
use std::iter::Iterator;
use crate::color::Color;
use crate::common::{ListSeparator, Op, QuoteKind};
use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
use crate::error::SassResult;
use crate::unit::Unit;
pub(crate) use number::Number;
@ -18,7 +18,7 @@ pub(crate) enum Value {
False,
Null,
Dimension(Number, Unit),
List(Vec<Value>, ListSeparator),
List(Vec<Value>, ListSeparator, Brackets),
Color(Color),
UnaryOp(Op, Box<Value>),
BinaryOp(Box<Value>, Op, Box<Value>),
@ -39,14 +39,24 @@ impl Display for Value {
}
_ => write!(f, "{}{}", num, unit),
},
Self::List(vals, sep) => write!(
Self::List(vals, sep, brackets) => match brackets {
Brackets::None => write!(
f,
"{}",
vals.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<String>>()
.join(sep.as_str())
.join(sep.as_str()),
),
Brackets::Bracketed => write!(
f,
"[{}]",
vals.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<String>>()
.join(sep.as_str()),
),
},
Self::Color(c) => write!(f, "{}", c),
Self::UnaryOp(..) | Self::BinaryOp(..) => write!(
f,

View File

@ -8,7 +8,7 @@ use num_traits::pow;
use crate::args::eat_call_args;
use crate::builtin::GLOBAL_FUNCTIONS;
use crate::color::Color;
use crate::common::{Keyword, ListSeparator, Op, QuoteKind, Symbol};
use crate::common::{Brackets, Keyword, ListSeparator, Op, QuoteKind, Symbol};
use crate::error::SassResult;
use crate::scope::Scope;
use crate::selector::Selector;
@ -82,19 +82,23 @@ impl Value {
None => return Ok(left),
};
match next.kind {
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseParen) => {
Ok(left)
}
TokenKind::Symbol(Symbol::SemiColon)
| TokenKind::Symbol(Symbol::CloseParen)
| TokenKind::Symbol(Symbol::CloseSquareBrace) => Ok(left),
TokenKind::Symbol(Symbol::Comma) => {
toks.next();
devour_whitespace_or_comment(toks);
let right = Self::from_tokens(toks, scope, super_selector)?;
if let Value::List(v, ListSeparator::Comma) = right {
if let Value::List(v, ListSeparator::Comma, Brackets::None) = right {
let mut v2 = vec![left];
v2.extend(v);
Ok(Value::List(v2, ListSeparator::Comma))
Ok(Value::List(v2, ListSeparator::Comma, Brackets::None))
} else {
Ok(Value::List(vec![left, right], ListSeparator::Comma))
Ok(Value::List(
vec![left, right],
ListSeparator::Comma,
Brackets::None,
))
}
}
TokenKind::Symbol(Symbol::Plus)
@ -120,12 +124,16 @@ impl Value {
_ => {
devour_whitespace_or_comment(toks);
let right = Self::from_tokens(toks, scope, super_selector)?;
if let Value::List(v, ListSeparator::Space) = right {
if let Value::List(v, ListSeparator::Space, Brackets::None) = right {
let mut v2 = vec![left];
v2.extend(v);
Ok(Value::List(v2, ListSeparator::Space))
Ok(Value::List(v2, ListSeparator::Space, Brackets::None))
} else {
Ok(Value::List(vec![left, right], ListSeparator::Space))
Ok(Value::List(
vec![left, right],
ListSeparator::Space,
Brackets::None,
))
}
}
}
@ -184,7 +192,11 @@ impl Value {
devour_whitespace_or_comment(toks);
if toks.peek().unwrap().is_symbol(Symbol::CloseParen) {
toks.next();
return Ok(Value::List(Vec::new(), ListSeparator::Space));
return Ok(Value::List(
Vec::new(),
ListSeparator::Space,
Brackets::None,
));
}
let val = Self::from_tokens(toks, scope, super_selector)?;
let next = toks.next();
@ -265,6 +277,15 @@ impl Value {
| q @ TokenKind::Symbol(Symbol::SingleQuote) => {
parse_quoted_string(toks, scope, &q, super_selector)
}
TokenKind::Symbol(Symbol::OpenSquareBrace) => {
let inner = Self::from_tokens(toks, scope, super_selector)?;
devour_whitespace_or_comment(toks);
toks.next();
Ok(match inner {
Value::List(v, sep, ..) => Value::List(v, sep, Brackets::Bracketed),
v => Value::List(vec![v], ListSeparator::Space, Brackets::Bracketed),
})
}
TokenKind::Variable(ref v) => Ok(scope.get_var(v)?),
TokenKind::Interpolation => {
let mut s = parse_interpolation(toks, scope, super_selector)?.to_string();

View File

@ -140,8 +140,12 @@ test!(
"a {\n color: join((a, b), (c, d), space);\n}\n",
"a {\n color: a b c d;\n}\n"
);
// test!(
// join_bracketed,
// "a {\n color: join([a], b);\n}\n",
// "a {\n color: [a b];\n}\n"
// );
test!(
join_bracketed,
"a {\n color: join([a], b);\n}\n",
"a {\n color: [a b];\n}\n"
);
test!(bracketed_ident, "a {\n color: [a];\n}\n");
test!(bracketed_space_list, "a {\n color: [a b];\n}\n");
test!(bracketed_comma_list, "a {\n color: [a, b];\n}\n");
test!(bracketed_as_space_list, "a {\n color: [a b] c;\n}\n");