Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: impl all parse error recovery with panic mode and add more unit test cases #460

Merged
merged 1 commit into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 41 additions & 11 deletions kclvm/ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@ impl TryInto<Node<Identifier>> for Node<Expr> {
}
}

impl Node<Expr> {
/// Into a missing identifier.
pub fn into_missing_identifier(&self) -> Node<Identifier> {
Node {
node: Identifier {
names: vec![],
pkgpath: String::new(),
ctx: ExprContext::Load,
},
filename: self.filename.clone(),
line: self.line,
column: self.column,
end_line: self.end_line,
end_column: self.end_column,
}
}
}

impl TryInto<Node<SchemaExpr>> for Node<Expr> {
type Error = &'static str;

Expand Down Expand Up @@ -418,7 +436,9 @@ impl SchemaStmt {
fn loop_body(body: &[NodeRef<Stmt>], attr_list: &mut Vec<(u64, u64, String)>) {
for stmt in body {
match &stmt.node {
Stmt::Unification(unification_stmt) => {
Stmt::Unification(unification_stmt)
if !unification_stmt.target.node.names.is_empty() =>
{
attr_list.push((
unification_stmt.target.line,
unification_stmt.target.column,
Expand All @@ -427,19 +447,23 @@ impl SchemaStmt {
}
Stmt::Assign(assign_stmt) => {
for target in &assign_stmt.targets {
attr_list.push((
target.line,
target.column,
target.node.names[0].to_string(),
));
if !target.node.names.is_empty() {
attr_list.push((
target.line,
target.column,
target.node.names[0].to_string(),
));
}
}
}
Stmt::AugAssign(aug_assign_stmt) => {
attr_list.push((
aug_assign_stmt.target.line,
aug_assign_stmt.target.column,
aug_assign_stmt.target.node.names[0].to_string(),
));
if !aug_assign_stmt.target.node.names.is_empty() {
attr_list.push((
aug_assign_stmt.target.line,
aug_assign_stmt.target.column,
aug_assign_stmt.target.node.names[0].to_string(),
));
}
}
Stmt::If(if_stmt) => {
loop_body(&if_stmt.body, attr_list);
Expand Down Expand Up @@ -555,6 +579,8 @@ pub enum Expr {
NameConstantLit(NameConstantLit),
JoinedString(JoinedString),
FormattedValue(FormattedValue),
/// A place holder for expression parse error.
Missing(MissingExpr),
}

/// Identifier, e.g.
Expand Down Expand Up @@ -1101,6 +1127,10 @@ pub struct FormattedValue {
pub format_spec: Option<String>,
}

/// MissingExpr placeholder for error recovery.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MissingExpr;

/// Comment, e.g.
/// ```kcl
/// # This is a comment
Expand Down
15 changes: 15 additions & 0 deletions kclvm/ast/src/walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub trait TypedResultWalker<'ctx>: Sized {
fn walk_joined_string(&self, joined_string: &'ctx ast::JoinedString) -> Self::Result;
fn walk_formatted_value(&self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result;
fn walk_comment(&self, comment: &'ctx ast::Comment) -> Self::Result;
fn walk_missing_expr(&self, missing_expr: &'ctx ast::MissingExpr) -> Self::Result;
}

/// Each method of the `MutSelfTypedResultWalker` trait returns a typed result.
Expand Down Expand Up @@ -209,6 +210,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized {
ast::Expr::FormattedValue(formatted_value) => {
self.walk_formatted_value(formatted_value)
}
ast::Expr::Missing(miss_expr) => self.walk_missing_expr(miss_expr),
}
}
fn walk_quant_expr(&mut self, quant_expr: &'ctx ast::QuantExpr) -> Self::Result;
Expand Down Expand Up @@ -250,6 +252,7 @@ pub trait MutSelfTypedResultWalker<'ctx>: Sized {
fn walk_joined_string(&mut self, joined_string: &'ctx ast::JoinedString) -> Self::Result;
fn walk_formatted_value(&mut self, formatted_value: &'ctx ast::FormattedValue) -> Self::Result;
fn walk_comment(&mut self, comment: &'ctx ast::Comment) -> Self::Result;
fn walk_missing_expr(&mut self, missing_expr: &'ctx ast::MissingExpr) -> Self::Result;
}

/// Each method of the `MutSelfMutWalker` trait returns void type.
Expand Down Expand Up @@ -454,6 +457,10 @@ pub trait MutSelfMutWalker<'ctx> {
// Nothing to do.
let _ = comment;
}
fn walk_missing_expr(&mut self, missing_expr: &'ctx mut ast::MissingExpr) {
// Nothing to do.
let _ = missing_expr;
}
fn walk_module(&mut self, module: &'ctx mut ast::Module) {
walk_list_mut!(self, walk_stmt, module.body)
}
Expand Down Expand Up @@ -512,6 +519,7 @@ pub trait MutSelfMutWalker<'ctx> {
ast::Expr::FormattedValue(formatted_value) => {
self.walk_formatted_value(formatted_value)
}
ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr),
}
}
}
Expand Down Expand Up @@ -646,6 +654,7 @@ pub trait Walker<'ctx>: TypedResultWalker<'ctx> {
fn walk_comment(&mut self, comment: &'ctx ast::Comment) {
walk_comment(self, comment);
}
fn walk_missing_expr(&mut self, missing_expr: &'ctx ast::MissingExpr);
fn walk_module(&mut self, module: &'ctx ast::Module) {
walk_module(self, module);
}
Expand Down Expand Up @@ -693,6 +702,7 @@ pub fn walk_expr<'ctx, V: Walker<'ctx>>(walker: &mut V, expr: &'ctx ast::Expr) {
}
ast::Expr::JoinedString(joined_string) => walker.walk_joined_string(joined_string),
ast::Expr::FormattedValue(formatted_value) => walker.walk_formatted_value(formatted_value),
ast::Expr::Missing(missing_expr) => walker.walk_missing_expr(missing_expr),
}
}

Expand Down Expand Up @@ -1189,6 +1199,10 @@ pub trait MutSelfWalker {
// Nothing to do.
let _ = comment;
}
fn walk_missing_expr(&mut self, missing_expr: &ast::MissingExpr) {
// Nothing to do.
let _ = missing_expr;
}
fn walk_module(&mut self, module: &ast::Module) {
walk_list!(self, walk_stmt, module.body)
}
Expand Down Expand Up @@ -1247,6 +1261,7 @@ pub trait MutSelfWalker {
ast::Expr::FormattedValue(formatted_value) => {
self.walk_formatted_value(formatted_value)
}
ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr),
}
}
}
4 changes: 4 additions & 0 deletions kclvm/ast_pretty/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ impl<'p, 'ctx> MutSelfTypedResultWalker<'ctx> for Printer<'p> {
self.writeln(&comment.text);
self.fill("");
}

fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result {
// Nothing to do
}
}

impl<'p> Printer<'p> {
Expand Down
7 changes: 7 additions & 0 deletions kclvm/compiler/src/codegen/llvm/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
ast::Expr::FormattedValue(formatted_value) => {
self.walk_formatted_value(formatted_value)
}
ast::Expr::Missing(missing_expr) => self.walk_missing_expr(missing_expr),
}
}

Expand Down Expand Up @@ -2224,6 +2225,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
self.ok_result()
}

fn walk_missing_expr(&self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result {
Err(kcl_error::KCLError::new(
"compile error: missing expression",
))
}

fn walk_module(&self, module: &'ctx ast::Module) -> Self::Result {
check_backtrack_stop!(self);
if !module.body.is_empty() {
Expand Down
2 changes: 1 addition & 1 deletion kclvm/error/src/error_codes/E2G22.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Erroneous code example:
```kcl,E2G22
1 |a: int = "1"
1 ^ -> got str(1)
expect int, got str(1)
expected int, got str(1)
```
16 changes: 6 additions & 10 deletions kclvm/parser/src/lexer/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'a> Lexer<'a> {
break;
}
Ordering::Greater => {
self.sess.struct_span_error_recovery(
self.sess.struct_span_error(
&format!("unindent {} does not match any outer indentation level", indent.spaces),
self.span(self.pos, self.pos),
);
Expand All @@ -127,10 +127,8 @@ impl<'a> Lexer<'a> {
ordering = indent.cmp(cur_indent);
}
Err(msg) => {
self.sess.struct_span_error_recovery(
msg,
self.span(self.pos, self.pos),
);
self.sess
.struct_span_error(msg, self.span(self.pos, self.pos));
break;
}
}
Expand All @@ -143,7 +141,7 @@ impl<'a> Lexer<'a> {
}
Err(msg) => {
self.sess
.struct_span_error_recovery(msg, self.span(self.pos, self.pos));
.struct_span_error(msg, self.span(self.pos, self.pos));
None
}
}
Expand All @@ -152,10 +150,8 @@ impl<'a> Lexer<'a> {
/// Get the last indent, if not exists, return a default level for error recovery.
fn last_indent(&mut self) -> &IndentLevel {
if self.indent_cxt.indents.is_empty() {
self.sess.struct_span_error_recovery(
"mismatched indent level",
self.span(self.pos, self.pos),
);
self.sess
.struct_span_error("mismatched indent level", self.span(self.pos, self.pos));
self.indent_cxt.indents.push(IndentLevel::default());
}
self.indent_cxt.indents.last().unwrap()
Expand Down
Loading