Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions c2rust-ast-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,17 @@ impl Builder {
)))
}

/// A convenience function for calling multiple methods in a chain.
pub fn method_chain_expr(
self,
expr: Box<Expr>,
calls: Vec<(PathSegment, Vec<Box<Expr>>)>,
) -> Box<Expr> {
calls.into_iter().fold(expr, |expr, (seg, args)| {
mk().method_call_expr(expr, seg, args)
})
}

pub fn tuple_expr(self, exprs: Vec<Box<Expr>>) -> Box<Expr> {
Box::new(Expr::Tuple(ExprTuple {
attrs: self.attrs,
Expand Down Expand Up @@ -2088,17 +2099,11 @@ impl Builder {
self,
capture: CaptureBy,
mov: Movability,
decl: FnDecl,
inputs: Vec<Pat>,
output: ReturnType,
body: Box<Expr>,
) -> Box<Expr> {
let (_name, inputs, _variadic, output) = decl;
let inputs = inputs
.into_iter()
.map(|e| match e {
FnArg::Receiver(_s) => panic!("found 'self' in closure arguments"),
FnArg::Typed(PatType { pat, .. }) => *pat,
})
.collect();
let inputs = inputs.into_iter().collect();
let capture = match capture {
CaptureBy::Ref => None,
CaptureBy::Value => Some(Default::default()),
Expand Down
2 changes: 1 addition & 1 deletion c2rust-ast-builder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
mod builder;
pub use crate::builder::{mk, properties, Builder, Make};
pub use crate::builder::{mk, properties, Builder, CaptureBy, Make};
127 changes: 89 additions & 38 deletions c2rust-transpile/src/translator/main_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! Rust.

use super::*;
use c2rust_ast_builder::CaptureBy;
use failure::format_err;
use proc_macro2::{TokenStream, TokenTree};

Expand Down Expand Up @@ -53,45 +54,96 @@ impl<'c> Translation<'c> {
if n >= 2 {
// `argv` and `argc`

stmts.push(mk().local_stmt(Box::new(mk().local(
mk().mutbl().ident_pat("args"),
Some(mk().path_ty(vec![mk().path_segment_with_args(
stmts.push(mk().local_stmt(Box::new({
// Vec<Vec<u8>>
let ty = mk().path_ty(vec![mk().path_segment_with_args(
"Vec",
mk().angle_bracketed_args(vec![
mk().mutbl().ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])),
]),
)])),
Some(mk().call_expr(mk().path_expr(vec!["Vec", "new"]), vec![])),
))));
stmts.push(mk().semi_stmt(mk().for_expr(
mk().ident_pat("arg"),
mk().call_expr(args_fn, vec![]),
mk().block(vec![mk().semi_stmt(mk().method_call_expr(
mk().path_expr(vec!["args"]),
"push",
vec![mk().method_call_expr(
mk().method_call_expr(
mk().call_expr(
// TODO(kkysen) change `"std"` to `"alloc"` after `#![feature(alloc_c_string)]` is stabilized in `1.63.0`
mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]),
vec![mk().path_expr(vec!["arg"])],
),
"expect",
vec![mk().lit_expr("Failed to convert argument into CString.")],
),
"into_raw",
mk().angle_bracketed_args(vec![mk().path_ty(vec![mk()
.path_segment_with_args(
"Vec",
mk().angle_bracketed_args(vec![mk().ident_ty("u8")]),
)])]),
)]);
// |arg| {
// (::std::ffi::CString::new(arg))
// .expect("Failed to convert argument into CString.")
// .into_bytes_with_nul()
// }
let cstring_call = mk().call_expr(
mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]),
vec![mk().path_expr(vec!["arg"])],
);
let expect_arg = mk().lit_expr("Failed to convert argument into CString.");
let map_arg = mk().closure_expr(
CaptureBy::Ref,
Movability::Movable,
vec![mk().ident_pat("arg")],
ReturnType::Default,
mk().method_chain_expr(
cstring_call,
vec![
(mk().path_segment("expect"), vec![expect_arg]),
(mk().path_segment("into_bytes_with_nul"), vec![]),
],
),
);
// (args_fn)
// .map(map_arg)
// .collect();
let init = mk().method_chain_expr(
mk().call_expr(args_fn, vec![]),
vec![
(mk().path_segment("map"), vec![map_arg]),
(mk().path_segment("collect"), vec![]),
],
);
mk().local(mk().mutbl().ident_pat("args_strings"), Some(ty), Some(init))
})));

stmts.push(mk().local_stmt(Box::new({
// Vec<*mut ::core::ffi::c_char>
let ty = mk().path_ty(vec![mk().path_segment_with_args(
"Vec",
mk().angle_bracketed_args(vec![mk()
.mutbl()
.ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"]))]),
)]);
// |arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char
let map_arg = mk().closure_expr(
CaptureBy::Ref,
Movability::Movable,
vec![mk().ident_pat("arg")],
ReturnType::Default,
mk().cast_expr(
mk().method_call_expr(mk().ident_expr("arg"), "as_mut_ptr", vec![]),
mk().mutbl()
.ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])),
),
);
// ::core::iter::once(::core::ptr::null_mut())
let chain_arg = mk().call_expr(
mk().abs_path_expr(vec!["core", "iter", "once"]),
vec![mk().call_expr(
mk().abs_path_expr(vec!["core", "ptr", "null_mut"]),
vec![],
)],
))]),
None::<Ident>,
)));
stmts.push(mk().semi_stmt(mk().method_call_expr(
mk().path_expr(vec!["args"]),
"push",
vec![
mk().call_expr(mk().abs_path_expr(vec!["core", "ptr", "null_mut"]), vec![]),
],
)));
);
// args_strings
// .iter_mut()
// .map(map_arg)
// .chain(chain_arg)
// .collect()
let init = mk().method_chain_expr(
mk().ident_expr("args_strings"),
vec![
(mk().path_segment("iter_mut"), vec![]),
(mk().path_segment("map"), vec![map_arg]),
(mk().path_segment("chain"), vec![chain_arg]),
(mk().path_segment("collect"), vec![]),
],
);
mk().local(mk().mutbl().ident_pat("args_ptrs"), Some(ty), Some(init))
})));

let argc_ty: Box<Type> = match self.ast_context.index(parameters[0]).kind {
CDeclKind::Variable { ref typ, .. } => self.convert_type(typ.ctype),
Expand All @@ -105,8 +157,7 @@ impl<'c> Translation<'c> {
"Cannot find type of 'argv' argument in main function",
)),
}?;

let args = mk().ident_expr("args");
let args = mk().ident_expr("args_ptrs");
let argc = mk().binary_expr(
BinOp::Sub(Default::default()),
mk().method_call_expr(args.clone(), "len", no_args.clone()),
Expand Down
3 changes: 3 additions & 0 deletions c2rust-transpile/tests/snapshots/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int main(int argc, char **argv, char **envp) {
return 0;
}
51 changes: 51 additions & 0 deletions c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
source: c2rust-transpile/tests/snapshots.rs
expression: cat tests/snapshots/main.rs
input_file: c2rust-transpile/tests/snapshots/main.c
---
#![allow(
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut
)]
unsafe fn main_0(
mut argc: ::core::ffi::c_int,
mut argv: *mut *mut ::core::ffi::c_char,
mut envp: *mut *mut ::core::ffi::c_char,
) -> ::core::ffi::c_int {
return 0 as ::core::ffi::c_int;
}
pub fn main() {
let mut args_strings: Vec<Vec<u8>> = ::std::env::args()
.map(|arg| {
::std::ffi::CString::new(arg)
.expect("Failed to convert argument into CString.")
.into_bytes_with_nul()
})
.collect();
let mut args_ptrs: Vec<*mut ::core::ffi::c_char> = args_strings
.iter_mut()
.map(|arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char)
.chain(::core::iter::once(::core::ptr::null_mut()))
.collect();
let mut vars: Vec<*mut ::core::ffi::c_char> = Vec::new();
for (var_name, var_value) in ::std::env::vars() {
let var: String = format!("{}={}", var_name, var_value);
vars.push(
::std::ffi::CString::new(var)
.expect("Failed to convert environment variable into CString.")
.into_raw(),
);
}
vars.push(::core::ptr::null_mut());
unsafe {
::std::process::exit(main_0(
(args_ptrs.len() - 1) as ::core::ffi::c_int,
args_ptrs.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
vars.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
) as i32)
}
}