<commit_before>//! Responsavel pelo parsing e de gerar a AST do programa BIRL

/// Representa as keywords da linguagem
pub mod kw {
    // Definições
    /// Usada para declaração de globais.birl constantes
    pub const KW_GLOBAL: &'static str = "SAI DE CASA";
    /// Usada pra declaração de globais.birl variáveis
    pub const KW_VAR_GLOBAL: &'static str = "IBIRAPUERA";
    /// Usada para definição de seções
    pub const KW_SECTION: &'static str = "JAULA";
    /// Usado pra definir seções parciais
    pub const KW_PART_SECTION: &'static str = "JAULINHA";
    /// Usada para finalizar a definição de seções
    pub const KW_SECTEND: &'static str = "SAINDO DA JAULA";

    /// Nome da variavel usada pra guardar o valor de retorno
    pub const KW_RETVAL_VAR: &'static str = "TREZE";

    pub const KW_SECT_GLOBAL: &'static str = "GLOBAL";
    pub const KW_SECT_DEFAULT: &'static str = "SHOW";

    // Comandos
    /// Copia o valor de uma variavel a outra
    pub const KW_MOVE: &'static str = "BORA";
    /// Limpa o valor de uma variavel
    pub const KW_CLEAR: &'static str = "SAI";
    /// Declara uma variável
    pub const KW_DECL: &'static str = "VEM";
    /// Declara uma variável com um valor
    pub const KW_DECLWV: &'static str = "VEM, CUMPADE";
    /// Realiza um "pulo" de uma seção para outra
    pub const KW_JUMP: &'static str = "E HORA DO";
    /// Comparação
    pub const KW_CMP: &'static str = "E ELE QUE A GENTE QUER";
    /// Comparação resultou em igual
    pub const KW_CMP_EQ: &'static str = "E ELE MEMO";
    /// Comparação resultou em diferente
    pub const KW_CMP_NEQ: &'static str = "NUM E ELE";
    /// Comparação resultou em menor
    pub const KW_CMP_LESS: &'static str = "MENOR, CUMPADE";
    /// Comparação resultou em menor ou igual
    pub const KW_CMP_LESSEQ: &'static str = "MENOR OU E MEMO";
    /// Comparação resultou em maior
    pub const KW_CMP_MORE: &'static str = "MAIOR, CUMPADE";
    /// Comparação resultou em maior ou igual
    pub const KW_CMP_MOREEQ: &'static str = "MAIOR OU E MEMO";
    /// Printa com nova linha
    pub const KW_PRINTLN: &'static str = "CE QUER VER ISSO";
    /// Printa
    pub const KW_PRINT: &'static str = "CE QUER VER";
    /// Sai do programa
    pub const KW_QUIT: &'static str = "NUM VAI DA NAO";
    /// Retorna da função atual
    pub const KW_RET: &'static str = "BIRL";
    /// Pega uma string da entrada padrão
    pub const KW_INPUT: &'static str = "BORA, CUMPADE";
    /// Pega uma string da entrada padrão com letras maiusculas
    pub const KW_INPUT_UP: &'static str = "BORA, CUMPADE!!!";
}

use eval;

#[derive(Clone)]
#[allow(dead_code)]
/// Representa um comando, que é executado dentro do contexto atual
/// Os valores passados aos comandos têm nomes fantasia alfabéticos para exemplificação
pub enum Command {
    /// Move (copia) o conteudo da variavel no endereco a pro b
    Move(String, String),
    /// Limpa o valor da variavel no endereco a
    Clear(String),
    /// Declara a variavel com nome a
    Decl(String),
    /// Declara a variavel com nome a e valor b
    DeclWV(String, String),
    /// Passa a execução para outra seção com nome a, retornando uma instrução à frente
    Jump(String),
    /// Compara os valores de a e b, usado em condicionais
    Cmp(String, String),
    /// Executa seção a caso ultima comparação seja igual
    CmpEq(Box<Command>),
    /// Executa seção caso a ultima comparação seja diferente
    CmpNEq(Box<Command>),
    /// Executa a seção caso a ultima comparação seja menor
    CmpLess(Box<Command>),
    /// Executa a seção caso a ultima comparação seja menor ou igual
    CmpLessEq(Box<Command>),
    /// Executa a seção caso a ultima comparação seja maior
    CmpMore(Box<Command>),
    /// Executa a seção caso a ultima comparação seja maior ou igual
    CmpMoreEq(Box<Command>),
    /// Printa uma série de valores com uma nova linha em seguida
    Println(Vec<String>),
    /// Printa uma série de valores
    Print(Vec<String>),
    /// Sai do programa
    Quit(String),
    /// Retorna da seção atual
    /// Valor, que pode existir ou não
    Return(Option<String>),
    /// Le a entrada padrão pra uma variavel
    Input(String),
    /// Le a entrada padrão e retorna um uppercase
    InputUpper(String),
}

/// Facil representação dos comandos sem os argumentos
pub enum CommandType {
    Move,
    Clear,
    Decl,
    DeclWV,
    Jump,
    Cmp,
    CmpEq,
    CmpNEq,
    CmpLess,
    CmpLessEq,
    CmpMore,
    CmpMoreEq,
    Println,
    Print,
    Quit,
    Return,
    Input,
    InputUpper,
}

/// Procura pelo caractere c em src e retorna quantas vezes ele foi encontrado
fn num_args(src: &str) -> i32 {
    if src.len() <= 0 {
        0
    } else {
        let c = ',';
        let mut num = 0i32;
        let mut last_char = ' ';
        let mut is_string = false;
        for cur in src.chars() {
            if cur == '\"' || cur == '\'' {
                // String ou caractere, verifica o ultimo caractere
                if last_char == '\\' {
                    // caractere de escape, ignora
                } else {
                    // inicia ou finaliza string ou char
                    is_string = !is_string;
                }
            }
            if !is_string {
                if cur == c {
                    num += 1;
                }
            }
            last_char = cur;
        }
        num
    }
}

/// Troca caracteres acentuados para suas versões sem acento
fn change_accents(src: &str) -> String {
    let mut nstr = String::new();
    for c in src.chars() {
        nstr.push(match c {
            'Á' | 'Ã' | 'À' => 'A',
            'É' => 'E',
            'Õ' | 'Ô' => 'O',
            'Í' => 'I',
            _ => c,
        });
    }
    nstr
}

/// Verifica se foi passada a quantidade correta de argumentos para um comando
fn check_n_params(command: CommandType, num_params: usize) {
    // Pra cada comando, retorne um valor inteiro para o numero de parametros
    let (expected, id) = match command {
        CommandType::Cmp => (2, kw::KW_CMP),
        CommandType::CmpEq => (1, kw::KW_CMP_EQ),
        CommandType::CmpNEq => (1, kw::KW_CMP_NEQ),
        CommandType::CmpLess => (1, kw::KW_CMP_LESS),
        CommandType::CmpLessEq => (1, kw::KW_CMP_LESSEQ),
        CommandType::CmpMore => (1, kw::KW_CMP_MORE),
        CommandType::CmpMoreEq => (1, kw::KW_CMP_MOREEQ),
        CommandType::Jump => (1, kw::KW_JUMP),
        CommandType::DeclWV => (2, kw::KW_DECLWV),
        CommandType::Decl => (1, kw::KW_DECL),
        CommandType::Clear => (1, kw::KW_CLEAR),
        CommandType::Move => (2, kw::KW_MOVE),
        // print e println aceitam mais de um argumento, então faça uma checagem adicional
        CommandType::Println => {
            // No caso do println, ele pode ser usado sem um argumento, assim printando apenas uma nova linha
            (num_params, kw::KW_PRINTLN)
        }
        CommandType::Print => {
            // Print não
            if num_params < 1 {
                (1, kw::KW_PRINT)
            } else {
                (num_params, kw::KW_PRINT)
            }
        }
        CommandType::Quit => {
            // Quit pode tomar um valor de retorno como valor de saida, mas é opcional
            if num_params == 1 {
                (1, kw::KW_QUIT)
            } else {
                (0, kw::KW_QUIT)
            }
        }
        CommandType::Return => {
            // Se for passado o retorno, retorne ele. Se não, deixe inalterado
            if num_params == 1 {
                (1, kw::KW_RET)
            } else {
                (0, kw::KW_RET)
            }
        }
        CommandType::Input => (1, kw::KW_INPUT),
        CommandType::InputUpper => (1, kw::KW_INPUT_UP),
    };
    if expected != num_params {
        panic!("\"{}\" espera {} parametros, porém {} foram passados.",
               id,
               expected,
               num_params)
    }
}

