Skip to content

Commit

Permalink
Improve numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
doonv committed Dec 29, 2023
1 parent 312c28f commit 5284a5b
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 34 deletions.
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2021"
[features]
default = ["builtin-parser"]

builtin-parser = ["dep:logos"]
builtin-parser = ["dep:logos", "dep:kinded"]

[dependencies]
bevy = "0.12.1"
Expand All @@ -20,6 +20,7 @@ web-time = "0.2.4"

# built-in parser
logos = { version = "0.13.0", optional = true }
kinded = { version = "0.3.0", optional = true }

[target.'cfg(target_os = "android")'.dependencies]
android_log-sys = "0.3.0"
Expand Down
1 change: 1 addition & 0 deletions src/builtin_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use self::{lexer::TokenStream, parser::parse};
pub(crate) mod lexer;
pub(crate) mod parser;
pub(crate) mod runner;
pub(crate) mod number;

pub use runner::{environment::Environment, error::RunError, unique_rc::*, Value};

Expand Down
30 changes: 22 additions & 8 deletions src/builtin_parser/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,22 @@ pub enum Token {
#[regex("[a-zA-Z_][a-zA-Z0-9_]*")]
Identifer,

#[regex("[0-9]+")]
Number,
#[regex(r#"[0-9]+"#)]
IntegerNumber,
#[regex(r#"[0-9]*\.?[0-9]*"#)]
FloatNumber,

#[token("i8")]
#[token("i16")]
#[token("i32")]
#[token("i64")]
#[token("u8")]
#[token("u16")]
#[token("u32")]
#[token("u64")]
#[token("f32")]
#[token("f64")]
NumberType,
}

/// A wrapper for the lexer which provides token peeking and other helper functions
Expand Down Expand Up @@ -138,7 +152,7 @@ impl<'a> TokenStream<'a> {
}

/// Get a [`str`] slice of the next [`Token`].
pub fn _peek_slice(&self) -> &str {
pub fn peek_slice(&self) -> &str {
self.lexer.slice()
}

Expand Down Expand Up @@ -171,27 +185,27 @@ mod tests {

#[test]
fn var_assign() {
let mut lexer = TokenStream::new("x = 1 + 2 - 30");
let mut lexer = TokenStream::new("x = 1 + 2 - 30.6");

assert_eq!(lexer.next(), Some(Ok(Token::Identifer)));
assert_eq!(lexer.slice(), "x");

assert_eq!(lexer.next(), Some(Ok(Token::Equals)));
assert_eq!(lexer.slice(), "=");

assert_eq!(lexer.next(), Some(Ok(Token::Number)));
assert_eq!(lexer.next(), Some(Ok(Token::IntegerNumber)));
assert_eq!(lexer.slice(), "1");

assert_eq!(lexer.next(), Some(Ok(Token::Plus)));
assert_eq!(lexer.slice(), "+");

assert_eq!(lexer.next(), Some(Ok(Token::Number)));
assert_eq!(lexer.next(), Some(Ok(Token::IntegerNumber)));
assert_eq!(lexer.slice(), "2");

assert_eq!(lexer.next(), Some(Ok(Token::Minus)));
assert_eq!(lexer.slice(), "-");

assert_eq!(lexer.next(), Some(Ok(Token::Number)));
assert_eq!(lexer.slice(), "30");
assert_eq!(lexer.next(), Some(Ok(Token::FloatNumber)));
assert_eq!(lexer.slice(), "30.6");
}
}
187 changes: 187 additions & 0 deletions src/builtin_parser/number.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#![allow(non_camel_case_types)]

use std::{fmt::Display, ops::*, str::FromStr};

use bevy::reflect::Reflect;
use logos::Span;

use super::{RunError, Spanned};

#[derive(Debug, Clone, Copy)]
pub enum Number {
/// Generic integer that can get downcasted.
Integer(i128),
/// Generic float that can get downcasted to a [`f64`] and [`f32`]
Float(f64),

u8(u8),
u16(u16),
u32(u32),
u64(u64),
i8(i8),
i16(i16),
i32(i32),
i64(i64),
f32(f32),
f64(f64),
}

impl Number {
pub fn reflect(self) -> Box<dyn Reflect> {
match self {
Number::u8(number) => Box::new(number),
Number::u16(number) => Box::new(number),
Number::u32(number) => Box::new(number),
Number::u64(number) => Box::new(number),
Number::i8(number) => Box::new(number),
Number::i16(number) => Box::new(number),
Number::i32(number) => Box::new(number),
Number::i64(number) => Box::new(number),
Number::f32(number) => Box::new(number),
Number::f64(number) => Box::new(number),
Number::Integer(_) => todo!(),
Number::Float(_) => todo!(),
}
}

pub fn kind(&self) -> &'static str {
match self {
Number::Float(_) => "{float}",
Number::Integer(_) => "{integer}",
Number::u8(_) => "u8",
Number::u16(_) => "u16",
Number::u32(_) => "u32",
Number::u64(_) => "u64",
Number::i8(_) => "i8",
Number::i16(_) => "i16",
Number::i32(_) => "i32",
Number::i64(_) => "i64",
Number::f32(_) => "f32",
Number::f64(_) => "f64",
}
}
}

