2020-04-02 12:07:54 -04:00
|
|
|
use std::collections::HashMap;
|
2020-01-25 11:00:29 -05:00
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
use codemap::{Span, Spanned};
|
|
|
|
|
2020-04-20 03:45:28 -04:00
|
|
|
use peekmore::PeekMoreIterator;
|
|
|
|
|
2020-05-22 22:28:38 -04:00
|
|
|
use crate::common::Identifier;
|
2020-02-16 21:34:52 -05:00
|
|
|
use crate::error::SassResult;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::scope::Scope;
|
2020-03-01 12:03:14 -05:00
|
|
|
use crate::selector::Selector;
|
2020-03-31 22:11:01 -04:00
|
|
|
use crate::utils::{
|
2020-04-23 13:54:49 -04:00
|
|
|
devour_whitespace, devour_whitespace_or_comment, eat_ident, eat_ident_no_interpolation,
|
|
|
|
read_until_closing_paren, read_until_closing_quote, read_until_closing_square_brace,
|
2020-03-31 22:11:01 -04:00
|
|
|
};
|
2020-01-26 09:13:39 -05:00
|
|
|
use crate::value::Value;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::Token;
|
2020-01-25 11:00:29 -05:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
pub(crate) struct FuncArgs(pub Vec<FuncArg>);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
pub(crate) struct FuncArg {
|
|
|
|
pub name: String,
|
2020-04-04 18:17:04 -04:00
|
|
|
pub default: Option<Vec<Token>>,
|
2020-04-02 12:07:54 -04:00
|
|
|
pub is_variadic: bool,
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FuncArgs {
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
FuncArgs(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-02 12:28:28 -04:00
|
|
|
#[derive(Debug, Clone)]
|
2020-04-12 19:37:12 -04:00
|
|
|
pub(crate) struct CallArgs(HashMap<CallArg, Vec<Token>>, Span);
|
2020-04-02 12:28:28 -04:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
|
|
|
enum CallArg {
|
2020-05-22 22:28:38 -04:00
|
|
|
Named(Identifier),
|
2020-04-02 12:28:28 -04:00
|
|
|
Positional(usize),
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
|
2020-04-02 13:33:26 -04:00
|
|
|
impl CallArg {
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn position(&self) -> Result<usize, String> {
|
2020-04-02 13:33:26 -04:00
|
|
|
match self {
|
2020-05-22 22:28:38 -04:00
|
|
|
Self::Named(ref name) => Err(name.to_string()),
|
2020-04-02 13:33:26 -04:00
|
|
|
Self::Positional(p) => Ok(*p),
|
|
|
|
}
|
|
|
|
}
|
2020-04-04 12:31:43 -04:00
|
|
|
|
|
|
|
pub fn decrement(self) -> CallArg {
|
|
|
|
match self {
|
|
|
|
Self::Named(..) => self,
|
|
|
|
Self::Positional(p) => Self::Positional(p - 1),
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 13:33:26 -04:00
|
|
|
}
|
|
|
|
|
2020-01-25 11:00:29 -05:00
|
|
|
impl CallArgs {
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn new(span: Span) -> Self {
|
|
|
|
CallArgs(HashMap::new(), span)
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn to_css_string(
|
|
|
|
self,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
) -> SassResult<Spanned<String>> {
|
2020-04-06 15:35:46 -04:00
|
|
|
let mut string = String::with_capacity(2 + self.len() * 10);
|
|
|
|
string.push('(');
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut span = self.1;
|
|
|
|
|
|
|
|
if self.is_empty() {
|
|
|
|
return Ok(Spanned {
|
|
|
|
node: "()".to_string(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-04-06 15:35:46 -04:00
|
|
|
let args = match self.get_variadic(scope, super_selector) {
|
|
|
|
Ok(v) => v,
|
2020-04-12 19:37:12 -04:00
|
|
|
Err(..) => {
|
|
|
|
return Err(("Plain CSS functions don't support keyword arguments.", span).into())
|
|
|
|
}
|
2020-04-06 15:35:46 -04:00
|
|
|
};
|
2020-04-12 19:37:12 -04:00
|
|
|
|
2020-04-06 15:35:46 -04:00
|
|
|
string.push_str(
|
|
|
|
&args
|
|
|
|
.iter()
|
2020-04-12 19:37:12 -04:00
|
|
|
.map(|a| {
|
|
|
|
span = span.merge(a.span);
|
2020-05-05 11:08:34 -04:00
|
|
|
Ok(a.node.to_css_string(a.span)?.into())
|
2020-04-12 19:37:12 -04:00
|
|
|
})
|
|
|
|
.collect::<SassResult<Vec<String>>>()?
|
2020-04-06 15:35:46 -04:00
|
|
|
.join(", "),
|
|
|
|
);
|
|
|
|
string.push(')');
|
2020-04-12 19:37:12 -04:00
|
|
|
Ok(Spanned { node: string, span })
|
2020-04-06 15:35:46 -04:00
|
|
|
}
|
|
|
|
|
2020-04-04 18:17:04 -04:00
|
|
|
/// Get argument by name
|
|
|
|
///
|
|
|
|
/// Removes the argument
|
2020-05-22 22:28:38 -04:00
|
|
|
pub fn get_named<T: Into<Identifier>>(
|
2020-04-04 18:17:04 -04:00
|
|
|
&mut self,
|
2020-05-22 22:28:38 -04:00
|
|
|
val: T,
|
2020-04-04 18:17:04 -04:00
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
2020-04-12 19:37:12 -04:00
|
|
|
) -> Option<SassResult<Spanned<Value>>> {
|
2020-05-22 22:28:38 -04:00
|
|
|
match self.0.remove(&CallArg::Named(val.into())) {
|
2020-04-06 00:11:18 -04:00
|
|
|
Some(v) => Some(Value::from_vec(v, scope, super_selector)),
|
2020-04-04 18:17:04 -04:00
|
|
|
None => None,
|
|
|
|
}
|
2020-04-02 12:28:28 -04:00
|
|
|
}
|
|
|
|
|
2020-04-04 18:17:04 -04:00
|
|
|
/// Get a positional argument by 0-indexed position
|
|
|
|
///
|
|
|
|
/// Removes the argument
|
|
|
|
pub fn get_positional(
|
|
|
|
&mut self,
|
|
|
|
val: usize,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
2020-04-12 19:37:12 -04:00
|
|
|
) -> Option<SassResult<Spanned<Value>>> {
|
2020-04-04 18:17:04 -04:00
|
|
|
match self.0.remove(&CallArg::Positional(val)) {
|
2020-04-06 00:11:18 -04:00
|
|
|
Some(v) => Some(Value::from_vec(v, scope, super_selector)),
|
2020-04-04 18:17:04 -04:00
|
|
|
None => None,
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
2020-02-14 11:52:31 -05:00
|
|
|
|
2020-05-13 01:32:29 -04:00
|
|
|
pub fn get(
|
|
|
|
&mut self,
|
|
|
|
position: usize,
|
|
|
|
name: String,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
) -> Option<SassResult<Spanned<Value>>> {
|
|
|
|
match self.get_named(name, scope, super_selector) {
|
2020-05-16 18:38:37 -04:00
|
|
|
Some(v) => Some(v),
|
|
|
|
None => self.get_positional(position, scope, super_selector),
|
2020-05-13 01:32:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn get_variadic(
|
|
|
|
self,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
) -> SassResult<Vec<Spanned<Value>>> {
|
2020-04-02 13:33:26 -04:00
|
|
|
let mut vals = Vec::new();
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut args = match self
|
2020-04-02 13:33:26 -04:00
|
|
|
.0
|
|
|
|
.into_iter()
|
|
|
|
.map(|(a, v)| Ok((a.position()?, v)))
|
2020-04-12 19:37:12 -04:00
|
|
|
.collect::<Result<Vec<(usize, Vec<Token>)>, String>>()
|
|
|
|
{
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(e) => return Err((format!("No argument named ${}.", e), self.1).into()),
|
|
|
|
};
|
2020-04-02 13:33:26 -04:00
|
|
|
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
|
|
|
|
for arg in args {
|
2020-04-06 00:11:18 -04:00
|
|
|
vals.push(Value::from_vec(arg.1, scope, super_selector)?);
|
2020-04-02 13:33:26 -04:00
|
|
|
}
|
2020-04-02 13:45:14 -04:00
|
|
|
Ok(vals)
|
2020-04-02 13:33:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-06 12:19:03 -04:00
|
|
|
/// Decrement all positional arguments by 1
|
|
|
|
///
|
|
|
|
/// This is used by builtin function `call` to pass
|
|
|
|
/// positional arguments to the other function
|
2020-04-04 12:31:43 -04:00
|
|
|
pub fn decrement(self) -> Self {
|
|
|
|
CallArgs(
|
|
|
|
self.0
|
|
|
|
.into_iter()
|
|
|
|
.map(|(k, v)| (k.decrement(), v))
|
|
|
|
.collect(),
|
2020-04-12 19:37:12 -04:00
|
|
|
self.1,
|
2020-04-04 12:31:43 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:22:26 -04:00
|
|
|
pub const fn span(&self) -> Span {
|
2020-04-12 19:37:12 -04:00
|
|
|
self.1
|
|
|
|
}
|
|
|
|
|
2020-02-14 11:52:31 -05:00
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.0.len()
|
|
|
|
}
|
2020-02-16 22:04:54 -05:00
|
|
|
|
2020-03-22 23:28:19 -04:00
|
|
|
pub fn is_empty(&self) -> bool {
|
2020-04-12 19:37:12 -04:00
|
|
|
self.0.is_empty()
|
2020-03-22 23:28:19 -04:00
|
|
|
}
|
2020-04-22 06:17:52 -04:00
|
|
|
|
|
|
|
pub fn max_args(&self, max: usize) -> SassResult<()> {
|
|
|
|
let len = self.len();
|
|
|
|
if len > max {
|
|
|
|
let mut err = String::with_capacity(50);
|
|
|
|
err.push_str(&format!("Only {} argument", max));
|
|
|
|
if max != 1 {
|
|
|
|
err.push('s');
|
|
|
|
}
|
|
|
|
err.push_str(" allowed, but ");
|
|
|
|
err.push_str(&len.to_string());
|
|
|
|
err.push(' ');
|
|
|
|
if len == 1 {
|
|
|
|
err.push_str("was passed.")
|
|
|
|
} else {
|
|
|
|
err.push_str("were passed.")
|
|
|
|
}
|
|
|
|
return Err((err, self.span()).into());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
|
2020-04-20 03:45:28 -04:00
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-01-26 09:13:39 -05:00
|
|
|
scope: &Scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector: &Selector,
|
2020-02-17 09:28:25 -05:00
|
|
|
) -> SassResult<FuncArgs> {
|
2020-01-25 11:00:29 -05:00
|
|
|
let mut args: Vec<FuncArg> = Vec::new();
|
2020-04-24 21:52:09 -04:00
|
|
|
let mut close_paren_span: Span = toks.peek().unwrap().pos();
|
2020-01-25 11:00:29 -05:00
|
|
|
|
|
|
|
devour_whitespace(toks);
|
2020-04-24 21:52:09 -04:00
|
|
|
while let Some(Token { kind, pos }) = toks.next() {
|
2020-01-25 11:00:29 -05:00
|
|
|
let name = match kind {
|
2020-05-17 00:35:07 -04:00
|
|
|
'$' => eat_ident(toks, scope, super_selector, pos)?,
|
2020-04-24 21:52:09 -04:00
|
|
|
')' => {
|
|
|
|
close_paren_span = pos;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-22 22:06:33 -04:00
|
|
|
_ => return Err(("expected \")\".", pos).into()),
|
2020-01-25 11:00:29 -05:00
|
|
|
};
|
|
|
|
let mut default: Vec<Token> = Vec::new();
|
2020-04-02 12:07:54 -04:00
|
|
|
let mut is_variadic = false;
|
2020-01-25 11:00:29 -05:00
|
|
|
devour_whitespace(toks);
|
2020-04-12 19:37:12 -04:00
|
|
|
let (kind, span) = match toks.next() {
|
|
|
|
Some(Token { kind, pos }) => (kind, pos),
|
2020-01-25 11:00:29 -05:00
|
|
|
_ => todo!("unexpected eof"),
|
|
|
|
};
|
|
|
|
match kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
':' => {
|
2020-01-25 11:00:29 -05:00
|
|
|
devour_whitespace(toks);
|
|
|
|
while let Some(tok) = toks.peek() {
|
|
|
|
match &tok.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
',' => {
|
2020-01-25 11:00:29 -05:00
|
|
|
toks.next();
|
|
|
|
args.push(FuncArg {
|
2020-03-31 01:22:41 -04:00
|
|
|
name: name.replace('_', "-"),
|
2020-04-04 18:17:04 -04:00
|
|
|
default: Some(default),
|
2020-04-02 12:07:54 -04:00
|
|
|
is_variadic,
|
2020-01-25 11:00:29 -05:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
')' => {
|
2020-01-25 11:00:29 -05:00
|
|
|
args.push(FuncArg {
|
2020-03-31 01:22:41 -04:00
|
|
|
name: name.replace('_', "-"),
|
2020-04-04 18:17:04 -04:00
|
|
|
default: Some(default),
|
2020-04-02 12:07:54 -04:00
|
|
|
is_variadic,
|
2020-01-25 11:00:29 -05:00
|
|
|
});
|
2020-04-24 21:52:09 -04:00
|
|
|
close_paren_span = tok.pos();
|
2020-01-25 11:00:29 -05:00
|
|
|
break;
|
|
|
|
}
|
2020-04-24 23:15:41 -04:00
|
|
|
'(' => {
|
|
|
|
default.push(toks.next().unwrap());
|
|
|
|
default.extend(read_until_closing_paren(toks));
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
2020-04-24 23:15:41 -04:00
|
|
|
_ => default.push(toks.next().unwrap()),
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 12:07:54 -04:00
|
|
|
'.' => {
|
2020-04-12 19:37:12 -04:00
|
|
|
let next = toks.next().ok_or(("expected \".\".", span))?;
|
|
|
|
if next.kind != '.' {
|
|
|
|
return Err(("expected \".\".", next.pos()).into());
|
2020-04-02 12:07:54 -04:00
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
let next = toks.next().ok_or(("expected \".\".", next.pos()))?;
|
|
|
|
if next.kind != '.' {
|
|
|
|
return Err(("expected \".\".", next.pos()).into());
|
2020-04-02 12:07:54 -04:00
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
2020-04-12 19:37:12 -04:00
|
|
|
let next = toks.next().ok_or(("expected \")\".", next.pos()))?;
|
|
|
|
if next.kind != ')' {
|
|
|
|
return Err(("expected \")\".", next.pos()).into());
|
2020-04-02 12:07:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
is_variadic = true;
|
|
|
|
|
|
|
|
args.push(FuncArg {
|
|
|
|
name: name.replace('_', "-"),
|
2020-04-04 18:17:04 -04:00
|
|
|
default: Some(default),
|
2020-04-02 12:07:54 -04:00
|
|
|
is_variadic,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
')' => {
|
2020-04-24 21:52:09 -04:00
|
|
|
close_paren_span = span;
|
2020-01-25 11:00:29 -05:00
|
|
|
args.push(FuncArg {
|
2020-03-31 01:22:41 -04:00
|
|
|
name: name.replace('_', "-"),
|
2020-01-25 11:00:29 -05:00
|
|
|
default: if default.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
2020-04-04 18:17:04 -04:00
|
|
|
Some(default)
|
2020-01-25 11:00:29 -05:00
|
|
|
},
|
2020-04-02 12:07:54 -04:00
|
|
|
is_variadic,
|
2020-01-25 11:00:29 -05:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
',' => args.push(FuncArg {
|
2020-03-31 01:22:41 -04:00
|
|
|
name: name.replace('_', "-"),
|
2020-01-25 11:00:29 -05:00
|
|
|
default: None,
|
2020-04-02 12:07:54 -04:00
|
|
|
is_variadic,
|
2020-01-25 11:00:29 -05:00
|
|
|
}),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
2020-04-24 21:52:09 -04:00
|
|
|
match toks.next() {
|
|
|
|
Some(v) if v.kind == '{' => {}
|
|
|
|
Some(..) | None => return Err(("expected \"{\".", close_paren_span).into()),
|
|
|
|
};
|
2020-02-17 09:28:25 -05:00
|
|
|
Ok(FuncArgs(args))
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
2020-04-20 03:45:28 -04:00
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-02-16 21:34:52 -05:00
|
|
|
) -> SassResult<CallArgs> {
|
2020-04-04 18:17:04 -04:00
|
|
|
let mut args: HashMap<CallArg, Vec<Token>> = HashMap::new();
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace_or_comment(toks)?;
|
2020-04-02 12:28:28 -04:00
|
|
|
let mut name = String::new();
|
2020-02-16 21:34:52 -05:00
|
|
|
let mut val: Vec<Token> = Vec::new();
|
2020-04-24 19:13:38 -04:00
|
|
|
// todo: panics on a { color:rgb(; }
|
2020-04-13 12:20:56 -04:00
|
|
|
let mut span = toks.peek().unwrap().pos();
|
2020-02-16 21:34:52 -05:00
|
|
|
loop {
|
|
|
|
match toks.peek().unwrap().kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
'$' => {
|
2020-04-12 19:37:12 -04:00
|
|
|
let Token { pos, .. } = toks.next().unwrap();
|
2020-04-23 13:54:49 -04:00
|
|
|
let v = eat_ident_no_interpolation(toks, false)?;
|
|
|
|
let whitespace = devour_whitespace_or_comment(toks)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
if toks.peek().unwrap().kind == ':' {
|
2020-02-29 18:58:09 -05:00
|
|
|
toks.next();
|
2020-04-12 19:37:12 -04:00
|
|
|
name = v.node;
|
2020-02-16 21:34:52 -05:00
|
|
|
} else {
|
2020-04-12 19:37:12 -04:00
|
|
|
val.push(Token::new(pos, '$'));
|
|
|
|
let mut current_pos = 0;
|
|
|
|
val.extend(v.chars().map(|x| {
|
|
|
|
let len = x.len_utf8() as u64;
|
|
|
|
let tok = Token::new(v.span.subspan(current_pos, current_pos + len), x);
|
|
|
|
current_pos += len;
|
|
|
|
tok
|
|
|
|
}));
|
2020-04-23 13:54:49 -04:00
|
|
|
if whitespace {
|
|
|
|
val.push(Token::new(pos, ' '));
|
|
|
|
}
|
2020-04-02 12:28:28 -04:00
|
|
|
name.clear();
|
2020-01-26 09:13:39 -05:00
|
|
|
}
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
')' => {
|
2020-02-16 21:34:52 -05:00
|
|
|
toks.next();
|
2020-04-12 19:37:12 -04:00
|
|
|
return Ok(CallArgs(args, span));
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
2020-04-02 12:28:28 -04:00
|
|
|
_ => name.clear(),
|
2020-02-16 21:34:52 -05:00
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace_or_comment(toks)?;
|
2020-02-16 21:34:52 -05:00
|
|
|
|
|
|
|
while let Some(tok) = toks.next() {
|
|
|
|
match tok.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
')' => {
|
2020-02-16 21:34:52 -05:00
|
|
|
args.insert(
|
2020-04-02 12:28:28 -04:00
|
|
|
if name.is_empty() {
|
|
|
|
CallArg::Positional(args.len())
|
|
|
|
} else {
|
2020-05-22 22:28:38 -04:00
|
|
|
CallArg::Named(name.into())
|
2020-04-02 12:28:28 -04:00
|
|
|
},
|
2020-04-04 18:17:04 -04:00
|
|
|
val,
|
2020-02-16 21:34:52 -05:00
|
|
|
);
|
2020-04-13 12:20:56 -04:00
|
|
|
span = span.merge(tok.pos());
|
2020-04-12 19:37:12 -04:00
|
|
|
return Ok(CallArgs(args, span));
|
2020-02-16 21:34:52 -05:00
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
',' => break,
|
|
|
|
'[' => {
|
2020-03-23 23:52:15 -04:00
|
|
|
val.push(tok);
|
2020-04-01 15:32:52 -04:00
|
|
|
val.extend(read_until_closing_square_brace(toks));
|
2020-03-23 23:52:15 -04:00
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'(' => {
|
2020-02-09 14:27:54 -05:00
|
|
|
val.push(tok);
|
2020-04-01 15:32:52 -04:00
|
|
|
val.extend(read_until_closing_paren(toks));
|
2020-02-09 14:27:54 -05:00
|
|
|
}
|
2020-03-31 22:11:01 -04:00
|
|
|
'"' | '\'' => {
|
|
|
|
val.push(tok);
|
|
|
|
val.extend(read_until_closing_quote(toks, tok.kind));
|
|
|
|
}
|
2020-02-16 21:34:52 -05:00
|
|
|
_ => val.push(tok),
|
2020-02-09 14:27:54 -05:00
|
|
|
}
|
2020-02-16 21:34:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
args.insert(
|
2020-04-02 12:28:28 -04:00
|
|
|
if name.is_empty() {
|
|
|
|
CallArg::Positional(args.len())
|
|
|
|
} else {
|
2020-05-22 22:28:38 -04:00
|
|
|
CallArg::Named(name.clone().into())
|
2020-04-02 12:28:28 -04:00
|
|
|
},
|
2020-04-04 18:17:04 -04:00
|
|
|
val.clone(),
|
2020-02-16 21:34:52 -05:00
|
|
|
);
|
|
|
|
val.clear();
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
2020-02-16 21:34:52 -05:00
|
|
|
|
|
|
|
if toks.peek().is_none() {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Ok(CallArgs(args, span));
|
2020-02-16 21:34:52 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|