<commit_before>use std::{borrow, io, option};

use syntax::abi;
use syntax::ast;
use syntax::codemap::{dummy_sp, dummy_spanned, ExpnInfo, NameAndSpan};
use syntax::ast_util::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::print::pprust;
use syntax::opt_vec;

use types::*;

struct GenCtx {
    ext_cx: @base::ExtCtxt,
    unnamed_ty: uint,
    abis: abi::AbiSet
}

fn empty_generics() -> ast::Generics {
    ast::Generics {
        lifetimes: opt_vec::Empty,
        ty_params: opt_vec::Empty
    }
}

fn rust_id(ctx: &mut GenCtx, name: ~str) -> (~str, bool) {
    let token = parse::token::IDENT(ctx.ext_cx.ident_of(name), false);
    if parse::token::is_any_keyword(&token) || "bool" == name {
        (~"_" + name, true)
    } else {
        (name, false)
    }

}

fn rust_type_id(ctx: &mut GenCtx, name: ~str) -> ~str {
    if "bool" == name ||
        "uint" == name ||
        "u8" == name ||
        "u16" == name ||
        "u32" == name ||
        "f32" == name ||
        "f64" == name ||
        "i8" == name ||
        "i16" == name ||
        "i32" == name ||
        "i64" == name ||
        "Self" == name ||
        "str" == name {
        ~"_" + name
    } else {
        let (n, _) = rust_id(ctx, name);
        n
    }
}

fn unnamed_name(ctx: &mut GenCtx, name: ~str) -> ~str {
    return if name.is_empty() {
        ctx.unnamed_ty += 1;
        fmt!("Unnamed%u", ctx.unnamed_ty)
    } else {
        name
    };
}

fn struct_name(name: ~str) -> ~str {
    fmt!("Struct_%s", name)
}

fn union_name(name: ~str) -> ~str {
    fmt!("Union_%s", name)
}

fn enum_name(name: ~str) -> ~str {
    fmt!("Enum_%s", name)
}

pub fn gen_rs(out: @io::Writer, abi: ~str, link: &Option<~str>, globs: &[Global]) {
    let abis = match abi {
        ~"cdecl" => abi::AbiSet::from(abi::Cdecl),
        ~"stdcall" => abi::AbiSet::from(abi::Stdcall),
        ~"fastcall" => abi::AbiSet::from(abi::Fastcall),
        ~"aapcs" => abi::AbiSet::from(abi::Aapcs),
        ~"Rust" => abi::AbiSet::Rust(),
        ~"rust-intrinsic" => abi::AbiSet::Intrinsic(),
        _ => abi::AbiSet::C()
    };

    let mut ctx = GenCtx { ext_cx: base::ExtCtxt::new(parse::new_parse_sess(None), ~[]),
                           unnamed_ty: 0,
                           abis: abis
                         };
    ctx.ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan { name: @"", span: None }
    });
    let uniq_globs = tag_dup_decl(globs);

    let mut fs = ~[];
    let mut vs = ~[];
    let mut gs = ~[];
    uniq_globs.iter().advance(|g| {
        match *g {
            GOther => {}
            GFunc(_) => fs.push(*g),
            GVar(_) => vs.push(*g),
            _ => gs.push(*g)
        }
        true
    });

    let mut defs = ~[];
    gs = remove_redundent_decl(gs);

    gs.iter().advance(|g| {
        match *g {
            GType(ti) => defs.push_all(ctypedef_to_rs(&mut ctx, ti.name.clone(), ti.ty)),
            GCompDecl(ci) => {
                ci.name = unnamed_name(&mut ctx, ci.name.clone());
                if ci.cstruct {
                    defs.push_all(ctypedef_to_rs(&mut ctx, struct_name(ci.name.clone()), @TVoid))
                } else {
                    defs.push_all(ctypedef_to_rs(&mut ctx, union_name(ci.name.clone()), @TVoid))
                }
            },
            GComp(ci) => {
                ci.name = unnamed_name(&mut ctx, ci.name.clone());
                if ci.cstruct {
                    defs.push(cstruct_to_rs(&mut ctx, struct_name(ci.name.clone()),
                                            ci.fields.clone()))
                } else {
                    defs.push_all(cunion_to_rs(&mut ctx, union_name(ci.name.clone()),
                                               ci.fields.clone()))
                }
            },
            GEnumDecl(ei) => {
                ei.name = unnamed_name(&mut ctx, ei.name.clone());
                defs.push_all(ctypedef_to_rs(&mut ctx, enum_name(ei.name.clone()), @TVoid))
            },
            GEnum(ei) => {
                ei.name = unnamed_name(&mut ctx, ei.name.clone());
                defs.push_all(cenum_to_rs(&mut ctx, enum_name(ei.name.clone()), ei.items.clone(),
                                          ei.kind))
            },
            _ => { }
        }
        true
    });

    let vars = do vs.map |v| {
        match *v {
            GVar(vi) => cvar_to_rs(&mut ctx, vi.name.clone(), vi.ty, vi.is_const),
            _ => { fail!(~"generate global variables") }
        }
    };

    let funcs = do fs.map |f| {
        match *f {
            GFunc(vi) => {
                match *vi.ty {
                    TFunc(rty, ref aty, var) => cfunc_to_rs(&mut ctx, vi.name.clone(),
                                                             rty, (*aty).clone(), var),
                    _ => { fail!(~"generate functions") }
                }
            },
            _ => { fail!(~"generate functions") }
        }
    };

    let views = ~[mk_import(&mut ctx, &[~"std", ~"libc"])];
    defs.push(mk_extern(&mut ctx, link, vars, funcs));

    let crate = ast::Crate {
        module: ast::_mod {
            view_items: views,
            items: defs,
        },
        attrs: ~[],
        config: ~[],
        span: dummy_sp()
    };

    let ps = pprust::rust_printer(out, parse::token::get_ident_interner());
    out.write_line("/* automatically generated by rust-bindgen */\n");
    pprust::print_crate_(ps, &crate);
}

