diff --git a/kclvm/api/src/service/service_impl.rs b/kclvm/api/src/service/service_impl.rs index 53e175400..fe6444da7 100644 --- a/kclvm/api/src/service/service_impl.rs +++ b/kclvm/api/src/service/service_impl.rs @@ -6,6 +6,7 @@ use std::string::String; use crate::gpyrpc::*; use kcl_language_server::rename; +use kclvm_ast::ast::SerializeProgram; use kclvm_config::settings::build_settings_pathbuf; use kclvm_loader::option::list_options; use kclvm_loader::{load_packages_with_cache, LoadPackageOptions}; @@ -147,7 +148,8 @@ impl KclvmServiceImpl { }), Some(KCLModuleCache::default()), )?; - let ast_json = serde_json::to_string(&result.program)?; + let serialize_program: SerializeProgram = result.program.into(); + let ast_json = serde_json::to_string(&serialize_program)?; Ok(ParseProgramResult { ast_json, @@ -264,7 +266,8 @@ impl KclvmServiceImpl { // Thread local options kclvm_ast::ast::set_should_serialize_id(true); } - let program_json = serde_json::to_string(&packages.program)?; + let serialize_program: SerializeProgram = packages.program.into(); + let program_json = serde_json::to_string(&serialize_program)?; let mut node_symbol_map = HashMap::new(); let mut symbol_node_map = HashMap::new(); let mut fully_qualified_name_map = HashMap::new(); diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs index a1821aa54..fda9044de 100644 --- a/kclvm/ast/src/ast.rs +++ b/kclvm/ast/src/ast.rs @@ -39,6 +39,7 @@ use std::collections::HashMap; use compiler_base_span::{Loc, Span}; use std::fmt::Debug; +use std::sync::Arc; use uuid; use super::token; @@ -374,11 +375,35 @@ pub struct SymbolSelectorSpec { /// Program is the AST collection of all files of the running KCL program. #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] -pub struct Program { +pub struct SerializeProgram { pub root: String, pub pkgs: HashMap>, } +impl Into for Program { + fn into(self) -> SerializeProgram { + SerializeProgram { + root: self.root, + pkgs: self + .pkgs + .iter() + .map(|(name, modules)| { + ( + name.clone(), + modules.iter().map(|m| m.as_ref().clone()).collect(), + ) + }) + .collect(), + } + } +} + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct Program { + pub root: String, + pub pkgs: HashMap>>, +} + impl Program { /// Get main entry files. pub fn get_main_files(&self) -> Vec { @@ -388,9 +413,9 @@ impl Program { } } /// Get the first module in the main package. - pub fn get_main_package_first_module(&self) -> Option<&Module> { + pub fn get_main_package_first_module(&self) -> Option> { match self.pkgs.get(crate::MAIN_PKG) { - Some(modules) => modules.first(), + Some(modules) => modules.first().cloned(), None => None, } } diff --git a/kclvm/evaluator/src/lib.rs b/kclvm/evaluator/src/lib.rs index 036317fb7..60a63f618 100644 --- a/kclvm/evaluator/src/lib.rs +++ b/kclvm/evaluator/src/lib.rs @@ -38,7 +38,7 @@ use std::{cell::RefCell, panic::UnwindSafe}; use crate::error as kcl_error; use anyhow::Result; -use kclvm_ast::ast::{self, AstIndex}; +use kclvm_ast::ast::{self, AstIndex, Module}; use kclvm_runtime::{Context, ValueRef}; /// SCALAR_KEY denotes the temp scalar key for the global variable json plan process. @@ -153,7 +153,11 @@ impl<'ctx> Evaluator<'ctx> { pub fn run(self: &Evaluator<'ctx>) -> Result<(String, String)> { if let Some(modules) = self.program.pkgs.get(kclvm_ast::MAIN_PKG) { self.init_scope(kclvm_ast::MAIN_PKG); - self.compile_ast_modules(modules); + let modules: Vec = modules + .iter() + .map(|arc| arc.clone().as_ref().clone()) + .collect(); + self.compile_ast_modules(&modules); } Ok(self.plan_globals_to_string()) } @@ -165,7 +169,11 @@ impl<'ctx> Evaluator<'ctx> { pub fn run_as_function(self: &Evaluator<'ctx>) -> ValueRef { if let Some(modules) = self.program.pkgs.get(kclvm_ast::MAIN_PKG) { self.init_scope(kclvm_ast::MAIN_PKG); - self.compile_ast_modules(modules) + let modules: Vec = modules + .iter() + .map(|arc| arc.clone().as_ref().clone()) + .collect(); + self.compile_ast_modules(&modules) } else { ValueRef::undefined() } diff --git a/kclvm/evaluator/src/node.rs b/kclvm/evaluator/src/node.rs index be176ce61..098c2a234 100644 --- a/kclvm/evaluator/src/node.rs +++ b/kclvm/evaluator/src/node.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use anyhow::Ok; use generational_arena::Index; -use kclvm_ast::ast::{self, CallExpr, ConfigEntry, NodeRef}; +use kclvm_ast::ast::{self, CallExpr, ConfigEntry, Module, NodeRef}; use kclvm_ast::walker::TypedResultWalker; use kclvm_runtime::{ schema_assert, schema_runtime_type, ConfigEntryOperationKind, DecoratorValue, RuntimeErrorType, @@ -233,7 +233,11 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { if let Some(modules) = self.program.pkgs.get(&import_stmt.path.node) { self.push_pkgpath(&pkgpath); self.init_scope(&pkgpath); - self.compile_ast_modules(modules); + let modules: Vec = modules + .iter() + .map(|arc| arc.clone().as_ref().clone()) + .collect(); + self.compile_ast_modules(&modules); self.pop_pkgpath(); } } diff --git a/kclvm/evaluator/src/scope.rs b/kclvm/evaluator/src/scope.rs index fea41f3ac..8460b967f 100644 --- a/kclvm/evaluator/src/scope.rs +++ b/kclvm/evaluator/src/scope.rs @@ -4,7 +4,7 @@ use crate::{ error as kcl_error, lazy::LazyEvalScope, rule::RuleEvalContextRef, schema::SchemaEvalContextRef, }; use indexmap::{IndexMap, IndexSet}; -use kclvm_ast::ast; +use kclvm_ast::ast::{self, Module}; use kclvm_ast::walker::TypedResultWalker; use kclvm_runtime::{ValueRef, _kclvm_get_fn_ptr_by_name, MAIN_PKG_PATH}; use kclvm_sema::{builtin, plugin}; @@ -39,20 +39,31 @@ impl<'ctx> Evaluator<'ctx> { } let msg = format!("pkgpath {} is not found", pkgpath); // Get the AST module list in the package path. - let module_list: &Vec = if self.program.pkgs.contains_key(pkgpath) { - self.program.pkgs.get(pkgpath).expect(&msg) + let module_list: Vec = if self.program.pkgs.contains_key(pkgpath) { + let modules = self.program.pkgs.get(pkgpath).expect(&msg); + let modules: Vec = modules + .iter() + .map(|arc| arc.clone().as_ref().clone()) + .collect(); + modules } else if pkgpath.starts_with(kclvm_runtime::PKG_PATH_PREFIX) && self.program.pkgs.contains_key(&pkgpath[1..]) { - self.program + let modules = self + .program .pkgs .get(&pkgpath[1..]) - .expect(kcl_error::INTERNAL_ERROR_MSG) + .expect(kcl_error::INTERNAL_ERROR_MSG); + let modules: Vec = modules + .iter() + .map(|arc| arc.clone().as_ref().clone()) + .collect(); + modules } else { panic!("pkgpath {} not found", pkgpath); }; // Init all global types including schema and rule. - for module in module_list { + for module in &module_list { for stmt in &module.body { let name = match &stmt.node { ast::Stmt::Schema(schema_stmt) => schema_stmt.name.node.clone(), diff --git a/kclvm/parser/src/lib.rs b/kclvm/parser/src/lib.rs index 71f476f40..560f1d5f1 100644 --- a/kclvm/parser/src/lib.rs +++ b/kclvm/parser/src/lib.rs @@ -34,6 +34,7 @@ use parser::Parser; use std::collections::{HashMap, HashSet, VecDeque}; use std::path::PathBuf; use std::sync::{Arc, RwLock}; +use std::time::Instant; use kclvm_span::create_session_globals_then; @@ -118,7 +119,7 @@ pub fn parse_single_file(filename: &str, code: Option) -> Result module.clone(), + Some(module) => module.as_ref().clone(), None => ast::Module::default(), }; let file_graph = match loader.file_graph.read() { @@ -665,7 +666,7 @@ pub fn parse_file( file: PkgFile, src: Option, module_cache: KCLModuleCache, - pkgs: &mut HashMap>, + pkgs: &mut HashMap>>, pkgmap: &mut PkgMap, file_graph: FileGraphCache, opts: &LoadProgramOptions, @@ -712,7 +713,7 @@ pub fn parse_file( pub fn get_deps( file: &PkgFile, m: &Module, - modules: &mut HashMap>, + modules: &mut HashMap>>, pkgmap: &mut PkgMap, opts: &LoadProgramOptions, sess: ParseSessionRef, @@ -772,7 +773,7 @@ pub fn parse_pkg( sess: ParseSessionRef, files: Vec<(PkgFile, Option)>, module_cache: KCLModuleCache, - pkgs: &mut HashMap>, + pkgs: &mut HashMap>>, pkgmap: &mut PkgMap, file_graph: FileGraphCache, opts: &LoadProgramOptions, @@ -798,7 +799,7 @@ pub fn parse_entry( sess: ParseSessionRef, entry: &entry::Entry, module_cache: KCLModuleCache, - pkgs: &mut HashMap>, + pkgs: &mut HashMap>>, pkgmap: &mut PkgMap, file_graph: FileGraphCache, opts: &LoadProgramOptions, @@ -915,9 +916,10 @@ pub fn parse_program( ) -> Result { let compile_entries = get_compile_entries_from_paths(&paths, &opts)?; let workdir = compile_entries.get_root_path().to_string(); - let mut pkgs: HashMap> = HashMap::new(); + let mut pkgs: HashMap>> = HashMap::new(); let mut pkgmap = PkgMap::new(); let mut new_files = HashSet::new(); + for entry in compile_entries.iter() { new_files.extend(parse_entry( sess.clone(), @@ -962,9 +964,8 @@ pub fn parse_program( } Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), }; - for file in files.iter() { - let mut m = match module_cache.read() { + let mut m_ref = match module_cache.read() { Ok(module_cache) => module_cache .ast_cache .get(&file.canonicalize()) @@ -972,33 +973,30 @@ pub fn parse_program( "Module not found in module: {:?}", file.canonicalize() )) - .as_ref() .clone(), Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), }; if new_files.contains(file) { let pkg = pkgmap.get(file).expect("file not in pkgmap"); + let mut m = Arc::make_mut(&mut m_ref); fix_rel_import_path_with_file(&pkg.pkg_root, &mut m, file, &pkgmap, opts, sess.clone()); - let m = Arc::new(m.clone()); - match &mut module_cache.write() { - Ok(module_cache) => module_cache.ast_cache.insert(file.canonicalize(), m), - Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")), - }; } match pkgs.get_mut(&file.pkg_path) { Some(modules) => { - modules.push(m); + modules.push(m_ref); } None => { - pkgs.insert(file.pkg_path.clone(), vec![m]); + pkgs.insert(file.pkg_path.clone(), vec![m_ref]); } } } + let program = ast::Program { root: workdir, pkgs, }; + Ok(LoadProgramResult { program, errors: sess.1.read().diagnostics.clone(), diff --git a/kclvm/query/src/override.rs b/kclvm/query/src/override.rs index 871ee7efd..3d12e2813 100644 --- a/kclvm/query/src/override.rs +++ b/kclvm/query/src/override.rs @@ -1,4 +1,5 @@ use std::collections::HashSet; +use std::sync::Arc; use anyhow::{anyhow, Result}; @@ -47,6 +48,7 @@ pub fn apply_overrides( for o in overrides { if let Some(modules) = prog.pkgs.get_mut(MAIN_PKG) { for m in modules.iter_mut() { + let m = Arc::make_mut(m); if apply_override_on_module(m, o, import_paths)? && print_ast { let code_str = print_ast_module(m); std::fs::write(&m.filename, &code_str)? diff --git a/kclvm/runner/src/lib.rs b/kclvm/runner/src/lib.rs index 7d918872d..b96d973f6 100644 --- a/kclvm/runner/src/lib.rs +++ b/kclvm/runner/src/lib.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, ffi::OsStr, path::Path}; +use std::{collections::HashMap, ffi::OsStr, path::Path, sync::Arc}; use anyhow::{anyhow, bail, Result}; use assembler::KclvmLibAssembler; @@ -248,7 +248,7 @@ pub fn execute( /// **Note that it is not thread safe.** pub fn execute_module(m: Module) -> Result { let mut pkgs = HashMap::new(); - pkgs.insert(MAIN_PKG.to_string(), vec![m]); + pkgs.insert(MAIN_PKG.to_string(), vec![Arc::new(m)]); let prog = Program { root: MAIN_PKG.to_string(), diff --git a/kclvm/runner/src/tests.rs b/kclvm/runner/src/tests.rs index ea0ea72d3..604763413 100644 --- a/kclvm/runner/src/tests.rs +++ b/kclvm/runner/src/tests.rs @@ -179,7 +179,7 @@ fn parse_program(test_kcl_case_path: &str) -> Program { /// Program.root = "__main__" fn construct_program(module: Module) -> Program { let mut pkgs_ast = HashMap::new(); - pkgs_ast.insert(MAIN_PKG_NAME.to_string(), vec![module]); + pkgs_ast.insert(MAIN_PKG_NAME.to_string(), vec![Arc::new(module)]); Program { root: MAIN_PKG_NAME.to_string(), pkgs: pkgs_ast, diff --git a/kclvm/sema/src/pre_process/config.rs b/kclvm/sema/src/pre_process/config.rs index d35457778..7bd144fef 100644 --- a/kclvm/sema/src/pre_process/config.rs +++ b/kclvm/sema/src/pre_process/config.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::info::is_private_field; use indexmap::{IndexMap, IndexSet}; use kclvm_ast::walker::MutSelfMutWalker; @@ -127,7 +129,8 @@ impl ConfigMergeTransformer { // 1. Collect merged config if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { for (module_id, module) in modules.iter_mut().enumerate() { - for (i, stmt) in module.body.iter_mut().enumerate() { + let filename = module.filename.to_string(); + for (i, stmt) in Arc::make_mut(module).body.iter_mut().enumerate() { match &mut stmt.node { ast::Stmt::Unification(unification_stmt) if !unification_stmt.target.node.names.is_empty() => @@ -135,7 +138,7 @@ impl ConfigMergeTransformer { let name = &unification_stmt.target.node.names[0].node; match name_declaration_mapping.get_mut(name) { Some(declarations) => declarations.push(( - module.filename.to_string(), + filename.clone(), module_id, i, ConfigMergeKind::Union, @@ -144,7 +147,7 @@ impl ConfigMergeTransformer { name_declaration_mapping.insert( name.to_string(), vec![( - module.filename.to_string(), + filename.clone(), module_id, i, ConfigMergeKind::Union, @@ -164,7 +167,7 @@ impl ConfigMergeTransformer { if is_private_field(name) { declarations.clear(); declarations.push(( - module.filename.to_string(), + filename.clone(), module_id, i, ConfigMergeKind::Override, @@ -175,7 +178,7 @@ impl ConfigMergeTransformer { name_declaration_mapping.insert( name.to_string(), vec![( - module.filename.to_string(), + filename.clone(), module_id, i, ConfigMergeKind::Override, @@ -202,7 +205,7 @@ impl ConfigMergeTransformer { if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { for (module_id, module) in modules.iter_mut().enumerate() { if &module.filename == merged_filename && module_id == *merged_id { - let stmt = module.body.get_mut(*index).unwrap(); + let stmt = Arc::make_mut(module).body.get_mut(*index).unwrap(); match &mut stmt.node { ast::Stmt::Unification(unification_stmt) if matches!(kind, ConfigMergeKind::Union) => @@ -239,7 +242,7 @@ impl ConfigMergeTransformer { if let Some(modules) = program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { for (module_id, module) in modules.iter_mut().enumerate() { if &module.filename == filename && module_id == *merged_id { - if let Some(stmt) = module.body.get_mut(*merged_index) { + if let Some(stmt) = Arc::make_mut(module).body.get_mut(*merged_index) { match &mut stmt.node { ast::Stmt::Unification(unification_stmt) if matches!(merged_kind, ConfigMergeKind::Union) => @@ -294,7 +297,7 @@ impl ConfigMergeTransformer { let mut body: Vec<(usize, &ast::NodeRef)> = module.body.iter().enumerate().collect(); body.retain(|(idx, _)| !delete_index_set.contains(idx)); - module.body = body + Arc::make_mut(module).body = body .iter() .map(|(_, stmt)| (*stmt).clone()) .collect::>>(); diff --git a/kclvm/sema/src/pre_process/mod.rs b/kclvm/sema/src/pre_process/mod.rs index 977e51adc..dabfbd429 100644 --- a/kclvm/sema/src/pre_process/mod.rs +++ b/kclvm/sema/src/pre_process/mod.rs @@ -3,6 +3,8 @@ mod identifier; mod lit_ty_default_value; mod multi_assign; +use std::sync::Arc; + use indexmap::IndexMap; use kclvm_ast::ast; @@ -34,6 +36,7 @@ pub fn pre_process_program(program: &mut ast::Program, opts: &Options) { if pkgpath != kclvm_ast::MAIN_PKG { import_names.clear(); } + let module = Arc::make_mut(module); // First we should transform the raw identifier to avoid raw identifier that happens to be a package path. fix_raw_identifier_prefix(module); fix_qualified_identifier(module, &mut import_names); diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 35e53755a..79d90a283 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -34,7 +34,7 @@ pub fn parse_program(filename: &str) -> Result { module.filename = filename.to_string(); prog.pkgs - .insert(kclvm_ast::MAIN_PKG.to_string(), vec![module]); + .insert(kclvm_ast::MAIN_PKG.to_string(), vec![Arc::new(module)]); Ok(prog) } diff --git a/kclvm/sema/src/resolver/ty_alias.rs b/kclvm/sema/src/resolver/ty_alias.rs index be2b47292..75c29cae9 100644 --- a/kclvm/sema/src/resolver/ty_alias.rs +++ b/kclvm/sema/src/resolver/ty_alias.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use indexmap::IndexMap; use kclvm_ast::ast::Node; use kclvm_ast::walker::MutSelfMutWalker; @@ -149,7 +151,11 @@ pub fn type_alias_pass( for (pkgpath, modules) in program.pkgs.iter_mut() { for module in modules.iter_mut() { if let Some(type_alias_mapping) = type_alias_mapping.get(pkgpath) { - fix_type_alias_identifier(pkgpath, module, type_alias_mapping.clone()); + fix_type_alias_identifier( + pkgpath, + Arc::make_mut(module), + type_alias_mapping.clone(), + ); } } } diff --git a/kclvm/sema/src/resolver/ty_erasure.rs b/kclvm/sema/src/resolver/ty_erasure.rs index f65d7d867..02d4abfb2 100644 --- a/kclvm/sema/src/resolver/ty_erasure.rs +++ b/kclvm/sema/src/resolver/ty_erasure.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use kclvm_ast::walker::MutSelfMutWalker; use kclvm_ast::{ast, walk_if_mut, walk_list_mut}; @@ -68,7 +70,8 @@ impl<'ctx> MutSelfMutWalker<'ctx> for TypeErasureTransformer { pub fn type_func_erasure_pass<'ctx>(program: &'ctx mut ast::Program) { for (_, modules) in program.pkgs.iter_mut() { for module in modules.iter_mut() { - TypeErasureTransformer::default().walk_module(module); + let mut m = Arc::make_mut(module); + TypeErasureTransformer::default().walk_module(&mut m); } } } diff --git a/kclvm/tools/src/vet/validator.rs b/kclvm/tools/src/vet/validator.rs index 906b67501..fc39c6b1f 100644 --- a/kclvm/tools/src/vet/validator.rs +++ b/kclvm/tools/src/vet/validator.rs @@ -64,6 +64,8 @@ //! name == "Alice" //! age > 10 //! ``` +use std::sync::Arc; + use super::expr_builder::ExprBuilder; pub use crate::util::loader::LoaderKind; use anyhow::Result; @@ -209,7 +211,7 @@ pub fn validate(val_opt: ValidateOption) -> Result { match compile_res.program.pkgs.get_mut(kclvm_ast::MAIN_PKG) { Some(pkg) => { if let Some(module) = pkg.first_mut() { - module.body.insert(0, assign_stmt); + Arc::make_mut(module).body.insert(0, assign_stmt); } else { return Err(anyhow::anyhow!("No main module found")); }