Skip to content

Commit

Permalink
More stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
doonv committed Dec 24, 2023
1 parent a79c1f3 commit f887164
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 102 deletions.
13 changes: 5 additions & 8 deletions examples/custom_functions.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
//! A simple exmaple
use std::{cell::RefCell, rc::Weak};

use bevy::{
log::{Level, LogPlugin},
prelude::*,
};
use bevy_dev_console::{
builtin_parser::{Environment, RunError, Spanned, Value},
builtin_parser::{Environment, RunError, Spanned, Value, StrongRef},
prelude::*,
register,
};
Expand Down Expand Up @@ -47,16 +45,15 @@ fn increment_global_counter(world: &mut World) -> f64 {
})
}

// Function with reference (Syntax subject to change very soon)
fn increment_number(number: Spanned<Weak<RefCell<Value>>>) -> Result<(), RunError> {
let rc = number.value.upgrade().unwrap();
let mut reference = rc.borrow_mut();
// Function with reference (Syntax subject to change soon)
fn increment_number(number: Spanned<StrongRef<Value>>) -> Result<(), RunError> {
let mut reference = number.value.borrow_mut();
if let Value::Number(number) = &mut *reference {
*number += 1.0;
Ok(())
} else {
Err(RunError::Custom {
text: "w".to_string(),
text: "Oh nooo".to_string(),
span: number.span,
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/builtin_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) mod lexer;
pub(crate) mod parser;
pub(crate) mod runner;

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

/// Wrapper around `T` that stores a [Span] (A location in the source code)
#[derive(Debug, Clone)]
Expand Down
64 changes: 34 additions & 30 deletions src/builtin_parser/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,25 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};

use environment::Environment;

use self::reflection::{object_to_dynamic_struct, IntoRegistration, IntoResource};
use self::{
reflection::{object_to_dynamic_struct, CreateRegistration, IntoResource},
unique_rc::{UniqueRc, WeakRef},
};

use super::{
parser::{Ast, Expression, Operator},
Spanned,
};
use bevy::{
prelude::*,
reflect::{DynamicEnum, Enum, EnumInfo, ReflectMut, TypeInfo, TypeRegistration},
reflect::{DynamicEnum, Enum, ReflectMut, TypeInfo, TypeRegistration},
};
use logos::Span;
pub mod environment;
pub mod reflection;
pub mod stdlib;
pub mod value;
pub mod unique_rc;
pub mod value;

pub use value::Value;

Expand All @@ -44,6 +47,7 @@ pub enum RunError {
CannotBorrowValue(Span),
IncompatibleReflectTypes { expected: String, actual: String },
EnumVariantNotFound { name: String },
CannotMoveOutOfResource(Spanned<String>),
}

pub fn run(ast: Ast, world: &mut World) {
Expand Down Expand Up @@ -95,7 +99,7 @@ pub fn run(ast: Ast, world: &mut World) {

match value {
Ok(Value::None) => {}
Ok(value) => match value.try_format(span, &world, &registrations) {
Ok(value) => match value.try_format(span, world, &registrations) {
Ok(value) => info!(name: "console_result", "> {value}"),
Err(err) => error!("{err:?}"),
},
Expand Down Expand Up @@ -123,7 +127,6 @@ fn eval_expression(
value: value_expr,
} => match eval_path(*name, environment, registrations)?.value {
Path::Variable(variable) => {
let temp = variable.clone();
let value = eval_expression(
*value_expr,
EvalParams {
Expand All @@ -132,9 +135,9 @@ fn eval_expression(
registrations,
},
)?;
*temp.borrow_mut() = value;
*variable.upgrade().unwrap().borrow_mut() = value;

Ok(Value::Reference(Rc::downgrade(&temp)))
Ok(Value::Reference(variable))
}
Path::NewVariable(variable) => {
let value = eval_expression(
Expand All @@ -145,15 +148,15 @@ fn eval_expression(
registrations,
},
)?;
let rc = Rc::new(RefCell::new(value));
let weak = Rc::downgrade(&rc);
let rc = UniqueRc::new(value);
let weak = rc.borrow();

environment.set(variable, rc);

Ok(Value::Reference(weak))
}
Path::Resource(resource) => {
let registeration = registrations.into_registration(resource.id);
let registeration = registrations.create_registration(resource.id);
let mut dyn_reflect = resource.mut_dyn_reflect(world, registeration);

let reflect = dyn_reflect
Expand Down Expand Up @@ -248,11 +251,14 @@ fn eval_expression(
Expression::String(string) => Ok(Value::String(string)),
Expression::Number(number) => Ok(Value::Number(number)),
Expression::Variable(variable) => {
if let Some(registration) = registrations
if registrations
.iter()
.find(|v| v.type_info().type_path_table().short_path() == variable)
.any(|v| v.type_info().type_path_table().short_path() == variable)
{
Ok(Value::Resource(IntoResource::new(registration.type_id())))
Err(RunError::CannotMoveOutOfResource(Spanned {
span: expr.span,
value: variable,
}))
} else {
environment.move_var(&variable, expr.span)
}
Expand Down Expand Up @@ -353,7 +359,7 @@ fn eval_expression(
Ok(Value::Resource(IntoResource::new(registration.type_id())))
} else {
let rc = environment.get(&variable, inner.span)?;
let weak = Rc::downgrade(rc);
let weak = rc.borrow();

Ok(Value::Reference(weak))
}
Expand Down Expand Up @@ -418,17 +424,17 @@ fn eval_member_expression(
}
}

enum Path<'a> {
Variable(&'a Rc<RefCell<Value>>),
enum Path {
Variable(WeakRef<Value>),
NewVariable(String),
Resource(IntoResource),
}

fn eval_path<'a>(
fn eval_path(
expr: Spanned<Expression>,
environment: &'a Environment,
environment: &Environment,
registrations: &[&TypeRegistration],
) -> Result<Spanned<Path<'a>>, RunError> {
) -> Result<Spanned<Path>, RunError> {
match expr.value {
Expression::Variable(variable) => {
if let Some(registration) = registrations
Expand All @@ -439,18 +445,16 @@ fn eval_path<'a>(
span: expr.span,
value: Path::Resource(IntoResource::new(registration.type_id())),
})
} else if let Ok(variable) = environment.get(&variable, expr.span.clone()) {
Ok(Spanned {
span: expr.span,
value: Path::Variable(variable.borrow()),
})
} else {
if let Ok(variable) = environment.get(&variable, expr.span.clone()) {
Ok(Spanned {
span: expr.span,
value: Path::Variable(variable),
})
} else {
Ok(Spanned {
span: expr.span,
value: Path::NewVariable(variable),
})
}
Ok(Spanned {
span: expr.span,
value: Path::NewVariable(variable),
})
}
}
Expression::Member { left, right } => {
Expand Down
53 changes: 28 additions & 25 deletions src/builtin_parser/runner/environment.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Environment and function registeration
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use std::collections::HashMap;

use bevy::{ecs::world::World, log::warn, reflect::TypeRegistration};
use logos::Span;

use super::{
super::{parser::Expression, Spanned},
eval_expression, stdlib, EvalParams, RunError, Value,
eval_expression, stdlib,
unique_rc::UniqueRc,
EvalParams, RunError, Value,
};

/// Macro for mass registering functions.
Expand Down Expand Up @@ -130,6 +132,7 @@ macro_rules! impl_into_function {
let world = &mut Some(world);
let environment = &mut Some(environment);

#[allow(clippy::too_many_arguments)]
fn call_inner<R: Into<ResultContainer<Value, RunError>>, $($($params),*)?>(
mut f: impl FnMut($($($params),*)?) -> R,
$($($params: $params),*)?
Expand All @@ -144,7 +147,7 @@ macro_rules! impl_into_function {
} else {
None
};

let res = $params::get(
arg,
world,
Expand Down Expand Up @@ -180,7 +183,7 @@ impl_into_function!(T1, T2, T3, T4, T5, T6, T7, T8);

/// A variable inside the [`Environment`].
pub enum Variable {
Unmoved(Rc<RefCell<Value>>),
Unmoved(UniqueRc<Value>),
Moved,
Function(Function),
}
Expand All @@ -206,7 +209,7 @@ impl Default for Environment {

impl Environment {
/// Set a variable.
pub fn set(&mut self, name: impl Into<String>, value: Rc<RefCell<Value>>) {
pub fn set(&mut self, name: impl Into<String>, value: UniqueRc<Value>) {
self.variables.insert(name.into(), Variable::Unmoved(value));
}

Expand Down Expand Up @@ -250,7 +253,7 @@ impl Environment {
return_result
}
/// Returns a reference to a variable.
pub fn get(&self, name: &str, span: Span) -> Result<&Rc<RefCell<Value>>, RunError> {
pub fn get(&self, name: &str, span: Span) -> Result<&UniqueRc<Value>, RunError> {
let (env, span) = self.resolve(name, span)?;

match env.variables.get(name) {
Expand All @@ -261,33 +264,33 @@ impl Environment {
}
}

/// "moves" a variable, giving you ownership over it. However it will no longer be able to be used unless
/// it's a [`Value::None`], [`Value::Boolean`], or [`Value::Number`] in which case it will be copied.
/// "Moves" a variable, giving you ownership over it.
///
/// However it will no longer be able to be used unless it's a [`Value::None`],
/// [`Value::Boolean`], or [`Value::Number`] in which case it will be copied.
pub fn move_var(&mut self, name: &str, span: Span) -> Result<Value, RunError> {
let (env, span) = self.resolve_mut(name, span)?;

match env.variables.get_mut(name) {
Some(Variable::Moved) => Err(RunError::VariableMoved(span)),
Some(Variable::Function(_)) => todo!(),
Some(reference) => {
let Variable::Unmoved(value) = std::mem::replace(reference, Variable::Moved) else {
Some(variable_reference) => {
let Variable::Unmoved(reference) = variable_reference else {
unreachable!()
};
// SAFETY: The reference goes out of scope before it can get borrowed again.
let reference = unsafe { value.try_borrow_unguarded().unwrap() };
// This is a pretty bad way of handling
match reference {
Value::None => Ok(Value::None),
Value::Boolean(bool) => Ok(Value::Boolean(*bool)),
Value::Number(number) => Ok(Value::Number(*number)),
_ => {
// Unwrapping will always succeed due to only the owner of the variable having
// a strong reference. All other references are weak.
let value = Rc::try_unwrap(value).unwrap();

Ok(value.into_inner())
}
}
// This is a pretty bad way of handling something similar to rust's [`Copy`] trait but whatever.
match &*reference.borrow_inner().borrow() {
Value::None => return Ok(Value::None),
Value::Boolean(bool) => return Ok(Value::Boolean(*bool)),
Value::Number(number) => return Ok(Value::Number(*number)),
_ => {}
};
let Variable::Unmoved(value) =
std::mem::replace(variable_reference, Variable::Moved)
else {
unreachable!()
};
Ok(value.into_inner())
}
None => Err(RunError::VariableNotFound(span)),
}
Expand Down
24 changes: 12 additions & 12 deletions src/builtin_parser/runner/reflection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ impl IntoResource {
pub fn ref_dyn_reflect<'a>(
&self,
world: &'a World,
registration: impl IntoRegistration,
registration: impl CreateRegistration,
) -> &'a dyn Reflect {
let registration = registration.into_registration(self.id);
let registration = registration.create_registration(self.id);
let ref_dyn_reflect = ref_dyn_reflect(world, registration).unwrap();

ref_dyn_reflect
}
pub fn mut_dyn_reflect<'a>(
&self,
world: &'a mut World,
registration: impl IntoRegistration,
registration: impl CreateRegistration,
) -> Mut<'a, dyn Reflect> {
let registration = registration.into_registration(self.id);
let registration = registration.create_registration(self.id);
let ref_dyn_reflect = mut_dyn_reflect(world, registration).unwrap();

ref_dyn_reflect
Expand Down Expand Up @@ -82,22 +82,22 @@ pub fn ref_dyn_reflect<'a>(
let resource = world.get_resource_by_id(component_id).unwrap();
let reflect_from_ptr = registration.data::<ReflectFromPtr>().unwrap();
// SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped`
let val: &'a dyn Reflect = unsafe { reflect_from_ptr.as_reflect(resource) };
let val: &dyn Reflect = unsafe { reflect_from_ptr.as_reflect(resource) };
Some(val)
}

pub trait IntoRegistration {
fn into_registration<'a>(&'a self, type_id: TypeId) -> &'a TypeRegistration;
pub trait CreateRegistration {
fn create_registration(&self, type_id: TypeId) -> &TypeRegistration;
}
impl IntoRegistration for &TypeRegistration {
fn into_registration<'a>(&'a self, type_id: TypeId) -> &'a TypeRegistration {
impl CreateRegistration for &TypeRegistration {
fn create_registration(&self, type_id: TypeId) -> &TypeRegistration {
assert!(self.type_id() == type_id);

&self
self
}
}
impl IntoRegistration for &[&TypeRegistration] {
fn into_registration<'a>(&'a self, type_id: TypeId) -> &'a TypeRegistration {
impl CreateRegistration for &[&TypeRegistration] {
fn create_registration(&self, type_id: TypeId) -> &TypeRegistration {
self.iter()
.find(|reg| reg.type_id() == type_id)
.expect("registration no longer exists")
Expand Down
Loading

0 comments on commit f887164

Please sign in to comment.