184 lines
5.8 KiB
Rust
184 lines
5.8 KiB
Rust
use std::fs;
|
|
use std::path::Path;
|
|
|
|
use log::info;
|
|
use pathdiff::diff_paths;
|
|
|
|
use crate::commands::ensure_tools_available;
|
|
pub use crate::config::RawOpts as Opts;
|
|
use crate::ir::*;
|
|
use crate::others::*;
|
|
use crate::utils::*;
|
|
|
|
mod commands;
|
|
mod config;
|
|
mod error;
|
|
mod generator;
|
|
mod ir;
|
|
mod markers;
|
|
mod others;
|
|
mod parser;
|
|
mod source_graph;
|
|
mod transformer;
|
|
mod utils;
|
|
use error::*;
|
|
|
|
pub fn frb_codegen(raw_opts: Opts) -> anyhow::Result<()> {
|
|
ensure_tools_available()?;
|
|
|
|
let config = config::parse(raw_opts);
|
|
info!("Picked config: {:?}", &config);
|
|
|
|
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
|
|
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
|
|
|
|
info!("Phase: Parse source code to AST");
|
|
let source_rust_content = fs::read_to_string(&config.rust_input_path)?;
|
|
let file_ast = syn::parse_file(&source_rust_content)?;
|
|
|
|
info!("Phase: Parse AST to IR");
|
|
let raw_ir_file = parser::parse(&source_rust_content, file_ast, &config.manifest_path);
|
|
|
|
info!("Phase: Transform IR");
|
|
let ir_file = transformer::transform(raw_ir_file);
|
|
|
|
info!("Phase: Generate Rust code");
|
|
let generated_rust = generator::rust::generate(
|
|
&ir_file,
|
|
&mod_from_rust_path(&config.rust_input_path, &config.rust_crate_dir),
|
|
);
|
|
fs::create_dir_all(&rust_output_dir)?;
|
|
fs::write(&config.rust_output_path, generated_rust.code)?;
|
|
|
|
info!("Phase: Generate Dart code");
|
|
let (generated_dart, needs_freezed) = generator::dart::generate(
|
|
&ir_file,
|
|
&config.dart_api_class_name(),
|
|
&config.dart_api_impl_class_name(),
|
|
&config.dart_wire_class_name(),
|
|
config
|
|
.dart_output_path_name()
|
|
.ok_or_else(|| Error::str("Invalid dart_output_path_name"))?,
|
|
);
|
|
|
|
info!("Phase: Other things");
|
|
|
|
commands::format_rust(&config.rust_output_path)?;
|
|
|
|
if !config.skip_add_mod_to_lib {
|
|
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
|
|
}
|
|
|
|
let c_struct_names = ir_file
|
|
.distinct_types(true, true)
|
|
.iter()
|
|
.filter_map(|ty| {
|
|
if let IrType::StructRef(_) = ty {
|
|
Some(ty.rust_wire_type())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
|
|
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
|
|
with_changed_file(
|
|
&config.rust_output_path,
|
|
DUMMY_WIRE_CODE_FOR_BINDGEN,
|
|
|| {
|
|
commands::bindgen_rust_to_dart(
|
|
&config.rust_crate_dir,
|
|
temp_bindgen_c_output_file
|
|
.path()
|
|
.as_os_str()
|
|
.to_str()
|
|
.unwrap(),
|
|
temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
|
|
&config.dart_wire_class_name(),
|
|
c_struct_names,
|
|
&config.llvm_path[..],
|
|
&config.llvm_compiler_opts,
|
|
)
|
|
},
|
|
)?;
|
|
|
|
let effective_func_names = [
|
|
generated_rust.extern_func_names,
|
|
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
|
|
]
|
|
.concat();
|
|
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
|
|
for output in &config.c_output_path {
|
|
fs::create_dir_all(Path::new(output).parent().unwrap())?;
|
|
fs::write(
|
|
&output,
|
|
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
|
|
)?;
|
|
}
|
|
|
|
fs::create_dir_all(&dart_output_dir)?;
|
|
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
|
|
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
|
|
&generated_dart_wire_code_raw,
|
|
&config.dart_wire_class_name(),
|
|
));
|
|
|
|
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
|
|
|
|
let generated_dart_decl_all = generated_dart.decl_code;
|
|
let generated_dart_impl_all = &generated_dart.impl_code + &generated_dart_wire;
|
|
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
|
|
let impl_import_decl = DartBasicCode {
|
|
import: format!(
|
|
"import \"{}\";",
|
|
diff_paths(dart_decl_output_path, dart_output_dir)
|
|
.unwrap()
|
|
.to_str()
|
|
.unwrap()
|
|
),
|
|
part: String::new(),
|
|
body: String::new(),
|
|
};
|
|
fs::write(
|
|
&dart_decl_output_path,
|
|
(&generated_dart.file_prelude + &generated_dart_decl_all).to_text(),
|
|
)?;
|
|
fs::write(
|
|
&config.dart_output_path,
|
|
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart_impl_all).to_text(),
|
|
)?;
|
|
} else {
|
|
fs::write(
|
|
&config.dart_output_path,
|
|
(&generated_dart.file_prelude + &generated_dart_decl_all + &generated_dart_impl_all)
|
|
.to_text(),
|
|
)?;
|
|
}
|
|
|
|
let dart_root = &config.dart_root;
|
|
if needs_freezed && config.build_runner {
|
|
let dart_root = dart_root.as_ref().ok_or_else(|| {
|
|
Error::str(
|
|
"build_runner configured to run, but Dart root could not be inferred.
|
|
Please specify --dart-root, or disable build_runner with --no-build-runner.",
|
|
)
|
|
})?;
|
|
commands::build_runner(dart_root)?;
|
|
commands::format_dart(
|
|
&config
|
|
.dart_output_freezed_path()
|
|
.ok_or_else(|| Error::str("Invalid freezed file path"))?,
|
|
config.dart_format_line_length,
|
|
)?;
|
|
}
|
|
|
|
commands::format_dart(&config.dart_output_path, config.dart_format_line_length)?;
|
|
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
|
|
commands::format_dart(dart_decl_output_path, config.dart_format_line_length)?;
|
|
}
|
|
|
|
info!("Success!");
|
|
Ok(())
|
|
}
|