From 4495df4fc85562e0b5c283a68e551005140ebba8 Mon Sep 17 00:00:00 2001 From: never Date: Fri, 13 Oct 2023 11:20:58 +0800 Subject: [PATCH] feat : namer for new architecture of semantic model Signed-off-by: never --- kclvm/Cargo.lock | 10 + kclvm/sema/Cargo.toml | 18 +- kclvm/sema/src/core/global_state.rs | 29 ++ kclvm/sema/src/core/mod.rs | 3 + kclvm/sema/src/core/package.rs | 89 ++++ kclvm/sema/src/core/symbol.rs | 389 ++++++++++++++++++ kclvm/sema/src/lib.rs | 2 + kclvm/sema/src/namer/mod.rs | 149 +++++++ kclvm/sema/src/namer/node.rs | 341 +++++++++++++++ .../sema/src/namer/test_data/import_test/a.k | 4 + .../sema/src/namer/test_data/import_test/b.k | 1 + .../sema/src/namer/test_data/import_test/c.k | 2 + .../sema/src/namer/test_data/import_test/d.k | 2 + .../sema/src/namer/test_data/import_test/e.k | 2 + .../sema/src/namer/test_data/import_test/f.k | 2 + kclvm/sema/src/namer/test_data/kcl.mod | 0 kclvm/sema/src/namer/test_data/pkg/pkg.k | 5 + .../sema/src/namer/test_data/schema_symbols.k | 32 ++ 18 files changed, 1071 insertions(+), 9 deletions(-) create mode 100644 kclvm/sema/src/core/global_state.rs create mode 100644 kclvm/sema/src/core/mod.rs create mode 100644 kclvm/sema/src/core/package.rs create mode 100644 kclvm/sema/src/core/symbol.rs create mode 100644 kclvm/sema/src/namer/mod.rs create mode 100644 kclvm/sema/src/namer/node.rs create mode 100644 kclvm/sema/src/namer/test_data/import_test/a.k create mode 100644 kclvm/sema/src/namer/test_data/import_test/b.k create mode 100644 kclvm/sema/src/namer/test_data/import_test/c.k create mode 100644 kclvm/sema/src/namer/test_data/import_test/d.k create mode 100644 kclvm/sema/src/namer/test_data/import_test/e.k create mode 100644 kclvm/sema/src/namer/test_data/import_test/f.k create mode 100644 kclvm/sema/src/namer/test_data/kcl.mod create mode 100644 kclvm/sema/src/namer/test_data/pkg/pkg.k create mode 100644 kclvm/sema/src/namer/test_data/schema_symbols.k diff --git a/kclvm/Cargo.lock b/kclvm/Cargo.lock index f83b0d867..d2cc73b1d 100644 --- a/kclvm/Cargo.lock +++ b/kclvm/Cargo.lock @@ -1059,6 +1059,15 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1758,6 +1767,7 @@ dependencies = [ "compiler_base_span 0.0.2", "criterion 0.3.6", "fancy-regex", + "generational-arena", "indexmap 1.9.3", "kclvm-ast", "kclvm-ast-pretty", diff --git a/kclvm/sema/Cargo.toml b/kclvm/sema/Cargo.toml index 84cd7aba8..b986d0704 100644 --- a/kclvm/sema/Cargo.toml +++ b/kclvm/sema/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +generational-arena = "0.2.9" phf = { version = "0.9", features = ["macros"] } ahash = "0.7.2" indexmap = "1.0" @@ -20,22 +21,21 @@ regex = "1.7.0" lazy_static = "1.4.0" pcre2 = "*" -kclvm-ast = {path = "../ast"} -kclvm-ast-pretty = {path = "../ast_pretty"} -kclvm-runtime = {path = "../runtime"} -kclvm-error = {path = "../error"} -kclvm-span = {path = "../span"} -compiler_base_span = {path = "../../compiler_base/span", version = "0.0.2"} -compiler_base_session = {path = "../../compiler_base/session"} +kclvm-ast = { path = "../ast" } +kclvm-ast-pretty = { path = "../ast_pretty" } +kclvm-runtime = { path = "../runtime" } +kclvm-error = { path = "../error" } +kclvm-span = { path = "../span" } +compiler_base_span = { path = "../../compiler_base/span", version = "0.0.2" } +compiler_base_session = { path = "../../compiler_base/session" } compiler_base_macros = "0.0.1" compiler_base_error = "0.0.8" suggestions = "0.1.1" [dev-dependencies] -kclvm-parser = {path = "../parser"} +kclvm-parser = { path = "../parser" } criterion = "0.3" [[bench]] name = "my_benchmark" harness = false - diff --git a/kclvm/sema/src/core/global_state.rs b/kclvm/sema/src/core/global_state.rs new file mode 100644 index 000000000..d1741b71d --- /dev/null +++ b/kclvm/sema/src/core/global_state.rs @@ -0,0 +1,29 @@ +use super::{package::PackageDB, symbol::KCLSymbolData}; + +#[derive(Default, Debug)] +pub struct GlobalState { + symbols: KCLSymbolData, + packages: PackageDB, +} + +impl GlobalState { + pub fn get_symbols(&self) -> &KCLSymbolData { + &self.symbols + } + + pub fn get_symbols_mut(&mut self) -> &mut KCLSymbolData { + &mut self.symbols + } + + pub fn get_packages(&self) -> &PackageDB { + &self.packages + } + + pub fn get_packages_mut(&mut self) -> &mut PackageDB { + &mut self.packages + } + + pub fn resolve_symbols(&mut self) { + self.symbols.replace_unresolved_symbol(&self.packages) + } +} diff --git a/kclvm/sema/src/core/mod.rs b/kclvm/sema/src/core/mod.rs new file mode 100644 index 000000000..c6518d459 --- /dev/null +++ b/kclvm/sema/src/core/mod.rs @@ -0,0 +1,3 @@ +pub mod global_state; +pub mod package; +pub mod symbol; diff --git a/kclvm/sema/src/core/package.rs b/kclvm/sema/src/core/package.rs new file mode 100644 index 000000000..84bc0a3c8 --- /dev/null +++ b/kclvm/sema/src/core/package.rs @@ -0,0 +1,89 @@ +use indexmap::IndexMap; + +#[derive(Default, Debug)] +pub struct PackageDB { + pub(crate) package_info: IndexMap, +} + +impl PackageDB { + pub fn add_package(&mut self, info: PackageInfo) { + self.package_info + .insert(info.fully_qualified_name.clone(), info); + } + + pub fn remove_package_info(&mut self, name: &str) { + self.package_info.remove(name); + } + + pub fn get_package_info(&self, name: &str) -> Option<&PackageInfo> { + self.package_info.get(name) + } + + pub fn get_package_info_mut(&mut self, name: &str) -> Option<&mut PackageInfo> { + self.package_info.get_mut(name) + } +} +#[derive(Debug)] +pub struct PackageInfo { + pub(crate) fully_qualified_name: String, + pub(crate) modules: IndexMap, + pub(crate) imports: IndexMap, +} + +impl PackageInfo { + pub fn new(fully_qualified_name: String) -> Self { + Self { + fully_qualified_name, + modules: IndexMap::default(), + imports: IndexMap::default(), + } + } + + pub fn add_import_info(&mut self, info: ImportInfo) { + self.imports.insert(info.fully_qualified_name.clone(), info); + } + + pub fn remove_import_info(&mut self, name: &str) { + self.imports.remove(name); + } + + pub fn get_import_info(&self, name: &str) -> Option<&ImportInfo> { + self.imports.get(name) + } + + pub fn add_module_info(&mut self, info: ModuleInfo) { + self.modules.insert(info.filename.clone(), info); + } + + pub fn remove_module_info(&mut self, name: &str) { + self.modules.remove(name); + } + + pub fn get_module_info(&self, name: &str) -> Option<&ModuleInfo> { + self.modules.get(name) + } +} +#[derive(Debug)] +pub struct ImportInfo { + pub(crate) unqualified_name: String, + pub(crate) fully_qualified_name: String, +} + +impl ImportInfo { + pub fn new(unqualified_name: String, fully_qualified_name: String) -> Self { + Self { + unqualified_name, + fully_qualified_name, + } + } +} +#[derive(Debug)] +pub struct ModuleInfo { + pub(crate) filename: String, +} + +impl ModuleInfo { + pub fn new(filename: String) -> Self { + Self { filename } + } +} diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs new file mode 100644 index 000000000..5d580782f --- /dev/null +++ b/kclvm/sema/src/core/symbol.rs @@ -0,0 +1,389 @@ +use generational_arena::Arena; +use indexmap::IndexMap; + +use kclvm_error::Position; + +use super::package::{PackageDB, PackageInfo}; + +#[derive(Default, Debug)] +pub struct KCLSymbolData { + pub(crate) values: Arena, + pub(crate) packages: Arena, + pub(crate) functions: Arena, + pub(crate) attributes: Arena, + pub(crate) schemas: Arena, + pub(crate) type_aliases: Arena, + pub(crate) unresolved: Arena, + pub(crate) rules: Arena, + + pub(crate) fully_qualified_name_map: IndexMap, +} + +impl KCLSymbolData { + pub fn get_symbol_by_fully_qualified_name(&self, fqn: &str) -> Option { + self.fully_qualified_name_map.get(fqn).cloned() + } + + pub fn get_fully_qualified_name(&self, symbol_ref: SymbolRef) -> String { + match symbol_ref.get_kind() { + SymbolKind::Schema => { + let schema_symbol = self.schemas.get(symbol_ref.get_id()).unwrap(); + let owner_name = self.get_fully_qualified_name(schema_symbol.owner.clone()); + owner_name + "." + &schema_symbol.name + } + SymbolKind::Attribute => { + let attribute_symbol = self.attributes.get(symbol_ref.get_id()).unwrap(); + let owner_name = self.get_fully_qualified_name(attribute_symbol.owner); + owner_name + "." + &attribute_symbol.name + } + SymbolKind::TypeAlias => { + let type_symbol = self.type_aliases.get(symbol_ref.get_id()).unwrap(); + let owner_name = self.get_fully_qualified_name(type_symbol.owner); + owner_name + "." + &type_symbol.name + } + SymbolKind::Rule => { + let rule_symbol = self.rules.get(symbol_ref.get_id()).unwrap(); + let owner_name = self.get_fully_qualified_name(rule_symbol.owner); + owner_name + "." + &rule_symbol.name + } + SymbolKind::Package => self.packages.get(symbol_ref.get_id()).unwrap().name.clone(), + SymbolKind::Function => todo!(), + SymbolKind::Value => todo!(), + SymbolKind::Unresolved => todo!(), + SymbolKind::Dummy => todo!(), + } + } + + pub fn build_fully_qualified_name_map(&mut self) { + for (id, _) in self.packages.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Package, + }; + self.fully_qualified_name_map + .insert(self.get_fully_qualified_name(symbol_ref), symbol_ref); + } + + for (id, _) in self.schemas.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Schema, + }; + self.fully_qualified_name_map + .insert(self.get_fully_qualified_name(symbol_ref), symbol_ref); + } + + for (id, _) in self.type_aliases.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::TypeAlias, + }; + self.fully_qualified_name_map + .insert(self.get_fully_qualified_name(symbol_ref), symbol_ref); + } + + for (id, _) in self.attributes.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Attribute, + }; + self.fully_qualified_name_map + .insert(self.get_fully_qualified_name(symbol_ref), symbol_ref); + } + + for (id, _) in self.rules.iter() { + let symbol_ref = SymbolRef { + id, + kind: SymbolKind::Rule, + }; + self.fully_qualified_name_map + .insert(self.get_fully_qualified_name(symbol_ref), symbol_ref); + } + } + + fn resolve_symbol(&self, symbol_ref: SymbolRef, package_info: &PackageInfo) -> SymbolRef { + if matches!(symbol_ref.get_kind(), SymbolKind::Unresolved) { + let unresolved_symbol = self.unresolved.get(symbol_ref.get_id()).unwrap(); + let target_symbol = self + .fully_qualified_name_map + .get(&unresolved_symbol.get_fully_qualified_name(package_info)); + match target_symbol { + Some(target_symbol) => *target_symbol, + None => symbol_ref, + } + } else { + symbol_ref + } + } + + pub fn replace_unresolved_symbol(&mut self, package_db: &PackageDB) { + let mut schema_refs = vec![]; + for (id, _) in self.schemas.iter() { + schema_refs.push(id) + } + for schema_ref in schema_refs { + let pkg_path = + self.get_fully_qualified_name(self.schemas.get(schema_ref).unwrap().owner); + let package_info = package_db.get_package_info(&pkg_path).unwrap(); + { + self.schemas.get_mut(schema_ref).unwrap().parent_schema = self + .schemas + .get(schema_ref) + .unwrap() + .parent_schema + .map(|symbol_ref| self.resolve_symbol(symbol_ref, package_info)); + } + + self.schemas.get_mut(schema_ref).unwrap().mixins = self + .schemas + .get(schema_ref) + .unwrap() + .mixins + .iter() + .map(|symbol_ref| self.resolve_symbol(*symbol_ref, package_info)) + .collect(); + } + } + + pub fn alloc_package_symbol(&mut self, pkg: PackageSymbol) -> SymbolRef { + let id = self.packages.insert(pkg); + SymbolRef { + id, + kind: SymbolKind::Package, + } + } + + pub fn alloc_schema_symbol(&mut self, schema: SchemaSymbol) -> SymbolRef { + let id = self.schemas.insert(schema); + SymbolRef { + id, + kind: SymbolKind::Schema, + } + } + + pub fn alloc_unresolved_symbol(&mut self, unresolved: UnresolvedSymbol) -> SymbolRef { + let id = self.unresolved.insert(unresolved); + SymbolRef { + id, + kind: SymbolKind::Unresolved, + } + } + + pub fn alloc_type_alias_symbol(&mut self, alias: TypeAliasSymbol) -> SymbolRef { + let id = self.type_aliases.insert(alias); + SymbolRef { + id, + kind: SymbolKind::TypeAlias, + } + } + + pub fn alloc_rule_symbol(&mut self, rule: RuleSymbol) -> SymbolRef { + let id = self.rules.insert(rule); + SymbolRef { + id, + kind: SymbolKind::Rule, + } + } + + pub fn alloc_attribute_symbol(&mut self, attribute: AttributeSymbol) -> SymbolRef { + let id = self.attributes.insert(attribute); + SymbolRef { + id, + kind: SymbolKind::Attribute, + } + } +} +#[allow(unused)] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SymbolKind { + Schema, + Function, + Attribute, + Value, + Package, + TypeAlias, + Unresolved, + Rule, + Dummy, +} +#[allow(unused)] +#[derive(Debug, Clone, Copy)] +pub struct SymbolRef { + id: generational_arena::Index, + kind: SymbolKind, +} + +impl SymbolRef { + pub fn dummy_symbol() -> Self { + Self { + id: generational_arena::Index::from_raw_parts(0, 0), + kind: SymbolKind::Dummy, + } + } +} + +impl SymbolRef { + pub fn get_kind(&self) -> SymbolKind { + self.kind + } + + pub fn get_id(&self) -> generational_arena::Index { + self.id + } +} +#[allow(unused)] +#[derive(Debug)] +pub struct SchemaSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + + pub(crate) parent_schema: Option, + pub(crate) mixins: Vec, + pub(crate) attributes: IndexMap, +} + +impl SchemaSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + name, + start, + end, + owner, + parent_schema: None, + mixins: Vec::default(), + attributes: IndexMap::default(), + } + } +} +#[allow(unused)] +#[derive(Debug)] + +pub struct FunctionSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, + + pub(crate) args: IndexMap, +} +#[allow(unused)] +#[derive(Debug)] +pub struct ValueSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, +} +#[allow(unused)] +#[derive(Debug)] +pub struct AttributeSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, +} + +impl AttributeSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + name, + start, + end, + owner, + } + } +} +#[allow(unused)] +#[derive(Debug)] +pub struct PackageSymbol { + pub(crate) name: String, + pub(crate) members: IndexMap, + pub(crate) start: Position, + pub(crate) end: Position, +} + +impl PackageSymbol { + pub fn new(name: String, start: Position, end: Position) -> Self { + Self { + name, + start, + end, + members: IndexMap::default(), + } + } +} +#[allow(unused)] +#[derive(Debug)] +pub struct TypeAliasSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, +} + +impl TypeAliasSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + name, + start, + end, + owner, + } + } +} +#[allow(unused)] +#[derive(Debug)] +pub struct RuleSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, +} + +impl RuleSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + name, + start, + end, + owner, + } + } +} +#[allow(unused)] +#[derive(Debug)] +pub struct UnresolvedSymbol { + pub(crate) name: String, + pub(crate) start: Position, + pub(crate) end: Position, + pub(crate) owner: SymbolRef, +} + +impl UnresolvedSymbol { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + Self { + name, + start, + end, + owner, + } + } + + pub fn get_fully_qualified_name(&self, package_info: &PackageInfo) -> String { + let names: Vec<_> = self.name.split('.').collect(); + let pkg_path = if names.len() == 1 { + kclvm_ast::MAIN_PKG.to_string() + } else { + let pkg_alias = names.first().unwrap(); + let import_info = package_info.get_import_info(*pkg_alias); + match import_info { + Some(info) => info.fully_qualified_name.clone(), + None => kclvm_ast::MAIN_PKG.to_string(), + } + }; + + pkg_path + "." + names.last().unwrap() + } +} diff --git a/kclvm/sema/src/lib.rs b/kclvm/sema/src/lib.rs index 9a90ffecf..aa015ce9c 100644 --- a/kclvm/sema/src/lib.rs +++ b/kclvm/sema/src/lib.rs @@ -1,7 +1,9 @@ pub mod builtin; +pub mod core; pub mod eval; pub mod info; pub mod lint; +pub mod namer; pub mod plugin; pub mod pre_process; pub mod resolver; diff --git a/kclvm/sema/src/namer/mod.rs b/kclvm/sema/src/namer/mod.rs new file mode 100644 index 000000000..92b44a545 --- /dev/null +++ b/kclvm/sema/src/namer/mod.rs @@ -0,0 +1,149 @@ +use crate::core::global_state::GlobalState; +use crate::core::package::PackageInfo; +use crate::core::symbol::{PackageSymbol, SymbolRef}; +use kclvm_ast::ast::Program; +use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_error::Position; +mod node; + +struct Namer<'ctx> { + gs: GlobalState, + ctx: NamerContext<'ctx>, +} + +struct NamerContext<'ctx> { + pub program: &'ctx Program, + pub current_package_info: Option, + pub owner_symbols: Vec, +} + +impl<'ctx> Namer<'ctx> { + fn new(program: &'ctx Program, gs: GlobalState) -> Self { + Self { + ctx: NamerContext { + program, + current_package_info: None, + owner_symbols: Vec::default(), + }, + gs, + } + } + + // serial namer pass + pub fn find_symbols(program: &'ctx Program, gs: GlobalState) -> GlobalState { + let mut namer = Self::new(program, gs); + + for (name, modules) in namer.ctx.program.pkgs.iter() { + { + if modules.is_empty() { + continue; + } + + let pkg_pos = Position { + filename: modules.last().unwrap().filename.clone(), + line: 1, + column: None, + }; + + let pkg_symbol = PackageSymbol::new(name.clone(), pkg_pos.clone(), pkg_pos); + let symbol_ref = namer.gs.get_symbols_mut().alloc_package_symbol(pkg_symbol); + namer.ctx.owner_symbols.push(symbol_ref); + + namer.ctx.current_package_info = Some(PackageInfo::new(name.to_string())); + } + + for module in modules.iter() { + namer.walk_module(module); + } + + namer.ctx.owner_symbols.pop(); + namer + .gs + .get_packages_mut() + .add_package(namer.ctx.current_package_info.take().unwrap()) + } + + namer.define_symbols(); + + namer.gs + } + + pub fn define_symbols(&mut self) { + self.gs.get_symbols_mut().build_fully_qualified_name_map(); + + self.gs.resolve_symbols() + } +} + +#[cfg(test)] +mod tests { + use super::Namer; + use crate::core::global_state::GlobalState; + use crate::core::symbol::SymbolKind; + use kclvm_parser::ParseSession; + use kclvm_parser::{load_program, parse_program}; + use std::sync::Arc; + + #[test] + fn test_find_symbols() { + let sess = Arc::new(ParseSession::default()); + let program = load_program( + sess.clone(), + &["./src/namer/test_data/schema_symbols.k"], + None, + ) + .unwrap(); + let gs = GlobalState::default(); + let gs = Namer::find_symbols(&program, gs); + + let symbols = gs.get_symbols(); + + let excepts_symbols = vec![ + ("import_test.a", SymbolKind::Package), + ("import_test.b", SymbolKind::Package), + ("import_test.c", SymbolKind::Package), + ("import_test.d", SymbolKind::Package), + ("import_test.e", SymbolKind::Package), + ("import_test.f", SymbolKind::Package), + ("__main__", SymbolKind::Package), + ("pkg", SymbolKind::Package), + ("import_test.f.UnionType", SymbolKind::Schema), + ("import_test.a.Person", SymbolKind::Schema), + ("import_test.c.TestOfMixin", SymbolKind::Schema), + ("import_test.d.Parent", SymbolKind::Schema), + ("import_test.e.UnionType", SymbolKind::Schema), + ("pkg.Name", SymbolKind::Schema), + ("pkg.Person", SymbolKind::Schema), + ("__main__.Main", SymbolKind::Schema), + ("import_test.f.UnionType.b", SymbolKind::Attribute), + ("import_test.a.Person.name", SymbolKind::Attribute), + ("import_test.a.Person.age", SymbolKind::Attribute), + ("pkg.Name.name", SymbolKind::Attribute), + ("pkg.Person.name", SymbolKind::Attribute), + ("import_test.c.TestOfMixin.age", SymbolKind::Attribute), + ("import_test.d.Parent.age1", SymbolKind::Attribute), + ("import_test.e.UnionType.a", SymbolKind::Attribute), + ("__main__.Main.name", SymbolKind::Attribute), + ("__main__.Main.age", SymbolKind::Attribute), + ("__main__.Main.person", SymbolKind::Attribute), + ("__main__.Main.list_union_type", SymbolKind::Attribute), + ("__main__.Main.dict_union_type", SymbolKind::Attribute), + ]; + + assert_eq!( + symbols.fully_qualified_name_map.len(), + excepts_symbols.len() + ); + + for (fqn, kind) in excepts_symbols { + assert!(symbols.fully_qualified_name_map.contains_key(fqn)); + assert_eq!( + symbols + .get_symbol_by_fully_qualified_name(fqn) + .unwrap() + .get_kind(), + kind + ); + } + } +} diff --git a/kclvm/sema/src/namer/node.rs b/kclvm/sema/src/namer/node.rs new file mode 100644 index 000000000..7233b3b9e --- /dev/null +++ b/kclvm/sema/src/namer/node.rs @@ -0,0 +1,341 @@ +use crate::core::package::{ImportInfo, ModuleInfo}; +use crate::core::symbol::{ + AttributeSymbol, RuleSymbol, SchemaSymbol, SymbolKind, SymbolRef, TypeAliasSymbol, + UnresolvedSymbol, +}; + +use super::Namer; +use kclvm_ast::ast; +use kclvm_ast::walker::MutSelfTypedResultWalker; +use kclvm_error::Position; + +fn get_node_position(node: &ast::Node) -> (Position, Position) { + ( + Position { + filename: node.filename.clone(), + line: node.line, + column: Some(node.column), + }, + Position { + filename: node.filename.clone(), + line: node.end_line, + column: Some(node.end_column), + }, + ) +} + +impl<'ctx> MutSelfTypedResultWalker<'ctx> for Namer<'ctx> { + type Result = SymbolRef; + fn walk_module(&mut self, module: &'ctx ast::Module) -> Self::Result { + let owner = *self.ctx.owner_symbols.last().unwrap(); + for stmt_node in module.body.iter() { + let symbol_ref = self.walk_stmt(&stmt_node.node); + + match symbol_ref.get_kind() { + SymbolKind::Dummy => continue, + _ => { + let member_name = self.gs.get_symbols().get_fully_qualified_name(symbol_ref); + self.gs + .get_symbols_mut() + .packages + .get_mut(owner.get_id()) + .unwrap() + .members + .insert(member_name, symbol_ref); + } + } + } + self.ctx + .current_package_info + .as_mut() + .unwrap() + .add_module_info(ModuleInfo::new(module.filename.clone())); + + SymbolRef::dummy_symbol() + } + + fn walk_expr_stmt(&mut self, _expr_stmt: &'ctx ast::ExprStmt) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_unification_stmt( + &mut self, + _unification_stmt: &'ctx ast::UnificationStmt, + ) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { + let (start_pos, end_pos) = get_node_position(&type_alias_stmt.type_name); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let type_alias_ref = + self.gs + .get_symbols_mut() + .alloc_type_alias_symbol(TypeAliasSymbol::new( + type_alias_stmt.type_name.node.get_name(), + start_pos, + end_pos, + owner, + )); + type_alias_ref + } + + fn walk_assign_stmt(&mut self, _assign_stmt: &'ctx ast::AssignStmt) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_aug_assign_stmt(&mut self, _aug_assign_stmt: &'ctx ast::AugAssignStmt) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_assert_stmt(&mut self, _assert_stmt: &'ctx ast::AssertStmt) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_if_stmt(&mut self, _if_stmt: &'ctx ast::IfStmt) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_import_stmt(&mut self, import_stmt: &'ctx ast::ImportStmt) -> Self::Result { + self.ctx + .current_package_info + .as_mut() + .unwrap() + .add_import_info(ImportInfo::new( + import_stmt.name.clone(), + import_stmt.path.clone(), + )); + + SymbolRef::dummy_symbol() + } + + fn walk_schema_stmt(&mut self, schema_stmt: &'ctx ast::SchemaStmt) -> Self::Result { + let (start_pos, end_pos) = get_node_position(&schema_stmt.name); + let owner = self.ctx.owner_symbols.last().unwrap(); + + let shcema_ref = self + .gs + .get_symbols_mut() + .alloc_schema_symbol(SchemaSymbol::new( + schema_stmt.name.node.clone(), + start_pos, + end_pos, + *owner, + )); + self.ctx.owner_symbols.push(shcema_ref); + + self.gs + .get_symbols_mut() + .schemas + .get_mut(shcema_ref.get_id()) + .unwrap() + .parent_schema = schema_stmt.parent_name.as_ref().map(|name| { + let (start_pos, end_pos) = get_node_position(&name); + self.gs + .get_symbols_mut() + .alloc_unresolved_symbol(UnresolvedSymbol::new( + name.node.get_name(), + start_pos, + end_pos, + shcema_ref, + )) + }); + + for mixin in schema_stmt.mixins.iter() { + let (start_pos, end_pos) = get_node_position(&schema_stmt.name); + let mixin_ref = + self.gs + .get_symbols_mut() + .alloc_unresolved_symbol(UnresolvedSymbol::new( + mixin.node.get_name(), + start_pos, + end_pos, + shcema_ref, + )); + self.gs + .get_symbols_mut() + .schemas + .get_mut(shcema_ref.get_id()) + .unwrap() + .mixins + .push(mixin_ref); + } + + for stmt in schema_stmt.body.iter() { + let symbol_ref = self.walk_stmt(&stmt.node); + if matches!(&symbol_ref.get_kind(), SymbolKind::Attribute) { + let attribut_name = self.gs.get_symbols().get_fully_qualified_name(symbol_ref); + let schema_symbol = self + .gs + .get_symbols_mut() + .schemas + .get_mut(shcema_ref.get_id()) + .unwrap(); + + schema_symbol.attributes.insert(attribut_name, symbol_ref); + } + } + self.ctx.owner_symbols.pop(); + shcema_ref + } + + fn walk_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> Self::Result { + let (start_pos, end_pos) = get_node_position(&rule_stmt.name); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let attribute_ref = self.gs.get_symbols_mut().alloc_rule_symbol(RuleSymbol::new( + rule_stmt.name.node.clone(), + start_pos, + end_pos, + owner, + )); + attribute_ref + } + + fn walk_quant_expr(&mut self, _quant_expr: &'ctx ast::QuantExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_schema_attr(&mut self, schema_attr: &'ctx ast::SchemaAttr) -> Self::Result { + let (start_pos, end_pos) = get_node_position(&schema_attr.name); + let owner = self.ctx.owner_symbols.last().unwrap().clone(); + let attribute_ref = self + .gs + .get_symbols_mut() + .alloc_attribute_symbol(AttributeSymbol::new( + schema_attr.name.node.clone(), + start_pos, + end_pos, + owner, + )); + attribute_ref + } + + /// if else -> sup([body, orelse]) + fn walk_if_expr(&mut self, _if_expr: &'ctx ast::IfExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_unary_expr(&mut self, _unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_binary_expr(&mut self, _binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_selector_expr(&mut self, _selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_call_expr(&mut self, _call_expr: &'ctx ast::CallExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_subscript(&mut self, _subscript: &'ctx ast::Subscript) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_paren_expr(&mut self, _paren_expr: &'ctx ast::ParenExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_list_expr(&mut self, _list_expr: &'ctx ast::ListExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_list_comp(&mut self, _list_comp: &'ctx ast::ListComp) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_dict_comp(&mut self, _dict_comp: &'ctx ast::DictComp) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_list_if_item_expr( + &mut self, + _list_if_item_expr: &'ctx ast::ListIfItemExpr, + ) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_starred_expr(&mut self, _starred_expr: &'ctx ast::StarredExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_config_if_entry_expr( + &mut self, + _config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr, + ) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_comp_clause(&mut self, _comp_clause: &'ctx ast::CompClause) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_schema_expr(&mut self, _schema_expr: &'ctx ast::SchemaExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_config_expr(&mut self, _config_expr: &'ctx ast::ConfigExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_check_expr(&mut self, _check_expr: &'ctx ast::CheckExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_lambda_expr(&mut self, _lambda_expr: &'ctx ast::LambdaExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_keyword(&mut self, _keyword: &'ctx ast::Keyword) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_arguments(&mut self, _arguments: &'ctx ast::Arguments) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_compare(&mut self, _compare: &'ctx ast::Compare) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_identifier(&mut self, _identifier: &'ctx ast::Identifier) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_number_lit(&mut self, _number_lit: &'ctx ast::NumberLit) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_string_lit(&mut self, _string_lit: &'ctx ast::StringLit) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_name_constant_lit( + &mut self, + _name_constant_lit: &'ctx ast::NameConstantLit, + ) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_joined_string(&mut self, _joined_string: &'ctx ast::JoinedString) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_formatted_value( + &mut self, + _formatted_value: &'ctx ast::FormattedValue, + ) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_comment(&mut self, _comment: &'ctx ast::Comment) -> Self::Result { + SymbolRef::dummy_symbol() + } + + fn walk_missing_expr(&mut self, _missing_expr: &'ctx ast::MissingExpr) -> Self::Result { + SymbolRef::dummy_symbol() + } +} diff --git a/kclvm/sema/src/namer/test_data/import_test/a.k b/kclvm/sema/src/namer/test_data/import_test/a.k new file mode 100644 index 000000000..8b6a81409 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/a.k @@ -0,0 +1,4 @@ +_a = 1 +schema Person: + name: str + age: int diff --git a/kclvm/sema/src/namer/test_data/import_test/b.k b/kclvm/sema/src/namer/test_data/import_test/b.k new file mode 100644 index 000000000..79fa8ccc7 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/b.k @@ -0,0 +1 @@ +_b = 1 diff --git a/kclvm/sema/src/namer/test_data/import_test/c.k b/kclvm/sema/src/namer/test_data/import_test/c.k new file mode 100644 index 000000000..f4832d10f --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/c.k @@ -0,0 +1,2 @@ +schema TestOfMixin: + age?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/d.k b/kclvm/sema/src/namer/test_data/import_test/d.k new file mode 100644 index 000000000..78dcd8b21 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/d.k @@ -0,0 +1,2 @@ +schema Parent: + age1?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/e.k b/kclvm/sema/src/namer/test_data/import_test/e.k new file mode 100644 index 000000000..98fabf8f4 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/e.k @@ -0,0 +1,2 @@ +schema UnionType: + a?: int diff --git a/kclvm/sema/src/namer/test_data/import_test/f.k b/kclvm/sema/src/namer/test_data/import_test/f.k new file mode 100644 index 000000000..65a0fa043 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/import_test/f.k @@ -0,0 +1,2 @@ +schema UnionType: + b?: int diff --git a/kclvm/sema/src/namer/test_data/kcl.mod b/kclvm/sema/src/namer/test_data/kcl.mod new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/sema/src/namer/test_data/pkg/pkg.k b/kclvm/sema/src/namer/test_data/pkg/pkg.k new file mode 100644 index 000000000..f8c946eff --- /dev/null +++ b/kclvm/sema/src/namer/test_data/pkg/pkg.k @@ -0,0 +1,5 @@ +schema Name: + name?: str + +schema Person: + name: Name = Name {name = "Alice"} diff --git a/kclvm/sema/src/namer/test_data/schema_symbols.k b/kclvm/sema/src/namer/test_data/schema_symbols.k new file mode 100644 index 000000000..5452a4a94 --- /dev/null +++ b/kclvm/sema/src/namer/test_data/schema_symbols.k @@ -0,0 +1,32 @@ +import import_test.a +import import_test.b +import import_test.c +import import_test.d +import import_test.e +import import_test.f as g +import pkg +import regex + +schema Main(d.Parent): + mixin [c.TestOfMixin] + name?: str + age?: int = 18 + person?: a.Person + list_union_type: [e.UnionType|int] + dict_union_type: {g.UnionType|int:float} + + check: + regex.match(name, r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*") if name + +if a._a > 1: + _c = 1 +elif a._a == 1: + _c = 2 +else: + _c = 3 + +p = Main{ + age = b._b +} + +person = pkg.Person {}