Răsfoiți Sursa

Prototype of generating code automatically, kinda scuffed

Lucien Greathouse 1 an în urmă
părinte
comite
7fa82725f6
5 a modificat fișierele cu 720 adăugiri și 124 ștergeri
  1. 357 0
      generate/Cargo.lock
  2. 3 0
      generate/Cargo.toml
  3. 224 0
      generate/src/api.rs
  4. 126 0
      generate/src/enums.rs
  5. 10 124
      generate/src/main.rs

+ 357 - 0
generate/Cargo.lock

@@ -0,0 +1,357 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+
+[[package]]
+name = "autocfg"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+
+[[package]]
+name = "clap"
+version = "4.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+
+[[package]]
+name = "fs-err"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "generate"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "fs-err",
+ "heck",
+ "paste",
+ "regex",
+ "walkdir",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "memchr"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

+ 3 - 0
generate/Cargo.toml

@@ -10,5 +10,8 @@ anyhow = "1.0.82"
 clap = { version = "4.5.4", features = ["derive"] }
 fs-err = "2.11.0"
 heck = "0.5.0"
+paste = "1.0.14"
 regex = "1.10.4"
 walkdir = "2.5.0"
+
+[workspace]

+ 224 - 0
generate/src/api.rs

@@ -0,0 +1,224 @@
+use std::io::Write;
+
+use crate::PREFIX;
+
+macro_rules! opaque_struct {
+    ($c_name:ident : $cpp_name:literal {$(
+        $c_ret:ident $cpp_meth:ident($(
+            $c_ty:ident $c_arg:ident
+        ),*) $(const)?;
+    )*}) => {
+        paste::paste! {
+            OpaqueStruct {
+                cpp_name: $cpp_name,
+                c_name: stringify!($c_name),
+                methods: vec![$(
+                    WrapperMethod {
+                        struct_c_name: stringify!($c_name),
+                        cpp_name: stringify!($cpp_meth),
+                        c_name: stringify!([<$c_name _ $cpp_meth>]),
+                        c_ret: stringify!($c_ret),
+                        self_const: stringify!()
+                    },
+                )*],
+            }
+        }
+    };
+}
+
+pub fn define_api() -> Api {
+    let body = opaque_struct!(JPC_Body : "JPH::Body" {
+        JPC_BodyID GetID() const;
+        JPC_BodyType GetBodyType() const;
+        bool IsRigidBody() const;
+        bool IsSoftBody() const;
+        bool IsActive() const;
+        bool IsState() const;
+        bool IsKinematic() const;
+        bool IsDynamic() const;
+        bool CanBeKinematicOrDynamic() const;
+        void SetIsSensor(bool inIsSensor);
+        bool IsSensor() const;
+        void SetCollideKinematicVsNonDynamic(bool inCollide);
+        bool GetCollideKinematicVsNonDynamic() const;
+        void SetUseManifoldReduction(bool inUseReduction);
+        bool GetUseManifoldReduction() const;
+        bool GetUseManifoldReductionWithBody(const Body &inBody2) const;
+        void SetApplyGyroscopicForce(bool inApply);
+        bool GetApplyGyroscopicForce() const;
+        void SetEnhancedInternalEdgeRemoval(bool inApply);
+        bool GetEnhancedInternalEdgeRemoval() const;
+        bool GetEnhancedInternalEdgeRemovalWithBody(const Body &inBody2) const;
+        JPC_MotionType GetMotionType() const;
+        void SetMotionType(JPC_MotionType inMotionType);
+        BroadPhaseLayer GetBroadPhaseLayer() const;
+        ObjectLayer GetObjectLayer() const;
+        const CollisionGroup & GetCollisionGroup() const;
+        CollisionGroup & GetCollisionGroup();
+        void SetCollisionGroup(const CollisionGroup &inGroup);
+        bool GetAllowSleeping() const;
+        void SetAllowSleeping(bool inAllow);
+        void ResetSleepTimer();
+        float GetFriction() const;
+        void SetFriction(float inFriction);
+        float GetRestitution() const;
+        void SetRestitution(float inRestitution);
+        Vec3 GetLinearVelocity() const;
+        void SetLinearVelocity(JPC_Vec3 inLinearVelocity);
+        void SetLinearVelocityClamped(JPC_Vec3 inLinearVelocity);
+        Vec3 GetAngularVelocity() const;
+        void SetAngularVelocity(JPC_Vec3 inAngularVelocity);
+        void SetAngularVelocityClamped(JPC_Vec3 inAngularVelocity);
+        Vec3 GetPointVelocityCOM(JPC_Vec3 inPointRelativeToCOM) const;
+        Vec3 GetPointVelocity(JPC_RVec3 inPoint) const;
+        void AddForce(JPC_Vec3 inForce);
+        void AddForce(JPC_Vec3 inForce, JPC_RVec3 inPosition);
+        void AddTorque(JPC_Vec3 inTorque);
+        Vec3 GetAccumulatedForce() const;
+        Vec3 GetAccumulatedTorque() const;
+        void ResetForce();
+        void ResetTorque();
+        void ResetMotion();
+        Mat44 GetInverseInertia() const;
+        void AddImpulse(JPC_Vec3 inImpulse);
+        void AddImpulse(JPC_Vec3 inImpulse, JPC_RVec3 inPosition);
+        void AddAngularImpulse(JPC_Vec3 inAngularImpulse);
+        void MoveKinematic(JPC_RVec3 inTargetPosition, QuatArg inTargetRotation, float inDeltaTime);
+        bool ApplyBuoyancyImpulse(JPC_RVec3 inSurfacePosition, JPC_Vec3 inSurfaceNormal, float inBuoyancy, float inLinearDrag, float inAngularDrag, JPC_Vec3 inFluidVelocity, JPC_Vec3 inGravity, float inDeltaTime);
+        bool IsInBroadPhase() const;
+        bool IsCollisionCacheInvalid() const;
+        const JPC_Shape* GetShape() const;
+        RVec3 GetPosition() const;
+        Quat GetRotation() const;
+        RMat44 GetWorldTransform() const;
+        RVec3 GetCenterOfMassPosition() const;
+        RMat44 GetCenterOfMassTransform() const;
+        RMat44 GetInverseCenterOfMassTransform() const;
+        const AABox & GetWorldSpaceBounds() const;
+        const MotionProperties *GetMotionProperties() const
+        MotionProperties * GetMotionProperties();
+        const MotionProperties *GetMotionPropertiesUnchecked() const
+        MotionProperties * GetMotionPropertiesUnchecked();
+        uint64_t GetUserData() const;
+        void SetUserData(uint64_t inUserData);
+        Vec3 GetWorldSpaceSurfaceNormal(const SubShapeID &inSubShapeID, JPC_RVec3 inPosition) const;
+        TransformedShape GetTransformedShape() const;
+        BodyCreationSettings GetBodyCreationSettings() const;
+        SoftBodyCreationSettings GetSoftBodyCreationSettings() const;
+    });
+
+    Api {
+        structs: vec![body],
+    }
+}
+
+#[derive(Debug)]
+pub struct Api {
+    structs: Vec<OpaqueStruct>,
+}
+
+impl Api {
+    pub fn header<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        for s in &self.structs {
+            s.header(out)?;
+        }
+
+        Ok(())
+    }
+
+    pub fn implementation<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        for s in &self.structs {
+            s.implementation(out)?;
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug)]
+struct OpaqueStruct {
+    cpp_name: &'static str,
+    c_name: &'static str,
+    methods: Vec<WrapperMethod>,
+}
+
+impl OpaqueStruct {
+    fn method(&mut self, method: impl Into<WrapperMethod>) {
+        let mut method = method.into();
+        method.struct_c_name = self.c_name;
+        self.methods.push(method);
+    }
+
+    fn header<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        let c_name = self.c_name;
+
+        writeln!(out, "typedef struct {c_name} {c_name};")?;
+
+        for method in &self.methods {
+            method.header(out)?;
+        }
+
+        Ok(())
+    }
+
+    fn implementation<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        let c_name = self.c_name;
+        let cpp_name = self.cpp_name;
+
+        writeln!(out, "OPAQUE_WRAPPER({c_name}, {cpp_name})");
+
+        for method in &self.methods {
+            method.implementation(out)?;
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug)]
+struct WrapperMethod {
+    self_const: &'static str,
+    struct_c_name: &'static str,
+    cpp_name: &'static str,
+    c_name: &'static str,
+    c_ret: &'static str,
+}
+
+impl WrapperMethod {
+    fn header<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        let self_const = self.self_const;
+        let struct_c_name = self.struct_c_name;
+        let c_name = self.c_name;
+        let c_ret = self.c_ret;
+
+        writeln!(
+            out,
+            "JPC_API {c_ret} {c_name}({self_const}{struct_c_name}* self);"
+        )?;
+
+        Ok(())
+    }
+
+    fn implementation<W: Write>(&self, out: &mut W) -> anyhow::Result<()> {
+        let self_const = self.self_const;
+        let struct_c_name = self.struct_c_name;
+        let cpp_name = self.cpp_name;
+        let c_name = self.c_name;
+        let c_ret = self.c_ret;
+
+        writeln!(
+            out,
+            "JPC_API {c_ret} {c_name}({self_const} {struct_c_name}* self) {{"
+        )?;
+        writeln!(out, "    return to_jpc(to_jph(self)->{cpp_name}());")?;
+        writeln!(out, "}}")?;
+
+        Ok(())
+    }
+}
+
+impl From<&str> for WrapperMethod {
+    fn from(value: &str) -> Self {
+        todo!()
+    }
+}

