Skip to content

Commit

Permalink
Feat: add lambda type annotation (#826)
Browse files Browse the repository at this point in the history
* feat: add lambda type annotation
Signed-off-by: zongz <[email protected]>

* fix: fix CR comments and add more test case

Signed-off-by: zongz <[email protected]>

* fix: rm useless test case

Signed-off-by: zongz <[email protected]>

* fix: make fmt

Signed-off-by: zongz <[email protected]>

* fix: more function type to erasure

Signed-off-by: zongz <[email protected]>

* fix: add constant for 'function'

Signed-off-by: zongz <[email protected]>

* fix: rm useless snap

Signed-off-by: zongz <[email protected]>

---------

Signed-off-by: zongz <[email protected]>
  • Loading branch information
zong-zhe authored Nov 2, 2023
1 parent fe1e4d6 commit 44b9d2e
Show file tree
Hide file tree
Showing 104 changed files with 4,200 additions and 56 deletions.
23 changes: 23 additions & 0 deletions kclvm/ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,13 @@ pub enum Type {
Dict(DictType),
Union(UnionType),
Literal(LiteralType),
Function(FunctionType),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct FunctionType {
pub params_ty: Option<Vec<NodeRef<Type>>>,
pub ret_ty: Option<NodeRef<Type>>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -1632,6 +1639,22 @@ impl ToString for Type {
w.push_str(&format!("\"{}\"", v.replace('"', "\\\"")));
}
},
Type::Function(v) => {
w.push_str("(");
if let Some(params) = &v.params_ty {
for (i, param) in params.iter().enumerate() {
if i > 0 {
w.push_str(", ");
}
to_str(&param.node, w);
}
}
w.push_str(")");
if let Some(ret) = &v.ret_ty {
w.push_str(" -> ");
to_str(&ret.node, w);
}
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions kclvm/parser/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ impl<'a> Parser<'a> {
self.cursor.next().is_some()
}

#[inline]
/// Whether the parser has the next token in the token stream.
pub(crate) fn peek_has_next(&mut self) -> bool {
self.cursor.peek().is_some()
}

pub(crate) fn bump_keyword(&mut self, kw: Symbol) {
if !self.token.is_keyword(kw) {
self.sess.struct_token_error(&[kw.into()], self.token);
Expand Down
35 changes: 34 additions & 1 deletion kclvm/parser/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,42 @@ impl<'a> Parser<'a> {

Some(t)
} else {
let miss_expr = self.missing_expr();
self.skip_newlines();
self.sess
.struct_token_error(&[TokenKind::Assign.into()], self.token);
None
if type_annotation.is_some() && !targets.is_empty() && !is_in_schema_stmt {
let mut pos = targets[0].pos();
pos.3 = targets.last().unwrap().end_line;
pos.4 = targets.last().unwrap().end_column;

let targets: Vec<_> = targets
.iter()
.map(|expr| match &expr.node {
Expr::Identifier(x) => {
let mut x = x.clone();
x.ctx = ExprContext::Store;
Box::new(Node::node_with_pos(x, expr.pos()))
}
_ => {
self.sess
.struct_token_error(&[TokenKind::ident_value()], self.token);
Box::new(expr.into_missing_identifier())
}
})
.collect();
Some(Box::new(Node::node_with_pos(
Stmt::Assign(AssignStmt {
targets: targets.clone(),
value: miss_expr,
type_annotation,
ty,
}),
pos,
)))
} else {
None
}
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions kclvm/parser/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,44 @@ impl<'a> Parser<'a> {
self.sess.struct_token_loc(token, self.prev_token),
));
}
// (type) -> type
else if let TokenKind::OpenDelim(DelimToken::Paren) = self.token.kind {
self.bump_token(TokenKind::OpenDelim(DelimToken::Paren));
let mut params_type = vec![];
// Parse all the params type until the params list end ')'
while self.token.kind != TokenKind::CloseDelim(DelimToken::Paren)
&& self.peek_has_next()
{
params_type.push(self.parse_type_annotation());
// All the params type should be separated by ','
if let TokenKind::Comma = self.token.kind {
self.bump_token(TokenKind::Comma);
}
}
// If there is no params type, set it to None
let params_ty = if params_type.len() == 0 {
None
} else {
Some(params_type)
};

self.bump_token(TokenKind::CloseDelim(DelimToken::Paren));
// If there is a return type, parse it
// Return type start with '->'
let ret_ty = if let TokenKind::RArrow = self.token.kind {
self.bump_token(TokenKind::RArrow);
Some(self.parse_type_annotation())
} else {
None
};

let t = Type::Function(ast::FunctionType { params_ty, ret_ty });

return Box::new(Node::node(
t,
self.sess.struct_token_loc(token, self.prev_token),
));
}
// Expect type tokens
self.sess.struct_token_error(
&[
Expand All @@ -234,9 +271,11 @@ impl<'a> Parser<'a> {
TokenKind::literal_value(),
TokenKind::OpenDelim(DelimToken::Bracket).into(),
TokenKind::OpenDelim(DelimToken::Brace).into(),
TokenKind::CloseDelim(DelimToken::Paren).into(),
],
self.token,
);
self.bump();
Box::new(Node::node(
Type::Any,
self.sess.struct_token_loc(token, self.prev_token),
Expand Down
1 change: 0 additions & 1 deletion kclvm/parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ const PARSE_FILE_INVALID_TEST_CASES: &[&str] = &[
"a: int", // No initial value error
"a -", // Invalid binary expression error
"a?: int", // Invalid optional annotation error
"a: () = 1", // Type annotation error
"if a not is not b: a = 1", // Logic operator error
"if True:\n a=1\n b=2", // Indent error with recovery
"a[1::::]", // List slice error
Expand Down
24 changes: 24 additions & 0 deletions kclvm/parser/src/tests/error_recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,27 @@ parse_module_snapshot! { rule_stmt_recovery_7, r#"
rule A:
@
"#}
parse_module_snapshot! { fn_ty_annotation_recovery_0, r#"a:("#}
parse_module_snapshot! { fn_ty_annotation_recovery_1, r#"a:(i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_2, r#"a:(int"#}
parse_module_snapshot! { fn_ty_annotation_recovery_3, r#"a:i)"#}
parse_module_snapshot! { fn_ty_annotation_recovery_4, r#"a:([i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_5, r#"a:([i:"#}
parse_module_snapshot! { fn_ty_annotation_recovery_6, r#"a:([i]"#}
parse_module_snapshot! { fn_ty_annotation_recovery_7, r#"a:([int]"#}
parse_module_snapshot! { fn_ty_annotation_recovery_8, r#"a:([int"#}
parse_module_snapshot! { fn_ty_annotation_recovery_9, r#"a:({}"#}
parse_module_snapshot! { fn_ty_annotation_recovery_10, r#"a:({"#}
parse_module_snapshot! { fn_ty_annotation_recovery_11, r#"a:({i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_12, r#"a:({i:"#}
parse_module_snapshot! { fn_ty_annotation_recovery_13, r#"a:({i:i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_14, r#"a:({i:int"#}
parse_module_snapshot! { fn_ty_annotation_recovery_15, r#"a:({i:int]"#}
parse_module_snapshot! { fn_ty_annotation_recovery_16, r#"a:({str:int]"#}
parse_module_snapshot! { fn_ty_annotation_recovery_17, r#"a:({str:int}"#}
parse_module_snapshot! { fn_ty_annotation_recovery_18, r#"a:({str:int} ->"#}
parse_module_snapshot! { fn_ty_annotation_recovery_19, r#"a:({str:int}) -> i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_20, r#"a:(str|int) -> i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_21, r#"a:(str|int, int) -> i"#}
parse_module_snapshot! { fn_ty_annotation_recovery_22, r#"a:(str|int, int|"#}
parse_module_snapshot! { fn_ty_annotation_recovery_23, r#"a:(str|int, int|) ->"#}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,72 @@ Module {
pkg: "",
doc: None,
name: "",
body: [],
body: [
Node {
node: Assign(
AssignStmt {
targets: [
Node {
node: Identifier {
names: [
Node {
node: "a",
filename: "",
line: 1,
column: 0,
end_line: 1,
end_column: 1,
},
],
pkgpath: "",
ctx: Store,
},
filename: "",
line: 1,
column: 0,
end_line: 1,
end_column: 1,
},
],
value: Node {
node: Missing(
MissingExpr,
),
filename: "",
line: 1,
column: 2,
end_line: 1,
end_column: 2,
},
type_annotation: Some(
Node {
node: "any",
filename: "",
line: 1,
column: 2,
end_line: 1,
end_column: 2,
},
),
ty: Some(
Node {
node: Any,
filename: "",
line: 1,
column: 2,
end_line: 1,
end_column: 2,
},
),
},
),
filename: "",
line: 1,
column: 0,
end_line: 1,
end_column: 1,
},
],
comments: [],
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,76 @@ Module {
name: "",
body: [
Node {
node: Expr(
ExprStmt {
exprs: [
node: Assign(
AssignStmt {
targets: [
Node {
node: NumberLit(
NumberLit {
binary_suffix: None,
value: Int(
0,
),
node: Identifier {
names: [
Node {
node: "a",
filename: "",
line: 1,
column: 0,
end_line: 1,
end_column: 1,
},
],
pkgpath: "",
ctx: Store,
},
filename: "",
line: 1,
column: 0,
end_line: 1,
end_column: 1,
},
],
value: Node {
node: NumberLit(
NumberLit {
binary_suffix: None,
value: Int(
0,
),
},
),
filename: "",
line: 1,
column: 8,
end_line: 1,
end_column: 9,
},
type_annotation: Some(
Node {
node: "()",
filename: "",
line: 1,
column: 3,
end_line: 1,
end_column: 5,
},
),
ty: Some(
Node {
node: Function(
FunctionType {
params_ty: None,
ret_ty: None,
},
),
filename: "",
line: 1,
column: 8,
column: 3,
end_line: 1,
end_column: 9,
end_column: 5,
},
],
),
},
),
filename: "",
line: 1,
column: 8,
column: 0,
end_line: 1,
end_column: 9,
},
Expand Down
Loading

0 comments on commit 44b9d2e

Please sign in to comment.