<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer,
                  Repr, Type};
use bindgen::library::Library;
use bindgen::mangle;
use bindgen::monomorph::Monomorphs;
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::{find_first_some, IterHelpers};
use bindgen::writer::{ListType, Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Struct {
    pub name: String,
    pub generic_params: GenericParams,
    pub fields: Vec<(String, Type, Documentation)>,
    pub is_tagged: bool,
    pub tuple_struct: bool,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Struct {
    pub fn load(item: &syn::ItemStruct, mod_cfg: &Option<Cfg>) -> Result<Struct, String> {
        if Repr::load(&item.attrs)? != Repr::C {
            return Err("Struct is not marked #[repr(C)].".to_owned());
        }

        let (fields, tuple_struct) = match &item.fields {
            &syn::Fields::Unit => (Vec::new(), false),
            &syn::Fields::Named(ref fields) => {
                let out = fields.named.iter().try_skip_map(|x| x.as_ident_and_type())?;
                (out, false)
            }
            &syn::Fields::Unnamed(ref fields) => {
                let mut out = Vec::new();
                let mut current = 0;
                for field in fields.unnamed.iter() {
                    if let Some(x) = Type::load(&field.ty)? {
                        out.push((format!("{}", current), x, Documentation::load(&field.attrs)));
                        current += 1;
                    }
                }
                (out, true)
            }
        };

        Ok(Struct {
            name: item.ident.to_string(),
            generic_params: GenericParams::new(&item.generics),
            fields: fields,
            is_tagged: false,
            tuple_struct: tuple_struct,
            cfg: Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            annotations: AnnotationSet::load(&item.attrs)?,
            documentation: Documentation::load(&item.attrs),
        })
    }

    pub fn simplify_option_to_ptr(&mut self) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.simplify_option_to_ptr();
        }
    }

    pub fn is_generic(&self) -> bool {
        self.generic_params.len() > 0
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        // Generic structs can instantiate monomorphs only once they've been
        // instantiated. See `instantiate_monomorph` for more details.
        if self.is_generic() {
            return;
        }

        for &(_, ref ty, _) in &self.fields {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Item for Struct {
    fn name(&self) -> &str {
        &self.name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Struct(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.name);
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.rename_for_config(config);
        }

        let field_rules = [
            self.annotations.parse_atom::<RenameRule>("rename-all"),
            config.structure.rename_fields,
        ];

        let mut names = self.fields.iter_mut().map(|field| &mut field.0);

        if let Some(o) = self.annotations.list("field-names") {
            for (dest, src) in names.zip(o) {
                *dest = src;
            }
        } else if let Some(r) = find_first_some(&field_rules) {
            for name in names {
                *name = r.apply_to_snake_case(name, IdentifierType::StructMember);
            }
        } else if self.tuple_struct {
            // If there is a tag field, skip it
            if self.is_tagged {
                names.next();
            }

            // If we don't have any rules for a tuple struct, prefix them with
            // an underscore so it still compiles
            for name in names {
                name.insert(0, '_');
            }
        }
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        let mut fields = self.fields.iter();

        // If there is a tag field, skip it
        if self.is_tagged {
            fields.next();
        }

        for &(_, ref ty, _) in fields {
            ty.add_dependencies_ignoring_generics(&self.generic_params, library, out);
        }
    }

    fn instantiate_monomorph(
        &self,
        generic_values: &Vec<Type>,
        library: &Library,
        out: &mut Monomorphs,
    ) {
        assert!(self.generic_params.len() > 0 && self.generic_params.len() == generic_values.len());

        let mappings = self.generic_params
            .iter()
            .zip(generic_values.iter())
            .collect::<Vec<_>>();

        let monomorph = Struct {
            name: mangle::mangle_path(&self.name, generic_values),
            generic_params: GenericParams::default(),
            fields: self.fields
                .iter()
                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                .collect(),
            is_tagged: self.is_tagged,
            tuple_struct: self.tuple_struct,
            cfg: self.cfg.clone(),
            annotations: self.annotations.clone(),
            documentation: self.documentation.clone(),
        };

        // Instantiate any monomorphs for any generic paths we may have just created.
        monomorph.add_monomorphs(library, out);

        out.insert_struct(self, monomorph, generic_values.clone());
    }
}

impl Source for Struct {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        self.cfg.write_before(config, out);

        self.documentation.write(config, out);

        self.generic_params.write(config, out);

        if config.language == Language::C {
            out.write("typedef struct");
        } else {
            write!(out, "struct {}", self.name);
        }
        out.open_brace();

        if config.documentation {
            out.write_vertical_source_list(&self.fields, ListType::Cap(";"));
        } else {
            out.write_vertical_source_list(
                &self.fields
                    .iter()
                    .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone()))
                    .collect(),
                ListType::Cap(";"),
            );
        }

        if config.language == Language::Cxx {
            let mut wrote_start_newline = false;

            if config.structure.derive_constructor(&self.annotations) && !self.fields.is_empty() {
                if !wrote_start_newline {
                    wrote_start_newline = true;
                    out.new_line();
                }

                out.new_line();

                let arg_renamer = |name: &str| {
                    config
                        .function
                        .rename_args
                        .as_ref()
                        .unwrap_or(&RenameRule::GeckoCase)
                        .apply_to_snake_case(name, IdentifierType::FunctionArg)
                };
                write!(out, "{}(", self.name);
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|&(ref name, ref ty, _)| {
                            // const-ref args to constructor
                            (format!("const& {}", arg_renamer(name)), ty.clone())
                        })
                        .collect(),
                    ListType::Join(","),
                );
                write!(out, ")");
                out.new_line();
                write!(out, "  : ");
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|x| format!("{}({})", x.0, arg_renamer(&x.0)))
                        .collect(),
                    ListType::Join(","),
                );
                out.new_line();
                write!(out, "{{}}");
                out.new_line();
            }

            let other = if let Some(r) = config.function.rename_args {
                r.apply_to_snake_case("other", IdentifierType::FunctionArg)
            } else {
                String::from("other")
            };

            let mut emit_op = |op, conjuc| {
                if !wrote_start_newline {
                    wrote_start_newline = true;
                    out.new_line();
                }

                out.new_line();

                write!(
                    out,
                    "bool operator{}(const {}& {}) const",
                    op, self.name, other
                );
                out.open_brace();
                out.write("return ");
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|x| format!("{} {} {}.{}", x.0, op, other, x.0))
                        .collect(),
                    ListType::Join(&format!(" {}", conjuc)),
                );
                out.write(";");
                out.close_brace(false);
            };

            if config.structure.derive_eq(&self.annotations) && !self.fields.is_empty()
                && self.fields.iter().all(|x| x.1.can_cmp_eq())
            {
                emit_op("==", "&&");
            }
            if config.structure.derive_neq(&self.annotations) && !self.fields.is_empty()
                && self.fields.iter().all(|x| x.1.can_cmp_eq())
            {
                emit_op("!=", "||");
            }
            if config.structure.derive_lt(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op("<", "&&");
            }
            if config.structure.derive_lte(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op("<=", "&&");
            }
            if config.structure.derive_gt(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op(">", "&&");
            }
            if config.structure.derive_gte(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op(">=", "&&");
            }
        }

        if config.language == Language::C {
            out.close_brace(false);
            write!(out, " {};", self.name);
        } else {
            out.close_brace(true);
        }

        self.cfg.write_after(config, out);
    }
}