/// Divide os argumentos de um comando
fn split_arguments(args: String) -> Vec<String> {
    if args == "" {
        vec![]
    } else {
        let mut result: Vec<String> = vec![];
        let (mut in_str, mut in_char, mut last_escape, mut in_sym, mut in_par) =
            (false, false, false, false, false);
        let mut num_op_par = 0; // Numero de parenteses abertos
        let mut last_arg = String::new();
        for c in args.chars() {
            match c {
                '\"' if in_str => {
                    if last_escape {
                        last_escape = false;
                        last_arg.push_str("\\\"");
                    } else {
                        in_str = false;
                        last_arg.push('\"');
                    }
                }
                '\"' => {
                    in_str = true;
                    last_arg.push('\"');
                }
                '\'' => {
                    last_arg.push(c);
                    if !in_str {
                        in_char = !in_char;
                    }
                }
                '\\' => {
                    if last_escape {
                        last_arg.push('\\');
                        last_escape = false;
                    } else {
                        last_escape = true;
                    }
                }
                'a'...'z' | 'A'...'Z' | '_' if !in_str && !in_char => {
                    in_sym = true;
                    last_arg.push(c);
                }
                '(' if in_sym => {
                    // Parenteses
                    num_op_par += 1; // Abriu um parentese
                    in_par = true;
                    last_arg.push(c);
                }
                ')' if in_par => {
                    if num_op_par <= 0 {
                        panic!("Parentese de fechamento sem nenhum abrindo!")
                    }
                    num_op_par -= 1;
                    if num_op_par <= 0 {
                        in_par = false;
                    }
                    last_arg.push(c);
                }
                ',' if in_sym && !in_par => {
                    in_sym = false;
                    result.push(last_arg.clone());
                    last_arg.clear();
                }
                ',' if !in_str && !in_char && !in_sym && !in_par => {
                    result.push(last_arg.clone());
                    last_arg.clear();
                }
                ' ' if !in_str && !in_char && !in_sym => {}
                _ => last_arg.push(c),
            }
        }
        if last_arg != "" {
            result.push(last_arg.clone());
        }
        result.iter().map(|arg| arg.trim().to_string()).collect::<Vec<String>>()
    }
}

/// Divide um comando em nome e argumentos
fn split_command(cmd: String) -> Vec<String> {
    let mut has_args = true; // Se o comando possui argumentos
    let index = match cmd.find(':') {
        Some(i) => i,
        None => {
            has_args = false;
            cmd.len()
        }
    };
    let cmd_name = &cmd[..index];
    let cmd_args: &str = if has_args { &cmd[index + 1..] } else { "" };
    vec![cmd_name.to_string(), cmd_args.to_string()]
}