fn mk_import(ctx: &mut GenCtx, path: &[~str]) -> ast::view_item {
    let view = ast::view_item_use(~[
        @dummy_spanned(
            ast::view_path_glob(
                ast::Path {
                    span: dummy_sp(),
                    global: false,
                    segments: path.map(|p|
                        ast::PathSegment {
                            identifier: ctx.ext_cx.ident_of((*p).clone()),
                            lifetime: None,
                            types: opt_vec::Empty
                        }
                    )
                },
                ast::DUMMY_NODE_ID
            )
        )
    ]);

    return ast::view_item {
              node: view,
              attrs: ~[],
              vis: ast::inherited,
              span: dummy_sp()
           };
}

fn mk_extern(ctx: &mut GenCtx, link: &Option<~str>,
                           vars: ~[@ast::foreign_item],
                           funcs: ~[@ast::foreign_item]) -> @ast::item {
    let attrs;
    match *link {
        None => attrs = ~[],
        Some(ref l) => {
            let link_args = dummy_spanned(ast::Attribute_ {
                style: ast::AttrOuter,
                value: @dummy_spanned(
                    ast::MetaNameValue(
                        @"link_args",
                        dummy_spanned(ast::lit_str((~"-l" + *l).to_managed(), ast::CookedStr))
                    )
                ),
                is_sugared_doc: false
            });
            attrs = ~[link_args];
        }
    }

    let ext = ast::item_foreign_mod(ast::foreign_mod {
        sort: ast::anonymous,
        abis: ctx.abis,
        view_items: ~[],
        items: vars + funcs
    });

    return @ast::item {
              ident: ctx.ext_cx.ident_of(""),
              attrs: attrs,
              id: ast::DUMMY_NODE_ID,
              node: ext,
              vis: ast::public,
              span: dummy_sp()
           };
}