pub trait SynFieldHelpers {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type, Documentation)>, String>;
}

impl SynFieldHelpers for syn::Field {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type, Documentation)>, String> {
        let ident = self.ident
            .as_ref()
            .ok_or(format!("field is missing identifier"))?
            .clone();
        let converted_ty = Type::load(&self.ty)?;

        if let Some(x) = converted_ty {
            Ok(Some((
                ident.to_string(),
                x,
                Documentation::load(&self.attrs),
            )))
        } else {
            Ok(None)
        }
    }
}
<commit_msg>Don't rename struct generic type parameters<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer,
                  Repr, Type};
use bindgen::library::Library;
use bindgen::mangle;
use bindgen::monomorph::Monomorphs;
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::{find_first_some, IterHelpers};
use bindgen::writer::{ListType, Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Struct {
    pub name: String,
    pub generic_params: GenericParams,
    pub fields: Vec<(String, Type, Documentation)>,
    pub is_tagged: bool,
    pub tuple_struct: bool,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Struct {
    pub fn load(item: &syn::ItemStruct, mod_cfg: &Option<Cfg>) -> Result<Struct, String> {
        if Repr::load(&item.attrs)? != Repr::C {
            return Err("Struct is not marked #[repr(C)].".to_owned());
        }

        let (fields, tuple_struct) = match &item.fields {
            &syn::Fields::Unit => (Vec::new(), false),
            &syn::Fields::Named(ref fields) => {
                let out = fields.named.iter().try_skip_map(|x| x.as_ident_and_type())?;
                (out, false)
            }
            &syn::Fields::Unnamed(ref fields) => {
                let mut out = Vec::new();
                let mut current = 0;
                for field in fields.unnamed.iter() {
                    if let Some(x) = Type::load(&field.ty)? {
                        out.push((format!("{}", current), x, Documentation::load(&field.attrs)));
                        current += 1;
                    }
                }
                (out, true)
            }
        };

        Ok(Struct {
            name: item.ident.to_string(),
            generic_params: GenericParams::new(&item.generics),
            fields: fields,
            is_tagged: false,
            tuple_struct: tuple_struct,
            cfg: Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            annotations: AnnotationSet::load(&item.attrs)?,
            documentation: Documentation::load(&item.attrs),
        })
    }

    pub fn simplify_option_to_ptr(&mut self) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.simplify_option_to_ptr();
        }
    }

    pub fn is_generic(&self) -> bool {
        self.generic_params.len() > 0
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        // Generic structs can instantiate monomorphs only once they've been
        // instantiated. See `instantiate_monomorph` for more details.
        if self.is_generic() {
            return;
        }

        for &(_, ref ty, _) in &self.fields {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Item for Struct {
    fn name(&self) -> &str {
        &self.name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Struct(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.name);
        for &mut (_, ref mut ty, _) in &mut self.fields {
            let generic_parameter = match ty.get_root_path() {
                Some(ref p) => self.generic_params.contains(p),
                None => false,
            };
            if !generic_parameter {
                ty.rename_for_config(config);
            }
        }

        let field_rules = [
            self.annotations.parse_atom::<RenameRule>("rename-all"),
            config.structure.rename_fields,
        ];

        let mut names = self.fields.iter_mut().map(|field| &mut field.0);

        if let Some(o) = self.annotations.list("field-names") {
            for (dest, src) in names.zip(o) {
                *dest = src;
            }
        } else if let Some(r) = find_first_some(&field_rules) {
            for name in names {
                *name = r.apply_to_snake_case(name, IdentifierType::StructMember);
            }
        } else if self.tuple_struct {
            // If there is a tag field, skip it
            if self.is_tagged {
                names.next();
            }

            // If we don't have any rules for a tuple struct, prefix them with
            // an underscore so it still compiles
            for name in names {
                name.insert(0, '_');
            }
        }
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        let mut fields = self.fields.iter();

        // If there is a tag field, skip it
        if self.is_tagged {
            fields.next();
        }

        for &(_, ref ty, _) in fields {
            ty.add_dependencies_ignoring_generics(&self.generic_params, library, out);
        }
    }

    fn instantiate_monomorph(
        &self,
        generic_values: &Vec<Type>,
        library: &Library,
        out: &mut Monomorphs,
    ) {
        assert!(self.generic_params.len() > 0 && self.generic_params.len() == generic_values.len());

        let mappings = self.generic_params
            .iter()
            .zip(generic_values.iter())
            .collect::<Vec<_>>();

        let monomorph = Struct {
            name: mangle::mangle_path(&self.name, generic_values),
            generic_params: GenericParams::default(),
            fields: self.fields
                .iter()
                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                .collect(),
            is_tagged: self.is_tagged,
            tuple_struct: self.tuple_struct,
            cfg: self.cfg.clone(),
            annotations: self.annotations.clone(),
            documentation: self.documentation.clone(),
        };

        // Instantiate any monomorphs for any generic paths we may have just created.
        monomorph.add_monomorphs(library, out);

        out.insert_struct(self, monomorph, generic_values.clone());
    }
}

impl Source for Struct {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        self.cfg.write_before(config, out);

        self.documentation.write(config, out);

        self.generic_params.write(config, out);

        if config.language == Language::C {
            out.write("typedef struct");
        } else {
            write!(out, "struct {}", self.name);
        }
        out.open_brace();

        if config.documentation {
            out.write_vertical_source_list(&self.fields, ListType::Cap(";"));
        } else {
            out.write_vertical_source_list(
                &self.fields
                    .iter()
                    .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone()))
                    .collect(),
                ListType::Cap(";"),
            );
        }

        if config.language == Language::Cxx {
            let mut wrote_start_newline = false;

            if config.structure.derive_constructor(&self.annotations) && !self.fields.is_empty() {
                if !wrote_start_newline {
                    wrote_start_newline = true;
                    out.new_line();
                }

                out.new_line();

                let arg_renamer = |name: &str| {
                    config
                        .function
                        .rename_args
                        .as_ref()
                        .unwrap_or(&RenameRule::GeckoCase)
                        .apply_to_snake_case(name, IdentifierType::FunctionArg)
                };
                write!(out, "{}(", self.name);
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|&(ref name, ref ty, _)| {
                            // const-ref args to constructor
                            (format!("const& {}", arg_renamer(name)), ty.clone())
                        })
                        .collect(),
                    ListType::Join(","),
                );
                write!(out, ")");
                out.new_line();
                write!(out, "  : ");
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|x| format!("{}({})", x.0, arg_renamer(&x.0)))
                        .collect(),
                    ListType::Join(","),
                );
                out.new_line();
                write!(out, "{{}}");
                out.new_line();
            }

            let other = if let Some(r) = config.function.rename_args {
                r.apply_to_snake_case("other", IdentifierType::FunctionArg)
            } else {
                String::from("other")
            };

            let mut emit_op = |op, conjuc| {
                if !wrote_start_newline {
                    wrote_start_newline = true;
                    out.new_line();
                }

                out.new_line();

                write!(
                    out,
                    "bool operator{}(const {}& {}) const",
                    op, self.name, other
                );
                out.open_brace();
                out.write("return ");
                out.write_vertical_source_list(
                    &self.fields
                        .iter()
                        .map(|x| format!("{} {} {}.{}", x.0, op, other, x.0))
                        .collect(),
                    ListType::Join(&format!(" {}", conjuc)),
                );
                out.write(";");
                out.close_brace(false);
            };

            if config.structure.derive_eq(&self.annotations) && !self.fields.is_empty()
                && self.fields.iter().all(|x| x.1.can_cmp_eq())
            {
                emit_op("==", "&&");
            }
            if config.structure.derive_neq(&self.annotations) && !self.fields.is_empty()
                && self.fields.iter().all(|x| x.1.can_cmp_eq())
            {
                emit_op("!=", "||");
            }
            if config.structure.derive_lt(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op("<", "&&");
            }
            if config.structure.derive_lte(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op("<=", "&&");
            }
            if config.structure.derive_gt(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op(">", "&&");
            }
            if config.structure.derive_gte(&self.annotations) && self.fields.len() == 1
                && self.fields[0].1.can_cmp_order()
            {
                emit_op(">=", "&&");
            }
        }

        if config.language == Language::C {
            out.close_brace(false);
            write!(out, " {};", self.name);
        } else {
            out.close_brace(true);
        }

        self.cfg.write_after(config, out);
    }
}

