initial implementation of get-function()
This commit is contained in:
parent
d26a81253f
commit
3f98d1abca
@ -4,6 +4,7 @@ use super::eat_stmts;
|
|||||||
|
|
||||||
use crate::args::{eat_func_args, CallArgs, FuncArgs};
|
use crate::args::{eat_func_args, CallArgs, FuncArgs};
|
||||||
use crate::atrule::AtRule;
|
use crate::atrule::AtRule;
|
||||||
|
use crate::common::Pos;
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::selector::Selector;
|
use crate::selector::Selector;
|
||||||
@ -16,11 +17,25 @@ pub(crate) struct Function {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
args: FuncArgs,
|
args: FuncArgs,
|
||||||
body: Vec<Stmt>,
|
body: Vec<Stmt>,
|
||||||
|
pos: Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Function {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.pos == other.pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Function {}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Stmt>) -> Self {
|
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Stmt>, pos: Pos) -> Self {
|
||||||
Function { scope, args, body }
|
Function {
|
||||||
|
scope,
|
||||||
|
args,
|
||||||
|
body,
|
||||||
|
pos,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
||||||
@ -28,6 +43,7 @@ impl Function {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> SassResult<(String, Function)> {
|
) -> SassResult<(String, Function)> {
|
||||||
|
let pos = toks.peek().unwrap().pos;
|
||||||
let name = eat_ident(toks, &scope, super_selector)?;
|
let name = eat_ident(toks, &scope, super_selector)?;
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let args = match toks.next() {
|
let args = match toks.next() {
|
||||||
@ -40,7 +56,7 @@ impl Function {
|
|||||||
let body = eat_stmts(toks, &mut scope.clone(), super_selector)?;
|
let body = eat_stmts(toks, &mut scope.clone(), super_selector)?;
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
Ok((name, Function::new(scope, args, body)))
|
Ok((name, Function::new(scope, args, body, pos)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(mut self, mut args: CallArgs) -> SassResult<Function> {
|
pub fn args(mut self, mut args: CallArgs) -> SassResult<Function> {
|
||||||
|
@ -133,6 +133,19 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
f.insert(
|
||||||
|
"get-function".to_owned(),
|
||||||
|
Box::new(|mut args, scope| {
|
||||||
|
max_args!(args, 2);
|
||||||
|
let name = match arg!(args, 0, "name") {
|
||||||
|
Value::Ident(s, _) => s,
|
||||||
|
v => return Err(format!("$name: {} is not a string.", v).into()),
|
||||||
|
};
|
||||||
|
let css = arg!(args, 1, "css" = Value::False).is_true()?;
|
||||||
|
|
||||||
|
Ok(Value::Function(Box::new(scope.get_fn(&name)?), css))
|
||||||
|
}),
|
||||||
|
);
|
||||||
f.insert("call".to_owned(), Box::new(|_args, _scope| {
|
f.insert("call".to_owned(), Box::new(|_args, _scope| {
|
||||||
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
|
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
|
||||||
// let func = arg!(args, 0, "function").to_string();
|
// let func = arg!(args, 0, "function").to_string();
|
||||||
|
@ -2,6 +2,7 @@ use std::cmp::Ordering;
|
|||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
|
use crate::atrule::Function;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
|
use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
@ -30,8 +31,8 @@ pub(crate) enum Value {
|
|||||||
Ident(String, QuoteKind),
|
Ident(String, QuoteKind),
|
||||||
Map(SassMap),
|
Map(SassMap),
|
||||||
ArgList(Vec<Value>),
|
ArgList(Vec<Value>),
|
||||||
// Returned by `get-function()`
|
/// Returned by `get-function()`
|
||||||
// Function(String)
|
Function(Box<Function>, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Value {
|
impl Display for Value {
|
||||||
@ -53,6 +54,7 @@ impl Display for Value {
|
|||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
|
Self::Function(..) => todo!("invalid CSS"),
|
||||||
Self::List(vals, sep, brackets) => match brackets {
|
Self::List(vals, sep, brackets) => match brackets {
|
||||||
Brackets::None => write!(
|
Brackets::None => write!(
|
||||||
f,
|
f,
|
||||||
@ -166,7 +168,7 @@ impl Value {
|
|||||||
Self::Ident(..) | Self::Important => Ok("string"),
|
Self::Ident(..) | Self::Important => Ok("string"),
|
||||||
Self::Dimension(..) => Ok("number"),
|
Self::Dimension(..) => Ok("number"),
|
||||||
Self::List(..) => Ok("list"),
|
Self::List(..) => Ok("list"),
|
||||||
// Self::Function(..) => Ok("function"),
|
Self::Function(..) => Ok("function"),
|
||||||
Self::ArgList(..) => Ok("arglist"),
|
Self::ArgList(..) => Ok("arglist"),
|
||||||
Self::True | Self::False => Ok("bool"),
|
Self::True | Self::False => Ok("bool"),
|
||||||
Self::Null => Ok("null"),
|
Self::Null => Ok("null"),
|
||||||
|
@ -14,7 +14,7 @@ impl Add for Value {
|
|||||||
}
|
}
|
||||||
let precedence = Op::Plus.precedence();
|
let precedence = Op::Plus.precedence();
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::ArgList(..) | Self::Map(..) => todo!(),
|
Self::Function(..) | Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||||
Self::Important | Self::True | Self::False => match other {
|
Self::Important | Self::True | Self::False => match other {
|
||||||
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
|
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
|
||||||
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
|
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
|
||||||
@ -86,7 +86,7 @@ impl Add for Value {
|
|||||||
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
|
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
|
||||||
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
|
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
|
||||||
Self::Paren(..) => (Self::Ident(s1, quotes1) + other.eval()?)?,
|
Self::Paren(..) => (Self::Ident(s1, quotes1) + other.eval()?)?,
|
||||||
Self::ArgList(..) | Self::Map(..) => todo!(),
|
Self::Function(..) | Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||||
},
|
},
|
||||||
Self::List(..) => match other {
|
Self::List(..) => match other {
|
||||||
Self::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),
|
Self::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),
|
||||||
|
34
tests/get-function.rs
Normal file
34
tests/get-function.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#![cfg(test)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
test!(
|
||||||
|
different_function_same_body_not_equal,
|
||||||
|
"@function user-defined() {@return null}
|
||||||
|
$first-reference: get-function(user-defined);
|
||||||
|
|
||||||
|
@function user-defined() {@return null}
|
||||||
|
$second-reference: get-function(user-defined);
|
||||||
|
a {b: $first-reference == $second-reference}",
|
||||||
|
"a {\n b: false;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
same_function_equal,
|
||||||
|
"@function user-defined() {@return null}
|
||||||
|
a {b: get-function(user-defined) == get-function(user-defined)}s",
|
||||||
|
"a {\n b: true;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
different_name_same_body_not_equal,
|
||||||
|
"@function user-defined-1() {@return null}
|
||||||
|
@function user-defined-2() {@return null}
|
||||||
|
a {b: get-function(user-defined-1) == get-function(user-defined-2)}",
|
||||||
|
"a {\n b: false;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
type_of_user_defined_function,
|
||||||
|
"@function user-defined() {@return null}
|
||||||
|
a {b: type-of(get-function(user-defined));}",
|
||||||
|
"a {\n b: function;\n}\n"
|
||||||
|
);
|
Loading…
x
Reference in New Issue
Block a user