impl Display for Number {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Number::Float(number) => write!(f, "{number} (float)"),
Number::Integer(number) => write!(f, "{number} (integer)"),
Number::u8(number) => write!(f, "{number} (u8)"),
Number::u16(number) => write!(f, "{number} (u16)"),
Number::u32(number) => write!(f, "{number} (u32)"),
Number::u64(number) => write!(f, "{number} (u64)"),
Number::i8(number) => write!(f, "{number} (i8)"),
Number::i16(number) => write!(f, "{number} (i16)"),
Number::i32(number) => write!(f, "{number} (i32)"),
Number::i64(number) => write!(f, "{number} (i64)"),
Number::f32(number) => write!(f, "{number} (f32)"),
Number::f64(number) => write!(f, "{number} (f64)"),
}
}
}

macro_rules! impl_op {
($trait:ident, $fn:ident, $op:tt) => {
impl $trait<Self> for Number {
type Output = Result<Self, RunError>;
fn $fn(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::u8(left), Number::u8(right)) => Ok(Number::u8(left $op right)),
(Number::u16(left), Number::u16(right)) => Ok(Number::u16(left $op right)),
(Number::u32(left), Number::u32(right)) => Ok(Number::u32(left $op right)),
(Number::u64(left), Number::u64(right)) => Ok(Number::u64(left $op right)),
(Number::i8(left), Number::i8(right)) => Ok(Number::i8(left $op right)),
(Number::i16(left), Number::i16(right)) => Ok(Number::i16(left $op right)),
(Number::i32(left), Number::i32(right)) => Ok(Number::i32(left $op right)),
(Number::i64(left), Number::i64(right)) => Ok(Number::i64(left $op right)),
(Number::f32(left), Number::f32(right)) => Ok(Number::f32(left $op right)),
(Number::f64(left), Number::f64(right)) => Ok(Number::f64(left $op right)),

(Number::Integer(left), Number::u8(right)) => Ok(Number::u8(left as u8 $op right)),
(Number::Integer(left), Number::u16(right)) => Ok(Number::u16(left as u16 $op right)),
(Number::Integer(left), Number::u32(right)) => Ok(Number::u32(left as u32 $op right)),
(Number::Integer(left), Number::u64(right)) => Ok(Number::u64(left as u64 $op right)),
(Number::Integer(left), Number::i8(right)) => Ok(Number::i8(left as i8 $op right)),
(Number::Integer(left), Number::i16(right)) => Ok(Number::i16(left as i16 $op right)),
(Number::Integer(left), Number::i32(right)) => Ok(Number::i32(left as i32 $op right)),
(Number::Integer(left), Number::i64(right)) => Ok(Number::i64(left as i64 $op right)),
(Number::Integer(left), Number::Integer(right)) => Ok(Number::Integer(left $op right)),
(Number::u8(left), Number::Integer(right)) => Ok(Number::u8(left $op right as u8)),
(Number::u16(left), Number::Integer(right)) => Ok(Number::u16(left $op right as u16)),
(Number::u32(left), Number::Integer(right)) => Ok(Number::u32(left $op right as u32)),
(Number::u64(left), Number::Integer(right)) => Ok(Number::u64(left $op right as u64)),
(Number::i8(left), Number::Integer(right)) => Ok(Number::i8(left $op right as i8)),
(Number::i16(left), Number::Integer(right)) => Ok(Number::i16(left $op right as i16)),
(Number::i32(left), Number::Integer(right)) => Ok(Number::i32(left $op right as i32)),
(Number::i64(left), Number::Integer(right)) => Ok(Number::i64(left $op right as i64)),

(Number::Float(left), Number::f32(right)) => Ok(Number::f32(left as f32 $op right)),
(Number::Float(left), Number::f64(right)) => Ok(Number::f64(left as f64 $op right)),
(Number::Float(left), Number::Float(right)) => Ok(Number::Float(left $op right)),
(Number::f32(left), Number::Float(right)) => Ok(Number::f32(left $op right as f32)),
(Number::f64(left), Number::Float(right)) => Ok(Number::f64(left $op right as f64)),
_ => todo!()
}
}
}
};
}

impl_op!(Add, add, +);
impl_op!(Sub, sub, -);
impl_op!(Mul, mul, *);
impl_op!(Div, div, /);
impl_op!(Rem, rem, %);

impl Number {
pub fn neg(self, span: Span) -> Result<Number, RunError> {
match self {
Number::u8(_) => Err(RunError::CannotNegateUnsignedInteger(Spanned {
span,
value: self,
})),
Number::u16(_) => Err(RunError::CannotNegateUnsignedInteger(Spanned {
span,
value: self,
})),
Number::u32(_) => Err(RunError::CannotNegateUnsignedInteger(Spanned {
span,
value: self,
})),
Number::u64(_) => Err(RunError::CannotNegateUnsignedInteger(Spanned {
span,
value: self,
})),
Number::i8(number) => Ok(Number::i8(-number)),
Number::i16(number) => Ok(Number::i16(-number)),
Number::i32(number) => Ok(Number::i32(-number)),
Number::i64(number) => Ok(Number::i64(-number)),
Number::f32(number) => Ok(Number::f32(-number)),
Number::f64(number) => Ok(Number::f64(-number)),
Number::Float(number) => Ok(Number::Float(-number)),
Number::Integer(number) => Ok(Number::Integer(-number)),
}
}
}

macro_rules! from_primitive {
($primitive:ident) => {
impl From<$primitive> for Number {
fn from(value: $primitive) -> Self {
Number::$primitive(value)
}
}
};
}

from_primitive!(u8);
from_primitive!(u16);
from_primitive!(u32);
from_primitive!(u64);
from_primitive!(i8);
from_primitive!(i16);
from_primitive!(i32);
from_primitive!(i64);
from_primitive!(f32);
from_primitive!(f64);
Loading

0 comments on commit 5284a5b

Please sign in to comment.