Skip to content

Commit

Permalink
Polishing and stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
doonv committed Dec 30, 2023
1 parent 5284a5b commit 76c67ff
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 85 deletions.
13 changes: 7 additions & 6 deletions examples/custom_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use bevy::{
prelude::*,
};
use bevy_dev_console::{
builtin_parser::{Environment, RunError, Spanned, StrongRef, Value},
builtin_parser::{Environment, RunError, Spanned, StrongRef, Value, Number},
prelude::*,
register,
};
Expand All @@ -21,7 +21,7 @@ fn time_since_epoch() {
}

/// Function with parameters and return value
fn add(num1: f64, num2: f64) -> f64 {
fn add(num1: Spanned<Number>, num2: Spanned<Number>) -> Result<Number, RunError> {
num1 + num2
}

Expand All @@ -37,24 +37,25 @@ fn print_debug_info(value: Spanned<Value>) {
struct MyCounter(u32);

/// Function with [`World`]
fn increment_global_counter(world: &mut World) -> f64 {
fn increment_global_counter(world: &mut World) -> u32 {
world.resource_scope(|_, mut counter: Mut<MyCounter>| {
counter.0 += 1;

counter.0 as f64
counter.0
})
}

// Function with reference (Syntax subject to change soon)
fn increment_number(number: Spanned<StrongRef<Value>>) -> Result<(), RunError> {
let span = number.span;
let mut reference = number.value.borrow_mut();
if let Value::Number(number) = &mut *reference {
*number += 1.0;
*number = Number::add(*number, Number::Integer(1), span).unwrap();
Ok(())
} else {
Err(RunError::Custom {
text: "Oh nooo".to_string(),
span: number.span,
span,
})
}
}
Expand Down
16 changes: 15 additions & 1 deletion src/builtin_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,26 @@ use crate::command::{CommandParser, DefaultCommandParser};
use self::{lexer::TokenStream, parser::parse};

pub(crate) mod lexer;
pub(crate) mod number;
pub(crate) mod parser;
pub(crate) mod runner;
pub(crate) mod number;

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

pub trait SpanExtension {
fn wrap<T>(self, value: T) -> Spanned<T>;
fn join(self, span: Self) -> Self;
}
impl SpanExtension for Span {
fn wrap<T>(self, value: T) -> Spanned<T> {
Spanned { span: self, value }
}
fn join(self, span: Self) -> Self {
self.start..span.end
}
}

/// Wrapper around `T` that stores a [Span] (A location in the source code)
#[derive(Debug, Clone)]
pub struct Spanned<T> {
Expand Down
57 changes: 42 additions & 15 deletions src/builtin_parser/number.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#![allow(non_camel_case_types)]

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

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

use super::{RunError, Spanned};
use super::{RunError, SpanExtension, Spanned};

/// An enum for containing any type of number.
///
/// The [`Integer`](Number::Integer) and [`Float`](Number::Float) types
/// are generic types that then get downcasted when they first interact
/// with a concrete type. (i.e. calling a function, etc)
#[derive(Debug, Clone, Copy)]
pub enum Number {
/// Generic integer that can get downcasted.
Expand Down Expand Up @@ -46,8 +52,8 @@ impl Number {

pub fn kind(&self) -> &'static str {
match self {
Number::Float(_) => "{float}",
Number::Integer(_) => "{integer}",
Number::Float(_) => "(float)",
Number::Integer(_) => "(integer)",
Number::u8(_) => "u8",
Number::u16(_) => "u16",
Number::u32(_) => "u32",
Expand Down Expand Up @@ -82,11 +88,10 @@ impl Display for Number {
}

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) {
($fn:ident, $op:tt) => {
impl Number {
pub fn $fn(left: Number, right: Number, span: Span) -> Result<Number, RunError> {
match (left, right) {
(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)),
Expand Down Expand Up @@ -121,18 +126,40 @@ macro_rules! impl_op {
(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!()
_ => Err(RunError::IncompatibleNumberTypes {
left: left.kind(),
right: right.kind(),
span
})
}
}
}
};
}

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

macro_rules! impl_op_spanned {
($trait:ident, $method:ident) => {
impl $trait<Self> for Spanned<Number> {
type Output = Result<Number, RunError>;
fn $method(self, rhs: Self) -> Self::Output {
let span = self.span.join(rhs.span);

Number::$method(self.value, rhs.value, span)
}
}
};
}

impl_op_spanned!(Add, add);
impl_op_spanned!(Sub, sub);
impl_op_spanned!(Mul, mul);
impl_op_spanned!(Rem, rem);

impl Number {
pub fn neg(self, span: Span) -> Result<Number, RunError> {
Expand Down
1 change: 1 addition & 0 deletions src/builtin_parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ fn parse_primary(
if let Some(Function { argument_count, .. }) =
environment.get_function(tokens.slice())
{
dbg!(argument_count);
let name = tokens.slice().to_string();
let start = tokens.span().start;
let mut arguments = Vec::new();
Expand Down
12 changes: 6 additions & 6 deletions src/builtin_parser/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use self::{

use super::{
parser::{Ast, Expression, Operator},
Spanned,
Number, SpanExtension, Spanned,
};
use bevy::{
prelude::*,
Expand Down Expand Up @@ -291,11 +291,11 @@ fn eval_expression(

match (left, right) {
(Value::Number(left), Value::Number(right)) => Ok(Value::Number(match operator {
Operator::Add => (left + right)?,
Operator::Sub => (left - right)?,
Operator::Mul => (left * right)?,
Operator::Div => (left / right)?,
Operator::Mod => (left % right)?,
Operator::Add => Number::add(left, right, expr.span)?,
Operator::Sub => Number::sub(left, right, expr.span)?,
Operator::Mul => Number::mul(left, right, expr.span)?,
Operator::Div => Number::div(left, right, expr.span)?,
Operator::Mod => Number::rem(left, right, expr.span)?,
})),
(left, right) => todo!("{left:#?}, {right:#?}"),
}
Expand Down
14 changes: 13 additions & 1 deletion src/builtin_parser/runner/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ pub enum RunError {
},
CannotMoveOutOfResource(Spanned<String>),
CannotNegateUnsignedInteger(Spanned<Number>),
IncompatibleNumberTypes {
left: &'static str,
right: &'static str,
span: Span
},
}

impl RunError {
Expand All @@ -58,7 +63,8 @@ impl RunError {
IncompatibleReflectTypes { span, .. } => vec![span.clone()],
EnumVariantNotFound { span, .. } => vec![span.clone()],
CannotMoveOutOfResource(Spanned { span, .. }) => vec![span.clone()],
CannotNegateUnsignedInteger(Spanned { span, .. }) => vec![span.clone()]
CannotNegateUnsignedInteger(Spanned { span, .. }) => vec![span.clone()],
IncompatibleNumberTypes { span, .. } => vec![span.clone()],
}
}
pub fn hints(&self) -> Vec<CommandHint> {
Expand Down Expand Up @@ -99,6 +105,12 @@ impl RunError {
value.kind()
)
.into(),
IncompatibleNumberTypes {
left,
right,
..
} => format!("Incompatible number types; `{left}` and `{right}` are incompatible.")
.into(),
}
}
}
105 changes: 53 additions & 52 deletions src/builtin_parser/runner/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,16 @@ impl From<()> for Value {
Value::None
}
}

macro_rules! from_t {
(impl $type:ty: $var:ident => $expr:expr) => {
impl From<$type> for Value {
fn from($var: $type) -> Self {
$expr
}
}
};
}
macro_rules! from_number {
($($number:ident),*$(,)?) => {
$(
Expand All @@ -254,45 +264,18 @@ macro_rules! from_number {
};
}

from_number!(
u8,
u16,
u32,
u64,
i8,
i16,
i32,
i64,
f32,
f64,
);

impl From<String> for Value {
fn from(string: String) -> Self {
Value::String(string)
}
}
impl From<bool> for Value {
fn from(boolean: bool) -> Self {
Value::Boolean(boolean)
}
}
from_number!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);

impl From<HashMap<String, Rc<RefCell<Value>>>> for Value {
fn from(hashmap: HashMap<String, Rc<RefCell<Value>>>) -> Self {
Value::Object(hashmap)
}
}
impl From<HashMap<String, Value>> for Value {
fn from(hashmap: HashMap<String, Value>) -> Self {
Value::Object(
hashmap
.into_iter()
.map(|(k, v)| (k, Rc::new(RefCell::new(v))))
.collect(),
)
}
}
from_t!(impl String: string => Value::String(string));
from_t!(impl bool: bool => Value::Boolean(bool));
from_t!(impl Number: number => Value::Number(number));
from_t!(impl HashMap<String, Rc<RefCell<Value>>>: hashmap => Value::Object(hashmap));
from_t!(impl HashMap<String, Value>: hashmap => Value::Object(
hashmap
.into_iter()
.map(|(k, v)| (k, Rc::new(RefCell::new(v))))
.collect(),
));

impl FunctionParam for Spanned<Value> {
type Item<'world, 'env, 'reg> = Self;
Expand Down Expand Up @@ -371,27 +354,45 @@ macro_rules! impl_function_param_for_value {
};
}
macro_rules! impl_function_param_for_numbers {
($($number:ident),*$(,)?) => {
($generic:ident ($($number:ident),*$(,)?)) => {
$(
impl_function_param_for_value!(impl $number: Value::Number(Number::$number(number)) => number);
impl FunctionParam for $number {
type Item<'world, 'env, 'reg> = Self;
const USES_VALUE: bool = true;

fn get<'world, 'env, 'reg>(
value: Option<Spanned<Value>>,
_: &mut Option<&'world mut World>,
_: &mut Option<&'env mut Environment>,
_: &'reg [&'reg TypeRegistration],
) -> Result<Self::Item<'world, 'env, 'reg>, RunError> {
match value.unwrap().value {
Value::Number(Number::$number(value)) => Ok(value),
Value::Number(Number::$generic(value)) => Ok(value as $number),
_ => todo!()
}
}
}
impl TryFrom<Value> for $number {
type Error = RunError;

fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Number(Number::$number(value)) => Ok(value),
Value::Number(Number::$generic(value)) => Ok(value as $number),
_ => todo!()
}
}
}
)*
};
}

impl_function_param_for_numbers!(
u8,
u16,
u32,
u64,
i8,
i16,
i32,
i64,
f32,
f64,
);
impl_function_param_for_numbers!(Float(f32, f64));
impl_function_param_for_numbers!(Integer(u8, u16, u32, u64, i8, i16, i32, i64));

impl_function_param_for_value!(impl bool: Value::Boolean(boolean) => boolean);
impl_function_param_for_value!(impl Number: Value::Number(number) => number);
impl_function_param_for_value!(impl String: Value::String(string) => string);
impl_function_param_for_value!(impl HashMap<String, Rc<RefCell<Value>>>: Value::Object(object) => object);
impl_function_param_for_value!(impl HashMap<String, Value>: Value::Object(object) => {
Expand Down
Loading

0 comments on commit 76c67ff

Please sign in to comment.