+ 126 - 0
generate/src/enums.rs

@@ -0,0 +1,126 @@
+use std::collections::HashMap;
+use std::fmt::Write;
+
+use anyhow::Context;
+use fs_err as fs;
+use heck::AsShoutySnakeCase;
+use regex::Regex;
+use walkdir::WalkDir;
+
+use crate::PREFIX;
+
+pub fn generate() -> anyhow::Result<()> {
+    let mut output = String::new();
+
+    writeln!(output, "// Generated by JoltC-generate").unwrap();
+
+    for entry in WalkDir::new("JoltPhysics/Jolt") {
+        let entry = entry?;
+        let file_name = entry
+            .file_name()
+            .to_str()
+            .context("invalid UTF-8 in file name")?;
+
+        if file_name.ends_with(".h") {
+            eprintln!("Processing {file_name}...");
+
+            let header = fs::read_to_string(entry.path())?;
+
+            convert_enums(&header, &mut output);
+        }
+    }
+
+    println!("{output}");
+
+    Ok(())
+}
+
+fn convert_enums(header: &str, output: &mut String) {
+    struct WipEnum {
+        cpp_name: String,
+        c_name: String,
+        shouty_c_name: String,
+        next_value: u32,
+        num_variants: u32,
+    }
+
+    let enum_types: HashMap<&str, &str> = HashMap::from_iter([
+        ("int", "int"),
+        ("uint", "unsigned int"),
+        ("uint8", "uint8_t"),
+        ("uint16", "uint16_t"),
+        ("uint32", "uint32_t"),
+    ]);
+
+    let enum_class = Regex::new(r"^\s*enum\s+class\s+(\w+)(?:\s*:\s*(\w+))?").unwrap();
+    let enum_member = Regex::new(r"^\s*(\w+)(?:\s*=\s*(.+?)(?:,|/|$))?").unwrap();
+    let end_block = Regex::new(r"^\s*}").unwrap();
+
+    let mut current_enum = None;
+
+    for line in header.lines() {
+        if current_enum.is_none() {
+            if let Some(captures) = enum_class.captures(line) {
+                let mut name = &captures[1];
+                let given_repr = captures.get(2).map(|m| m.as_str()).unwrap_or("int");
+
+                let repr = enum_types
+                    .get(given_repr)
+                    .unwrap_or_else(|| panic!("unknown enum type {given_repr}"));
+
+                // EShapeSubType => ShapeSubType
+                if name.starts_with('E') && name.as_bytes()[1].is_ascii_uppercase() {
+                    name = &name[1..];
+                }
+
+                let c_name = format!("{PREFIX}_{}", name);
+
+                let shouty_c_name =
+                    format!("{}", AsShoutySnakeCase(&c_name)).replace("DO_FS", "DOFS");
+
+                writeln!(output, "typedef {repr} {c_name};").unwrap();
+
+                current_enum = Some(WipEnum {
+                    cpp_name: name.to_owned(),
+                    c_name,
+                    shouty_c_name,
+                    next_value: 0,
+                    num_variants: 0,
+                });
+
+                continue;
+            }
+
+            continue;
+        }
+
+        if let Some(current) = &mut current_enum {
+            if end_block.is_match(line) {
+                writeln!(output).unwrap();
+
+                current_enum = None;
+                continue;
+            }
+
+            if let Some(captures) = enum_member.captures(line) {
+                current.num_variants += 1;
+
+                let name = &captures[1];
+                let given_value = captures.get(2).map(|m| m.as_str().trim().to_string());
+
+                if given_value.is_none() && current.num_variants > 1 && current.next_value == 0 {
+                    panic!("Enum {} variant {name} did not have a value, but is set to use auto values", current.cpp_name);
+                }
+
+                let value = given_value.unwrap_or_else(|| {
+                    let v = current.next_value;
+                    current.next_value += 1;
+                    v.to_string()
+                });
+
+                let c_name = format!("{}_{}", current.shouty_c_name, AsShoutySnakeCase(name));
+                writeln!(output, "static {} {c_name} = {value};", current.c_name).unwrap();
+            }
+        }
+    }
+}

