theosirian / nanilang

Repositório para o Trabalho de Implementação de Linguagens de Programação
MIT License
3 stars 2 forks source link

[wip] Errors handling #6

Closed GChicha closed 5 years ago

GChicha commented 5 years ago

Mas para iniciar a discussão do que ajudar eu fiz uns testes do tratamento de erro, e levantei pontos que valem a pena ser pontuados:

Esse pull request pode ser descartado com tranquilidade, só quis pontuar essas coisas mesmo

andrmng commented 5 years ago

Larlpop mostra posição na stream, ok. Como é que é no vim?

Em dom, 11 de nov de 2018 01:31, Guilherme Chichanoski < notifications@github.com escreveu:

Mas para iniciar a discussão do que ajudar eu fiz uns testes do tratamento de erro, e levantei pontos que valem a pena ser pontuados:

  • O LALRPOP retorna a posição do caracter na stream então seguir um padrão de exibição de erros que seja compatível com o VIM e similares vai ser um problema já que o formato de erros deles normalmente envolvem a apresentação da linha e coluna, como no exemplo do eslint:

set errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %trror\ -\ %mset errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %tarning\ -\ %m

Saída do terminal do eslint de exemplo

/some/dir/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops) /some/dir/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi)

  • A recuperação de erros no parser é bem difícil de ser aproveitada, pensei em poucos casos:
    • Na declaração do vetor onde o valor do tamanho é diferente de um numero literal
    • Na declaração do for, sendo que não está claro agora mas a nossa gramatica da a entender que é obrigatória a inicialização e o passo do for, logo podemos recuperar da falta deles

Esse pull request pode ser descartado com tranquilidade, só quis pontuar essas coisas mesmo

You can view, comment on, or merge this pull request online at:

https://github.com/theosirian/nanilang/pull/6 Commit Summary

  • First try with errors and add coments

File Changes

Patch Links:

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/theosirian/nanilang/pull/6, or mute the thread https://github.com/notifications/unsubscribe-auth/ALsh2X2yTHfaddeXQkNrr2VV9EwUwoUUks5ut5oZgaJpZM4YYTZM .

andrmng commented 5 years ago

Ou eu sou burro(grandes chances) mas não dá pra compatibilizar posição comparando?

Em dom, 11 de nov de 2018 22:28, André Menegazzo <andremenegazzo@gmail.com escreveu:

Larlpop mostra posição na stream, ok. Como é que é no vim?

Em dom, 11 de nov de 2018 01:31, Guilherme Chichanoski < notifications@github.com escreveu:

Mas para iniciar a discussão do que ajudar eu fiz uns testes do tratamento de erro, e levantei pontos que valem a pena ser pontuados:

  • O LALRPOP retorna a posição do caracter na stream então seguir um padrão de exibição de erros que seja compatível com o VIM e similares vai ser um problema já que o formato de erros deles normalmente envolvem a apresentação da linha e coluna, como no exemplo do eslint:

set errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %trror\ -\ %mset errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %tarning\ -\ %m

Saída do terminal do eslint de exemplo

/some/dir/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops) /some/dir/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi)

  • A recuperação de erros no parser é bem difícil de ser aproveitada, pensei em poucos casos:
    • Na declaração do vetor onde o valor do tamanho é diferente de um numero literal
    • Na declaração do for, sendo que não está claro agora mas a nossa gramatica da a entender que é obrigatória a inicialização e o passo do for, logo podemos recuperar da falta deles

Esse pull request pode ser descartado com tranquilidade, só quis pontuar essas coisas mesmo

You can view, comment on, or merge this pull request online at:

https://github.com/theosirian/nanilang/pull/6 Commit Summary

  • First try with errors and add coments

File Changes

Patch Links:

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/theosirian/nanilang/pull/6, or mute the thread https://github.com/notifications/unsubscribe-auth/ALsh2X2yTHfaddeXQkNrr2VV9EwUwoUUks5ut5oZgaJpZM4YYTZM .

theosirian commented 5 years ago

Acho que dá pra contar as quebras de linha e relacionar. Só que ai precisa de uma regra se não me engano.

On Sun, Nov 11, 2018, 10:30 PM andrmng <notifications@github.com wrote:

Ou eu sou burro(grandes chances) mas não dá pra compatibilizar posição comparando?

Em dom, 11 de nov de 2018 22:28, André Menegazzo <andremenegazzo@gmail.com escreveu:

Larlpop mostra posição na stream, ok. Como é que é no vim?

Em dom, 11 de nov de 2018 01:31, Guilherme Chichanoski < notifications@github.com escreveu:

