Skip to content

Commit

Permalink
better recovery api
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Aug 11, 2023
1 parent c654bea commit cae82cc
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 69 deletions.
5 changes: 1 addition & 4 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,7 @@ fn connect_node<'eng: 'cfg, 'cfg>(
ty::TyAstNodeContent::Declaration(decl) => Ok(NodeConnection::NextStep(
connect_declaration(engines, node, decl, graph, leaves)?,
)),
ty::TyAstNodeContent::Error(spans, _) => {
let span = Span::join_all(spans.iter().cloned());
return Err(vec![CompileError::InvalidStatement { span }]);
}
ty::TyAstNodeContent::Error(_, _) => Ok(NodeConnection::NextStep(vec![])),
}
}

Expand Down
5 changes: 1 addition & 4 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,7 @@ fn connect_node<'eng: 'cfg, 'cfg>(
exit_node,
)
}
ty::TyAstNodeContent::Error(spans, _) => {
let span = Span::join_all(spans.iter().cloned());
return Err(CompileError::InvalidStatement { span });
}
ty::TyAstNodeContent::Error(_, _) => (vec![], None),
})
}

Expand Down
7 changes: 2 additions & 5 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,11 +693,8 @@ fn const_eval_codeblock(
ty::TyAstNodeContent::SideEffect(_) => Err(ConstEvalError::CannotBeEvaluatedToConst {
span: ast_node.span.clone(),
}),
ty::TyAstNodeContent::Error(spans, _) => {
let span = Span::join_all(spans.iter().cloned());
Err(ConstEvalError::CompileError(
CompileError::InvalidStatement { span },
))
ty::TyAstNodeContent::Error(_, _) => {
unreachable!("error node found when generating IR");
}
};

Expand Down
5 changes: 2 additions & 3 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,8 @@ impl<'eng> FnCompiler<'eng> {
// a side effect can be () because it just impacts the type system/namespacing.
// There should be no new IR generated.
ty::TyAstNodeContent::SideEffect(_) => Ok(None),
ty::TyAstNodeContent::Error(spans, _) => {
let span = Span::join_all(spans.iter().cloned());
Err(CompileError::InvalidStatement { span })
ty::TyAstNodeContent::Error(_, _) => {
unreachable!("error node found when generating IR");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/language/ty/ast_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl DebugWithEngines for TyAstNode {
Expression(exp) => DebugWithEngines::fmt(exp, f, engines),
ImplicitReturnExpression(exp) => write!(f, "return {:?}", engines.help_out(exp)),
SideEffect(_) => f.write_str(""),
Error(_, err) => f.write_str("error"),
Error(_, _) => f.write_str("error"),
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ fn parse_in_memory(
submodules: Default::default(),
},
);

Ok((lexed_program, parsed::ParseProgram { kind, root }))
}

Expand Down Expand Up @@ -480,6 +481,9 @@ pub fn compile_to_ast(
metrics
);

// Fail compilation if we have errors
handler.ok()?;

let (lexed_program, mut parsed_program) = match parse_program_opt {
Ok(modules) => modules,
Err(e) => {
Expand Down Expand Up @@ -946,7 +950,6 @@ fn test_unary_ordering() {

#[test]
fn test_parser_recovery() {
use crate::language::{self, parsed};
let handler = Handler::default();
let engines = Engines::default();
let prog = parse(
Expand All @@ -962,7 +965,7 @@ fn test_parser_recovery() {
&engines,
None,
);
let (lexed, parsed) = prog.unwrap();
let (_, _) = prog.unwrap();
assert!(handler.has_errors());
dbg!(handler);
}
4 changes: 0 additions & 4 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,6 @@ pub enum CompileError {
#[error("This opcode takes an immediate value but none was provided.")]
MissingImmediate { span: Span },

#[error("This statement is invalid.")]
InvalidStatement { span: Span },

#[error("This immediate value is invalid.")]
InvalidImmediateValue { span: Span },
#[error("Variant \"{variant_name}\" does not exist on enum \"{enum_name}\"")]
Expand Down Expand Up @@ -855,7 +852,6 @@ impl Spanned for CompileError {
AbiShadowsSuperAbiMethod { span, .. } => span.clone(),
ConflictingSuperAbiMethods { span, .. } => span.clone(),
AbiSupertraitMethodCallAsContractCall { span, .. } => span.clone(),
InvalidStatement { span } => span.clone(),
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions sway-error/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,40 @@ impl Handler {
}
}

pub fn append_ref(&self, other: &Handler) {
let other = other.inner.borrow();

for warn in other.warnings.iter() {
self.emit_warn(warn.clone());
}
for err in other.errors.iter() {
self.emit_err(err.clone());
}
}

pub fn dedup(&self) {
let mut inner = self.inner.borrow_mut();
inner.errors = dedup_unsorted(inner.errors.clone());
inner.warnings = dedup_unsorted(inner.warnings.clone());
}

pub fn ok(&self) -> Result<(), ErrorEmitted> {
if !self.has_errors() {
Ok(())
} else {
Err(ErrorEmitted { _priv: () })
}
}

pub fn clear_errors(&self) {
let mut inner = self.inner.borrow_mut();
inner.errors.clear();
}

pub fn clear_warnings(&self) {
let mut inner = self.inner.borrow_mut();
inner.warnings.clear();
}
}

/// Proof that an error was emitted through a `Handler`.
Expand Down
4 changes: 4 additions & 0 deletions sway-error/src/parser_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum ParseErrorKind {
UnexpectedTokenAfterArrayIndex,
#[error("Invalid literal to use as a field name.")]
InvalidLiteralFieldName,
#[error("Invalid statement.")]
InvalidStatement,
#[error("Integer field names cannot have type suffixes.")]
IntFieldWithTypeSuffix,
#[error("Expected a field name.")]
Expand All @@ -38,6 +40,8 @@ pub enum ParseErrorKind {
MalformedAsmImmediate,
#[error("Expected an identifier.")]
ExpectedIdent,
#[error("Expected an pattern.")]
ExpectedPattern,
#[error("Unexpected token after str length.")]
UnexpectedTokenAfterStrLength,
#[error("Expected a type.")]
Expand Down
21 changes: 13 additions & 8 deletions sway-parse/src/expr/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::parser::ParseWithRecoveryResult;
use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed, Peek};

use sway_ast::brackets::{Braces, Parens, SquareBrackets};
Expand All @@ -7,7 +6,7 @@ use sway_ast::keywords::{
AbiToken, AddEqToken, AsmToken, CommaToken, ConfigurableToken, ConstToken, DivEqToken,
DoubleColonToken, EnumToken, EqToken, FalseToken, FnToken, IfToken, ImplToken, LetToken,
OpenAngleBracketToken, PubToken, SemicolonToken, ShlEqToken, ShrEqToken, StarEqToken,
StorageToken, StructToken, SubEqToken, Token, TraitToken, TrueToken, TypeToken, UseToken,
StorageToken, StructToken, SubEqToken, TraitToken, TrueToken, TypeToken, UseToken,
};
use sway_ast::literal::{LitBool, LitBoolType};
use sway_ast::punctuated::Punctuated;
Expand Down Expand Up @@ -94,8 +93,14 @@ impl Parse for Expr {

impl Parse for StatementLet {
fn parse(parser: &mut Parser) -> ParseResult<Self> {
let let_token = parser.parse()?;
let pattern = parser.try_parse()?;
let let_token: LetToken = parser.parse()?;
let pattern = parser.try_parse().map_err(|err| {
parser.emit_error_with_span(
ParseErrorKind::ExpectedPattern,
let_token.span().next_char(),
);
err
})?;
let ty_opt = match parser.take() {
Some(colon_token) => Some((colon_token, parser.parse()?)),
None => None,
Expand Down Expand Up @@ -180,10 +185,10 @@ fn parse_stmt<'a>(parser: &mut Parser<'a, '_>) -> ParseResult<StmtOrTail<'a>> {
// Try a `let` statement.
match parser.guarded_parse_with_recovery::<LetToken, StatementLet>() {
Ok(None) => {}
Ok(Some(slet)) => return stmt(Statement::Let(slet)),
Err(recovery) => {
let p = recovery.start();
let (spans, error) = recovery.finish(p);
Ok(Some(item)) => return stmt(Statement::Let(item)),
Err(r) => {
let (spans, error) =
r.recover_at_next_line_with_fallback_error(ParseErrorKind::InvalidStatement);
return stmt(Statement::Error(spans, error));
}
}
Expand Down
3 changes: 2 additions & 1 deletion sway-parse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ pub fn parse_file(
source_id: Option<SourceId>,
) -> Result<Annotated<Module>, ErrorEmitted> {
let ts = lex(handler, &src, 0, src.len(), source_id)?;
Parser::new(handler, &ts).parse_to_end().map(|(m, _)| m)
let (m, _) = Parser::new(handler, &ts).parse_to_end()?;
Ok(m)
}

pub fn parse_module_kind(
Expand Down
Loading

0 comments on commit cae82cc

Please sign in to comment.