Adding parsing stuff (parsing the hard way)

attempt/001
Elijah C. Voigt 1 year ago
parent 87ca1b13f6
commit 5ae1379e3a

20
Cargo.lock generated

@ -81,7 +81,6 @@ dependencies = [
"bevy", "bevy",
"bevy_mod_picking", "bevy_mod_picking",
"nom", "nom",
"parser",
"thiserror", "thiserror",
"uuid", "uuid",
"wee_alloc", "wee_alloc",
@ -313,6 +312,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e938630e9f472b1899c78ef84aa907081b23bad8333140e2295c620485b6ee7" checksum = "8e938630e9f472b1899c78ef84aa907081b23bad8333140e2295c620485b6ee7"
dependencies = [ dependencies = [
"bevy_dylib",
"bevy_internal", "bevy_internal",
] ]
@ -521,6 +521,15 @@ dependencies = [
"sysinfo", "sysinfo",
] ]
[[package]]
name = "bevy_dylib"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8494bf550eb30f570da1563217bcea25530cf29b35d35887ca6c2d76a411d00"
dependencies = [
"bevy_internal",
]
[[package]] [[package]]
name = "bevy_ecs" name = "bevy_ecs"
version = "0.14.0" version = "0.14.0"
@ -3172,15 +3181,6 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "parser"
version = "0.1.0"
dependencies = [
"nom",
"quote",
"syn 2.0.71",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.15" version = "1.0.15"

@ -3,13 +3,8 @@ name = "acts-of-gods"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[workspace]
members = [
"crates/*"
]
[dependencies] [dependencies]
bevy = { version = "0.14", features = ["file_watcher"] } # , "dynamic_linking"] } bevy = { version = "0.14", features = ["file_watcher", "dynamic_linking"] }
wee_alloc = "*" wee_alloc = "*"
bevy_mod_picking = "0.20" bevy_mod_picking = "0.20"
thiserror = "1" thiserror = "1"

@ -13,6 +13,9 @@ pub(crate) mod save;
/// Window handling /// Window handling
pub(crate) mod window; pub(crate) mod window;
/// Save file parsing
pub(crate) mod parser;
use crate::prelude::*; use crate::prelude::*;
fn main() { fn main() {

@ -0,0 +1,327 @@
use crate::prelude::*;
#[derive(Error, Debug)]
pub(crate) enum SaveEntityParseError {
#[error("Failed to parse Uuid: {0}")]
Uuid(#[from] uuid::Error),
#[error("Failed to parse name")]
Name,
#[error("Failed to parse Transform")]
Transform,
#[error("Failed to parse Entity")]
Nom(nom::Err<nom::error::Error<Box<str>>>),
#[error("Failed to parse camera")]
Camera,
}
// Convert Nom error to parse error
// https://stackoverflow.com/a/77974858/3096574
impl From<nom::Err<nom::error::Error<&str>>> for SaveEntityParseError {
fn from(err: nom::Err<nom::error::Error<&str>>) -> Self {
SaveEntityParseError::Nom(err.map_input(|input| input.into()))
}
}
fn parse_word<'a>(w: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
move |i: &'a str| tag(w)(i)
}
fn parse_xyz(i: &str) -> IResult<&str, (f32, f32, f32)> {
tuple((float, space1, float, space1, float))(i)
.map(|(s, (x, _, y, _, z))| (s, (x, y, z)))
}
fn parse_wxyz(i: &str) -> IResult<&str, (f32, f32, f32, f32)> {
tuple((
float,
space1,
float,
space1,
float,
space1,
float,
))(i)
.map(|(s, (w, _, x, _, y, _, z))| (s, (w, x, y, z)))
}
fn parse_string(i: &str) -> IResult<&str, &str> {
let (rem, (_, out, _)) = tuple((tag("\""), take_until1("\""), tag("\"")))(i)?;
Ok((rem, out))
}
///
///
pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityParseError> {
let (rem, _) = tag("transform")(line)?;
let mut transform = Transform::default();
let mut curr = rem.trim_start();
for _ in 0..3 {
if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("translation"), space1, parse_xyz))(curr.trim_start()) {
transform.translation = Vec3::new(x, y, z);
curr = rem.trim_start();
} else if let Ok((rem, (_, _, (x, y, z, w)))) = tuple((parse_word("rotation"), space1, parse_wxyz))(curr.trim_start()) {
transform.rotation = Quat::from_xyzw(x, y, z, w);
curr = rem.trim_start();
} else if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("scale"), space1, parse_xyz))(curr.trim_start()) {
transform.scale = Vec3::new(x, y, z);
curr = rem.trim_start();
} else {
return Err(SaveEntityParseError::Transform);
}
}
// Assert there are no trailing characters on the line
debug_assert_eq!(curr, "");
Ok(transform)
}
#[test]
fn test_parse_transform() {
let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3";
let parsed = parse_save_transform(line).unwrap();
let expected = Transform {
translation: Vec3::new(1.0, 2.0, 3.0),
rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0),
scale: Vec3::new(1.1, 1.2, 1.3),
};
assert_eq!(parsed, expected);
}
///
///
pub(crate) fn parse_save_name(line: &str) -> Result<Name, SaveEntityParseError> {
let (remainder, _) = tag("name")(line)?;
let n = remainder.trim().to_string();
if n.is_empty() {
Err(SaveEntityParseError::Name)
} else {
let name = Name::new(n);
Ok(name)
}
}
#[test]
fn test_parse_name() {
{
let line = "name Van";
let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Van");
assert_eq!(parsed, expected);
}
{
let line = "name Big Mike";
let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Big Mike");
assert_eq!(parsed, expected);
}
}
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
#[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 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 { id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into() };
assert_eq!(parsed, expected);
}
///
///
pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), SaveEntityParseError> {
let (rem, (_, _, gltf_path, _, scene_name)) = tuple((
tag("model"),
space1,
parse_string,
space1,
parse_string,
))(line)?;
debug_assert!(rem == "");
Ok((gltf_path.into(), scene_name.into()))
}
#[test]
fn test_parse_model() {
let line = "model \"models/foo.glb\" \"My Scene\"";
let parsed = parse_save_model(line).unwrap();
let expected = (String::from("models/foo.glb"), String::from("My Scene"));
assert_eq!(parsed, expected);
}
#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)]
#[reflect_value(Component, Default)]
pub(crate) enum SaveCameraRenderTarget {
#[default]
Default,
Window(Uuid),
}
pub(crate) fn parse_save_camera(line: &str) -> Result<SaveCameraRenderTarget, SaveEntityParseError> {
if let Ok((rem, _camera)) = tag::<&str, &str, ()>("camera")(line) {
if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) {
if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) {
// Camera + target + window + UUID
if let Ok((rem, (_, uuid))) = tuple((space1::<&str, ()>, take(36usize)))(rem) {
debug_assert!(rem == "");
let parsed_uuid = Uuid::parse_str(uuid)?;
Ok(SaveCameraRenderTarget::Window(parsed_uuid))
// Camera + target + widow
} else {
debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default)
}
// camera + target
} else {
debug_assert!(rem == "");
Err(SaveEntityParseError::Camera)
}
// Just camera
} else {
debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default)
}
// Nothing parsed well
} else {
Err(SaveEntityParseError::Camera)
}
}
#[test]
fn test_parse_camera() {
{
let line = "camera";
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected);
}
{
let line = "camera target window";
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected);
}
{
let line = "camera target";
let parsed = parse_save_camera(line);
assert!(parsed.is_err());
}
{
let line = "camera target window 9a1367e0-71e5-4c79-b4ad-02aa44b68af0";
let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap();
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Window(target_uuid);
assert_eq!(parsed, expected);
}
{
let line = "notcamera";
let parsed = parse_save_camera(line);
assert!(parsed.is_err());
}
}
/// SaveParent entity which is a reference to which entity this is a child of
/// A run-time system converts this to a bevy Parent component
#[derive(Component, PartialEq, Debug, Reflect, Clone)]
#[reflect_value(Component)]
pub(crate) struct SaveParent(String);
/// Parses a parent entity with this format:
/// ```text
/// parent some_other_file.entity
/// ```
pub(crate) fn parse_save_parent(line: &str) -> Result<SaveParent, SaveEntityParseError> {
todo!()
}
#[test]
fn test_parse_parent() {
let line = "parent some_other_file.entity";
let parsed = parse_save_parent(line).unwrap();
let expected = SaveParent("some_other_file.entity".into());
assert_eq!(parsed, expected);
}
///
/// Parse the Window component (which is very big!)
/// We only sparsely define the bits that we want to edit (for now)
///
pub(crate) fn parse_save_window(line: &str) -> Result<Window, SaveEntityParseError> {
todo!()
}
#[test]
fn test_parse_window() {
let line = "window \"Editor\" visible false";
let parsed = parse_save_window(line).unwrap();
let expected = Window { visible: false, title: "Editor".into(), ..default() };
assert_eq!(parsed.visible, expected.visible);
assert_eq!(parsed.title, expected.title);
}
///
/// The UI Text bundle specified as a sparse subset of a bundle
///
pub(crate) fn parse_save_ui_text(line: &str) -> Result<TextBundle, SaveEntityParseError> {
todo!()
}
#[test]
fn test_save_ui_text() {
todo!()
}
///
/// Returns a parser function for a basic stand-alone tag
/// e.g., "editor_tag" or "ui_node"
pub(crate) fn parse_save_tag<T: Component + Reflect>(tag: &str) -> impl FnOnce(&str) -> Result<T, SaveEntityParseError> {
move |line: &str| -> Result<T, SaveEntityParseError> {
todo!()
}
}
#[test]
fn test_save_tag() {
todo!()
}
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
#[reflect(Component)]
pub(crate) struct SaveTargetCamera(String);
/// Parses the a SaveTargetCamera which at runtime is converted to a TargetCamera
pub(crate) fn parse_save_target_camera(line: &str) -> Result<SaveTargetCamera, SaveEntityParseError> {
todo!()
}
#[test]
fn test_target_camera() {
todo!()
}

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

