Add (variable|function|mixin)-exists builtin functions
This commit is contained in:
parent
cbec684052
commit
4585558266
@ -10,7 +10,7 @@ use crate::units::Unit;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "rgb", |args| {
|
decl!(f "rgb", |args, _| {
|
||||||
let channels = args.get("channels").unwrap_or(&Value::Null);
|
let channels = args.get("channels").unwrap_or(&Value::Null);
|
||||||
if channels.is_null() {
|
if channels.is_null() {
|
||||||
let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
|
let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
|
||||||
@ -21,19 +21,19 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
todo!("channels variable in `rgb`")
|
todo!("channels variable in `rgb`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "red", |args| {
|
decl!(f "red", |args, _| {
|
||||||
match arg!(args, 0, "red") {
|
match arg!(args, 0, "red") {
|
||||||
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.red())), Unit::None)),
|
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.red())), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `red()`")
|
_ => todo!("non-color given to builtin function `red()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "green", |args| {
|
decl!(f "green", |args, _| {
|
||||||
match arg!(args, 0, "green") {
|
match arg!(args, 0, "green") {
|
||||||
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.green())), Unit::None)),
|
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.green())), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `green()`")
|
_ => todo!("non-color given to builtin function `green()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "blue", |args| {
|
decl!(f "blue", |args, _| {
|
||||||
match arg!(args, 0, "blue") {
|
match arg!(args, 0, "blue") {
|
||||||
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.blue())), Unit::None)),
|
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.blue())), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `blue()`")
|
_ => todo!("non-color given to builtin function `blue()`")
|
||||||
|
@ -6,7 +6,7 @@ use crate::units::Unit;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "if", |args| {
|
decl!(f "if", |args, _| {
|
||||||
let cond: &Value = arg!(args, 0, "condition");
|
let cond: &Value = arg!(args, 0, "condition");
|
||||||
let if_true = arg!(args, 1, "if-true").clone();
|
let if_true = arg!(args, 1, "if-true").clone();
|
||||||
let if_false = arg!(args, 2, "if-false").clone();
|
let if_false = arg!(args, 2, "if-false").clone();
|
||||||
@ -16,7 +16,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Some(if_false)
|
Some(if_false)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "feature-exists", |args| {
|
decl!(f "feature-exists", |args, _| {
|
||||||
let feature: &Value = arg!(args, 0, "feature");
|
let feature: &Value = arg!(args, 0, "feature");
|
||||||
match feature.clone().unquote().to_string().as_str() {
|
match feature.clone().unquote().to_string().as_str() {
|
||||||
// A local variable will shadow a global variable unless
|
// A local variable will shadow a global variable unless
|
||||||
@ -37,7 +37,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
_ => Some(Value::False),
|
_ => Some(Value::False),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "unit", |args| {
|
decl!(f "unit", |args, _| {
|
||||||
let number = arg!(args, 0, "number");
|
let number = arg!(args, 0, "number");
|
||||||
let unit = match number {
|
let unit = match number {
|
||||||
Value::Dimension(_, u) => u.to_string(),
|
Value::Dimension(_, u) => u.to_string(),
|
||||||
@ -45,11 +45,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
Some(Value::Ident(unit, QuoteKind::Double))
|
Some(Value::Ident(unit, QuoteKind::Double))
|
||||||
});
|
});
|
||||||
decl!(f "type-of", |args| {
|
decl!(f "type-of", |args, _| {
|
||||||
let value = arg!(args, 0, "value");
|
let value = arg!(args, 0, "value");
|
||||||
Some(Value::Ident(value.kind().to_owned(), QuoteKind::None))
|
Some(Value::Ident(value.kind().to_owned(), QuoteKind::None))
|
||||||
});
|
});
|
||||||
decl!(f "unitless", |args| {
|
decl!(f "unitless", |args, _| {
|
||||||
let number = arg!(args, 0, "number");
|
let number = arg!(args, 0, "number");
|
||||||
match number {
|
match number {
|
||||||
Value::Dimension(_, Unit::None) => Some(Value::True),
|
Value::Dimension(_, Unit::None) => Some(Value::True),
|
||||||
@ -57,8 +57,20 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
_ => Some(Value::True)
|
_ => Some(Value::True)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "inspect", |args| {
|
decl!(f "inspect", |args, _| {
|
||||||
let value = arg!(args, 0, "value");
|
let value = arg!(args, 0, "value");
|
||||||
Some(Value::Ident(value.to_string(), QuoteKind::None))
|
Some(Value::Ident(value.to_string(), QuoteKind::None))
|
||||||
});
|
});
|
||||||
|
decl!(f "variable-exists", |args, scope| {
|
||||||
|
let value = arg!(args, 0, "name");
|
||||||
|
Some(Value::bool(scope.var_exists(&value.to_string())))
|
||||||
|
});
|
||||||
|
decl!(f "mixin-exists", |args, scope| {
|
||||||
|
let value = arg!(args, 0, "name");
|
||||||
|
Some(Value::bool(scope.mixin_exists(&value.to_string())))
|
||||||
|
});
|
||||||
|
decl!(f "function-exists", |args, scope| {
|
||||||
|
let value = arg!(args, 0, "name");
|
||||||
|
Some(Value::bool(scope.fn_exists(&value.to_string())))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use lazy_static::lazy_static;
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::args::CallArgs;
|
use crate::args::CallArgs;
|
||||||
|
use crate::common::Scope;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -15,7 +16,7 @@ mod meta;
|
|||||||
mod selector;
|
mod selector;
|
||||||
mod string;
|
mod string;
|
||||||
|
|
||||||
pub(crate) type Builtin = Box<dyn Fn(&CallArgs) -> Option<Value> + Send + Sync>;
|
pub(crate) type Builtin = Box<dyn Fn(&CallArgs, &Scope) -> Option<Value> + Send + Sync>;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap<String, Builtin> = {
|
pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap<String, Builtin> = {
|
||||||
|
@ -200,7 +200,7 @@ impl Value {
|
|||||||
let func = match scope.get_fn(&s) {
|
let func = match scope.get_fn(&s) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
||||||
Some(f) => return f(&args),
|
Some(f) => return f(&args, scope),
|
||||||
None => todo!("called undefined function"),
|
None => todo!("called undefined function"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -229,6 +229,51 @@ test!(
|
|||||||
"a {\n color: inspect(null)\n}\n",
|
"a {\n color: inspect(null)\n}\n",
|
||||||
"a {\n color: null;\n}\n"
|
"a {\n color: null;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
variable_does_exist,
|
||||||
|
"$a: red; a {\n color: variable-exists(a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
variable_does_not_exist,
|
||||||
|
"a {\n color: variable-exists(a)\n}\n",
|
||||||
|
"a {\n color: false;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
variable_exists_named,
|
||||||
|
"$a: red; a {\n color: variable-exists($name: a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
mixin_does_exist,
|
||||||
|
"@mixin a{} a {\n color: mixin-exists(a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
mixin_does_not_exist,
|
||||||
|
"a {\n color: mixin-exists(a)\n}\n",
|
||||||
|
"a {\n color: false;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
mixin_exists_named,
|
||||||
|
"@mixin a{} a {\n color: mixin-exists($name: a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
function_does_exist,
|
||||||
|
"@function a(){} a {\n color: function-exists(a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
function_does_not_exist,
|
||||||
|
"a {\n color: function-exists(a)\n}\n",
|
||||||
|
"a {\n color: false;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
function_exists_named,
|
||||||
|
"@function a(){} a {\n color: function-exists($name: a)\n}\n",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
// test!(
|
// test!(
|
||||||
// inspect_empty_list,
|
// inspect_empty_list,
|
||||||
// "a {\n color: inspect(())\n}\n",
|
// "a {\n color: inspect(())\n}\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user