├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── src ├── main.rs ├── parser.rs └── zig_types.rs └── truelove.png /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "zig2rs" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zig2rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✨ *zig2rs* ✨ 2 | Have you ever wanted to use two of the objectively best programming languages out there - Rust and Zig - at the same time? Has linking applications through C ABI tired you? Well then look no further, as my solution will revolutionise the world of software development! 3 | 4 | ## Why? 5 | ![Ferris the Crab and Zero the Ziguana cuddling on a raft](truelove.png) 6 | 7 | ## How? 8 | It's a small macro you can use: 9 | ```rust 10 | unsafe fn print_string(ptr: *const u8, len: usize) { 11 | let slice = std::slice::from_raw_parts(ptr, len); 12 | let string = std::str::from_utf8(slice).unwrap(); 13 | println!("{}", string); 14 | } 15 | 16 | zig2rs! { 17 | fn hello_world(times: usize) void { 18 | const message = "this is a crime"; 19 | var i: usize = 0; 20 | while (i < times) : (i += 1) { 21 | print_string(message.ptr, message.len); 22 | } 23 | } 24 | } 25 | 26 | fn main() { 27 | unsafe { 28 | hello_world(3); 29 | } 30 | } 31 | ``` 32 | You can't actually use any good features Zig has going for itself, but shhh be quiet. This example is about everything this thing can do, and anything else will anger the compiler. 33 | 34 | ## Who? 35 | hi, [I](https://github.com/natanalt) did this medium effort shitpost 36 | 37 | ## What's next? 38 | Someday I may write a proper compiler using procedural macros instead of `macro_rules!` which would allow for much greater flexibility, lack of which is why this macro is so limited 39 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod parser; 2 | mod zig_types; 3 | 4 | #[allow(unused_imports)] 5 | use parser::*; 6 | #[allow(unused_imports)] 7 | use zig_types::*; 8 | 9 | unsafe fn print_string(ptr: *const u8, len: usize) { 10 | let slice = std::slice::from_raw_parts(ptr, len); 11 | let string = std::str::from_utf8(slice).unwrap(); 12 | println!("{}", string); 13 | } 14 | 15 | zig2rs! { 16 | fn hello_world(times: usize) void { 17 | const message = "this is a crime"; 18 | var i: usize = 0; 19 | while (i < times) : (i += 1) { 20 | print_string(message.ptr, message.len); 21 | } 22 | } 23 | } 24 | 25 | fn main() { 26 | unsafe { 27 | hello_world(3); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_export] 3 | macro_rules! zig2rs { 4 | () => {}; 5 | ($($code:tt)*) => { 6 | zig2rs_parser_core! { 7 | $($code)* 8 | } 9 | }; 10 | } 11 | 12 | #[macro_export] 13 | macro_rules! zig2rs_parser_core { 14 | () => { 15 | compile_error!("ended up with empty parser core input") 16 | }; 17 | 18 | // Function declaration 19 | ( 20 | // TODO: fix type parsing to allow more than 1 identifier 21 | // it takes a single identifier to prevent weird errors 22 | // it should in fact take entire *expressions* but for that 23 | // I'd definitely need a proc-macro-based compiler, as Rust 24 | // isn't capable of this magic lmao 25 | // 26 | // in general, most of the language should be implemented in 27 | // proc macros, as this is very not enough 28 | 29 | fn $fname:ident ( 30 | $( $pname:ident : $ptype_raw:ident $(,)? )* 31 | ) $fret:ident { 32 | $( $body:tt )* 33 | } 34 | 35 | $($tail:tt)* 36 | ) => { 37 | unsafe fn $fname ( 38 | $( $pname : zig2rs_parse_type!{ $ptype_raw } )* 39 | ) -> zig2rs_parse_type!{ $fret } { 40 | zig2rs_emit_scope! { 41 | $($body)* 42 | } 43 | } 44 | }; 45 | } 46 | 47 | #[macro_export] 48 | macro_rules! zig2rs_parse_type { 49 | (void) => { () }; 50 | (usize) => { usize }; 51 | } 52 | 53 | #[macro_export] 54 | macro_rules! zig2rs_emit_scope { 55 | ($($body:tt)*) => { 56 | { 57 | zig2rs_emit_scope_impl! { 58 | $($body)* 59 | __break_line__ 60 | } 61 | } 62 | }; 63 | } 64 | 65 | #[macro_export] 66 | macro_rules! zig2rs_emit_scope_impl { 67 | ( 68 | __break_line__ 69 | $($processed:tt)* 70 | ) => { 71 | $($processed)* 72 | }; 73 | 74 | // Constant creating 75 | ( 76 | const $vname:ident $(: $vtype:ident)? = $vvalue:expr; 77 | $($tail:tt)* 78 | ) => { 79 | zig2rs_emit_scope_impl! { 80 | $($tail)* 81 | let $vname $(:$vtype)? = ($vvalue).zigify(); 82 | } 83 | }; 84 | 85 | // Varaible creating 86 | ( 87 | var $vname:ident $(: $vtype:ident)? = $vvalue:expr; 88 | $($tail:tt)* 89 | ) => { 90 | zig2rs_emit_scope_impl! { 91 | $($tail)* 92 | let mut $vname $(:$vtype)? = ($vvalue).zigify(); 93 | } 94 | }; 95 | 96 | // Function call creating 97 | ( 98 | $fname:ident ( $($inner:tt)* ); 99 | $($tail:tt)* 100 | ) => { 101 | zig2rs_emit_scope_impl! { 102 | $($tail)* 103 | $fname($($inner)*); 104 | } 105 | }; 106 | 107 | // While loops 108 | ( 109 | while ($condition:expr) : ($($continuation:tt)*) { 110 | $($body:tt)* 111 | } 112 | $($tail:tt)* 113 | ) => { 114 | zig2rs_emit_scope_impl! { 115 | $($tail)* 116 | while $condition { 117 | zig2rs_emit_scope! { $($body)* } 118 | $($continuation)*; 119 | } 120 | } 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /src/zig_types.rs: -------------------------------------------------------------------------------- 1 | 2 | pub struct ZigConstSlice { 3 | pub ptr: *const T, 4 | pub len: usize, 5 | } 6 | 7 | impl ZigConstSlice { 8 | pub const fn from_string(s: &'static str) -> Self { 9 | Self { 10 | ptr: s.as_ptr(), 11 | len: s.len(), 12 | } 13 | } 14 | } 15 | 16 | pub trait ZigToString { 17 | fn zigify(self) -> ZigConstSlice; 18 | } 19 | 20 | impl ZigToString for &'static str { 21 | fn zigify(self) -> ZigConstSlice { 22 | ZigConstSlice::::from_string(self) 23 | } 24 | } 25 | 26 | pub trait ZigToUSize { 27 | fn zigify(self) -> usize; 28 | } 29 | 30 | impl ZigToUSize for usize { 31 | fn zigify(self) -> usize { 32 | self 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /truelove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanalt/zig2rs/733d1e070b2d5dc0f3d4fcb13691de9a80b28974/truelove.png --------------------------------------------------------------------------------