fn remove_redundent_decl(gs: &[Global]) -> ~[Global] {
    fn check_decl(a: Global, b: Global) -> bool {
        match (a, b) {
          (GComp(ci1), GType(ti)) => match *ti.ty {
              TComp(ci2) => {
                  let n = ci1.name.clone();
                  borrow::ref_eq(ci1, ci2) && n.is_empty()
              },
              _ => false
          },
          (GEnum(ei1), GType(ti)) => match *ti.ty {
              TEnum(ei2) => {
                  let n = ei1.name.clone();
                  borrow::ref_eq(ei1, ei2) && n.is_empty()
              },
              _ => false<commit_msg>update for ast::foreign_mod change<commit_after>use std::{borrow, io, option};

use syntax::abi;
use syntax::ast;
use syntax::codemap::{dummy_sp, dummy_spanned, ExpnInfo, NameAndSpan};
use syntax::ast_util::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::print::pprust;
use syntax::opt_vec;

use types::*;

struct GenCtx {
    ext_cx: @base::ExtCtxt,
    unnamed_ty: uint,
    abis: abi::AbiSet
}

fn empty_generics() -> ast::Generics {
    ast::Generics {
        lifetimes: opt_vec::Empty,
        ty_params: opt_vec::Empty
    }
}

fn rust_id(ctx: &mut GenCtx, name: ~str) -> (~str, bool) {
    let token = parse::token::IDENT(ctx.ext_cx.ident_of(name), false);
    if parse::token::is_any_keyword(&token) || "bool" == name {
        (~"_" + name, true)
    } else {
        (name, false)
    }

}

fn rust_type_id(ctx: &mut GenCtx, name: ~str) -> ~str {
    if "bool" == name ||
        "uint" == name ||
        "u8" == name ||
        "u16" == name ||
        "u32" == name ||
        "f32" == name ||
        "f64" == name ||
        "i8" == name ||
        "i16" == name ||
        "i32" == name ||
        "i64" == name ||
        "Self" == name ||
        "str" == name {
        ~"_" + name
    } else {
        let (n, _) = rust_id(ctx, name);
        n
    }
}

fn unnamed_name(ctx: &mut GenCtx, name: ~str) -> ~str {
    return if name.is_empty() {
        ctx.unnamed_ty += 1;
        fmt!("Unnamed%u", ctx.unnamed_ty)
    } else {
        name
    };
}

fn struct_name(name: ~str) -> ~str {
    fmt!("Struct_%s", name)
}

fn union_name(name: ~str) -> ~str {
    fmt!("Union_%s", name)
}

fn enum_name(name: ~str) -> ~str {
    fmt!("Enum_%s", name)
}

pub fn gen_rs(out: @io::Writer, abi: ~str, link: &Option<~str>, globs: &[Global]) {
    let abis = match abi {
        ~"cdecl" => abi::AbiSet::from(abi::Cdecl),
        ~"stdcall" => abi::AbiSet::from(abi::Stdcall),
        ~"fastcall" => abi::AbiSet::from(abi::Fastcall),
        ~"aapcs" => abi::AbiSet::from(abi::Aapcs),
        ~"Rust" => abi::AbiSet::Rust(),
        ~"rust-intrinsic" => abi::AbiSet::Intrinsic(),
        _ => abi::AbiSet::C()
    };

    let mut ctx = GenCtx { ext_cx: base::ExtCtxt::new(parse::new_parse_sess(None), ~[]),
                           unnamed_ty: 0,
                           abis: abis
                         };
    ctx.ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan { name: @"", span: None }
    });
    let uniq_globs = tag_dup_decl(globs);

    let mut fs = ~[];
    let mut vs = ~[];
    let mut gs = ~[];
    uniq_globs.iter().advance(|g| {
        match *g {
            GOther => {}
            GFunc(_) => fs.push(*g),
            GVar(_) => vs.push(*g),
            _ => gs.push(*g)
        }
        true
    });

    let mut defs = ~[];
    gs = remove_redundent_decl(gs);

    gs.iter().advance(|g| {
        match *g {
            GType(ti) => defs.push_all(ctypedef_to_rs(&mut ctx, ti.name.clone(), ti.ty)),
            GCompDecl(ci) => {
                ci.name = unnamed_name(&mut ctx, ci.name.clone());
                if ci.cstruct {
                    defs.push_all(ctypedef_to_rs(&mut ctx, struct_name(ci.name.clone()), @TVoid))
                } else {
                    defs.push_all(ctypedef_to_rs(&mut ctx, union_name(ci.name.clone()), @TVoid))
                }
            },
            GComp(ci) => {
                ci.name = unnamed_name(&mut ctx, ci.name.clone());
                if ci.cstruct {
                    defs.push(cstruct_to_rs(&mut ctx, struct_name(ci.name.clone()),
                                            ci.fields.clone()))
                } else {
                    defs.push_all(cunion_to_rs(&mut ctx, union_name(ci.name.clone()),
                                               ci.fields.clone()))
                }
            },
            GEnumDecl(ei) => {
                ei.name = unnamed_name(&mut ctx, ei.name.clone());
                defs.push_all(ctypedef_to_rs(&mut ctx, enum_name(ei.name.clone()), @TVoid))
            },
            GEnum(ei) => {
                ei.name = unnamed_name(&mut ctx, ei.name.clone());
                defs.push_all(cenum_to_rs(&mut ctx, enum_name(ei.name.clone()), ei.items.clone(),
                                          ei.kind))
            },
            _ => { }
        }
        true
    });

    let vars = do vs.map |v| {
        match *v {
            GVar(vi) => cvar_to_rs(&mut ctx, vi.name.clone(), vi.ty, vi.is_const),
            _ => { fail!(~"generate global variables") }
        }
    };

    let funcs = do fs.map |f| {
        match *f {
            GFunc(vi) => {
                match *vi.ty {
                    TFunc(rty, ref aty, var) => cfunc_to_rs(&mut ctx, vi.name.clone(),
                                                             rty, (*aty).clone(), var),
                    _ => { fail!(~"generate functions") }
                }
            },
            _ => { fail!(~"generate functions") }
        }
    };

    let views = ~[mk_import(&mut ctx, &[~"std", ~"libc"])];
    defs.push(mk_extern(&mut ctx, link, vars, funcs));

    let crate = ast::Crate {
        module: ast::_mod {
            view_items: views,
            items: defs,
        },
        attrs: ~[],
        config: ~[],
        span: dummy_sp()
    };

    let ps = pprust::rust_printer(out, parse::token::get_ident_interner());
    out.write_line("/* automatically generated by rust-bindgen */\n");
    pprust::print_crate_(ps, &crate);
}

fn mk_import(ctx: &mut GenCtx, path: &[~str]) -> ast::view_item {
    let view = ast::view_item_use(~[
        @dummy_spanned(
            ast::view_path_glob(
                ast::Path {
                    span: dummy_sp(),
                    global: false,
                    segments: path.map(|p|
                        ast::PathSegment {
                            identifier: ctx.ext_cx.ident_of((*p).clone()),
                            lifetime: None,
                            types: opt_vec::Empty
                        }
                    )
                },
                ast::DUMMY_NODE_ID
            )
        )
    ]);

    return ast::view_item {
              node: view,
              attrs: ~[],
              vis: ast::inherited,
              span: dummy_sp()
           };
}

fn mk_extern(ctx: &mut GenCtx, link: &Option<~str>,
                           vars: ~[@ast::foreign_item],
                           funcs: ~[@ast::foreign_item]) -> @ast::item {
    let attrs;
    match *link {
        None => attrs = ~[],
        Some(ref l) => {
            let link_args = dummy_spanned(ast::Attribute_ {
                style: ast::AttrOuter,
                value: @dummy_spanned(
                    ast::MetaNameValue(
                        @"link_args",
                        dummy_spanned(ast::lit_str((~"-l" + *l).to_managed(), ast::CookedStr))
                    )
                ),
                is_sugared_doc: false
            });
            attrs = ~[link_args];
        }
    }

    let ext = ast::item_foreign_mod(ast::foreign_mod {
        abis: ctx.abis,
        view_items: ~[],
        items: vars + funcs
    });

    return @ast::item {
              ident: ctx.ext_cx.ident_of(""),
              attrs: attrs,
              id: ast::DUMMY_NODE_ID,
              node: ext,
              vis: ast::public,
              span: dummy_sp()
           };
}

fn remove_redundent_decl(gs: &[Global]) -> ~[Global] {
    fn check_decl(a: Global, b: Global) -> bool {
        match (a, b) {
          (GComp(ci1), GType(ti)) => match *ti.ty {
              TComp(ci2) => {
                  let n = ci1.name.clone();
                  borrow::ref_eq(ci1, ci2) && n.is_empty()
              },
              _ => false
          },
          (GEnum(ei1), GType(ti)) => match *ti.ty {
              TEnum(ei2) => {
                  let n = ei1.name.clone();
                  borrow::ref_eq(ei1, ei2) && n.is_empty()
              },
              _ => false
{'fraction_non_alphanumeric': 0.1625069672384963, 'fraction_numerical': 0.003468136495943519, 'mean_word_length': 1.4759276295614843, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6102660', 'n_tokens_mistral': 5408, 'n_tokens_neox': 5264, 'n_words': 960}