implement builtin function call()
This commit is contained in:
parent
c0eaf4c5f6
commit
051185e280
16
src/args.rs
16
src/args.rs
@ -44,6 +44,13 @@ impl CallArg {
|
|||||||
Self::Positional(p) => Ok(*p),
|
Self::Positional(p) => Ok(*p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decrement(self) -> CallArg {
|
||||||
|
match self {
|
||||||
|
Self::Named(..) => self,
|
||||||
|
Self::Positional(p) => Self::Positional(p - 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallArgs {
|
impl CallArgs {
|
||||||
@ -74,6 +81,15 @@ impl CallArgs {
|
|||||||
Ok(vals)
|
Ok(vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decrement(self) -> Self {
|
||||||
|
CallArgs(
|
||||||
|
self.0
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k.decrement(), v))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
@ -142,29 +142,28 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
Value::Ident(s, _) => s,
|
Value::Ident(s, _) => s,
|
||||||
v => return Err(format!("$name: {} is not a string.", v).into()),
|
v => return Err(format!("$name: {} is not a string.", v).into()),
|
||||||
};
|
};
|
||||||
let css = arg!(args, 1, "css" = Value::False).is_true()?;
|
// let css = arg!(args, 1, "css" = Value::False).is_true()?;
|
||||||
|
// let module = arg!(args, 2, "module" = Value::Null);
|
||||||
|
|
||||||
let func = match scope.get_fn(&name) {
|
let func = match scope.get_fn(&name) {
|
||||||
Ok(f) => SassFunction::UserDefined(Box::new(f), name),
|
Ok(f) => SassFunction::UserDefined(Box::new(f), name),
|
||||||
Err(e) => match GLOBAL_FUNCTIONS.get(&name) {
|
Err(..) => match GLOBAL_FUNCTIONS.get(&name) {
|
||||||
Some(f) => SassFunction::Builtin(f.clone(), name),
|
Some(f) => SassFunction::Builtin(f.clone(), name),
|
||||||
None => return Err(e),
|
None => return Err(format!("Function not found: {}", name).into()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Value::Function(func))
|
Ok(Value::Function(func))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
f.insert("call".to_owned(), Builtin::new(|_args, _scope| {
|
f.insert(
|
||||||
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
|
"call".to_owned(),
|
||||||
// let func = arg!(args, 0, "function").to_string();
|
Builtin::new(|mut args, scope| {
|
||||||
// let func = match scope.get_fn(&func) {
|
let func = match arg!(args, 0, "function") {
|
||||||
// Ok(f) => f,
|
Value::Function(f) => f,
|
||||||
// Err(_) => match GLOBAL_FUNCTIONS.get(&func) {
|
v => return Err(format!("$function: {} is not a function reference.", v).into()),
|
||||||
// Some(f) => return f(&args, scope),
|
};
|
||||||
// None => todo!("called undefined function"),
|
func.call(args.decrement(), scope)
|
||||||
// },
|
}),
|
||||||
// };
|
);
|
||||||
// Some(func.clone().args(&args).call())
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::args::CallArgs;
|
||||||
use crate::atrule::Function;
|
use crate::atrule::Function;
|
||||||
use crate::builtin::Builtin;
|
use crate::builtin::Builtin;
|
||||||
|
use crate::error::SassResult;
|
||||||
|
use crate::scope::Scope;
|
||||||
|
use crate::selector::Selector;
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) enum SassFunction {
|
pub(crate) enum SassFunction {
|
||||||
@ -16,6 +21,14 @@ impl SassFunction {
|
|||||||
Self::UserDefined(_, name) => name,
|
Self::UserDefined(_, name) => name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call(self, args: CallArgs, scope: &Scope) -> SassResult<Value> {
|
||||||
|
match self {
|
||||||
|
Self::Builtin(f, ..) => f.0(args, scope),
|
||||||
|
// todo: superselector
|
||||||
|
Self::UserDefined(f, ..) => f.clone().args(args)?.call(&Selector::new(), f.body()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for SassFunction {
|
impl fmt::Debug for SassFunction {
|
||||||
|
@ -52,3 +52,45 @@ test!(
|
|||||||
"a {b: inspect(get-function(lighten));}",
|
"a {b: inspect(get-function(lighten));}",
|
||||||
"a {\n b: get-function(\"lighten\");\n}\n"
|
"a {\n b: get-function(\"lighten\");\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
call_user_defined_no_args,
|
||||||
|
"@function user-defined() {\n @return foo;\n}\n
|
||||||
|
a {b: call(get-function(user-defined));}",
|
||||||
|
"a {\n b: foo;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
call_user_defined_positional_args,
|
||||||
|
"@function user-defined($a, $b) {\n @return $a, $b;\n}\n
|
||||||
|
a {b: call(get-function(user-defined), a, b);}",
|
||||||
|
"a {\n b: a, b;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
call_user_defined_keyword_args,
|
||||||
|
"@function user-defined($a, $b) {\n @return $a, $b;\n}\n
|
||||||
|
a {b: call(get-function(user-defined), $a: a, $b: b);}",
|
||||||
|
"a {\n b: a, b;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
call_builtin_positional_args,
|
||||||
|
"a {b: call(get-function(lighten), red, 5);}",
|
||||||
|
"a {\n b: #ff1a1a;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
call_builtin_keyword_args,
|
||||||
|
"a {b: call(get-function(lighten), $color: red, $amount: 5);}",
|
||||||
|
"a {\n b: #ff1a1a;\n}\n"
|
||||||
|
);
|
||||||
|
// test!(
|
||||||
|
// call_user_defined_super_selector,
|
||||||
|
// "@function user-defined() {\n @return &;\n}\n
|
||||||
|
// a {b: call(get-function(user-defined));}",
|
||||||
|
// "a {\n b: a;\n}\n"
|
||||||
|
// );
|
||||||
|
error!(
|
||||||
|
undefined_function,
|
||||||
|
"a {color: get-function(foo);}", "Error: Function not found: foo"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
non_function_call,
|
||||||
|
"a {color: call(4);}", "Error: $function: 4 is not a function reference."
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user