/// Faz parsing de um comando
fn parse_cmd(cmd: &str) -> Command {
    // Estrutura de um comando:
    // COMANDO: var1, var2, ...
    let cmd_parts = split_command(cmd.to_string());
    let cmd_parts = cmd_parts.iter().map(|part| part.trim()).collect::<Vec<&str>>();
    // argumentos
    let mut arguments: Vec<String> = Vec::new();
    // Tipo/nome do comando
    let cmd_type = if cmd_parts.len() > 1 {
        if num_args(cmd_parts[1]) == 0 {
            if cmd_parts[1].trim() != "" {
                // Um argumento
                arguments.push(cmd_parts[1].trim().to_string());
            }
        } else {
            arguments = split_arguments(cmd_parts[1].trim().to_string());
        }
        cmd_parts[0]
    } else {
        cmd.trim()
    };
    let cmd: Command = match cmd_type {
        kw::KW_MOVE => {
            check_n_params(CommandType::Move, arguments.len());
            let (addr1, addr2) = (arguments[0].clone(), arguments[1].clone());
            Command::Move(addr1, addr2)
        }
        kw::KW_CLEAR => {
            check_n_params(CommandType::Clear, arguments.len());
            Command::Clear(arguments[0].clone())
        }
        kw::KW_DECL => {
            check_n_params(CommandType::Decl, arguments.len());
            Command::Decl(arguments[0].clone())
        }
        kw::KW_DECLWV => {
            check_n_params(CommandType::DeclWV, arguments.len());
            let (name, val) = (arguments[0].clone(), arguments[1].clone());
            Command::DeclWV(name, val)
        }
        kw::KW_JUMP => {
            // Jump requere uma gambiarra: As funções podem ter argumentos (',') adicionais, então use joint pra juntar os argumentos em 1 e retorne
            check_n_params(CommandType::Jump, arguments.len());
            Command::Jump(arguments[0].clone())
        }
        kw::KW_CMP => {
            check_n_params(CommandType::Cmp, arguments.len());
            let (addr1, addr2) = (arguments[0].clone(), arguments[1].clone());
            Command::Cmp(addr1, addr2)
        }
        kw::KW_CMP_EQ => {
            check_n_params(CommandType::CmpEq, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpEq(Box::new(cmd))
        }
        kw::KW_CMP_NEQ => {
            check_n_params(CommandType::CmpNEq, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpNEq(Box::new(cmd))
        }
        kw::KW_CMP_LESS => {
            check_n_params(CommandType::CmpLess, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpLess(Box::new(cmd))
        }
        kw::KW_CMP_LESSEQ => {
            check_n_params(CommandType::CmpLessEq, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpLessEq(Box::new(cmd))
        }
        kw::KW_CMP_MORE => {
            check_n_params(CommandType::CmpMore, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpMore(Box::new(cmd))
        }
        kw::KW_CMP_MOREEQ => {
            check_n_params(CommandType::CmpMoreEq, arguments.len());
            let cmd = parse_cmd(&arguments[0]);
            Command::CmpMoreEq(Box::new(cmd))
        }
        kw::KW_PRINTLN => {
            check_n_params(CommandType::Println, arguments.len());
            Command::Println(arguments.iter().map(|arg| arg.clone()).collect::<Vec<String>>())
        }
        kw::KW_PRINT => {
            check_n_params(CommandType::Print, arguments.len());
            Command::Print(arguments.iter().map(|arg| arg.clone()).collect::<Vec<String>>())
        }
        kw::KW_QUIT => {
            check_n_params(CommandType::Quit, arguments.len());
            let exitcode = if arguments.len() == 1 {
                // Se for 1 argumento, retorne o valor, se não, deixe inalterado
                arguments[0].clone()
            } else {
                String::from("0")
            };
            Command::Quit(exitcode)
        }
        kw::KW_RET => {
            check_n_params(CommandType::Return, arguments.len());
            let val = if arguments.len() == 1 {
                // Se for 1 argumento, retorne o valor, se não, deixe inalterado
                Some(arguments[0].clone())
            } else {
                None
            };
            Command::Return(val)
        }
        kw::KW_INPUT => {
            check_n_params(CommandType::Input, arguments.len());
            Command::Input(arguments[0].clone())
        }
        kw::KW_INPUT_UP => {
            check_n_params(CommandType::InputUpper, arguments.len());
            Command::InputUpper(arguments[0].clone())
        }
        _ => panic!("Comando \"{}\" não existe.", cmd_type),
    };
    cmd
}

#[derive(Clone)]
/// Representa uma unidade (arquivo compilado) contendo o conteudo a ser executado
pub struct Unit {
    /// Conjunto de seções para execução
    pub sects: Vec<Section>,
    /// Conjunto de globais.birl, constantes ou variaveis
    pub globals: Vec<Global>,
}

/// Representa diferentes tipos de informação que uma linha carrega e o que representa
enum LineType {
    /// No caso de representar um comando
    Command,
    /// No caso de representar uma declaração de seção
    SectStart,
    /// No caso de representar o fim de uma seção
    SectEnd,
    /// Na declaração de um global
    GlobalDecl,
}

fn parse_line_type(line: &str) -> LineType {
    // line já foi usada trim()
    // testa se está finalizando uma seção
    if line == kw::KW_SECTEND {
        LineType::SectEnd
    } else {
        let mut ret = LineType::Command;
        // Se for a declaração de uma seção
        let fword = line.split(' ').collect::<Vec<&str>>()[0];
        if fword == kw::KW_SECTION || fword == kw::KW_PART_SECTION {
            ret = LineType::SectStart;
        }
        // Testa se é a declaração de um global
        let fword = line.split(':').collect::<Vec<&str>>()[0];
        if fword == kw::KW_GLOBAL || fword == kw::KW_VAR_GLOBAL {
            ret = LineType::GlobalDecl;
        }
        ret
    }
}

/// Realiza a interpretação de um arquivo e retorna sua unidade compilada
pub fn parse(file: &str) -> Unit {
    use std::fs;
    use std::io::{BufRead, BufReader};
    let f = match fs::File::open(file) {
        Ok(ff) => ff,
        Err(err) => {
            panic!("Não foi possivel abrir o arquivo \"{}\". Erro: {}",
                   file,
                   err)
        }
    };
    // Valor de retorno
    let mut final_unit = Unit {
        sects: vec![Section::new()],
        globals: vec![],
    };
    final_unit.sects[0].name = String::from(kw::KW_SECT_GLOBAL);
    let reader = BufReader::new(f);
    let mut lines = reader.lines();
    // Se está fazendo parsing de uma seção e o conteudo atual da seção
    let mut parsing_section = false;
    let mut cur_section: Vec<String> = vec![];
    loop {
        let line = match lines.next() {
            Some(l) => {
                match l {
                    Ok(ll) => String::from(ll.trim()),
                    Err(_) => String::new(),
                }
            }
            None => break,
        };
        if line == "" {
            continue;
        }
        // Retira os comentarios das linhas
        let line = if line.contains('#') || line.contains(';') {
            let mut tmp = String::new();
            for c in line.chars() {
                // Enquanto o caractere não for um comentário, continue
                if c != '#' && c != ';' {
                    tmp.push(c);
                } else {
                    break;
                }
            }
            tmp.trim().to_string()
        } else {
            line.trim().to_string()
        };
        if line == "" {
            // Depois de tirar os comentarios, a linha ficou vazia
            continue;
        }
        // Verifica a primeira palavra da linha
        match parse_line_type(&line) {
            // Se for declaração de um global, empurra o global pra unit
            LineType::GlobalDecl if !parsing_section => {
                final_unit.globals.push(parse_global(&line))
            }
            // Se for declaração de uma seção, começa o parsing da seção
            LineType::SectStart if !parsing_section => {
                cur_section.push(line.clone());
                parsing_section = true;
            }
            LineType::SectEnd if parsing_section => {
                cur_section.push(line.clone());
                if line == kw::KW_SECTEND {
                    // Encerra seção
                    parsing_section = false;
                    final_unit.sects.push(parse_section(cur_section.clone()));
                    cur_section.clear();
                }
            }
            // Quando estiver dentro de uma seção, empurre o comando pra seção
            LineType::Command if parsing_section => {
                // Mude os acentos para que aceite comandos com acento
                cur_section.push(change_accents(&line));
            }
            // Se não for nenhuma (os comandos só são interpretados dentro da seção)
            // A primeira seção sempre é a global, por isso puxe pra primeira seção
            LineType::Command => final_unit.sects[0].lines.push(parse_cmd(&change_accents(&line))),
            _ => {
                // Quando não for nenhuma das acima
                panic!("Erro de sintaxe! Linha atual não reconhecida no contexto: {}",
                       line)
            }
        }
    }
    final_unit
}

#[derive(Clone)]
/// Representa uma área chamável que pode ser executada
pub struct Section {
    /// Nome da seção
    pub name: String,
    /// Conjunto de linhas/comandos para execução
    pub lines: Vec<Command>,
    /// Conjunto de parametros a serem passados para a seção ser executada
    pub param_list: Vec<ExpectedParameter>,
    /// Se a seção é apenas parcial
    pub partial: bool,
}

impl Section {
    pub fn new() -> Section {
        Section {
            name: String::new(),
            lines: vec![],
            param_list: vec![],
            partial: false,
        }
    }
}

#[derive(Clone)]
pub struct ExpectedParameter {
    /// Identificador do parametro
    pub id: String,
    /// Tipo que o parametro espera
    pub tp: eval::ValueType,
}

/// Faz parsing de um parametro
fn parse_parameter(param: &str) -> ExpectedParameter {
    let div_token = match param.find(':') {
        Some(pos) => pos,
        None => panic!("Parametro deve ter tipo declarado depois do nome, separado por um ':'"),
    };
    let param_id = &param[..div_token];
    let param_tp = match eval::ValueType::try_parse(&param[div_token + 1..]) {
        Some(tp) => tp,
        None => {
            panic!("Tipo inválido para parâmetro: {}",
                   &param[div_token + 1..])
        }
    };
    ExpectedParameter {
        id: param_id.trim().to_string(),
        tp: param_tp,
    }
}

/// Faz parsing da lista de argumentos que uma seção recebe
fn parse_section_parameters(decl_line: &str) -> Vec<ExpectedParameter> {
    let decl_line = decl_line.trim();
    if !decl_line.contains('(') {
        vec![] // Nenhum argumento, retorna um array vazio
    } else {
        // Formato da declaração de uma seção com parametros:
        // JAULA seção (PARAMETRO1:TIPO, ...)
        let start_par = decl_line.find('(').unwrap(); // Ja verifiquei a existencia de um parentese
        if start_par >= decl_line.len() {
            panic!("Parametros declarados de forma incorreta. Parêntese em aberto");
        }
        let fin_par = decl_line.find(')').expect("Parêntese de fechamento não encontrado na declaração dos parametros da seção");
        if fin_par < start_par {
            panic!("Erro na sintaxe! Parêntese de fechamento veio antes do de abertura");
        }
        let parameters = decl_line[start_par + 1..fin_par].trim();
        if parameters == "" {
            vec![] // Retorna um array vazio, são só os parenteses nessa seção
        } else {
            if parameters.contains(',') {
                parameters.split(',').map(|param| parse_parameter(param.trim())).collect()
            } else {
                vec![parse_parameter(parameters)]
            }
        }
    }
}

/// Faz parsing de uma seção
fn parse_section(lines: Vec<String>) -> Section {
    // Separa a seção em linha
    if lines.len() < 2 {
        panic!("Erro fazendo parsing da seção. Número incorreto de linhas: {}.",
               lines.len())
    } else {
        // Checagens de declaração e finalização são feitas em parse
        // Declaração de uma seção:
        // PALAVRA_CHAVE nome
        if !lines[0].contains(' ') {
            panic!("Erro na declaração da seção! Falta nome depois da palavra chave")
        }
        let params = parse_section_parameters(&lines[0]);
        let first_space = lines[0].find(' ').unwrap(); // Primeira ocorrencia de espaco
        let name = if lines[0].contains('(') {
            // Se a declaração possui parametros, separa o nome dos parametros
            let starting_par = lines[0].find('(').unwrap();
            lines[0][first_space + 1..starting_par].trim().to_string()
        } else {
            lines[0][first_space + 1..].trim().to_string()
        };
        let sect_type = lines[0].split(' ').collect::<Vec<&str>>()[0];
        let is_part = sect_type == kw::KW_PART_SECTION;
        let mut sect = Section {
            name: name,
            lines: vec![],
            param_list: params,
            partial: is_part,
        };
        if lines.len() > 2 {
            // O -1 é pra não contar com a ultima linha, o SAINDO DA JAULA
            for line in lines[1..lines.len() - 1].iter() {
                if line == "" {
                    continue;
                }
                // Se a linha não tem nada de util até um comentario, pula ela
                if line.chars().collect::<Vec<char>>()[0] == '#' ||
                   line.chars().collect::<Vec<char>>()[0] == ';' {
                    continue;
                }
                sect.lines.push(parse_cmd(&line));
            }
        }
        sect
    }
}

/// Faz parsing da chamada de uma seção
pub fn parse_section_call_params(call: &str) -> (Vec<String>, String) {
    match call.find('(') {
        Some(op_par) => {
            if op_par >= call.len() - 1 {
                panic!("Parentese de abertura não possui fechamento");
            }
            let name = call[..op_par].to_string();
            let args = &call[op_par + 1..];
            let mut params: Vec<String> = vec![];
            let mut param_indx = 0; // Quantos parenteses foram abertos
            let mut last_arg = String::new();
            for c in args.chars() {
                if c == ')' {
                    if param_indx <= 0 {
                        break;
                    } else {
                        param_indx -= 1;
                    }
                } else if c == ')' {
                    param_indx += 1;
                } else if c == ',' {
                    if last_arg.trim() == "" {
                        panic!("Virgula após lista vazia de parametros passada.");
                    }
                    params.push(last_arg.clone());
                    last_arg.clear();
                } else {
                    last_arg.push(c);
                }
            }
            if param_indx != 0 {
                panic!("Parametros não fechados.");
            }
            if last_arg.trim() != "" {
                params.push(last_arg);
            }
            (params, name)
        }
        None => (vec![], call.to_string()), // Nenhum parametro passado
    }
}

#[derive(Clone)]
/// Representa um valor global, constante
pub struct Global {
    /// Identificador do valor global
    pub identifier: String,
    /// Valor do global
    pub value: String,
    /// Se o global é constante ou não
    pub is_const: bool,
}

/// Divide a declaração do global
fn split_global<'a>(glb: &'a str) -> Vec<&'a str> {
    let index = match glb.find(':') {
        Some(i) => i,
        None => panic!("Numero incorreto de ':' na declaração de um global."),
    };
    if index >= glb.len() - 1 {
        panic!("Faltam informações depois do primeiro ':'")
    }
    let nindex = match glb[index + 1..].find(':') {
        Some(i) => i,
        None => panic!("Numero incorreto de ':' na declaração de um global."),
    };
    if nindex >= glb.len() - 1 {
        panic!("Faltam informações após o segundo ':'")
    }
    vec![&glb[..index].trim(),
         &glb[index + 1..nindex + index + 1].trim(),
         &glb[nindex + index + 2..].trim()]
}

/// Faz parsing de um global
fn parse_global(glb: &str) -> Global {
    // Estrutura da declaração de um global: PALAVRA_CHAVE: nome: valor
    let words = split_global(glb.trim());
    if words.len() != 3 {
        panic!("Problema na declaração do global. Número incorreto de ':': {}",
               words.len())
    }
    let is_const = match words[0].trim() {
        kw::KW_GLOBAL => true,
        kw::KW_VAR_GLOBAL => false,
        _ => unreachable!(),
    };
    // Separa o nome e valor do global
    let (glb_name, glb_value) = (words[1].clone(), String::from(words[2]));
    Global {
        identifier: String::from(glb_name),
        value: glb_value,
        is_const: is_const,
    }
}
<commit_msg>Modulo não mais necessário<commit_after><|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;

use super::sql::*;

//pub enum Keyword {
//    Select,
//    From,
//    Where
//}

pub enum Token {
    Identifier(String),
    Keyword(String),
    Operator(String),
}

#[derive(Debug,Clone)]
pub enum ParserError {
    TokenizerError(String)
}

struct Tokenizer {
    query: String
}

impl Tokenizer {

    pub fn tokenize(&mut self) -> Result<Vec<Token>, ParserError> {

        let mut peekable = self.query.chars().peekable();

        Err(ParserError::TokenizerError(String::from("not implemented yet")))
    }

}

<commit_msg>roughing out tokenizer<commit_after>use std::error::Error;
use std::fs::File;
use std::iter::Peekable;
use std::str::Chars;

use super::sql::*;

//pub enum Keyword {
//    Select,
//    From,
//    Where
//}

pub enum Token {
    Identifier(String),
    Keyword(String),
    Operator(String),
    Whitespace
}

#[derive(Debug,Clone)]
pub enum ParserError {
    TokenizerError(String)
}

struct Tokenizer {
    query: String,
}

impl Tokenizer {

    pub fn tokenize(&mut self) -> Result<Vec<Token>, ParserError> {

        let mut peekable = self.query.chars().peekable();

        let mut tokens : Vec<Token> = vec![];

        while let Some(token) = self.next_token(&mut peekable)? {
            tokens.push(token);
        }

        Ok(tokens)
    }

    fn next_token(&self, chars: &mut Peekable<Chars>) -> Result<Option<Token>, ParserError> {
        match chars.peek() {
            Some(&ch) => match ch {
                ' ' | '\t' | '\n' => {
                    chars.next();
                    Ok(Some(Token::Whitespace))
                },
                _ => Err(ParserError::TokenizerError(String::from("unhandled case in tokenizer")))
            },
            None => Ok(None)
        }
    }

}

<|endoftext|>


<commit_before>use std::str::{self, FromStr};

use pest::prelude::*;

const STRING_BOUNDARY: &'static str = "\"";
const STATEMENT_TERMINATOR: &'static str = ";";
const ASSIGNMENT_OPERATOR: &'static str = "=";
const LINE_COMMENT: &'static str = "//";

const START_BLOCK_COMMENT: &'static str = "/*";
const END_BLOCK_COMMENT: &'static str = "*/";
const BEGIN_SLICE: &'static str = "[";
const END_SLICE: &'static str = "]";
const BEGIN_BLOCK: &'static str = "{";
const END_BLOCK: &'static str = "}";

const OUTPUT_KEYWORD: &'static str = "out";
const INPUT_KEYWORD: &'static str = "in";
const WHILE_KEYWORD: &'static str = "while";
const IF_KEYWORD: &'static str = "if";

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = String;
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        println!("{:?}", (parser.program(), parser.end()));
        println!("{:#?}", parser.queue());
        println!("{:?}", parser.stack());
        let (expected, pos) = parser.expected();
        let (line, col) = parser.input().line_col(pos);
        println!("Expected: {:?} at line {} col {}", expected, line, col);
        unimplemented!();
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Output(Vec<Expression>),
    Input {
        name: String,
        slice: Option<Slice>,
    },
    Declaration {
        name: String,
        slice: Option<Slice>,
        expr: Expression,
    },
    WhileLoop {
        condition: WhileCondition,
        body: Vec<Statement>,
    },
    IfCondition {
        condition: Expression,
        body: Vec<Statement>,
    },
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Slice {
    SingleValue(usize),
    //Range(Option<usize>, Option<usize>),
    Unspecified,
}

#[derive(Debug, PartialEq, Clone)]
pub enum WhileCondition {
    Input {
        name: String,
        slice: Option<Slice>,
    },
    Expression(Expression),
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(String),
}

impl_rdp! {
    grammar! {
        program = _{ statement* ~ eoi }

        statement = _{ declaration | assignment | while_loop | for_loop | conditional | (expr ~ semi) | comment }

        comment = @{ block_comment | line_comment }
        line_comment = _{ ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi) }
        block_comment = _{ ["/*"] ~ ((!(["*/"]) ~ any) | block_comment)* ~ ["*/"] }

        assignment = { identifier ~ ["="] ~ expr ~ semi}
        declaration = { ["let"] ~ pattern ~ [":"] ~ type_def ~ (["="] ~ expr)? ~ semi}
        pattern = { identifier }

        type_def = { identifier | array_type }
        array_type = { ["["] ~ identifier ~ semi ~ array_size ~ ["]"] }
        array_size = { ["_"] | number }

        while_loop = { ["while"] ~ expr ~ block }
        for_loop = { ["for"] ~ pattern ~ ["in"] ~ expr ~ block }

        expr = {
            { block | group | constant | func_call | call_chain | conditional | bool_not | string_literal | range | number }

            // Ordered from lowest precedence to highest precedence
            bool_or = {< ["||"] }
            bool_and = {< ["&&"] }
            // NOTE: Order matters! { ["<"] | ["<="] } will never match "<="
            comparison = { ["=="] | ["!="] | [">="] | ["<="] | [">"] | ["<"] }
            concatenation = {< ["++"] }
            term = { ["+"] | ["-"] }
            factor = { ["/"] | ["*"] | ["%"] }
            pow = { ["**"] }
        }

        conditional = { ["if"] ~ expr ~ block ~ (["else"] ~ conditional)? ~ (["else"] ~ block)? }

        // This allows {} and {statement; statement; statement;} and {statement; expr} and {expr}
        block = { ["{"] ~ statement* ~ expr? ~ ["}"] }

        group = { ["("] ~ expr ~ [")"] }
        bool_not = { ["!"] ~ expr }
        range = { number ~ (comma ~ number)? ~ [".."] ~ number }

        func_call = { identifier ~ func_args }

        call_chain = { identifier ~ prop_get_call* }
        prop_get_call = { ["."] ~ identifier ~ func_args? }

        // This allows () and (func_arg, func_arg) and (func_arg) and (func_arg,)
        func_args = { ["("] ~ (func_arg ~ comma)* ~ func_arg? ~ [")"] }
        func_arg = { expr }

        string_literal = { ["\""] ~ literal_char* ~ ["\""] }
        literal_char = _{ escape_sequence | (!["\""] ~ any) }
        escape_sequence = _{ ["\\\\"] | ["\\\""] | ["\\\'"] | ["\\n"] | ["\\r"] | ["\\t"] | ["\\0"] | ["\\f"] | ["\\v"] | ["\\e"] }

        identifier = @{ !keyword ~ (alpha | ["_"]) ~ (alphanumeric | ["_"])* }
        alpha = _{ ['a'..'z'] | ['A'..'Z'] }
        alphanumeric = _{ alpha | ['0'..'9'] }

        number = @{ (["-"] | ["+"])? ~ positive_integer }
        positive_integer = _{ ["0"] | (nonzero ~ digit*) }
        // Allow "_" in numbers for grouping: 1_000_000 == 1000000
        digit = _{ ["0"] | nonzero | ["_"] }
        nonzero = _{ ['1'..'9'] }

        constant = @{ ["true"] | ["false"] }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
        // NOTE: When changing this code, make sure you don't have a subset of a word before
        // another word. For example: { ["type"] | ["typeof"] } will never match "typeof"
        keyword = @{
            ["abstract"] | ["as"] | ["become"] | ["break"] | ["byte"] | ["class"] | ["clear"] |
            ["const"] | ["continue"] | ["do"] | ["else"] | ["enum"] | ["eval"] | ["export"] |
            ["extern"] | ["false"] | ["final"] | ["fn"] | ["for"] | ["if"] | ["impl"] | ["import"] |
            ["in"] | ["let"] | ["loop"] | ["match"] | ["mod"] | ["move"] | ["mut"] | ["of"] |
            ["out"] | ["pub"] | ["raw"] | ["ref"] | ["return"] | ["self"] | ["static"] |
            ["struct"] | ["super"] | ["trait"] | ["true"] | ["typeof"] | ["type"] | ["unsafe"] |
            ["use"] | ["where"] | ["while"] | ["yield"]
        }

        // These are separate rules because we can use the generated rules and tokens to provide
        // better error messages
        comma = { [","] }
        semi = { [";"] }
    }
}
<commit_msg>Defining new AST<commit_after>use std::str::{self, FromStr};

use pest::prelude::*;

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = String;
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        println!("{:?}", (parser.program(), parser.end()));
        println!("{:#?}", parser.queue());
        println!("{:?}", parser.stack());
        let (expected, pos) = parser.expected();
        let (line, col) = parser.input().line_col(pos);
        println!("Expected: {:?} at line {} col {}", expected, line, col);
        unimplemented!();
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Expression,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    ConditionGroup {
        // Condition expression and body block
        branches: Vec<(Expression, Block)>,
        // "default" or "else" branch body
        default: Option<Block>,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        //TODO: This probably isn't the right type since this should accept anything and then get
        // statically checked to ensure the correct number was put here
        size: usize,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(Identifier),
}

pub type Identifier = String;
pub type Block = Vec<Statement>;

impl_rdp! {
    grammar! {
        program = _{ statement* ~ eoi }

        statement = _{ declaration | assignment | while_loop | for_loop | conditional | (expr ~ semi) | comment }

        comment = @{ block_comment | line_comment }
        line_comment = _{ ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi) }
        block_comment = _{ ["/*"] ~ ((!(["*/"]) ~ any) | block_comment)* ~ ["*/"] }

        assignment = { identifier ~ ["="] ~ expr ~ semi}
        declaration = { ["let"] ~ pattern ~ [":"] ~ type_def ~ (["="] ~ expr)? ~ semi}
        pattern = { identifier }

        type_def = { identifier | array_type }
        array_type = { ["["] ~ identifier ~ semi ~ array_size ~ ["]"] }
        array_size = { ["_"] | number }

        while_loop = { ["while"] ~ expr ~ block }
        for_loop = { ["for"] ~ pattern ~ ["in"] ~ expr ~ block }

        expr = {
            { block | group | constant | func_call | call_chain | conditional | bool_not | string_literal | range | number }

            // Ordered from lowest precedence to highest precedence
            bool_or = {< ["||"] }
            bool_and = {< ["&&"] }
            // NOTE: Order matters! { ["<"] | ["<="] } will never match "<="
            comparison = { ["=="] | ["!="] | [">="] | ["<="] | [">"] | ["<"] }
            concatenation = {< ["++"] }
            term = { ["+"] | ["-"] }
            factor = { ["/"] | ["*"] | ["%"] }
            pow = { ["**"] }
        }

        conditional = { ["if"] ~ expr ~ block ~ (["else"] ~ conditional)? ~ (["else"] ~ block)? }

        // This allows {} and {statement; statement; statement;} and {statement; expr} and {expr}
        block = { ["{"] ~ statement* ~ expr? ~ ["}"] }

        group = { ["("] ~ expr ~ [")"] }
        bool_not = { ["!"] ~ expr }
        range = { number ~ (comma ~ number)? ~ [".."] ~ number }

        func_call = { identifier ~ func_args }

        call_chain = { identifier ~ prop_get_call* }
        prop_get_call = { ["."] ~ identifier ~ func_args? }

        // This allows () and (func_arg, func_arg) and (func_arg) and (func_arg,)
        func_args = { ["("] ~ (func_arg ~ comma)* ~ func_arg? ~ [")"] }
        func_arg = { expr }

        string_literal = { ["\""] ~ literal_char* ~ ["\""] }
        literal_char = _{ escape_sequence | (!["\""] ~ any) }
        escape_sequence = _{ ["\\\\"] | ["\\\""] | ["\\\'"] | ["\\n"] | ["\\r"] | ["\\t"] | ["\\0"] | ["\\f"] | ["\\v"] | ["\\e"] }

        identifier = @{ !keyword ~ (alpha | ["_"]) ~ (alphanumeric | ["_"])* }
        alpha = _{ ['a'..'z'] | ['A'..'Z'] }
        alphanumeric = _{ alpha | ['0'..'9'] }

        number = @{ (["-"] | ["+"])? ~ positive_integer }
        positive_integer = _{ ["0"] | (nonzero ~ digit*) }
        // Allow "_" in numbers for grouping: 1_000_000 == 1000000
        digit = _{ ["0"] | nonzero | ["_"] }
        nonzero = _{ ['1'..'9'] }

        constant = @{ ["true"] | ["false"] }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
        // NOTE: When changing this code, make sure you don't have a subset of a word before
        // another word. For example: { ["type"] | ["typeof"] } will never match "typeof"
        keyword = @{
            ["abstract"] | ["as"] | ["become"] | ["break"] | ["byte"] | ["class"] | ["clear"] |
            ["const"] | ["continue"] | ["do"] | ["else"] | ["enum"] | ["eval"] | ["export"] |
            ["extern"] | ["false"] | ["final"] | ["fn"] | ["for"] | ["if"] | ["impl"] | ["import"] |
            ["in"] | ["let"] | ["loop"] | ["match"] | ["mod"] | ["move"] | ["mut"] | ["of"] |
            ["out"] | ["pub"] | ["raw"] | ["ref"] | ["return"] | ["self"] | ["static"] |
            ["struct"] | ["super"] | ["trait"] | ["true"] | ["typeof"] | ["type"] | ["unsafe"] |
            ["use"] | ["where"] | ["while"] | ["yield"]
        }

        // These are separate rules because we can use the generated rules and tokens to provide
        // better error messages
        comma = { [","] }
        semi = { [";"] }
    }
}
<|endoftext|>


<commit_before>use crate::spec::{FramePointer, RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
    TargetOptions {
        os: "freebsd".to_string(),
        dynamic_linking: true,
        executables: true,
        families: vec!["unix".to_string()],
        has_rpath: true,
        position_independent_executables: true,
        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
        relro_level: RelroLevel::Full,
        abi_return_struct_as_int: true,
        dwarf_version: Some(2),
        ..Default::default()
    }
}
<commit_msg>freebsd remove compiler workaround.<commit_after>use crate::spec::{RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
    TargetOptions {
        os: "freebsd".to_string(),
        dynamic_linking: true,
        executables: true,
        families: vec!["unix".to_string()],
        has_rpath: true,
        position_independent_executables: true,
        relro_level: RelroLevel::Full,
        abi_return_struct_as_int: true,
        dwarf_version: Some(2),
        ..Default::default()
    }
}
<|endoftext|>


<commit_before>extern crate time;

pub use self::time::{Duration, SteadyTime};

/// Useful utility for accurately measuring elapsed time.
pub struct Stopwatch {
    start_time: SteadyTime,
    end_time: SteadyTime,
    running: bool,
}

impl Stopwatch {
    pub fn new() -> Stopwatch {
        let initial_time = SteadyTime::now();

        Stopwatch {
            start_time: initial_time,
            end_time: initial_time,
            running: false,
        }
    }

    /// Retrieves the elapsed time.
    pub fn elapsed(&self) -> Duration {
        self.end_time - self.start_time
    }

    /// Stops, resets, and starts the stopwatch again.
    pub fn restart(&mut self) {
        self.reset();
        self.start();
    }

    /// Starts, or resumes, measuring elapsed time. If the stopwatch has been
    /// started and stopped before, the new results are compounded onto the
    /// existing elapsed time value.
    ///
    /// Note: Starting an already running stopwatch will do nothing.
    pub fn start(&mut self) {
        if !self.running {
            if self.elapsed() == Duration::seconds(0) {
                self.reset()
            }

            self.running = true;
        }
    }

    /// Stops measuring elapsed time.
    ///
    /// Note: Stopping a stopwatch that isn't running will do nothing.
    pub fn stop(&mut self) {
        if self.running {
            self.end_time = SteadyTime::now();
            self.running = false;
        }
    }

    /// Clears the current elapsed time value.
    pub fn reset(&mut self) {
        self.start_time = SteadyTime::now();
        self.end_time = self.start_time;
    }
}
<commit_msg>add engine::timing unit tests<commit_after>extern crate time;

pub use self::time::{Duration, SteadyTime};

/// Useful utility for accurately measuring elapsed time.
pub struct Stopwatch {
    start_time: SteadyTime,
    end_time: SteadyTime,
    running: bool,
}

impl Stopwatch {
    pub fn new() -> Stopwatch {
        let initial_time = SteadyTime::now();

        Stopwatch {
            start_time: initial_time,
            end_time: initial_time,
            running: false,
        }
    }

    /// Retrieves the elapsed time.
    pub fn elapsed(&self) -> Duration {
        self.end_time - self.start_time
    }

    /// Stops, resets, and starts the stopwatch again.
    pub fn restart(&mut self) {
        self.reset();
        self.start();
    }

    /// Starts, or resumes, measuring elapsed time. If the stopwatch has been
    /// started and stopped before, the new results are compounded onto the
    /// existing elapsed time value.
    ///
    /// Note: Starting an already running stopwatch will do nothing.
    pub fn start(&mut self) {
        if !self.running {
            if self.elapsed() == Duration::seconds(0) {
                self.reset()
            }

            self.running = true;
        }
    }

    /// Stops measuring elapsed time.
    ///
    /// Note: Stopping a stopwatch that isn't running will do nothing.
    pub fn stop(&mut self) {
        if self.running {
            self.end_time = SteadyTime::now();
            self.running = false;
        }
    }

    /// Clears the current elapsed time value.
    pub fn reset(&mut self) {
        self.start_time = SteadyTime::now();
        self.end_time = self.start_time;
    }
}

// Unit tests
#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::time;

    #[test]
    fn elapsed() {
        let mut watch = Stopwatch::new();

        watch.start();
        thread::sleep(time::Duration::from_secs(2));
        watch.stop();

        assert_eq!(2, watch.elapsed().num_seconds());
    }

    #[test]
    fn reset() {
        let mut watch = Stopwatch::new();

        watch.start();
        thread::sleep(time::Duration::from_secs(2));
        watch.stop();
        watch.reset();

        assert_eq!(0, watch.elapsed().num_nanoseconds().unwrap());
    }

    #[test]
    fn restart() {
        let mut watch = Stopwatch::new();

        watch.start();
        thread::sleep(time::Duration::from_secs(2));
        watch.stop();

        watch.restart();
        thread::sleep(time::Duration::from_secs(1));
        watch.stop();

        assert_eq!(1, watch.elapsed().num_seconds());
    }
}
<|endoftext|>