pub trait SynFieldHelpers {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type, Documentation)>, String>;
}

impl SynFieldHelpers for syn::Field {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type, Documentation)>, String> {
        let ident = self.ident
            .as_ref()
            .ok_or(format!("field is missing identifier"))?
            .clone();
        let converted_ty = Type::load(&self.ty)?;

        if let Some(x) = converted_ty {
            Ok(Some((
                ident.to_string(),
                x,
                Documentation::load(&self.attrs),
            )))
        } else {
            Ok(None)
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate rustc_version;
extern crate xdg;

use std::env;
use std::ffi::OsStr;
use std::process::{self, Command};

#[path = "../common.rs"]
mod common;

fn main() {
    if !common::archive_file_path().exists() {
        let version = common::rustc_version();
        eprintln!("AFL LLVM runtime is not built with Rust {}, run `cargo \
                   install --force afl` to build it.", version);
        process::exit(1);
    }

    let _ = clap_app().get_matches();

    let mut args = env::args().skip(2).peekable(); // skip `cargo` and `afl`
    match args.peek().map(|s| &**s) {
        Some("analyze") => run_afl(args, "afl-analyze"),
        Some("cmin") => run_afl(args, "afl-cmin"),
        Some("fuzz") => run_afl(args, "afl-fuzz"),
        Some("gotcpu") => run_afl(args, "afl-got-cpu"),
        Some("plot") => run_afl(args, "afl-plot"),
        Some("showmap") => run_afl(args, "afl-showmap"),
        Some("tmin") => run_afl(args, "afl-tmin"),
        Some("whatsup") => run_afl(args, "afl-whatsup"),
        _ => run_cargo(args),
    }
}

fn clap_app() -> clap::App<'static, 'static> {
    clap::App::new("cargo afl").bin_name("cargo").subcommand(
        clap::SubCommand::with_name("afl")
            .version(crate_version!())
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .setting(clap::AppSettings::TrailingVarArg)
            .setting(clap::AppSettings::AllowExternalSubcommands)
            .usage("cargo afl [SUBCOMMAND or Cargo SUBCOMMAND]")
            .after_help(
                "In addition to the subcommands above, Cargo subcommands are also \
                     supported (see `cargo help` for a list of all Cargo subcommands).",
            )
            .subcommand(
                clap::SubCommand::with_name("analyze")
                    .about("Invoke afl-analyze")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-analyze args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("cmin")
                    .about("Invoke afl-cmin")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-cmin args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("fuzz")
                    .about("Invoke afl-fuzz")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-fuzz args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("gotcpu")
                    .about("Invoke afl-gotcpu")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-gotcpu args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("plot")
                    .about("Invoke afl-plot")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-plot args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("showmap")
                    .about("Invoke afl-showmap")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-showmap args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("tmin")
                    .about("Invoke afl-tmin")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-tmin args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("whatsup")
                    .about("Invoke afl-whatsup")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-whatsup args").multiple(true)),
            ),
    )
}

fn run_afl<I, S>(args: I, cmd: &str)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cmd_path = common::afl_dir().join("bin").join(cmd);
    let status = Command::new(cmd_path)
        .args(args.into_iter().skip(1)) // skip afl sub-command
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}

fn run_cargo<I, S>(args: I)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cargo_path = env!("CARGO");