@ -6,8 +6,8 @@ pub(crate) struct SavePlugin;
impl Plugin for SavePlugin { impl Plugin for SavePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app app
.register_type::<parse::EntityUuid>() .register_type::<EntityUuid>()
.register_type::<parse::SaveCameraRenderTarget>() .register_type::<SaveCameraRenderTarget>()
.register_type::<GltfScene>() .register_type::<GltfScene>()
.init_asset::<SaveEntity>() .init_asset::<SaveEntity>()
.init_asset_loader::<SaveEntityLoader>() .init_asset_loader::<SaveEntityLoader>()
@ -34,22 +34,30 @@ impl SaveEntity {
fn parse( fn parse(
text: &str, text: &str,
load_context: &mut LoadContext, load_context: &mut LoadContext,
) -> Result<SaveEntity, parse::SaveEntityParseError> { ) -> Result<SaveEntity, SaveEntityParseError> {
let lines = text.split('\n'); let lines = text.split('\n');
let mut entity = SaveEntity { ..default() }; let mut entity = SaveEntity { ..default() };
lines.into_iter().for_each(|line| { lines.into_iter().for_each(|line| {
if let Ok(name) = parse::parse_save_name(line) { if let Ok(name) = parse_save_name(line) {
entity.components.push(name.clone_value()); entity.components.push(name.clone_value());
} else if let Ok(transform) = parse::parse_save_transform(line) { } else if let Ok(transform) = parse_save_transform(line) {
entity.components.push(transform.clone_value()); entity.components.push(transform.clone_value());
} else if let Ok(uuid) = parse::parse_save_uuid(line) { } else if let Ok(uuid) = parse_save_uuid(line) {
entity.components.push(uuid.clone_value()); entity.components.push(uuid.clone_value());
} else if let Ok((gltf_file, scene_name)) = parse::parse_save_model(line) { } else if let Ok((gltf_file, scene_name)) = parse_save_model(line) {
let gltf_scene = GltfScene { gltf: load_context.load(gltf_file), name: scene_name }; let gltf_scene = GltfScene { gltf: load_context.load(gltf_file), name: scene_name };
entity.components.push(gltf_scene.clone_value()); entity.components.push(gltf_scene.clone_value());
} else if let Ok(target) = parse::parse_save_camera(line) { } else if let Ok(target) = parse_save_camera(line) {
entity.components.push(target.clone_value()); entity.components.push(target.clone_value());
} else if let Ok(parent) = parse_save_parent(line) {
entity.components.push(parent.clone_value());
} else if let Ok(window) = parse_save_window(line) {
entity.components.push(window.clone_value());
// } else if let Ok(ui_text_bundle) = parse_save_ui_text(line) {
// entity.components.push(ui_text_bundle.clone_value());
} else if let Ok(target_camera) = parse_save_target_camera(line) {
entity.components.push(target_camera.clone_value());
} else { } else {
error!("Failed to parse line component `{:?}`", line); error!("Failed to parse line component `{:?}`", line);
} }
@ -65,259 +73,6 @@ struct GltfScene {
name: String, name: String,
} }
mod parse {
use super::*;
#[derive(Error, Debug)]
pub(crate) enum SaveEntityParseError {
#[error("Failed to parse Uuid: {0}")]
Uuid(#[from] uuid::Error),
#[error("Failed to parse name")]
Name,
#[error("Failed to parse Transform")]
Transform,
#[error("Failed to parse Entity")]
Nom(nom::Err<nom::error::Error<Box<str>>>),
#[error("Failed to parse camera")]
Camera,
}
// Convert Nom error to parse error
// https://stackoverflow.com/a/77974858/3096574
impl From<nom::Err<nom::error::Error<&str>>> for SaveEntityParseError {
fn from(err: nom::Err<nom::error::Error<&str>>) -> Self {
SaveEntityParseError::Nom(err.map_input(|input| input.into()))
}
}
fn parse_word<'a>(w: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
move |i: &'a str| {
tag(w)(i)
}
}
fn parse_xyz(i: &str) -> IResult<&str, (f32, f32, f32)> {
tuple((float, space1, float, space1, float))(i)
.map(|(s, (x, _, y, _, z))| (s, (x, y, z)))
}
fn parse_wxyz(i: &str) -> IResult<&str, (f32, f32, f32, f32)> {
tuple((
float,
space1,
float,
space1,
float,
space1,
float,
))(i)
.map(|(s, (w, _, x, _, y, _, z))| (s, (w, x, y, z)))
}
fn parse_string(i: &str) -> IResult<&str, &str> {
let (rem, (_, out, _)) = tuple((tag("\""), take_until1("\""), tag("\"")))(i)?;
Ok((rem, out))
}
///
///
pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityParseError> {
let (rem, _) = tag("transform")(line)?;
let mut transform = Transform::default();
let mut curr = rem.trim_start();
for _ in 0..3 {
if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("translation"), space1, parse_xyz))(curr.trim_start()) {
transform.translation = Vec3::new(x, y, z);
curr = rem.trim_start();
} else if let Ok((rem, (_, _, (x, y, z, w)))) = tuple((parse_word("rotation"), space1, parse_wxyz))(curr.trim_start()) {
transform.rotation = Quat::from_xyzw(x, y, z, w);
curr = rem.trim_start();
} else if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("scale"), space1, parse_xyz))(curr.trim_start()) {
transform.scale = Vec3::new(x, y, z);
curr = rem.trim_start();
} else {
return Err(SaveEntityParseError::Transform);
}
}
// Assert there are no trailing characters on the line
debug_assert_eq!(curr, "");
Ok(transform)
}
#[test]
fn test_parse_transform() {
let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3";
let parsed = parse_save_transform(line).unwrap();
let expected = Transform {
translation: Vec3::new(1.0, 2.0, 3.0),
rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0),
scale: Vec3::new(1.1, 1.2, 1.3),
};
assert_eq!(parsed, expected);
}
///
///
pub(crate) fn parse_save_name(line: &str) -> Result<Name, SaveEntityParseError> {
let (remainder, _) = tag("name")(line)?;
let n = remainder.trim().to_string();
if n.is_empty() {
Err(SaveEntityParseError::Name)
} else {
let name = Name::new(n);
Ok(name)
}
}
#[test]
fn test_parse_name() {
{
let line = "name Van";
let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Van");
assert_eq!(parsed, expected);
}
{
let line = "name Big Mike";
let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Big Mike");
assert_eq!(parsed, expected);
}
}
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
#[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 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 { id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into() };
assert_eq!(parsed, expected);
}
///
///
pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), SaveEntityParseError> {
let (rem, (_, _, gltf_path, _, scene_name)) = tuple((
tag("model"),
space1,
parse_string,
space1,
parse_string,
))(line)?;
debug_assert!(rem == "");
Ok((gltf_path.into(), scene_name.into()))
}
#[test]
fn test_parse_model() {
let line = "model \"models/foo.glb\" \"My Scene\"";
let parsed = parse_save_model(line).unwrap();
let expected = (String::from("models/foo.glb"), String::from("My Scene"));
assert_eq!(parsed, expected);
}
#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)]
#[reflect_value(Component, Default)]
pub(crate) enum SaveCameraRenderTarget {
#[default]
Default,
Window(Uuid),
}
pub(crate) fn parse_save_camera(line: &str) -> Result<SaveCameraRenderTarget, SaveEntityParseError> {
if let Ok((rem, _camera)) = tag::<&str, &str, ()>("camera")(line) {
if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) {
if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) {
// Camera + target + window + UUID
if let Ok((rem, (_, uuid))) = tuple((space1::<&str, ()>, take(36usize)))(rem) {
debug_assert!(rem == "");
let parsed_uuid = Uuid::parse_str(uuid)?;
Ok(SaveCameraRenderTarget::Window(parsed_uuid))
// Camera + target + widow
} else {
debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default)
}
// camera + target
} else {
debug_assert!(rem == "");
Err(SaveEntityParseError::Camera)
}
// Just camera
} else {
debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default)
}
// Nothing parsed well
} else {
Err(SaveEntityParseError::Camera)
}
}
#[test]
fn test_parse_camera() {
{
let line = "camera";
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected);
}
{
let line = "camera target window";
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected);
}
{
let line = "camera target";
let parsed = parse_save_camera(line);
assert!(parsed.is_err());
}
{
let line = "camera target window 9a1367e0-71e5-4c79-b4ad-02aa44b68af0";
let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap();
let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Window(target_uuid);
assert_eq!(parsed, expected);
}
{
let line = "notcamera";
let parsed = parse_save_camera(line);
assert!(parsed.is_err());
}
}
}
#[derive(Default)] #[derive(Default)]
struct SaveEntityLoader; struct SaveEntityLoader;
@ -326,7 +81,7 @@ enum SaveEntityLoaderError {
#[error("Could not load asset: {0}")] #[error("Could not load asset: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error("Could not parse entity: {0}")] #[error("Could not parse entity: {0}")]
Parse(#[from] parse::SaveEntityParseError), Parse(#[from] SaveEntityParseError),
} }
impl AssetLoader for SaveEntityLoader { impl AssetLoader for SaveEntityLoader {

Loading…
Cancel
Save