<commit_before>use ::bert_parser::BertTerm;
use ::bert_parser::BertTerm::*;

const INDENT_WIDTH: usize = 2;
const MAX_TERMS_PER_LINE: usize = 4;

pub fn print(term: &BertTerm, indent_level: usize) {
    match *term {
        Int(n) => {
            print!("{}", n);
        }

        BigInt(ref n) => {
            print!("{}", n);
        }

        Float(f) => {
            print!("{}", f);
        }

        Atom(ref a) => {
            print!("{}", a);
        }

        Tuple(ref terms) => {
            print_collection(terms, indent_level, '{', '}');
        }

        List(ref terms) => {
            print_collection(terms, indent_level, '[', ']');
        }

        String(ref bytes) => {
            print!("\"");
            for b in bytes {
                print!("{}", *b as char);
            }
            print!("\"");
        }

        Binary(ref bytes) => {
            if bytes.iter().all(|b| is_printable(*b)) {
                print!("<<\"");
                for b in bytes {
                    print!("{}", *b as char);
                }
                print!("\">>");
            } else {
                print!("<<");
                for b in bytes {
                    print!("{:x}", *b);
                    print!(",");
                }
                print!(">>");
            }
        }
    }
}

fn print_collection(terms: &[BertTerm], level: usize, open: char, close: char) {
    let is_single_line = print_on_single_line(terms);

    print!("{}", open);

    let mut is_first = true;
    for t in terms {
        if !is_first { print!(", "); }
        if !is_single_line {
            println!();
            indent(level + 1);
            print(t, level + 1);
        } else {
            print(t, level + 1);
        }
        is_first = false;
    }

    if !is_single_line { println!(); indent(level); }
    print!("{}", close);
}

