diff --git a/examples/resource.rs b/examples/resource.rs index 5cd4218..8c32478 100644 --- a/examples/resource.rs +++ b/examples/resource.rs @@ -20,7 +20,7 @@ enum MyEnum { #[derive(Resource, Reflect, Default, Debug)] struct MyStruct { number1: f64, - number2: f64, + number2: i16, number3: f32, string: String, } @@ -29,13 +29,13 @@ fn main() { App::new() .register_type::() .init_resource::() - .register_type::() .insert_resource(MyStruct { number1: 52138.0, - number2: -123.8, + number2: -123, number3: 0.0, string: "hi there :)".to_string(), }) + .register_type::() .add_plugins(( ConsoleLogPlugin::default(), DefaultPlugins.build().disable::(), diff --git a/src/builtin_parser/number.rs b/src/builtin_parser/number.rs index 46f94ad..089908f 100644 --- a/src/builtin_parser/number.rs +++ b/src/builtin_parser/number.rs @@ -24,20 +24,18 @@ pub enum Number { u32(u32), u64(u64), usize(usize), - i8(i8), i16(i16), i32(i32), i64(i64), isize(isize), - f32(f32), f64(f64), } impl Number { /// Converts this into a [`Box`](Reflect). - pub fn reflect(self) -> Box { + pub fn reflect(self, ty: &str) -> Box { match self { Number::u8(number) => Box::new(number), Number::u16(number) => Box::new(number), @@ -51,8 +49,24 @@ impl Number { Number::isize(number) => Box::new(number), Number::f32(number) => Box::new(number), Number::f64(number) => Box::new(number), - Number::Integer(_) => todo!(), - Number::Float(_) => todo!(), + Number::Integer(number) => match ty { + "u8" => Box::new(number as u8), + "u16" => Box::new(number as u16), + "u32" => Box::new(number as u32), + "u64" => Box::new(number as u64), + "usize" => Box::new(number as usize), + "i8" => Box::new(number as i8), + "i16" => Box::new(number as i16), + "i32" => Box::new(number as i32), + "i64" => Box::new(number as i64), + "isize" => Box::new(number as isize), + ty => todo!("{ty:?}"), + }, + Number::Float(number) => match ty { + "f32" => Box::new(number as f32), + "f64" => Box::new(number), + ty => todo!("{ty:?}"), + }, } } diff --git a/src/builtin_parser/parser.rs b/src/builtin_parser/parser.rs index 25d3cbb..2daaf7c 100644 --- a/src/builtin_parser/parser.rs +++ b/src/builtin_parser/parser.rs @@ -16,12 +16,12 @@ use super::{ pub type Ast = Vec>; macro_rules! expect { - ($tokens:ident, $token:pat, $tokenexpr:expr) => { + ($tokens:ident, $($token:tt)+) => { match $tokens.next() { - Some(Ok($token)) => $tokenexpr, + Some(Ok($($token)+)) => ($($token)+) , Some(Ok(token)) => { return Err(ParseError::ExpectedTokenButGot { - expected: $tokenexpr, + expected: $($token)+, got: token, span: $tokens.span(), }) @@ -171,9 +171,9 @@ fn parse_expression( }) } fn parse_block(tokens: &mut TokenStream, environment: &Environment) -> Result { - expect!(tokens, Token::LeftBracket, Token::LeftBracket); + expect!(tokens, Token::LeftBracket); let ast = parse(tokens, environment)?; - expect!(tokens, Token::RightBracket, Token::RightBracket); + expect!(tokens, Token::RightBracket); Ok(ast) } fn parse_additive( @@ -246,7 +246,7 @@ fn parse_primary( }) } else { let expr = parse_expression(tokens, environment)?; - expect!(tokens, Token::RightParen, Token::RightParen); + expect!(tokens, Token::RightParen); Ok(expr) } } @@ -254,7 +254,7 @@ fn parse_primary( Some(Ok(Token::LeftBracket)) => { let name = tokens.slice().to_string(); - expect!(tokens, Token::LeftBracket, Token::LeftBracket); + expect!(tokens, Token::LeftBracket); let map = parse_object(tokens, environment)?; Ok(Spanned { @@ -386,7 +386,7 @@ fn parse_primary( // If theres a dot after the expression, do a member expression: while let Some(Ok(Token::Dot)) = tokens.peek() { tokens.next(); // skip the dot - expect!(tokens, Token::Identifer, Token::Identifer); + expect!(tokens, Token::Identifer); let right = tokens.slice().to_string(); expr = Spanned { span: expr.span.start..tokens.span().end, @@ -430,7 +430,7 @@ fn parse_object( while let Some(Ok(Token::Identifer)) = tokens.peek() { tokens.next(); let ident = tokens.slice().to_string(); - expect!(tokens, Token::Colon, Token::Colon); + expect!(tokens, Token::Colon); let expr = parse_expression(tokens, environment)?; map.insert(ident, expr); match tokens.peek() { @@ -441,7 +441,7 @@ fn parse_object( token => todo!("{token:?}"), } } - expect!(tokens, Token::RightBracket, Token::RightBracket); + expect!(tokens, Token::RightBracket); Ok(map) } diff --git a/src/builtin_parser/runner.rs b/src/builtin_parser/runner.rs index a1ca5ef..f5b4e3a 100644 --- a/src/builtin_parser/runner.rs +++ b/src/builtin_parser/runner.rs @@ -18,7 +18,10 @@ use super::{ }; use bevy::{ prelude::*, - reflect::{DynamicEnum, Enum, ReflectMut, TypeInfo, TypeRegistration}, + reflect::{ + DynamicEnum, DynamicStruct, Enum, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, + VariantInfo, + }, }; pub mod environment; @@ -199,38 +202,51 @@ fn eval_expression( if enum_info.contains_variant(&variable) { let new_enum = DynamicEnum::new(variable, ()); - dyn_enum.set(Box::new(new_enum)).map_err(|new_enum| { - RunError::IncompatibleReflectTypes { - span, - expected: dyn_enum.variant_name().to_string(), - actual: new_enum - .downcast::() - .unwrap() - .variant_name() - .to_string(), - } - }) + dyn_enum.apply(&new_enum); } else { Err(RunError::EnumVariantNotFound { name: variable, span, - }) - }? + })? + } } Expression::StructObject { name, map } => { - let map: HashMap = map + let variant_info = enum_info.variant(&name).ok_or( + RunError::EnumVariantNotFound { + name: name.clone(), + span: span.clone(), + }, + )?; + let VariantInfo::Struct(variant_info) = variant_info else { + return todo_error!("{variant_info:?}"); + }; + + let map: HashMap<_, _> = map .into_iter() .map(|(k, v)| { + let ty = variant_info + .field(&k) + .ok_or(RunError::EnumVariantStructFieldNotFound { + field_name: k.clone(), + variant_name: name.clone(), + span: span.clone(), + })? + .type_path_table() + .short_path() + .to_owned(); Ok(( k, - eval_expression( - v, - EvalParams { - world, - environment, - registrations, - }, - )?, + ( + eval_expression( + v, + EvalParams { + world, + environment, + registrations, + }, + )?, + ty, + ), )) }) .collect::>()?; @@ -251,6 +267,7 @@ fn eval_expression( } _ => { let span = value_expr.span.clone(); + let ty = reflect.reflect_short_type_path().to_owned(); let value = eval_expression( *value_expr, EvalParams { @@ -259,7 +276,7 @@ fn eval_expression( registrations, }, )?; - let value_reflect = value.reflect(); + let value_reflect = value.reflect(&ty); let mut dyn_reflect = resource.mut_dyn_reflect(world, registrations); diff --git a/src/builtin_parser/runner/error.rs b/src/builtin_parser/runner/error.rs index 5c881e7..64b162e 100644 --- a/src/builtin_parser/runner/error.rs +++ b/src/builtin_parser/runner/error.rs @@ -49,6 +49,11 @@ pub enum RunError { actual: &'static str, span: Span, }, + EnumVariantStructFieldNotFound { + field_name: String, + variant_name: String, + span: Span, + }, } impl RunError { @@ -69,6 +74,7 @@ impl RunError { CannotBorrowValue(span) => vec![span.clone()], IncompatibleReflectTypes { span, .. } => vec![span.clone()], EnumVariantNotFound { span, .. } => vec![span.clone()], + EnumVariantStructFieldNotFound { span, .. } => vec![span.clone()], CannotMoveOutOfResource(Spanned { span, .. }) => vec![span.clone()], CannotNegateUnsignedInteger(Spanned { span, .. }) => vec![span.clone()], IncompatibleNumberTypes { span, .. } => vec![span.clone()], @@ -105,11 +111,18 @@ impl RunError { VariableMoved(Spanned { value, .. }) => format!("Variable `{value}` was moved.").into(), CannotBorrowValue(_) => todo!(), IncompatibleReflectTypes { - expected, - actual, - span, - } => todo!(), + expected, actual, .. + } => format!( + "Cannot set incompatible reflect types. Expected `{expected}`, got `{actual}`" + ) + .into(), EnumVariantNotFound { name, span } => todo!(), + EnumVariantStructFieldNotFound { + field_name, + variant_name, + .. + } => format!("Field `{field_name}` doesn't exist on struct variant `{variant_name}`.") + .into(), CannotMoveOutOfResource(Spanned { value, .. }) => { format!("Cannot move out of resource `{value}`, try borrowing it instead.").into() } diff --git a/src/builtin_parser/runner/reflection.rs b/src/builtin_parser/runner/reflection.rs index b52c718..1935edd 100644 --- a/src/builtin_parser/runner/reflection.rs +++ b/src/builtin_parser/runner/reflection.rs @@ -41,10 +41,10 @@ impl IntoResource { } } -pub fn object_to_dynamic_struct(hashmap: HashMap) -> DynamicStruct { +pub fn object_to_dynamic_struct(hashmap: HashMap) -> DynamicStruct { let mut dynamic_struct = DynamicStruct::default(); - for (key, value) in hashmap { - dynamic_struct.insert_boxed(&key, value.reflect()); + for (key, (value, reflect)) in hashmap { + dynamic_struct.insert_boxed(&key, value.reflect(&reflect)); } dynamic_struct } diff --git a/src/builtin_parser/runner/unique_rc.rs b/src/builtin_parser/runner/unique_rc.rs index f8a19f4..1fb3f47 100644 --- a/src/builtin_parser/runner/unique_rc.rs +++ b/src/builtin_parser/runner/unique_rc.rs @@ -1,5 +1,5 @@ use std::{ - cell::{Cell, Ref, RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, fmt::Debug, ops::{Deref, DerefMut}, rc::{Rc, Weak}, diff --git a/src/builtin_parser/runner/value.rs b/src/builtin_parser/runner/value.rs index 1dc7a98..2c17791 100644 --- a/src/builtin_parser/runner/value.rs +++ b/src/builtin_parser/runner/value.rs @@ -53,10 +53,12 @@ pub enum Value { impl Value { /// Converts this value into a [`Box`]. - pub fn reflect(self) -> Box { + /// + /// `ty` is used for type inference. + pub fn reflect(self, ty: &str) -> Box { match self { Value::None => Box::new(()), - Value::Number(number) => number.reflect(), + Value::Number(number) => number.reflect(ty), Value::Boolean(boolean) => Box::new(boolean), Value::String(string) => Box::new(string), Value::Reference(reference) => todo!(), @@ -64,8 +66,10 @@ impl Value { let mut dyn_struct = DynamicStruct::default(); for (name, value) in object { - dyn_struct - .insert_boxed(&name, Rc::try_unwrap(value).unwrap().into_inner().reflect()); + dyn_struct.insert_boxed( + &name, + Rc::try_unwrap(value).unwrap().into_inner().reflect(ty), + ); } Box::new(dyn_struct)