Value operations can fail
This commit is contained in:
parent
0e2e5cb8bc
commit
844b506872
@ -1,18 +1,18 @@
|
||||
macro_rules! arg {
|
||||
($args:ident, $idx:literal, $name:literal) => {
|
||||
match $args.remove(stringify!($idx)) {
|
||||
Some(v) => v.eval(),
|
||||
Some(v) => v.eval()?,
|
||||
None => match $args.remove($name) {
|
||||
Some(v) => v.eval(),
|
||||
Some(v) => v.eval()?,
|
||||
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
||||
},
|
||||
};
|
||||
};
|
||||
($args:ident, $idx:literal, $name:literal=$default:expr) => {
|
||||
match $args.remove(stringify!($idx)) {
|
||||
Some(v) => v.eval(),
|
||||
Some(v) => v.eval()?,
|
||||
None => match $args.remove($name) {
|
||||
Some(v) => v.eval(),
|
||||
Some(v) => v.eval()?,
|
||||
None => $default,
|
||||
},
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ use crate::value::Value;
|
||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||
decl!(f "if", |args, _| {
|
||||
max_args!(args, 3);
|
||||
if arg!(args, 0, "condition").is_true() {
|
||||
if arg!(args, 0, "condition").is_true()? {
|
||||
Ok(arg!(args, 1, "if-true"))
|
||||
} else {
|
||||
Ok(arg!(args, 2, "if-false"))
|
||||
@ -46,7 +46,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||
decl!(f "type-of", |args, _| {
|
||||
max_args!(args, 1);
|
||||
let value = arg!(args, 0, "value");
|
||||
Ok(Value::Ident(value.kind().to_owned(), QuoteKind::None))
|
||||
Ok(Value::Ident(value.kind()?.to_owned(), QuoteKind::None))
|
||||
});
|
||||
decl!(f "unitless", |args, _| {
|
||||
max_args!(args, 1);
|
||||
|
@ -4,6 +4,7 @@ use std::iter::Iterator;
|
||||
|
||||
use crate::color::Color;
|
||||
use crate::common::{ListSeparator, Op, QuoteKind};
|
||||
use crate::error::SassResult;
|
||||
use crate::units::Unit;
|
||||
pub(crate) use number::Number;
|
||||
|
||||
@ -39,7 +40,7 @@ impl Display for Value {
|
||||
.join(sep.as_str())
|
||||
),
|
||||
Self::Color(c) => write!(f, "{}", c),
|
||||
Self::BinaryOp(..) => write!(f, "{}", self.clone().eval()),
|
||||
Self::BinaryOp(..) => write!(f, "{}", self.clone().eval().unwrap()),
|
||||
Self::Paren(val) => write!(f, "{}", val),
|
||||
Self::Ident(val, kind) => write!(f, "{}{}{}", kind.as_str(), val, kind.as_str()),
|
||||
Self::True => write!(f, "true"),
|
||||
@ -54,11 +55,11 @@ impl Value {
|
||||
self == &Value::Null
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
pub fn is_true(&self) -> SassResult<bool> {
|
||||
match self {
|
||||
Value::Null | Value::False => false,
|
||||
Self::BinaryOp(..) => self.clone().eval().is_true(),
|
||||
_ => true,
|
||||
Value::Null | Value::False => Ok(false),
|
||||
Self::BinaryOp(..) => self.clone().eval()?.is_true(),
|
||||
_ => Ok(true),
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,17 +70,17 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> &'static str {
|
||||
pub fn kind(&self) -> SassResult<&'static str> {
|
||||
match self {
|
||||
Value::Color(..) => "color",
|
||||
Value::Ident(..) => "string",
|
||||
Value::Dimension(..) => "number",
|
||||
Value::List(..) => "list",
|
||||
// Value::Function(..) => "function",
|
||||
Value::True | Value::False => "bool",
|
||||
Value::Null => "null",
|
||||
Value::BinaryOp(..) => self.clone().eval().kind(),
|
||||
_ => "unknown",
|
||||
Value::Color(..) => Ok("color"),
|
||||
Value::Ident(..) => Ok("string"),
|
||||
Value::Dimension(..) => Ok("number"),
|
||||
Value::List(..) => Ok("list"),
|
||||
// Value::Function(..) => Ok("function"),
|
||||
Value::True | Value::False => Ok("bool"),
|
||||
Value::Null => Ok("null"),
|
||||
Value::BinaryOp(..) => self.clone().eval()?.kind(),
|
||||
_ => Ok("unknown"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,18 +92,18 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval(self) -> Self {
|
||||
pub fn eval(self) -> SassResult<Self> {
|
||||
match self {
|
||||
Self::BinaryOp(lhs, op, rhs) => match op {
|
||||
Op::Plus => *lhs + *rhs,
|
||||
Op::Minus => *lhs - *rhs,
|
||||
Op::Equal => Self::bool(*lhs == *rhs),
|
||||
Op::NotEqual => Self::bool(*lhs != *rhs),
|
||||
Op::Equal => Ok(Self::bool(*lhs == *rhs)),
|
||||
Op::NotEqual => Ok(Self::bool(*lhs != *rhs)),
|
||||
Op::Mul => *lhs * *rhs,
|
||||
Op::Div => *lhs / *rhs,
|
||||
_ => Self::BinaryOp(lhs, op, rhs),
|
||||
_ => Ok(Self::BinaryOp(lhs, op, rhs)),
|
||||
},
|
||||
_ => self,
|
||||
_ => Ok(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
use crate::common::QuoteKind;
|
||||
use crate::error::SassResult;
|
||||
use crate::units::Unit;
|
||||
use crate::value::Value;
|
||||
|
||||
// Undefined operation "red + white".
|
||||
impl Add for Value {
|
||||
type Output = Self;
|
||||
type Output = SassResult<Self>;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
match self {
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
Ok(match self {
|
||||
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)
|
||||
@ -77,15 +78,15 @@ impl Add for Value {
|
||||
_ => todo!(),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Value {
|
||||
type Output = Self;
|
||||
type Output = SassResult<Self>;
|
||||
|
||||
fn sub(self, other: Self) -> Self {
|
||||
match self {
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Ok(match self {
|
||||
Self::Null => todo!(),
|
||||
Self::Dimension(num, unit) => match other {
|
||||
Self::Dimension(num2, unit2) => Value::Dimension(num - num2, unit),
|
||||
@ -104,7 +105,7 @@ impl Sub for Value {
|
||||
Self::Dimension(..) => todo!("investigate adding numbers and colors"),
|
||||
_ => Value::Ident(format!("{}-{}", c, other), QuoteKind::None),
|
||||
},
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval(),
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval()?,
|
||||
Self::Ident(s1, quotes1) => match other {
|
||||
Self::Ident(s2, quotes2) => {
|
||||
let quotes1 = match quotes1 {
|
||||
@ -157,30 +158,30 @@ impl Sub for Value {
|
||||
Self::Null => Value::Ident(format!("{}-", self), QuoteKind::None),
|
||||
_ => Value::Ident(format!("{}-{}", self, other), QuoteKind::None),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Value {
|
||||
type Output = Self;
|
||||
type Output = SassResult<Self>;
|
||||
|
||||
fn mul(self, other: Self) -> Self {
|
||||
match self {
|
||||
fn mul(self, other: Self) -> Self::Output {
|
||||
Ok(match self {
|
||||
Self::Null => todo!(),
|
||||
Self::Dimension(num, unit) => match other {
|
||||
Self::Dimension(num2, unit2) => Value::Dimension(num * num2, unit),
|
||||
_ => todo!(),
|
||||
},
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval(),
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval()?,
|
||||
_ => todo!("incompatible mul types"),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Div for Value {
|
||||
type Output = Self;
|
||||
type Output = SassResult<Self>;
|
||||
|
||||
fn div(self, other: Self) -> Self {
|
||||
match self {
|
||||
fn div(self, other: Self) -> Self::Output {
|
||||
Ok(match self {
|
||||
Self::Null => todo!(),
|
||||
Self::Dimension(num, unit) => match other {
|
||||
Self::Dimension(num2, unit2) => {
|
||||
@ -200,7 +201,9 @@ impl Div for Value {
|
||||
QuoteKind::None,
|
||||
)
|
||||
}
|
||||
Self::BinaryOp(..) | Self::Paren(..) => Self::Dimension(num, unit) / other.eval(),
|
||||
Self::BinaryOp(..) | Self::Paren(..) => {
|
||||
(Self::Dimension(num, unit) / other.eval()?)?
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
// Self::List(..) => todo!(),
|
||||
@ -216,7 +219,7 @@ impl Div for Value {
|
||||
Self::Dimension(..) => todo!("investigate adding numbers and colors"),
|
||||
_ => Value::Ident(format!("{}/{}", c, other), QuoteKind::None),
|
||||
},
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval(),
|
||||
Self::BinaryOp(..) | Self::Paren(..) => self.eval()?,
|
||||
Self::Ident(s1, quotes1) => match other {
|
||||
Self::Ident(s2, quotes2) => {
|
||||
let quotes1 = match quotes1 {
|
||||
@ -269,6 +272,6 @@ impl Div for Value {
|
||||
Self::Null => Value::Ident(format!("{}/", self), QuoteKind::None),
|
||||
_ => Value::Ident(format!("{}/{}", self, other), QuoteKind::None),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user