fn indent(level: usize) {
    for _ in 0 .. level * INDENT_WIDTH {
        print!(" ");
    }
}

fn is_printable(b: u8) -> bool {
    b >= 0x20 && b <= 0x7e
}

fn is_basic(t: &BertTerm) -> bool {
    match *t {
        Int(_) | BigInt(_) | Float(_) | Atom(_) | String(_) | Binary(_) => true,
        List(_) | Tuple(_) => false
    }
}

fn print_on_single_line(terms: &[BertTerm]) -> bool {
    terms.len() <= MAX_TERMS_PER_LINE &&
        terms.iter().all(is_basic)
}
<commit_msg>Print binary bytes in decimal form<commit_after>use ::bert_parser::BertTerm;
use ::bert_parser::BertTerm::*;

const INDENT_WIDTH: usize = 2;
const MAX_TERMS_PER_LINE: usize = 4;

pub fn print(term: &BertTerm, indent_level: usize) {
    match *term {
        Int(n) => {
            print!("{}", n);
        }

        BigInt(ref n) => {
            print!("{}", n);
        }

        Float(f) => {
            print!("{}", f);
        }

        Atom(ref a) => {
            print!("{}", a);
        }

        Tuple(ref terms) => {
            print_collection(terms, indent_level, '{', '}');
        }

        List(ref terms) => {
            print_collection(terms, indent_level, '[', ']');
        }

        String(ref bytes) => {
            print!("\"");
            for b in bytes {
                print!("{}", *b as char);
            }
            print!("\"");
        }

        Binary(ref bytes) => {
            if bytes.iter().all(|b| is_printable(*b)) {
                print!("<<\"");
                for b in bytes {
                    print!("{}", *b as char);
                }
                print!("\">>");
            } else {
                print!("<<");
                for b in bytes {
                    print!("{}", *b);
                    print!(",");
                }
                print!(">>");
            }
        }
    }
}

