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)]
|
||||
pub(crate) struct CallArgs(pub HashMap<String, Value>);
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CallArgs(HashMap<CallArg, Value>);
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
enum CallArg {
|
||||
Named(String),
|
||||
Positional(usize),
|
||||
}
|
||||
|
||||
impl CallArgs {
|
||||
pub fn new() -> Self {
|
||||
CallArgs(HashMap::new())
|
||||
}
|
||||
|
||||
pub fn get(&self, val: &str) -> Option<&Value> {
|
||||
self.0.get(val)
|
||||
pub fn get_named(&self, val: String) -> Option<&Value> {
|
||||
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 {
|
||||
@ -48,8 +58,12 @@ impl CallArgs {
|
||||
self.0.len() == 0
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, s: &str) -> Option<Value> {
|
||||
self.0.remove(s)
|
||||
pub fn remove_named(&mut self, s: String) -> Option<Value> {
|
||||
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,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<CallArgs> {
|
||||
let mut args: HashMap<String, Value> = HashMap::new();
|
||||
let mut args: HashMap<CallArg, Value> = HashMap::new();
|
||||
devour_whitespace_or_comment(toks)?;
|
||||
let mut name: String;
|
||||
let mut name = String::new();
|
||||
let mut val: Vec<Token> = Vec::new();
|
||||
loop {
|
||||
match toks.peek().unwrap().kind {
|
||||
@ -190,14 +204,14 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
||||
} else {
|
||||
val.push(Token::new(Pos::new(), '$'));
|
||||
val.extend(v.chars().map(|x| Token::new(Pos::new(), x)));
|
||||
name = args.len().to_string();
|
||||
name.clear();
|
||||
}
|
||||
}
|
||||
')' => {
|
||||
toks.next();
|
||||
return Ok(CallArgs(args));
|
||||
}
|
||||
_ => name = args.len().to_string(),
|
||||
_ => name.clear(),
|
||||
}
|
||||
devour_whitespace_or_comment(toks)?;
|
||||
|
||||
@ -205,7 +219,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
||||
match tok.kind {
|
||||
')' => {
|
||||
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)?,
|
||||
);
|
||||
return Ok(CallArgs(args));
|
||||
@ -228,7 +246,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
||||
}
|
||||
|
||||
args.insert(
|
||||
name.replace('_', "-"),
|
||||
if name.is_empty() {
|
||||
CallArg::Positional(args.len())
|
||||
} else {
|
||||
CallArg::Named(name.replace('_', "-"))
|
||||
},
|
||||
Value::from_tokens(
|
||||
&mut val.clone().into_iter().peekable(),
|
||||
scope,
|
||||
|
@ -45,9 +45,9 @@ impl Function {
|
||||
|
||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Function> {
|
||||
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,
|
||||
None => match args.remove(&arg.name) {
|
||||
None => match args.remove_named(arg.name.clone()) {
|
||||
Some(v) => v,
|
||||
None => match &arg.default {
|
||||
Some(v) => v.clone(),
|
||||
|
@ -61,9 +61,9 @@ impl Mixin {
|
||||
|
||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
||||
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,
|
||||
None => match args.remove(&arg.name) {
|
||||
None => match args.remove_named(arg.name.clone()) {
|
||||
Some(v) => v,
|
||||
None => match &arg.default {
|
||||
Some(v) => v.clone(),
|
||||
|
@ -11,7 +11,7 @@ use crate::value::{Number, Value};
|
||||
macro_rules! opt_rgba {
|
||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||
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::Null => None,
|
||||
v => return Err(format!("${}: {} is not a number.", $arg, v).into()),
|
||||
@ -22,7 +22,7 @@ macro_rules! opt_rgba {
|
||||
macro_rules! opt_hsl {
|
||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||
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::Null => None,
|
||||
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>) {
|
||||
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());
|
||||
}
|
||||
|
||||
@ -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()))))
|
||||
}
|
||||
|
||||
let hue = match arg!(args, -1, "hue"=Value::Null) {
|
||||
let hue = match named_arg!(args, "hue"=Value::Null) {
|
||||
Value::Dimension(n, _) => Some(n),
|
||||
Value::Null => None,
|
||||
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::Null => None,
|
||||
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 {
|
||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
|
||||
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) => {
|
||||
Some(bound!($arg, n, Unit::Percent, x, $high) / Number::from(100))
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
macro_rules! arg {
|
||||
($args:ident, $idx:literal, $name:literal) => {
|
||||
match $args.remove(stringify!($idx)) {
|
||||
match $args.remove_positional($idx) {
|
||||
Some(v) => v.eval()?,
|
||||
None => match $args.remove($name) {
|
||||
None => match $args.remove_named($name.to_owned()) {
|
||||
Some(v) => v.eval()?,
|
||||
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
||||
},
|
||||
};
|
||||
};
|
||||
($args:ident, $idx:literal, $name:literal=$default:expr) => {
|
||||
match $args.remove(stringify!($idx)) {
|
||||
match $args.remove_positional($idx) {
|
||||
Some(v) => v.eval()?,
|
||||
None => match $args.remove($name) {
|
||||
None => match $args.remove_named($name.to_owned()) {
|
||||
Some(v) => v.eval()?,
|
||||
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 {
|
||||
($args:ident, $count:literal) => {
|
||||
if $args.len() > $count {
|
||||
|
Loading…
x
Reference in New Issue
Block a user