Properly print decimal numbers
This commit is contained in:
parent
04d2c4ab74
commit
44d257494a
@ -7,7 +7,7 @@ use num_rational::BigRational;
|
|||||||
use super::Builtin;
|
use super::Builtin;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::units::Unit;
|
use crate::units::Unit;
|
||||||
use crate::value::Value;
|
use crate::value::{Number, 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, _| {
|
||||||
@ -23,31 +23,31 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
});
|
});
|
||||||
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(Number::from(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(Number::from(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(Number::from(BigInt::from(c.blue())), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `blue()`")
|
_ => todo!("non-color given to builtin function `blue()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "opacity", |args, _| {
|
decl!(f "opacity", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.alpha())), Unit::None)),
|
Value::Color(c) => Some(Value::Dimension(Number::new(BigRational::new(BigInt::from(c.alpha()), BigInt::from(255))), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `opacity()`")
|
_ => todo!("non-color given to builtin function `opacity()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "alpha", |args, _| {
|
decl!(f "alpha", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(BigRational::from_integer(BigInt::from(c.alpha())), Unit::None)),
|
Value::Color(c) => Some(Value::Dimension(Number::new(BigRational::new(BigInt::from(c.alpha()), BigInt::from(255))), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `alpha()`")
|
_ => todo!("non-color given to builtin function `alpha()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -360,7 +360,7 @@ impl Scope {
|
|||||||
pub fn get_var(&self, v: &str) -> Result<&Value, String> {
|
pub fn get_var(&self, v: &str) -> Result<&Value, String> {
|
||||||
match self.vars.get(&v.replace('_', "-")) {
|
match self.vars.get(&v.replace('_', "-")) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(format!("Undefined variable `{}`.", v))
|
None => Err(format!("Undefined variable `{}`.", v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ impl Scope {
|
|||||||
pub fn get_mixin(&self, v: &str) -> Result<&Mixin, String> {
|
pub fn get_mixin(&self, v: &str) -> Result<&Mixin, String> {
|
||||||
match self.mixins.get(&v.replace('_', "-")) {
|
match self.mixins.get(&v.replace('_', "-")) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(format!("Undefined mixin `{}`.", v))
|
None => Err(format!("Undefined mixin `{}`.", v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ impl Scope {
|
|||||||
pub fn get_fn(&self, v: &str) -> Result<&Function, String> {
|
pub fn get_fn(&self, v: &str) -> Result<&Function, String> {
|
||||||
match self.functions.get(&v.replace('_', "-")) {
|
match self.functions.get(&v.replace('_', "-")) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(format!("Undefined function `{}`.", v))
|
None => Err(format!("Undefined function `{}`.", v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +51,8 @@ pub(crate) fn parse_interpolation<I: Iterator<Item = Token>>(
|
|||||||
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
||||||
todo!("invalid character in interpolation")
|
todo!("invalid character in interpolation")
|
||||||
}
|
}
|
||||||
TokenKind::Variable(ref v) => val.extend(
|
TokenKind::Variable(ref v) => val
|
||||||
Lexer::new(&scope.get_var(v).unwrap().to_string()).collect::<Vec<Token>>(),
|
.extend(Lexer::new(&scope.get_var(v).unwrap().to_string()).collect::<Vec<Token>>()),
|
||||||
),
|
|
||||||
TokenKind::Interpolation => val.extend(parse_interpolation(tokens, scope)),
|
TokenKind::Interpolation => val.extend(parse_interpolation(tokens, scope)),
|
||||||
_ => val.push(tok),
|
_ => val.push(tok),
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,13 @@ use std::fmt::{self, Display};
|
|||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_rational::BigRational;
|
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::common::{ListSeparator, Op, QuoteKind};
|
use crate::common::{ListSeparator, Op, QuoteKind};
|
||||||
use crate::units::Unit;
|
use crate::units::Unit;
|
||||||
|
pub(crate) use number::Number;
|
||||||
|
|
||||||
|
mod number;
|
||||||
mod ops;
|
mod ops;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ pub(crate) enum Value {
|
|||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
Null,
|
Null,
|
||||||
Dimension(BigRational, Unit),
|
Dimension(Number, Unit),
|
||||||
List(Vec<Value>, ListSeparator),
|
List(Vec<Value>, ListSeparator),
|
||||||
Color(Color),
|
Color(Color),
|
||||||
BinaryOp(Box<Value>, Op, Box<Value>),
|
BinaryOp(Box<Value>, Op, Box<Value>),
|
||||||
@ -58,7 +59,7 @@ impl TryInto<u16> for Value {
|
|||||||
Self::BinaryOp(..) => self.eval().try_into(),
|
Self::BinaryOp(..) => self.eval().try_into(),
|
||||||
Self::Dimension(n, Unit::Percent) => todo!(),
|
Self::Dimension(n, Unit::Percent) => todo!(),
|
||||||
Self::Dimension(n, Unit::None) => {
|
Self::Dimension(n, Unit::None) => {
|
||||||
if n >= BigRational::from_integer(BigInt::from(255)) {
|
if n >= Number::from(BigInt::from(255)) {
|
||||||
Ok(255)
|
Ok(255)
|
||||||
} else {
|
} else {
|
||||||
Ok(n.to_integer().to_str_radix(10).parse().unwrap())
|
Ok(n.to_integer().to_str_radix(10).parse().unwrap())
|
||||||
|
70
src/value/number.rs
Normal file
70
src/value/number.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use std::convert::From;
|
||||||
|
use std::fmt::{self, Display, Write};
|
||||||
|
use std::ops::{Add, Sub};
|
||||||
|
|
||||||
|
use num_bigint::BigInt;
|
||||||
|
use num_rational::BigRational;
|
||||||
|
|
||||||
|
const PRECISION: usize = 10;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
pub(crate) struct Number {
|
||||||
|
val: BigRational,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Number {
|
||||||
|
pub const fn new(val: BigRational) -> Number {
|
||||||
|
Number { val }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_integer(&self) -> BigInt {
|
||||||
|
self.val.to_integer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BigInt> for Number {
|
||||||
|
fn from(b: BigInt) -> Self {
|
||||||
|
Number {
|
||||||
|
val: BigRational::from_integer(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Number {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.val.to_integer())?;
|
||||||
|
let mut frac = self.val.fract();
|
||||||
|
if frac != BigRational::from_integer(BigInt::from(0)) {
|
||||||
|
f.write_char('.')?;
|
||||||
|
for _ in 0..PRECISION {
|
||||||
|
frac *= BigRational::from_integer(BigInt::from(10));
|
||||||
|
write!(f, "{}", frac.to_integer())?;
|
||||||
|
frac = frac.fract();
|
||||||
|
if frac == BigRational::from_integer(BigInt::from(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Number {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: Self) -> Self {
|
||||||
|
Number {
|
||||||
|
val: self.val + other.val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Number {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, other: Self) -> Self {
|
||||||
|
Number {
|
||||||
|
val: self.val - other.val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,8 @@ use crate::utils::{devour_whitespace_or_comment, parse_interpolation};
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{Token, TokenKind};
|
use crate::{Token, TokenKind};
|
||||||
|
|
||||||
|
use super::number::Number;
|
||||||
|
|
||||||
fn parse_hex(s: String) -> Value {
|
fn parse_hex(s: String) -> Value {
|
||||||
match s.len() {
|
match s.len() {
|
||||||
3 => {
|
3 => {
|
||||||
@ -162,7 +164,7 @@ impl Value {
|
|||||||
Unit::None
|
Unit::None
|
||||||
};
|
};
|
||||||
Some(Value::Dimension(
|
Some(Value::Dimension(
|
||||||
val.parse().expect("error parsing integer"),
|
Number::new(val.parse().expect("error parsing integer")),
|
||||||
unit,
|
unit,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -46,3 +46,8 @@ test!(
|
|||||||
"a {\n color: rgb(255, 255, 255);\n}\n",
|
"a {\n color: rgb(255, 255, 255);\n}\n",
|
||||||
"a {\n color: #ffffff;\n}\n"
|
"a {\n color: #ffffff;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
alpha_function_4_hex,
|
||||||
|
"a {\n color: alpha(#0123);\n}\n",
|
||||||
|
"a {\n color: .25;\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user