fn print_collection(terms: &[BertTerm], level: usize, open: char, close: char) {
    let is_single_line = print_on_single_line(terms);

    print!("{}", open);

    let mut is_first = true;
    for t in terms {
        if !is_first { print!(", "); }
        if !is_single_line {
            println!();
            indent(level + 1);
            print(t, level + 1);
        } else {
            print(t, level + 1);
        }
        is_first = false;
    }

    if !is_single_line { println!(); indent(level); }
    print!("{}", close);
}

fn indent(level: usize) {
    for _ in 0 .. level * INDENT_WIDTH {
        print!(" ");
    }
}

fn is_printable(b: u8) -> bool {
    b >= 0x20 && b <= 0x7e
}

fn is_basic(t: &BertTerm) -> bool {
    match *t {
        Int(_) | BigInt(_) | Float(_) | Atom(_) | String(_) | Binary(_) => true,
        List(_) | Tuple(_) => false
    }
}

fn print_on_single_line(terms: &[BertTerm]) -> bool {
    terms.len() <= MAX_TERMS_PER_LINE &&
        terms.iter().all(is_basic)
}
<|endoftext|>


<commit_before>extern crate rand;

use super::structure::{Program,Condition,Command,Expression,Sensor};

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			0 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			1 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			0 => Condition::True,
			1 => Condition::False,
			2 => Condition::Not(Box::new(Condition::rand(rng))),
			3 => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			4 => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			5 => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			6 => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			7 => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			8 => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			9 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			0 => Command::Skip,
			1 => Command::Left,
			2 => Command::Right,
			3 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			0 => Expression::Constant(rng.next_f32()),
			1 => Expression::Sensor(Sensor::rand(rng)),
			2 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			3 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			4 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			5 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			0 => Sensor::X,
			1 => Sensor::Y,
			2 => Sensor::Vx,
			3 => Sensor::Vy,
			4 => Sensor::O,
			5 => Sensor::W,
			_ => panic!(),
		}
	}
}<commit_msg>Prepare for weighted random AST generation<commit_after>extern crate rand;

