differentiate named and positional args
This commit is contained in:
parent
c16b8f448b
commit
f9fc0ed8cb
46
src/args.rs
46
src/args.rs
@ -28,16 +28,26 @@ impl FuncArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, std::default::Default)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct CallArgs(pub HashMap<String, Value>);
|
pub(crate) struct CallArgs(HashMap<CallArg, Value>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum CallArg {
|
||||||
|
Named(String),
|
||||||
|
Positional(usize),
|
||||||
|
}
|
||||||
|
|
||||||
impl CallArgs {
|
impl CallArgs {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CallArgs(HashMap::new())
|
CallArgs(HashMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, val: &str) -> Option<&Value> {
|
pub fn get_named(&self, val: String) -> Option<&Value> {
|
||||||
self.0.get(val)
|
self.0.get(&CallArg::Named(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_positional(&self, val: usize) -> Option<&Value> {
|
||||||
|
self.0.get(&CallArg::Positional(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
@ -48,8 +58,12 @@ impl CallArgs {
|
|||||||
self.0.len() == 0
|
self.0.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, s: &str) -> Option<Value> {
|
pub fn remove_named(&mut self, s: String) -> Option<Value> {
|
||||||
self.0.remove(s)
|
self.0.remove(&CallArg::Named(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_positional(&mut self, s: usize) -> Option<Value> {
|
||||||
|
self.0.remove(&CallArg::Positional(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +188,9 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> SassResult<CallArgs> {
|
) -> SassResult<CallArgs> {
|
||||||
let mut args: HashMap<String, Value> = HashMap::new();
|
let mut args: HashMap<CallArg, Value> = HashMap::new();
|
||||||
devour_whitespace_or_comment(toks)?;
|
devour_whitespace_or_comment(toks)?;
|
||||||
let mut name: String;
|
let mut name = String::new();
|
||||||
let mut val: Vec<Token> = Vec::new();
|
let mut val: Vec<Token> = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match toks.peek().unwrap().kind {
|
match toks.peek().unwrap().kind {
|
||||||
@ -190,14 +204,14 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
} else {
|
} else {
|
||||||
val.push(Token::new(Pos::new(), '$'));
|
val.push(Token::new(Pos::new(), '$'));
|
||||||
val.extend(v.chars().map(|x| Token::new(Pos::new(), x)));
|
val.extend(v.chars().map(|x| Token::new(Pos::new(), x)));
|
||||||
name = args.len().to_string();
|
name.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
')' => {
|
')' => {
|
||||||
toks.next();
|
toks.next();
|
||||||
return Ok(CallArgs(args));
|
return Ok(CallArgs(args));
|
||||||
}
|
}
|
||||||
_ => name = args.len().to_string(),
|
_ => name.clear(),
|
||||||
}
|
}
|
||||||
devour_whitespace_or_comment(toks)?;
|
devour_whitespace_or_comment(toks)?;
|
||||||
|
|
||||||
@ -205,7 +219,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
match tok.kind {
|
match tok.kind {
|
||||||
')' => {
|
')' => {
|
||||||
args.insert(
|
args.insert(
|
||||||
name.replace('_', "-"),
|
if name.is_empty() {
|
||||||
|
CallArg::Positional(args.len())
|
||||||
|
} else {
|
||||||
|
CallArg::Named(name.replace('_', "-"))
|
||||||
|
},
|
||||||
Value::from_tokens(&mut val.into_iter().peekable(), scope, super_selector)?,
|
Value::from_tokens(&mut val.into_iter().peekable(), scope, super_selector)?,
|
||||||
);
|
);
|
||||||
return Ok(CallArgs(args));
|
return Ok(CallArgs(args));
|
||||||
@ -228,7 +246,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
args.insert(
|
args.insert(
|
||||||
name.replace('_', "-"),
|
if name.is_empty() {
|
||||||
|
CallArg::Positional(args.len())
|
||||||
|
} else {
|
||||||
|
CallArg::Named(name.replace('_', "-"))
|
||||||
|
},
|
||||||
Value::from_tokens(
|
Value::from_tokens(
|
||||||
&mut val.clone().into_iter().peekable(),
|
&mut val.clone().into_iter().peekable(),
|
||||||
scope,
|
scope,
|
||||||
|
@ -45,9 +45,9 @@ impl Function {
|
|||||||
|
|
||||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Function> {
|
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Function> {
|
||||||
for (idx, arg) in self.args.0.iter().enumerate() {
|
for (idx, arg) in self.args.0.iter().enumerate() {
|
||||||
let val = match args.remove(&format!("{}", idx)) {
|
let val = match args.remove_positional(idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match args.remove(&arg.name) {
|
None => match args.remove_named(arg.name.clone()) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match &arg.default {
|
None => match &arg.default {
|
||||||
Some(v) => v.clone(),
|
Some(v) => v.clone(),
|
||||||
|
@ -61,9 +61,9 @@ impl Mixin {
|
|||||||
|
|
||||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
||||||
for (idx, arg) in self.args.0.iter().enumerate() {
|
for (idx, arg) in self.args.0.iter().enumerate() {
|
||||||
let val = match args.remove(&format!("{}", idx)) {
|
let val = match args.remove_positional(idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match args.remove(&arg.name) {
|
None => match args.remove_named(arg.name.clone()) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match &arg.default {
|
None => match &arg.default {
|
||||||
Some(v) => v.clone(),
|
Some(v) => v.clone(),
|
||||||
|
@ -11,7 +11,7 @@ use crate::value::{Number, Value};
|
|||||||
macro_rules! opt_rgba {
|
macro_rules! opt_rgba {
|
||||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||||
let x = $low;
|
let x = $low;
|
||||||
let $name = match arg!($args, -1, $arg = Value::Null) {
|
let $name = match named_arg!($args, $arg = Value::Null) {
|
||||||
Value::Dimension(n, u) => Some(bound!($arg, n, u, x, $high)),
|
Value::Dimension(n, u) => Some(bound!($arg, n, u, x, $high)),
|
||||||
Value::Null => None,
|
Value::Null => None,
|
||||||
v => return Err(format!("${}: {} is not a number.", $arg, v).into()),
|
v => return Err(format!("${}: {} is not a number.", $arg, v).into()),
|
||||||
@ -22,7 +22,7 @@ macro_rules! opt_rgba {
|
|||||||
macro_rules! opt_hsl {
|
macro_rules! opt_hsl {
|
||||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||||
let x = $low;
|
let x = $low;
|
||||||
let $name = match arg!($args, -1, $arg = Value::Null) {
|
let $name = match named_arg!($args, $arg = Value::Null) {
|
||||||
Value::Dimension(n, u) => Some(bound!($arg, n, u, x, $high) / Number::from(100)),
|
Value::Dimension(n, u) => Some(bound!($arg, n, u, x, $high) / Number::from(100)),
|
||||||
Value::Null => None,
|
Value::Null => None,
|
||||||
v => return Err(format!("${}: {} is not a number.", $arg, v).into()),
|
v => return Err(format!("${}: {} is not a number.", $arg, v).into()),
|
||||||
@ -32,7 +32,7 @@ macro_rules! opt_hsl {
|
|||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
f.insert("change-color".to_owned(), Box::new(|args, _| {
|
f.insert("change-color".to_owned(), Box::new(|args, _| {
|
||||||
if args.get("1").is_some() {
|
if args.get_positional(1).is_some() {
|
||||||
return Err("Only one positional argument is allowed. All other arguments must be passed by name.".into());
|
return Err("Only one positional argument is allowed. All other arguments must be passed by name.".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
return Ok(Value::Color(Color::from_rgba(red.unwrap_or(color.red()), green.unwrap_or(color.green()), blue.unwrap_or(color.blue()), alpha.unwrap_or(color.alpha()))))
|
return Ok(Value::Color(Color::from_rgba(red.unwrap_or(color.red()), green.unwrap_or(color.green()), blue.unwrap_or(color.blue()), alpha.unwrap_or(color.alpha()))))
|
||||||
}
|
}
|
||||||
|
|
||||||
let hue = match arg!(args, -1, "hue"=Value::Null) {
|
let hue = match named_arg!(args, "hue"=Value::Null) {
|
||||||
Value::Dimension(n, _) => Some(n),
|
Value::Dimension(n, _) => Some(n),
|
||||||
Value::Null => None,
|
Value::Null => None,
|
||||||
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
||||||
@ -93,7 +93,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let hue = match arg!(args, -1, "hue" = Value::Null) {
|
let hue = match named_arg!(args, "hue" = Value::Null) {
|
||||||
Value::Dimension(n, _) => Some(n),
|
Value::Dimension(n, _) => Some(n),
|
||||||
Value::Null => None,
|
Value::Null => None,
|
||||||
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
||||||
@ -132,7 +132,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
macro_rules! opt_scale_arg {
|
macro_rules! opt_scale_arg {
|
||||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||||
let x = $low;
|
let x = $low;
|
||||||
let $name = match arg!($args, -1, $arg = Value::Null) {
|
let $name = match named_arg!($args, $arg = Value::Null) {
|
||||||
Value::Dimension(n, Unit::Percent) => {
|
Value::Dimension(n, Unit::Percent) => {
|
||||||
Some(bound!($arg, n, Unit::Percent, x, $high) / Number::from(100))
|
Some(bound!($arg, n, Unit::Percent, x, $high) / Number::from(100))
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
macro_rules! arg {
|
macro_rules! arg {
|
||||||
($args:ident, $idx:literal, $name:literal) => {
|
($args:ident, $idx:literal, $name:literal) => {
|
||||||
match $args.remove(stringify!($idx)) {
|
match $args.remove_positional($idx) {
|
||||||
Some(v) => v.eval()?,
|
Some(v) => v.eval()?,
|
||||||
None => match $args.remove($name) {
|
None => match $args.remove_named($name.to_owned()) {
|
||||||
Some(v) => v.eval()?,
|
Some(v) => v.eval()?,
|
||||||
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
($args:ident, $idx:literal, $name:literal=$default:expr) => {
|
($args:ident, $idx:literal, $name:literal=$default:expr) => {
|
||||||
match $args.remove(stringify!($idx)) {
|
match $args.remove_positional($idx) {
|
||||||
Some(v) => v.eval()?,
|
Some(v) => v.eval()?,
|
||||||
None => match $args.remove($name) {
|
None => match $args.remove_named($name.to_owned()) {
|
||||||
Some(v) => v.eval()?,
|
Some(v) => v.eval()?,
|
||||||
None => $default,
|
None => $default,
|
||||||
},
|
},
|
||||||
@ -19,6 +19,21 @@ macro_rules! arg {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! named_arg {
|
||||||
|
($args:ident, $name:literal) => {
|
||||||
|
match $args.remove_named($name.to_owned()) {
|
||||||
|
Some(v) => v.eval()?,
|
||||||
|
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
($args:ident, $name:literal=$default:expr) => {
|
||||||
|
match $args.remove_named($name.to_owned()) {
|
||||||
|
Some(v) => v.eval()?,
|
||||||
|
None => $default,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! max_args {
|
macro_rules! max_args {
|
||||||
($args:ident, $count:literal) => {
|
($args:ident, $count:literal) => {
|
||||||
if $args.len() > $count {
|
if $args.len() > $count {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user