    let rustflags = &format!(
        "-C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C passes=sancov \
         -l afl-llvm-rt \
         -L {}",
        common::afl_llvm_rt_dir().display()
    );
    let status = Command::new(cargo_path)
        .args(args) // skip `cargo` and `afl`
        .env("RUSTFLAGS", rustflags)
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}
<commit_msg>Update RUSTFLAGS<commit_after>#[macro_use]
extern crate clap;
extern crate rustc_version;
extern crate xdg;

use std::env;
use std::ffi::OsStr;
use std::process::{self, Command};

#[path = "../common.rs"]
mod common;

fn main() {
    if !common::archive_file_path().exists() {
        let version = common::rustc_version();
        eprintln!("AFL LLVM runtime is not built with Rust {}, run `cargo \
                   install --force afl` to build it.", version);
        process::exit(1);
    }

    let _ = clap_app().get_matches();

    let mut args = env::args().skip(2).peekable(); // skip `cargo` and `afl`
    match args.peek().map(|s| &**s) {
        Some("analyze") => run_afl(args, "afl-analyze"),
        Some("cmin") => run_afl(args, "afl-cmin"),
        Some("fuzz") => run_afl(args, "afl-fuzz"),
        Some("gotcpu") => run_afl(args, "afl-got-cpu"),
        Some("plot") => run_afl(args, "afl-plot"),
        Some("showmap") => run_afl(args, "afl-showmap"),
        Some("tmin") => run_afl(args, "afl-tmin"),
        Some("whatsup") => run_afl(args, "afl-whatsup"),
        _ => run_cargo(args),
    }
}

fn clap_app() -> clap::App<'static, 'static> {
    clap::App::new("cargo afl").bin_name("cargo").subcommand(
        clap::SubCommand::with_name("afl")
            .version(crate_version!())
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .setting(clap::AppSettings::TrailingVarArg)
            .setting(clap::AppSettings::AllowExternalSubcommands)
            .usage("cargo afl [SUBCOMMAND or Cargo SUBCOMMAND]")
            .after_help(
                "In addition to the subcommands above, Cargo subcommands are also \
                     supported (see `cargo help` for a list of all Cargo subcommands).",
            )
            .subcommand(
                clap::SubCommand::with_name("analyze")
                    .about("Invoke afl-analyze")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-analyze args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("cmin")
                    .about("Invoke afl-cmin")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-cmin args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("fuzz")
                    .about("Invoke afl-fuzz")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-fuzz args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("gotcpu")
                    .about("Invoke afl-gotcpu")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-gotcpu args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("plot")
                    .about("Invoke afl-plot")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-plot args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("showmap")
                    .about("Invoke afl-showmap")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-showmap args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("tmin")
                    .about("Invoke afl-tmin")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-tmin args").multiple(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("whatsup")
                    .about("Invoke afl-whatsup")
                    .setting(clap::AppSettings::AllowLeadingHyphen)
                    .setting(clap::AppSettings::DisableHelpSubcommand)
                    .setting(clap::AppSettings::DisableVersion)
                    .arg(clap::Arg::with_name("h").short("h").hidden(true))
                    .arg(clap::Arg::with_name("help").long("help").hidden(true))
                    .arg(clap::Arg::with_name("afl-whatsup args").multiple(true)),
            ),
    )
}

fn run_afl<I, S>(args: I, cmd: &str)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cmd_path = common::afl_dir().join("bin").join(cmd);
    let status = Command::new(cmd_path)
        .args(args.into_iter().skip(1)) // skip afl sub-command
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}

fn run_cargo<I, S>(args: I)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cargo_path = env!("CARGO");

    let rustflags = &format!(
        "--cfg fuzzing \
         -C debug-assertions \
         -C overflow_checks \
         -C passes=sancov \
         -C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C opt-level=3 \
         -C target-cpu=native \
         -C debuginfo=0 \
         -l afl-llvm-rt \
         -L {}",
        common::afl_llvm_rt_dir().display()
    );
    let status = Command::new(cargo_path)
        .args(args) // skip `cargo` and `afl`
        .env("RUSTFLAGS", rustflags)
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;
use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
    if admins.is_empty() {
        return;
    }
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => {
                    info!("adminstrative region without coordinates for relation {}.",
                          relation.id);
                    continue;
                }
            };
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(ref l) if !levels.contains(&l) => continue,
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    info!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn index_osm(url: &str, admins: &AdminsMap) {
	info!("purge and create Munin...");
    mimirsbrunn::purge_and_create_munin().unwrap();
    info!("Munin purged and created.");
    mimirsbrunn::bulk_index(&format!("{}/admin", url), admins.values()).unwrap();
}