use super::structure::{Program,Condition,Command,Expression,Sensor};

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}<|endoftext|>


<commit_before>use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::{BufferedReader, BufferedWriter};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {
    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,
}

pub trait ReaderFile {

    fn create(&self) -> Box<File>;

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

}

impl Reader {
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: apath.clone(),
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        //self.insert(item.as_bytes());
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn create(&self) -> Box<File> {
        match File::create(&self.path) {
            Ok(file)    => box file,
            Err(..)     => { panic!("Unable to create file at {}", &self.path.display()); },
        }
    }

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

//#[test]
fn test_create_file() {
    use std::io::fs::PathExtensions;
    let reader = Reader::new(Path::new("tests/base-test-created.txt"));
    reader.create();
    let path = Path::new("tests/base-test-created.txt");
    assert!(path.is_file());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");
    Reader::new(Path::new("tests/base-test.txt"))
}
<commit_msg>Added encode and decode to ReaderFile<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {
    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,
}

pub trait ReaderFile {

    fn create(&self) -> Box<File>;

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?
}

impl Reader {
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: apath.clone(),
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        //self.insert(item.as_bytes());
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn create(&self) -> Box<File> {
        match File::create(&self.path) {
            Ok(file)    => box file,
            Err(..)     => { panic!("Unable to create file at {}", &self.path.display()); },
        }
    }

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }
}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

//#[test]
fn test_create_file() {
    use std::io::fs::PathExtensions;
    let reader = Reader::new(Path::new("tests/base-test-created.txt"));
    reader.create();
    let path = Path::new("tests/base-test-created.txt");
    assert!(path.is_file());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");
    Reader::new(Path::new("tests/base-test.txt"))
}
<|endoftext|>


<commit_before>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount
struct SumCount {
    sum_count: HashMap<u32, u32>, // key: line number, value: count
    sum_br_count: HashMap<String, Branch>, // key: function name, value: Branch
    sum_fn_count: HashMap<String, u32> // FIXME br data structure
}

// key: line_number, value: checksum value
type CheckSum = HashMap<u32, String>;

// key: function name, value: line_number
type FunctionData = HashMap<String, u32>;

struct Branch {
    block: u32,
    branch: u32,
    taken: u32
}

use std::hash:: { Hash, Hasher };
use std::cmp:: { Eq, PartialEq };
use std::fmt;

#[derive(Debug, Eq)]
struct BranchKey(u32, u32);

impl PartialEq for BranchKey {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0 && self.1 == other.1
    }
}

impl Hash for BranchKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
        self.1.hash(state);
    }
}

impl fmt::Display for BranchKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}-{}", self.0, self.1)
    }
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount,
    checksum: CheckSum,
    func: FunctionData
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                &LCOVRecord::Data(ref line_number, ref execution_count, ref checksum) => self.on_data(
                    line_number,
                    execution_count,
                    checksum,
                ),
                &LCOVRecord::FunctionName(ref line_number, ref func_name, ) => self.on_func_name(
                    func_name,
                    line_number
                ),
                &LCOVRecord::FunctionData(ref execution_count, ref func_name) => self.on_func_data(
                    func_name,
                    execution_count
                ),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                // $testcount = $testdata->{$testname};
                // $testfnccount = $testfncdata->{$testname};
                // $testbrcount = $testbrdata->{$testname};
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
    fn on_data(&mut self, line_number: &u32, execution_count: &u32, checksum: &Option<String>) {
        let mut sum_count = self.sum.sum_count.entry(line_number.clone()).or_insert(0);
        *sum_count += *execution_count;

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let mut test_count = test.test_count.entry(line_number.clone()).or_insert(0);
                *test_count += *execution_count;
            }
        }

        if checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(line_number) {
            let checksum_value = checksum.clone().unwrap();
            self.checksum.insert(line_number.clone(), checksum_value);
            return;
        }

        let checksum_value = checksum.clone().unwrap();
        let current_checksum = self.checksum.get(line_number).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &String, line_number: &u32) {
        let _ = self.func.entry(func_name.clone())
            .or_insert(line_number.clone());

        let _ = self.sum.sum_fn_count.entry(func_name.clone())
            .or_insert(0);

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
            }
        }

        if !(self.test_name.is_some() && self.test.is_some()) {
            return;
        }
        let mut test = self.test.as_mut().unwrap();
        let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
    }
    fn on_func_data(&mut self, func_name: &String, execution_count: &u32) {
        let mut sum_fn_count = self.sum.sum_fn_count.entry(func_name.clone()).or_insert(0);
        *sum_fn_count += *execution_count;

        if self.test_name.is_none() {
            return;
        }

        let mut test = self.test.as_mut().unwrap();
        let mut test_fn_count = test.test_fn_count.entry(func_name.clone()).or_insert(0);
        *test_fn_count += *execution_count;
    }
    fn on_branch_data(line_number: &u32, block_number: &u32, branch_number: &u32, taken: &u32) {

/*
        if self.sum.sum_br_count.contains_key(line_number) {
            let mut branch = self.sum.sum_br_count.get_mut(line_number).unwrap();

            if (branch.block == block_number && branch.branch == branch_number) {
            }
        } else {
            self.sum.sum_br_count.insert(line_number.clone(), Branch {
                block: block_number.clone(),
                branch: branch_number.cline(),
                taken: taken.cline()
            }
        }
*/
/*
        let mut branch = self.sum.sum_br_count.entry(line_number.clone())
            .or_insert(Branch {
                block: block_number.clone(),
                branch: branch_number.cline(),
                taken: taken.cline()
            });
*/

//BranchData(u32, u32, u32, u32),   // BRDA:<line number>,<block number>,<branch number>,<taken>

/*
        my ($line, $block, $branch, $taken) =
           ($1, $2, $3, $4);

        last if (!$br_coverage);
        $sumbrcount->{$line} =
            br_ivec_push($sumbrcount->{$line},
                     $block, $branch, $taken);

        # Add test-specific counts
        if (defined($testname)) {
            $testbrcount->{$line} =
                br_ivec_push(
                    $testbrcount->{$line},
                    $block, $branch,
                    $taken);
        }
        last;
*/

    }
}

