diff --git a/kclvm/parser/src/parser/expr.rs b/kclvm/parser/src/parser/expr.rs index d02fa8d70..67cff9cc3 100644 --- a/kclvm/parser/src/parser/expr.rs +++ b/kclvm/parser/src/parser/expr.rs @@ -9,6 +9,7 @@ use super::Parser; use either::{self, Either}; use kclvm_ast::node_ref; +use kclvm_ast::token::Token; use crate::parser::precedence::Precedence; use kclvm_ast::ast::*; @@ -2233,7 +2234,7 @@ impl<'a> Parser<'a> { Box::new(Node::node( Expr::Missing(MissingExpr), // The text range of missing expression is zero. - self.sess.struct_token_loc(self.prev_token, self.token), + self.sess.struct_token_loc(self.token, self.token), )) } diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap index 64f2ac338..3b954a7e2 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 156 expression: "crate::tests::parsing_module_string(r#\"assert\"#)" --- Module { @@ -18,7 +17,7 @@ Module { ), filename: "", line: 1, - column: 0, + column: 6, end_line: 1, end_column: 6, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap index b704cbfda..268fdb8fc 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assert_stmt_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 158 expression: "crate::tests::parsing_module_string(r#\"assert True,,, 'msg'\"#)" --- Module { @@ -32,7 +31,7 @@ Module { ), filename: "", line: 1, - column: 11, + column: 12, end_line: 1, end_column: 13, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap index 002220517..816185317 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 145 expression: "crate::tests::parsing_module_string(r#\"a = \"#)" --- Module { @@ -34,7 +33,7 @@ Module { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap index 2b41ad1a1..574e5a445 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 147 expression: "crate::tests::parsing_module_string(r#\"a: int =\"#)" --- Module { @@ -34,7 +33,7 @@ Module { ), filename: "", line: 1, - column: 7, + column: 8, end_line: 1, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap index aa351c63b..f43dd11fe 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__assign_stmt_recovery_5.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 150 expression: "crate::tests::parsing_module_string(r#\"a = b = \"#)" --- Module { @@ -48,7 +47,7 @@ Module { ), filename: "", line: 1, - column: 6, + column: 8, end_line: 1, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap index 93e6f06ef..6e7ca10ed 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__binary_recovery_6.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 69 expression: "crate::tests::parsing_expr_string(r#\"a -not- b\"#)" --- Node { @@ -38,7 +37,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 6, end_line: 1, end_column: 7, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap index c7da69911..6eecf95e2 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 112 expression: "crate::tests::parsing_expr_string(r#\"a(\"#)" --- Node { @@ -29,7 +28,7 @@ Node { ), filename: "", line: 1, - column: 1, + column: 2, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap index 3a13d0239..f7a79b3b3 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__call_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 114 expression: "crate::tests::parsing_expr_string(r#\"a(a,,)\"#)" --- Node { @@ -45,7 +44,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 4, end_line: 1, end_column: 5, }, @@ -55,7 +54,7 @@ Node { ), filename: "", line: 1, - column: 4, + column: 5, end_line: 1, end_column: 6, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap index 282f1dfce..dd7b2ca60 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 72 expression: "crate::tests::parsing_expr_string(r#\"a <> b\"#)" --- Node { @@ -33,7 +32,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 3, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap index 56a9ed02d..f89c3c9c4 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_3.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 75 expression: "crate::tests::parsing_expr_string(r#\"a <<< b\"#)" --- Node { @@ -34,7 +33,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 5, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap index 135c7b4b6..63861ae45 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__compare_recovery_4.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 76 expression: "crate::tests::parsing_expr_string(r#\"a <+< b\"#)" --- Node { @@ -37,7 +36,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 4, end_line: 1, end_column: 5, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap index 3ba2d2168..7facff34b 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_10.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 64 expression: "crate::tests::parsing_expr_string(\"{**a, *b}\")" --- Node { @@ -47,7 +46,7 @@ Node { ), filename: "", line: 1, - column: 4, + column: 6, end_line: 1, end_column: 7, }, @@ -85,7 +84,7 @@ Node { ), filename: "", line: 1, - column: 8, + column: 9, end_line: 1, end_column: 9, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap index b1011c3eb..2dda6b298 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_11.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 69 expression: "crate::tests::parsing_expr_string(\"{if True: a = , b = 2}\")" --- Node { @@ -52,7 +51,7 @@ Node { ), filename: "", line: 1, - column: 12, + column: 14, end_line: 1, end_column: 15, }, @@ -61,7 +60,7 @@ Node { }, filename: "", line: 1, - column: 12, + column: 14, end_line: 1, end_column: 15, }, @@ -118,7 +117,7 @@ Node { ), filename: "", line: 1, - column: 20, + column: 21, end_line: 1, end_column: 22, }, @@ -129,7 +128,7 @@ Node { ), filename: "", line: 1, - column: 20, + column: 21, end_line: 1, end_column: 22, }, @@ -138,7 +137,7 @@ Node { }, filename: "", line: 1, - column: 20, + column: 21, end_line: 1, end_column: 22, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap index bea660323..ee18eda3b 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_12.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 70 expression: "crate::tests::parsing_expr_string(\"{if True: *a, b = 2}\")" --- Node { @@ -38,7 +37,7 @@ Node { ), filename: "", line: 1, - column: 8, + column: 10, end_line: 1, end_column: 11, }, @@ -76,7 +75,7 @@ Node { ), filename: "", line: 1, - column: 11, + column: 12, end_line: 1, end_column: 13, }, @@ -85,7 +84,7 @@ Node { }, filename: "", line: 1, - column: 11, + column: 12, end_line: 1, end_column: 13, }, @@ -142,7 +141,7 @@ Node { ), filename: "", line: 1, - column: 18, + column: 19, end_line: 1, end_column: 20, }, @@ -153,7 +152,7 @@ Node { ), filename: "", line: 1, - column: 18, + column: 19, end_line: 1, end_column: 20, }, @@ -162,7 +161,7 @@ Node { }, filename: "", line: 1, - column: 18, + column: 19, end_line: 1, end_column: 20, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap index c1d0c1cd1..9f2d22cdb 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_7.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 65 expression: "crate::tests::parsing_expr_string(\"{a = 1,, b = 2}\")" --- Node { @@ -60,7 +59,7 @@ Node { ), filename: "", line: 1, - column: 6, + column: 7, end_line: 1, end_column: 8, }, @@ -99,7 +98,7 @@ Node { ), filename: "", line: 1, - column: 9, + column: 11, end_line: 1, end_column: 12, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap index 3ded2e214..4341c7db9 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__config_recovery_9.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 63 expression: "crate::tests::parsing_expr_string(\"{*a, **b}\")" --- Node { @@ -19,7 +18,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, @@ -60,7 +59,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 5, end_line: 1, end_column: 7, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap index 02260bb87..528d37531 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_0.snap @@ -26,7 +26,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 4, }, @@ -36,7 +36,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap index 02260bb87..528d37531 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_1.snap @@ -26,7 +26,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 4, }, @@ -36,7 +36,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 4, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap index 23ab1b2f6..49690bc2f 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_2.snap @@ -38,7 +38,7 @@ Node { ), filename: "", line: 1, - column: 5, + column: 9, end_line: 1, end_column: 9, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap index 0efa223a1..db389259e 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_recovery_3.snap @@ -38,7 +38,7 @@ Node { ), filename: "", line: 1, - column: 10, + column: 14, end_line: 1, end_column: 14, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap index 0c97b25b6..7d3f16201 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 174 expression: "crate::tests::parsing_module_string(r#\"if True a = 1\"#)" --- Module { @@ -25,7 +24,7 @@ Module { }, filename: "", line: 1, - column: 8, + column: 10, end_line: 1, end_column: 11, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap index bc317fe2c..b27b13695 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 176 expression: "crate::tests::parsing_module_string(r#\"if : a = 1\"#)" --- Module { @@ -64,7 +63,7 @@ Module { ), filename: "", line: 1, - column: 0, + column: 3, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap index 69e35115e..ddd46d631 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_3.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 177 expression: "crate::tests::parsing_module_string(r#\"if True: a = 1 else b = 2\"#)" --- Module { @@ -83,7 +82,7 @@ Module { }, filename: "", line: 1, - column: 20, + column: 22, end_line: 1, end_column: 23, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap index 0315e1c39..6409c75b0 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__if_stmt_recovery_5.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 179 expression: "crate::tests::parsing_module_string(r#\"if\"#)" --- Module { @@ -43,7 +42,7 @@ Module { ), filename: "", line: 1, - column: 0, + column: 2, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap index 05825f577..f2ee300b8 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_0.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 126 expression: "crate::tests::parsing_expr_string(r#\"'${}'\"#)" --- Node { @@ -18,7 +17,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 3, end_line: 1, end_column: 3, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap index 37115ade3..033c033ba 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_1.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 127 expression: "crate::tests::parsing_expr_string(r#\"'${a +}'\"#)" --- Node { @@ -40,7 +39,7 @@ Node { ), filename: "", line: 1, - column: 5, + column: 6, end_line: 1, end_column: 6, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap index 5837a2656..2524d2a2f 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__joined_string_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 128 expression: "crate::tests::parsing_expr_string(r#\"'${(a +}'\"#)" --- Node { @@ -43,7 +42,7 @@ Node { ), filename: "", line: 1, - column: 6, + column: 7, end_line: 1, end_column: 7, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap index 6a491df4b..4bc767631 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_10.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 50 expression: "crate::tests::parsing_expr_string(\"[**a, *b\")" --- Node { @@ -16,7 +15,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 3, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap index 1f8684924..4a397e4be 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_12.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 54 expression: "crate::tests::parsing_expr_string(\"[if True: **a, b]\")" --- Node { @@ -32,7 +31,7 @@ Node { ), filename: "", line: 1, - column: 8, + column: 10, end_line: 1, end_column: 12, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap index 41f5395b5..2b65148ce 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__list_recovery_9.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 49 expression: "crate::tests::parsing_expr_string(\"[*a, **b]\")" --- Node { @@ -44,7 +43,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 5, end_line: 1, end_column: 7, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap index b0aa4c264..555d7f732 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_2.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 33 expression: "crate::tests::parsing_expr_string(r#\"(\"#)" --- Node { @@ -12,7 +11,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 1, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap index fd580d7b7..891fafced 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_3.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 34 expression: "crate::tests::parsing_expr_string(r#\"(]\"#)" --- Node { @@ -12,7 +11,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap index c7aa4f010..3ad71240b 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__paren_recovery_5.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 36 expression: "crate::tests::parsing_expr_string(r#\"(a +\"#)" --- Node { @@ -34,7 +33,7 @@ Node { ), filename: "", line: 1, - column: 3, + column: 4, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap index 39372deab..fbc048913 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_3.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 238 expression: "crate::tests::parsing_module_string(r#\"rule A::\"#)" --- Module { @@ -32,7 +31,7 @@ Module { ), filename: "", line: 1, - column: 7, + column: 8, end_line: 1, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap index c91f51ccf..c64922282 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_4.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 239 expression: "crate::tests::parsing_module_string(r#\"rule A:B\"#)" --- Module { @@ -32,7 +31,7 @@ Module { ), filename: "", line: 1, - column: 7, + column: 8, end_line: 1, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap index 27300132c..c091cafa6 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_5.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 240 expression: "crate::tests::parsing_module_string(r#\"rule A(:\"#)" --- Module { @@ -30,7 +29,7 @@ Module { }, filename: "", line: 1, - column: 6, + column: 7, end_line: 1, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap index 689c80ef7..4eb5f0c33 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__rule_stmt_recovery_7.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 248 expression: "crate::tests::parsing_module_string(r#\"\nrule A:\n @\n\"#)" --- Module { @@ -53,7 +52,7 @@ Module { ), filename: "", line: 3, - column: 4, + column: 5, end_line: 3, end_column: 6, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap index 6a790f996..884d6ce56 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_11.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 196 expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: str = \"#)" --- Module { @@ -62,7 +61,7 @@ Module { ), filename: "", line: 2, - column: 11, + column: 13, end_line: 2, end_column: 13, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap index 53b65e4c5..85c02e831 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_12.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 198 expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: = \"#)" --- Module { @@ -62,7 +61,7 @@ Module { ), filename: "", line: 2, - column: 7, + column: 9, end_line: 2, end_column: 9, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap index eba478f89..edd1aff07 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_13.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 200 expression: "crate::tests::parsing_module_string(r#\"schema A:\n[str]: ''= \"#)" --- Module { @@ -62,7 +61,7 @@ Module { ), filename: "", line: 2, - column: 9, + column: 11, end_line: 2, end_column: 11, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap index 5beaa9f4d..dc51a66dc 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_15.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 204 expression: "crate::tests::parsing_module_string(r#\"schema A:\na!: int \"#)" --- Module { @@ -82,7 +81,7 @@ Module { ), filename: "", line: 2, - column: 1, + column: 2, end_line: 2, end_column: 3, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap index 9b332d9f5..2e13a431d 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_16.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 206 expression: "crate::tests::parsing_module_string(r#\"schema A:\na!!: int \"#)" --- Module { @@ -82,7 +81,7 @@ Module { ), filename: "", line: 2, - column: 1, + column: 2, end_line: 2, end_column: 3, }, @@ -117,7 +116,7 @@ Module { ), filename: "", line: 2, - column: 2, + column: 3, end_line: 2, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap index 96770b7f8..4b486b891 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_20.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 213 expression: "crate::tests::parsing_module_string(r#\"@deprecated(\nschema A:\n a: \"#)" --- Module { @@ -95,7 +94,7 @@ Module { ), filename: "", line: 1, - column: 11, + column: 12, end_line: 2, end_column: 0, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap index de2805860..4b486b891 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_21.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 216 expression: "crate::tests::parsing_module_string(r#\"@deprecated(\nschema A:\n a: \"#)" --- Module { @@ -95,7 +94,7 @@ Module { ), filename: "", line: 1, - column: 11, + column: 12, end_line: 2, end_column: 0, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap index 4bdb64b09..39fdcfb21 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_23.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 222 expression: "crate::tests::parsing_module_string(r#\"@deprecated(a,\nschema A:\n a: \"#)" --- Module { @@ -111,7 +110,7 @@ Module { ), filename: "", line: 1, - column: 13, + column: 14, end_line: 2, end_column: 0, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap index fd106de80..2dfa47ba4 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_24.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 225 expression: "crate::tests::parsing_module_string(r#\"@deprecated((),\nschema A:\n a: \"#)" --- Module { @@ -98,7 +97,7 @@ Module { ), filename: "", line: 1, - column: 12, + column: 13, end_line: 1, end_column: 14, }, @@ -116,7 +115,7 @@ Module { ), filename: "", line: 1, - column: 14, + column: 15, end_line: 2, end_column: 0, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap index bb7f11ce1..b6b56650b 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_26.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 235 expression: "crate::tests::parsing_module_string(r#\"\nschema A:\n check: \n @\"#)" --- Module { @@ -59,7 +58,7 @@ Module { ), filename: "", line: 4, - column: 8, + column: 9, end_line: 4, end_column: 9, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap index b53e5bf7b..cb61c6ea5 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__schema_stmt_recovery_8.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 190 expression: "crate::tests::parsing_module_string(r#\"schema A:\na: int =\"#)" --- Module { @@ -64,7 +63,7 @@ Module { ), filename: "", line: 2, - column: 7, + column: 8, end_line: 2, end_column: 8, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap index 9506f4564..a5e94d9c5 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_1.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 85 expression: "crate::tests::parsing_expr_string(r#\"a[1,b]\"#)" --- Node { @@ -29,7 +28,7 @@ Node { ), filename: "", line: 1, - column: 2, + column: 3, end_line: 1, end_column: 4, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap index de24e6246..ee9c5696e 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__subscript_recovery_3.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 87 expression: "crate::tests::parsing_expr_string(r#\"a[b[b]\"#)" --- Node { @@ -29,7 +28,7 @@ Node { ), filename: "", line: 1, - column: 5, + column: 6, end_line: 1, end_column: 6, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap index 0e249554b..16dc359a3 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_1.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 56 expression: "crate::tests::parsing_expr_string(r#\"!!a\"#)" --- Node { @@ -13,7 +12,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap index 21a61e685..b18119d8e 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_5.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 59 expression: "crate::tests::parsing_expr_string(r#\"++i\"#)" --- Node { @@ -16,7 +15,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap index 13d0462cf..7685fb8e4 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_6.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 60 expression: "crate::tests::parsing_expr_string(r#\"--i\"#)" --- Node { @@ -16,7 +15,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap index 259a3e214..6eb7e2113 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_7.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 61 expression: "crate::tests::parsing_expr_string(r#\"-+i\"#)" --- Node { @@ -16,7 +15,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap index 010dffead..35ca71f65 100644 --- a/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap +++ b/kclvm/parser/src/tests/snapshots/kclvm_parser__tests__error_recovery__unary_recovery_8.snap @@ -1,6 +1,5 @@ --- source: parser/src/tests/error_recovery.rs -assertion_line: 62 expression: "crate::tests::parsing_expr_string(r#\"~~i\"#)" --- Node { @@ -13,7 +12,7 @@ Node { ), filename: "", line: 1, - column: 0, + column: 1, end_line: 1, end_column: 2, }, diff --git a/kclvm/sema/src/resolver/scope.rs b/kclvm/sema/src/resolver/scope.rs index d766e6ea5..21e057584 100644 --- a/kclvm/sema/src/resolver/scope.rs +++ b/kclvm/sema/src/resolver/scope.rs @@ -190,6 +190,22 @@ impl Scope { None => None, } } + + /// Search scope obj by the object name. + pub fn search_obj_by_name(&self, name: &str) -> Vec { + let mut res = vec![]; + for (obj_name, obj) in &self.elems { + if obj_name == name { + res.push(obj.borrow().clone()) + } + } + for c in &self.children { + let c = c.borrow(); + let mut objs = c.search_obj_by_name(name); + res.append(&mut objs); + } + res + } } /// Program scope is scope contains a multiple scopes related to the diff --git a/kclvm/tools/src/LSP/src/capabilities.rs b/kclvm/tools/src/LSP/src/capabilities.rs index 1656a6eac..a83d16ce1 100644 --- a/kclvm/tools/src/LSP/src/capabilities.rs +++ b/kclvm/tools/src/LSP/src/capabilities.rs @@ -1,5 +1,6 @@ use lsp_types::{ - ClientCapabilities, OneOf, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, + ClientCapabilities, CompletionOptions, OneOf, ServerCapabilities, TextDocumentSyncCapability, + TextDocumentSyncKind, WorkDoneProgressOptions, }; /// Returns the capabilities of this LSP server implementation given the capabilities of the client. @@ -7,6 +8,14 @@ pub fn server_capabilities(_client_caps: &ClientCapabilities) -> ServerCapabilit ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)), // document_symbol_provider: Some(OneOf::Left(true)), + completion_provider: Some(CompletionOptions { + resolve_provider: None, + trigger_characters: Some(vec![String::from(".")]), + all_commit_characters: None, + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + }), definition_provider: Some(OneOf::Left(true)), ..Default::default() } diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs new file mode 100644 index 000000000..2c53d0a71 --- /dev/null +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -0,0 +1,172 @@ +//! Complete for KCL +//! Github Issue: https://github.com/KusionStack/KCLVM/issues/476 +//! Now supports code completion in treigger mode (triggered when user enters `.`), +//! and the content of the completion includes: +//! + import path +//! + schema attr +//! + builtin function(str function) +//! + defitions in pkg +//! + system module functions + +use std::{fs, path::Path}; + +use indexmap::IndexSet; +use kclvm_ast::ast::{Expr, ImportStmt, Program, Stmt}; +use kclvm_config::modfile::KCL_FILE_EXTENSION; + +use kclvm_error::Position as KCLPos; +use kclvm_sema::builtin::{ + get_system_module_members, STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS, +}; +use kclvm_sema::resolver::scope::ProgramScope; +use lsp_types::CompletionItem; + +use crate::goto_def::get_identifier_last_name; +use crate::{goto_def::find_objs_in_program_scope, util::inner_most_expr_in_stmt}; + +/// Computes completions at the given position. +pub(crate) fn completion( + trigger_character: Option, + program: &Program, + pos: &KCLPos, + prog_scope: &ProgramScope, +) -> Option { + if let Some('.') = trigger_character { + completion_dot(program, pos, prog_scope) + } else { + // todo: Complete identifiers such as attr, variables, types, etc. + None + } +} + +fn completion_dot( + program: &Program, + pos: &KCLPos, + prog_scope: &ProgramScope, +) -> Option { + match program.pos_to_stmt(pos) { + Some(node) => match node.node { + Stmt::Import(stmt) => completion_for_import(&stmt, pos, prog_scope, program), + _ => { + let expr = inner_most_expr_in_stmt(&node.node, pos, None).0; + match expr { + Some(node) => { + let items = get_completion_items(&node.node, prog_scope); + Some(into_completion_items(&items).into()) + } + None => None, + } + } + }, + None => None, + } +} + +fn completion_for_import( + stmt: &ImportStmt, + _pos: &KCLPos, + _prog_scope: &ProgramScope, + program: &Program, +) -> Option { + let mut items: IndexSet = IndexSet::new(); + let pkgpath = &stmt.path; + let real_path = + Path::new(&program.root).join(pkgpath.replace('.', &std::path::MAIN_SEPARATOR.to_string())); + if real_path.is_dir() { + if let Ok(entries) = fs::read_dir(real_path) { + for entry in entries.flatten() { + let path = entry.path(); + let filename = path.file_name().unwrap().to_str().unwrap().to_string(); + if path.is_dir() { + items.insert(filename); + } else if path.is_file() { + if let Some(extension) = path.extension() { + if extension == KCL_FILE_EXTENSION { + items.insert( + path.with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string(), + ); + } + } + } + } + } + } + Some(into_completion_items(&items).into()) +} + +fn get_completion_items(expr: &Expr, prog_scope: &ProgramScope) -> IndexSet { + let mut items = IndexSet::new(); + match expr { + Expr::Identifier(id) => { + let name = get_identifier_last_name(&id); + if !id.pkgpath.is_empty() { + // standard system module + if STANDARD_SYSTEM_MODULES.contains(&name.as_str()) { + items.extend( + get_system_module_members(name.as_str()) + .iter() + .map(|s| s.to_string()), + ) + } + // user module + if let Some(scope) = prog_scope.scope_map.get(&id.pkgpath) { + let scope = scope.borrow(); + for (name, obj) in &scope.elems { + if obj.borrow().ty.is_module() { + continue; + } + items.insert(name.clone()); + } + } + return items; + } + + let objs = find_objs_in_program_scope(&name, prog_scope); + for obj in objs { + match &obj.ty.kind { + // builtin (str) functions + kclvm_sema::ty::TypeKind::Str => { + for k in STRING_MEMBER_FUNCTIONS.keys() { + items.insert(format!("{}{}", k, "()")); + } + } + // schema attrs + kclvm_sema::ty::TypeKind::Schema(schema) => { + for k in schema.attrs.keys() { + if k != "__settings__" { + items.insert(k.clone()); + } + } + } + _ => {} + } + } + } + Expr::StringLit(_) => { + for k in STRING_MEMBER_FUNCTIONS.keys() { + items.insert(format!("{}{}", k, "()")); + } + } + Expr::Selector(select_expr) => { + let res = get_completion_items(&select_expr.value.node, prog_scope); + items.extend(res); + } + _ => {} + } + items +} + +pub(crate) fn into_completion_items(items: &IndexSet) -> Vec { + items + .iter() + .map(|item| CompletionItem { + label: item.clone(), + ..Default::default() + }) + .collect() +} diff --git a/kclvm/tools/src/LSP/src/find_ref/mod.rs b/kclvm/tools/src/LSP/src/find_ref/mod.rs index ead4b1016..86fe83f9a 100644 --- a/kclvm/tools/src/LSP/src/find_ref/mod.rs +++ b/kclvm/tools/src/LSP/src/find_ref/mod.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] use anyhow::Result; +use kclvm_driver::get_kcl_files; use kclvm_error::Position; -use kclvm_tools::util::get_kcl_files; -use rustc_lexer; + mod find_refs; mod go_to_def; mod word_map; @@ -49,7 +49,7 @@ pub fn word_at_pos(pos: Position) -> Option { } pub fn read_file(path: &String) -> Result { - let text = std::fs::read_to_string(&path)?; + let text = std::fs::read_to_string(path)?; Ok(text) } @@ -96,33 +96,29 @@ pub fn line_to_words(text: String) -> Vec { // Get all occurrences of the word in the entire path. pub fn match_word(path: String, name: String) -> Vec { let mut res = vec![]; - let files = get_kcl_files(path, true); - match files { - Ok(files) => { - // Searching in all files. - for file in files.into_iter() { - let text = read_file(&file); - if text.is_err() { - continue; - } - let text = text.unwrap(); - let lines: Vec<&str> = text.lines().collect(); - for (li, line) in lines.into_iter().enumerate() { - // Get the matching results for each line. - let matched: Vec = line_to_words(line.to_string()) - .into_iter() - .filter(|x| x.word == name) - .map(|x| Position { - filename: file.clone(), - line: li as u64, - column: Some(x.startpos as u64), - }) - .collect(); - res.extend(matched); - } + if let Ok(files) = get_kcl_files(path, true) { + // Searching in all files. + for file in files.into_iter() { + let text = read_file(&file); + if text.is_err() { + continue; + } + let text = text.unwrap(); + let lines: Vec<&str> = text.lines().collect(); + for (li, line) in lines.into_iter().enumerate() { + // Get the matching results for each line. + let matched: Vec = line_to_words(line.to_string()) + .into_iter() + .filter(|x| x.word == name) + .map(|x| Position { + filename: file.clone(), + line: li as u64, + column: Some(x.startpos), + }) + .collect(); + res.extend(matched); } } - Err(_) => {} } res } diff --git a/kclvm/tools/src/LSP/src/find_ref/tests.rs b/kclvm/tools/src/LSP/src/find_ref/tests.rs index 54e018d8f..e2886da35 100644 --- a/kclvm/tools/src/LSP/src/find_ref/tests.rs +++ b/kclvm/tools/src/LSP/src/find_ref/tests.rs @@ -240,12 +240,10 @@ mod tests { ); let except = vec![Position { - filename: String::from( - Path::new(&test_word_workspace_map()) - .join("inherit_bak.k") - .display() - .to_string(), - ), + filename: Path::new(&test_word_workspace_map()) + .join("inherit_bak.k") + .display() + .to_string(), line: 2, column: Some(7), }]; diff --git a/kclvm/tools/src/LSP/src/find_ref/word_map.rs b/kclvm/tools/src/LSP/src/find_ref/word_map.rs index b15efcb21..220eedc7a 100644 --- a/kclvm/tools/src/LSP/src/find_ref/word_map.rs +++ b/kclvm/tools/src/LSP/src/find_ref/word_map.rs @@ -1,7 +1,7 @@ use crate::find_ref; +use kclvm_driver::get_kcl_files; use kclvm_error::Position; -use kclvm_tools::util::get_kcl_files; use std::collections::HashMap; // Record all occurrences of the name in a file @@ -44,7 +44,7 @@ impl FileWordMap { .push(Position { filename: self.file_name.clone(), line: li as u64, - column: Some(x.startpos as u64), + column: Some(x.startpos), }) }); } @@ -101,16 +101,12 @@ impl WorkSpaceWordMap { // build & maintain the record map for each file under the path pub fn build(&mut self) { //TODO may use some cache from other component? - let files = get_kcl_files(&self.path, true); - match files { - Ok(files) => { - for file in files.into_iter() { - self.file_map - .insert(file.clone(), FileWordMap::new(file.clone())); - self.file_map.get_mut(&file).unwrap().build(None); - } + if let Ok(files) = get_kcl_files(&self.path, true) { + for file in files.into_iter() { + self.file_map + .insert(file.clone(), FileWordMap::new(file.clone())); + self.file_map.get_mut(&file).unwrap().build(None); } - Err(_) => {} } } @@ -118,12 +114,8 @@ impl WorkSpaceWordMap { pub fn get(self, name: &String) -> Option> { let mut words = Vec::new(); for (_, mp) in self.file_map.iter() { - match mp.get(name) { - Some(file_words) => { - // words.extend(file_words.into_iter()); - words.extend_from_slice(file_words); - } - None => {} + if let Some(file_words) = mp.get(name) { + words.extend_from_slice(file_words); } } Some(words) diff --git a/kclvm/tools/src/LSP/src/from_lsp.rs b/kclvm/tools/src/LSP/src/from_lsp.rs index 13836d2f8..7e1bd2dcf 100644 --- a/kclvm/tools/src/LSP/src/from_lsp.rs +++ b/kclvm/tools/src/LSP/src/from_lsp.rs @@ -28,7 +28,7 @@ pub(crate) fn kcl_pos(file: &str, pos: Position) -> KCLPos { } /// Converts the given lsp range to `Range` -pub(crate) fn text_range(text: &String, range: lsp_types::Range) -> Range { +pub(crate) fn text_range(text: &str, range: lsp_types::Range) -> Range { let mut lines_length = vec![]; let lines_text: Vec<&str> = text.split('\n').collect(); let mut pre_total_length = 0; diff --git a/kclvm/tools/src/LSP/src/goto_def.rs b/kclvm/tools/src/LSP/src/goto_def.rs index 74f9a333f..a865b6cc2 100644 --- a/kclvm/tools/src/LSP/src/goto_def.rs +++ b/kclvm/tools/src/LSP/src/goto_def.rs @@ -1,61 +1,90 @@ +//! GotoDefinition for KCL +//! Github Issue: https://github.com/KusionStack/KCLVM/issues/476 +//! Now supports goto definition for the following situation: +//! + variable +//! + schema definition +//! + mixin definition +//! + schema attr +//! + attr type + use indexmap::IndexSet; +use kclvm_driver::get_kcl_files; -use std::fs; use std::path::Path; -use kclvm_ast::ast::{AssignStmt, ImportStmt, Program, Stmt, UnificationStmt}; -use kclvm_ast::pos::ContainsPos; +use kclvm_ast::ast::{Expr, Identifier, ImportStmt, Program, SchemaExpr, Stmt}; use kclvm_config::modfile::KCL_FILE_EXTENSION; use kclvm_error::Position as KCLPos; -use kclvm_sema::resolver::scope::ProgramScope; +use kclvm_sema::resolver::scope::{ProgramScope, ScopeObject}; use lsp_types::{GotoDefinitionResponse, Url}; use lsp_types::{Location, Range}; use crate::to_lsp::lsp_pos; +use crate::util::inner_most_expr_in_stmt; +// Navigates to the definition of an identifier. pub(crate) fn goto_definition( - program: Program, - kcl_pos: KCLPos, - prog_scope: ProgramScope, + program: &Program, + kcl_pos: &KCLPos, + prog_scope: &ProgramScope, ) -> Option { - match program.pos_to_stmt(&kcl_pos) { + match program.pos_to_stmt(kcl_pos) { Some(node) => match node.node { - Stmt::Unification(stmt) => goto_def_for_unification(stmt, kcl_pos, prog_scope), - Stmt::Assign(stmt) => goto_def_for_assign(stmt, kcl_pos, prog_scope), - Stmt::Import(stmt) => goto_def_for_import(stmt, kcl_pos, prog_scope, program), + Stmt::Import(stmt) => goto_def_for_import(&stmt, kcl_pos, prog_scope, program), _ => { - // todo - None + let (inner_expr, parent) = inner_most_expr_in_stmt(&node.node, kcl_pos, None); + match inner_expr { + Some(expr) => { + match expr.node { + Expr::Identifier(id) => { + let name = get_identifier_last_name(&id); + let objs = if let Some(parent) = parent { + // find schema attr def + match parent.node { + Expr::Schema(schema_expr) => { + find_def_of_schema_attr(schema_expr, prog_scope, name) + } + _ => vec![], + } + } else { + find_objs_in_program_scope(&name, prog_scope) + }; + let positions = objs + .iter() + .map(|obj| (obj.start.clone(), obj.end.clone())) + .collect(); + positions_to_goto_def_resp(&positions) + } + _ => None, + } + } + None => None, + } } }, None => None, } } -fn find_name_in_program_scope(name: &str, prog_scope: ProgramScope) -> IndexSet<(KCLPos, KCLPos)> { - let mut positions = IndexSet::new(); - let mut scopes = vec![]; +// This function serves as the result of a global search, which may cause duplication. +// It needs to be pruned according to the situation. There are two actions todo: +// + AST Identifier provides location information for each name. +// + Scope provides a method similar to resolve_var of the resolver to replace this function. +pub(crate) fn find_objs_in_program_scope( + name: &str, + prog_scope: &ProgramScope, +) -> Vec { + let mut res = vec![]; for s in prog_scope.scope_map.values() { - scopes.push(s.borrow().clone()); + let mut objs = s.borrow().search_obj_by_name(name); + res.append(&mut objs); } - while !scopes.is_empty() { - let s = scopes.pop().unwrap(); - match s.lookup(&name) { - Some(obj) => { - let obj = obj.borrow().clone(); - positions.insert((obj.start, obj.end)); - } - None => { - for c in s.children { - scopes.push(c.borrow().clone()); - } - } - } - } - positions + res } +// Convert kcl position to GotoDefinitionResponse. This function will convert to +// None, Scalar or Array according to the number of positions fn positions_to_goto_def_resp( positions: &IndexSet<(KCLPos, KCLPos)>, ) -> Option { @@ -77,8 +106,8 @@ fn positions_to_goto_def_resp( res.push(Location { uri: Url::from_file_path(start.filename.clone()).unwrap(), range: Range { - start: lsp_pos(&start), - end: lsp_pos(&end), + start: lsp_pos(start), + end: lsp_pos(end), }, }) } @@ -87,66 +116,15 @@ fn positions_to_goto_def_resp( } } -fn goto_def_for_unification( - stmt: UnificationStmt, - kcl_pos: KCLPos, - prog_scope: ProgramScope, -) -> Option { - let schema_expr = stmt.value.node; - if schema_expr.name.contains_pos(&kcl_pos) { - let id = schema_expr.name.node.names.last().unwrap(); - let positions = find_name_in_program_scope(id, prog_scope); - positions_to_goto_def_resp(&positions) - } else { - None - } -} - -fn goto_def_for_assign( - stmt: AssignStmt, - kcl_pos: KCLPos, - prog_scope: ProgramScope, -) -> Option { - let id = { - if let Some(ty) = stmt.type_annotation { - if ty.contains_pos(&kcl_pos) { - Some(ty.node) - } else { - None - } - } else if stmt.value.contains_pos(&kcl_pos) { - match stmt.value.node { - kclvm_ast::ast::Expr::Identifier(id) => Some(id.names.last().unwrap().clone()), - kclvm_ast::ast::Expr::Schema(schema_expr) => { - if schema_expr.name.contains_pos(&kcl_pos) { - Some(schema_expr.name.node.names.last().unwrap().clone()) - } else { - None - } - } - _ => None, - } - } else { - None - } - }; - match id { - Some(id) => { - let positions = find_name_in_program_scope(&id, prog_scope); - positions_to_goto_def_resp(&positions) - } - None => None, - } -} - fn goto_def_for_import( - stmt: ImportStmt, - _kcl_pos: KCLPos, - _prog_scope: ProgramScope, - program: Program, + stmt: &ImportStmt, + _kcl_pos: &KCLPos, + _prog_scope: &ProgramScope, + program: &Program, ) -> Option { let pkgpath = &stmt.path; - let real_path = Path::new(&program.root).join(pkgpath.replace('.', "/")); + let real_path = + Path::new(&program.root).join(pkgpath.replace('.', &std::path::MAIN_SEPARATOR.to_string())); let mut positions = IndexSet::new(); let mut k_file = real_path.clone(); k_file.set_extension(KCL_FILE_EXTENSION); @@ -160,23 +138,73 @@ fn goto_def_for_import( let end = start.clone(); positions.insert((start, end)); } else if real_path.is_dir() { - if let Ok(entries) = fs::read_dir(real_path) { - for entry in entries { - if let Ok(entry) = entry { - if let Some(extension) = entry.path().extension() { - if extension == KCL_FILE_EXTENSION { - let start = KCLPos { - filename: entry.path().to_str().unwrap().to_string(), - line: 1, - column: None, - }; - let end = start.clone(); - positions.insert((start, end)); - } + if let Ok(files) = get_kcl_files(real_path, false) { + positions.extend(files.iter().map(|file| { + let start = KCLPos { + filename: file.clone(), + line: 1, + column: None, + }; + let end = start.clone(); + (start, end) + })) + } + } + positions_to_goto_def_resp(&positions) +} + +// Todo: fix ConfigExpr +// ```kcl +// schema Person: +// name: str +// data: Data + +// schema Data: +// id: int + +// person = Person { +// data.id = 1 +// data: { +// id = 1 +// } +// data: Data { +// id = 3 +// } +// } +fn find_def_of_schema_attr( + schema_expr: SchemaExpr, + prog_scope: &ProgramScope, + attr_name: String, +) -> Vec { + let schema_name = get_identifier_last_name(&schema_expr.name.node); + let mut res = vec![]; + for scope in prog_scope.scope_map.values() { + let s = scope.borrow(); + if let Some(scope) = s.search_child_scope_by_name(&schema_name) { + let s = scope.borrow(); + if matches!(s.kind, kclvm_sema::resolver::scope::ScopeKind::Schema(_)) { + for (attr, obj) in &s.elems { + if attr == &attr_name { + res.push(obj.borrow().clone()); } } } } } - positions_to_goto_def_resp(&positions) + res +} + +pub(crate) fn get_identifier_last_name(id: &Identifier) -> String { + match id.names.len() { + 0 => "".to_string(), + 1 => id.names[0].clone(), + _ => { + if id.names.last().unwrap().clone() == *"" { + // MissingExpr + id.names.get(id.names.len() - 2).unwrap().clone() + } else { + id.names.last().unwrap().clone() + } + } + } } diff --git a/kclvm/tools/src/LSP/src/lib.rs b/kclvm/tools/src/LSP/src/lib.rs index 1f9e9277d..6b58c2ae6 100644 --- a/kclvm/tools/src/LSP/src/lib.rs +++ b/kclvm/tools/src/LSP/src/lib.rs @@ -1,4 +1,5 @@ mod analysis; +mod completion; mod config; mod db; mod dispatcher; diff --git a/kclvm/tools/src/LSP/src/main.rs b/kclvm/tools/src/LSP/src/main.rs index b798c9078..9e3d11979 100644 --- a/kclvm/tools/src/LSP/src/main.rs +++ b/kclvm/tools/src/LSP/src/main.rs @@ -4,6 +4,7 @@ use state::LanguageServerState; mod analysis; mod capabilities; +mod completion; mod config; mod db; mod dispatcher; @@ -12,11 +13,12 @@ mod goto_def; mod notification; mod request; mod state; -#[cfg(test)] -mod tests; mod to_lsp; mod util; +#[cfg(test)] +mod tests; + /// Runs the main loop of the language server. This will receive requests and handle them. pub fn main_loop(connection: Connection, config: Config) -> anyhow::Result<()> { LanguageServerState::new(connection.sender, config).run(connection.receiver) diff --git a/kclvm/tools/src/LSP/src/notification.rs b/kclvm/tools/src/LSP/src/notification.rs index 968a12d08..d18a0cf35 100644 --- a/kclvm/tools/src/LSP/src/notification.rs +++ b/kclvm/tools/src/LSP/src/notification.rs @@ -10,7 +10,7 @@ impl LanguageServerState { &mut self, notification: lsp_server::Notification, ) -> anyhow::Result<()> { - self.log_message(format!("on notification {:?}", notification.method)); + self.log_message(format!("on notification {:?}", notification)); NotificationDispatcher::new(self, notification) .on::(LanguageServerState::on_did_open_text_document)? .on::(LanguageServerState::on_did_change_text_document)? diff --git a/kclvm/tools/src/LSP/src/request.rs b/kclvm/tools/src/LSP/src/request.rs index 8ec18e148..7452fb79c 100644 --- a/kclvm/tools/src/LSP/src/request.rs +++ b/kclvm/tools/src/LSP/src/request.rs @@ -1,8 +1,10 @@ use std::time::Instant; +use anyhow::Ok; use crossbeam_channel::Sender; use crate::{ + completion::completion, dispatcher::RequestDispatcher, from_lsp::kcl_pos, goto_def::goto_definition, @@ -17,10 +19,7 @@ impl LanguageServerState { request: lsp_server::Request, request_received: Instant, ) -> anyhow::Result<()> { - log_message( - format!("on request {:?}", request.method), - &self.task_sender, - )?; + log_message(format!("on request {:?}", request), &self.task_sender)?; self.register_request(&request, request_received); // If a shutdown was requested earlier, immediately respond with an error @@ -40,6 +39,7 @@ impl LanguageServerState { Ok(()) })? .on::(handle_goto_definition)? + .on::(handle_completion)? .finish(); Ok(()) @@ -62,13 +62,50 @@ pub(crate) fn handle_goto_definition( Param { file: file.to_string(), }, - Some(snapshot.vfs.clone()), + Some(snapshot.vfs), ) .unwrap(); let kcl_pos = kcl_pos(file, params.text_document_position_params.position); - let res = goto_definition(program, kcl_pos, prog_scope); + let res = goto_definition(&program, &kcl_pos, &prog_scope); if res.is_none() { log_message("Definition not found".to_string(), &sender)?; } Ok(res) } + +/// Called when a `Completion` request was received. +pub(crate) fn handle_completion( + snapshot: LanguageServerSnapshot, + params: lsp_types::CompletionParams, + sender: Sender, +) -> anyhow::Result> { + let file = params.text_document_position.text_document.uri.path(); + + let (program, prog_scope, _) = parse_param_and_compile( + Param { + file: file.to_string(), + }, + Some(snapshot.vfs), + ) + .unwrap(); + let kcl_pos = kcl_pos(file, params.text_document_position.position); + log_message( + format!( + "handle_completion {:?}", + params.text_document_position.position + ), + &sender, + )?; + let completion_trigger_character = params + .context + .and_then(|ctx| ctx.trigger_character) + .and_then(|s| s.chars().next()); + + let res = completion( + completion_trigger_character, + &program, + &kcl_pos, + &prog_scope, + ); + Ok(res) +} diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs index ce3670ab8..b824707fa 100644 --- a/kclvm/tools/src/LSP/src/state.rs +++ b/kclvm/tools/src/LSP/src/state.rs @@ -235,8 +235,7 @@ fn handle_diagnostics( let diagnostics = diags .iter() - .map(|diag| kcl_diag_to_lsp_diags(diag, filename.as_str())) - .flatten() + .flat_map(|diag| kcl_diag_to_lsp_diags(diag, filename.as_str())) .collect::>(); sender.send(Task::Notify(lsp_server::Notification { method: PublishDiagnostics::METHOD.to_owned(), diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion.k new file mode 100644 index 000000000..144098b2f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion.k @@ -0,0 +1,22 @@ +import .pkg. # complete import path +import .pkg.subpkg +schema Person: + name: str + age: int + +p = Person { + name: "alice" + age: 1 +} + +p1 = p. # complete schema attr + +p2 = p.name. # complete builtin (str) function + +p3 = subpkg. # complete user module definition + +import math +math. # complete user module definition + +import kcl_plugin.hello as hello +err_result = hello. diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file1.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file2.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file2.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/subpkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/subpkg/file1.k new file mode 100644 index 000000000..3ab0802b2 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/subpkg/file1.k @@ -0,0 +1,3 @@ +schema Person1: + name: str + age: int \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k index 6526be071..58f3943f0 100644 --- a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_def.k @@ -6,4 +6,10 @@ p = pkg.Person { age: 1 } -p1 = p \ No newline at end of file +p1 = p + +schema Person3: + p1: pkg.Person + p2: [pkg.Person] + p3: {str: pkg.Person} + p4: pkg.Person | pkg.Person1 \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k index 956ac0c28..b4ba6786a 100644 --- a/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/pkg/schema_def1.k @@ -1,4 +1,3 @@ schema Person1: name: str age: int - \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index ba00f3b10..21f146c13 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -1,20 +1,39 @@ use std::path::PathBuf; use indexmap::IndexSet; +use kclvm_ast::ast::Program; +use kclvm_error::Diagnostic; use kclvm_error::ErrorKind::InvalidSyntax; use kclvm_error::ErrorKind::TypeError; use kclvm_error::{DiagnosticId, Position as KCLPos}; +use kclvm_sema::builtin::MATH_FUNCTION_NAMES; +use kclvm_sema::builtin::STRING_MEMBER_FUNCTIONS; +use kclvm_sema::resolver::scope::ProgramScope; +use lsp_types::CompletionResponse; use lsp_types::{Position, Range, TextDocumentContentChangeEvent}; use crate::{ + completion::{completion, into_completion_items}, goto_def::goto_definition, util::{apply_document_changes, parse_param_and_compile, Param}, }; +fn compile_test_file(testfile: &str) -> (String, Program, ProgramScope, IndexSet) { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut test_file = path; + test_file.push(testfile); + + let file = test_file.to_str().unwrap().to_string(); + + let (program, prog_scope, diags) = + parse_param_and_compile(Param { file: file.clone() }, None).unwrap(); + (file, program, prog_scope, diags) +} + #[test] fn diagnostics_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut test_file = path.clone(); + let mut test_file = path; test_file.push("src/test_data/diagnostics.k"); let file = test_file.to_str().unwrap(); @@ -31,28 +50,17 @@ fn diagnostics_test() { } #[test] -fn goto_def_test() { +fn goto_import_pkg_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut test_file = path.clone(); - test_file.push("src/test_data/goto_def_test/goto_def.k"); - - let file = test_file.to_str().unwrap(); - - let (program, prog_scope, _) = parse_param_and_compile( - Param { - file: file.to_string(), - }, - None, - ) - .unwrap(); - + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { - filename: file.to_owned(), + filename: file, line: 1, column: Some(10), }; - let res = goto_definition(program.clone(), pos, prog_scope.clone()); + let res = goto_definition(&program, &pos, &prog_scope); let mut expeced_files = IndexSet::new(); let path_str = path.to_str().unwrap(); let test_files = [ @@ -74,39 +82,57 @@ fn goto_def_test() { unreachable!("test error") } } +} + +#[test] +fn goto_import_file_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); // test goto import file: import .pkg.schema_def let pos = KCLPos { - filename: file.to_string(), + filename: file, line: 2, column: Some(10), }; - let res = goto_definition(program.clone(), pos, prog_scope.clone()); + let res = goto_definition(&program, &pos, &prog_scope); match res.unwrap() { lsp_types::GotoDefinitionResponse::Scalar(loc) => { let got_path = loc.uri.path(); - let mut expected_path = path.clone(); - expected_path.push(test_files[1]); assert_eq!(got_path, expected_path.to_str().unwrap()) } _ => { unreachable!("test error") } } +} - // test goto schema definition: p = pkg.Person { +#[test] +fn goto_schema_def_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + // test goto import file: import .pkg.schema_def let pos = KCLPos { - filename: file.to_string(), + filename: file, line: 4, column: Some(11), }; - let res = goto_definition(program.clone(), pos, prog_scope.clone()); + let res = goto_definition(&program, &pos, &prog_scope); match res.unwrap() { lsp_types::GotoDefinitionResponse::Scalar(loc) => { let got_path = loc.uri.path(); - let mut expected_path = path.clone(); - expected_path.push(test_files[1]); assert_eq!(got_path, expected_path.to_str().unwrap()); let (got_start, got_end) = (loc.range.start, loc.range.end); @@ -127,6 +153,17 @@ fn goto_def_test() { unreachable!("test error") } } +} + +#[test] +fn goto_identifier_def_test() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); // test goto identifier definition: p1 = p let pos = KCLPos { @@ -134,7 +171,7 @@ fn goto_def_test() { line: 9, column: Some(6), }; - let res = goto_definition(program.clone(), pos, prog_scope.clone()); + let res = goto_definition(&program, &pos, &prog_scope); match res.unwrap() { lsp_types::GotoDefinitionResponse::Scalar(loc) => { let got_path = loc.uri.path(); @@ -161,6 +198,221 @@ fn goto_def_test() { } } +#[test] +fn goto_schema_attr_ty_def_test() { + // test goto schema attr type definition: p1: pkg.Person + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + let pos = KCLPos { + filename: file, + line: 12, + column: Some(15), + }; + let res = goto_definition(&program, &pos, &prog_scope); + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = loc.uri.path(); + assert_eq!(got_path, expected_path.to_str().unwrap()); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: 0, // zero-based + character: 0, + }; + + let expected_end = Position { + line: 2, // zero-based + character: 13, + }; + + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + +#[test] +fn goto_schema_attr_ty_def_test1() { + // test goto schema attr type definition: p2: [pkg.Person] + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + let pos = KCLPos { + filename: file, + line: 13, + column: Some(15), + }; + let res = goto_definition(&program, &pos, &prog_scope); + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = loc.uri.path(); + assert_eq!(got_path, expected_path.to_str().unwrap()); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: 0, // zero-based + character: 0, + }; + + let expected_end = Position { + line: 2, // zero-based + character: 13, + }; + + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + +#[test] +fn goto_schema_attr_ty_def_test3() { + // test goto schema attr type definition: p3: {str: pkg.Person} + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + let pos = KCLPos { + filename: file, + line: 14, + column: Some(22), + }; + let res = goto_definition(&program, &pos, &prog_scope); + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = loc.uri.path(); + assert_eq!(got_path, expected_path.to_str().unwrap()); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: 0, // zero-based + character: 0, + }; + + let expected_end = Position { + line: 2, // zero-based + character: 13, + }; + + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + +#[test] +fn goto_schema_attr_ty_def_test4() { + // test goto schema attr type definition(Person): p4: pkg.Person | pkg.Person1 + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); + + let pos = KCLPos { + filename: file, + line: 15, + column: Some(17), + }; + let res = goto_definition(&program, &pos, &prog_scope); + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = loc.uri.path(); + assert_eq!(got_path, expected_path.to_str().unwrap()); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: 0, // zero-based + character: 0, + }; + + let expected_end = Position { + line: 2, // zero-based + character: 13, + }; + + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + +#[test] +fn goto_schema_attr_ty_def_test5() { + // test goto schema attr type definition(Person1): p4: pkg.Person | pkg.Person1 + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/goto_def_test/goto_def.k"); + + let mut expected_path = path; + expected_path.push("src/test_data/goto_def_test/pkg/schema_def1.k"); + + let pos = KCLPos { + filename: file, + line: 15, + column: Some(28), + }; + let res = goto_definition(&program, &pos, &prog_scope); + match res.unwrap() { + lsp_types::GotoDefinitionResponse::Scalar(loc) => { + let got_path = loc.uri.path(); + assert_eq!(got_path, expected_path.to_str().unwrap()); + + let (got_start, got_end) = (loc.range.start, loc.range.end); + + let expected_start = Position { + line: 0, // zero-based + character: 0, + }; + + let expected_end = Position { + line: 2, // zero-based + character: 13, + }; + + assert_eq!(got_start, expected_start); + assert_eq!(got_end, expected_end); + } + _ => { + unreachable!("test error") + } + } +} + #[test] fn test_apply_document_changes() { macro_rules! change { @@ -240,3 +492,96 @@ fn test_apply_document_changes() { // apply_document_changes(&mut text, change![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); // assert_eq!(text, "ațc\ncb"); } + +#[test] +fn completion_test() { + let (file, program, prog_scope, _) = + compile_test_file("src/test_data/completion_test/dot/completion.k"); + + // test completion for schema attr + let pos = KCLPos { + filename: file.to_owned(), + line: 12, + column: Some(7), + }; + + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + let mut items = IndexSet::new(); + items.insert("name".to_string()); + items.insert("age".to_string()); + + let expect: CompletionResponse = into_completion_items(&items).into(); + + assert_eq!(got, expect); + items.clear(); + + let pos = KCLPos { + filename: file.to_owned(), + line: 14, + column: Some(12), + }; + + // test completion for str builtin function + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + for k in STRING_MEMBER_FUNCTIONS.keys() { + items.insert(format!("{}{}", k, "()")); + } + let expect: CompletionResponse = into_completion_items(&items).into(); + + assert_eq!(got, expect); + items.clear(); + + // test completion for import pkg path + let pos = KCLPos { + filename: file.to_owned(), + line: 1, + column: Some(12), + }; + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + items.insert("file2".to_string()); + items.insert("subpkg".to_string()); + items.insert("file1".to_string()); + + let expect: CompletionResponse = into_completion_items(&items).into(); + assert_eq!(got, expect); + items.clear(); + + // test completion for import pkg' schema + let pos = KCLPos { + filename: file.to_owned(), + line: 16, + column: Some(12), + }; + + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + items.insert("Person1".to_string()); + let expect: CompletionResponse = into_completion_items(&items).into(); + assert_eq!(got, expect); + items.clear(); + + let pos = KCLPos { + filename: file.to_owned(), + line: 19, + column: Some(5), + }; + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + items.extend(MATH_FUNCTION_NAMES.iter().map(|s| s.to_string())); + let expect: CompletionResponse = into_completion_items(&items).into(); + assert_eq!(got, expect); + items.clear(); + + let pos = KCLPos { + filename: file.to_owned(), + line: 22, + column: Some(19), + }; + let got = completion(Some('.'), &program, &pos, &prog_scope).unwrap(); + + match got { + CompletionResponse::Array(arr) => { + assert!(arr.is_empty()) + } + CompletionResponse::List(_) => unreachable!("test error"), + } + items.clear(); +} diff --git a/kclvm/tools/src/LSP/src/to_lsp.rs b/kclvm/tools/src/LSP/src/to_lsp.rs index 92e81eef4..0fbcd9012 100644 --- a/kclvm/tools/src/LSP/src/to_lsp.rs +++ b/kclvm/tools/src/LSP/src/to_lsp.rs @@ -25,6 +25,7 @@ fn kcl_msg_to_lsp_diags(msg: &Message, severity: DiagnosticSeverity) -> Diagnost let kcl_pos = msg.pos.clone(); let start_position = lsp_pos(&kcl_pos); let end_position = lsp_pos(&kcl_pos); + Diagnostic { range: Range::new(start_position, end_position), severity: Some(severity), diff --git a/kclvm/tools/src/LSP/src/util.rs b/kclvm/tools/src/LSP/src/util.rs index 31c3643f7..48fa38749 100644 --- a/kclvm/tools/src/LSP/src/util.rs +++ b/kclvm/tools/src/LSP/src/util.rs @@ -1,9 +1,11 @@ use std::{fs, sync::Arc}; use indexmap::IndexSet; -use kclvm_ast::ast::Program; +use kclvm_ast::ast::{ConfigEntry, Expr, Identifier, Node, NodeRef, Program, Stmt, Type}; +use kclvm_ast::pos::ContainsPos; use kclvm_driver::lookup_compile_unit; use kclvm_error::Diagnostic; +use kclvm_error::Position as KCLPos; use kclvm_parser::{load_program, ParseSession}; use kclvm_sema::resolver::{resolve_program, scope::ProgramScope}; use lsp_types::Url; @@ -65,7 +67,7 @@ pub(crate) fn parse_param_and_compile( let prog_scope = resolve_program(&mut program); sess.append_diagnostic(prog_scope.handler.diagnostics.clone()); let diags = sess.1.borrow().diagnostics.clone(); - Ok((program, prog_scope.clone(), diags)) + Ok((program, prog_scope, diags)) } /// Update text with TextDocumentContentChangeEvent param @@ -76,7 +78,7 @@ pub(crate) fn apply_document_changes( for change in content_changes { match change.range { Some(range) => { - let range = from_lsp::text_range(&old_text, range); + let range = from_lsp::text_range(old_text, range); old_text.replace_range(range, &change.text); } None => { @@ -109,3 +111,473 @@ fn load_files_code_from_vfs(files: &[&str], vfs: Arc>) -> anyhow::Re } Ok(res) } + +macro_rules! walk_if_contains { + ($expr: expr, $pos: expr, $schema_def: expr) => { + if $expr.contains_pos($pos) { + return inner_most_expr(&$expr, &$pos, $schema_def); + } + }; +} + +macro_rules! walk_if_contains_with_new_expr { + ($expr: expr, $pos: expr, $schema_def: expr, $kind: expr) => { + if $expr.contains_pos($pos) { + walk_if_contains!( + Node::node_with_pos( + $kind($expr.node.clone()), + ( + $expr.filename.clone(), + $expr.line, + $expr.column, + $expr.end_line, + $expr.end_column, + ), + ), + $pos, + $schema_def + ); + } + }; +} + +macro_rules! walk_option_if_contains { + ($opt: expr, $pos: expr, $schema_def: expr) => { + if let Some(expr) = &$opt { + walk_if_contains!(expr, $pos, $schema_def) + } + }; +} + +macro_rules! walk_list_if_contains { + ($list: expr, $pos: expr, $schema_def: expr) => { + for elem in &$list { + walk_if_contains!(elem, $pos, $schema_def) + } + }; +} + +/// Recursively finds the inner most expr and its schema_def expr if in a schema expr(e.g., schema_attr and schema_expr) +/// in a stmt according to the position. +pub(crate) fn inner_most_expr_in_stmt( + stmt: &Stmt, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + match stmt { + Stmt::Assign(assign_stmt) => { + if let Some(ty) = &assign_stmt.type_annotation { + // build a temp identifier with string + return ( + Some(Node::node_with_pos( + Expr::Identifier(Identifier { + names: vec![ty.node.clone()], + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + ty.filename.clone(), + ty.line, + ty.column, + ty.end_line, + ty.end_column, + ), + )), + schema_def, + ); + } + walk_if_contains!(assign_stmt.value, pos, schema_def); + + for expr in &assign_stmt.targets { + walk_if_contains_with_new_expr!(expr, pos, schema_def, Expr::Identifier); + } + (None, schema_def) + } + Stmt::TypeAlias(type_alias_stmt) => { + walk_if_contains_with_new_expr!( + type_alias_stmt.type_name, + pos, + schema_def, + Expr::Identifier + ); + (None, schema_def) + } + Stmt::Expr(expr_stmt) => { + walk_list_if_contains!(expr_stmt.exprs, pos, schema_def); + (None, schema_def) + } + Stmt::Unification(unification_stmt) => { + walk_if_contains_with_new_expr!( + unification_stmt.target, + pos, + schema_def, + Expr::Identifier + ); + + walk_if_contains_with_new_expr!(unification_stmt.value, pos, schema_def, Expr::Schema); + + (None, schema_def) + } + Stmt::AugAssign(aug_assign_stmt) => { + walk_if_contains!(aug_assign_stmt.value, pos, schema_def); + walk_if_contains_with_new_expr!( + aug_assign_stmt.target, + pos, + schema_def, + Expr::Identifier + ); + (None, schema_def) + } + Stmt::Assert(assert_stmt) => { + walk_if_contains!(assert_stmt.test, pos, schema_def); + walk_option_if_contains!(assert_stmt.if_cond, pos, schema_def); + walk_option_if_contains!(assert_stmt.msg, pos, schema_def); + (None, schema_def) + } + Stmt::If(if_stmt) => { + walk_if_contains!(if_stmt.cond, pos, schema_def); + for stmt in &if_stmt.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + for stmt in &if_stmt.orelse { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + (None, schema_def) + } + Stmt::Schema(schema_stmt) => { + walk_if_contains!( + Node::node_with_pos( + Expr::Identifier(Identifier { + names: vec![schema_stmt.name.node.clone()], + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + schema_stmt.name.filename.clone(), + schema_stmt.name.line, + schema_stmt.name.column, + schema_stmt.name.end_line, + schema_stmt.name.end_column, + ), + ), + pos, + schema_def + ); + if let Some(parent_id) = &schema_stmt.parent_name { + walk_if_contains_with_new_expr!(parent_id, pos, schema_def, Expr::Identifier); + } + if let Some(host) = &schema_stmt.for_host_name { + walk_if_contains_with_new_expr!(host, pos, schema_def, Expr::Identifier); + } + for mixin in &schema_stmt.mixins { + walk_if_contains_with_new_expr!(mixin, pos, schema_def, Expr::Identifier); + } + for stmt in &schema_stmt.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + for decorator in &schema_stmt.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + for check in &schema_stmt.checks { + walk_if_contains_with_new_expr!(check, pos, schema_def, Expr::Check); + } + (None, schema_def) + } + Stmt::SchemaAttr(schema_attr_expr) => { + if schema_attr_expr.ty.contains_pos(pos) { + return ( + build_identifier_from_ty_string(&schema_attr_expr.ty, pos), + schema_def, + ); + } + walk_option_if_contains!(schema_attr_expr.value, pos, schema_def); + for decorator in &schema_attr_expr.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + (None, schema_def) + } + Stmt::Rule(rule_stmt) => { + for parent_id in &rule_stmt.parent_rules { + walk_if_contains_with_new_expr!(parent_id, pos, schema_def, Expr::Identifier); + } + for decorator in &rule_stmt.decorators { + walk_if_contains_with_new_expr!(decorator, pos, schema_def, Expr::Call); + } + for check in &rule_stmt.checks { + walk_if_contains_with_new_expr!(check, pos, schema_def, Expr::Check); + } + (None, schema_def) + } + Stmt::Import(_) => (None, schema_def), + } +} + +/// Recursively finds the inner most expr and its schema_def expr if in a schema expr(e.g., schema_attr in schema_expr) +/// in a expr according to the position. +pub(crate) fn inner_most_expr( + expr: &Node, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + if !expr.contains_pos(pos) { + return (None, None); + } + match &expr.node { + Expr::Identifier(_) => (Some(expr.clone()), schema_def), + Expr::Selector(select_expr) => { + walk_if_contains_with_new_expr!(select_expr.attr, pos, schema_def, Expr::Identifier); + walk_if_contains!(select_expr.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Schema(schema_expr) => { + walk_if_contains_with_new_expr!(schema_expr.name, pos, schema_def, Expr::Identifier); + walk_list_if_contains!(schema_expr.args, pos, schema_def); + + for kwargs in &schema_expr.kwargs { + walk_if_contains_with_new_expr!(kwargs, pos, schema_def, Expr::Keyword); + } + if schema_expr.config.contains_pos(pos) { + return inner_most_expr(&schema_expr.config, pos, Some(expr.clone())); + } + (Some(expr.clone()), schema_def) + } + Expr::Config(config_expr) => { + for item in &config_expr.items { + if item.contains_pos(pos) { + return inner_most_expr_in_config_entry(item, pos, schema_def); + } + } + (Some(expr.clone()), schema_def) + } + Expr::Unary(unary_expr) => { + walk_if_contains!(unary_expr.operand, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Binary(binary_expr) => { + walk_if_contains!(binary_expr.left, pos, schema_def); + walk_if_contains!(binary_expr.right, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::If(if_expr) => { + walk_if_contains!(if_expr.body, pos, schema_def); + walk_if_contains!(if_expr.cond, pos, schema_def); + walk_if_contains!(if_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Call(call_expr) => { + walk_list_if_contains!(call_expr.args, pos, schema_def); + for keyword in &call_expr.keywords { + walk_if_contains_with_new_expr!(keyword, pos, schema_def, Expr::Keyword); + } + walk_if_contains!(call_expr.func, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Paren(paren_expr) => { + walk_if_contains!(paren_expr.expr, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Quant(quant_expr) => { + walk_if_contains!(quant_expr.target, pos, schema_def); + for var in &quant_expr.variables { + walk_if_contains_with_new_expr!(var, pos, schema_def, Expr::Identifier); + } + walk_if_contains!(quant_expr.test, pos, schema_def); + walk_option_if_contains!(quant_expr.if_cond, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::List(list_expr) => { + walk_list_if_contains!(list_expr.elts, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::ListIfItem(list_if_item_expr) => { + walk_if_contains!(list_if_item_expr.if_cond, pos, schema_def); + walk_list_if_contains!(list_if_item_expr.exprs, pos, schema_def); + walk_option_if_contains!(list_if_item_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::ListComp(list_comp_expr) => { + walk_if_contains!(list_comp_expr.elt, pos, schema_def); + for comp_clause in &list_comp_expr.generators { + walk_if_contains_with_new_expr!(comp_clause, pos, schema_def, Expr::CompClause); + } + (Some(expr.clone()), schema_def) + } + Expr::Starred(starred_exor) => { + walk_if_contains!(starred_exor.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::DictComp(_) => (Some(expr.clone()), schema_def), + Expr::ConfigIfEntry(config_if_entry_expr) => { + walk_if_contains!(config_if_entry_expr.if_cond, pos, schema_def); + for item in &config_if_entry_expr.items { + if item.contains_pos(pos) { + return inner_most_expr_in_config_entry(item, pos, schema_def); + } + } + walk_option_if_contains!(config_if_entry_expr.orelse, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::CompClause(comp_clause) => { + for target in &comp_clause.targets { + walk_if_contains_with_new_expr!(target, pos, schema_def, Expr::Identifier); + } + walk_if_contains!(comp_clause.iter, pos, schema_def); + walk_list_if_contains!(comp_clause.ifs, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Check(check_expr) => { + walk_if_contains!(check_expr.test, pos, schema_def); + walk_option_if_contains!(check_expr.if_cond, pos, schema_def); + walk_option_if_contains!(check_expr.msg, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Lambda(lambda_expr) => { + if let Some(args) = &lambda_expr.args { + walk_if_contains_with_new_expr!(args, pos, schema_def, Expr::Arguments); + } + for stmt in &lambda_expr.body { + if stmt.contains_pos(pos) { + return inner_most_expr_in_stmt(&stmt.node, pos, schema_def); + } + } + + (Some(expr.clone()), schema_def) + } + Expr::Subscript(subscript_expr) => { + walk_if_contains!(subscript_expr.value, pos, schema_def); + walk_option_if_contains!(subscript_expr.index, pos, schema_def); + walk_option_if_contains!(subscript_expr.lower, pos, schema_def); + walk_option_if_contains!(subscript_expr.upper, pos, schema_def); + walk_option_if_contains!(subscript_expr.step, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Keyword(keyword) => { + walk_if_contains_with_new_expr!(keyword.arg, pos, schema_def, Expr::Identifier); + walk_option_if_contains!(keyword.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Arguments(argument) => { + for arg in &argument.args { + walk_if_contains_with_new_expr!(arg, pos, schema_def, Expr::Identifier); + } + for default in &argument.defaults { + walk_option_if_contains!(default, pos, schema_def); + } + for ty in argument.type_annotation_list.iter().flatten() { + if ty.contains_pos(pos) { + return (Some(build_identifier_from_string(ty)), schema_def); + } + } + (Some(expr.clone()), schema_def) + } + Expr::Compare(compare_expr) => { + walk_if_contains!(compare_expr.left, pos, schema_def); + walk_list_if_contains!(compare_expr.comparators, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::NumberLit(_) => (Some(expr.clone()), schema_def), + Expr::StringLit(_) => (Some(expr.clone()), schema_def), + Expr::NameConstantLit(_) => (Some(expr.clone()), schema_def), + Expr::JoinedString(joined_string) => { + walk_list_if_contains!(joined_string.values, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::FormattedValue(formatted_value) => { + walk_if_contains!(formatted_value.value, pos, schema_def); + (Some(expr.clone()), schema_def) + } + Expr::Missing(_) => (Some(expr.clone()), schema_def), + } +} + +fn inner_most_expr_in_config_entry( + config_entry: &Node, + pos: &KCLPos, + schema_def: Option>, +) -> (Option>, Option>) { + if let Some(key) = &config_entry.node.key { + if key.contains_pos(pos) { + return inner_most_expr(key, pos, schema_def); + } + } + if config_entry.node.value.contains_pos(pos) { + inner_most_expr(&config_entry.node.value, pos, None) + } else { + (None, None) + } +} + +/// Build a temp identifier expr with string +fn build_identifier_from_string(s: &NodeRef) -> Node { + Node::node_with_pos( + Expr::Identifier(Identifier { + names: vec![s.node.clone()], + pkgpath: "".to_string(), + ctx: kclvm_ast::ast::ExprContext::Load, + }), + ( + s.filename.clone(), + s.line, + s.column, + s.end_line, + s.end_column, + ), + ) +} + +/// Build a temp identifier expr with string +fn build_identifier_from_ty_string(ty: &NodeRef, pos: &KCLPos) -> Option> { + if !ty.contains_pos(pos) { + return None; + } + match &ty.node { + Type::Any => None, + Type::Named(id) => Some(Node::node_with_pos( + Expr::Identifier(id.clone()), + ( + ty.filename.clone(), + ty.line, + ty.column, + ty.end_line, + ty.end_column, + ), + )), + Type::Basic(_) => None, + Type::List(list_ty) => { + if let Some(inner) = &list_ty.inner_type { + if inner.contains_pos(pos) { + return build_identifier_from_ty_string(inner, pos); + } + } + None + } + Type::Dict(dict_ty) => { + if let Some(key_ty) = &dict_ty.key_type { + if key_ty.contains_pos(pos) { + return build_identifier_from_ty_string(key_ty, pos); + } + } + if let Some(value_ty) = &dict_ty.value_type { + if value_ty.contains_pos(pos) { + return build_identifier_from_ty_string(value_ty, pos); + } + } + None + } + Type::Union(union_ty) => { + for ty in &union_ty.type_elements { + if ty.contains_pos(pos) { + return build_identifier_from_ty_string(ty, pos); + } + } + None + } + Type::Literal(_) => None, + } +} diff --git a/kclvm/tools/src/format/mod.rs b/kclvm/tools/src/format/mod.rs index e00e995b4..ea37475db 100644 --- a/kclvm/tools/src/format/mod.rs +++ b/kclvm/tools/src/format/mod.rs @@ -7,9 +7,9 @@ //! to print it as source code string. use anyhow::{anyhow, Result}; use kclvm_ast_pretty::print_ast_module; +use kclvm_driver::get_kcl_files; use std::path::Path; -use crate::util::get_kcl_files; use kclvm_parser::parse_file; #[cfg(test)] diff --git a/kclvm/tools/src/util/mod.rs b/kclvm/tools/src/util/mod.rs index 7b4e8b3ff..c8474ee40 100644 --- a/kclvm/tools/src/util/mod.rs +++ b/kclvm/tools/src/util/mod.rs @@ -1,23 +1,3 @@ -use anyhow::Result; -use kclvm_config::modfile::KCL_FILE_SUFFIX; -use std::path::Path; -use walkdir::WalkDir; - pub mod loader; #[cfg(test)] mod tests; - -/// Get kcl files from path. -pub fn get_kcl_files>(path: P, recursively: bool) -> Result> { - let mut files = vec![]; - for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { - let path = entry.path(); - if path.is_file() { - let file = path.to_str().unwrap(); - if file.ends_with(KCL_FILE_SUFFIX) && (recursively || entry.depth() == 1) { - files.push(file.to_string()) - } - } - } - Ok(files) -}