box function references
This commit is contained in:
parent
add1698180
commit
e25a9f7b12
@ -2,32 +2,13 @@ use crate::{builtin::builtin_imports::*, evaluate::div};
|
||||
|
||||
pub(crate) fn percentage(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||
args.max_args(1)?;
|
||||
let num = match args.get_err(0, "number")? {
|
||||
Value::Dimension(SassNumber {
|
||||
num: n,
|
||||
unit: Unit::None,
|
||||
as_slash: _,
|
||||
}) => n * Number::from(100),
|
||||
v @ Value::Dimension(SassNumber { .. }) => {
|
||||
return Err((
|
||||
format!(
|
||||
"$number: Expected {} to have no units.",
|
||||
v.inspect(args.span())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
v => {
|
||||
return Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
let num = args
|
||||
.get_err(0, "number")?
|
||||
.assert_number_with_name("number", args.span)?;
|
||||
num.assert_no_units("number", args.span)?;
|
||||
|
||||
Ok(Value::Dimension(SassNumber {
|
||||
num,
|
||||
num: Number(num.num.0 * 100.0),
|
||||
unit: Unit::Percent,
|
||||
as_slash: None,
|
||||
}))
|
||||
@ -107,54 +88,26 @@ pub(crate) fn floor(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResu
|
||||
|
||||
pub(crate) fn abs(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||
args.max_args(1)?;
|
||||
match args.get_err(0, "number")? {
|
||||
Value::Dimension(SassNumber {
|
||||
num: n,
|
||||
unit: u,
|
||||
as_slash: _,
|
||||
}) => Ok(Value::Dimension(SassNumber {
|
||||
num: (n.abs()),
|
||||
unit: u,
|
||||
as_slash: None,
|
||||
})),
|
||||
v => Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
let mut num = args
|
||||
.get_err(0, "number")?
|
||||
.assert_number_with_name("number", args.span())?;
|
||||
|
||||
num.num = num.num.abs();
|
||||
|
||||
Ok(Value::Dimension(num))
|
||||
}
|
||||
|
||||
pub(crate) fn comparable(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||
args.max_args(2)?;
|
||||
let unit1 = match args.get_err(0, "number1")? {
|
||||
Value::Dimension(SassNumber {
|
||||
num: _,
|
||||
unit: u,
|
||||
as_slash: _,
|
||||
}) => u,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$number1: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
let unit2 = match args.get_err(1, "number2")? {
|
||||
Value::Dimension(SassNumber {
|
||||
num: _,
|
||||
unit: u,
|
||||
as_slash: _,
|
||||
}) => u,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$number2: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
let unit1 = args
|
||||
.get_err(0, "number1")?
|
||||
.assert_number_with_name("number1", args.span())?
|
||||
.unit;
|
||||
|
||||
let unit2 = args
|
||||
.get_err(1, "number2")?
|
||||
.assert_number_with_name("number2", args.span())?
|
||||
.unit;
|
||||
|
||||
Ok(Value::bool(unit1.comparable(&unit2)))
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ pub(crate) fn get_function(mut args: ArgumentResult, visitor: &mut Visitor) -> S
|
||||
};
|
||||
|
||||
match func {
|
||||
Some(func) => Ok(Value::FunctionRef(func)),
|
||||
Some(func) => Ok(Value::FunctionRef(Box::new(func))),
|
||||
None => Err((format!("Function not found: {}", name), args.span()).into()),
|
||||
}
|
||||
}
|
||||
@ -318,7 +318,7 @@ pub(crate) fn call(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResul
|
||||
|
||||
args.remove_positional(0).unwrap();
|
||||
|
||||
visitor.run_function_callable_with_maybe_evaled(func, MaybeEvaledArguments::Evaled(args), span)
|
||||
visitor.run_function_callable_with_maybe_evaled(*func, MaybeEvaledArguments::Evaled(args), span)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
|
@ -100,7 +100,7 @@ pub(crate) fn str_slice(mut args: ArgumentResult, visitor: &mut Visitor) -> Sass
|
||||
} else if start > 0 {
|
||||
(start as usize).min(str_len + 1)
|
||||
} else {
|
||||
(start + str_len as i32 + 1).max(1) as usize
|
||||
(start + str_len as i64 + 1).max(1) as usize
|
||||
};
|
||||
|
||||
let end = args
|
||||
@ -120,7 +120,7 @@ pub(crate) fn str_slice(mut args: ArgumentResult, visitor: &mut Visitor) -> Sass
|
||||
let mut end = end.num().assert_int(span)?;
|
||||
|
||||
if end < 0 {
|
||||
end += str_len as i32 + 1;
|
||||
end += str_len as i64 + 1;
|
||||
}
|
||||
|
||||
let end = (end.max(0) as usize).min(str_len + 1);
|
||||
@ -232,7 +232,7 @@ pub(crate) fn str_insert(mut args: ArgumentResult, visitor: &mut Visitor) -> Sas
|
||||
} else if index_int == 0 {
|
||||
insert(0, s1, &substr)
|
||||
} else {
|
||||
let idx = (len as i32 + index_int + 1).max(0) as usize;
|
||||
let idx = (len as i64 + index_int + 1).max(0) as usize;
|
||||
insert(idx, s1, &substr)
|
||||
};
|
||||
|
||||
|
@ -343,7 +343,7 @@ impl Module {
|
||||
.map(|(key, value)| {
|
||||
(
|
||||
Value::String(key.to_string(), QuoteKind::Quoted).span(span),
|
||||
Value::FunctionRef(value),
|
||||
Value::FunctionRef(Box::new(value)),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
|
@ -134,13 +134,13 @@ impl Environment {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
if let Some(v) = self.get_variable_from_global_modules(name.node) {
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_var(
|
||||
&mut self,
|
||||
|
@ -64,6 +64,16 @@ impl UserDefinedCallable for AstFunctionDecl {
|
||||
}
|
||||
}
|
||||
|
||||
impl UserDefinedCallable for Arc<AstFunctionDecl> {
|
||||
fn name(&self) -> Identifier {
|
||||
self.name.node
|
||||
}
|
||||
|
||||
fn arguments(&self) -> &ArgumentDeclaration {
|
||||
&self.arguments
|
||||
}
|
||||
}
|
||||
|
||||
impl UserDefinedCallable for AstMixin {
|
||||
fn name(&self) -> Identifier {
|
||||
self.name
|
||||
@ -1112,7 +1122,7 @@ impl<'a> Visitor<'a> {
|
||||
// todo: independency
|
||||
|
||||
let func = SassFunction::UserDefined(UserDefinedFunction {
|
||||
function: Box::new(fn_decl),
|
||||
function: Arc::new(fn_decl),
|
||||
name,
|
||||
env: self.env.new_closure(),
|
||||
});
|
||||
@ -1701,6 +1711,14 @@ impl<'a> Visitor<'a> {
|
||||
|
||||
let direction = if from > to { -1 } else { 1 };
|
||||
|
||||
if to == i64::MAX || to == i64::MIN {
|
||||
return Err((
|
||||
"@for loop upper bound exceeds valid integer representation (i64::MAX)",
|
||||
to_span,
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if !for_stmt.is_exclusive {
|
||||
to += direction;
|
||||
}
|
||||
@ -2200,13 +2218,8 @@ impl<'a> Visitor<'a> {
|
||||
Ok(self.without_slash(val))
|
||||
}
|
||||
SassFunction::UserDefined(UserDefinedFunction { function, env, .. }) => self
|
||||
.run_user_defined_callable(
|
||||
arguments,
|
||||
*function,
|
||||
&env,
|
||||
span,
|
||||
|function, visitor| {
|
||||
for stmt in function.children {
|
||||
.run_user_defined_callable(arguments, function, &env, span, |function, visitor| {
|
||||
for stmt in function.children.clone() {
|
||||
let result = visitor.visit_stmt(stmt)?;
|
||||
|
||||
if let Some(val) = result {
|
||||
@ -2215,8 +2228,7 @@ impl<'a> Visitor<'a> {
|
||||
}
|
||||
|
||||
Err(("Function finished without @return.", span).into())
|
||||
},
|
||||
),
|
||||
}),
|
||||
SassFunction::Plain { name } => {
|
||||
let arguments = match arguments {
|
||||
MaybeEvaledArguments::Invocation(args) => args,
|
||||
|
@ -40,8 +40,7 @@ pub(crate) enum Value {
|
||||
Map(SassMap),
|
||||
ArgList(ArgList),
|
||||
/// Returned by `get-function()`
|
||||
// todo: benchmark boxing this (function refs are infrequent)
|
||||
FunctionRef(SassFunction),
|
||||
FunctionRef(Box<SassFunction>),
|
||||
Calculation(SassCalculation),
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ pub(crate) fn fuzzy_equals(a: f64, b: f64) -> bool {
|
||||
(a - b).abs() <= epsilon() && (a * inverse_epsilon()).round() == (b * inverse_epsilon()).round()
|
||||
}
|
||||
|
||||
pub(crate) fn fuzzy_as_int(num: f64) -> Option<i32> {
|
||||
pub(crate) fn fuzzy_as_int(num: f64) -> Option<i64> {
|
||||
if !num.is_finite() {
|
||||
return None;
|
||||
}
|
||||
@ -55,7 +55,7 @@ pub(crate) fn fuzzy_as_int(num: f64) -> Option<i32> {
|
||||
let rounded = num.round();
|
||||
|
||||
if fuzzy_equals(num, rounded) {
|
||||
Some(rounded as i32)
|
||||
Some(rounded as i64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -110,14 +110,14 @@ impl Number {
|
||||
self.0.is_sign_negative() && !self.is_zero()
|
||||
}
|
||||
|
||||
pub fn assert_int(self, span: Span) -> SassResult<i32> {
|
||||
pub fn assert_int(self, span: Span) -> SassResult<i64> {
|
||||
match fuzzy_as_int(self.0) {
|
||||
Some(i) => Ok(i),
|
||||
None => Err((format!("{} is not an int.", self.0), span).into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_int_with_name(self, name: &'static str, span: Span) -> SassResult<i32> {
|
||||
pub fn assert_int_with_name(self, name: &'static str, span: Span) -> SassResult<i64> {
|
||||
match fuzzy_as_int(self.0) {
|
||||
Some(i) => Ok(i),
|
||||
None => Err((
|
||||
|
@ -3,24 +3,15 @@
|
||||
//! Sass functions can be either user-defined or builtin.
|
||||
//!
|
||||
//! User-defined functions are those that have been implemented in Sass
|
||||
//! using the @function rule. See the documentation of `crate::atrule::Function`
|
||||
//! using the @function rule. See the documentation of [`crate::atrule::Function`]
|
||||
//! for more information.
|
||||
//!
|
||||
//! Builtin functions are those that have been implemented in rust and are
|
||||
//! in the global scope.
|
||||
|
||||
use std::fmt;
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
// use codemap::Spanned;
|
||||
|
||||
use crate::{
|
||||
// error::SassResult,
|
||||
ast::AstFunctionDecl,
|
||||
// value::Value,
|
||||
builtin::Builtin,
|
||||
common::Identifier,
|
||||
evaluate::Environment,
|
||||
};
|
||||
use crate::{ast::AstFunctionDecl, builtin::Builtin, common::Identifier, evaluate::Environment};
|
||||
|
||||
/// A Sass function
|
||||
///
|
||||
@ -39,7 +30,7 @@ pub(crate) enum SassFunction {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct UserDefinedFunction {
|
||||
pub function: Box<AstFunctionDecl>,
|
||||
pub function: Arc<AstFunctionDecl>,
|
||||
pub name: Identifier,
|
||||
pub env: Environment,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user