+ 10 - 124
generate/src/main.rs

@@ -1,132 +1,18 @@
-use std::collections::HashMap;
-use std::fmt::Write;
-
-use anyhow::Context;
-use fs_err as fs;
-use heck::AsShoutySnakeCase;
-use regex::Regex;
-use walkdir::WalkDir;
+mod api;
+mod enums;
 
 static PREFIX: &str = "JPC";
 
 fn main() {
-    if let Err(err) = generate() {
-        eprintln!("Fatal error: {err:?}");
-    }
-}
-
-fn generate() -> anyhow::Result<()> {
-    let mut output = String::new();
-
-    writeln!(output, "// Generated by JoltC-generate").unwrap();
-
-    for entry in WalkDir::new("JoltPhysics/Jolt") {
-        let entry = entry?;
-        let file_name = entry
-            .file_name()
-            .to_str()
-            .context("invalid UTF-8 in file name")?;
-
-        if file_name.ends_with(".h") {
-            eprintln!("Processing {file_name}...");
-
-            let header = fs::read_to_string(entry.path())?;
-
-            convert_enums(&header, &mut output);
-        }
-    }
-
-    println!("{output}");
-
-    Ok(())
-}
-
-fn convert_enums(header: &str, output: &mut String) {
-    struct WipEnum {
-        cpp_name: String,
-        c_name: String,
-        shouty_c_name: String,
-        next_value: u32,
-        num_variants: u32,
-    }
-
-    let enum_types: HashMap<&str, &str> = HashMap::from_iter([
-        ("int", "int"),
-        ("uint", "unsigned int"),
-        ("uint8", "uint8_t"),
-        ("uint16", "uint16_t"),
-        ("uint32", "uint32_t"),
-    ]);
-
-    let enum_class = Regex::new(r"^\s*enum\s+class\s+(\w+)(?:\s*:\s*(\w+))?").unwrap();
-    let enum_member = Regex::new(r"^\s*(\w+)(?:\s*=\s*(.+?)(?:,|/|$))?").unwrap();
-    let end_block = Regex::new(r"^\s*}").unwrap();
-
-    let mut current_enum = None;
-
-    for line in header.lines() {
-        if current_enum.is_none() {
-            if let Some(captures) = enum_class.captures(line) {
-                let mut name = &captures[1];
-                let given_repr = captures.get(2).map(|m| m.as_str()).unwrap_or("int");
-
-                let repr = enum_types
-                    .get(given_repr)
-                    .unwrap_or_else(|| panic!("unknown enum type {given_repr}"));
-
-                // EShapeSubType => ShapeSubType
-                if name.starts_with('E') && name.as_bytes()[1].is_ascii_uppercase() {
-                    name = &name[1..];
-                }
-
-                let c_name = format!("{PREFIX}_{}", name);
-
-                let shouty_c_name =
-                    format!("{}", AsShoutySnakeCase(&c_name)).replace("DO_FS", "DOFS");
-
-                writeln!(output, "typedef {repr} {c_name};").unwrap();
-
-                current_enum = Some(WipEnum {
-                    cpp_name: name.to_owned(),
-                    c_name,
-                    shouty_c_name,
-                    next_value: 0,
-                    num_variants: 0,
-                });
-
-                continue;
-            }
-
-            continue;
-        }
-
-        if let Some(current) = &mut current_enum {
-            if end_block.is_match(line) {
-                writeln!(output).unwrap();
-
-                current_enum = None;
-                continue;
-            }
-
-            if let Some(captures) = enum_member.captures(line) {
-                current.num_variants += 1;
-
-                let name = &captures[1];
-                let given_value = captures.get(2).map(|m| m.as_str().trim().to_string());
+    let api = api::define_api();
 
-                if given_value.is_none() && current.num_variants > 1 && current.next_value == 0 {
-                    panic!("Enum {} variant {name} did not have a value, but is set to use auto values", current.cpp_name);
-                }
+    println!("==== HEADER ====");
+    api.header(&mut std::io::stdout());
 
-                let value = given_value.unwrap_or_else(|| {
-                    let v = current.next_value;
-                    current.next_value += 1;
-                    v.to_string()
-                });
+    println!("==== IMPL   ====");
+    api.implementation(&mut std::io::stdout());
 
-                let c_name = format!("{}_{}", current.shouty_c_name, AsShoutySnakeCase(name));
-                writeln!(output, "static {} {c_name} = {value};", current.c_name).unwrap();
-            }
-        }
-    }
+    // if let Err(err) = enums::generate() {
+    //     eprintln!("Fatal error: {err:?}");
+    // }
 }