mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-31 07:38:02 +00:00
Merge branch 'main' into pr/320
This commit is contained in:
commit
924b22a171
91 changed files with 1836 additions and 1027 deletions
|
@ -1004,6 +1004,15 @@ impl_nested_display_for_enum!(RecordAttrOrIdent; Attr, Ident);
|
|||
impl_display_for_enum!(RecordAttrOrIdent; Attr, Ident);
|
||||
impl_locational_for_enum!(RecordAttrOrIdent; Attr, Ident);
|
||||
|
||||
impl RecordAttrOrIdent {
|
||||
pub fn ident(&self) -> Option<&Identifier> {
|
||||
match self {
|
||||
Self::Attr(attr) => attr.sig.ident(),
|
||||
Self::Ident(ident) => Some(ident),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NormalSet {
|
||||
pub l_brace: Token,
|
||||
|
|
|
@ -4,7 +4,7 @@ use erg_common::Str;
|
|||
|
||||
use crate::ast::AST;
|
||||
use crate::desugar::Desugarer;
|
||||
use crate::error::{ParserRunnerError, ParserRunnerErrors};
|
||||
use crate::error::{CompleteArtifact, IncompleteArtifact, ParserRunnerError, ParserRunnerErrors};
|
||||
use crate::parse::ParserRunner;
|
||||
|
||||
/// Summarize parsing and desugaring
|
||||
|
@ -45,31 +45,55 @@ impl Runnable for ASTBuilder {
|
|||
|
||||
fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
|
||||
let src = self.cfg_mut().input.read();
|
||||
let ast = self.build(src)?;
|
||||
println!("{ast}");
|
||||
let artifact = self.build(src).map_err(|iart| iart.errors)?;
|
||||
println!("{}", artifact.ast);
|
||||
Ok(ExitStatus::OK)
|
||||
}
|
||||
|
||||
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {
|
||||
let ast = self.build(src)?;
|
||||
Ok(format!("{ast}"))
|
||||
let artifact = self.build(src).map_err(|iart| iart.errors)?;
|
||||
Ok(format!("{}", artifact.ast))
|
||||
}
|
||||
}
|
||||
|
||||
impl ASTBuilder {
|
||||
pub fn build(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||
let module = self.runner.parse(src)?;
|
||||
pub fn build(
|
||||
&mut self,
|
||||
src: String,
|
||||
) -> Result<
|
||||
CompleteArtifact<AST, ParserRunnerErrors>,
|
||||
IncompleteArtifact<AST, ParserRunnerErrors>,
|
||||
> {
|
||||
let name = Str::rc(self.runner.cfg().input.unescaped_filename());
|
||||
let artifact = self
|
||||
.runner
|
||||
.parse(src)
|
||||
.map_err(|iart| iart.map_mod(|module| AST::new(name.clone(), module)))?;
|
||||
let mut desugarer = Desugarer::new();
|
||||
let module = desugarer.desugar(module);
|
||||
let name = self.runner.cfg().input.unescaped_filename();
|
||||
let ast = AST::new(Str::rc(name), module);
|
||||
Ok(ast)
|
||||
let module = desugarer.desugar(artifact.ast);
|
||||
let ast = AST::new(name, module);
|
||||
Ok(CompleteArtifact::new(
|
||||
ast,
|
||||
ParserRunnerErrors::convert(self.input(), artifact.warns),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn build_without_desugaring(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||
let module = self.runner.parse(src)?;
|
||||
let name = self.runner.cfg().input.unescaped_filename();
|
||||
let ast = AST::new(Str::rc(name), module);
|
||||
Ok(ast)
|
||||
pub fn build_without_desugaring(
|
||||
&mut self,
|
||||
src: String,
|
||||
) -> Result<
|
||||
CompleteArtifact<AST, ParserRunnerErrors>,
|
||||
IncompleteArtifact<AST, ParserRunnerErrors>,
|
||||
> {
|
||||
let name = Str::rc(self.runner.cfg().input.unescaped_filename());
|
||||
let artifact = self
|
||||
.runner
|
||||
.parse(src)
|
||||
.map_err(|iart| iart.map_mod(|module| AST::new(name.clone(), module)))?;
|
||||
let ast = AST::new(name, artifact.ast);
|
||||
Ok(CompleteArtifact::new(
|
||||
ast,
|
||||
ParserRunnerErrors::convert(self.input(), artifact.warns),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
//! パーサーが出すエラーを定義
|
||||
use std::fmt;
|
||||
|
||||
use erg_common::config::Input;
|
||||
use erg_common::error::{
|
||||
ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage,
|
||||
};
|
||||
use erg_common::style::{Attribute, Color, StyledStr, StyledStrings, THEME};
|
||||
use erg_common::io::Input;
|
||||
use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, THEME};
|
||||
use erg_common::traits::Stream;
|
||||
use erg_common::{fmt_iter, fmt_vec_split_with, impl_display_and_error, impl_stream, switch_lang};
|
||||
|
||||
use crate::ast::Module;
|
||||
use crate::token::TokenKind;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -50,6 +51,7 @@ impl fmt::Display for LexErrors {
|
|||
impl std::error::Error for LexErrors {}
|
||||
|
||||
const ERR: Color = THEME.colors.error;
|
||||
const WARN: Color = THEME.colors.warning;
|
||||
const HINT: Color = THEME.colors.hint;
|
||||
#[cfg(not(feature = "pretty"))]
|
||||
const ATTR: Attribute = Attribute::Bold;
|
||||
|
@ -534,12 +536,30 @@ impl LexError {
|
|||
);
|
||||
Self::syntax_error(errno, loc, msg, None)
|
||||
}
|
||||
|
||||
pub fn duplicate_elem_warning(errno: usize, loc: Location, elem: String) -> Self {
|
||||
let elem = StyledString::new(elem, Some(WARN), Some(Attribute::Underline));
|
||||
Self::new(ErrorCore::new(
|
||||
vec![SubMessage::only_loc(loc)],
|
||||
switch_lang!(
|
||||
"japanese" => format!("重複する要素です: {elem}"),
|
||||
"simplified_chinese" => format!("{elem}"),
|
||||
"traditional_chinese" => format!("{elem}"),
|
||||
"english" => format!("duplicated element: {elem}"),
|
||||
),
|
||||
errno,
|
||||
SyntaxWarning,
|
||||
loc,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub type LexResult<T> = Result<T, LexError>;
|
||||
|
||||
pub type ParseError = LexError;
|
||||
pub type ParseErrors = LexErrors;
|
||||
pub type ParseWarning = LexError;
|
||||
pub type ParseWarnings = LexErrors;
|
||||
pub type ParseResult<T> = Result<T, ()>;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -618,4 +638,71 @@ pub type ParserRunnerResult<T> = Result<T, ParserRunnerError>;
|
|||
|
||||
pub type LexerRunnerError = ParserRunnerError;
|
||||
pub type LexerRunnerErrors = ParserRunnerErrors;
|
||||
pub type ParserRunnerWarning = ParserRunnerError;
|
||||
pub type ParserRunnerWarnings = ParserRunnerErrors;
|
||||
pub type LexerRunnerResult<T> = Result<T, LexerRunnerError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompleteArtifact<A = Module, Es = ParseErrors> {
|
||||
pub ast: A,
|
||||
pub warns: Es,
|
||||
}
|
||||
|
||||
impl<A, Es> CompleteArtifact<A, Es> {
|
||||
pub fn new(ast: A, warns: Es) -> Self {
|
||||
Self { ast, warns }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IncompleteArtifact<A = Module, Es = ParseErrors> {
|
||||
pub ast: Option<A>,
|
||||
pub warns: Es,
|
||||
pub errors: Es,
|
||||
}
|
||||
|
||||
impl<A> From<ParserRunnerErrors> for IncompleteArtifact<A, ParserRunnerErrors> {
|
||||
fn from(value: ParserRunnerErrors) -> IncompleteArtifact<A, ParserRunnerErrors> {
|
||||
IncompleteArtifact::new(None, ParserRunnerErrors::empty(), value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> From<LexErrors> for IncompleteArtifact<A, ParseErrors> {
|
||||
fn from(value: LexErrors) -> IncompleteArtifact<A, ParseErrors> {
|
||||
IncompleteArtifact::new(None, ParseErrors::empty(), value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, Es> IncompleteArtifact<A, Es> {
|
||||
pub fn new(ast: Option<A>, warns: Es, errors: Es) -> Self {
|
||||
Self { ast, warns, errors }
|
||||
}
|
||||
|
||||
pub fn map_errs<U>(self, f: impl Fn(Es) -> U) -> IncompleteArtifact<A, U> {
|
||||
IncompleteArtifact {
|
||||
ast: self.ast,
|
||||
warns: f(self.warns),
|
||||
errors: f(self.errors),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_mod<U>(self, f: impl Fn(A) -> U) -> IncompleteArtifact<U, Es> {
|
||||
IncompleteArtifact {
|
||||
ast: self.ast.map(f),
|
||||
warns: self.warns,
|
||||
errors: self.errors,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ErrorArtifact<Es = ParseErrors> {
|
||||
pub warns: Es,
|
||||
pub errors: Es,
|
||||
}
|
||||
|
||||
impl<Es> ErrorArtifact<Es> {
|
||||
pub fn new(warns: Es, errors: Es) -> ErrorArtifact<Es> {
|
||||
Self { warns, errors }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use unicode_xid::UnicodeXID;
|
|||
|
||||
use erg_common::cache::CacheSet;
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::config::Input;
|
||||
use erg_common::io::Input;
|
||||
use erg_common::traits::DequeStream;
|
||||
use erg_common::traits::{Locational, Runnable, Stream};
|
||||
use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang};
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use std::mem;
|
||||
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::config::{Input, InputKind};
|
||||
use erg_common::error::Location;
|
||||
use erg_common::io::{Input, InputKind};
|
||||
use erg_common::set::Set as HashSet;
|
||||
use erg_common::str::Str;
|
||||
use erg_common::traits::{DequeStream, ExitStatus, Locational, Runnable, Stream};
|
||||
|
@ -17,7 +17,10 @@ use erg_common::{
|
|||
|
||||
use crate::ast::*;
|
||||
use crate::desugar::Desugarer;
|
||||
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
||||
use crate::error::{
|
||||
CompleteArtifact, IncompleteArtifact, ParseError, ParseErrors, ParseResult, ParserRunnerError,
|
||||
ParserRunnerErrors,
|
||||
};
|
||||
use crate::lex::Lexer;
|
||||
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
||||
|
||||
|
@ -96,13 +99,13 @@ macro_rules! expect_pop {
|
|||
}
|
||||
|
||||
pub trait Parsable {
|
||||
fn parse(code: String) -> Result<Module, ParseErrors>;
|
||||
fn parse(code: String) -> Result<CompleteArtifact, IncompleteArtifact<Module, ParseErrors>>;
|
||||
}
|
||||
|
||||
pub struct SimpleParser {}
|
||||
|
||||
impl Parsable for SimpleParser {
|
||||
fn parse(code: String) -> Result<Module, ParseErrors> {
|
||||
fn parse(code: String) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
let ts = Lexer::from_str(code).lex()?;
|
||||
let mut parser = Parser::new(ts);
|
||||
parser.parse()
|
||||
|
@ -416,59 +419,77 @@ impl Runnable for ParserRunner {
|
|||
|
||||
fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
|
||||
let src = self.cfg_mut().input.read();
|
||||
let ast = self.parse(src)?;
|
||||
println!("{ast}");
|
||||
let artifact = self.parse(src).map_err(|iart| iart.errors)?;
|
||||
println!("{}", artifact.ast);
|
||||
Ok(ExitStatus::OK)
|
||||
}
|
||||
|
||||
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {
|
||||
let ast = self.parse(src)?;
|
||||
Ok(format!("{ast}"))
|
||||
let artifact = self.parse(src).map_err(|iart| iart.errors)?;
|
||||
Ok(format!("{}", artifact.ast))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParserRunner {
|
||||
pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result<Module, ParserRunnerErrors> {
|
||||
pub fn parse_token_stream(
|
||||
&mut self,
|
||||
ts: TokenStream,
|
||||
) -> Result<CompleteArtifact, IncompleteArtifact<Module, ParserRunnerErrors>> {
|
||||
Parser::new(ts)
|
||||
.parse()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
||||
.map_err(|iart| iart.map_errs(|errs| ParserRunnerErrors::convert(self.input(), errs)))
|
||||
}
|
||||
|
||||
pub fn parse(&mut self, src: String) -> Result<Module, ParserRunnerErrors> {
|
||||
pub fn parse(
|
||||
&mut self,
|
||||
src: String,
|
||||
) -> Result<CompleteArtifact, IncompleteArtifact<Module, ParserRunnerErrors>> {
|
||||
let ts = Lexer::new(Input::new(InputKind::Str(src), self.cfg.input.id()))
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||
Parser::new(ts)
|
||||
.parse()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
||||
.map_err(|iart| iart.map_errs(|errs| ParserRunnerErrors::convert(self.input(), errs)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn parse(&mut self) -> Result<Module, ParseErrors> {
|
||||
pub fn parse(&mut self) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
if self.tokens.is_empty() {
|
||||
return Ok(Module::empty());
|
||||
return Ok(CompleteArtifact::new(Module::empty(), ParseErrors::empty()));
|
||||
}
|
||||
log!(info "the parsing process has started.");
|
||||
log!(info "token stream: {}", self.tokens);
|
||||
let module = match self.try_reduce_module() {
|
||||
Ok(module) => module,
|
||||
Err(_) => {
|
||||
return Err(mem::take(&mut self.errs));
|
||||
return Err(IncompleteArtifact::new(
|
||||
None,
|
||||
mem::take(&mut self.warns),
|
||||
mem::take(&mut self.errs),
|
||||
));
|
||||
}
|
||||
};
|
||||
if !self.cur_is(EOF) {
|
||||
let loc = self.peek().map(|t| t.loc()).unwrap_or_default();
|
||||
self.errs
|
||||
.push(ParseError::compiler_bug(0, loc, fn_name!(), line!()));
|
||||
return Err(mem::take(&mut self.errs));
|
||||
return Err(IncompleteArtifact::new(
|
||||
Some(module),
|
||||
mem::take(&mut self.warns),
|
||||
mem::take(&mut self.errs),
|
||||
));
|
||||
}
|
||||
log!(info "the parsing process has completed (errs: {}).", self.errs.len());
|
||||
log!(info "AST:\n{module}");
|
||||
if self.errs.is_empty() {
|
||||
Ok(module)
|
||||
Ok(CompleteArtifact::new(module, mem::take(&mut self.warns)))
|
||||
} else {
|
||||
Err(mem::take(&mut self.errs))
|
||||
Err(IncompleteArtifact::new(
|
||||
Some(module),
|
||||
mem::take(&mut self.warns),
|
||||
mem::take(&mut self.errs),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2839,6 +2860,17 @@ impl Parser {
|
|||
})?;
|
||||
match next {
|
||||
Expr::Def(def) => {
|
||||
if attrs.iter().any(|attr| {
|
||||
attr.ident()
|
||||
.zip(def.sig.ident())
|
||||
.is_some_and(|(l, r)| l == r)
|
||||
}) {
|
||||
self.warns.push(ParseError::duplicate_elem_warning(
|
||||
line!() as usize,
|
||||
def.sig.loc(),
|
||||
def.sig.to_string(),
|
||||
));
|
||||
}
|
||||
attrs.push(RecordAttrOrIdent::Attr(def));
|
||||
}
|
||||
Expr::Accessor(acc) => {
|
||||
|
|
|
@ -1,83 +1,97 @@
|
|||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::consts::DEBUG_MODE;
|
||||
use erg_common::error::MultiErrorDisplay;
|
||||
use erg_common::io::Input;
|
||||
use erg_common::spawn::exec_new_thread;
|
||||
use erg_common::traits::{Runnable, Stream};
|
||||
|
||||
use erg_parser::error::ParserRunnerErrors;
|
||||
use erg_parser::error::{ErrorArtifact, ParseWarnings, ParserRunnerErrors};
|
||||
use erg_parser::lex::Lexer;
|
||||
use erg_parser::ParserRunner;
|
||||
|
||||
#[test]
|
||||
fn parse_args() -> Result<(), ()> {
|
||||
expect_success("tests/args.er")
|
||||
expect_success("tests/args.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_containers() -> Result<(), ()> {
|
||||
expect_success("tests/containers.er")
|
||||
expect_success("tests/containers.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dependent() -> Result<(), ()> {
|
||||
expect_success("tests/dependent.er")
|
||||
expect_success("tests/dependent.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_fib() -> Result<(), ()> {
|
||||
expect_success("tests/fib.er")
|
||||
expect_success("tests/fib.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_hello_world() -> Result<(), ()> {
|
||||
expect_success("tests/hello_world.er")
|
||||
expect_success("tests/hello_world.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_simple_if() -> Result<(), ()> {
|
||||
expect_success("tests/simple_if.er")
|
||||
expect_success("tests/simple_if.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_stream() -> Result<(), ()> {
|
||||
expect_success("tests/stream.er")
|
||||
expect_success("tests/stream.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_test1_basic_syntax() -> Result<(), ()> {
|
||||
expect_success("tests/test1_basic_syntax.er")
|
||||
expect_success("tests/test1_basic_syntax.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_test2_advanced_syntax() -> Result<(), ()> {
|
||||
expect_success("tests/test2_advanced_syntax.er")
|
||||
expect_success("tests/test2_advanced_syntax.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_stack() -> Result<(), ()> {
|
||||
expect_failure("tests/stack.er", 2)
|
||||
expect_failure("tests/stack.er", 0, 2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_str_literal() -> Result<(), ()> {
|
||||
expect_failure("tests/failed_str_lit.er", 2)
|
||||
expect_failure("tests/failed_str_lit.er", 0, 2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_chunk() -> Result<(), ()> {
|
||||
expect_failure("tests/invalid_chunk.er", 62)
|
||||
expect_failure("tests/invalid_chunk.er", 0, 62)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_collections() -> Result<(), ()> {
|
||||
expect_failure("tests/invalid_collections.er", 29)
|
||||
expect_failure("tests/invalid_collections.er", 0, 29)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_class_definition() -> Result<(), ()> {
|
||||
expect_failure("tests/invalid_class_definition.er", 7)
|
||||
expect_failure("tests/invalid_class_definition.er", 0, 7)
|
||||
}
|
||||
|
||||
fn _parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerErrors> {
|
||||
#[test]
|
||||
fn exec_invalid_chunk_prs_err() -> Result<(), ()> {
|
||||
expect_failure("tests/invalid_chunk.er", 0, 62)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_warns() -> Result<(), ()> {
|
||||
expect_success("tests/warns.er", 1)
|
||||
}
|
||||
|
||||
fn _parse_test_from_code(
|
||||
file_path: &'static str,
|
||||
) -> Result<ParseWarnings, ErrorArtifact<ParserRunnerErrors>> {
|
||||
let input = Input::file(file_path.into());
|
||||
let cfg = ErgConfig {
|
||||
input: input.clone(),
|
||||
|
@ -86,43 +100,81 @@ fn _parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerErro
|
|||
};
|
||||
let lexer = Lexer::new(input.clone());
|
||||
let mut parser = ParserRunner::new(cfg);
|
||||
match parser.parse_token_stream(
|
||||
lexer
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(&input, errs))?,
|
||||
) {
|
||||
Ok(module) => {
|
||||
println!("{module}");
|
||||
Ok(())
|
||||
match parser.parse_token_stream(lexer.lex().map_err(|errs| {
|
||||
ErrorArtifact::new(
|
||||
ParserRunnerErrors::empty(),
|
||||
ParserRunnerErrors::convert(&input, errs),
|
||||
)
|
||||
})?) {
|
||||
Ok(artifact) => {
|
||||
if DEBUG_MODE {
|
||||
println!("{}", artifact.ast);
|
||||
}
|
||||
Ok(artifact.warns)
|
||||
}
|
||||
Err(e) => {
|
||||
e.fmt_all_stderr();
|
||||
Err(e)
|
||||
Err(artifact) => {
|
||||
if DEBUG_MODE {
|
||||
artifact.warns.write_all_stderr();
|
||||
artifact.errors.write_all_stderr();
|
||||
}
|
||||
Err(ErrorArtifact::new(artifact.warns, artifact.errors))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerErrors> {
|
||||
fn parse_test_from_code(
|
||||
file_path: &'static str,
|
||||
) -> Result<ParseWarnings, ErrorArtifact<ParserRunnerErrors>> {
|
||||
exec_new_thread(move || _parse_test_from_code(file_path), file_path)
|
||||
}
|
||||
|
||||
fn expect_success(file_path: &'static str) -> Result<(), ()> {
|
||||
fn expect_success(file_path: &'static str, num_warns: usize) -> Result<(), ()> {
|
||||
match parse_test_from_code(file_path) {
|
||||
Ok(_) => Ok(()),
|
||||
Ok(warns) => {
|
||||
if warns.len() == num_warns {
|
||||
Ok(())
|
||||
} else {
|
||||
println!(
|
||||
"err: number of warnings is not {num_warns} but {}",
|
||||
warns.len()
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_failure(file_path: &'static str, errs_len: usize) -> Result<(), ()> {
|
||||
fn expect_failure(file_path: &'static str, num_warns: usize, num_errs: usize) -> Result<(), ()> {
|
||||
match parse_test_from_code(file_path) {
|
||||
Ok(_) => Err(()),
|
||||
Err(errs) => {
|
||||
if errs.len() == errs_len {
|
||||
Ok(())
|
||||
} else {
|
||||
println!("err: error length is not {errs_len} but {}", errs.len());
|
||||
Err(eart) => match (eart.errors.len() == num_errs, eart.warns.len() == num_warns) {
|
||||
(true, true) => Ok(()),
|
||||
(true, false) => {
|
||||
println!(
|
||||
"err: number of warnings is not {num_warns} but {}",
|
||||
eart.warns.len()
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
(false, true) => {
|
||||
println!(
|
||||
"err: number of errors is not {num_errs} but {}",
|
||||
eart.errors.len()
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
(false, false) => {
|
||||
println!(
|
||||
"err: number of warnings is not {num_warns} but {}",
|
||||
eart.warns.len()
|
||||
);
|
||||
println!(
|
||||
"err: number of errors is not {num_errs} but {}",
|
||||
eart.errors.len()
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::iter::Iterator;
|
||||
|
||||
use erg_common::config::Input;
|
||||
use erg_common::io::Input;
|
||||
|
||||
// use erg_compiler::parser;
|
||||
|
||||
|
|
1
crates/erg_parser/tests/warns.er
Normal file
1
crates/erg_parser/tests/warns.er
Normal file
|
@ -0,0 +1 @@
|
|||
_ = { .foo = 1; .foo = 1 } # WARN
|
Loading…
Add table
Add a link
Reference in a new issue