2020-01-25 13:20:21 -05:00
|
|
|
use std::iter::Peekable;
|
|
|
|
|
2020-03-24 01:26:23 -04:00
|
|
|
use super::eat_stmts;
|
|
|
|
|
2020-02-17 09:23:24 -05:00
|
|
|
use crate::args::{eat_func_args, CallArgs, FuncArgs};
|
2020-01-25 14:11:04 -05:00
|
|
|
use crate::atrule::AtRule;
|
2020-02-17 08:13:15 -05:00
|
|
|
use crate::error::SassResult;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::scope::Scope;
|
2020-02-22 15:34:32 -05:00
|
|
|
use crate::selector::Selector;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::utils::{devour_whitespace, eat_ident};
|
2020-01-25 21:02:22 -05:00
|
|
|
use crate::value::Value;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::{Stmt, Token};
|
2020-01-25 13:20:21 -05:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct Function {
|
|
|
|
scope: Scope,
|
|
|
|
args: FuncArgs,
|
2020-03-24 01:26:23 -04:00
|
|
|
body: Vec<Stmt>,
|
2020-01-25 13:20:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Function {
|
2020-03-24 01:26:23 -04:00
|
|
|
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Stmt>) -> Self {
|
2020-01-25 13:20:21 -05:00
|
|
|
Function { scope, args, body }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut Peekable<I>,
|
2020-03-24 01:26:23 -04:00
|
|
|
scope: Scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector: &Selector,
|
2020-02-17 09:22:41 -05:00
|
|
|
) -> SassResult<(String, Function)> {
|
2020-03-29 13:28:17 -04:00
|
|
|
let name = eat_ident(toks, &scope, super_selector)?;
|
2020-01-25 13:20:21 -05:00
|
|
|
devour_whitespace(toks);
|
|
|
|
let args = match toks.next() {
|
2020-03-29 13:28:17 -04:00
|
|
|
Some(Token { kind: '(', .. }) => eat_func_args(toks, &scope, super_selector)?,
|
2020-02-17 09:22:41 -05:00
|
|
|
_ => return Err("expected \"(\".".into()),
|
2020-01-25 13:20:21 -05:00
|
|
|
};
|
|
|
|
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
|
|
|
|
2020-03-24 01:26:23 -04:00
|
|
|
let body = eat_stmts(toks, &mut scope.clone(), super_selector)?;
|
2020-03-19 20:01:13 -04:00
|
|
|
devour_whitespace(toks);
|
2020-03-24 01:26:23 -04:00
|
|
|
|
2020-03-18 20:11:14 -04:00
|
|
|
Ok((name, Function::new(scope, args, body)))
|
2020-01-25 13:20:21 -05:00
|
|
|
}
|
|
|
|
|
2020-02-17 08:13:15 -05:00
|
|
|
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Function> {
|
2020-01-25 21:02:22 -05:00
|
|
|
for (idx, arg) in self.args.0.iter().enumerate() {
|
2020-04-02 12:28:28 -04:00
|
|
|
let val = match args.remove_positional(idx) {
|
2020-02-17 08:13:15 -05:00
|
|
|
Some(v) => v,
|
2020-04-02 12:28:28 -04:00
|
|
|
None => match args.remove_named(arg.name.clone()) {
|
2020-02-17 08:13:15 -05:00
|
|
|
Some(v) => v,
|
|
|
|
None => match &arg.default {
|
|
|
|
Some(v) => v.clone(),
|
2020-02-17 09:23:24 -05:00
|
|
|
None => return Err(format!("Missing argument ${}.", &arg.name).into()),
|
|
|
|
},
|
2020-01-25 21:02:22 -05:00
|
|
|
},
|
|
|
|
};
|
2020-02-29 20:09:41 -05:00
|
|
|
self.scope.insert_var(&arg.name, val)?;
|
2020-01-25 21:02:22 -05:00
|
|
|
}
|
2020-02-17 08:13:15 -05:00
|
|
|
Ok(self)
|
2020-01-25 21:02:22 -05:00
|
|
|
}
|
|
|
|
|
2020-03-24 22:13:38 -04:00
|
|
|
pub fn body(&self) -> Vec<Stmt> {
|
|
|
|
self.body.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn call(&self, super_selector: &Selector, stmts: Vec<Stmt>) -> SassResult<Value> {
|
|
|
|
for stmt in stmts {
|
2020-03-24 01:26:23 -04:00
|
|
|
match stmt {
|
|
|
|
Stmt::AtRule(AtRule::Return(toks)) => {
|
2020-01-25 21:02:22 -05:00
|
|
|
return Value::from_tokens(
|
2020-03-30 17:06:23 -04:00
|
|
|
&mut toks.into_iter().peekable(),
|
2020-01-25 21:02:22 -05:00
|
|
|
&self.scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector,
|
2020-01-25 21:02:22 -05:00
|
|
|
)
|
|
|
|
}
|
2020-03-24 01:26:23 -04:00
|
|
|
Stmt::AtRule(AtRule::For(..)) => todo!("@for in function"),
|
2020-03-24 22:13:38 -04:00
|
|
|
Stmt::AtRule(AtRule::If(i)) => {
|
2020-03-30 17:06:23 -04:00
|
|
|
if let Ok(v) = self.call(
|
2020-03-24 22:13:38 -04:00
|
|
|
super_selector,
|
|
|
|
i.eval(&mut self.scope.clone(), super_selector)?,
|
|
|
|
) {
|
2020-03-30 17:06:23 -04:00
|
|
|
return Ok(v);
|
2020-03-24 22:13:38 -04:00
|
|
|
}
|
|
|
|
}
|
2020-03-01 17:06:55 -05:00
|
|
|
_ => return Err("This at-rule is not allowed here.".into()),
|
2020-01-25 21:02:22 -05:00
|
|
|
}
|
|
|
|
}
|
2020-03-24 22:13:38 -04:00
|
|
|
Err("Function finished without @return.".into())
|
2020-01-25 21:02:22 -05:00
|
|
|
}
|
|
|
|
}
|