Mas para iniciar a discussão do que ajudar eu fiz uns testes do tratamento de erro, e levantei pontos que valem a pena ser pontuados:

  • O LALRPOP retorna a posição do caracter na stream então seguir um padrão de exibição de erros que seja compatível com o VIM e similares vai ser um problema já que o formato de erros deles normalmente envolvem a apresentação da linha e coluna, como no exemplo do eslint:

set errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %trror\ -\ %mset errorformat+=%f:\ line\ %l\,\ col\ %c\,\ %tarning\ -\ %m

Saída do terminal do eslint de exemplo

/some/dir/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops) /some/dir/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi)

  • A recuperação de erros no parser é bem difícil de ser aproveitada, pensei em poucos casos:
  • Na declaração do vetor onde o valor do tamanho é diferente de um numero literal
  • Na declaração do for, sendo que não está claro agora mas a nossa gramatica da a entender que é obrigatória a inicialização e o passo do for, logo podemos recuperar da falta deles

Esse pull request pode ser descartado com tranquilidade, só quis pontuar essas coisas mesmo

You can view, comment on, or merge this pull request online at:

https://github.com/theosirian/nanilang/pull/6 Commit Summary

  • First try with errors and add coments

File Changes

Patch Links:

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/theosirian/nanilang/pull/6, or mute the thread < https://github.com/notifications/unsubscribe-auth/ALsh2X2yTHfaddeXQkNrr2VV9EwUwoUUks5ut5oZgaJpZM4YYTZM

.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/theosirian/nanilang/pull/6#issuecomment-437720496, or mute the thread https://github.com/notifications/unsubscribe-auth/AEDT3lMWWET8XK7uCQ6QOz0DqLsOOy8Cks5uuMFCgaJpZM4YYTZM .

GChicha commented 5 years ago

Acho que no tutorial do lalr tem aquela parte de retornar os tokens de espaço e tabs, dá para fazer algo semelhante para mudar o retorno do Location para uma tupla com linha e coluna, amanhã tento fazer isso ou forneço mais informações quanto a viabilidade

GChicha commented 5 years ago

Como disse no tutorial do LALR tem como fazer um lexer custom, só que é bem dificil seguindo o tutorial dele como está ali.

Fui ver o código do LALRPOP e acho que dá para aproveitar o código do parser gerado, pello que vi o que teria de ser rescrito/editado seria a parte do matcher:

