Wow I should ahve committed a long time ago

Going down a rabbit hole trying to make a parser macro.
Learning how to make a proc macro is... a steep learning curve.
attempt/001
Elijah C. Voigt 1 year ago
parent 8f3472c4cd
commit 6207a7f032

@ -25,6 +25,10 @@ rustflags = [
[target.x86_64-pc-windows-msvc]
linker = "rust-lld.exe" # Use LLD Linker
rustflags = [
"-Zshare-generics=n", # This needs to be off if you use dynamic linking on Windows.
"-Zthreads=0"
]
[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"

441
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -3,8 +3,14 @@ name = "acts-of-gods"
version = "0.1.0"
edition = "2021"
[workspace]
members = [
"crates/*"
]
[dependencies]
bevy = { version = "0.14", features = ["file_watcher", "dynamic_linking"] }
parser = { path = "crates/parser" }
bevy = { version = "0.14", features = ["file_watcher"] } # , "dynamic_linking"] }
wee_alloc = "*"
bevy_mod_picking = "0.20"
thiserror = "1"
@ -12,17 +18,17 @@ nom = "7"
# Entity Uuid parsing
uuid = "1.7.0"
# Enable a small amount of optimization in debug mode
[profile.dev]
opt-level = 1
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
[profile.dev.package."*"]
opt-level = 3
# Prioritize binary size for wasm
[profile.release]
codegen-units = 1
lto = "thin"
[profile.wasm-release]
inherits = "release"
opt-level = "z"
lto = "fat"
codegen-units = 1
opt-level = "s"
strip = "debuginfo"

@ -0,0 +1,4 @@
entities/camera.entity
entities/ui_container.entity
entities/ui_title.entity
entities/window.entity

@ -0,0 +1,2 @@
entities/camera.entity
entities/van.entity

@ -0,0 +1,12 @@
[package]
name = "parser"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
nom = "7"
syn = "2"
quote = "1"

@ -0,0 +1,92 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, token::Paren, Expr, Ident, Type, TypeTuple};
#[derive(Debug)]
enum Component {
// Members(Vec<Component>),
Member {
tag: Ident,
inputs: Vec<Type>,
}
}
impl syn::parse::Parse for Component {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
// TODO: Handle components with multiple struct members
let tag: Ident = input.parse()?;
let mut inputs = Vec::new();
while let Ok(ty) = input.parse() {
inputs.push(ty)
}
Ok(Component::Member { tag, inputs })
}
}
///
/// Macro for generating parsing functions for entity components.
///
/// ```
/// let line = "foo 1.2 2.3";
/// let (x, y) = parse!("foo <f32> <f32>")(line).unwrap();
/// ```
///
#[proc_macro]
pub fn parse(tokens: TokenStream) -> TokenStream {
match parse_macro_input!(tokens as Component) {
Component::Member { tag, inputs } => {
// For each input value
// nom::character::complete::space1,
// Match on type to determine parsing function (either float or string likely)
// nom::number::complete::float,
let parsers = Vec::new();
let nom_tuple = quote! {
nom::bytes::complete::tag("#tag"),
#(nom::character::complete::space1, #parsers),*
};
let parsed_vars = Vec::new();
let nom_results = quote! {
#(#parsed_vars),*
};
let nom_output_type = quote! { #(#inputs),* };
let nom_outputs = quote! {
// (x1, x2, ...)
};
let expanded = quote! {
|line: &str| -> Result<#nom_output_type, nom::Err<_>> {
tuple(#nom_tuple)(line).map(|(_, #nom_results)| #nom_outputs)
}
};
TokenStream::from(expanded)
}
}
}
// let t = nom::bytes::complete::take_while1(nom::character::is_alphabetic)(todo!()).unwrap();
// let return_type = todo!();
// let method_body = todo!();
// let return_type = "Result<(f32, f32, f32), nom::Err<()>>";
// let method_body = "
// nom::sequence::tuple((
// nom::bytes::complete::tag(\"thing\"),
// nom::character::complete::space1,
// nom::number::complete::float,
// nom::character::complete::space1,
// nom::number::complete::float,
// nom::character::complete::space1,
// nom::number::complete::float
// ))(line)
// .map(|(_, (_, _, x, _, y, _, z))| {
// (x, y, z)
// })
// ";
// let lambda = format!("|line: &str| -> {} {{ {} }}", return_type, method_body);
// lambda.parse().unwrap()

@ -0,0 +1,7 @@
use parser::parse;
fn main() {
let line = "thing 1.23 3.45 5.67";
let f = parse!(thing f32 f32 f32);
let (_x, _y, _z) = f(line).unwrap();
}

@ -20,6 +20,4 @@ pub(crate) use nom::{
pub(crate) use uuid::Uuid;
pub(crate) use thiserror::Error;
pub(crate) use crate::{
conditions::*,
};
pub(crate) use crate::conditions::*;

@ -11,10 +11,11 @@ impl Plugin for SavePlugin {
.register_type::<GltfScene>()
.init_asset::<SaveEntity>()
.init_asset_loader::<SaveEntityLoader>()
.add_systems(Startup, test_save_entity)
.init_asset_loader::<SaveSceneLoader>()
.add_systems(Startup, test_load_entity)
.add_systems(
Update,
check_loaded_entity_assets.run_if(on_event::<AssetEvent<SaveEntity>>()),
spawn_loaded_entities.run_if(on_event::<AssetEvent<SaveEntity>>()),
);
}
}
@ -58,6 +59,7 @@ impl SaveEntity {
}
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
#[reflect(Component)]
struct GltfScene {
gltf: Handle<Gltf>,
name: String,
@ -67,6 +69,17 @@ struct GltfScene {
mod parse {
use super::*;
use parser::parse;
#[test]
fn test_parse_macro() {
let line = "thing 1.23 3.45 5.67";
let f = parse!(thing f32 f32 f32);
let result = f(line);
assert_eq!(Ok((1.23, 3.45, 5.67)), result);
}
#[derive(Error, Debug)]
pub(crate) enum SaveEntityParseError {
#[error("Failed to parse Uuid: {0}")]
@ -193,21 +206,24 @@ mod parse {
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
pub(crate) struct EntityUuid(Uuid);
#[reflect(Component)]
pub(crate) struct EntityUuid {
id: String
}
///
///
pub(crate) fn parse_save_uuid(line: &str) -> Result<EntityUuid, SaveEntityParseError> {
let (remainder, _) = tag("uuid")(line)?;
let uuid = Uuid::try_parse(remainder.trim())?;
Ok(EntityUuid(uuid))
let id = remainder.trim().into();
Ok(EntityUuid { id })
}
#[test]
fn test_parse_uuid() {
let line = "uuid 1c16ab9a-5f79-4340-8469-4086f69c64f2";
let parsed = parse_save_uuid(line).unwrap();
let expected = EntityUuid(Uuid::parse_str("1c16ab9a-5f79-4340-8469-4086f69c64f2").unwrap());
let expected = EntityUuid { id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into() };
assert_eq!(parsed, expected);
}
@ -237,7 +253,8 @@ mod parse {
assert_eq!(parsed, expected);
}
#[derive(Debug, Default, PartialEq, Reflect)]
#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)]
#[reflect_value(Component, Default)]
pub(crate) enum SaveCameraRenderTarget {
#[default]
Default,
@ -347,7 +364,44 @@ impl AssetLoader for SaveEntityLoader {
}
}
fn test_save_entity(loader: Res<AssetServer>, mut commands: Commands) {
#[derive(Default)]
struct SaveSceneLoader;
impl AssetLoader for SaveSceneLoader {
type Asset = DynamicScene;
type Settings = ();
type Error = SaveEntityLoaderError;
async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a (),
load_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let s = std::str::from_utf8(bytes.as_slice()).unwrap();
let asset_path = load_context.path().to_path_buf();
let parent_dir = asset_path.parent().unwrap();
let _sub_assets: Vec<Handle<SaveEntity>> = s.lines().map(|line| {
parent_dir.join(line)
}).map(|path| {
load_context.load(path)
}).collect();
Ok(DynamicScene::default())
}
fn extensions(&self) -> &[&str] {
&["scene"]
}
}
fn test_load_entity(loader: Res<AssetServer>, mut commands: Commands) {
let _: Handle<DynamicScene> = loader.load("editor/_.scene");
let handle: Handle<SaveEntity> = loader.load("levels/00/entities/van.entity");
commands.spawn((
SpatialBundle { ..default() },
@ -355,7 +409,7 @@ fn test_save_entity(loader: Res<AssetServer>, mut commands: Commands) {
));
}
fn check_loaded_entity_assets(
fn spawn_loaded_entities(
query: Query<(Entity, &Handle<SaveEntity>)>,
mut events: EventReader<AssetEvent<SaveEntity>>,
save_entities: Res<Assets<SaveEntity>>,
@ -369,7 +423,11 @@ fn check_loaded_entity_assets(
.for_each(|(entity, _handle)| {
let saved = save_entities.get(*id).unwrap();
// Get entity with SaveEntity handle
let mut e = commands.entity(entity);
// Clear the entity
e.despawn_descendants();
// Populate with reflected components
saved.components.iter().for_each(|dc| {
e.insert_reflect(dc.clone_value());
});

Loading…
Cancel
Save