1#![forbid(unsafe_code)]
2
3use std::fs::File;
4use std::io::Write;
5
6use structopt::StructOpt;
7use strum::VariantNames;
8use strum_macros::{Display, EnumString, VariantNames};
9
10mod assemblyscript;
11mod astype;
12mod cpp;
13mod doc;
14mod error;
15mod overview;
16mod pretty_writer;
17mod rust;
18mod weet;
19mod zig;
20
21pub use crate::error::*;
22
23#[derive(Debug, Copy, Clone, PartialEq, Eq, Display, EnumString, VariantNames)]
25#[strum(serialize_all = "snake_case")]
26pub enum OutputType {
27 #[strum(serialize = "assemblyscript")]
28 AssemblyScript,
29 Rust,
30 Zig,
31 Overview,
32 #[strum(serialize = "doc", serialize = "markdown")]
33 Doc,
34 Cpp,
35 Weet,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
39pub struct Config {
40 #[structopt(short, long)]
42 pub module_name: Option<String>,
43
44 #[structopt(short, long)]
46 pub output_file: Option<String>,
47
48 #[structopt()]
50 pub witx_files: Vec<String>,
51
52 #[structopt(short="t", long, possible_values=OutputType::VARIANTS)]
54 pub output_type: OutputType,
55
56 #[structopt(flatten)]
57 pub flags: Options,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 module_name: None,
64 output_file: None,
65 witx_files: vec![],
66 output_type: OutputType::Doc,
67 flags: Options {
68 skip_header: false,
69 skip_imports: false,
70 },
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
77pub struct Options {
78 #[structopt(short = "I", long)]
80 skip_imports: bool,
81
82 #[structopt(short = "H", long)]
84 skip_header: bool,
85}
86
87pub trait Generator<T: Write> {
89 fn generate(
90 &self,
91 writer: &mut T,
92 module_witx: witx::Module,
93 options: &Options,
94 ) -> Result<(), Error>;
95}
96
97fn get_generator<T: Write>(module: Option<&str>, output: OutputType) -> Box<dyn Generator<T>> {
98 let m = module.map(|v| v.to_string());
99
100 match output {
101 OutputType::AssemblyScript => Box::new(assemblyscript::AssemblyScriptGenerator::new(m)),
102 OutputType::Zig => Box::new(zig::ZigGenerator::new(m)),
103 OutputType::Rust => Box::new(rust::RustGenerator::new(m)),
104 OutputType::Overview => Box::new(overview::OverviewGenerator::new(m)),
105 OutputType::Doc => Box::new(doc::DocGenerator::new(m)),
106 OutputType::Cpp => Box::new(cpp::CppGenerator::new(m)),
107 OutputType::Weet => Box::new(weet::WeetGenerator::new(m)),
108 }
109}
110
111pub fn generate(cfg: &Config) -> Result<(), Error> {
113 let mut writer: Box<dyn Write> = match cfg.output_file.as_deref() {
117 None | Some("-") => Box::new(std::io::stdout()),
118 Some(file) => Box::new(File::create(file).unwrap()),
119 };
120
121 let mut flags = cfg.flags.clone();
122
123 for witx_file in &cfg.witx_files {
124 let witx = witx::load(witx_file).unwrap();
126
127 let generator = get_generator(cfg.module_name.as_deref(), cfg.output_type);
129
130 generator.generate(&mut writer, witx, &flags).unwrap();
132
133 flags.skip_imports = true;
135 flags.skip_header = true;
136 }
137
138 Ok(())
139}