diff --git a/Cargo.toml b/Cargo.toml
index 9ead302..af4dc6c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,7 +23,30 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-trixy-parser = { path = "./trixy-parser" }
-trixy-macros = { path = "./trixy-macros" }
-trixy-types = { path = "./trixy-types" }
-thiserror = "1.0.57"
+clap = { version = "4.5.4", features = ["derive"], optional = true }
+convert_case = {version = "0.6.0", optional = true}
+proc-macro2 = {version = "1.0.79", optional = true}
+quote = {version = "1.0.35", optional = true}
+syn = { version = "2.0.55", features = ["extra-traits", "full", "parsing"], optional = true }
+thiserror = { version = "1.0.58", optional = true}
+
+# macros
+prettyplease = {version = "0.2.17", optional = true}
+
+# parser
+regex = {version = "1.10.4", optional = true}
+
+# types
+libc ={ version = "0.2.153", optional = true}
+log = { version = "0.4.21", optional = true}
+
+[dev-dependencies]
+# parser
+pretty_assertions = "1.4.0"
+
+[features]
+default = ["parser", "types", "macros"]
+
+parser = [ "regex", "thiserror", "convert_case" ]
+types = [ "parser", "libc", "log", "proc-macro2", "quote", "syn", "thiserror", "convert_case" ]
+macros = [ "parser", "types", "prettyplease", "proc-macro2", "quote", "syn", "convert_case" ]
diff --git a/trixy-parser/generate_docs b/docs/generate_docs
similarity index 92%
rename from trixy-parser/generate_docs
rename to docs/generate_docs
index b486c21..5b7e0b0 100755
--- a/trixy-parser/generate_docs
+++ b/docs/generate_docs
@@ -18,7 +18,7 @@
# and the Lesser GNU General Public License along with this program.
# If not, see .
-ebnf2pdf make "./docs/grammar.ebnf"
-mv grammar.ebnf.pdf ./docs/grammar.pdf
+ebnf2pdf make "./grammar.ebnf"
+mv grammar.ebnf.pdf ./grammar.pdf
# vim: ft=sh
diff --git a/trixy-parser/docs/grammar.ebnf b/docs/grammar.ebnf
similarity index 100%
rename from trixy-parser/docs/grammar.ebnf
rename to docs/grammar.ebnf
diff --git a/trixy-parser/docs/grammar.pdf b/docs/grammar.pdf
similarity index 100%
rename from trixy-parser/docs/grammar.pdf
rename to docs/grammar.pdf
diff --git a/src/lib.rs b/src/lib.rs
index 9be5fae..d9a07b4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,13 +19,13 @@
* If not, see .
*/
-pub mod types {
- pub use trixy_types::*;
-}
+#[cfg(feature = "macros")]
+pub mod macros;
+#[cfg(feature = "types")]
+pub mod types;
+#[cfg(feature = "parser")]
+pub mod parser;
-pub mod macros {
- pub use trixy_macros::*;
-}
pub mod __private {
//! This module contains crates needed for the generated code, it should not be used by humans.
pub mod thiserror {
diff --git a/src/macros/config/file_tree.rs b/src/macros/config/file_tree.rs
new file mode 100644
index 0000000..8ac7949
--- /dev/null
+++ b/src/macros/config/file_tree.rs
@@ -0,0 +1,127 @@
+//! [`FileTree`]s are the fundamental data structure used by trixy to present generated data to
+//! you.
+
+use std::{
+ fmt::Display,
+ fs, io,
+ path::{Path, PathBuf},
+};
+
+use super::trixy::Language;
+
+/// A file tree containing all files that were generated. These are separated into host and
+/// auxiliary files. See their respective descriptions about what differentiates them.
+#[derive(Default, Debug)]
+pub struct FileTree {
+ /// Files, that are supposed to be included in the compiled crate.
+ pub host_files: Vec,
+
+ /// Files, that should be shared with the consumer (e. g. c headers).
+ pub auxiliary_files: Vec,
+}
+
+/// A generated files
+#[derive(Default, Debug)]
+pub struct GeneratedFile {
+ /// The path this generated file would like to be placed at.
+ /// This path is relative to the crate root.
+ pub path: PathBuf,
+
+ /// The content of this file.
+ ///
+ /// This should already be formatted and ready to be used.
+ pub value: String,
+
+ /// The language this file is written in.
+ ///
+ /// # Note
+ /// This can also be a associated language,
+ /// like having this set to [`Language::C`] for a c header file.
+ pub language: Language,
+}
+
+impl GeneratedFile {
+ pub fn new(path: PathBuf, value: String, language: Language) -> Self {
+ Self {
+ path,
+ value,
+ language,
+ }
+ }
+ pub fn new_in_out_dir(name: String, value: String, language: Language, out_dir: &Path) -> Self {
+ let path = out_dir.join(name);
+ Self {
+ path,
+ value,
+ language,
+ }
+ }
+
+ pub fn materialize(self) -> io::Result<()> {
+ fs::create_dir_all(self.path.parent().expect("This path should have a parent"))?;
+ fs::write(self.path, self.value.as_bytes())?;
+ Ok(())
+ }
+}
+
+impl FileTree {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn add_host_file(&mut self, file: GeneratedFile) {
+ self.host_files.push(file)
+ }
+
+ pub fn add_auxiliary_file(&mut self, file: GeneratedFile) {
+ self.auxiliary_files.push(file)
+ }
+
+ pub fn materialize(self) -> io::Result<()> {
+ self.host_files
+ .into_iter()
+ .map(|file| -> io::Result<()> { file.materialize() })
+ .collect::>()?;
+ self.auxiliary_files
+ .into_iter()
+ .map(|file| -> io::Result<()> { file.materialize() })
+ .collect::>()?;
+ Ok(())
+ }
+}
+
+impl Display for Language {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match &self {
+ Language::Rust => f.write_str("rust"),
+ Language::C => f.write_str("c"),
+ Language::Lua => f.write_str("lua"),
+ Language::All => unreachable!("The `all` language variant should never be displayed"),
+ }
+ }
+}
+
+impl Display for GeneratedFile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("File path: `{}`\n", self.path.display()))?;
+ f.write_fmt(format_args!("```{}\n", self.language))?;
+ f.write_fmt(format_args!("{}\r", &self.value))?;
+ f.write_str("```\n\n")
+ }
+}
+
+impl Display for FileTree {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str("# Host files\n")?;
+ self.host_files
+ .iter()
+ .map(|file| -> std::fmt::Result { f.write_str(&file.to_string()) })
+ .collect::()?;
+
+ f.write_str("# Auxiliary files\n")?;
+ self.auxiliary_files
+ .iter()
+ .map(|file| -> std::fmt::Result { f.write_str(&file.to_string()) })
+ .collect::()
+ }
+}
diff --git a/src/macros/config/mod.rs b/src/macros/config/mod.rs
new file mode 100644
index 0000000..5e85912
--- /dev/null
+++ b/src/macros/config/mod.rs
@@ -0,0 +1,2 @@
+pub mod file_tree;
+pub mod trixy;
diff --git a/trixy-macros/src/config/mod.rs b/src/macros/config/trixy.rs
similarity index 62%
rename from trixy-macros/src/config/mod.rs
rename to src/macros/config/trixy.rs
index 71848af..864c325 100644
--- a/trixy-macros/src/config/mod.rs
+++ b/src/macros/config/trixy.rs
@@ -21,64 +21,72 @@
//! This module is responsible for the config passed to trixy.
//! It works using the popular builder syntax:
-//! ```no_run
-//! use trixy_macros::config::{Language, TrixyConfig};
+//! ```
+//! use crate::macros::config::{Language, TrixyConfig};
//!# fn main() {
//! let config = TrixyConfig::new()
-//! .set_input_path("path/to/trixy/api.tri")
-//! .set_output_path("api.rs")
-//! .set_languages(vec![Language::Rust, Language::C])
-//! .set_generate_debug(false);
+//! .trixy_path("path/to/trixy/api.tri")
+//! .output_path("api.rs")
+//! .languages(vec![Language::Rust, Language::C])
//!# }
//! ```
-use std::path::PathBuf;
+use std::{env, path::PathBuf};
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub enum Language {
Rust,
C,
Lua,
+ #[default]
+ All,
}
#[derive(Default, Debug)]
pub struct TrixyConfig {
- /// The Path to the base command interface config file
+ /// The Path to the base command interface config file.
pub trixy_path: PathBuf,
- /// The name of the outputted host code (rust and c bindings)
- /// This file is written in $OUT_DIR
- pub host_code_name: PathBuf,
- /// The name of the c header
- /// This file is written in $OUT_DIR
- pub c_header_name: PathBuf,
+ /// The name of the outputted host code (rust and c bindings).
+ /// This file is written in $OUT_DIR>
+ pub host_code_name: String,
+ /// The name of the c header.
+ /// This file is written in $OUT_DIR.
+ pub c_header_name: String,
/// The path from the root to the distribution directory.
- /// Things like the c headers are copied in this dir
- /// When this is [None] no dist dir will be generated
+ /// Things like the c headers are copied in this dir.
+ /// When this is [None] no dist dir will be generated.
pub dist_dir_path: Option,
- /// Whether to check if the dist dir is empty before writing something to it
- pub check_dist_dir: bool,
-
- /// Should the macro generate Debug trait implementation for each enum
- /// These are very useful but completely obscure the `cargo expand` output
- pub generate_debug: bool,
-
+ // /// Whether to check if the dist dir is empty before writing something to it.
+ // pub check_dist_dir: bool,
/// This function is executed whenever an API function is called.
/// The only argument is the command (encoded as the `Commands`) enum
- /// which is represented by this function
- /// Because of rust limitations this is supposed to be the name of a macro acting as said
- /// function. This macro must be in scope of the generated code
+ /// which is represented by this function.
pub callback_function: String,
+
+ /// This path is used to place the outputted host code files.
+ /// Normally this would be the `$OUT_DIR` environment variable set by cargo at build time.
+ /// You have to set this, if you want to use trixy in an other context.
+ pub out_dir: PathBuf,
}
impl TrixyConfig {
pub fn new>(callback_function: T) -> Self {
+ let out_dir;
+ if let Ok(out_dir_new) = env::var("OUT_DIR") {
+ let out_path = PathBuf::from(out_dir_new);
+ out_dir = out_path;
+ } else {
+ out_dir = PathBuf::default();
+ };
+
Self {
callback_function: callback_function.into(),
host_code_name: "api.rs".into(),
c_header_name: "interface.h".into(),
+ out_dir,
..Default::default()
}
}
@@ -90,13 +98,6 @@ impl TrixyConfig {
}
}
- pub fn generate_debug(self, generate_debug: bool) -> Self {
- Self {
- generate_debug,
- ..self
- }
- }
-
pub fn dist_dir_path>(self, dist_dir_path: T) -> Self {
Self {
dist_dir_path: Some(dist_dir_path.into()),
@@ -104,21 +105,21 @@ impl TrixyConfig {
}
}
- pub fn check_dist_dir(self, check_dist_dir: bool) -> Self {
- Self {
- check_dist_dir,
- ..self
- }
- }
-
- pub fn host_code_name>(self, output_path: T) -> Self {
+ pub fn host_code_name>(self, output_path: T) -> Self {
Self {
host_code_name: output_path.into(),
..self
}
}
- pub fn c_header_name>(self, output_path: T) -> Self {
+ pub fn out_dir>(self, out_dir: T) -> Self {
+ Self {
+ out_dir: out_dir.into(),
+ ..self
+ }
+ }
+
+ pub fn c_header_name>(self, output_path: T) -> Self {
Self {
c_header_name: output_path.into(),
..self
diff --git a/trixy-macros/src/generate.old/command_enum/mod.rs b/src/macros/generate.old/command_enum/mod.rs
similarity index 100%
rename from trixy-macros/src/generate.old/command_enum/mod.rs
rename to src/macros/generate.old/command_enum/mod.rs
diff --git a/trixy-macros/src/generate.old/lua_wrapper/lua_functions_to_globals/mod.rs b/src/macros/generate.old/lua_wrapper/lua_functions_to_globals/mod.rs
similarity index 100%
rename from trixy-macros/src/generate.old/lua_wrapper/lua_functions_to_globals/mod.rs
rename to src/macros/generate.old/lua_wrapper/lua_functions_to_globals/mod.rs
diff --git a/trixy-macros/src/generate.old/lua_wrapper/mod.rs b/src/macros/generate.old/lua_wrapper/mod.rs
similarity index 100%
rename from trixy-macros/src/generate.old/lua_wrapper/mod.rs
rename to src/macros/generate.old/lua_wrapper/mod.rs
diff --git a/trixy-macros/src/generate.old/lua_wrapper/rust_wrapper_functions/mod.rs b/src/macros/generate.old/lua_wrapper/rust_wrapper_functions/mod.rs
similarity index 100%
rename from trixy-macros/src/generate.old/lua_wrapper/rust_wrapper_functions/mod.rs
rename to src/macros/generate.old/lua_wrapper/rust_wrapper_functions/mod.rs
diff --git a/trixy-macros/src/generate.old/mod.rs b/src/macros/generate.old/mod.rs
similarity index 100%
rename from trixy-macros/src/generate.old/mod.rs
rename to src/macros/generate.old/mod.rs
diff --git a/trixy-macros/src/generate/c_api/header/mod.rs b/src/macros/generate/auxiliary/c/mod.rs
similarity index 80%
rename from trixy-macros/src/generate/c_api/header/mod.rs
rename to src/macros/generate/auxiliary/c/mod.rs
index 4ff5d38..f7ee0ff 100644
--- a/trixy-macros/src/generate/c_api/header/mod.rs
+++ b/src/macros/generate/auxiliary/c/mod.rs
@@ -23,14 +23,8 @@
//! It works by firstly listing the functions and then by grouping them into structures, effectively
//! simulating namespaces in c.
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use trixy_parser::command_spec::{Attribute, CommandSpec, NamedType};
-use trixy_types::header_names;
-
use crate::{
- config::TrixyConfig,
- generate::{c_api::type_to_c, identifier_to_rust},
+ macros::config::trixy::TrixyConfig, parser::command_spec::CommandSpec, types::header_names,
};
mod pure_header;
@@ -109,19 +103,3 @@ pub fn generate(trixy: &CommandSpec, _config: &TrixyConfig) -> String {
END_HEADER_GUARD
)
}
-
-fn attribute_to_doc_comment(attribute: &Attribute) -> String {
- if let Attribute::doc(doc_comment) = attribute {
- format!("/** {}\n*/", doc_comment)
- } else {
- "".to_owned()
- }
-}
-
-fn named_type_to_c(named_type: &NamedType) -> TokenStream2 {
- let ident = identifier_to_rust(&named_type.name);
- let c_type = type_to_c(&named_type.r#type, false);
- quote! {
- #c_type #ident
- }
-}
diff --git a/trixy-parser/example/comments.tri b/src/macros/generate/auxiliary/c/pure_header.rs
similarity index 52%
rename from trixy-parser/example/comments.tri
rename to src/macros/generate/auxiliary/c/pure_header.rs
index b99a2af..fe7a795 100644
--- a/trixy-parser/example/comments.tri
+++ b/src/macros/generate/auxiliary/c/pure_header.rs
@@ -19,14 +19,31 @@
* If not, see .
*/
-fn print(message: String);
+use crate::parser::command_spec::{CommandSpec, Enumeration, Structure};
-/// First doc comment
-// Some more text
-mod trinitrix {
- /// Second doc comment
- fn hi(name: String) -> String;
+pub fn generate(trixy: &CommandSpec) -> String {
+ let functions: String = trixy
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_auxiliary_c(&[]))
+ .collect();
+ let namespaces: String = trixy
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_auxiliary_c(&vec![]))
+ .collect();
+ let structures: String = trixy
+ .structures
+ .iter()
+ .map(Structure::to_auxiliary_c)
+ .collect();
+ let enumerations: String = trixy
+ .enumerations
+ .iter()
+ .map(Enumeration::to_auxiliary_c)
+ .collect();
+ format!(
+ "{}\n{}\n{}\n{}",
+ enumerations, structures, functions, namespaces
+ )
}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/multiple.tri b/src/macros/generate/auxiliary/c/structs_init.rs
similarity index 70%
rename from trixy-parser/example/multiple.tri
rename to src/macros/generate/auxiliary/c/structs_init.rs
index ff59b64..c9b851b 100644
--- a/trixy-parser/example/multiple.tri
+++ b/src/macros/generate/auxiliary/c/structs_init.rs
@@ -19,15 +19,15 @@
* If not, see .
*/
-fn print(message: CommandTransferValue);
+use proc_macro2::TokenStream as TokenStream2;
-mod trinitrix {
- fn hi(name: String) -> String;
+use crate::parser::command_spec::CommandSpec;
+
+pub fn generate(trixy: &CommandSpec) -> String {
+ let struct_initializer: TokenStream2 = trixy
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_auxiliary_c_full_struct_init(&vec![]))
+ .collect();
+ struct_initializer.to_string()
}
-
-mod trinitrix {
- fn ho(name: String, name2: String) -> String;
-}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/failing_types.tri b/src/macros/generate/auxiliary/c/typedef.rs
similarity index 72%
rename from trixy-parser/example/failing_types.tri
rename to src/macros/generate/auxiliary/c/typedef.rs
index a4c5ca2..37b233b 100644
--- a/trixy-parser/example/failing_types.tri
+++ b/src/macros/generate/auxiliary/c/typedef.rs
@@ -19,12 +19,15 @@
* If not, see .
*/
-struct Callback {
- func: Function,
- timeout: Integer,
+use crate::parser::command_spec::{CommandSpec, Namespace};
+
+pub fn generate(trixy: &CommandSpec) -> String {
+ let type_defs: String = trixy
+ .namespaces
+ .iter()
+ .rev()
+ .map(Namespace::to_auxiliary_c_full_typedef)
+ .collect::>()
+ .join("\n");
+ type_defs.to_string()
}
-
-fn execute_callback(callback: Name);
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/src/macros/generate/auxiliary/mod.rs b/src/macros/generate/auxiliary/mod.rs
new file mode 100644
index 0000000..614991f
--- /dev/null
+++ b/src/macros/generate/auxiliary/mod.rs
@@ -0,0 +1,47 @@
+use std::io::Write;
+use std::process::{Command, Stdio};
+
+use crate::{
+ macros::{config::trixy::TrixyConfig, VIM_LINE_C},
+ parser::command_spec::CommandSpec,
+};
+
+pub mod c;
+
+// FIXME(@soispha): We made to promise to not panic (outside of the toplevel generate function).
+// Therefore these panics here should be avoided. <2024-03-25>
+pub fn format_c(input: String) -> String {
+ let mut clang_format = Command::new("clang-format")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .args(["--style", "GNU"])
+ .spawn()
+ .expect("`clang-format` is a dependency and should be provided by the user");
+
+ let mut stdin = clang_format
+ .stdin
+ .take()
+ .expect("We should be able to take stdin");
+ std::thread::spawn(move || {
+ stdin
+ .write_all(input.as_bytes())
+ .expect("Should be able to write to stdin");
+ });
+
+ let output = clang_format
+ .wait_with_output()
+ .expect("Should be able to read stdout");
+ String::from_utf8(output.stdout).expect("The input was utf8, it should not have changed")
+}
+
+pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> String {
+ let c_code = c::generate(trixy, config);
+ let c_code = format_c(c_code);
+
+ format!(
+ "
+{}\n{}
+",
+ c_code, VIM_LINE_C
+ )
+}
diff --git a/src/macros/generate/convert/auxiliary/c/attribute/mod.rs b/src/macros/generate/convert/auxiliary/c/attribute/mod.rs
new file mode 100644
index 0000000..9ed3ede
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/attribute/mod.rs
@@ -0,0 +1,11 @@
+use crate::parser::command_spec::Attribute;
+
+impl Attribute {
+ pub fn to_auxiliary_c(&self) -> String {
+ if let Attribute::doc(doc_comment) = self {
+ format!("/**\n {}\n*/", doc_comment)
+ } else {
+ "".to_owned()
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs b/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs
new file mode 100644
index 0000000..3a28455
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs
@@ -0,0 +1,36 @@
+use crate::parser::command_spec::{Attribute, DocIdentifier, Enumeration};
+
+impl Enumeration {
+ pub fn to_auxiliary_c(&self) -> String {
+ let doc_comments: String = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+ let ident = &self.identifier.to_auxiliary_c();
+ let states = self
+ .states
+ .iter()
+ .map(DocIdentifier::to_auxiliary_c)
+ .collect::();
+ let states = if self.states.is_empty() {
+ "/**
+ * This enum does not have variants on the rust side
+ * to work around c limitiation with variant-less enums
+ * we added a `__never` variant:
+ */
+ __never,"
+ .to_owned()
+ } else {
+ states
+ };
+ format!(
+ "
+ {}
+ {} {{
+ {}
+ }};",
+ doc_comments, ident, states
+ )
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/function/mod.rs b/src/macros/generate/convert/auxiliary/c/function/mod.rs
new file mode 100644
index 0000000..7bed115
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/function/mod.rs
@@ -0,0 +1,77 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Attribute, Function, Identifier, NamedType};
+
+impl Function {
+ pub fn to_auxiliary_c(&self, namespaces: &[&Identifier]) -> String {
+ let doc_comments: String = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+ let ident = self.identifier.to_c_with_path(namespaces);
+ let inputs: Vec = self.inputs.iter().map(NamedType::to_auxiliary_c).collect();
+
+ let function_output = if let Some(out) = &self.output {
+ let type_name = &out.to_auxiliary_c(true);
+ let comma = if !inputs.is_empty() {
+ quote! {
+ ,
+ }
+ } else {
+ TokenStream2::default()
+ };
+ quote! {
+ #type_name trixy_output #comma
+ }
+ } else {
+ TokenStream2::default()
+ };
+
+ let output = quote! {
+ extern int #ident(#function_output #(#inputs),*);
+ };
+ format!("{}{}\n", doc_comments, output)
+ }
+
+ pub fn to_auxiliary_c_namespace_init(&self, namespaces: &[&Identifier]) -> TokenStream2 {
+ let ident = &self.identifier.to_rust();
+ let full_ident = &self.identifier.to_c_with_path(namespaces);
+
+ quote! {
+ . #ident = #full_ident,
+ }
+ }
+
+ pub fn to_auxiliary_c_typedef(&self) -> TokenStream2 {
+ let ident = self.identifier.to_rust();
+
+ let (output, output_comma) = if let Some(output) = &self.output {
+ let output = output.to_auxiliary_c(true);
+ (quote! { #output }, quote! {,})
+ } else {
+ (TokenStream2::default(), TokenStream2::default())
+ };
+
+ let inputs: TokenStream2 = if self.inputs.is_empty() && output.is_empty() {
+ quote! { void }
+ } else if !self.inputs.is_empty() && !output.is_empty() {
+ let inputs: Vec = self
+ .inputs
+ .iter()
+ .map(|named_type| &named_type.r#type)
+ .map(|r#type| r#type.to_auxiliary_c(false))
+ .collect();
+ quote! {
+ #output_comma #(#inputs),*
+ }
+ } else {
+ TokenStream2::default()
+ };
+
+ quote! {
+ int (* #ident ) (#output #inputs);
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/identifier/doc_identifier.rs b/src/macros/generate/convert/auxiliary/c/identifier/doc_identifier.rs
new file mode 100644
index 0000000..8901839
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/identifier/doc_identifier.rs
@@ -0,0 +1,13 @@
+use crate::parser::command_spec::{Attribute, DocIdentifier};
+
+impl DocIdentifier {
+ pub fn to_auxiliary_c(&self) -> String {
+ let doc_comments: String = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+ let ident = &self.name;
+ format!("{}{},", doc_comments, ident)
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/identifier/mod.rs b/src/macros/generate/convert/auxiliary/c/identifier/mod.rs
new file mode 100644
index 0000000..321bded
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/identifier/mod.rs
@@ -0,0 +1,42 @@
+use convert_case::{Case, Casing};
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Identifier, Variant};
+
+mod doc_identifier;
+
+//
+// pub use doc_identifier::*;
+
+impl Identifier {
+ pub fn to_auxiliary_c(&self) -> TokenStream2 {
+ let ident = self.to_rust_pascalized();
+ match &self.variant {
+ Variant::Structure { .. } => {
+ let ident = self.to_rust_pascalized();
+ quote! {
+ struct #ident
+ }
+ }
+ Variant::Enumeration { .. } => {
+ quote! {
+ enum #ident
+ }
+ }
+ Variant::Primitive => match self.name.to_case(Case::Snake).as_str() {
+ "string" => {
+ quote! {
+ const char*
+ }
+ }
+ other => {
+ todo!("'{}' is not yet supported", other)
+ }
+ },
+ other => {
+ unimplemented!("{:#?}", other)
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/mod.rs b/src/macros/generate/convert/auxiliary/c/mod.rs
new file mode 100644
index 0000000..1dee304
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/mod.rs
@@ -0,0 +1,16 @@
+mod attribute;
+mod enumeration;
+mod function;
+mod identifier;
+mod namespace;
+mod structure;
+mod r#type;
+
+
+// pub use attribute::*;
+// pub use enumeration::*;
+// pub use function::*;
+// pub use identifier::*;
+// pub use namespace::*;
+// pub use structure::*;
+// pub use r#type::*;
diff --git a/src/macros/generate/convert/auxiliary/c/namespace/mod.rs b/src/macros/generate/convert/auxiliary/c/namespace/mod.rs
new file mode 100644
index 0000000..2361a87
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/namespace/mod.rs
@@ -0,0 +1,122 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, quote};
+
+use crate::parser::command_spec::{
+ Attribute, Enumeration, Function, Identifier, Namespace, Structure,
+};
+
+impl Namespace {
+ pub fn to_auxiliary_c(&self, namespaces: &Vec<&Identifier>) -> String {
+ let mut nasps = namespaces.clone();
+ nasps.push(&self.name);
+
+ let structures: String = self
+ .structures
+ .iter()
+ .map(Structure::to_auxiliary_c)
+ .collect::>()
+ .join("\n");
+ let enumerations: String = self
+ .enumerations
+ .iter()
+ .map(Enumeration::to_auxiliary_c)
+ .collect::>()
+ .join("\n");
+ let functions: String = self
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_auxiliary_c(&nasps))
+ .collect::>()
+ .join("\n");
+ let namespaces: String = self
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_auxiliary_c(&nasps))
+ .collect();
+
+ format! {"{}\n{}\n{}\n{}", enumerations, structures, functions, namespaces}
+ }
+
+ pub fn to_auxiliary_c_full_struct_init(&self, namespaces: &Vec<&Identifier>) -> TokenStream2 {
+ let mut input_namespaces = namespaces.clone();
+ input_namespaces.push(&self.name);
+
+ let ident = &self.name.to_rust();
+ let type_ident = ident.clone();
+
+ let functions: TokenStream2 = self
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_auxiliary_c_namespace_init(&input_namespaces))
+ .collect();
+ let namespaces: TokenStream2 = self
+ .namespaces
+ .iter()
+ .map(Namespace::to_auxiliary_c_namespace_init)
+ .collect();
+
+ let next_namespace: TokenStream2 = self
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_auxiliary_c_full_struct_init(&input_namespaces))
+ .collect();
+
+ quote! {
+ #next_namespace
+
+ const struct #type_ident #ident = {
+ #functions
+ #namespaces
+ };
+ }
+ }
+ pub fn to_auxiliary_c_typedef(&self) -> TokenStream2 {
+ let ident = &self.name.to_rust();
+ let type_ident = ident.clone();
+
+ quote! {
+ struct #type_ident #ident;
+ }
+ }
+ pub fn to_auxiliary_c_full_typedef(&self) -> String {
+ let ident = format_ident!("{}", self.name.name);
+ let doc_comments = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+
+ let functions: TokenStream2 = self
+ .functions
+ .iter()
+ .map(Function::to_auxiliary_c_typedef)
+ .collect();
+ let namespaces: TokenStream2 = self
+ .namespaces
+ .iter()
+ .map(Namespace::to_auxiliary_c_typedef)
+ .collect();
+ let next_namespace: String = self
+ .namespaces
+ .iter()
+ .map(Namespace::to_auxiliary_c_full_typedef)
+ .collect::>()
+ .join("\n");
+
+ let namespace = quote! {
+ struct #ident {
+ #functions
+ #namespaces
+ };
+ };
+ format! {"{}\n{}{}\n", next_namespace, doc_comments, namespace}
+ }
+
+ pub fn to_auxiliary_c_namespace_init(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+
+ quote! {
+ . #ident = #ident ,
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/structure/mod.rs b/src/macros/generate/convert/auxiliary/c/structure/mod.rs
new file mode 100644
index 0000000..f533b45
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/structure/mod.rs
@@ -0,0 +1,25 @@
+use crate::parser::command_spec::{Attribute, DocNamedType, Structure};
+
+impl Structure {
+ pub fn to_auxiliary_c(&self) -> String {
+ let doc_comments: String = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+ let ident = self.identifier.to_rust();
+ let contents = self
+ .contents
+ .iter()
+ .map(DocNamedType::to_auxiliary_c)
+ .collect::();
+ format!(
+ "
+ {}
+ {} {{
+ {}
+ }};",
+ doc_comments, ident, contents
+ )
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/type/doc_named_type.rs b/src/macros/generate/convert/auxiliary/c/type/doc_named_type.rs
new file mode 100644
index 0000000..21deaf4
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/type/doc_named_type.rs
@@ -0,0 +1,14 @@
+use crate::parser::command_spec::{Attribute, DocNamedType};
+
+impl DocNamedType {
+ pub fn to_auxiliary_c(&self) -> String {
+ let doc_comments: String = self
+ .attributes
+ .iter()
+ .map(Attribute::to_auxiliary_c)
+ .collect::();
+ let ident = &self.name.to_rust();
+ let r#type = self.r#type.to_auxiliary_c(false);
+ format!("{}{} {};", doc_comments, r#type, ident)
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/type/mod.rs b/src/macros/generate/convert/auxiliary/c/type/mod.rs
new file mode 100644
index 0000000..6ee7989
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/type/mod.rs
@@ -0,0 +1,52 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{NamedType, Type};
+
+mod doc_named_type;
+mod named_type;
+
+// pub use doc_named_type::*;
+// pub use named_type::*;
+
+impl Type {
+ pub fn to_auxiliary_c(&self, is_output: bool) -> TokenStream2 {
+ match self {
+ Type::Typical {
+ identifier,
+ generic_args: _,
+ } => {
+ let ident = identifier.to_auxiliary_c();
+ let output = if is_output {
+ quote! {
+ *
+ }
+ } else {
+ TokenStream2::default()
+ };
+ quote! {
+ #ident #output
+ }
+ }
+ Type::Function { inputs, output } => {
+ // We cannot return a function pointer as of yet, thus guard against it
+ assert_eq!(is_output, false);
+
+ let output = if let Some(output) = output {
+ output.to_auxiliary_c(false)
+ } else {
+ quote! {
+ void
+ }
+ };
+
+ let inputs: Vec =
+ inputs.iter().map(NamedType::to_auxiliary_c).collect();
+
+ quote! {
+ #output (*name) (#(#inputs),*)
+ }
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/c/type/named_type.rs b/src/macros/generate/convert/auxiliary/c/type/named_type.rs
new file mode 100644
index 0000000..85a506b
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/c/type/named_type.rs
@@ -0,0 +1,14 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::NamedType;
+
+impl NamedType {
+ pub fn to_auxiliary_c(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+ let c_type = self.r#type.to_auxiliary_c(false);
+ quote! {
+ #c_type #ident
+ }
+ }
+}
diff --git a/src/macros/generate/convert/auxiliary/mod.rs b/src/macros/generate/convert/auxiliary/mod.rs
new file mode 100644
index 0000000..ca8f836
--- /dev/null
+++ b/src/macros/generate/convert/auxiliary/mod.rs
@@ -0,0 +1 @@
+mod c;
diff --git a/src/macros/generate/convert/host/c/enumeration/mod.rs b/src/macros/generate/convert/host/c/enumeration/mod.rs
new file mode 100644
index 0000000..768fe46
--- /dev/null
+++ b/src/macros/generate/convert/host/c/enumeration/mod.rs
@@ -0,0 +1,47 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocIdentifier, Enumeration};
+
+impl Enumeration {
+ pub fn to_c(&self) -> TokenStream2 {
+ let ident = &self.identifier.to_c();
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.identifier))
+ .collect();
+
+ let states: Vec = self.states.iter().map(DocIdentifier::to_rust).collect();
+ let paired_type = {
+ let path = &self
+ .identifier
+ .variant
+ .to_rust_path()
+ .expect("This should always be some for enums");
+
+ let ident = &self.identifier.to_rust();
+ if path.is_empty() {
+ quote! {
+ crate :: #ident
+ }
+ } else {
+ quote! {
+ #path :: #ident
+ }
+ }
+ };
+
+ let convertible = &self.derive_from_c_paried_rust(&paired_type);
+ quote! {
+ #doc_comments
+ #[allow(non_camel_case_types)]
+ #[repr(C)]
+ #[derive(Debug)]
+ pub enum #ident {
+ #(#states),*
+ }
+ #convertible
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/function/mod.rs b/src/macros/generate/convert/host/c/function/mod.rs
new file mode 100644
index 0000000..8a14131
--- /dev/null
+++ b/src/macros/generate/convert/host/c/function/mod.rs
@@ -0,0 +1,146 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, quote};
+
+use crate::{
+ macros::config::trixy::TrixyConfig,
+ parser::command_spec::{Function, Identifier, NamedType, Namespace},
+};
+
+impl Function {
+ pub fn to_c(&self, config: &TrixyConfig, namespaces: &Vec<&Identifier>) -> TokenStream2 {
+ let ident = self.identifier.to_c_with_path(namespaces);
+ let inputs: Vec = self
+ .inputs
+ .iter()
+ // FIXME(@soispha): This was `named_type_to_rust_trixy` <2024-03-25>
+ .map(NamedType::to_rust)
+ .collect();
+
+ let callback_function = format_ident!("{}", config.callback_function);
+
+ let command_value: TokenStream2 = self.identifier.to_c_with_path(&namespaces);
+
+ if let Some(r#type) = &self.output {
+ let output_ident = r#type.to_c();
+ quote! {
+ #[no_mangle]
+ pub extern "C" fn #ident(output: *mut #output_ident, #(#inputs),*) -> core::ffi::c_int {
+ let output_val: #output_ident = {
+ let (tx, rx) = trixy::oneshot::channel();
+ #callback_function (#command_value);
+ let recv = rx.recv().expect("The channel should not be closed until this value is received");
+ recv.into()
+ };
+ unsafe {
+ std::ptr::write(output, output_val);
+ }
+ return 1;
+ }
+ }
+ } else {
+ quote! {
+ #[no_mangle]
+ pub extern "C" fn #ident(#(#inputs),*) -> core::ffi::c_int {
+ #callback_function (#command_value);
+ return 1;
+ }
+ }
+ }
+ }
+
+ /// Turns a function in namespaces to the generated host enum path:
+ /// *trixy code:*
+ /// ```text
+ /// fn fn_alone();
+ /// mod one {
+ /// fn fn_one();
+ /// mod two {
+ /// fn fn_two(input: String);
+ /// }
+ /// }
+ /// ```
+ /// *rust enum path for fn_alone:*
+ /// ```
+ /// Commands::fn_alone
+ /// ```
+ /// *rust enum path for fn_one:*
+ /// ```
+ /// // `Commands` is just the name for the top-level namespace
+ /// Commands::One(one::One(
+ /// One::fn_one
+ /// ))
+ /// ```
+ /// *rust enum path for fn_two:*
+ /// ```
+ /// Commands::One(one::One(
+ /// one::two::Two(one::two::Two(
+ /// Two::fn_two {input: String}
+ /// ))))
+ /// ```
+ pub fn to_rust_path(&self, namespaces: &Vec<&Identifier>) -> TokenStream2 {
+ let function_ident = self.to_rust_identifier(NamedType::to_rust_assignment, |_| {
+ quote! {
+ // This is defined in the outer call
+ tx
+ }
+ });
+
+ if namespaces.is_empty() {
+ quote! {
+ Commands:: #function_ident
+ }
+ } else {
+ let nasp_pascal_ident = namespaces.last().expect("We checked").to_rust_pascalized();
+
+ let namespace_path = Namespace::to_rust_path(namespaces);
+
+ let function_call = quote! {
+ #namespace_path :: #nasp_pascal_ident :: #function_ident
+ };
+
+ let output: TokenStream2 = namespaces
+ .iter()
+ .enumerate()
+ .rev()
+ .fold(function_call, |acc, (index, nasp)| {
+ nasp_path_one_part(nasp, &acc, &namespaces, index)
+ });
+
+ output
+ }
+ }
+}
+/// This function add a namespace component to the [input] value like so:
+/// (taking the example from the [function_path_to_rust] function)
+/// ```text
+/// one::two::Two::fn_two [= ]
+/// ->
+/// one::One::Two() [= ]
+/// ->
+/// Commands::One() [= ]
+/// ```
+fn nasp_path_one_part(
+ current_nasp: &Identifier,
+ input: &TokenStream2,
+ namespaces: &Vec<&Identifier>,
+ index: usize,
+) -> TokenStream2 {
+ let namespaces_to_do = &namespaces[..index];
+
+ let ident_pascal = current_nasp.to_rust_pascalized();
+
+ if index == 0 {
+ quote! {
+ Commands :: #ident_pascal ( #input )
+ }
+ } else {
+ let ident_pascal_next = namespaces_to_do
+ .last()
+ .expect("We checked the index")
+ .to_rust_pascalized();
+ let namespace_path = Namespace::to_rust_path(namespaces_to_do);
+ quote! {
+ #namespace_path :: #ident_pascal_next :: #ident_pascal ( #input )
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/identifier/mod.rs b/src/macros/generate/convert/host/c/identifier/mod.rs
new file mode 100644
index 0000000..4fcc9cc
--- /dev/null
+++ b/src/macros/generate/convert/host/c/identifier/mod.rs
@@ -0,0 +1,26 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, ToTokens};
+
+use crate::parser::command_spec::Identifier;
+
+impl Identifier {
+ pub fn to_c_with_path(&self, namespaces: &[&Identifier]) -> TokenStream2 {
+ let namespace_str = namespaces.iter().fold(String::default(), |acc, nasp| {
+ if acc.is_empty() {
+ nasp.name.clone()
+ } else {
+ format!("{}_{}", acc, nasp.name)
+ }
+ });
+
+ if namespace_str.is_empty() {
+ format_ident!("{}", self.name).to_token_stream()
+ } else {
+ format_ident!("{}_{}", namespace_str, self.name).to_token_stream()
+ }
+ }
+
+ pub fn to_c(&self) -> TokenStream2 {
+ format_ident!("{}_c", self.name).to_token_stream()
+ }
+}
diff --git a/src/macros/generate/convert/host/c/mod.rs b/src/macros/generate/convert/host/c/mod.rs
new file mode 100644
index 0000000..894a7c3
--- /dev/null
+++ b/src/macros/generate/convert/host/c/mod.rs
@@ -0,0 +1,15 @@
+mod enumeration;
+mod function;
+mod identifier;
+mod namespace;
+mod structure;
+mod r#type;
+mod variant;
+
+// pub use enumeration::*;
+// pub use function::*;
+// pub use identifier::*;
+// pub use namespace::*;
+// pub use r#type::*;
+// pub use structure::*;
+// pub use variant::*;
diff --git a/src/macros/generate/convert/host/c/namespace/mod.rs b/src/macros/generate/convert/host/c/namespace/mod.rs
new file mode 100644
index 0000000..e990d19
--- /dev/null
+++ b/src/macros/generate/convert/host/c/namespace/mod.rs
@@ -0,0 +1,36 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::{
+ macros::config::trixy::TrixyConfig,
+ parser::command_spec::{Enumeration, Identifier, Namespace, Structure},
+};
+
+impl Namespace {
+ pub fn to_c(&self, config: &TrixyConfig, namespaces: &Vec<&Identifier>) -> TokenStream2 {
+ let ident = &self.name.to_c();
+ let mut namespaces = namespaces.clone();
+ namespaces.push(&self.name);
+
+ let functions: TokenStream2 = self
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_c(&config, &namespaces))
+ .collect();
+ let additional_functions: TokenStream2 = self
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_c(&config, &namespaces))
+ .collect();
+ let structures: TokenStream2 = self.structures.iter().map(Structure::to_c).collect();
+ let enumerations: TokenStream2 = self.enumerations.iter().map(Enumeration::to_c).collect();
+ quote! {
+ pub mod #ident {
+ #enumerations
+ #structures
+ }
+ #functions
+ #additional_functions
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/structure/mod.rs b/src/macros/generate/convert/host/c/structure/mod.rs
new file mode 100644
index 0000000..5932da5
--- /dev/null
+++ b/src/macros/generate/convert/host/c/structure/mod.rs
@@ -0,0 +1,28 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocNamedType, Structure};
+
+impl Structure {
+ pub fn to_c(&self) -> TokenStream2 {
+ let ident = &self.identifier.to_c();
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.identifier))
+ .collect();
+
+ let contents: Vec = self.contents.iter().map(DocNamedType::to_c).collect();
+
+ // TODO: Convertible <2024-03-08>
+ quote! {
+ #doc_comments
+ #[allow(non_camel_case_types)]
+ #[repr(C)]
+ #[derive(Debug)]
+ pub struct #ident {
+ #(#contents),*
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/type/doc_named_type.rs b/src/macros/generate/convert/host/c/type/doc_named_type.rs
new file mode 100644
index 0000000..4a0a8ef
--- /dev/null
+++ b/src/macros/generate/convert/host/c/type/doc_named_type.rs
@@ -0,0 +1,19 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocNamedType, NamedType};
+
+impl DocNamedType {
+ pub fn to_c(&self) -> TokenStream2 {
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.name))
+ .collect();
+ let named_type = &Into::::into(self).to_c();
+ quote! {
+ #doc_comments
+ pub #named_type
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/type/mod.rs b/src/macros/generate/convert/host/c/type/mod.rs
new file mode 100644
index 0000000..26854dd
--- /dev/null
+++ b/src/macros/generate/convert/host/c/type/mod.rs
@@ -0,0 +1,100 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Identifier, NamedType, Type};
+
+mod doc_named_type;
+mod named_type;
+
+// pub use doc_named_type::*;
+// pub use named_type::*;
+
+impl Type {
+ pub fn to_c(&self) -> TokenStream2 {
+ match self {
+ Type::Typical {
+ identifier,
+ generic_args,
+ } => Type::to_c_typical(&identifier, &generic_args),
+ Type::Function { inputs, output } => Type::to_c_function(&inputs, &output),
+ }
+ }
+
+ pub fn to_c_function(inputs: &[NamedType], output: &Option>) -> TokenStream2 {
+ Type::to_rust_function(&inputs, &output)
+ }
+
+ fn to_c_typical(identifier: &Identifier, generic_args: &Vec) -> TokenStream2 {
+ let trixy_build_in_types: Vec<&str> = crate::types::BASE_TYPES
+ .iter()
+ .filter_map(|(name, _)| {
+ if name == &identifier.name {
+ Some(*name)
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ if trixy_build_in_types.is_empty() {
+ // The types was specified in the api.tri file
+
+ let ident = identifier.to_c();
+
+ let namespaces_path = &identifier.variant.to_c_path();
+ let nasp_path = if namespaces_path.is_empty() {
+ quote! {
+ crate ::
+ }
+ } else {
+ let path = namespaces_path;
+ quote! {
+ #path ::
+ }
+ };
+ quote! {
+ #nasp_path #ident
+ }
+ } else {
+ debug_assert_eq!(trixy_build_in_types.len(), 1);
+
+ let type_name = trixy_build_in_types
+ .first()
+ .expect("The names should not be dublicated, this should be the only value");
+
+ match *type_name {
+ "Result" => {
+ let ident_ok = &generic_args.first().expect("This is a result").to_c();
+ let ident_err = &generic_args.last().expect("This is a result").to_c();
+ quote! {
+ // eg: as Convertible>::Ptr,
+ as Convertible>::Ptr
+ }
+ }
+ "Option" => {
+ let value = generic_args
+ .first()
+ .expect("An option does only have one arg")
+ .to_rust();
+ quote! {
+ *const #value
+ }
+ }
+ _ => {
+ let ident = &identifier.to_rust();
+ let generics: TokenStream2 = {
+ let generics: Vec =
+ generic_args.iter().map(|val| val.to_c()).collect();
+ quote! {
+ <#(#generics),*>
+ }
+ };
+
+ quote! {
+ trixy::types:: #ident #generics
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/type/named_type.rs b/src/macros/generate/convert/host/c/type/named_type.rs
new file mode 100644
index 0000000..7d98870
--- /dev/null
+++ b/src/macros/generate/convert/host/c/type/named_type.rs
@@ -0,0 +1,33 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::NamedType;
+
+impl NamedType {
+ pub fn to_c(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+ let r#type = self.r#type.to_c();
+ quote! {
+ #ident : #r#type
+ }
+ }
+ pub fn to_rust_c_assignment(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+ let type_ident = self.r#type.to_c();
+ quote! {
+ #ident : #type_ident
+ }
+ }
+ pub fn to_rust_assignment(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+ quote! {
+ #ident : match #ident.try_into() {
+ Ok(ok) => ok,
+ Err(err) => {
+ trixy::types::traits::errno::set(err);
+ return 0;
+ }
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/c/variant/mod.rs b/src/macros/generate/convert/host/c/variant/mod.rs
new file mode 100644
index 0000000..c2ee82e
--- /dev/null
+++ b/src/macros/generate/convert/host/c/variant/mod.rs
@@ -0,0 +1,36 @@
+use proc_macro2::TokenStream as TokenStream2;
+
+use crate::parser::command_spec::{Identifier, Namespace, Variant};
+
+impl Variant {
+ pub fn to_c_path(&self) -> TokenStream2 {
+ fn mangle_namespace_name(vec: &Vec) -> Vec {
+ vec.into_iter()
+ .map(|ident| {
+ if "" == &ident.name && ident.variant == Variant::RootNamespace {
+ // The [`namespaces_to_path_expansive`] function already deals with
+ // [`RootNamespace`] variants, so we just leave that as is
+ ident.clone()
+ } else {
+ Identifier {
+ name: ident.to_c().to_string(),
+ variant: ident.variant.clone(),
+ }
+ }
+ })
+ .collect()
+ }
+
+ let main_namespace;
+ match self {
+ Variant::Structure { namespace } => {
+ main_namespace = mangle_namespace_name(namespace);
+ }
+ Variant::Enumeration { namespace } => {
+ main_namespace = mangle_namespace_name(namespace);
+ }
+ _ => unreachable!("This should never be called"),
+ }
+ Namespace::to_rust_path_owned(&main_namespace[..])
+ }
+}
diff --git a/src/macros/generate/convert/host/mod.rs b/src/macros/generate/convert/host/mod.rs
new file mode 100644
index 0000000..65d76bf
--- /dev/null
+++ b/src/macros/generate/convert/host/mod.rs
@@ -0,0 +1,2 @@
+pub mod rust;
+pub mod c;
diff --git a/src/macros/generate/convert/host/rust/attribute/mod.rs b/src/macros/generate/convert/host/rust/attribute/mod.rs
new file mode 100644
index 0000000..a486fc7
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/attribute/mod.rs
@@ -0,0 +1,22 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Attribute, Identifier};
+
+impl Attribute {
+ pub fn to_rust(&self, _target: &Identifier) -> TokenStream2 {
+ match self {
+ Attribute::doc(comment) => quote! {
+ #[doc = #comment]
+ },
+ Attribute::error => quote! {
+ // We simply use thiserror here
+ #[derive(trixy::__private::thiserror::Error)]
+ },
+ Attribute::msg(msg) => quote! {
+ #[error(#msg)]
+ },
+ Attribute::derive(_) => unimplemented!("Derive is not used as of now"),
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/derive/enumeration.rs b/src/macros/generate/convert/host/rust/derive/enumeration.rs
new file mode 100644
index 0000000..111198a
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/derive/enumeration.rs
@@ -0,0 +1,48 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{quote, ToTokens};
+
+use crate::parser::command_spec::{Enumeration, Identifier};
+
+impl Enumeration {
+ fn derive_from_paired(
+ &self,
+ ident_self: &TokenStream2,
+ ident_paired: &TokenStream2,
+ paired_type: &TokenStream2,
+ ) -> TokenStream2 {
+ let match_lines: TokenStream2 = self
+ .states
+ .iter()
+ .map(|state| {
+ let name = Into::::into(state).to_rust();
+ quote! {
+ #ident_paired :: #name => Self :: #name,
+ }
+ })
+ .collect();
+ quote! {
+ impl From<#paired_type> for #ident_self {
+ fn from(value: #paired_type) -> Self {
+ match value {
+ #match_lines
+ }
+ }
+ }
+ }
+ }
+ /// This function generates the `From` trait implementation for a given c enumeration
+ pub fn derive_from_c_paried_rust(&self, paired_type: &TokenStream2) -> TokenStream2 {
+ let c_ident = &self.identifier.to_c();
+ let ident = &self.identifier.to_rust();
+
+ self.derive_from_paired(&c_ident.into_token_stream(), &ident, &paired_type)
+ }
+
+ /// This function generates the `From` trait implementation for a given rust enumeration
+ pub fn derive_from_rust_paried_c(&self, paired_type: &TokenStream2) -> TokenStream2 {
+ let c_ident = &self.identifier.to_c();
+ let ident = &self.identifier.to_rust();
+
+ self.derive_from_paired(&ident, &c_ident.into_token_stream(), &paired_type)
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/derive/mod.rs b/src/macros/generate/convert/host/rust/derive/mod.rs
new file mode 100644
index 0000000..51b50c3
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/derive/mod.rs
@@ -0,0 +1,2 @@
+pub mod structure;
+pub mod enumeration;
diff --git a/src/macros/generate/convert/host/rust/derive/structure.rs b/src/macros/generate/convert/host/rust/derive/structure.rs
new file mode 100644
index 0000000..bf653a9
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/derive/structure.rs
@@ -0,0 +1,68 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::Structure;
+
+impl Structure {
+ /// This function generates the `Convertible` implementation for a structure
+ // was: `structure_convertable_derive`
+ pub fn derive_convertible(&self, paired_type: &TokenStream2) -> TokenStream2 {
+ let ident = self.identifier.to_rust();
+
+ let into_fields: TokenStream2 = self
+ .contents
+ .iter()
+ .map(|con| {
+ let ident = &con.name.to_rust();
+ quote! {
+ #ident: self.#ident.into(),
+ }
+ })
+ .collect();
+
+ quote! {
+ impl trixy::types::traits::convert_trait::Convertible for #ident {
+ type Ptr = #paired_type;
+
+ fn into_ptr(self) -> Self::Ptr {
+ Self::Ptr {
+ #into_fields
+ }
+ }
+
+ fn from_ptr(ptr: Self::Ptr) -> Result {
+ todo!()
+ }
+ }
+ }
+ }
+
+ /// This function generates the `TryFrom` trait implementation for a given structure
+ // was: `structure_into_impl`
+ pub fn derive_into_impl(&self, paired_type: &TokenStream2) -> TokenStream2 {
+ let ident = self.identifier.to_rust();
+
+ let try_into_fields: TokenStream2 = self
+ .contents
+ .iter()
+ .map(|con| {
+ let ident = &con.name.to_rust();
+ quote! {
+ #ident: value.#ident.try_into()?,
+ }
+ })
+ .collect();
+
+ quote! {
+ impl TryFrom<#paired_type> for #ident {
+ type Error = trixy::types::error::TypeConversionError;
+
+ fn try_from(value: #paired_type) -> Result {
+ Ok(Self {
+ #try_into_fields
+ })
+ }
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/enumeration/mod.rs b/src/macros/generate/convert/host/rust/enumeration/mod.rs
new file mode 100644
index 0000000..061d167
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/enumeration/mod.rs
@@ -0,0 +1,45 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocIdentifier, Enumeration};
+
+impl Enumeration {
+ pub fn to_rust(&self) -> TokenStream2 {
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.identifier))
+ .collect();
+
+ let ident = self.identifier.to_rust();
+ let states: Vec = self.states.iter().map(DocIdentifier::to_rust).collect();
+
+ let paired_type = {
+ let path = self.identifier.variant.to_c_path();
+
+ let ident = self.identifier.to_c();
+ if path.is_empty() {
+ quote! {
+ crate :: #ident
+ }
+ } else {
+ quote! {
+ #path :: #ident
+ }
+ }
+ };
+
+ // was: `rust_enumeration_into_impl`
+ let convertible = self.derive_from_rust_paried_c(&paired_type);
+
+ quote! {
+ #doc_comments
+ #[allow(non_camel_case_types)]
+ #[derive(Debug)]
+ pub enum #ident {
+ #(#states),*
+ }
+ #convertible
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/function/mod.rs b/src/macros/generate/convert/host/rust/function/mod.rs
new file mode 100644
index 0000000..13f087a
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/function/mod.rs
@@ -0,0 +1,61 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Function, Identifier, NamedType, Type};
+
+impl Function {
+ // was called function_identifier_to_rust
+ pub fn to_rust_identifier(
+ &self,
+ input_fmt_fn: fn(&NamedType) -> TokenStream2,
+ output_fmt_fn: F,
+ ) -> TokenStream2
+ where
+ F: Fn(&Type) -> TokenStream2,
+ {
+ let ident = self.identifier.to_rust();
+ let inputs: Vec = self.inputs.iter().map(input_fmt_fn).collect();
+ let output = &self.output;
+
+ if inputs.is_empty() && output.is_none() {
+ quote! {
+ #ident
+ }
+ } else if output.is_some() {
+ let output = output_fmt_fn(&output.as_ref().expect("We checked"));
+ quote! {
+ #ident {
+ trixy_output: #output ,
+ #(#inputs),*
+ }
+ }
+ } else if output.is_none() && !inputs.is_empty() {
+ quote! {
+ #ident { #(#inputs),* }
+ }
+ } else {
+ unreachable!("All other conditions should be met")
+ }
+ }
+
+ pub fn to_rust(&self, _namespaces: &[&Identifier]) -> TokenStream2 {
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.identifier))
+ .collect();
+
+ let function_ident = self.to_rust_identifier(NamedType::to_rust, move |r#type| {
+ let ident = r#type.to_c();
+ quote! {
+ trixy::oneshot::Sender<#ident>
+ }
+ });
+
+ quote! {
+ #doc_comments
+ #[allow(non_camel_case_types)]
+ #function_ident
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/identifier/doc_identifier.rs b/src/macros/generate/convert/host/rust/identifier/doc_identifier.rs
new file mode 100644
index 0000000..10a5ffa
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/identifier/doc_identifier.rs
@@ -0,0 +1,20 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocIdentifier, Identifier};
+
+impl DocIdentifier {
+ pub fn to_rust(&self) -> TokenStream2 {
+ let attributes: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&Into::::into(self)))
+ .collect();
+ let identifier = Into::::into(self).to_rust();
+
+ quote! {
+ #attributes
+ #identifier
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/identifier/mod.rs b/src/macros/generate/convert/host/rust/identifier/mod.rs
new file mode 100644
index 0000000..5d8b182
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/identifier/mod.rs
@@ -0,0 +1,29 @@
+use convert_case::{Case, Casing};
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, quote};
+
+use crate::parser::command_spec::Identifier;
+
+mod doc_identifier;
+// pub use doc_identifier::*;
+
+impl Identifier {
+ pub fn to_rust(&self) -> TokenStream2 {
+ if self.name == "()" {
+ quote! {
+ ()
+ }
+ } else {
+ let ident = format_ident!("{}", self.name);
+ quote! {
+ #ident
+ }
+ }
+ }
+ pub fn to_rust_pascalized(&self) -> TokenStream2 {
+ let pascal_ident = format_ident!("{}", self.name.to_case(Case::Pascal));
+ quote! {
+ #pascal_ident
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/mod.rs b/src/macros/generate/convert/host/rust/mod.rs
new file mode 100644
index 0000000..27e1e00
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/mod.rs
@@ -0,0 +1,19 @@
+mod attribute;
+mod enumeration;
+mod function;
+mod identifier;
+mod namespace;
+mod structure;
+mod r#type;
+mod variant;
+
+// pub use attribute::*;
+// pub use enumeration::*;
+// pub use function::*;
+// pub use identifier::*;
+// pub use namespace::*;
+// pub use r#type::*;
+// pub use structure::*;
+// pub use variant::*;
+
+pub mod derive;
diff --git a/src/macros/generate/convert/host/rust/namespace/mod.rs b/src/macros/generate/convert/host/rust/namespace/mod.rs
new file mode 100644
index 0000000..9c719bd
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/namespace/mod.rs
@@ -0,0 +1,2 @@
+pub mod path;
+pub mod module;
diff --git a/src/macros/generate/convert/host/rust/namespace/module.rs b/src/macros/generate/convert/host/rust/namespace/module.rs
new file mode 100644
index 0000000..37eb5a2
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/namespace/module.rs
@@ -0,0 +1,59 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Enumeration, Identifier, Namespace, Structure};
+
+impl Namespace {
+ pub fn to_rust_module(&self, namespaces: &Vec<&Identifier>) -> TokenStream2 {
+ let mut namespaces = namespaces.clone();
+ namespaces.push(&self.name);
+ let ident = self.name.to_rust();
+ let enum_ident = self.name.to_rust_pascalized();
+
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.name))
+ .collect();
+ let structures: TokenStream2 = self.structures.iter().map(Structure::to_rust).collect();
+ let enumerations: TokenStream2 =
+ self.enumerations.iter().map(Enumeration::to_rust).collect();
+ let functions: Vec = self
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_rust(&namespaces))
+ .collect();
+ let namespace_modules: Vec = self
+ .namespaces
+ .iter()
+ .map(Self::to_rust_module_enum)
+ .collect();
+ let namespaces: TokenStream2 = self
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_rust_module(&namespaces))
+ .collect();
+
+ quote! {
+ #doc_comments
+ pub mod #ident {
+ #structures
+ #enumerations
+ #[derive(Debug)]
+ pub enum #enum_ident {
+ #(#functions,)*
+ #(#namespace_modules),*
+ }
+ #namespaces
+ }
+ }
+ }
+
+ pub fn to_rust_module_enum(&self) -> TokenStream2 {
+ let pascal_ident = self.name.to_rust_pascalized();
+ let ident = self.name.to_rust();
+ quote! {
+ #pascal_ident(#ident :: #pascal_ident)
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/namespace/path.rs b/src/macros/generate/convert/host/rust/namespace/path.rs
new file mode 100644
index 0000000..cbdff2e
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/namespace/path.rs
@@ -0,0 +1,65 @@
+use std::ops::Deref;
+
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{format_ident, quote};
+
+use crate::parser::command_spec::{Identifier, Namespace, Variant};
+
+impl Namespace {
+ pub fn to_rust_path>(namespaces: &[T]) -> TokenStream2 {
+ namespaces
+ .iter()
+ .fold(TokenStream2::default(), |acc, nasp| {
+ if nasp.variant == Variant::RootNamespace && nasp.name == "" {
+ if acc.is_empty() {
+ quote! {
+ crate
+ }
+ } else {
+ unreachable!("An root namespace can never come, after another namespcae")
+ }
+ } else {
+ let ident = format_ident!("{}", nasp.name);
+ if acc.is_empty() {
+ quote! {
+ crate :: #ident
+ }
+ } else {
+ quote! {
+ #acc :: #ident
+ }
+ }
+ }
+ })
+ }
+ pub fn to_rust_path_owned(namespaces: &[Identifier]) -> TokenStream2 {
+ // PERFORMANCE(@soispha): Reallocating a new vector here can't really be the most efficient
+ // way to do this <2024-03-25>
+ let vec: Vec<&Identifier> = namespaces.iter().map(|val| val).collect();
+ Namespace::to_rust_path(&vec)
+ // namespaces
+ // .iter()
+ // .fold(TokenStream2::default(), |acc, nasp| {
+ // if nasp.variant == Variant::RootNamespace && nasp.name == "" {
+ // if acc.is_empty() {
+ // quote! {
+ // crate
+ // }
+ // } else {
+ // unreachable!("An root namespace can never come, after another namespcae")
+ // }
+ // } else {
+ // let ident = format_ident!("{}", nasp.name);
+ // if acc.is_empty() {
+ // quote! {
+ // crate :: #ident
+ // }
+ // } else {
+ // quote! {
+ // #acc :: #ident
+ // }
+ // }
+ // }
+ // })
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/structure/mod.rs b/src/macros/generate/convert/host/rust/structure/mod.rs
new file mode 100644
index 0000000..db84fac
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/structure/mod.rs
@@ -0,0 +1,43 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocNamedType, Structure};
+
+impl Structure {
+ pub fn to_rust(&self) -> TokenStream2 {
+ let doc_comments: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.identifier))
+ .collect();
+
+ let ident = &self.identifier.to_rust();
+ let c_ident = {
+ let path = &self.identifier.variant.to_c_path();
+ let ident = &self.identifier.to_c();
+ if path.is_empty() {
+ quote! {
+ crate :: #ident
+ }
+ } else {
+ quote! {
+ #path :: #ident
+ }
+ }
+ };
+ let contents: Vec = self.contents.iter().map(DocNamedType::to_rust).collect();
+ let convertible = self.derive_convertible(&c_ident);
+ let into_impl = self.derive_into_impl(&c_ident);
+
+ quote! {
+ #doc_comments
+ #[allow(non_camel_case_types)]
+ #[derive(Debug)]
+ pub struct #ident {
+ #(#contents),*
+ }
+ #convertible
+ #into_impl
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/type/doc_named_type.rs b/src/macros/generate/convert/host/rust/type/doc_named_type.rs
new file mode 100644
index 0000000..0531cab
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/type/doc_named_type.rs
@@ -0,0 +1,19 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{DocNamedType, NamedType};
+
+impl DocNamedType {
+ pub fn to_rust(&self) -> TokenStream2 {
+ let attributes: TokenStream2 = self
+ .attributes
+ .iter()
+ .map(|attr| attr.to_rust(&self.name))
+ .collect();
+ let named_type = Into::::into(self).to_rust();
+ quote! {
+ #attributes
+ pub #named_type
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/type/mod.rs b/src/macros/generate/convert/host/rust/type/mod.rs
new file mode 100644
index 0000000..f6141ef
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/type/mod.rs
@@ -0,0 +1,67 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::{Identifier, NamedType, Type, Variant};
+
+mod doc_named_type;
+mod named_type;
+
+// pub use doc_named_type::*;
+// pub use named_type::*;
+
+impl Type {
+ pub fn to_rust(&self) -> TokenStream2 {
+ match self {
+ Type::Typical {
+ identifier,
+ generic_args,
+ } => Self::to_rust_typical(&identifier, &generic_args),
+ Type::Function { inputs, output } => Self::to_rust_function(&inputs, &output),
+ }
+ }
+ pub fn to_rust_function(inputs: &[NamedType], output: &Option>) -> TokenStream2 {
+ let inputs: Vec = inputs.iter().map(NamedType::to_rust).collect();
+ let output = if let Some(output) = output {
+ let output = output.to_rust();
+ quote! {
+ -> #output
+ }
+ } else {
+ TokenStream2::default()
+ };
+
+ quote! {
+ fn(#(#inputs),*) #output
+ }
+ }
+ pub fn to_rust_typical(identifier: &Identifier, generic_args: &Vec) -> TokenStream2 {
+ let ident = identifier.to_rust();
+ let namespaces_path = Variant::to_rust_path(&identifier.variant);
+
+ let nasp_path = if let Some(nasp_path) = Variant::to_rust_path(&identifier.variant) {
+ if nasp_path.is_empty() {
+ quote! {
+ crate ::
+ }
+ } else {
+ let path = namespaces_path;
+ quote! {
+ #path ::
+ }
+ }
+ } else {
+ quote! {}
+ };
+
+ if generic_args.is_empty() {
+ quote! {
+ #nasp_path #ident
+ }
+ } else {
+ let generics: Vec = generic_args.iter().map(Type::to_rust).collect();
+ quote! {
+ #nasp_path #ident <#(#generics),*>
+ }
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/type/named_type.rs b/src/macros/generate/convert/host/rust/type/named_type.rs
new file mode 100644
index 0000000..dd17d8a
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/type/named_type.rs
@@ -0,0 +1,14 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::parser::command_spec::NamedType;
+
+impl NamedType {
+ pub fn to_rust(&self) -> TokenStream2 {
+ let ident = self.name.to_rust();
+ let r#type = self.r#type.to_rust();
+ quote! {
+ #ident : #r#type
+ }
+ }
+}
diff --git a/src/macros/generate/convert/host/rust/variant/mod.rs b/src/macros/generate/convert/host/rust/variant/mod.rs
new file mode 100644
index 0000000..dc6b8b7
--- /dev/null
+++ b/src/macros/generate/convert/host/rust/variant/mod.rs
@@ -0,0 +1,25 @@
+use proc_macro2::TokenStream as TokenStream2;
+
+use crate::parser::command_spec::{Identifier, Namespace, Variant};
+
+impl Variant {
+ // was named `type_variant_rust_path`
+ pub fn to_rust_path(&self) -> Option {
+ fn namespace_to_borrowed(vec: &Vec) -> Vec<&Identifier> {
+ let vec_2: Vec<&Identifier> = vec.iter().collect();
+ vec_2
+ }
+
+ let main_namespace;
+ match self {
+ Variant::Structure { namespace } => {
+ main_namespace = namespace_to_borrowed(namespace);
+ }
+ Variant::Enumeration { namespace } => {
+ main_namespace = namespace_to_borrowed(namespace);
+ }
+ _ => return None,
+ }
+ Some(Namespace::to_rust_path(&main_namespace[..]))
+ }
+}
diff --git a/src/macros/generate/convert/mod.rs b/src/macros/generate/convert/mod.rs
new file mode 100644
index 0000000..50c2842
--- /dev/null
+++ b/src/macros/generate/convert/mod.rs
@@ -0,0 +1,2 @@
+pub mod host;
+pub mod auxiliary;
diff --git a/src/macros/generate/host/c/host/mod.rs b/src/macros/generate/host/c/host/mod.rs
new file mode 100644
index 0000000..a22a74b
--- /dev/null
+++ b/src/macros/generate/host/c/host/mod.rs
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2023 - 2024:
+* The Trinitrix Project
+*
+* This file is part of the Trixy crate for Trinitrix.
+*
+* Trixy is free software: you can redistribute it and/or modify
+* it under the terms of the Lesser GNU General Public License as
+* published by the Free Software Foundation, either version 3 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* and the Lesser GNU General Public License along with this program.
+* If not, see .
+*/
+
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::{
+ macros::config::trixy::TrixyConfig,
+ parser::command_spec::{CommandSpec, Enumeration, Structure},
+};
+
+/// This function generates the main c API provided by Trixy.
+/// This works for example like this:
+/// Turning this:
+/// ```text
+/// nasp trinitrix {
+/// struct Callback {
+/// func: String,
+/// timeout: String,
+/// };
+///
+/// enum CallbackPriority {
+/// High,
+/// Medium,
+/// Low,
+/// };
+///
+/// fn execute_callback(callback: Callback, priority: CallbackPriority);
+/// }
+/// ```
+/// to this:
+/// ```no_run
+/// pub extern "C" fn exectute_callback(callback: Callback, priority: CallbackPriority) {
+/// /* Here we simply call your handler function, with the command of the function */
+/// }
+/// ```
+pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
+ let functions: TokenStream2 = trixy
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_c(&config, &vec![]))
+ .collect();
+ let namespaced_functions: TokenStream2 = trixy
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_c(&config, &vec![]))
+ .collect();
+ let structures: TokenStream2 = trixy.structures.iter().map(Structure::to_c).collect();
+ let enumerations: TokenStream2 = trixy.enumerations.iter().map(Enumeration::to_c).collect();
+ quote! {
+ #enumerations
+ #structures
+ #functions
+ #namespaced_functions
+ }
+}
diff --git a/trixy-parser/example/other_comments.tri b/src/macros/generate/host/c/mod.rs
similarity index 68%
rename from trixy-parser/example/other_comments.tri
rename to src/macros/generate/host/c/mod.rs
index 8454713..caf7f6c 100644
--- a/trixy-parser/example/other_comments.tri
+++ b/src/macros/generate/host/c/mod.rs
@@ -19,20 +19,23 @@
* If not, see .
*/
-/// other doc comment
-fn hi(name: String) -> String;
+use crate::{
+ macros::{config::trixy::TrixyConfig, generate::host::format_rust},
+ parser::command_spec::CommandSpec,
+};
-/// struct comment
-struct ho {
- ident: String,
- /// also a doc comment
- codebase: Vec,
+pub mod host;
+
+pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> String {
+ let host_rust_code = host::generate(&trixy, &config);
+
+ let rust_code = format_rust(host_rust_code);
+
+ format!(
+ "
+/* c API */
+{}
+",
+ rust_code
+ )
}
-
-/// Some doc comment
-mod trinitrix {
- fn hi(name: String) -> String;
-}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/src/macros/generate/host/mod.rs b/src/macros/generate/host/mod.rs
new file mode 100644
index 0000000..f19f6ca
--- /dev/null
+++ b/src/macros/generate/host/mod.rs
@@ -0,0 +1,34 @@
+//! Host files that are included in the final binary
+
+use proc_macro2::TokenStream as TokenStream2;
+
+use crate::{
+ macros::{config::trixy::TrixyConfig, VIM_LINE_RUST},
+ parser::command_spec::CommandSpec,
+};
+
+pub mod c;
+pub mod rust;
+
+pub fn format_rust(input: TokenStream2) -> String {
+ prettyplease::unparse(
+ &syn::parse2(input).expect("This code was generated, it should also be parsable"),
+ )
+}
+
+pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> String {
+ let rust_host = rust::generate(trixy, config);
+ let c_host = c::generate(trixy, config);
+
+ format!(
+ "
+// Host code {{{{{{
+{}
+/* C API */
+{}
+// }}}}}}
+{}
+ ",
+ rust_host, c_host, VIM_LINE_RUST
+ )
+}
diff --git a/src/macros/generate/host/rust/host/mod.rs b/src/macros/generate/host/rust/host/mod.rs
new file mode 100644
index 0000000..62f5720
--- /dev/null
+++ b/src/macros/generate/host/rust/host/mod.rs
@@ -0,0 +1,114 @@
+/*
+* Copyright (C) 2023 - 2024:
+* The Trinitrix Project
+*
+* This file is part of the Trixy crate for Trinitrix.
+*
+* Trixy is free software: you can redistribute it and/or modify
+* it under the terms of the Lesser GNU General Public License as
+* published by the Free Software Foundation, either version 3 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* and the Lesser GNU General Public License along with this program.
+* If not, see .
+*/
+
+//! This module is responsible for generating the rust code used to interface with the api.
+//! That includes the structs and enums declared in the trixy file and the enum used to describe the
+//! command being executed.
+
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::{
+ macros::config::trixy::TrixyConfig,
+ parser::command_spec::{CommandSpec, Enumeration, Namespace, Structure},
+};
+
+/// This function turns, for example, the following trixy input into this rust code:
+/// ```text
+/// nasp trinitrix {
+/// struct Callback {
+/// func: String,
+/// timeout: String,
+/// };
+///
+/// enum CallbackPriority {
+/// High,
+/// Medium,
+/// Low,
+/// };
+///
+/// fn execute_callback(callback: Callback, priority: CallbackPriority) -> String;
+/// }
+/// ```
+/// ```no_run
+/// #[derive(Debug)]
+/// pub enum Commands {
+/// Trinitrix(trinitrix::Trinitrix),
+/// }
+/// pub mod trinitrix {
+/// #[allow(non_camel_case_types)]
+/// #[derive(Debug)]
+/// struct Callback {
+/// func: String,
+/// timeout: String,
+/// }
+/// #[allow(non_camel_case_types)]
+/// #[derive(Debug)]
+/// enum CallbackPriority {
+/// High,
+/// Medium,
+/// Low,
+/// }
+/// #[derive(Debug)]
+/// pub enum Trinitrix {
+/// #[allow(non_camel_case_types)]
+/// execute_callback {
+/// callback: Callback,
+/// priority: CallbackPriority,
+/// trixy_output: trixy::oneshot::channel
+/// },
+/// }
+/// }
+/// ```
+pub fn generate(trixy: &CommandSpec, _config: &TrixyConfig) -> TokenStream2 {
+ let modules: TokenStream2 = trixy
+ .namespaces
+ .iter()
+ .map(|nasp| nasp.to_rust_module(&vec![]))
+ .collect();
+ let structures: TokenStream2 = trixy.structures.iter().map(Structure::to_rust).collect();
+ let enumerations: TokenStream2 = trixy
+ .enumerations
+ .iter()
+ .map(Enumeration::to_rust)
+ .collect();
+ let functions: Vec = trixy
+ .functions
+ .iter()
+ .map(|r#fn| r#fn.to_rust(&[]))
+ .collect();
+ let namespace_modules: Vec = trixy
+ .namespaces
+ .iter()
+ .map(Namespace::to_rust_module_enum)
+ .collect();
+
+ quote! {
+ #structures
+ #enumerations
+ #[derive(Debug)]
+ pub enum Commands {
+ #(#functions,)*
+ #(#namespace_modules),*
+ }
+ #modules
+ }
+}
diff --git a/trixy-parser/example/types.tri b/src/macros/generate/host/rust/mod.rs
similarity index 68%
rename from trixy-parser/example/types.tri
rename to src/macros/generate/host/rust/mod.rs
index 1a135c5..5fc0b12 100644
--- a/trixy-parser/example/types.tri
+++ b/src/macros/generate/host/rust/mod.rs
@@ -19,20 +19,22 @@
* If not, see .
*/
-mod trinitrix {
- struct Callback {
- func: Function,
- timeout: Integer,
- }
+use crate::parser::command_spec::CommandSpec;
- enum CallbackPriority {
- High,
- Medium,
- Low,
- }
+use crate::macros::{config::trixy::TrixyConfig, generate::host::format_rust};
- fn execute_callback(callback: Callback, priority: CallbackPriority);
+pub mod host;
+
+pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> String {
+ let host_rust_code = host::generate(&trixy, &config);
+
+ let rust_code = format_rust(host_rust_code);
+
+ format!(
+ "
+/* Rust API */
+{}
+",
+ rust_code
+ )
}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/src/macros/generate/mod.rs b/src/macros/generate/mod.rs
new file mode 100644
index 0000000..779d053
--- /dev/null
+++ b/src/macros/generate/mod.rs
@@ -0,0 +1,3 @@
+pub mod host;
+pub mod auxiliary;
+pub mod convert;
diff --git a/src/macros/mod.rs b/src/macros/mod.rs
new file mode 100644
index 0000000..9d31784
--- /dev/null
+++ b/src/macros/mod.rs
@@ -0,0 +1,123 @@
+/*
+* Copyright (C) 2023 - 2024:
+* The Trinitrix Project
+*
+* This file is part of the Trixy crate for Trinitrix.
+*
+* Trixy is free software: you can redistribute it and/or modify
+* it under the terms of the Lesser GNU General Public License as
+* published by the Free Software Foundation, either version 3 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* and the Lesser GNU General Public License along with this program.
+* If not, see .
+*/
+
+use std::{
+ fs, iter,
+ path::{Path, PathBuf},
+};
+
+use crate::parser::parse_trixy_lang;
+use crate::types::C_TYPE_HEADER;
+use config::{
+ file_tree::{FileTree, GeneratedFile},
+ trixy::Language,
+};
+
+use self::config::trixy::TrixyConfig;
+
+pub mod config;
+mod generate;
+
+const VIM_LINE_RUST: &'static str = "// vim: filetype=rust\n";
+const VIM_LINE_C: &'static str = "// vim: filetype=c\n";
+
+impl TrixyConfig {
+ /// This is the heart of the trixy crate.
+ /// It's main purpose is to generate, what you have asked for in the [`TrixyConfig`] and to
+ /// return this generated code as a [`FileTree`].
+ ///
+ /// # Panic
+ ///
+ /// Beware that this function will panic on errors, as it is written with the expectation that
+ /// it's run from a `build.rs` file. If you want to avoid that, usage of the raw generation
+ /// functions is guaranteed to never panic.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use crate::macros::TrixyConfig;
+ ///
+ /// let trixy_config = TrixyConfig::new("some_callback_function")
+ /// .trixy_path("./path/to/api/file.tri")
+ /// /* other config settings */;
+ /// trixy_config.generate();
+ /// ```
+ pub fn generate(&self) -> FileTree {
+ let mut file_tree = FileTree::new();
+
+ let source_code = fs::read_to_string(&self.trixy_path).unwrap_or_else(|err| {
+ panic! {"Can't read file at path: '{}'. The Error was: '{}'", self.trixy_path.display(), err};
+ });
+
+ let trixy_code = parse_trixy_lang(&source_code).unwrap_or_else(|err| {
+ panic! {"Parsing of the trixy file failed: \n{}", err}
+ });
+
+ // host code
+ let host_code = generate::host::generate(&trixy_code, &self);
+ file_tree.add_host_file(GeneratedFile::new_in_out_dir(
+ self.host_code_name.clone(),
+ host_code,
+ Language::Rust,
+ &self.out_dir,
+ ));
+
+ // auxiliary code
+ let c_header = generate::auxiliary::generate(&trixy_code, &self);
+
+ if let Some(dist_dir) = &self.dist_dir_path {
+ let c_header_dist =
+ PathBuf::from(format!("{}/{}", dist_dir.display(), &self.c_header_name));
+ file_tree.add_auxiliary_file(GeneratedFile::new(c_header_dist, c_header, Language::C));
+
+ // TODO(@soispha): Is this even necessary? <2024-03-25>
+ let (interface_name, interface_content) = {
+ let interface_header = format!(
+ "\
+ /* This file is automatcially generated by Trixy */ \n\
+ #ifndef TRIXY_INTERFACE_H \n\
+ #define TRIXY_INTERFACE_H \n\
+ #include \"{}\" \n\
+ #endif // TRIXY_INTERFACE_H \n\
+ ",
+ &self.c_header_name
+ );
+ ("interface.h", interface_header)
+ };
+
+ C_TYPE_HEADER
+ .iter()
+ .chain(iter::once(&(interface_name, &interface_content[..])))
+ .for_each(|(name, content)| {
+ let path: &Path = &Path::new(name);
+
+ let header_path =
+ PathBuf::from(format!("{}/{}", dist_dir.display(), path.display()));
+ file_tree.add_auxiliary_file(GeneratedFile::new(
+ header_path,
+ content.to_string(),
+ Language::C,
+ ));
+ });
+ }
+ file_tree
+ }
+}
diff --git a/trixy-parser/src/command_spec/checked.rs b/src/parser/command_spec/checked.rs
similarity index 99%
rename from trixy-parser/src/command_spec/checked.rs
rename to src/parser/command_spec/checked.rs
index 36ff31f..c001662 100644
--- a/trixy-parser/src/command_spec/checked.rs
+++ b/src/parser/command_spec/checked.rs
@@ -23,7 +23,7 @@
use std::fmt::{Display, Write};
-use crate::lexing::TokenKind;
+use crate::parser::lexing::TokenKind;
use super::unchecked::{self, DeriveValue};
diff --git a/trixy-parser/src/command_spec/mod.rs b/src/parser/command_spec/mod.rs
similarity index 100%
rename from trixy-parser/src/command_spec/mod.rs
rename to src/parser/command_spec/mod.rs
diff --git a/trixy-parser/src/command_spec/unchecked.rs b/src/parser/command_spec/unchecked.rs
similarity index 96%
rename from trixy-parser/src/command_spec/unchecked.rs
rename to src/parser/command_spec/unchecked.rs
index 4d45b4d..d3d113f 100644
--- a/trixy-parser/src/command_spec/unchecked.rs
+++ b/src/parser/command_spec/unchecked.rs
@@ -25,9 +25,9 @@
use std::fmt::{Display, Write};
-use crate::lexing::{Token, TokenKind, TokenSpan};
+use crate::parser::lexing::{Token, TokenKind, TokenSpan};
-#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CommandSpec {
pub structures: Vec,
pub enumerations: Vec,
@@ -189,7 +189,7 @@ pub enum Type {
impl Display for NamedType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ident = match self.name.kind() {
- crate::lexing::TokenKind::Identifier(ident) => ident,
+ crate::parser::lexing::TokenKind::Identifier(ident) => ident,
_ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
};
f.write_str(ident)?;
@@ -206,7 +206,7 @@ impl Display for Type {
generic_args,
} => {
let ident = match identifier.kind() {
- crate::lexing::TokenKind::Identifier(ident) => ident,
+ crate::parser::lexing::TokenKind::Identifier(ident) => ident,
_ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
};
diff --git a/trixy-parser/src/error.rs b/src/parser/error.rs
similarity index 99%
rename from trixy-parser/src/error.rs
rename to src/parser/error.rs
index e75cb0b..fdc619d 100644
--- a/trixy-parser/src/error.rs
+++ b/src/parser/error.rs
@@ -23,9 +23,9 @@ use core::fmt;
use thiserror::Error;
-use crate::{
+use crate::parser::{
lexing::{error::SpannedLexingError, TokenSpan},
- parsing::{self},
+ parsing,
};
#[derive(Error, Debug)]
diff --git a/trixy-parser/src/lexing/error.rs b/src/parser/lexing/error.rs
similarity index 95%
rename from trixy-parser/src/lexing/error.rs
rename to src/parser/lexing/error.rs
index c9bcf54..b7f5ee6 100644
--- a/trixy-parser/src/lexing/error.rs
+++ b/src/parser/lexing/error.rs
@@ -22,7 +22,7 @@
use std::{error::Error, fmt::Display};
use thiserror::Error;
-use crate::error::{AdditionalHelp, ErrorContext, ErrorContextDisplay};
+use crate::parser::error::{AdditionalHelp, ErrorContext, ErrorContextDisplay};
#[derive(Error, Debug)]
pub enum LexingError {
@@ -67,7 +67,7 @@ impl Error for SpannedLexingError {
impl ErrorContextDisplay for SpannedLexingError {
type Error = LexingError;
- fn context(&self) -> &crate::error::ErrorContext {
+ fn context(&self) -> &crate::parser::error::ErrorContext {
&self.context
}
diff --git a/trixy-parser/src/lexing/mod.rs b/src/parser/lexing/mod.rs
similarity index 77%
rename from trixy-parser/src/lexing/mod.rs
rename to src/parser/lexing/mod.rs
index 1c84dd9..89bae0e 100644
--- a/trixy-parser/src/lexing/mod.rs
+++ b/src/parser/lexing/mod.rs
@@ -31,7 +31,7 @@ mod tokenizer;
#[cfg(test)]
mod test;
-#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
+#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone)]
pub struct TokenStream {
pub original_file: String,
tokens: Vec,
@@ -308,7 +308,7 @@ impl Display for AttributeKeyword {
/// # Examples
///
/// ```
-/// use trixy_parser::token;
+/// use crate::parser::token;
///# fn main() {
/// token![mod];
/// token![;];
@@ -317,56 +317,56 @@ impl Display for AttributeKeyword {
/// ```
#[macro_export]
macro_rules! token {
- [Semicolon] => { $crate::lexing::TokenKind::Semicolon };
- [;] => { $crate::lexing::TokenKind::Semicolon };
- [Colon] => { $crate::lexing::TokenKind::Colon };
- [:] => { $crate::lexing::TokenKind::Colon };
- [Comma] => { $crate::lexing::TokenKind::Comma };
- [,] => { $crate::lexing::TokenKind::Comma };
- [Arrow] => { $crate::lexing::TokenKind::Arrow };
- [->] => { $crate::lexing::TokenKind::Arrow };
- [PoundSign] => { $crate::lexing::TokenKind::PoundSign };
- [#] => { $crate::lexing::TokenKind::PoundSign };
- [EqualsSign] => { $crate::lexing::TokenKind::EqualsSign };
- [=] => { $crate::lexing::TokenKind::EqualsSign };
+ [Semicolon] => { $crate::parser::lexing::TokenKind::Semicolon };
+ [;] => { $crate::parser::lexing::TokenKind::Semicolon };
+ [Colon] => { $crate::parser::lexing::TokenKind::Colon };
+ [:] => { $crate::parser::lexing::TokenKind::Colon };
+ [Comma] => { $crate::parser::lexing::TokenKind::Comma };
+ [,] => { $crate::parser::lexing::TokenKind::Comma };
+ [Arrow] => { $crate::parser::lexing::TokenKind::Arrow };
+ [->] => { $crate::parser::lexing::TokenKind::Arrow };
+ [PoundSign] => { $crate::parser::lexing::TokenKind::PoundSign };
+ [#] => { $crate::parser::lexing::TokenKind::PoundSign };
+ [EqualsSign] => { $crate::parser::lexing::TokenKind::EqualsSign };
+ [=] => { $crate::parser::lexing::TokenKind::EqualsSign };
- [AngledBracketOpen] => { $crate::lexing::TokenKind::AngledBracketOpen };
- [<] => { $crate::lexing::TokenKind::AngledBracketOpen };
+ [AngledBracketOpen] => { $crate::parser::lexing::TokenKind::AngledBracketOpen };
+ [<] => { $crate::parser::lexing::TokenKind::AngledBracketOpen };
- [AngledBracketClose] => { $crate::lexing::TokenKind::AngledBracketClose };
- [>] => { $crate::lexing::TokenKind::AngledBracketClose };
+ [AngledBracketClose] => { $crate::parser::lexing::TokenKind::AngledBracketClose };
+ [>] => { $crate::parser::lexing::TokenKind::AngledBracketClose };
- [CurlyBracketOpen] => { $crate::lexing::TokenKind::CurlyBracketOpen};
- // [{] => { $crate::lexing::TokenKind::CurlyBracketOpen };
- [CurlyBracketClose] => { $crate::lexing::TokenKind::CurlyBracketClose};
- // [}] => { $crate::lexing::TokenKind::CurlyBracketClose };
- [CurvedBracketOpen] => { $crate::lexing::TokenKind::CurvedBracketOpen};
- // [(] => { $crate::lexing::TokenKind::ParenthesisOpen };
- [CurvedBracketClose] => { $crate::lexing::TokenKind::CurvedBracketClose};
- // [)] => { $crate::lexing::TokenKind::ParenthesisClose };
- [SquareBracketOpen] => { $crate::lexing::TokenKind::SquareBracketOpen};
- // [[] => { $crate::lexing::TokenKind::ParenthesisOpen };
- [SquareBracketClose] => { $crate::lexing::TokenKind::SquareBracketClose};
- // []] => { $crate::lexing::TokenKind::ParenthesisClose };
+ [CurlyBracketOpen] => { $crate::parser::lexing::TokenKind::CurlyBracketOpen};
+ // [{] => { $crate::parser::lexing::TokenKind::CurlyBracketOpen };
+ [CurlyBracketClose] => { $crate::parser::lexing::TokenKind::CurlyBracketClose};
+ // [}] => { $crate::parser::lexing::TokenKind::CurlyBracketClose };
+ [CurvedBracketOpen] => { $crate::parser::lexing::TokenKind::CurvedBracketOpen};
+ // [(] => { $crate::parser::lexing::TokenKind::ParenthesisOpen };
+ [CurvedBracketClose] => { $crate::parser::lexing::TokenKind::CurvedBracketClose};
+ // [)] => { $crate::parser::lexing::TokenKind::ParenthesisClose };
+ [SquareBracketOpen] => { $crate::parser::lexing::TokenKind::SquareBracketOpen};
+ // [[] => { $crate::parser::lexing::TokenKind::ParenthesisOpen };
+ [SquareBracketClose] => { $crate::parser::lexing::TokenKind::SquareBracketClose};
+ // []] => { $crate::parser::lexing::TokenKind::ParenthesisClose };
- [mod] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#mod) };
- [fn] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#fn) };
- [struct] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#struct) };
- [enum] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#enum) };
+ [mod] => { $crate::parser::lexing::TokenKind::Keyword($crate::parser::lexing::Keyword::r#mod) };
+ [fn] => { $crate::parser::lexing::TokenKind::Keyword($crate::parser::lexing::Keyword::r#fn) };
+ [struct] => { $crate::parser::lexing::TokenKind::Keyword($crate::parser::lexing::Keyword::r#struct) };
+ [enum] => { $crate::parser::lexing::TokenKind::Keyword($crate::parser::lexing::Keyword::r#enum) };
// The `derive` here is completely arbitrary. It is only for comparisons (see `same_kind`)
- [AttributeKeyword] => { $crate::lexing::TokenKind::AttributeKeyword($crate::lexing::AttributeKeyword::derive) };
+ [AttributeKeyword] => { $crate::parser::lexing::TokenKind::AttributeKeyword($crate::parser::lexing::AttributeKeyword::derive) };
// This is only works for checking for a identifier or comment
// see the `same_kind` method on TokenKind
- [Ident] => { $crate::lexing::TokenKind::Identifier("".to_owned()) };
- [Identifier] => { $crate::lexing::TokenKind::Identifier("".to_owned()) };
+ [Ident] => { $crate::parser::lexing::TokenKind::Identifier("".to_owned()) };
+ [Identifier] => { $crate::parser::lexing::TokenKind::Identifier("".to_owned()) };
- [StringLiteral] => { $crate::lexing::TokenKind::StringLiteral("".to_owned()) };
+ [StringLiteral] => { $crate::parser::lexing::TokenKind::StringLiteral("".to_owned()) };
- [Comment] => { $crate::lexing::TokenKind::Comment("".to_owned()) };
+ [Comment] => { $crate::parser::lexing::TokenKind::Comment("".to_owned()) };
}
#[cfg(test)]
@@ -397,6 +397,6 @@ mod tests {
token_macro_test!(tok_expands_to_arrow, ->, => TokenKind::Arrow);
token_macro_test!(tok_expands_to_semicolon, Semicolon, => TokenKind::Semicolon);
- token_macro_test!(tok_expands_to_mod, mod, => TokenKind::Keyword(crate::lexing::Keyword::r#mod));
- token_macro_test!(tok_expands_to_fn, fn, => TokenKind::Keyword(crate::lexing::Keyword::r#fn));
+ token_macro_test!(tok_expands_to_mod, mod, => TokenKind::Keyword(crate::parser::lexing::Keyword::r#mod));
+ token_macro_test!(tok_expands_to_fn, fn, => TokenKind::Keyword(crate::parser::lexing::Keyword::r#fn));
}
diff --git a/trixy-parser/src/lexing/test.rs b/src/parser/lexing/test.rs
similarity index 100%
rename from trixy-parser/src/lexing/test.rs
rename to src/parser/lexing/test.rs
diff --git a/trixy-parser/src/lexing/tokenizer.rs b/src/parser/lexing/tokenizer.rs
similarity index 99%
rename from trixy-parser/src/lexing/tokenizer.rs
rename to src/parser/lexing/tokenizer.rs
index 3904911..bca7dee 100644
--- a/trixy-parser/src/lexing/tokenizer.rs
+++ b/src/parser/lexing/tokenizer.rs
@@ -21,7 +21,7 @@
// This code is heavily inspired by: https://michael-f-bryan.github.io/static-analyser-in-rust/book/lex.html
-use crate::{
+use crate::parser::{
error::ErrorContext,
lexing::{Keyword, TokenSpan},
};
diff --git a/trixy-parser/src/lib.rs b/src/parser/mod.rs
similarity index 97%
rename from trixy-parser/src/lib.rs
rename to src/parser/mod.rs
index 493b40b..3b92749 100644
--- a/trixy-parser/src/lib.rs
+++ b/src/parser/mod.rs
@@ -21,7 +21,7 @@
use error::TrixyError;
-use crate::lexing::TokenStream;
+use crate::parser::lexing::TokenStream;
use self::command_spec::checked::CommandSpec;
diff --git a/trixy-parser/src/parsing/checked/error.rs b/src/parser/parsing/checked/error.rs
similarity index 98%
rename from trixy-parser/src/parsing/checked/error.rs
rename to src/parser/parsing/checked/error.rs
index bb6bafc..4d6dd67 100644
--- a/trixy-parser/src/parsing/checked/error.rs
+++ b/src/parser/parsing/checked/error.rs
@@ -23,7 +23,7 @@ use thiserror::Error;
use std::{error::Error, fmt::Display};
-use crate::{
+use crate::parser::{
command_spec::{checked::Identifier, unchecked::Attribute},
error::{AdditionalHelp, ErrorContext, ErrorContextDisplay},
lexing::TokenSpan,
@@ -133,7 +133,7 @@ impl Display for SpannedParsingError {
impl ErrorContextDisplay for SpannedParsingError {
type Error = ParsingError;
- fn context(&self) -> &crate::error::ErrorContext {
+ fn context(&self) -> &crate::parser::error::ErrorContext {
&self.context
}
diff --git a/trixy-parser/src/parsing/checked/mod.rs b/src/parser/parsing/checked/mod.rs
similarity index 98%
rename from trixy-parser/src/parsing/checked/mod.rs
rename to src/parser/parsing/checked/mod.rs
index 5a76b2c..8557d03 100644
--- a/trixy-parser/src/parsing/checked/mod.rs
+++ b/src/parser/parsing/checked/mod.rs
@@ -21,10 +21,10 @@
use std::{iter, mem};
+use crate::types::BASE_TYPES;
use convert_case::{Case, Casing};
-use trixy_types::BASE_TYPES;
-use crate::{
+use crate::parser::{
command_spec::{
checked::{
self, CommandSpec, DocIdentifier, DocNamedType, Enumeration, Function, Identifier,
@@ -68,13 +68,13 @@ macro_rules! take_attrs {
}
};
(@process_val $iden:ident, $val:ident) => {
- if let $crate::command_spec::unchecked::Attribute::$val{..} = $iden {
+ if let $crate::parser::command_spec::unchecked::Attribute::$val{..} = $iden {
return Ok($iden.into());
};
take_attrs!{@process_val_last $iden}
};
(@process_val $iden:ident, $val:ident, $($other:tt),+ $(,)*) => {
- if let $crate::command_spec::unchecked::Attribute::$val{..} = $iden {
+ if let $crate::parser::command_spec::unchecked::Attribute::$val{..} = $iden {
return Ok($iden.into());
};
take_attrs!{@process_val $iden, $($other),*}
diff --git a/trixy-parser/src/parsing/checked/test.rs b/src/parser/parsing/checked/test.rs
similarity index 100%
rename from trixy-parser/src/parsing/checked/test.rs
rename to src/parser/parsing/checked/test.rs
diff --git a/trixy-parser/src/parsing/mod.rs b/src/parser/parsing/mod.rs
similarity index 100%
rename from trixy-parser/src/parsing/mod.rs
rename to src/parser/parsing/mod.rs
diff --git a/trixy-parser/src/parsing/unchecked/error.rs b/src/parser/parsing/unchecked/error.rs
similarity index 98%
rename from trixy-parser/src/parsing/unchecked/error.rs
rename to src/parser/parsing/unchecked/error.rs
index 80b2342..34c6fe0 100644
--- a/trixy-parser/src/parsing/unchecked/error.rs
+++ b/src/parser/parsing/unchecked/error.rs
@@ -22,7 +22,7 @@
use std::{error::Error, fmt::Display};
use thiserror::Error;
-use crate::{
+use crate::parser::{
command_spec::unchecked::{Attribute, StringLiteral},
error::{AdditionalHelp, ErrorContext, ErrorContextDisplay},
lexing::{TokenKind, TokenSpan},
@@ -113,7 +113,7 @@ impl Display for SpannedParsingError {
impl ErrorContextDisplay for SpannedParsingError {
type Error = ParsingError;
- fn context(&self) -> &crate::error::ErrorContext {
+ fn context(&self) -> &crate::parser::error::ErrorContext {
&self.context
}
diff --git a/trixy-parser/src/parsing/unchecked/mod.rs b/src/parser/parsing/unchecked/mod.rs
similarity index 97%
rename from trixy-parser/src/parsing/unchecked/mod.rs
rename to src/parser/parsing/unchecked/mod.rs
index c362b1e..8201349 100644
--- a/trixy-parser/src/parsing/unchecked/mod.rs
+++ b/src/parser/parsing/unchecked/mod.rs
@@ -22,12 +22,14 @@
use std::{iter::once, mem};
use crate::{
- command_spec::unchecked::{
- Attribute, CommandSpec, Declaration, DeriveValue, DocNamedType, DocToken, Enumeration,
- Function, NamedType, Namespace, StringLiteral, Structure, Type,
+ parser::{
+ command_spec::unchecked::{
+ Attribute, CommandSpec, Declaration, DeriveValue, DocNamedType, DocToken, Enumeration,
+ Function, NamedType, Namespace, StringLiteral, Structure, Type,
+ },
+ error::ErrorContext,
+ lexing::{AttributeKeyword, Token, TokenKind, TokenSpan, TokenStream},
},
- error::ErrorContext,
- lexing::{AttributeKeyword, Token, TokenKind, TokenSpan, TokenStream},
token,
};
diff --git a/trixy-parser/src/parsing/unchecked/test.rs b/src/parser/parsing/unchecked/test.rs
similarity index 100%
rename from trixy-parser/src/parsing/unchecked/test.rs
rename to src/parser/parsing/unchecked/test.rs
diff --git a/trixy-types/src/c_headers/errno.h b/src/types/c_headers/errno.h
similarity index 100%
rename from trixy-types/src/c_headers/errno.h
rename to src/types/c_headers/errno.h
diff --git a/trixy-types/src/c_headers/string.h b/src/types/c_headers/string.h
similarity index 100%
rename from trixy-types/src/c_headers/string.h
rename to src/types/c_headers/string.h
diff --git a/trixy-types/src/c_headers/vec.h b/src/types/c_headers/vec.h
similarity index 100%
rename from trixy-types/src/c_headers/vec.h
rename to src/types/c_headers/vec.h
diff --git a/trixy-types/src/error/mod.rs b/src/types/error/mod.rs
similarity index 100%
rename from trixy-types/src/error/mod.rs
rename to src/types/error/mod.rs
diff --git a/trixy-types/src/lib.rs b/src/types/mod.rs
similarity index 100%
rename from trixy-types/src/lib.rs
rename to src/types/mod.rs
diff --git a/trixy-types/src/traits/convert_trait.rs b/src/types/traits/convert_trait.rs
similarity index 97%
rename from trixy-types/src/traits/convert_trait.rs
rename to src/types/traits/convert_trait.rs
index 1521911..aca5fc5 100644
--- a/trixy-types/src/traits/convert_trait.rs
+++ b/src/types/traits/convert_trait.rs
@@ -19,7 +19,7 @@
* If not, see .
*/
-use crate::error::{self, TypeConversionError};
+use crate::types::error::{self, TypeConversionError};
use log::warn;
use std::{
error::Error,
@@ -180,7 +180,7 @@ impl Convertible for Result {
}
impl Convertible for Vec {
- type Ptr = crate::Vec<::Ptr>;
+ type Ptr = crate::types::Vec<::Ptr>;
fn into_ptr(self) -> Self::Ptr {
let data_vec: Vec<_> = self.into_iter().map(|val| val.into_ptr()).collect();
@@ -222,7 +222,7 @@ impl Convertible for Vec {
macro_rules! make_vec_free {
($value:ident, $name:ident) => {
#[no_mangle]
- pub extern "C" fn $name(ptr: crate::Vec<<$value as Convertible>::Ptr>) {
+ pub extern "C" fn $name(ptr: crate::types::Vec<<$value as Convertible>::Ptr>) {
Vec::<$value>::drop_ptr(ptr);
}
};
diff --git a/trixy-types/src/traits/errno.rs b/src/types/traits/errno.rs
similarity index 98%
rename from trixy-types/src/traits/errno.rs
rename to src/types/traits/errno.rs
index 985d70a..49a3fee 100644
--- a/trixy-types/src/traits/errno.rs
+++ b/src/types/traits/errno.rs
@@ -29,7 +29,7 @@ use std::{
use log::{error, warn};
-use crate::error::TypeConversionError;
+use crate::types::error::TypeConversionError;
// This code is heavily inspired by: https://michael-f-bryan.github.io/rust-ffi-guide/errors/return_types.html
thread_local! {
diff --git a/trixy-types/src/traits/mod.rs b/src/types/traits/mod.rs
similarity index 96%
rename from trixy-types/src/traits/mod.rs
rename to src/types/traits/mod.rs
index b06ca91..964d07b 100644
--- a/trixy-types/src/traits/mod.rs
+++ b/src/types/traits/mod.rs
@@ -22,4 +22,4 @@
pub mod convert_trait;
pub mod errno;
mod try_from_impl;
-pub use try_from_impl::*;
+// pub use try_from_impl::*;
diff --git a/trixy-types/src/traits/try_from_impl.rs b/src/types/traits/try_from_impl.rs
similarity index 94%
rename from trixy-types/src/traits/try_from_impl.rs
rename to src/types/traits/try_from_impl.rs
index f84d3dc..db5ad87 100644
--- a/trixy-types/src/traits/try_from_impl.rs
+++ b/src/types/traits/try_from_impl.rs
@@ -19,7 +19,7 @@
* If not, see .
*/
-use crate::String;
+use crate::types::String;
use std::ffi::CString;
use super::convert_trait::Convertible;
@@ -34,7 +34,7 @@ impl From for String {
}
impl TryFrom for std::string::String {
- type Error = crate::error::TypeConversionError;
+ type Error = crate::types::error::TypeConversionError;
fn try_from(value: String) -> Result {
let cstring = CString::from_ptr(value.0)?;
diff --git a/trixy-types/src/types_list.rs b/src/types/types_list.rs
similarity index 100%
rename from trixy-types/src/types_list.rs
rename to src/types/types_list.rs
diff --git a/trixy-macros/.gitignore b/trixy-macros/.gitignore
deleted file mode 100644
index 20c0ba9..0000000
--- a/trixy-macros/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# build
-/target
-/result
-
-# This crate is a library
-Cargo.lock
diff --git a/trixy-macros/Cargo.toml b/trixy-macros/Cargo.toml
deleted file mode 100644
index 53eb334..0000000
--- a/trixy-macros/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2023 - 2024:
-# The Trinitrix Project
-#
-# This file is part of the Trixy crate for Trinitrix.
-#
-# Trixy is free software: you can redistribute it and/or modify
-# it under the terms of the Lesser GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# and the Lesser GNU General Public License along with this program.
-# If not, see .
-
-[package]
-name = "trixy-macros"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-convert_case = "0.6.0"
-prettyplease = "0.2.15"
-proc-macro2 = {version = "1.0.70", features = [ ]}
-quote = "1.0.33"
-syn = { version = "2.0.41", features = ["extra-traits", "full", "parsing"] }
-trixy-parser = { path = "../trixy-parser" }
-trixy-types = { path = "../trixy-types" }
diff --git a/trixy-macros/src/generate/c_api/header/pure_header.rs b/trixy-macros/src/generate/c_api/header/pure_header.rs
deleted file mode 100644
index 7885019..0000000
--- a/trixy-macros/src/generate/c_api/header/pure_header.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use trixy_parser::command_spec::{
- CommandSpec, DocIdentifier, DocNamedType, Enumeration, Function, Identifier, Namespace,
- Structure,
-};
-
-use crate::generate::{
- c_api::{
- header::{attribute_to_doc_comment, named_type_to_c, type_to_c},
- identifier_to_c, mangle_c_function_identifier,
- },
- identifier_to_rust,
-};
-
-pub fn generate(trixy: &CommandSpec) -> String {
- let functions: String = trixy
- .functions
- .iter()
- .map(|r#fn| function_to_header(r#fn, &[]))
- .collect();
- let namespaces: String = trixy
- .namespaces
- .iter()
- .map(|nasp| namespace_to_header(nasp, &vec![]))
- .collect();
- let structures: String = trixy
- .structures
- .iter()
- .map(|r#struct| structure_to_header(r#struct))
- .collect();
- let enumerations: String = trixy
- .enumerations
- .iter()
- .map(|r#enum| enumeration_to_header(r#enum))
- .collect();
- format!(
- "{}\n{}\n{}\n{}",
- enumerations, structures, functions, namespaces
- )
-}
-fn structure_to_header(structure: &Structure) -> String {
- let doc_comments: String = structure
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
- let ident = identifier_to_c(&structure.identifier);
- let contents = structure
- .contents
- .iter()
- .map(doc_named_type_to_header)
- .collect::();
- format!(
- "
- {}
- {} {{
- {}
- }};",
- doc_comments, ident, contents
- )
-}
-fn doc_named_type_to_header(doc_named_type: &DocNamedType) -> String {
- let doc_comments: String = doc_named_type
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
- let ident = identifier_to_rust(&doc_named_type.name);
- let r#type = type_to_c(&doc_named_type.r#type, false);
- format!("{}{} {};", doc_comments, r#type, ident)
-}
-fn enumeration_to_header(enumeration: &Enumeration) -> String {
- let doc_comments: String = enumeration
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
- let ident = identifier_to_c(&enumeration.identifier);
- let states = enumeration
- .states
- .iter()
- .map(doc_identifier_to_header)
- .collect::();
- let states = if enumeration.states.is_empty() {
- "/**
- * This enum does not have variants on the rust side
- * to work around c limitiation with variant-less enums
- * we added a `__never` variant:
- */
- __never,"
- .to_owned()
- } else {
- states
- };
- format!(
- "
- {}
- {} {{
- {}
- }};",
- doc_comments, ident, states
- )
-}
-fn doc_identifier_to_header(doc_identifier: &DocIdentifier) -> String {
- let doc_comments: String = doc_identifier
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
- let ident = &doc_identifier.name;
- format!("{}{},", doc_comments, ident)
-}
-fn function_to_header(function: &Function, namespaces: &[&Identifier]) -> String {
- let doc_comments: String = function
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
- let ident = mangle_c_function_identifier(&function.identifier, namespaces);
- let inputs: Vec = function.inputs.iter().map(named_type_to_c).collect();
-
- let function_output = if let Some(out) = &function.output {
- let type_name = type_to_c(&out, true);
- let comma = if !inputs.is_empty() {
- quote! {
- ,
- }
- } else {
- TokenStream2::default()
- };
- quote! {
- #type_name trixy_output #comma
- }
- } else {
- TokenStream2::default()
- };
-
- let output = quote! {
- extern int #ident(#function_output #(#inputs),*);
- };
- format!("{}{}\n", doc_comments, output)
-}
-fn namespace_to_header(nasp: &Namespace, namespaces: &Vec<&Identifier>) -> String {
- let mut nasps = namespaces.clone();
- nasps.push(&nasp.name);
-
- let structures: String = nasp
- .structures
- .iter()
- .map(|r#fn| structure_to_header(r#fn))
- .collect::>()
- .join("\n");
- let enumerations: String = nasp
- .enumerations
- .iter()
- .map(|r#fn| enumeration_to_header(r#fn))
- .collect::>()
- .join("\n");
- let functions: String = nasp
- .functions
- .iter()
- .map(|r#fn| function_to_header(r#fn, &nasps))
- .collect::>()
- .join("\n");
- let namespaces: String = nasp
- .namespaces
- .iter()
- .map(|nasp| namespace_to_header(nasp, &nasps))
- .collect();
-
- format! {"{}\n{}\n{}\n{}", enumerations, structures, functions, namespaces}
-}
diff --git a/trixy-macros/src/generate/c_api/header/structs_init.rs b/trixy-macros/src/generate/c_api/header/structs_init.rs
deleted file mode 100644
index 8aa1482..0000000
--- a/trixy-macros/src/generate/c_api/header/structs_init.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::format_ident;
-use quote::quote;
-use trixy_parser::command_spec::{CommandSpec, Function, Identifier, Namespace};
-
-use crate::generate::{c_api::mangle_c_function_identifier, identifier_to_rust};
-
-pub fn generate(trixy: &CommandSpec) -> String {
- let struct_initializer: TokenStream2 = trixy
- .namespaces
- .iter()
- .map(|nasp| namespace_to_full_struct_init(nasp, &vec![]))
- .collect();
- struct_initializer.to_string()
-}
-
-fn namespace_to_full_struct_init(nasp: &Namespace, namespaces: &Vec<&Identifier>) -> TokenStream2 {
- let mut input_namespaces = namespaces.clone();
- input_namespaces.push(&nasp.name);
-
- let ident = identifier_to_rust(&nasp.name);
- let type_ident = format_ident!("{}", ident.to_string());
- let functions: TokenStream2 = nasp
- .functions
- .iter()
- .map(|r#fn| function_to_struct_init(r#fn, &input_namespaces))
- .collect();
- let namespaces: TokenStream2 = nasp
- .namespaces
- .iter()
- .map(namespace_to_struct_init)
- .collect();
-
- let next_namespace: TokenStream2 = nasp
- .namespaces
- .iter()
- .map(|nasp| namespace_to_full_struct_init(nasp, &input_namespaces))
- .collect();
-
- quote! {
- #next_namespace
-
- const struct #type_ident #ident = {
- #functions
- #namespaces
- };
- }
-}
-fn function_to_struct_init(function: &Function, namespaces: &[&Identifier]) -> TokenStream2 {
- let ident = identifier_to_rust(&function.identifier);
- let full_ident = mangle_c_function_identifier(&function.identifier, namespaces);
-
- quote! {
- . #ident = #full_ident,
- }
-}
-
-fn namespace_to_struct_init(namespace: &Namespace) -> TokenStream2 {
- let ident = identifier_to_rust(&namespace.name);
-
- quote! {
- . #ident = #ident ,
- }
-}
diff --git a/trixy-macros/src/generate/c_api/header/typedef.rs b/trixy-macros/src/generate/c_api/header/typedef.rs
deleted file mode 100644
index 67854e4..0000000
--- a/trixy-macros/src/generate/c_api/header/typedef.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{format_ident, quote};
-use trixy_parser::command_spec::{CommandSpec, Function, Namespace};
-
-use crate::generate::{
- c_api::{header::attribute_to_doc_comment, type_to_c},
- identifier_to_rust,
-};
-
-pub fn generate(trixy: &CommandSpec) -> String {
- let type_defs: String = trixy
- .namespaces
- .iter()
- .rev()
- .map(|nasp| namespace_to_full_typedef(nasp))
- .collect::>()
- .join("\n");
- type_defs.to_string()
-}
-
-fn function_to_typedef(function: &Function) -> TokenStream2 {
- let ident = identifier_to_rust(&function.identifier);
-
- let (output, output_comma) = if let Some(output) = &function.output {
- let output = type_to_c(output, true);
- (quote! { #output }, quote! {,})
- } else {
- (TokenStream2::default(), TokenStream2::default())
- };
-
- let inputs: TokenStream2 = if function.inputs.is_empty() && output.is_empty() {
- quote! { void }
- } else if !function.inputs.is_empty() && !output.is_empty() {
- let inputs: Vec = function
- .inputs
- .iter()
- .map(|named_type| &named_type.r#type)
- .map(|r#type| type_to_c(&r#type, false))
- .collect();
- quote! {
- #output_comma #(#inputs),*
- }
- } else {
- TokenStream2::default()
- };
-
- quote! {
- int (* #ident ) (#output #inputs);
- }
-}
-
-fn namespace_to_typedef(namespace: &Namespace) -> TokenStream2 {
- let ident = identifier_to_rust(&namespace.name);
- let type_ident = format_ident!("{}", ident.to_string());
-
- quote! {
- struct #type_ident #ident;
- }
-}
-
-fn namespace_to_full_typedef(nasp: &Namespace) -> String {
- let ident = format_ident!("{}", nasp.name.name);
- let doc_comments = nasp
- .attributes
- .iter()
- .map(attribute_to_doc_comment)
- .collect::();
-
- let functions: TokenStream2 = nasp
- .functions
- .iter()
- .map(|r#fn| function_to_typedef(r#fn))
- .collect();
- let namespaces: TokenStream2 = nasp
- .namespaces
- .iter()
- .map(|nasp| namespace_to_typedef(nasp))
- .collect();
- let next_namespace: String = nasp
- .namespaces
- .iter()
- .map(|nasp| namespace_to_full_typedef(nasp))
- .collect::>()
- .join("\n");
-
- let namespace = quote! {
- struct #ident {
- #functions
- #namespaces
- };
- };
- format! {"{}\n{}{}\n", next_namespace, doc_comments, namespace}
-}
diff --git a/trixy-macros/src/generate/c_api/host.rs b/trixy-macros/src/generate/c_api/host.rs
deleted file mode 100644
index 95385c1..0000000
--- a/trixy-macros/src/generate/c_api/host.rs
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use convert_case::{Case, Casing};
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{format_ident, quote};
-use trixy_parser::command_spec::{
- CommandSpec, Enumeration, Function, Identifier, NamedType, Namespace, Structure,
-};
-
-use crate::{
- config::TrixyConfig,
- generate::{
- attribute_to_rust,
- c_api::{
- doc_named_type_to_c_equivalent, mangle_c_function_identifier, mangle_c_type_identifier,
- type_to_c_equivalent,
- },
- convertible_derive::c_enumeration_into_impl,
- doc_identifier_to_rust, function_identifier_to_rust, identifier_to_rust,
- namespaces_to_path, type_variant_rust_path,
- },
-};
-
-/// This function generates the main c API provided by Trixy.
-/// This works for example like this:
-/// Turning this:
-/// ```text
-/// nasp trinitrix {
-/// struct Callback {
-/// func: String,
-/// timeout: String,
-/// };
-///
-/// enum CallbackPriority {
-/// High,
-/// Medium,
-/// Low,
-/// };
-///
-/// fn execute_callback(callback: Callback, priority: CallbackPriority);
-/// }
-/// ```
-/// to this:
-/// ```no_run
-/// pub extern "C" fn exectute_callback(callback: Callback, priority: CallbackPriority) {
-/// /* Here we simply call your handler function, with the command of the function */
-/// }
-/// ```
-pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
- let functions: TokenStream2 = trixy
- .functions
- .iter()
- .map(|r#fn| function_to_c(r#fn, &config, &vec![]))
- .collect();
- let namespaced_functions: TokenStream2 = trixy
- .namespaces
- .iter()
- .map(|nasp| namespace_to_c(&nasp, &config, &vec![]))
- .collect();
- let structures: TokenStream2 = trixy
- .structures
- .iter()
- .map(|nasp| structure_to_c(&nasp))
- .collect();
- let enumerations: TokenStream2 = trixy
- .enumerations
- .iter()
- .map(|nasp| enumeration_to_c(&nasp))
- .collect();
- quote! {
- #enumerations
- #structures
- #functions
- #namespaced_functions
- }
-}
-
-fn enumeration_to_c(enumeration: &Enumeration) -> TokenStream2 {
- let ident = mangle_c_type_identifier(&enumeration.identifier);
- let doc_comments: TokenStream2 = enumeration
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&enumeration.identifier, attr))
- .collect();
-
- let states: Vec = enumeration
- .states
- .iter()
- .map(doc_identifier_to_rust)
- .collect();
- let paired_type = {
- let path = type_variant_rust_path(&enumeration.identifier.variant)
- .expect("This should always be some for enums");
-
- let ident = identifier_to_rust(&enumeration.identifier);
- if path.is_empty() {
- quote! {
- crate :: #ident
- }
- } else {
- quote! {
- #path :: #ident
- }
- }
- };
-
- let convertible = c_enumeration_into_impl(&enumeration, &paired_type);
- quote! {
- #doc_comments
- #[allow(non_camel_case_types)]
- #[repr(C)]
- #[derive(Debug)]
- pub enum #ident {
- #(#states),*
- }
- #convertible
- }
-}
-
-fn structure_to_c(structure: &Structure) -> TokenStream2 {
- let ident = mangle_c_type_identifier(&structure.identifier);
- let doc_comments: TokenStream2 = structure
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&structure.identifier, attr))
- .collect();
-
- let contents: Vec = structure
- .contents
- .iter()
- .map(doc_named_type_to_c_equivalent)
- .collect();
-
- // TODO: Convertible <2024-03-08>
- quote! {
- #doc_comments
- #[allow(non_camel_case_types)]
- #[repr(C)]
- #[derive(Debug)]
- pub struct #ident {
- #(#contents),*
- }
- }
-}
-
-fn namespace_to_c(
- namespace: &Namespace,
- config: &TrixyConfig,
- namespaces: &Vec<&Identifier>,
-) -> TokenStream2 {
- let ident = mangle_c_type_identifier(&namespace.name);
- let mut namespaces = namespaces.clone();
- namespaces.push(&namespace.name);
-
- let functions: TokenStream2 = namespace
- .functions
- .iter()
- .map(|r#fn| function_to_c(&r#fn, &config, &namespaces))
- .collect();
- let additional_functions: TokenStream2 = namespace
- .namespaces
- .iter()
- .map(|nasp| namespace_to_c(&nasp, &config, &namespaces))
- .collect();
- let structures: TokenStream2 = namespace
- .structures
- .iter()
- .map(|nasp| structure_to_c(&nasp))
- .collect();
- let enumerations: TokenStream2 = namespace
- .enumerations
- .iter()
- .map(|nasp| enumeration_to_c(&nasp))
- .collect();
- quote! {
- pub mod #ident {
- #enumerations
- #structures
- }
- #functions
- #additional_functions
- }
-}
-
-fn function_to_c(
- function: &Function,
- config: &TrixyConfig,
- namespaces: &Vec<&Identifier>,
-) -> TokenStream2 {
- let ident = mangle_c_function_identifier(&function.identifier, namespaces);
- let inputs: Vec = function
- .inputs
- .iter()
- .map(|named_type| named_type_to_rust_trixy(named_type))
- .collect();
-
- let callback_function = format_ident!("{}", config.callback_function);
-
- let command_value: TokenStream2 = function_path_to_rust(&namespaces, &function);
-
- if let Some(r#type) = &function.output {
- let output_ident = type_to_c_equivalent(&r#type);
- quote! {
- #[no_mangle]
- pub extern "C" fn #ident(output: *mut #output_ident, #(#inputs),*) -> core::ffi::c_int {
- let output_val: #output_ident = {
- let (tx, rx) = trixy::oneshot::channel();
- #callback_function (#command_value);
- let recv = rx.recv().expect("The channel should not be closed until this value is received");
- recv.into()
- };
- unsafe {
- std::ptr::write(output, output_val);
- }
- return 1;
- }
- }
- } else {
- quote! {
- #[no_mangle]
- pub extern "C" fn #ident(#(#inputs),*) -> core::ffi::c_int {
- #callback_function (#command_value);
- return 1;
- }
- }
- }
-}
-
-fn named_type_to_rust_trixy(named_type: &NamedType) -> TokenStream2 {
- let ident = identifier_to_rust(&named_type.name);
- let type_ident = type_to_c_equivalent(&named_type.r#type);
- quote! {
- #ident : #type_ident
- }
-}
-
-/// Turns a function in namespaces to the generated host enum path:
-/// *trixy code:*
-/// ```text
-/// fn fn_alone();
-/// nasp one {
-/// fn fn_one();
-/// nasp two {
-/// fn fn_two(input: String);
-/// }
-/// }
-/// ```
-/// *rust enum path for fn_alone:*
-/// ```no_run
-/// Commands::fn_alone
-/// ```
-/// *rust enum path for fn_one:*
-/// ```no_run
-/// // `Commands` is just the name for the top-level namespace
-/// Commands::One(one::One(
-/// One::fn_one
-/// ))
-/// ```
-/// *rust enum path for fn_two:*
-/// ```no_run
-/// Commands::One(one::One(
-/// one::two::Two(one::two::Two(
-/// Two::fn_two {input: String}
-/// ))))
-/// ```
-fn function_path_to_rust(namespaces: &Vec<&Identifier>, function: &Function) -> TokenStream2 {
- let function_ident =
- function_identifier_to_rust(&function, named_type_to_rust_assignment, |_| {
- quote! {
- // This is defined in the outer call
- tx
- }
- });
- if namespaces.is_empty() {
- quote! {
- Commands:: #function_ident
- }
- } else {
- let nasp_pascal_ident = format_ident!(
- "{}",
- namespaces
- .last()
- .expect("We checked")
- .name
- .to_case(Case::Pascal)
- );
-
- let namespace_path = namespaces_to_path(namespaces);
-
- let function_call = quote! {
- #namespace_path :: #nasp_pascal_ident :: #function_ident
- };
-
- let output: TokenStream2 = namespaces
- .iter()
- .enumerate()
- .rev()
- .fold(function_call, |acc, (index, nasp)| {
- nasp_path_one_part(nasp, &acc, &namespaces, index)
- });
-
- output
- }
-}
-
-fn named_type_to_rust_assignment(named_type: &NamedType) -> TokenStream2 {
- let ident = identifier_to_rust(&named_type.name);
- quote! {
- #ident : match #ident.try_into() {
- Ok(ok) => ok,
- Err(err) => {
- trixy::types::traits::errno::set(err);
- return 0;
- }
- }
- }
-}
-
-/// This function add a namespace component to the [input] value like so:
-/// (taking the example from the [function_path_to_rust] function)
-/// ```text
-/// one::two::Two::fn_two [= ]
-/// ->
-/// one::One::Two() [= ]
-/// ->
-/// Commands::One() [= ]
-/// ```
-fn nasp_path_one_part(
- current_nasp: &Identifier,
- input: &TokenStream2,
- namespaces: &Vec<&Identifier>,
- index: usize,
-) -> TokenStream2 {
- let namespaces_to_do = &namespaces[..index];
-
- let ident_pascal = format_ident!("{}", current_nasp.name.to_case(Case::Pascal));
-
- if index == 0 {
- quote! {
- Commands :: #ident_pascal ( #input )
- }
- } else {
- let ident_pascal_next = format_ident!(
- "{}",
- namespaces_to_do
- .last()
- .expect("We checked the index")
- .name
- .to_case(Case::Pascal)
- );
- let namespace_path = namespaces_to_path(namespaces_to_do);
- quote! {
- #namespace_path :: #ident_pascal_next :: #ident_pascal ( #input )
- }
- }
-}
diff --git a/trixy-macros/src/generate/c_api/mod.rs b/trixy-macros/src/generate/c_api/mod.rs
deleted file mode 100644
index b94135a..0000000
--- a/trixy-macros/src/generate/c_api/mod.rs
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use convert_case::{Case, Casing};
-use proc_macro2::{Ident, TokenStream as TokenStream2};
-use quote::{format_ident, quote};
-use trixy_parser::command_spec::{DocNamedType, Identifier, NamedType, Type, Variant};
-
-use crate::generate::{attribute_to_rust, namespaces_to_path_expansive, type_to_rust};
-
-use super::identifier_to_rust;
-
-pub mod header;
-pub mod host;
-
-pub fn mangle_c_function_identifier(identifier: &Identifier, namespaces: &[&Identifier]) -> Ident {
- let namespace_str = namespaces.iter().fold(String::default(), |acc, nasp| {
- if acc.is_empty() {
- nasp.name.clone()
- } else {
- format!("{}_{}", acc, nasp.name)
- }
- });
-
- if namespace_str.is_empty() {
- format_ident!("{}", &identifier.name)
- } else {
- format_ident!("{}_{}", namespace_str, &identifier.name)
- }
-}
-pub fn mangle_c_type_identifier(identifier: &Identifier) -> Ident {
- format_ident!("{}_c", &identifier.name)
-}
-
-pub fn type_to_c(r#type: &Type, is_output: bool) -> TokenStream2 {
- let ident = identifier_to_c(&r#type.identifier);
- let output = if is_output {
- quote! {
- *
- }
- } else {
- TokenStream2::default()
- };
- quote! {
- #ident #output
- }
-}
-pub fn identifier_to_c(identifier: &Identifier) -> TokenStream2 {
- match &identifier.variant {
- Variant::Structure { .. } => {
- let ident = format_ident!("{}", identifier.name.to_case(Case::Pascal));
- quote! {
- struct #ident
- }
- }
- Variant::Enumeration { .. } => {
- let ident = format_ident!("{}", identifier.name.to_case(Case::Pascal));
- quote! {
- enum #ident
- }
- }
- Variant::Primitive => match identifier.name.to_case(Case::Snake).as_str() {
- "string" => {
- quote! {
- const char*
- }
- }
- other => {
- todo!("'{}' is not yet supported", other)
- }
- },
- other => {
- unimplemented!("{:#?}", other)
- }
- }
-}
-
-pub fn type_to_c_equivalent(r#type: &Type) -> TokenStream2 {
- let trixy_build_in_types: Vec<&str> = trixy_types::BASE_TYPES
- .iter()
- .filter_map(|(name, _)| {
- if name == &r#type.identifier.name {
- Some(*name)
- } else {
- None
- }
- })
- .collect();
-
- if trixy_build_in_types.is_empty() {
- // The types was specified in the api.tri file
-
- let ident = mangle_c_type_identifier(&r#type.identifier);
-
- let namespaces_path = type_variant_c_path(&r#type.identifier.variant);
- let nasp_path = if namespaces_path.is_empty() {
- quote! {
- crate ::
- }
- } else {
- let path = namespaces_path;
- quote! {
- #path ::
- }
- };
- quote! {
- #nasp_path #ident
- }
- } else {
- debug_assert_eq!(trixy_build_in_types.len(), 1);
-
- let type_name = trixy_build_in_types
- .first()
- .expect("The names should not be dublicated, this should be the only value");
-
- match *type_name {
- "Result" => {
- let ident_ok =
- type_to_c_equivalent(&r#type.generic_args.first().expect("This is a result"));
- let ident_err =
- type_to_c_equivalent(&r#type.generic_args.last().expect("This is a result"));
- quote! {
- // as Convertible>::Ptr,
- as Convertible>::Ptr
- }
- }
- "Option" => {
- let value = type_to_rust(
- r#type
- .generic_args
- .first()
- .expect("An option does only have one arg"),
- );
- quote! {
- *const #value
- }
- }
- _ => {
- let ident = identifier_to_rust(&r#type.identifier);
- let generics: TokenStream2 = {
- let generics: Vec = r#type
- .generic_args
- .iter()
- .map(|val| type_to_c_equivalent(val))
- .collect();
- quote! {
- <#(#generics),*>
- }
- };
-
- quote! {
- trixy::types:: #ident #generics
- }
- }
- }
- }
-}
-fn doc_named_type_to_c_equivalent(doc_named_type: &DocNamedType) -> TokenStream2 {
- let doc_comments: TokenStream2 = doc_named_type
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&&doc_named_type.name, attr))
- .collect();
- let named_type = named_type_to_c_equivalent(&doc_named_type.into());
- quote! {
- #doc_comments
- pub #named_type
- }
-}
-fn named_type_to_c_equivalent(named_type: &NamedType) -> TokenStream2 {
- let ident = identifier_to_rust(&named_type.name);
- let r#type = type_to_c_equivalent(&named_type.r#type);
- quote! {
- #ident : #r#type
- }
-}
-pub fn type_variant_c_path(variant: &Variant) -> TokenStream2 {
- fn mangle_namespace_name(vec: &Vec) -> Vec {
- vec.into_iter()
- .map(|ident| {
- if "" == &ident.name && ident.variant == Variant::RootNamespace {
- // The [`namespaces_to_path_expansive`] function already deals with
- // [`RootNamespace`] variants, so we just leave that as is
- ident.clone()
- } else {
- Identifier {
- // TODO(@soispha): This should use [`mangle_c_type_name`]
- // to ensure same mangling as the others <2024-03-05>
- name: format!("{}_c", ident.name),
- variant: ident.variant.clone(),
- }
- }
- })
- .collect()
- }
-
- let main_namespace;
- match variant {
- Variant::Structure { namespace } => {
- main_namespace = mangle_namespace_name(namespace);
- }
- Variant::Enumeration { namespace } => {
- main_namespace = mangle_namespace_name(namespace);
- }
- _ => unreachable!("This should never be called"),
- }
- namespaces_to_path_expansive(&main_namespace[..])
-}
diff --git a/trixy-macros/src/generate/convertible_derive.rs b/trixy-macros/src/generate/convertible_derive.rs
deleted file mode 100644
index 77a62ae..0000000
--- a/trixy-macros/src/generate/convertible_derive.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use proc_macro2::TokenStream;
-use quote::{quote, ToTokens};
-use trixy_parser::command_spec::{Enumeration, Structure};
-
-use crate::generate::{c_api::mangle_c_type_identifier, identifier_to_rust};
-
-/// This function generates the `Convertible` implementation for a structure
-pub fn structure_convertable_derive(
- structure: &Structure,
- paired_type: &TokenStream,
-) -> TokenStream {
- let ident = identifier_to_rust(&structure.identifier);
-
- let into_fields: TokenStream = structure
- .contents
- .iter()
- .map(|con| {
- let ident = identifier_to_rust(&con.name);
- quote! {
- #ident: self.#ident.into(),
- }
- })
- .collect();
-
- quote! {
- impl trixy::types::traits::convert_trait::Convertible for #ident {
- type Ptr = #paired_type;
-
- fn into_ptr(self) -> Self::Ptr {
- Self::Ptr {
- #into_fields
- }
- }
-
- fn from_ptr(ptr: Self::Ptr) -> Result {
- todo!()
- }
- }
- }
-}
-
-/// This function generates the `TryFrom` trait implementation for a given structure
-pub fn structure_into_impl(structure: &Structure, paired_type: &TokenStream) -> TokenStream {
- let ident = identifier_to_rust(&structure.identifier);
-
- let try_into_fields: TokenStream = structure
- .contents
- .iter()
- .map(|con| {
- let ident = identifier_to_rust(&con.name);
- quote! {
- #ident: value.#ident.try_into()?,
- }
- })
- .collect();
-
- quote! {
- impl TryFrom<#paired_type> for #ident {
- type Error = trixy::types::error::TypeConversionError;
-
- fn try_from(value: #paired_type) -> Result {
- Ok(Self {
- #try_into_fields
- })
- }
- }
- }
-}
-
-/// This function generates the `From` trait implementation for a given c enumeration
-pub fn c_enumeration_into_impl(
- enumeration: &Enumeration,
- paired_type: &TokenStream,
-) -> TokenStream {
- let c_ident = mangle_c_type_identifier(&enumeration.identifier);
- let ident = identifier_to_rust(&enumeration.identifier);
-
- enumeration_into_impl(
- enumeration,
- &c_ident.into_token_stream(),
- &ident,
- &paired_type,
- )
-}
-
-/// This function generates the `From` trait implementation for a given rust enumeration
-pub fn rust_enumeration_into_impl(
- enumeration: &Enumeration,
- paired_type: &TokenStream,
-) -> TokenStream {
- let c_ident = mangle_c_type_identifier(&enumeration.identifier);
- let ident = identifier_to_rust(&enumeration.identifier);
-
- enumeration_into_impl(
- enumeration,
- &ident,
- &c_ident.into_token_stream(),
- &paired_type,
- )
-}
-
-fn enumeration_into_impl(
- enumeration: &Enumeration,
- ident_main: &TokenStream,
- ident_client: &TokenStream,
- paired_type: &TokenStream,
-) -> TokenStream {
- let match_lines: TokenStream = enumeration
- .states
- .iter()
- .map(|state| {
- let name = identifier_to_rust(&(state.into()));
- quote! {
- #ident_client :: #name => Self :: #name,
- }
- })
- .collect();
- quote! {
- impl From<#paired_type> for #ident_main {
- fn from(value: #paired_type) -> Self {
- match value {
- #match_lines
- }
- }
- }
- }
-}
diff --git a/trixy-macros/src/generate/host/mod.rs b/trixy-macros/src/generate/host/mod.rs
deleted file mode 100644
index 548c051..0000000
--- a/trixy-macros/src/generate/host/mod.rs
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-//! This module is responsible for generating the rust code used to interface with the api.
-//! That includes the structs and enums declared in the trixy file and the enum used to describe the
-//! command being executed.
-
-use std::cell::OnceCell;
-
-use convert_case::{Case, Casing};
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{format_ident, quote};
-use trixy_parser::command_spec::{
- CommandSpec, Enumeration, Function, Identifier, Namespace, Structure,
-};
-
-use crate::{
- config::TrixyConfig,
- generate::{
- attribute_to_rust,
- c_api::{mangle_c_type_identifier, type_variant_c_path},
- convertible_derive::{
- rust_enumeration_into_impl, structure_convertable_derive, structure_into_impl,
- },
- doc_identifier_to_rust, doc_named_type_to_rust, identifier_to_rust, named_type_to_rust,
- type_variant_rust_path,
- },
-};
-
-use super::{c_api::type_to_c_equivalent, function_identifier_to_rust};
-
-thread_local! {static DEBUG: OnceCell = OnceCell::new();}
-
-/// This function turns, for example, the following trixy input into this rust code:
-/// ```text
-/// nasp trinitrix {
-/// struct Callback {
-/// func: String,
-/// timeout: String,
-/// };
-///
-/// enum CallbackPriority {
-/// High,
-/// Medium,
-/// Low,
-/// };
-///
-/// fn execute_callback(callback: Callback, priority: CallbackPriority) -> String;
-/// }
-/// ```
-/// ```no_run
-/// #[derive(Debug)]
-/// pub enum Commands {
-/// Trinitrix(trinitrix::Trinitrix),
-/// }
-/// pub mod trinitrix {
-/// #[allow(non_camel_case_types)]
-/// #[derive(Debug)]
-/// struct Callback {
-/// func: String,
-/// timeout: String,
-/// }
-/// #[allow(non_camel_case_types)]
-/// #[derive(Debug)]
-/// enum CallbackPriority {
-/// High,
-/// Medium,
-/// Low,
-/// }
-/// #[derive(Debug)]
-/// pub enum Trinitrix {
-/// #[allow(non_camel_case_types)]
-/// execute_callback {
-/// callback: Callback,
-/// priority: CallbackPriority,
-/// trixy_output: trixy::oneshot::channel
-/// },
-/// }
-/// }
-/// ```
-pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
- DEBUG.with(|d| {
- d.set(if config.generate_debug {
- quote! {
- #[derive(Debug)]
- }
- } else {
- TokenStream2::default()
- })
- .expect("The cell should always be empty at this point");
- });
-
- let modules: TokenStream2 = trixy
- .namespaces
- .iter()
- .map(|nasp| namespace_to_module(nasp, &vec![]))
- .collect();
- let structures: TokenStream2 = trixy.structures.iter().map(structure_to_rust).collect();
- let enumerations: TokenStream2 = trixy.enumerations.iter().map(enumeration_to_rust).collect();
- let functions: Vec = trixy
- .functions
- .iter()
- .map(|r#fn| function_to_rust(r#fn, &[]))
- .collect();
- let namespace_modules: Vec = trixy
- .namespaces
- .iter()
- .map(namespace_to_module_enum)
- .collect();
-
- let debug = get_debug_sate();
-
- quote! {
- #structures
- #enumerations
- #debug
- pub enum Commands {
- #(#functions,)*
- #(#namespace_modules),*
- }
- #modules
- }
-}
-
-fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) -> TokenStream2 {
- let mut namespaces = namespaces.clone();
- namespaces.push(&namespace.name);
- let ident = identifier_to_rust(&namespace.name);
- let enum_ident = format_ident!("{}", &namespace.name.name.to_case(Case::Pascal));
-
- let doc_comments: TokenStream2 = namespace
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&namespace.name, attr))
- .collect();
- let structures: TokenStream2 = namespace.structures.iter().map(structure_to_rust).collect();
- let enumerations: TokenStream2 = namespace
- .enumerations
- .iter()
- .map(enumeration_to_rust)
- .collect();
- let functions: Vec = namespace
- .functions
- .iter()
- .map(|r#fn| function_to_rust(r#fn, &namespaces))
- .collect();
- let namespace_modules: Vec = namespace
- .namespaces
- .iter()
- .map(namespace_to_module_enum)
- .collect();
- let namespaces: TokenStream2 = namespace
- .namespaces
- .iter()
- .map(|nasp| namespace_to_module(nasp, &namespaces))
- .collect();
-
- let debug = get_debug_sate();
- quote! {
- #doc_comments
- pub mod #ident {
- #structures
- #enumerations
- #debug
- pub enum #enum_ident {
- #(#functions,)*
- #(#namespace_modules),*
- }
- #namespaces
- }
- }
-}
-
-fn namespace_to_module_enum(namespace: &Namespace) -> TokenStream2 {
- let pascal_ident = format_ident!("{}", namespace.name.name.to_case(Case::Pascal));
- let ident = identifier_to_rust(&namespace.name);
- quote! {
- #pascal_ident(#ident :: #pascal_ident)
- }
-}
-
-fn get_debug_sate() -> TokenStream2 {
- let debug = DEBUG.with(|d| {
- d.get()
- .expect("The cell should contain something at this point")
- .clone()
- });
- debug
-}
-
-fn function_to_rust(function: &Function, namespaces: &[&Identifier]) -> TokenStream2 {
- let doc_comments: TokenStream2 = function
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&function.identifier, attr))
- .collect();
- let function_ident =
- function_identifier_to_rust(&function, named_type_to_rust, move |r#type| {
- let ident = type_to_c_equivalent(r#type);
- quote! {
- trixy::oneshot::Sender<#ident>
- }
- });
-
- quote! {
- #doc_comments
- #[allow(non_camel_case_types)]
- #function_ident
- }
-}
-
-fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 {
- let doc_comments: TokenStream2 = enumeration
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&enumeration.identifier, attr))
- .collect();
-
- let ident = identifier_to_rust(&enumeration.identifier);
- let states: Vec = enumeration
- .states
- .iter()
- .map(doc_identifier_to_rust)
- .collect();
-
- let debug = get_debug_sate();
-
- let paired_type = {
- let path = type_variant_c_path(&enumeration.identifier.variant);
-
- let ident = mangle_c_type_identifier(&enumeration.identifier);
- if path.is_empty() {
- quote! {
- crate :: #ident
- }
- } else {
- quote! {
- #path :: #ident
- }
- }
- };
-
- let convertible = rust_enumeration_into_impl(&enumeration, &paired_type);
-
- quote! {
- #doc_comments
- #[allow(non_camel_case_types)]
- #debug
- pub enum #ident {
- #(#states),*
- }
- #convertible
- }
-}
-
-fn structure_to_rust(structure: &Structure) -> TokenStream2 {
- let doc_comments: TokenStream2 = structure
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&structure.identifier, attr))
- .collect();
-
- let ident = identifier_to_rust(&structure.identifier);
- let c_ident = {
- let path = type_variant_c_path(&structure.identifier.variant);
- let ident = mangle_c_type_identifier(&structure.identifier);
- if path.is_empty() {
- quote! {
- crate :: #ident
- }
- } else {
- quote! {
- #path :: #ident
- }
- }
- };
- let contents: Vec = structure
- .contents
- .iter()
- .map(doc_named_type_to_rust)
- .collect();
- let convertible = structure_convertable_derive(&structure, &c_ident);
- let into_impl = structure_into_impl(&structure, &c_ident);
-
- let debug = get_debug_sate();
-
- quote! {
- #doc_comments
- #[allow(non_camel_case_types)]
- #debug
- pub struct #ident {
- #(#contents),*
- }
- #convertible
- #into_impl
- }
-}
diff --git a/trixy-macros/src/generate/mod.rs b/trixy-macros/src/generate/mod.rs
deleted file mode 100644
index 2b429f6..0000000
--- a/trixy-macros/src/generate/mod.rs
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use std::ops::Deref;
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{format_ident, quote};
-use trixy_parser::command_spec::{
- Attribute, CommandSpec, DocIdentifier, DocNamedType, Function, Identifier, NamedType, Type,
- Variant,
-};
-
-use crate::config::TrixyConfig;
-
-pub mod c_api;
-pub mod convertible_derive;
-pub mod host;
-
-pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
- // Build the language wrappers
- let c_host_api = c_api::host::generate(&trixy, &config);
-
- // Build the final rust hosting code
- let host_rust_code = host::generate(&trixy, &config);
-
- quote! {
- #host_rust_code
- /* C api */
- #c_host_api
- }
-}
-
-fn identifier_to_rust(identifier: &Identifier) -> TokenStream2 {
- if &identifier.name == "()" {
- quote! {
- ()
- }
- } else {
- let ident = format_ident!("{}", &identifier.name);
- quote! {
- #ident
- }
- }
-}
-
-fn function_identifier_to_rust(
- function: &Function,
- input_fmt_fn: fn(&NamedType) -> TokenStream2,
- output_fmt_fn: F,
-) -> TokenStream2
-where
- F: Fn(&Type) -> TokenStream2,
-{
- let ident = identifier_to_rust(&function.identifier);
- let inputs: Vec = function.inputs.iter().map(input_fmt_fn).collect();
- let output = &function.output;
-
- if inputs.is_empty() && output.is_none() {
- quote! {
- #ident
- }
- } else if output.is_some() {
- let output = output_fmt_fn(&output.as_ref().expect("We checked"));
- quote! {
- #ident {
- trixy_output: #output ,
- #(#inputs),*
- }
- }
- } else if output.is_none() && !inputs.is_empty() {
- quote! {
- #ident { #(#inputs),* }
- }
- } else {
- unreachable!("All other conditions should be met")
- }
-}
-
-fn named_type_to_rust(named_type: &NamedType) -> TokenStream2 {
- let ident = identifier_to_rust(&named_type.name);
- let r#type = type_to_rust(&named_type.r#type);
- quote! {
- #ident : #r#type
- }
-}
-fn type_to_rust(r#type: &Type) -> TokenStream2 {
- let ident = identifier_to_rust(&r#type.identifier);
- let namespaces_path = type_variant_rust_path(&r#type.identifier.variant);
-
- let nasp_path = if let Some(nasp_path) = type_variant_rust_path(&r#type.identifier.variant) {
- if nasp_path.is_empty() {
- quote! {
- crate ::
- }
- } else {
- let path = namespaces_path;
- quote! {
- #path ::
- }
- }
- } else {
- quote! {}
- };
-
- if r#type.generic_args.is_empty() {
- quote! {
- #nasp_path #ident
- }
- } else {
- let generics: Vec = r#type.generic_args.iter().map(type_to_rust).collect();
- quote! {
- #nasp_path #ident <#(#generics),*>
- }
- }
-}
-fn doc_identifier_to_rust(doc_identifier: &DocIdentifier) -> TokenStream2 {
- let doc_comments: TokenStream2 = doc_identifier
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&doc_identifier.into(), attr))
- .collect();
- let identifier = identifier_to_rust(&doc_identifier.into());
-
- quote! {
- #doc_comments
- #identifier
- }
-}
-
-fn doc_named_type_to_rust(doc_named_type: &DocNamedType) -> TokenStream2 {
- let doc_comments: TokenStream2 = doc_named_type
- .attributes
- .iter()
- .map(|attr| attribute_to_rust(&&doc_named_type.name, attr))
- .collect();
- let named_type = named_type_to_rust(&doc_named_type.into());
- quote! {
- #doc_comments
- pub #named_type
- }
-}
-fn attribute_to_rust(_target: &Identifier, attribute: &Attribute) -> TokenStream2 {
- match attribute {
- Attribute::doc(comment) => quote! {
- #[doc = #comment]
- },
- Attribute::error => quote! {
- // We simply use thiserror here
- #[derive(trixy::__private::thiserror::Error)]
- },
- Attribute::msg(msg) => quote! {
- #[error(#msg)]
- },
- Attribute::derive(_) => unimplemented!("Derive is not used as of now"),
- }
-}
-pub fn type_variant_rust_path(variant: &Variant) -> Option {
- fn namespace_to_borrowed(vec: &Vec) -> Vec<&Identifier> {
- let vec_2: Vec<&Identifier> = vec.iter().collect();
- vec_2
- }
-
- let main_namespace;
- match variant {
- Variant::Structure { namespace } => {
- main_namespace = namespace_to_borrowed(namespace);
- }
- Variant::Enumeration { namespace } => {
- main_namespace = namespace_to_borrowed(namespace);
- }
- _ => return None,
- }
- Some(namespaces_to_path(&main_namespace[..]))
-}
-fn namespaces_to_path>(namespaces: &[T]) -> TokenStream2 {
- namespaces
- .iter()
- .fold(TokenStream2::default(), |acc, nasp| {
- if nasp.variant == Variant::RootNamespace && nasp.name == "" {
- if acc.is_empty() {
- quote! {
- crate
- }
- } else {
- unreachable!("An root namespace can never come, after another namespcae")
- }
- } else {
- let ident = format_ident!("{}", nasp.name);
- if acc.is_empty() {
- quote! {
- crate :: #ident
- }
- } else {
- quote! {
- #acc :: #ident
- }
- }
- }
- })
-}
-fn namespaces_to_path_expansive(namespaces: &[Identifier]) -> TokenStream2 {
- namespaces
- .iter()
- .fold(TokenStream2::default(), |acc, nasp| {
- if nasp.variant == Variant::RootNamespace && nasp.name == "" {
- if acc.is_empty() {
- quote! {
- crate
- }
- } else {
- unreachable!("An root namespace can never come, after another namespcae")
- }
- } else {
- let ident = format_ident!("{}", nasp.name);
- if acc.is_empty() {
- quote! {
- crate :: #ident
- }
- } else {
- quote! {
- #acc :: #ident
- }
- }
- }
- })
-}
diff --git a/trixy-macros/src/lib.rs b/trixy-macros/src/lib.rs
deleted file mode 100644
index 8ab6668..0000000
--- a/trixy-macros/src/lib.rs
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use std::{
- env,
- fs::{self, File},
- io::Write,
- iter,
- path::{Path, PathBuf},
- process::Command,
-};
-
-use trixy_parser::parse_trixy_lang;
-use trixy_types::C_TYPE_HEADER;
-
-use crate::config::TrixyConfig;
-
-pub mod config;
-mod generate;
-
-const VIM_LINE_RUST: &'static str = "// vim: filetype=rust\n";
-const VIM_LINE_C: &'static str = "// vim: filetype=c\n";
-
-impl TrixyConfig {
- /// This is the heart of Trixy
- /// It mainly does one thing:
- /// - Generate a tree of modules from the input trixy file
- ///
- pub fn generate(&self) {
- let source_code = fs::read_to_string(&self.trixy_path).unwrap_or_else(|err| {
- panic! {"Can't read file at path: '{}'. The Error is: '{}'",
- self.trixy_path.display(), err};
- });
-
- let trixy_code = parse_trixy_lang(&source_code).unwrap_or_else(|err| {
- panic! {"Parsing of the trixy file failed: \n{}", err}
- });
-
- // host code
- let tokens = generate::generate(&trixy_code, &self);
- eprintln!("{}", tokens);
- let host_code = prettyplease::unparse(
- &syn::parse2(tokens).expect("This code was generated, it should also be parsable"),
- );
- let mut host_code_out = fs::File::create(PathBuf::from(format!(
- "{}/{}",
- env::var("OUT_DIR").expect("The build script should have this define"),
- &self.host_code_name.display()
- )))
- .expect("This file should always be free to use");
- write!(host_code_out, "{}\n{}", host_code, VIM_LINE_RUST).expect("Write should work");
-
- // c header
- let c_header = generate::c_api::header::generate(&trixy_code, &self);
- let c_header_path = PathBuf::from(format!(
- "{}/{}",
- env::var("OUT_DIR").expect("The build script should have this define"),
- &self.c_header_name.display()
- ));
- let mut c_header_out =
- fs::File::create(&c_header_path).expect("This file should always be free to use");
- write!(c_header_out, "{}\n{}", c_header, VIM_LINE_C).expect("Write should work");
-
- Command::new("clang-format")
- .args(["--style", "GNU"])
- .args(["-i", &c_header_path.to_str().unwrap()])
- .status()
- .unwrap_or_else(|err| {
- panic!(
- "Failed to format the c header file with `clang-format`; Error: `{}`",
- err
- )
- });
-
- if let Some(dist_dir) = &self.dist_dir_path {
- if !dist_dir.is_dir() {
- fs::create_dir(dist_dir).unwrap_or_else(|err| {
- panic! {
- "Failed to create the dist directory ('{}') because of: `{}`",
- dist_dir.display(), err}
- });
- }
- let c_header_dist = PathBuf::from(format!("{}/{}", dist_dir.display(), "generated.h"));
- fs::copy(c_header_path, c_header_dist).unwrap_or_else(
- |err| panic! {"Failed to copy the c header ('generated.h') to the dist dir because of: `{}`", err},
- );
- let (interface_name, interface_content) = {
- let interface_header = format!(
- "\
- /* This file is automatcially generated by Trixy */ \n\
- #ifndef TRIXY_INTERFACE_H \n\
- #define TRIXY_INTERFACE_H \n\
- #include \"generated.h\" \n\
- #endif // TRIXY_INTERFACE_H \n\
- "
- );
- ("interface.h", interface_header)
- };
-
- C_TYPE_HEADER
- .iter()
- .chain(iter::once(&(interface_name, &interface_content[..])))
- .for_each(|(name, content)| {
- let path: &Path = &Path::new(name);
- if self.check_dist_dir {
- if path.exists() {
- panic! {
- "The file ('{}') already exists in your dist dir ('{}')!
- If you want to silence this check set `check_dist_dir` to false",
- path.display(), dist_dir.display()
- }
- }
- }
- let header_path =
- PathBuf::from(format!("{}/{}", dist_dir.display(), path.display()));
- let mut file = File::create(&header_path).unwrap_or_else(|err| {
- panic! {
- "Failed to create the file at '{}' because of: '{}'",
- header_path.display(),
- err
- }
- });
- write!(file, "{}", content).unwrap_or_else(|err| {
- panic! {
- "Failed to copy the c header ('{}') to the dist dir because of: `{}`",
- path.display(),
- err}
- });
- });
- }
- }
-}
diff --git a/trixy-parser/.gitignore b/trixy-parser/.gitignore
deleted file mode 100644
index 20c0ba9..0000000
--- a/trixy-parser/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# build
-/target
-/result
-
-# This crate is a library
-Cargo.lock
diff --git a/trixy-parser/Cargo.toml b/trixy-parser/Cargo.toml
deleted file mode 100644
index c9b4b87..0000000
--- a/trixy-parser/Cargo.toml
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2023 - 2024:
-# The Trinitrix Project
-#
-# This file is part of the Trixy crate for Trinitrix.
-#
-# Trixy is free software: you can redistribute it and/or modify
-# it under the terms of the Lesser GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# and the Lesser GNU General Public License along with this program.
-# If not, see .
-
-[package]
-name = "trixy-parser"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-clap = { version = "4.4.11", features = ["derive"], optional = true }
-convert_case = "0.6.0"
-regex = "1.10.3"
-thiserror = "1.0.50"
-trixy-types = { path = "../trixy-types" }
-
-[dev-dependencies]
-pretty_assertions = "1.4.0"
-
-[features]
-build-binary = ["clap"]
-
-[[bin]]
-name = "trixy-parser"
-required-features = ["build-binary"]
diff --git a/trixy-parser/README.md b/trixy-parser/README.md
deleted file mode 100644
index 9d8c341..0000000
--- a/trixy-parser/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# trixy-lang_parser
-
-This crate contains a parser (and lexer) for the Trixy language.
-The corresponding grammar is in the grammar file [here](./docs/grammar.ebnf) encoded in [Extended Backus-Naur Form](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form).
-
-## Testing
-
-A binary (`trixy-parser`) exists, which provides easy access to the different library
-parsing steps
-
-## Docs
-
-Run `./generate_docs` to turn the grammar file into railroad diagrams.
diff --git a/trixy-parser/example/derives.tri b/trixy-parser/example/derives.tri
deleted file mode 100644
index dfa2f5e..0000000
--- a/trixy-parser/example/derives.tri
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-/// Call out an outstanding person
-fn outstanding(name: String);
-
-enum DogTraining {
- Sheep,
- Wolf,
- Blind,
-}
-
-#[derive("Error")]
-enum TrainingMistake {
- GotBitten,
-}
-
-struct Dog {
- name: String,
-}
-
-struct TrainedDog {
- name: String,
- training: DogTraining,
-}
-
-mod one {
- /// Say hi to a name
- fn hi(name: String) -> String;
-
- /// Train a dog (if it is there, otherwise do nothing)
- fn train_dog(dog: Option) -> Result;
-}
-
-// Trixy is a subset of Rust
-// vim: syntax=rust cms=//%s
diff --git a/trixy-parser/example/derives_minimal.tri b/trixy-parser/example/derives_minimal.tri
deleted file mode 100644
index 35ed596..0000000
--- a/trixy-parser/example/derives_minimal.tri
+++ /dev/null
@@ -1,6 +0,0 @@
-#[derive("Error")]
-enum A {}
-
-// This derive should fail (and produce a wrong spanned error)
-#[derive("Error")]
-mod B {}
diff --git a/trixy-parser/example/empty.tri b/trixy-parser/example/empty.tri
deleted file mode 100644
index 1776d65..0000000
--- a/trixy-parser/example/empty.tri
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-// an empty comment:
-//
-// an empty doc comment:
-///
-mod test {}
diff --git a/trixy-parser/example/failing_derives.tri b/trixy-parser/example/failing_derives.tri
deleted file mode 100644
index df22ea3..0000000
--- a/trixy-parser/example/failing_derives.tri
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-/// Call out an outstanding person
-fn outstanding(name: String);
-
-enum DogTraining {
- Sheep,
- Wolf,
- Blind,
-}
-
-#[derive("Error")]
-enum TrainingMistake {
- GotBitten,
-}
-
-struct Dog {
- name: String,
-}
-
-struct TrainedDog {
- name: String,
- training: DogTraining,
-}
-
-#[derive("Error")]
-mod one {
- /// Say hi to a name
- fn hi(name: String) -> String;
-
- /// Train a dog (if it is there, otherwise do nothing)
- fn train_dog(dog: Option) -> Result;
-}
-
-// Trixy is a subset of Rust
-// vim: syntax=rust cms=//%s
diff --git a/trixy-parser/example/failing_enum_name.tri b/trixy-parser/example/failing_enum_name.tri
deleted file mode 100644
index 15b3909..0000000
--- a/trixy-parser/example/failing_enum_name.tri
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-mod trinitrix {
- /// This enum can't be called Trinitrix, as that's already the name of the namespace
- /// (if it's in Pascal case)
- enum Trinitrix {
- High,
- Medium,
- Low,
- }
-
- fn execute_callback(priority: Trinitrix);
-}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/failing_types_generic.tri b/trixy-parser/example/failing_types_generic.tri
deleted file mode 100644
index 7e7d1c4..0000000
--- a/trixy-parser/example/failing_types_generic.tri
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-struct A {}
-struct B {}
-
-enum Error {}
-
-fn execute_callback(callback: String) -> Error;
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/full.tri b/trixy-parser/example/full.tri
deleted file mode 100644
index ee30e2f..0000000
--- a/trixy-parser/example/full.tri
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-/// Prints to the output, with a newline.
-// HACK(@soispha): The stdlib Lua `print()` function has stdout as output hardcoded,
-// redirecting stdout seems too much like a hack thus we are just redefining the print function
-// to output to a controlled output. <2023-09-09>
-//fn print(input: CommandTransferValue);
-
-mod trinitrix {
- /// Language specific functions, which mirror the `trinitrix.api` namespace.
- /// That is, if you have to choose between a `std` and a `api` function choose the `std`
- /// one as it will most likely be more high-level and easier to use (as it isn't abstracted
- /// over multiple languages). Feel free to drop down to the lower level api, if you feel
- /// like that more, it should be as stable and user-oriented as the `std` functions
- mod std {}
-
- /// Debug only functions, these are effectively useless
- mod debug {
- enum UserGreet {
- Friendly,
- Angrily,
- Hastly,
- }
- struct GreetedUser {
- names: Vec,
- new: GreetedUser,
- state: UserGreet,
- }
- /// Greets the user
- fn greet(input: String) -> String;
-
- /// Returns a table of greeted users
- fn greet_multiple() -> GreetedUser;
- }
-
- /// General API to change stuff in Trinitrix
- mod api {
- /// Closes the application
- fn exit();
-
- /// Send a message to the current room
- /// The send message is interpreted literally.
- fn room_message_send(msg: String);
-
- /// Open the help pages at the first occurrence of
- /// the input string if it is Some, otherwise open
- /// the help pages at the start
- fn help(input: Option);
-
- // Register a function to be used with the Trinitrix API
- // (This function is actually implemented in the std namespace)
- /* fn register_function(function: RawFunction); */
-
- /// Function that change the UI, or UI state
- mod ui {
- /// Shows the command line
- fn command_line_show();
-
- /// Hides the command line
- fn command_line_hide();
-
- /// Go to the next plane
- fn cycle_planes();
- /// Go to the previous plane
- fn cycle_planes_rev();
-
- /// Sets the current app mode to Normal / navigation mode
- fn set_mode_normal();
- /// Sets the current app mode to Insert / editing mode
- fn set_mode_insert();
- }
-
- /// Manipulate keymappings, the mode is specified as a String build up of all mode
- /// the keymapping should be active in. The mapping works as follows:
- /// n => normal Mode
- /// c => command Mode
- /// i => insert Mode
- ///
- /// The key works in a similar matter, specifying the required keypresses to trigger the
- /// callback. For example "aba" for require the user to press "a" then "b" then "a" again
- /// to trigger the mapping. Special characters are encoded as follows:
- /// "ba" => "Ctrl+a" then "b" then "a"
- /// "" => "A" or "Shift+a"
- /// "A" => "A"
- /// " " => "Alt+a" () or "Meta+a"() (most terminals can't really differentiate between these characters)
- /// "a" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super)
- /// "" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter)
- /// "a " => "a" then a literal space (" ")
- /// "å🙂" => "å" then "🙂" (full Unicode support!)
- /// "" => escape key
- /// "" => F3 key
- /// "" => backspace key (and so forth)
- /// "" => a literal "-"
- /// "" or "" => a literal "<"
- /// "" or "" => a literal ">"
- ///
- /// The callback MUST be registered first by calling
- /// `trinitrix.api.register_function()` the returned value can than be used to
- /// set the keymap.
- mod keymaps {
- /// Add a new keymapping
- fn add(mode: String, key: String, callback: Function);
-
- /// Remove a keymapping
- ///
- /// Does nothing, if the keymapping doesn't exists
- fn remove(mode: String, key: String);
-
- /// List declared keymappings
- fn get(mode: String);
- }
-
- /// Functions only used internally within Trinitrix
- mod raw {
- /// Send an error to the default error output
- fn raise_error(input: String);
-
- /// Send output to the default output
- /// This is mainly used to display the final
- /// output of evaluated lua commands.
- fn display_output(input: String);
-
- /// Input a character without checking for possible keymaps
- /// If the current state does not expect input, this character is ignored
- /// The encoding is the same as in the `trinitrix.api.keymaps` commands
- fn send_input_unprocessed(input: String);
-
- /// This namespace is used to store some command specific data (like functions, as
- /// ensuring memory locations stay allocated in garbage collected language is hard)
- ///
- /// Treat it as an implementation detail
- mod __private {}
- }
- }
-}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/functions.tri b/trixy-parser/example/functions.tri
deleted file mode 100644
index b99b4e5..0000000
--- a/trixy-parser/example/functions.tri
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-/// Call out an outstanding person
-fn call_me_back_outstanding(callback: fn(name: String) -> String);
-
-mod one {
- /// Call out a person
- fn call_me_back(callback: fn(age: u32));
-}
-
-// Trixy is a subset of Rust
-// vim: syntax=rust cms=//%s
diff --git a/trixy-parser/example/simple.tri b/trixy-parser/example/simple.tri
deleted file mode 100644
index eff99fe..0000000
--- a/trixy-parser/example/simple.tri
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-fn print(message: CommandTransferValue);
-
-mod trinitrix {
- fn hi(name: String) -> String;
-}
-
-// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing:
-// vim: syntax=rust
diff --git a/trixy-parser/example/trinitrix_api.tri b/trixy-parser/example/trinitrix_api.tri
deleted file mode 100644
index 885e471..0000000
--- a/trixy-parser/example/trinitrix_api.tri
+++ /dev/null
@@ -1,117 +0,0 @@
-//// Prints to the output, with a newline.
-// HACK(@soispha): The stdlib Lua `print()` function has stdout as output hardcoded,
-// redirecting stdout seems too much like a hack thus we are just redefining the print function
-// to output to a controlled output. <2023-09-09>
-// This is implemented only for lua
-/* fn print(CommandTransferValue); */
-
-mod trinitrix {
- /// Language specific functions, which mirror the `trinitrix.api` namespace.
- /// That is, if you have to choose between a `std` and a `api` function choose the `std`
- /// one as it will most likely be more high-level and easier to use (as it isn't abstracted
- /// over multiple languages). Feel free to drop down to the lower level api, if you feel
- /// like that more, it should be as stable and user-oriented as the `std` functions
- mod std {}
-
- /// General API to change stuff in Trinitrix
- mod api {
- /// Closes the application
- fn exit();
-
- /// Send a message to the current room
- /// The send message is interpreted literally.
- fn room_message_send(message: String);
-
- //// Open the help pages at the first occurrence of
- //// the input string if it is Some, otherwise open
- //// the help pages at the start
- // TODO(@soispha): To be implemented <2024-03-09>
- // fn help(Option);
-
- //// Register a function to be used with the Trinitrix api
- // (This function is not actually implemented here)
- /* declare register_function: false, */
-
- /// Function that change the UI, or UI state
- mod ui {
- /// Shows the command line
- fn command_line_show();
-
- /// Hides the command line
- fn command_line_hide();
-
- /// Go to the next plane
- fn cycle_planes();
- /// Go to the previous plane
- fn cycle_planes_rev();
-
- /// Sets the current app mode to Normal / navigation mode
- fn set_mode_normal();
- /// Sets the current app mode to Insert / editing mode
- fn set_mode_insert();
- }
-
- /// Manipulate keymappings, the mode is specified as a String build up of all mode
- /// the keymapping should be active in. The mapping works as follows:
- /// n => normal Mode
- /// c => command Mode
- /// i => insert Mode
- ///
- /// The key works in a similar matter, specifying the required keypresses to trigger the
- /// callback. For example "aba" for require the user to press "a" then "b" then "a" again
- /// to trigger the mapping. Special characters are encoded as follows:
- /// "ba" => "Ctrl+a" then "b" then "a"
- /// "" => "A" or "Shift+a"
- /// "A" => "A"
- /// " " => "Alt+a" () or "Meta+a"() (most terminals can't really differentiate between these characters)
- /// "a" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super)
- /// "" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter)
- /// "a " => "a" then a literal space (" ")
- /// "å🙂" => "å" then "🙂" (full Unicode support!)
- /// "" => escape key
- /// "" => F3 key
- /// "" => backspace key (and so forth)
- /// "" => a literal "-"
- /// "" or "" => a literal "<"
- /// "" or "" => a literal ">"
- ///
- /// The callback MUST be registered first by calling
- /// `trinitrix.api.register_function()` the returned value can than be used to
- /// set the keymap.
- mod keymaps {
- /// Add a new keymapping
- fn add(mode: String, key: String, callback: fn());
-
- /// Remove a keymapping
- ///
- /// Does nothing, if the keymapping doesn't exists yet
- fn remove(mode: String, key: String);
-
- /// List declared keymappings
- fn get(mode: String);
- }
-
- /// Functions only used internally within Trinitrix
- mod raw {
- /// Send an error to the default error output
- fn raise_error(error_message: String);
-
- /// Send output to the default output
- /// This is mainly used to display the final
- /// output of evaluated lua commands.
- fn display_output(output_message: String);
-
- /// Input a character without checking for possible keymaps
- /// If the current state does not expect input, this character is ignored
- /// The encoding is the same as in the `trinitrix.api.keymaps` commands
- fn send_input_unprocessed(input: String);
-
- /// This namespace is used to store some command specific data (like functions, as
- /// ensuring memory locations stay allocated in garbage collected language is hard)
- ///
- /// Treat it as an implementation detail
- mod __private {}
- }
- }
-}
-// vim: syntax=rust
diff --git a/trixy-parser/src/bin/trixy-parser.rs b/trixy-parser/src/bin/trixy-parser.rs
deleted file mode 100644
index 3545150..0000000
--- a/trixy-parser/src/bin/trixy-parser.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-* Copyright (C) 2023 - 2024:
-* The Trinitrix Project
-*
-* This file is part of the Trixy crate for Trinitrix.
-*
-* Trixy is free software: you can redistribute it and/or modify
-* it under the terms of the Lesser GNU General Public License as
-* published by the Free Software Foundation, either version 3 of
-* the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* and the Lesser GNU General Public License along with this program.
-* If not, see .
-*/
-
-use std::{fs, path::PathBuf, process::exit};
-
-use clap::{Parser, Subcommand};
-
-use trixy_parser::{lexing::TokenStream, parse_trixy_lang};
-
-/// A helper command for the trixy-lang_parser crate
-#[derive(Parser, Debug)]
-#[clap(author, version, about, long_about = None)]
-pub struct Args {
- #[command(subcommand)]
- /// The subcommand to execute
- pub subcommand: Command,
-}
-
-#[derive(Subcommand, Debug)]
-pub enum Command {
- #[clap(value_parser)]
- /// Only replace the regex replacements in the file
- Replace {
- #[clap(value_parser)]
- /// The file containing the trixy code to replace
- file: PathBuf,
- },
-
- #[clap(value_parser)]
- /// Only try to tokenize the file
- Tokenize {
- #[clap(value_parser)]
- /// The file containing the trixy code to tokenize
- file: PathBuf,
- },
- #[clap(value_parser)]
- /// Only try to tokenize the file
- Lex {
- #[clap(value_parser)]
- /// The file containing the trixy code to tokenize
- file: PathBuf,
- },
-
- /// Check syntax, without type checking
- Parse {
- #[clap(value_parser)]
- /// The file containing the trixy code to parse
- file: PathBuf,
- },
- /// Type check
- Process {
- #[clap(value_parser)]
- /// The file containing the trixy code to process
- file: PathBuf,
- },
-
- /// Act on the file as the library would do it
- Library {
- #[clap(value_parser)]
- /// The file containing the trixy code to process
- file: PathBuf,
- },
-}
-
-pub fn main() {
- let args = Args::parse();
- match args.subcommand {
- Command::Tokenize { file } | Command::Lex { file } => {
- let input = fs::read_to_string(file).unwrap();
-
- let input_tokens = match TokenStream::lex(&input) {
- Ok(err) => err,
- Err(ok) => {
- eprintln!("{}", ok);
- exit(1);
- }
- };
-
- println!("{:#?}", input_tokens);
- }
- Command::Parse { file } => {
- let input = fs::read_to_string(file).unwrap();
-
- let input_tokens = match TokenStream::lex(&input) {
- Ok(ok) => ok,
- Err(err) => {
- eprintln!("Error while tokenizing:");
- eprintln!("{}", err);
- exit(1);
- }
- };
-
- let parsed = match input_tokens.parse_unchecked() {
- Ok(ok) => ok,
- Err(err) => {
- eprintln!("Error while doing the first (unchecked) parsing run:");
- eprintln!("{}", err);
- exit(1)
- }
- };
- println!("{:#?}", parsed);
- }
- Command::Process { file } => {
- let input = fs::read_to_string(file).unwrap();
-
- let input_tokens = match TokenStream::lex(&input) {
- Ok(ok) => ok,
- Err(err) => {
- eprintln!("Error while tokenizing:");
- eprintln!("{}", err);
- exit(1);
- }
- };
-
- let parsed = match input_tokens.parse_unchecked() {
- Ok(ok) => ok,
- Err(err) => {
- eprintln!("Error while doing the first (unchecked) parsing run:");
- eprintln!("{}", err);
- exit(1)
- }
- };
-
- let processed = match parsed.process(input) {
- Ok(ok) => ok,
- Err(err) => {
- eprintln!("Error while doing the second (checked) parsing run:");
- eprintln!("{}", err);
- exit(1)
- }
- };
- println!("{:#?}", processed);
- }
- Command::Library { file } => {
- let input = fs::read_to_string(file).unwrap();
- let parsed = parse_trixy_lang(&input).unwrap_or_else(|err| {
- eprintln!("{}", err);
- exit(1)
- });
- println!("{:#?}", parsed);
- }
-
- Command::Replace { file } => {
- let input = fs::read_to_string(file).unwrap();
- let parsed = TokenStream::replace(&input);
- println!("{}", parsed);
- }
- }
-}
diff --git a/trixy-types/.gitignore b/trixy-types/.gitignore
deleted file mode 100644
index 20c0ba9..0000000
--- a/trixy-types/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# build
-/target
-/result
-
-# This crate is a library
-Cargo.lock
diff --git a/trixy-types/Cargo.toml b/trixy-types/Cargo.toml
deleted file mode 100644
index 7c455dd..0000000
--- a/trixy-types/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2023 - 2024:
-# The Trinitrix Project
-#
-# This file is part of the Trixy crate for Trinitrix.
-#
-# Trixy is free software: you can redistribute it and/or modify
-# it under the terms of the Lesser GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# and the Lesser GNU General Public License along with this program.
-# If not, see .
-
-[package]
-name = "trixy-types"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-convert_case = "0.6.0"
-libc = "0.2.151"
-log = "0.4.20"
-proc-macro2 = "1.0.70"
-quote = "1.0.33"
-syn = { version = "2.0.41", features = ["extra-traits", "full", "parsing"] }
-thiserror = "1.0.51"