mlang_rs/lang/rustgen/
mod.rs1pub mod mapping;
4
5mod opcode;
6pub use opcode::*;
7mod serde;
8pub use serde::*;
9
10mod ext {
11 use std::{
12 io::{Error, ErrorKind, Result},
13 path::{Path, PathBuf},
14 };
15
16 use proc_macro2::TokenStream;
17 use quote::quote;
18
19 use crate::lang::{ir::Stat, rustgen::gen_opcode_mod};
20
21 use super::gen_serde_mod;
22
23 fn write_and_fmt_rs<C: AsRef<[u8]>, P: AsRef<Path>>(path: P, content: C) -> Result<()> {
24 println!("codegen({:?}):", path.as_ref());
25
26 std::fs::write(path.as_ref(), content).map_err(|err| {
27 Error::new(
28 ErrorKind::Other,
29 format!("write file {:?} error: {}", path.as_ref(), err),
30 )
31 })?;
32
33 println!(" write file ... ok");
34
35 std::process::Command::new("rustfmt")
36 .arg(path.as_ref())
37 .output()
38 .map_err(|err| {
39 Error::new(
40 ErrorKind::Other,
41 format!("run rustfmt for {:?} error: {}", path.as_ref(), err),
42 )
43 })?;
44
45 println!(" run rustfmt ... ok");
46
47 Ok(())
48 }
49
50 pub struct CodeGen {
52 with_serde: bool,
53 target: PathBuf,
54 }
55
56 impl Default for CodeGen {
57 fn default() -> Self {
58 Self {
59 with_serde: true,
60 target: Path::new("./").to_path_buf(),
61 }
62 }
63 }
64
65 impl CodeGen {
66 pub fn with_serde(mut self, on: bool) -> Self {
68 self.with_serde = on;
69 self
70 }
71
72 pub fn target(mut self, path: impl AsRef<Path>) -> Self {
74 self.target = path.as_ref().to_path_buf();
75 self
76 }
77
78 pub fn codegen(self, stats: impl AsRef<[Stat]>) -> Result<()> {
80 if !self.target.exists() {
81 std::fs::create_dir_all(&self.target)?;
82 }
83
84 let mut mods = vec![("opcode", gen_opcode_mod(stats.as_ref()))];
85
86 if self.with_serde {
87 mods.push(("serde", gen_serde_mod(stats.as_ref(), "super::opcode::")));
88 }
89
90 let mut impls = vec![];
91
92 for (name, codes) in mods {
93 let target_file = self.target.join(format!("{}.rs", name));
94
95 write_and_fmt_rs(target_file, codes.to_string())?;
96
97 let ident = name.parse::<TokenStream>().unwrap();
98
99 impls.push(quote! {
100 pub mod #ident;
101 });
102 }
103
104 let codes = quote! {
105 #(#impls)*
108 };
109
110 let target_file = self.target.join("mod.rs");
111
112 write_and_fmt_rs(target_file, codes.to_string())?;
113
114 Ok(())
115 }
116 }
117}
118
119pub use ext::*;