/*
sub br_ivec_push($$$$)
{
    my ($vec, $block, $branch, $taken) = @_;
	my $offset;
	my $num = br_ivec_len($vec);
	my $i;

	$vec = "" if (!defined($vec));
	$block = $BR_VEC_MAX if $block < 0;

	# Check if branch already exists in vector
	for ($i = 0; $i < $num; $i++) {
		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
		$v_block = $BR_VEC_MAX if $v_block < 0;

		next if ($v_block != $block || $v_branch != $branch);

		# Add taken counts
		$taken = br_taken_add($taken, $v_taken);
		last;
	}

	$offset = $i * $BR_VEC_ENTRIES;
	$taken = br_taken_to_num($taken);

	# Add to vector
	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;

	return $vec;
}
*/

#[cfg(test)]
mod tests {
    use report:: { BranchKey };
    use std::collections:: { HashMap };

    #[test]
    fn branch_key() {
        let branch1 = BranchKey(1, 1);
        let branch2 = BranchKey(1, 2);
        assert!(branch1 != branch2, "branch1 = {}, branch2 = {}", branch1, branch2);

        let same_branch1 = BranchKey(1, 1);
        let same_branch2 = BranchKey(1, 1);
        assert!(same_branch1 == same_branch2, "branch1 = {}, branch2 = {}", same_branch1, same_branch2);
    }

    #[test]
    fn branch_key_as_hash_key() {
        let mut container = HashMap::new();
        container.insert(BranchKey(1, 1), 1);

        assert!( container.contains_key(&BranchKey(1, 1)) );
    }
}
<commit_msg>Remove old branch struct<commit_after>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };
use branch:: { Branch, BranchUnit };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount

struct SumCount {
    sum_count: HashMap<u32, u32>, // key: line number, value: count
    sum_br_count: HashMap<String, Branch>, // key: function name, value: Branch
    sum_fn_count: HashMap<String, u32> // FIXME br data structure
}

// key: line_number, value: checksum value
type CheckSum = HashMap<u32, String>;

// key: function name, value: line_number
type FunctionData = HashMap<String, u32>;

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount,
    checksum: CheckSum,
    func: FunctionData
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                &LCOVRecord::Data(ref line_number, ref execution_count, ref checksum) => self.on_data(
                    line_number,
                    execution_count,
                    checksum,
                ),
                &LCOVRecord::FunctionName(ref line_number, ref func_name, ) => self.on_func_name(
                    func_name,
                    line_number
                ),
                &LCOVRecord::FunctionData(ref execution_count, ref func_name) => self.on_func_data(
                    func_name,
                    execution_count
                ),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                // $testcount = $testdata->{$testname};
                // $testfnccount = $testfncdata->{$testname};
                // $testbrcount = $testbrdata->{$testname};
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
    fn on_data(&mut self, line_number: &u32, execution_count: &u32, checksum: &Option<String>) {
        let mut sum_count = self.sum.sum_count.entry(line_number.clone()).or_insert(0);
        *sum_count += *execution_count;

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let mut test_count = test.test_count.entry(line_number.clone()).or_insert(0);
                *test_count += *execution_count;
            }
        }

        if checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(line_number) {
            let checksum_value = checksum.clone().unwrap();
            self.checksum.insert(line_number.clone(), checksum_value);
            return;
        }

        let checksum_value = checksum.clone().unwrap();
        let current_checksum = self.checksum.get(line_number).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &String, line_number: &u32) {
        let _ = self.func.entry(func_name.clone())
            .or_insert(line_number.clone());

        let _ = self.sum.sum_fn_count.entry(func_name.clone())
            .or_insert(0);

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
            }
        }

        if !(self.test_name.is_some() && self.test.is_some()) {
            return;
        }
        let mut test = self.test.as_mut().unwrap();
        let _ = test.test_fn_count.entry(func_name.clone()).or_insert(0);
    }
    fn on_func_data(&mut self, func_name: &String, execution_count: &u32) {
        let mut sum_fn_count = self.sum.sum_fn_count.entry(func_name.clone()).or_insert(0);
        *sum_fn_count += *execution_count;

        if self.test_name.is_none() {
            return;
        }

        let mut test = self.test.as_mut().unwrap();
        let mut test_fn_count = test.test_fn_count.entry(func_name.clone()).or_insert(0);
        *test_fn_count += *execution_count;
    }
    fn on_branch_data(line_number: &u32, block_number: &u32, branch_number: &u32, taken: &u32) {

/*
        if self.sum.sum_br_count.contains_key(line_number) {
            let mut branch = self.sum.sum_br_count.get_mut(line_number).unwrap();

            if (branch.block == block_number && branch.branch == branch_number) {
            }
        } else {
            self.sum.sum_br_count.insert(line_number.clone(), Branch {
                block: block_number.clone(),
                branch: branch_number.cline(),
                taken: taken.cline()
            }
        }
*/
/*
        let mut branch = self.sum.sum_br_count.entry(line_number.clone())
            .or_insert(Branch {
                block: block_number.clone(),
                branch: branch_number.cline(),
                taken: taken.cline()
            });
*/

//BranchData(u32, u32, u32, u32),   // BRDA:<line number>,<block number>,<branch number>,<taken>

/*
        my ($line, $block, $branch, $taken) =
           ($1, $2, $3, $4);

        last if (!$br_coverage);
        $sumbrcount->{$line} =
            br_ivec_push($sumbrcount->{$line},
                     $block, $branch, $taken);

        # Add test-specific counts
        if (defined($testname)) {
            $testbrcount->{$line} =
                br_ivec_push(
                    $testbrcount->{$line},
                    $block, $branch,
                    $taken);
        }
        last;
*/

    }
}

/*
sub br_ivec_push($$$$)
{
    my ($vec, $block, $branch, $taken) = @_;
	my $offset;
	my $num = br_ivec_len($vec);
	my $i;

	$vec = "" if (!defined($vec));
	$block = $BR_VEC_MAX if $block < 0;

	# Check if branch already exists in vector
	for ($i = 0; $i < $num; $i++) {
		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
		$v_block = $BR_VEC_MAX if $v_block < 0;

		next if ($v_block != $block || $v_branch != $branch);

		# Add taken counts
		$taken = br_taken_add($taken, $v_taken);
		last;
	}

	$offset = $i * $BR_VEC_ENTRIES;
	$taken = br_taken_to_num($taken);

	# Add to vector
	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;

	return $vec;
}
*/
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::error::Error;
use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method};
use iron::typemap;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[derive(Show)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(iron::method::Method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H: Handler, S: Str>(&mut self, method: method::Method, glob: S, handler: H) -> &mut Router {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.insert(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice(), Box::new(handler) as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(Box::new(handler) as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }
}

impl typemap::Key for Router { type Value = Params; }

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(Box::new(NoRoute) as IronError)
        };

        req.extensions.insert::<Router>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::with(status::InternalServerError), Err(err))
        }
    }
}
<commit_msg>(fix) RFC 565 compliance (Show/String guidelines)<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::error::Error;
use std::fmt::{self, Debug};
use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method};
use iron::typemap;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[derive(Debug)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(iron::method::Method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H: Handler, S: Str>(&mut self, method: method::Method, glob: S, handler: H) -> &mut Router {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.insert(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice(), Box::new(handler) as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(Box::new(handler) as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }
}

impl typemap::Key for Router { type Value = Params; }

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(Box::new(NoRoute) as IronError)
        };

        req.extensions.insert::<Router>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::with(status::InternalServerError), Err(err))
        }
    }
}
<|endoftext|>