fn main() {
    env_logger::init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    let levels = args.flag_level.iter().cloned().collect();
    let mut res = administartive_regions(&args.flag_input, &levels);
    update_coordinates(&args.flag_input, &mut res);
    index_osm(&args.flag_connection_string, &res);

}
<commit_msg>corrections<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;
use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
    if admins.is_empty() {
        return;
    }
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => {
                    info!("adminstrative region without coordinates for relation {}.",
                          relation.id);
                    continue;
                }
            };
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(ref l) if !levels.contains(&l) => continue,
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    info!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn index_osm(url: &str, admins: &AdminsMap) {
	info!("purge and create Munin...");
	mimirsbrunn::purge_and_create_munin().unwrap();
	info!("Munin purged and created.");
	mimirsbrunn::bulk_index(&format!("{}/admin", url), admins.values()).unwrap();
}

fn main() {
    env_logger::init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    let levels = args.flag_level.iter().cloned().collect();
    let mut res = administartive_regions(&args.flag_input, &levels);
    update_coordinates(&args.flag_input, &mut res);
    index_osm(&args.flag_connection_string, &res);

}
<|endoftext|>


<commit_before>macro_rules! vk_struct_bindings {
    ($($raw_name: expr, $name: ident ($($param_name: ident: $param: ty),*,) -> $ret: ty);+;) => {
        $(type $name = unsafe extern "system" fn($($param),*) -> $ret);+;

        pub struct FnPtr {
            pub raw_name: &'static str,
            fn_ptr: *const ()
        }

        impl FnPtr {
            pub fn is_loaded(&self) -> bool {
                self.fn_ptr != unloaded_function_panic as *const ()
            }
        }

        pub struct Vk {
            $($name: FnPtr),+
        }

        impl Vk {
            pub fn new() -> Vk {unsafe{
                use std::mem;
                let mut vk: Vk = mem::uninitialized();

                $(
                    vk.$name = FnPtr{ raw_name: $raw_name, fn_ptr: unloaded_function_panic as *const ()};
                )+

                vk
            }}

            pub fn load_with<F: FnMut(&str) -> *const ()>(&mut self, mut load_fn: F) -> ::std::result::Result<(), Vec<&'static str>> {
                use std::ptr;
                let mut fn_buf: *const ();
                let mut unloaded_fns = Vec::new();

                $(
                    fn_buf = load_fn($raw_name);
                    if ptr::null() != fn_buf {
                        self.$name = FnPtr{ raw_name: $raw_name, fn_ptr: fn_buf };
                    } else if self.$name.fn_ptr != unloaded_function_panic as *const () {
                        unloaded_fns.push($raw_name)
                    }
                )+

                if 0 == unloaded_fns.len() {
                    Ok(())
                } else {
                    Err(unloaded_fns)
                }
            }

            $(
                pub unsafe extern "system" fn $name(&self, $($param_name: $param),*) -> $ret {
                    use std::mem;

                    mem::transmute::<_, $name>(self.$name.fn_ptr)($($param_name),*)
                }
            )+
        }
    }
}
<commit_msg>fixed bug where names of previously loaded functions were returned instead of unloaded ones<commit_after>macro_rules! vk_struct_bindings {
    ($($raw_name: expr, $name: ident ($($param_name: ident: $param: ty),*,) -> $ret: ty);+;) => {
        $(type $name = unsafe extern "system" fn($($param),*) -> $ret);+;

        pub struct FnPtr {
            pub raw_name: &'static str,
            fn_ptr: *const ()
        }

        impl FnPtr {
            pub fn is_loaded(&self) -> bool {
                self.fn_ptr != unloaded_function_panic as *const ()
            }
        }

        pub struct Vk {
            $($name: FnPtr),+
        }

        impl Vk {
            pub fn new() -> Vk {unsafe{
                use std::mem;
                let mut vk: Vk = mem::uninitialized();

                $(
                    vk.$name = FnPtr{ raw_name: $raw_name, fn_ptr: unloaded_function_panic as *const ()};
                )+

                vk
            }}

            pub fn load_with<F: FnMut(&str) -> *const ()>(&mut self, mut load_fn: F) -> ::std::result::Result<(), Vec<&'static str>> {
                use std::ptr;
                let mut fn_buf: *const ();
                let mut unloaded_fns = Vec::new();

                $(
                    fn_buf = load_fn($raw_name);
                    if ptr::null() != fn_buf {
                        self.$name = FnPtr{ raw_name: $raw_name, fn_ptr: fn_buf };
                    } else if self.$name.fn_ptr == unloaded_function_panic as *const () {
                        unloaded_fns.push($raw_name)
                    }
                )+

                if 0 == unloaded_fns.len() {
                    Ok(())
                } else {
                    Err(unloaded_fns)
                }
            }

            $(
                pub unsafe extern "system" fn $name(&self, $($param_name: $param),*) -> $ret {
                    use std::mem;

                    mem::transmute::<_, $name>(self.$name.fn_ptr)($($param_name),*)
                }
            )+
        }
    }
}
<|endoftext|>


<commit_before>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export MapTile;
export StaticTile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type MapTile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type StaticTile = {
    header: u32,
    width: u16,
    height: u16,
    image: ~[u16]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[(uint, MapTile)], ~[(uint, StaticTile)]) { //TODO: Find a better return type for this
    let maybe_reader: option::option<mul_reader::MulReader> = mul_reader::reader(root_path, ~"artidx.mul", ~"art.mul");

    if option::is_none(maybe_reader) {
        io::println("Error reading art tiles");
        assert false;
    }

    let reader: mul_reader::MulReader = option::get(maybe_reader);

    let mut map_tiles: ~[(uint, MapTile)] = ~[];
    let mut static_tiles: ~[(uint, StaticTile)] = ~[];

    let mut index:uint = 0;
    while (reader.eof() != true) {
        let item: option::option<mul_reader::MulRecord> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::MulRecord = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters

            //if (record_header > 0xFFFF || record_header == 0) {
            if (index < 0x4000) {
                let maybe_map_tile: option::option<MapTile> = parse_map_tile(unwrapped);
                if option::is_some(maybe_map_tile) {
                    vec::push(map_tiles, (index, maybe_map_tile.get()));
                }
            } else if (index < 0x8000){
                let maybe_static_tile: option::option<StaticTile> = parse_static_tile(unwrapped);
                if option::is_some(maybe_static_tile) {
                    vec::push(static_tiles, (index, maybe_static_tile.get()));
                }
            }
        }
        index += 1;
    }

    return (map_tiles, static_tiles);
}

