properly parse and emit bracketed lists
This commit is contained in:
parent
9233b1d2ba
commit
981bf27cb8
@ -18,7 +18,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
let mut channels = match arg!(args, 0, "channels") {
|
||||||
Value::List(v, _) => v,
|
Value::List(v, ..) => v,
|
||||||
_ => return Err("Missing argument $channels.".into()),
|
_ => return Err("Missing argument $channels.".into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
let mut channels = match arg!(args, 0, "channels") {
|
||||||
Value::List(v, _) => v,
|
Value::List(v, ..) => v,
|
||||||
_ => return Err("Missing argument $channels.".into()),
|
_ => return Err("Missing argument $channels.".into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
let mut channels = match arg!(args, 0, "channels") {
|
||||||
Value::List(v, _) => v,
|
Value::List(v, ..) => v,
|
||||||
_ => return Err("Missing argument $channels.".into()),
|
_ => return Err("Missing argument $channels.".into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
let mut channels = match arg!(args, 0, "channels") {
|
||||||
Value::List(v, _) => v,
|
Value::List(v, ..) => v,
|
||||||
_ => return Err("Missing argument $channels.".into()),
|
_ => return Err("Missing argument $channels.".into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||||
|
|
||||||
use super::Builtin;
|
use super::Builtin;
|
||||||
use crate::common::{ListSeparator, QuoteKind};
|
use crate::common::{Brackets, ListSeparator, QuoteKind};
|
||||||
use crate::unit::Unit;
|
use crate::unit::Unit;
|
||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
Box::new(|args, _| {
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let len = match arg!(args, 0, "list") {
|
let len = match arg!(args, 0, "list") {
|
||||||
Value::List(v, _) => Number::from(v.len()),
|
Value::List(v, ..) => Number::from(v.len()),
|
||||||
_ => Number::one(),
|
_ => Number::one(),
|
||||||
};
|
};
|
||||||
Ok(Value::Dimension(len, Unit::None))
|
Ok(Value::Dimension(len, Unit::None))
|
||||||
@ -24,7 +24,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
Box::new(|args, _| {
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let list = match arg!(args, 0, "list") {
|
let list = match arg!(args, 0, "list") {
|
||||||
Value::List(v, _) => v,
|
Value::List(v, ..) => v,
|
||||||
v => vec![v],
|
v => vec![v],
|
||||||
};
|
};
|
||||||
let n = match arg!(args, 1, "n") {
|
let n = match arg!(args, 1, "n") {
|
||||||
@ -62,7 +62,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
Ok(Value::Ident(
|
Ok(Value::Ident(
|
||||||
match arg!(args, 0, "list") {
|
match arg!(args, 0, "list") {
|
||||||
Value::List(_, sep) => sep.name(),
|
Value::List(_, sep, ..) => sep.name(),
|
||||||
_ => ListSeparator::Space.name(),
|
_ => ListSeparator::Space.name(),
|
||||||
}
|
}
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
@ -75,7 +75,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
Box::new(|args, _| {
|
Box::new(|args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let (mut list, sep) = match arg!(args, 0, "list") {
|
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),
|
v => (vec![v], ListSeparator::Space),
|
||||||
};
|
};
|
||||||
let n = match arg!(args, 1, "n") {
|
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;
|
list[len - n.abs().to_integer().to_usize().unwrap()] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::List(list, sep))
|
Ok(Value::List(list, sep, Brackets::None))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
f.insert(
|
f.insert(
|
||||||
@ -115,7 +115,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
Box::new(|args, _| {
|
Box::new(|args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let (mut list, sep) = match arg!(args, 0, "list") {
|
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),
|
v => (vec![v], ListSeparator::Space),
|
||||||
};
|
};
|
||||||
let val = arg!(args, 1, "val");
|
let val = arg!(args, 1, "val");
|
||||||
@ -137,16 +137,16 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
list.push(val);
|
list.push(val);
|
||||||
|
|
||||||
Ok(Value::List(list, sep))
|
Ok(Value::List(list, sep, Brackets::None))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
f.insert(
|
f.insert(
|
||||||
"join".to_owned(),
|
"join".to_owned(),
|
||||||
Box::new(|args, _| {
|
Box::new(|args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let (mut list1, sep1) = match arg!(args, 0, "list") {
|
let (mut list1, sep1, brackets) = match arg!(args, 0, "list") {
|
||||||
Value::List(v, sep) => (v, sep),
|
Value::List(v, sep, brackets) => (v, sep, brackets),
|
||||||
v => (vec![v], ListSeparator::Space),
|
v => (vec![v], ListSeparator::Space, Brackets::None),
|
||||||
};
|
};
|
||||||
let list2 = match arg!(args, 1, "list") {
|
let list2 = match arg!(args, 1, "list") {
|
||||||
Value::List(v, ..) => v,
|
Value::List(v, ..) => v,
|
||||||
@ -176,7 +176,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
list1.extend(list2);
|
list1.extend(list2);
|
||||||
|
|
||||||
Ok(Value::List(list1, sep))
|
Ok(Value::List(list1, sep, brackets))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum ListSeparator {
|
pub(crate) enum ListSeparator {
|
||||||
Space,
|
Space,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Write};
|
|||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::common::{ListSeparator, Op, QuoteKind};
|
use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
use crate::unit::Unit;
|
use crate::unit::Unit;
|
||||||
pub(crate) use number::Number;
|
pub(crate) use number::Number;
|
||||||
@ -18,7 +18,7 @@ pub(crate) enum Value {
|
|||||||
False,
|
False,
|
||||||
Null,
|
Null,
|
||||||
Dimension(Number, Unit),
|
Dimension(Number, Unit),
|
||||||
List(Vec<Value>, ListSeparator),
|
List(Vec<Value>, ListSeparator, Brackets),
|
||||||
Color(Color),
|
Color(Color),
|
||||||
UnaryOp(Op, Box<Value>),
|
UnaryOp(Op, Box<Value>),
|
||||||
BinaryOp(Box<Value>, Op, Box<Value>),
|
BinaryOp(Box<Value>, Op, Box<Value>),
|
||||||
@ -39,14 +39,24 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
_ => write!(f, "{}{}", num, unit),
|
_ => write!(f, "{}{}", num, unit),
|
||||||
},
|
},
|
||||||
Self::List(vals, sep) => write!(
|
Self::List(vals, sep, brackets) => match brackets {
|
||||||
|
Brackets::None => write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
vals.iter()
|
vals.iter()
|
||||||
.map(std::string::ToString::to_string)
|
.map(std::string::ToString::to_string)
|
||||||
.collect::<Vec<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::Color(c) => write!(f, "{}", c),
|
||||||
Self::UnaryOp(..) | Self::BinaryOp(..) => write!(
|
Self::UnaryOp(..) | Self::BinaryOp(..) => write!(
|
||||||
f,
|
f,
|
||||||
|
@ -8,7 +8,7 @@ use num_traits::pow;
|
|||||||
use crate::args::eat_call_args;
|
use crate::args::eat_call_args;
|
||||||
use crate::builtin::GLOBAL_FUNCTIONS;
|
use crate::builtin::GLOBAL_FUNCTIONS;
|
||||||
use crate::color::Color;
|
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::error::SassResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::selector::Selector;
|
use crate::selector::Selector;
|
||||||
@ -82,19 +82,23 @@ impl Value {
|
|||||||
None => return Ok(left),
|
None => return Ok(left),
|
||||||
};
|
};
|
||||||
match next.kind {
|
match next.kind {
|
||||||
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseParen) => {
|
TokenKind::Symbol(Symbol::SemiColon)
|
||||||
Ok(left)
|
| TokenKind::Symbol(Symbol::CloseParen)
|
||||||
}
|
| TokenKind::Symbol(Symbol::CloseSquareBrace) => Ok(left),
|
||||||
TokenKind::Symbol(Symbol::Comma) => {
|
TokenKind::Symbol(Symbol::Comma) => {
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
let right = Self::from_tokens(toks, scope, super_selector)?;
|
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];
|
let mut v2 = vec![left];
|
||||||
v2.extend(v);
|
v2.extend(v);
|
||||||
Ok(Value::List(v2, ListSeparator::Comma))
|
Ok(Value::List(v2, ListSeparator::Comma, Brackets::None))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::List(vec![left, right], ListSeparator::Comma))
|
Ok(Value::List(
|
||||||
|
vec![left, right],
|
||||||
|
ListSeparator::Comma,
|
||||||
|
Brackets::None,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::Plus)
|
TokenKind::Symbol(Symbol::Plus)
|
||||||
@ -120,12 +124,16 @@ impl Value {
|
|||||||
_ => {
|
_ => {
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
let right = Self::from_tokens(toks, scope, super_selector)?;
|
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];
|
let mut v2 = vec![left];
|
||||||
v2.extend(v);
|
v2.extend(v);
|
||||||
Ok(Value::List(v2, ListSeparator::Space))
|
Ok(Value::List(v2, ListSeparator::Space, Brackets::None))
|
||||||
} else {
|
} 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);
|
devour_whitespace_or_comment(toks);
|
||||||
if toks.peek().unwrap().is_symbol(Symbol::CloseParen) {
|
if toks.peek().unwrap().is_symbol(Symbol::CloseParen) {
|
||||||
toks.next();
|
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 val = Self::from_tokens(toks, scope, super_selector)?;
|
||||||
let next = toks.next();
|
let next = toks.next();
|
||||||
@ -265,6 +277,15 @@ impl Value {
|
|||||||
| q @ TokenKind::Symbol(Symbol::SingleQuote) => {
|
| q @ TokenKind::Symbol(Symbol::SingleQuote) => {
|
||||||
parse_quoted_string(toks, scope, &q, super_selector)
|
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::Variable(ref v) => Ok(scope.get_var(v)?),
|
||||||
TokenKind::Interpolation => {
|
TokenKind::Interpolation => {
|
||||||
let mut s = parse_interpolation(toks, scope, super_selector)?.to_string();
|
let mut s = parse_interpolation(toks, scope, super_selector)?.to_string();
|
||||||
|
@ -140,8 +140,12 @@ test!(
|
|||||||
"a {\n color: join((a, b), (c, d), space);\n}\n",
|
"a {\n color: join((a, b), (c, d), space);\n}\n",
|
||||||
"a {\n color: a b c d;\n}\n"
|
"a {\n color: a b c d;\n}\n"
|
||||||
);
|
);
|
||||||
// test!(
|
test!(
|
||||||
// join_bracketed,
|
join_bracketed,
|
||||||
// "a {\n color: join([a], b);\n}\n",
|
"a {\n color: join([a], b);\n}\n",
|
||||||
// "a {\n color: [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");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user