pub use self::__parse__Program::ProgramParser;
#[cfg_attr(rustfmt, rustfmt_skip)]
mod __intern_token {
    #![allow(unused_imports)]
    use lalrpop_util::{ ErrorRecovery, ParseError };
    use std::str::FromStr;
    use ast::*;
    #[allow(unused_extern_crates)]
    extern crate lalrpop_util as __lalrpop_util;
    extern crate regex as __regex;
    use std::fmt as __fmt;

    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
    pub struct Token<'input>(pub usize, pub &'input str);
    impl<'a> __fmt::Display for Token<'a> {
        fn fmt(&self, formatter: &mut __fmt::Formatter) -> Result<(), __fmt::Error> {
            __fmt::Display::fmt(self.1, formatter)
        }
    }

    pub struct __MatcherBuilder {
        regex_set: __regex::RegexSet,
        regex_vec: Vec<__regex::Regex>,
    }

    impl __MatcherBuilder {
        pub fn new() -> __MatcherBuilder {
            let __strs: &[&str] = &[
                "^([0-9]+)",
                "^([A-Z_a-z][0-9A-Z_a-z]*)",
                "^((let|var))",
                "^((skip|continue))",
                "^((stop|break))",
                "^(!)",
                "^(%)",
                "^(\\&)",
                "^(\\()",
                "^(\\))",
                "^(\\*)",
                "^(\\+)",
                "^(,)",
                "^(\\-)",
                "^(/)",
                "^(:)",
                "^(;)",
                "^(<)",
                "^(=)",
                "^(>)",
                "^(\\?)",
                "^(\\[)",
                "^(\\])",
                "^(bool)",
                "^(def)",
                "^(else)",
                "^(false)",
                "^(for)",
                "^(if)",
                "^(int)",
                "^(read)",
                "^(return)",
                "^(str)",
                "^(true)",
                "^(while)",
                "^(write)",
                "^(\\{)",
                "^(\\|)",
                "^(\\})",
            ];
            let __regex_set = __regex::RegexSet::new(__strs).unwrap();
            let __regex_vec = vec![
                __regex::Regex::new("^([0-9]+)").unwrap(),
                __regex::Regex::new("^([A-Z_a-z][0-9A-Z_a-z]*)").unwrap(),
                __regex::Regex::new("^((let|var))").unwrap(),
                __regex::Regex::new("^((skip|continue))").unwrap(),
                __regex::Regex::new("^((stop|break))").unwrap(),
                __regex::Regex::new("^(!)").unwrap(),
                __regex::Regex::new("^(%)").unwrap(),
                __regex::Regex::new("^(\\&)").unwrap(),
                __regex::Regex::new("^(\\()").unwrap(),
                __regex::Regex::new("^(\\))").unwrap(),
                __regex::Regex::new("^(\\*)").unwrap(),
                __regex::Regex::new("^(\\+)").unwrap(),
                __regex::Regex::new("^(,)").unwrap(),
                __regex::Regex::new("^(\\-)").unwrap(),
                __regex::Regex::new("^(/)").unwrap(),
                __regex::Regex::new("^(:)").unwrap(),
                __regex::Regex::new("^(;)").unwrap(),
                __regex::Regex::new("^(<)").unwrap(),
                __regex::Regex::new("^(=)").unwrap(),
                __regex::Regex::new("^(>)").unwrap(),
                __regex::Regex::new("^(\\?)").unwrap(),
                __regex::Regex::new("^(\\[)").unwrap(),
                __regex::Regex::new("^(\\])").unwrap(),
                __regex::Regex::new("^(bool)").unwrap(),
                __regex::Regex::new("^(def)").unwrap(),
                __regex::Regex::new("^(else)").unwrap(),
                __regex::Regex::new("^(false)").unwrap(),
                __regex::Regex::new("^(for)").unwrap(),
                __regex::Regex::new("^(if)").unwrap(),
                __regex::Regex::new("^(int)").unwrap(),
                __regex::Regex::new("^(read)").unwrap(),
                __regex::Regex::new("^(return)").unwrap(),
                __regex::Regex::new("^(str)").unwrap(),
                __regex::Regex::new("^(true)").unwrap(),
                __regex::Regex::new("^(while)").unwrap(),
                __regex::Regex::new("^(write)").unwrap(),
                __regex::Regex::new("^(\\{)").unwrap(),
                __regex::Regex::new("^(\\|)").unwrap(),
                __regex::Regex::new("^(\\})").unwrap(),
            ];
            __MatcherBuilder { regex_set: __regex_set, regex_vec: __regex_vec }
        }
        pub fn matcher<'input, 'builder>(&'builder self, s: &'input str) -> __Matcher<'input, 'builder> {
            __Matcher {
                text: s,
                consumed: 0,
                regex_set: &self.regex_set,
                regex_vec: &self.regex_vec,
            }
        }
    }

    pub struct __Matcher<'input, 'builder> {
        text: &'input str,
        consumed: usize,
        regex_set: &'builder __regex::RegexSet,
        regex_vec: &'builder Vec<__regex::Regex>,
    }

    impl<'input, 'builder> Iterator for __Matcher<'input, 'builder> {
        type Item = Result<(usize, Token<'input>, usize), __lalrpop_util::ParseError<usize,Token<'input>,&'static str>>;

        fn next(&mut self) -> Option<Self::Item> {
            let __text = self.text.trim_left();
            let __whitespace = self.text.len() - __text.len();
            let __start_offset = self.consumed + __whitespace;
            if __text.is_empty() {
                self.text = __text;
                self.consumed = __start_offset;
                None
            } else {
                let __matches = self.regex_set.matches(__text);
                if !__matches.matched_any() {
                    Some(Err(__lalrpop_util::ParseError::InvalidToken {
                        location: __start_offset,
                    }))
                } else {
                    let mut __longest_match = 0;
                    let mut __index = 0;
                    for __i in 0 .. 39 {
                        if __matches.matched(__i) {
                            let __match = self.regex_vec[__i].find(__text).unwrap();
                            let __len = __match.end();
                            if __len >= __longest_match {
                                __longest_match = __len;
                                __index = __i;
                            }
                        }
                    }
                    let __result = &__text[..__longest_match];
                    let __remaining = &__text[__longest_match..];
                    let __end_offset = __start_offset + __longest_match;
                    self.text = __remaining;
                    self.consumed = __end_offset;
                    Some(Ok((__start_offset, Token(__index, __result), __end_offset)))
                }
            }
        }
    }
}

Sendo um pouco mais especifico a parte que deveria ser editada seria no inicio do metodo next onde tem um trim left, e mais umas coisinhas para contar corretamente a coluna do caracter.

Quando sobrar tempo tento simplesmente separar essa parte em um arquivo e ver oque sai.

GChicha commented 5 years ago

Tudo que foi discutido aqui não teve importância já que o caminho tomado foi do uso do codespan