//TODO: Use borrowed pointers;
fn parse_map_tile(record: mul_reader::MulRecord) -> option::option<MapTile> { //Interestingly, pixels seem to be 565, rather than 555

    if (vec::len(record.data) != expected_tile_size) {
        return option::none;
    }

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));

    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    return option::some({
        header: record_header as u32,
        image: image
    });
}

fn parse_static_tile(record: mul_reader::MulRecord) -> option::option<StaticTile> {
    let data_size: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 1)) as u16; //Might not be size :P
    let trigger: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 2, 3)) as u16;

    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 6, 7)) as u16;
    let mut image: ~[u16] = ~[];

    return option::none;
}

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    return vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<commit_msg>WIP on getting ART Statics parsing<commit_after>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export MapTile;
export StaticTile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type MapTile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type StaticTile = {
    data_size: u16,
    trigger: u16,
    width: u16,
    height: u16,
    image: ~[u16]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[(uint, MapTile)], ~[(uint, StaticTile)]) { //TODO: Find a better return type for this
    let maybe_reader: option::option<mul_reader::MulReader> = mul_reader::reader(root_path, ~"artidx.mul", ~"art.mul");

    if option::is_none(maybe_reader) {
        io::println("Error reading art tiles");
        assert false;
    }

    let reader: mul_reader::MulReader = option::get(maybe_reader);

    let mut map_tiles: ~[(uint, MapTile)] = ~[];
    let mut static_tiles: ~[(uint, StaticTile)] = ~[];

    let mut index:uint = 0;
    while (reader.eof() != true) {
        let item: option::option<mul_reader::MulRecord> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::MulRecord = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters

            //if (record_header > 0xFFFF || record_header == 0) {
            if (index < 0x4000) {
                /*let maybe_map_tile: option::option<MapTile> = parse_map_tile(unwrapped);
                if option::is_some(maybe_map_tile) {
                    vec::push(map_tiles, (index, maybe_map_tile.get()));
                }*/ //Skip
            } else if (index < 0x8000){
                let maybe_static_tile: option::option<StaticTile> = parse_static_tile(unwrapped);
                if option::is_some(maybe_static_tile) {
                    vec::push(static_tiles, (index, maybe_static_tile.get()));
                }
            }
        }
        index += 1;
    }

    return (map_tiles, static_tiles);
}

//TODO: Use borrowed pointers;
fn parse_map_tile(record: mul_reader::MulRecord) -> option::option<MapTile> { //Interestingly, pixels seem to be 565, rather than 555

    if (vec::len(record.data) != expected_tile_size) {
        return option::none;
    }

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));

    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    return option::some({
        header: record_header as u32,
        image: image
    });
}

fn parse_static_tile(record: mul_reader::MulRecord) -> option::option<StaticTile> {
    let data_size: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 1)) as u16; //Might not be size :P
    let trigger: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 2, 3)) as u16;

    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 6, 7)) as u16;

    let mut image: ~[u16] = ~[];

    if (width == 0 || height >= 1024 || height == 0 || height >= 1024) {
        io::println("Bad image dimensions found");
        return option::none;
    }

    //Offset table
    //let mut offset_table: ~[u16] = ~[];
    //TODO: Less magic numbers
    io::println("Access");
    for uint::range(0, height as uint) |index| {
        io::println("ROW");
        let offset = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 8 + (index * 2), 9 + (index * 2)));
        let mut data_start = offset + 8 + (height as uint * 2);
        let mut current_row_width:uint = 0;
        //From here, read the padding length, run length, and then Run pixels
        loop {
            io::println("LOOP");
            let padding_pixels = byte_helpers::bytes_to_le_uint(vec::slice(record.data, data_start, data_start + 1));
            let run_by = byte_helpers::bytes_to_le_uint(vec::slice(record.data, data_start + 2, data_start + 3));
            if padding_pixels == 0 && run_by == 0 {
                //Fill until current row width is less than width
                io::println("BREAK");
                if current_row_width < width as uint {
                    vec::grow(image, width as uint - current_row_width, transparent);
                }
                break;
            }
            let run_data = byte_helpers::u8vec_to_u16vec(vec::slice(record.data, data_start + 4, data_start + 4 + (run_by * 2)));

            vec::grow(image, padding_pixels, transparent);
            vec::push_all(image, run_data);

            data_start += 4 + (run_by * 2);
            current_row_width += padding_pixels + (run_by * 2);
        }
        //offset_table.push(byte_helpers::bytes_to_le_uint(vec::slice(record.data, 8 + (index * 2), 9 + (index * 2)))
    };

    return option::some({
        data_size: data_size,
        trigger: trigger,
        width: width,
        height: height,
        image: image
    });
}

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    return vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<|endoftext|>


<commit_before>//! The abstract syntax tree of buildlua.
//!
//! Most of this file is based on the syntax of lua page in the lua manual.
//!
//! The page can be found at http://www.lua.org/manual/5.2/manual.html#9.

/// The largest unit of code in lua. Equates to an entire file of code.
pub struct Chunk(Block);

pub struct Block(Option<Vec<Statement>>, Option<Box<ReturnStatement>>);

