initial implementation of get-function()

This commit is contained in:
ConnorSkees 2020-04-03 21:38:34 -04:00
parent d26a81253f
commit 3f98d1abca
5 changed files with 73 additions and 8 deletions

View File

@ -4,6 +4,7 @@ use super::eat_stmts;
use crate::args::{eat_func_args, CallArgs, FuncArgs};
use crate::atrule::AtRule;
use crate::common::Pos;
use crate::error::SassResult;
use crate::scope::Scope;
use crate::selector::Selector;
@ -16,11 +17,25 @@ pub(crate) struct Function {
scope: Scope,
args: FuncArgs,
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 {
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Stmt>) -> Self {
Function { scope, args, body }
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Stmt>, pos: Pos) -> Self {
Function {
scope,
args,
body,
pos,
}
}
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
@ -28,6 +43,7 @@ impl Function {
scope: Scope,
super_selector: &Selector,
) -> SassResult<(String, Function)> {
let pos = toks.peek().unwrap().pos;
let name = eat_ident(toks, &scope, super_selector)?;
devour_whitespace(toks);
let args = match toks.next() {
@ -40,7 +56,7 @@ impl Function {
let body = eat_stmts(toks, &mut scope.clone(), super_selector)?;
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> {

View File

@ -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| {
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
// let func = arg!(args, 0, "function").to_string();

View File

@ -2,6 +2,7 @@ use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::iter::Iterator;
use crate::atrule::Function;
use crate::color::Color;
use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
use crate::error::SassResult;
@ -30,8 +31,8 @@ pub(crate) enum Value {
Ident(String, QuoteKind),
Map(SassMap),
ArgList(Vec<Value>),
// Returned by `get-function()`
// Function(String)
/// Returned by `get-function()`
Function(Box<Function>, bool),
}
impl Display for Value {
@ -53,6 +54,7 @@ impl Display for Value {
.collect::<Vec<String>>()
.join(", ")
),
Self::Function(..) => todo!("invalid CSS"),
Self::List(vals, sep, brackets) => match brackets {
Brackets::None => write!(
f,
@ -166,7 +168,7 @@ impl Value {
Self::Ident(..) | Self::Important => Ok("string"),
Self::Dimension(..) => Ok("number"),
Self::List(..) => Ok("list"),
// Self::Function(..) => Ok("function"),
Self::Function(..) => Ok("function"),
Self::ArgList(..) => Ok("arglist"),
Self::True | Self::False => Ok("bool"),
Self::Null => Ok("null"),

View File

@ -14,7 +14,7 @@ impl Add for Value {
}
let precedence = Op::Plus.precedence();
Ok(match self {
Self::ArgList(..) | Self::Map(..) => todo!(),
Self::Function(..) | Self::ArgList(..) | Self::Map(..) => todo!(),
Self::Important | Self::True | Self::False => match other {
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
@ -86,7 +86,7 @@ impl Add for Value {
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
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::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),

34
tests/get-function.rs Normal file
View 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"
);