Repository: kcl-lang/kcl (language: rust)

Issue:
[WIP] Feat : Support Call Kclvm Cli by C API
<!-- Thank you for contributing to KusionStack!

Note: 

1. With pull requests:

    - Open your pull request against "main"
    - Your pull request should have no more than two commits, if not you should squash them.
    - It should pass all tests in the available continuous integration systems such as GitHub Actions.
    - You should add/modify tests to cover your proposed code changes.
    - If your pull request contains a new feature, please document it on the README.

2. Please create an issue first to describe the problem.

    We recommend that link the issue with the PR in the following question.
    For more info, check https://kusionstack.io/docs/governance/contribute/
-->

#### 1. Does this PR affect any open issues?(Y/N) and add issue references (e.g. "fix #123", "re #123".):

- [ ] N
- [x] Y 
re #125 

#### 2. What is the scope of this PR (e.g. component or file name):

<!-- You can add the scope of this change here. 
-->
        KCLVM/kclvm/spec
        KCLVM/kclvm/src/lib.rs

#### 3. Provide a description of the PR(e.g. more details, effects, motivations or doc link):

<!-- You can choose a brief description here -->
- [ ] Affects user behaviors
- [ ] Contains syntax changes
- [ ] Contains variable changes
- [x] Contains experimental features
- [ ] Performance regression: Consumes more CPU
- [ ] Performance regression: Consumes more Memory
- [ ] Other

<!-- You can add more details here.
-->
    Support user to call kclvm_cli by c_api


#### 4. Are there any breaking changes?(Y/N) and describe the breaking changes(e.g. more details, motivations or doc link):

- [x] N
- [ ] Y 

<!-- You can add more details here.

-->

#### 5. Are there test cases for these changes?(Y/N) select and add more details, references or doc links:

<!-- You can choose a brief description here -->
- [x] Unit test
- [ ] Integration test
- [ ] Benchmark (add benchmark stats below)
- [ ] Manual test (add detailed scripts or steps below)
- [ ] Other

<!-- You can add more details here.
None
-->
KCLVM/kclvm/src/api_test.rs

#### 6. Release note

<!-- compatibility change, improvement, bugfix, and new feature need a release note -->