pub enum Statement {
    Semicolon,
    Assignment(Box<VariableList>, Box<ExpressionList>),
    FunctionCall(Box<FunctionCall>),
    Label(Label),
    Break,
    Goto(Label),
    Do(Box<Block>),
    While { exp: Box<Expression>, do_: Box<Block> },
    Repeat { block: Box<Block>, until: Box<Expression> },
    If {
        condition: Box<Expression>, then: Box<Block>,
        elseif_condition: Option<Box<Expression>>, elsethen: Option<Box<Block>>,
        else_: Box<Block>
    },
    ForStepping { name: String, from: Box<Expression>, to: Box<Expression>, step: Option<Box<Expression>>, block: Box<Block> },
    ForIn { name_list: Box<NameList>, in_: Box<ExpressionList>, do_: Box<Block> },
    Function(FunctionName, Box<FunctionBody>),
    LocalFunction { name: String, body: Box<FunctionBody> },
    LocalVariableBinding(NameList, Option<ExpressionList>),
}

pub struct ReturnStatement(Box<ExpressionList>);
pub struct Label(String);

pub struct FunctionName {
    pub first_dot_access: String,
    pub rest_dot_access: Option<Vec<String>>,
    pub self_name: Option<String>,
}

pub struct VariableList {
    pub first: Box<Variable>,
    pub rest: Option<Vec<Variable>>,
}

pub enum Variable {
    Name(String),
    ArrayAccess { from: Box<PrefixExpression>, key: Box<Expression> },
    DotAccess { from: Box<PrefixExpression>, key: String },
}

pub struct NameList(pub String, pub Option<Vec<String>>);
pub struct ExpressionList(pub Box<Expression>, pub Option<Vec<Expression>>);

pub enum Expression {
    Nil,
    False,
    True,
    Number(f64),
    String(String),
    /// Reperesents the lua ... variable in a function that takes extended arguments with a ...
    /// at the end of it's argument list.
    ExtendedArgumentAccess,
    FunctionDefine(Box<FunctionDefine>),
    PrefixExpression(Box<PrefixExpression>),
    TableConstructor(Box<TableConstructor>),
    BinaryOperation(Box<Expression>, Box<Expression>),
    UnaryOperation(Box<Expression>),
}

pub enum PrefixExpression {
    Variable(Box<Variable>),
    FunctionCall(Box<FunctionCall>),
    Parenthesis(Box<Expression>),
}

pub enum FunctionCall {
    /// Calling the function with a . to access through tables or through the global enviroment,
    /// not passing a self argument.
    ///
    /// # Example
    /// ```lua
    /// abcde("foo")
    /// bar.foo("foobar")
    /// ```
    Static(Box<PrefixExpression>, Box<FunctionArguments>),
    /// Calling with a self argument, using a : access.
    ///
    /// # Example
    /// ```lua
    /// foo:bar("barfoo")
    /// ```
    SelfTaking(Box<PrefixExpression>, String, FunctionArguments),
}

pub enum FunctionArguments {
    /// Calling a function normally.
    ///
    /// # Example
    /// ```lua
    /// foo("abc")
    /// ```
    Parenthesis(Option<Box<ExpressionList>>),
    /// Calling the function with a single table.
    ///
    /// # Example
    /// ```lua
    /// foo{a = "aaa"}
    /// ```
    TableConstructor(Box<TableConstructor>),
    /// Calls the function with a singlur literal string.
    ///
    /// # Example
    /// ```lua
    /// foo"abc"
    /// ```
    String(String), // This is really weird. I see the point, but why?
}

pub struct FunctionDefine(pub Box<FunctionBody>);
pub struct FunctionBody(pub Option<Box<ParameterList>>, pub Box<Block>);

pub enum ParameterList {
    /// A normal parameter list, without any extended arguments or special features.
    ///
    /// # Example
    /// ```lua
    /// function foo(a, b)
    /// end
    /// ```
    NameList(Box<NameList>),
    /// A parameter list with both arguments and an extended argument.
    ///
    /// # Example
    /// ```lua
    /// function foo(a, b, ...)
    /// ```
    ExtendedArguments(Box<NameList>),
    /// A function with an extended argument, but no regular arguments.
    ///
    /// # Example
    /// ```lua
    /// function foo(...)
    /// ```
    ExtendedArgumentsVoid,
}

pub struct TableConstructor(pub Box<FieldList>);
pub struct FieldList(pub Box<Field>, pub Option<Vec<Field>>);

pub enum Field {
    /// A field in a table that takes an expression for the name of the field.
    ExpressionForName { name: Box<Expression>, equals: Box<Expression> },
    /// A normal field.
    ///
    /// # Example
    /// ```lua
    /// a = { b = "bbb" }
    /// ```
    Equals { name: String, equals: Box<Expression> },
    /// A field in the form of an array.
    ///
    /// # Example
    /// ```lua
    /// a = { "bbb" }
    /// ```
    ArrayStyle(Box<Expression>),
}

pub enum BinaryOperation {
    /// + sigil.
    Plus,
    /// - sigil, when used as a binary operation.
    Minus,
    /// * sigil.
    Times,
    /// / sigil.
    Devide,
    /// ^ sigil.
    Exponent,
    /// % sigil.
    Modulo,
    /// .. sigil.
    Concatanate,
    /// < sigil.
    LessThan,
    /// <= sigil.
    LessThanOrEqual,
    /// > sigil.
    GreaterThan,
    /// >= sigil.
    GreaterThanOrEqual,
    /// == sigil.
    Equal,
    /// ~= sigil.
    NotEqual,
    And,
    Or,
}

pub enum UnaryOperation {
    /// - sigil, when used as a unary operation.
    Negate,
    Not,
    /// # sigil.
    Length,
}
<commit_msg>Makes a few accadently private fields public<commit_after>//! The abstract syntax tree of buildlua.
//!
//! Most of this file is based on the syntax of lua page in the lua manual.
//!
//! The page can be found at http://www.lua.org/manual/5.2/manual.html#9.

