Properly print decimal numbers

This commit is contained in:
ConnorSkees 2020-02-08 18:43:18 -05:00
parent 04d2c4ab74
commit 44d257494a
7 changed files with 93 additions and 16 deletions

View File

@ -7,7 +7,7 @@ use num_rational::BigRational;
use super::Builtin;
use crate::color::Color;
use crate::units::Unit;
use crate::value::Value;
use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "rgb", |args, _| {
@ -23,31 +23,31 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "red", |args, _| {
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()`")
}
});
decl!(f "green", |args, _| {
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()`")
}
});
decl!(f "blue", |args, _| {
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()`")
}
});
decl!(f "opacity", |args, _| {
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()`")
}
});
decl!(f "alpha", |args, _| {
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()`")
}
});

View File

@ -360,7 +360,7 @@ impl Scope {
pub fn get_var(&self, v: &str) -> Result<&Value, String> {
match self.vars.get(&v.replace('_', "-")) {
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> {
match self.mixins.get(&v.replace('_', "-")) {
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> {
match self.functions.get(&v.replace('_', "-")) {
Some(v) => Ok(v),
None => Err(format!("Undefined function `{}`.", v))
None => Err(format!("Undefined function `{}`.", v)),
}
}

View File

@ -51,9 +51,8 @@ pub(crate) fn parse_interpolation<I: Iterator<Item = Token>>(
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
todo!("invalid character in interpolation")
}
TokenKind::Variable(ref v) => val.extend(
Lexer::new(&scope.get_var(v).unwrap().to_string()).collect::<Vec<Token>>(),
),
TokenKind::Variable(ref v) => val
.extend(Lexer::new(&scope.get_var(v).unwrap().to_string()).collect::<Vec<Token>>()),
TokenKind::Interpolation => val.extend(parse_interpolation(tokens, scope)),
_ => val.push(tok),
}

View File

@ -4,12 +4,13 @@ use std::fmt::{self, Display};
use std::iter::Iterator;
use num_bigint::BigInt;
use num_rational::BigRational;
use crate::color::Color;
use crate::common::{ListSeparator, Op, QuoteKind};
use crate::units::Unit;
pub(crate) use number::Number;
mod number;
mod ops;
mod parse;
@ -19,7 +20,7 @@ pub(crate) enum Value {
True,
False,
Null,
Dimension(BigRational, Unit),
Dimension(Number, Unit),
List(Vec<Value>, ListSeparator),
Color(Color),
BinaryOp(Box<Value>, Op, Box<Value>),
@ -58,7 +59,7 @@ impl TryInto<u16> for Value {
Self::BinaryOp(..) => self.eval().try_into(),
Self::Dimension(n, Unit::Percent) => todo!(),
Self::Dimension(n, Unit::None) => {
if n >= BigRational::from_integer(BigInt::from(255)) {
if n >= Number::from(BigInt::from(255)) {
Ok(255)
} else {
Ok(n.to_integer().to_str_radix(10).parse().unwrap())

70
src/value/number.rs Normal file
View 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,
}
}
}

View File

@ -10,6 +10,8 @@ use crate::utils::{devour_whitespace_or_comment, parse_interpolation};
use crate::value::Value;
use crate::{Token, TokenKind};
use super::number::Number;
fn parse_hex(s: String) -> Value {
match s.len() {
3 => {
@ -162,7 +164,7 @@ impl Value {
Unit::None
};
Some(Value::Dimension(
val.parse().expect("error parsing integer"),
Number::new(val.parse().expect("error parsing integer")),
unit,
))
}

View File

@ -46,3 +46,8 @@ test!(
"a {\n color: rgb(255, 255, 255);\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"
);