Please refer to [Release Notes Language Style Guide](https://kusionstack.io/docs/governance/release-policy/) to write a quality release note.

```release-note
None
```



Discussion / hints:
****CLA Assistant Lite bot**** All contributors have signed the CLA  ✍️ ✅
I have read the CLA Document and I hereby sign the CLA
## Pull Request Test Coverage Report for [Build 2744948016](https://coveralls.io/builds/51191024)

* **2** of **5523**   **(0.04%)**  changed or added relevant lines in **6** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-7.6%**) to **51.731%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [kclvm/spec/src/main.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fmain.rs#L2) | 1 | 3 | 33.33%
| [kclvm/spec/src/service/util.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Futil.rs#L2) | 0 | 25 | 0.0%
| [kclvm/spec/src/service/service.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Fservice.rs#L10) | 0 | 109 | 0.0%
| [kclvm/spec/src/service/api.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Fapi.rs#L10) | 0 | 153 | 0.0%
| [kclvm/spec/src/model/gpyrpc.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fmodel%2Fgpyrpc.rs#L28) | 0 | 5232 | 0.0%
<!-- | **Total:** | **2** | **5523** | **0.04%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/51191024/badge)](https://coveralls.io/builds/51191024) |
| :-- | --: |
| Change from base [Build 2743999583](https://coveralls.io/builds/51186839): |  -7.6% |
| Covered Lines: | 22244 |
| Relevant Lines: | 42999 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Fix patch:
diff --git a/kclvm/sema/src/core/global_state.rs b/kclvm/sema/src/core/global_state.rs
index 66f6b4736..e6a3f93a0 100644
--- a/kclvm/sema/src/core/global_state.rs
+++ b/kclvm/sema/src/core/global_state.rs
@@ -23,6 +23,13 @@ pub struct GlobalState {
     pub(crate) sema_db: SemanticDB,
     // new and invalidate(changed and affected by changed) pkg from CachedScope::update()
     pub new_or_invalidate_pkgs: HashSet<String>,
+
+    pub ctx: GlobalStateContext,
+}
+
+#[derive(Default, Debug, Clone)]
+pub struct GlobalStateContext {
+    pub has_init_builtin: bool,
 }
 
 impl GlobalState {
diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs
index 0b81521fe..b1df29129 100644
--- a/kclvm/sema/src/core/symbol.rs
+++ b/kclvm/sema/src/core/symbol.rs
@@ -240,6 +240,7 @@ impl SymbolData {
         match id.get_kind() {
             SymbolKind::Schema => {
                 self.schemas.remove(id.get_id());
+                self.symbols_info.schema_builtin_symbols.remove(id);
             }
             SymbolKind::Attribute => {
                 self.attributes.remove(id.get_id());
@@ -887,11 +888,21 @@ impl SymbolData {
         &self.symbols_info.node_symbol_map
     }
 
+    #[inline]
+    pub fn get_node_symbol_map_mut(&mut self) -> &mut IndexMap<NodeKey, SymbolRef> {
+        &mut self.symbols_info.node_symbol_map
+    }
+
     #[inline]
     pub fn get_symbol_node_map(&self) -> &IndexMap<SymbolRef, NodeKey> {
         &self.symbols_info.symbol_node_map
     }
 
+    #[inline]
+    pub fn get_symbol_node_map_mut(&mut self) -> &mut IndexMap<SymbolRef, NodeKey> {
+        &mut self.symbols_info.symbol_node_map
+    }
+
     #[inline]
     pub fn get_fully_qualified_name_map(&self) -> &IndexMap<String, SymbolRef> {
         &self.symbols_info.fully_qualified_name_map
@@ -913,6 +924,9 @@ impl SymbolData {
         }
         for symbol in to_remove {
             self.remove_symbol(&symbol);
+            if let Some(node_id) = self.get_symbol_node_map_mut().remove(&symbol) {
+                self.get_node_symbol_map_mut().remove(&node_id);
+            }
         }
     }
 
diff --git a/kclvm/sema/src/namer/mod.rs b/kclvm/sema/src/namer/mod.rs
index 5c6560672..78c08fa1c 100644
--- a/kclvm/sema/src/namer/mod.rs
+++ b/kclvm/sema/src/namer/mod.rs
@@ -100,13 +100,18 @@ impl<'ctx> Namer<'ctx> {
 
     // serial namer pass
     pub fn find_symbols(program: &'ctx Program, gs: &'ctx mut GlobalState) {
+        let has_init_builtin = gs.ctx.has_init_builtin;
+        gs.ctx.has_init_builtin = true;
         let mut namer = Self::new(program, gs);
         namer.ctx.current_package_info = Some(PackageInfo::new(
             BUILTIN_SYMBOL_PKG_PATH.to_string(),
             "".to_string(),
             true,
         ));
-        namer.init_builtin_symbols();
+        if !has_init_builtin {
+            namer.init_builtin_symbols();
+        }
+
         namer
             .gs
             .get_packages_mut()
diff --git a/kclvm/sema/src/resolver/mod.rs b/kclvm/sema/src/resolver/mod.rs
index 3987f821a..fe5476ea2 100644
--- a/kclvm/sema/src/resolver/mod.rs
+++ b/kclvm/sema/src/resolver/mod.rs
@@ -208,7 +208,6 @@ pub fn resolve_program_with_opts(
             cached_scope.invalidate_pkgs.clear();
             cached_scope.update(program);
             resolver.scope_map = cached_scope.scope_map.clone();
-            resolver.node_ty_map = Rc::new(RefCell::new(cached_scope.node_ty_map.clone()));
             resolver.ctx.schema_mapping = cached_scope.schema_mapping.clone();
             cached_scope
                 .invalidate_pkgs
@@ -216,6 +215,16 @@ pub fn resolve_program_with_opts(
             for pkg in &cached_scope.invalidate_pkgs {
                 resolver.scope_map.remove(pkg);
             }
+            let mut nodes = vec![];
+            for node in cached_scope.node_ty_map.keys() {
+                if cached_scope.invalidate_pkgs.contains(&node.pkgpath) {
+                    nodes.push(node.clone());
+                }
+            }
+            for node in nodes {
+                cached_scope.node_ty_map.remove(&node);
+            }
+            resolver.node_ty_map = Rc::new(RefCell::new(cached_scope.node_ty_map.clone()));
         }
     }
     let scope = resolver.check_and_lint_all_pkgs();


Test patch:
diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs
index 88b3d8682..2a3e64e40 100644
--- a/kclvm/sema/src/resolver/tests.rs
+++ b/kclvm/sema/src/resolver/tests.rs
@@ -1098,3 +1098,54 @@ fn test_clear_cache_by_module() {
         assert_eq!(cached_scope.invalidate_pkgs, expect);
     };
 }
+
+#[test]
+fn clear_cache_test() {
+    let sess = Arc::new(ParseSession::default());
+    let mut program = load_program(
+        sess.clone(),
+        &["./src/resolver/test_data/cache/main.k"],
+        None,
+        None,
+    )
+    .unwrap()
+    .program;
+
+    let scope_cache = Arc::new(RwLock::new(CachedScope::default()));
+    let first_scope = resolve_program_with_opts(
+        &mut program,
+        Options {
+            merge_program: false,
+            type_erasure: false,
+            ..Default::default()
+        },
+        Some(scope_cache.clone()),
+    );
+
+    let mut program = load_program(
+        sess.clone(),
+        &["./src/resolver/test_data/cache/main.k"],
+        None,
+        None,
+    )
+    .unwrap()
+    .program;
+
+    let second_scope = resolve_program_with_opts(
+        &mut program,
+        Options {
+            merge_program: false,
+            type_erasure: false,
+            ..Default::default()
+        },
+        Some(scope_cache.clone()),
+    );
+    let first_node_ty_map_len = first_scope.node_ty_map.borrow().len();
+    let second_node_ty_map_len = second_scope.node_ty_map.borrow().len();
+    assert_eq!(first_node_ty_map_len, second_node_ty_map_len);
+    assert_eq!(first_scope.scope_map.len(), second_scope.scope_map.len());
+    assert_eq!(
+        first_scope.schema_mapping.len(),
+        second_scope.schema_mapping.len()
+    );
+}