/// The largest unit of code in lua. Equates to an entire file of code.
pub struct Chunk(pub Block);

pub struct Block(pub Option<Vec<Statement>>, pub Option<Box<ReturnStatement>>);

pub enum Statement {
    Semicolon,
    Assignment(Box<VariableList>, Box<ExpressionList>),
    FunctionCall(Box<FunctionCall>),
    Label(Label),
    Break,
    Goto(Label),
    Do(Box<Block>),
    While { exp: Box<Expression>, do_: Box<Block> },
    Repeat { block: Box<Block>, until: Box<Expression> },
    If {
        condition: Box<Expression>, then: Box<Block>,
        elseif_condition: Option<Box<Expression>>, elsethen: Option<Box<Block>>,
        else_: Box<Block>
    },
    ForStepping { name: String, from: Box<Expression>, to: Box<Expression>, step: Option<Box<Expression>>, block: Box<Block> },
    ForIn { name_list: Box<NameList>, in_: Box<ExpressionList>, do_: Box<Block> },
    Function(FunctionName, Box<FunctionBody>),
    LocalFunction { name: String, body: Box<FunctionBody> },
    LocalVariableBinding(NameList, Option<ExpressionList>),
}

pub struct ReturnStatement(pub Box<ExpressionList>);
pub struct Label(pub String);

pub struct FunctionName {
    pub first_dot_access: String,
    pub rest_dot_access: Option<Vec<String>>,
    pub self_name: Option<String>,
}

pub struct VariableList {
    pub first: Box<Variable>,
    pub rest: Option<Vec<Variable>>,
}

pub enum Variable {
    Name(String),
    ArrayAccess { from: Box<PrefixExpression>, key: Box<Expression> },
    DotAccess { from: Box<PrefixExpression>, key: String },
}

pub struct NameList(pub String, pub Option<Vec<String>>);
pub struct ExpressionList(pub Box<Expression>, pub Option<Vec<Expression>>);

pub enum Expression {
    Nil,
    False,
    True,
    Number(f64),
    String(String),
    /// Reperesents the lua ... variable in a function that takes extended arguments with a ...
    /// at the end of it's argument list.
    ExtendedArgumentAccess,
    FunctionDefine(Box<FunctionDefine>),
    PrefixExpression(Box<PrefixExpression>),
    TableConstructor(Box<TableConstructor>),
    BinaryOperation(Box<Expression>, Box<Expression>),
    UnaryOperation(Box<Expression>),
}

pub enum PrefixExpression {
    Variable(Box<Variable>),
    FunctionCall(Box<FunctionCall>),
    Parenthesis(Box<Expression>),
}

pub enum FunctionCall {
    /// Calling the function with a . to access through tables or through the global enviroment,
    /// not passing a self argument.
    ///
    /// # Example
    /// ```lua
    /// abcde("foo")
    /// bar.foo("foobar")
    /// ```
    Static(Box<PrefixExpression>, Box<FunctionArguments>),
    /// Calling with a self argument, using a : access.
    ///
    /// # Example
    /// ```lua
    /// foo:bar("barfoo")
    /// ```
    SelfTaking(Box<PrefixExpression>, String, FunctionArguments),
}

pub enum FunctionArguments {
    /// Calling a function normally.
    ///
    /// # Example
    /// ```lua
    /// foo("abc")
    /// ```
    Parenthesis(Option<Box<ExpressionList>>),
    /// Calling the function with a single table.
    ///
    /// # Example
    /// ```lua
    /// foo{a = "aaa"}
    /// ```
    TableConstructor(Box<TableConstructor>),
    /// Calls the function with a singlur literal string.
    ///
    /// # Example
    /// ```lua
    /// foo"abc"
    /// ```
    String(String), // This is really weird. I see the point, but why?
}

pub struct FunctionDefine(pub Box<FunctionBody>);
pub struct FunctionBody(pub Option<Box<ParameterList>>, pub Box<Block>);

pub enum ParameterList {
    /// A normal parameter list, without any extended arguments or special features.
    ///
    /// # Example
    /// ```lua
    /// function foo(a, b)
    /// end
    /// ```
    NameList(Box<NameList>),
    /// A parameter list with both arguments and an extended argument.
    ///
    /// # Example
    /// ```lua
    /// function foo(a, b, ...)
    /// ```
    ExtendedArguments(Box<NameList>),
    /// A function with an extended argument, but no regular arguments.
    ///
    /// # Example
    /// ```lua
    /// function foo(...)
    /// ```
    ExtendedArgumentsVoid,
}

pub struct TableConstructor(pub Box<FieldList>);
pub struct FieldList(pub Box<Field>, pub Option<Vec<Field>>);

pub enum Field {
    /// A field in a table that takes an expression for the name of the field.
    ExpressionForName { name: Box<Expression>, equals: Box<Expression> },
    /// A normal field.
    ///
    /// # Example
    /// ```lua
    /// a = { b = "bbb" }
    /// ```
    Equals { name: String, equals: Box<Expression> },
    /// A field in the form of an array.
    ///
    /// # Example
    /// ```lua
    /// a = { "bbb" }
    /// ```
    ArrayStyle(Box<Expression>),
}

pub enum BinaryOperation {
    /// + sigil.
    Plus,
    /// - sigil, when used as a binary operation.
    Minus,
    /// * sigil.
    Times,
    /// / sigil.
    Devide,
    /// ^ sigil.
    Exponent,
    /// % sigil.
    Modulo,
    /// .. sigil.
    Concatanate,
    /// < sigil.
    LessThan,
    /// <= sigil.
    LessThanOrEqual,
    /// > sigil.
    GreaterThan,
    /// >= sigil.
    GreaterThanOrEqual,
    /// == sigil.
    Equal,
    /// ~= sigil.
    NotEqual,
    And,
    Or,
}

pub enum UnaryOperation {
    /// - sigil, when used as a unary operation.
    Negate,
    Not,
    /// # sigil.
    Length,
}
<|endoftext|>