diff --git a/parser/src/parser/parser.rs b/parser/src/parser/parser.rs index 9788592c..2c943ce5 100644 --- a/parser/src/parser/parser.rs +++ b/parser/src/parser/parser.rs @@ -323,7 +323,9 @@ impl Parser { Kind::Global => self.parse_global_statement(), Kind::Nonlocal => self.parse_nonlocal_statement(), _ => { - if self.cur_kind() == Kind::Indent { + if self.cur_kind() == Kind::Identifier && self.cur_token().value.to_string() == "type" { + self.parse_type_alias_statement() + } else if self.cur_kind() == Kind::Indent { let node = self.start_node(); let kind = self.cur_kind(); return Err(self.unexpected_token_new( @@ -3145,6 +3147,28 @@ impl Parser { } Ok(type_params) } + + fn parse_type_alias_statement(&mut self) -> std::result::Result { + let node = self.start_node(); + self.expect(Kind::Identifier)?; + let name = self.cur_token().value.to_string(); + self.expect(Kind::Identifier)?; + let type_params = if self.eat(Kind::LeftBrace) { + let type_params = self.parse_type_parameters()?; + self.expect(Kind::RightBrace)?; + type_params + } else { + vec![] + }; + self.expect(Kind::Assign)?; + let value = self.parse_expression_2()?; + Ok(Statement::TypeAlias(TypeAlias { + node: self.finish_node(node), + name, + type_params, + value: Box::new(value), + })) + } } #[cfg(test)] diff --git a/typechecker/src/nodes.rs b/typechecker/src/nodes.rs index 99a6fc6e..ae7842af 100755 --- a/typechecker/src/nodes.rs +++ b/typechecker/src/nodes.rs @@ -337,4 +337,6 @@ impl<'a> TraversalVisitor for EnderpyFile { fn visit_global(&mut self, _g: &parser::ast::Global) {} fn visit_nonlocal(&mut self, _n: &parser::ast::Nonlocal) {} + + fn visit_type_alias(&mut self, _t: &parser::ast::TypeAlias) {} } diff --git a/typechecker/src/semantic_analyzer.rs b/typechecker/src/semantic_analyzer.rs index 57aa1ca1..81ca722d 100644 --- a/typechecker/src/semantic_analyzer.rs +++ b/typechecker/src/semantic_analyzer.rs @@ -13,7 +13,7 @@ use crate::{ }, symbol_table::{ Alias, Class, Declaration, DeclarationPath, Function, Paramter, SymbolScope, SymbolTable, - SymbolTableNode, SymbolTableScope, SymbolTableType, Variable, + SymbolTableNode, SymbolTableScope, SymbolTableType, Variable, TypeAlias, }, }; @@ -465,6 +465,20 @@ impl TraversalVisitor for SemanticAnalyzer { self.create_symbol(f.name.clone(), function_declaration); } + fn visit_type_alias(&mut self, t: &parser::ast::TypeAlias) { + let declaration_path = DeclarationPath { + module_name: self.file.module_name().clone(), + node: t.node, + }; + self.create_symbol( + t.name.clone(), + Declaration::TypeAlias(TypeAlias { + declaration_path, + type_alias_node: t.clone(), + } + )); + } + fn visit_async_function_def(&mut self, _f: &parser::ast::AsyncFunctionDef) {} fn visit_class_def(&mut self, c: &parser::ast::ClassDef) { diff --git a/typechecker/src/symbol_table.rs b/typechecker/src/symbol_table.rs index 07c930ba..cd847a46 100644 --- a/typechecker/src/symbol_table.rs +++ b/typechecker/src/symbol_table.rs @@ -65,6 +65,8 @@ pub enum Declaration { // TypeParameterDeclaration represents a type parameter in a generic class or function. // It models type parameters declared on classes and functions like T in List[T]. TypeParameter(Box), + + TypeAlias(TypeAlias), } impl Declaration { @@ -76,6 +78,7 @@ impl Declaration { Declaration::Parameter(p) => &p.declaration_path, Declaration::Alias(a) => &a.declaration_path, Declaration::TypeParameter(t) => &t.declaration_path, + Declaration::TypeAlias(t) => &t.declaration_path, } } } @@ -142,6 +145,12 @@ pub struct Alias { pub import_result: ImportResult, } +#[derive(Debug, Clone)] +pub struct TypeAlias { + pub declaration_path: DeclarationPath, + pub type_alias_node: ast::TypeAlias, +} + #[derive(Debug, Clone, Copy)] pub enum SymbolScope { Global, @@ -299,6 +308,7 @@ impl std::fmt::Display for Declaration { Declaration::Parameter(p) => write!(f, "{:#?}", p), Declaration::Alias(a) => write!(f, "{:#?}", a), Declaration::TypeParameter(t) => write!(f, "{:#?}", t), + Declaration::TypeAlias(t) => write!(f, "{:#?}", t), } } } diff --git a/typechecker/src/type_check/type_evaluator.rs b/typechecker/src/type_check/type_evaluator.rs index 680b5b93..693f667e 100755 --- a/typechecker/src/type_check/type_evaluator.rs +++ b/typechecker/src/type_check/type_evaluator.rs @@ -44,7 +44,7 @@ impl TypeEvaluator { match decl { Some(decl) => self.get_type_from_declaration(decl), None => Ok(PythonType::Unknown), - } + } } pub fn get_type(&self, expr: &ast::Expression) -> Result { match expr { @@ -226,6 +226,7 @@ impl TypeEvaluator { Declaration::Parameter(_) => Ok(PythonType::Unknown), Declaration::Alias(_) => Ok(PythonType::Unknown), Declaration::TypeParameter(_) => Ok(PythonType::Unknown), + Declaration::TypeAlias(_) => Ok(PythonType::Unknown), } } diff --git a/typechecker/test_data/inputs/symbol_table/type_alias.py b/typechecker/test_data/inputs/symbol_table/type_alias.py new file mode 100644 index 00000000..c9272b36 --- /dev/null +++ b/typechecker/test_data/inputs/symbol_table/type_alias.py @@ -0,0 +1,7 @@ +# Show me some examples of type aliasing in Python try to give examples for all + +type Alias1 = int +type Alias2 = str +type Alias3 = float + +type AliasToAnotherAlias = Alias1 diff --git a/typechecker/testdata/output/enderpy_python_type_checker__build__tests__symbol_table@type_alias.py.snap b/typechecker/testdata/output/enderpy_python_type_checker__build__tests__symbol_table@type_alias.py.snap new file mode 100644 index 00000000..4a0ca4d6 --- /dev/null +++ b/typechecker/testdata/output/enderpy_python_type_checker__build__tests__symbol_table@type_alias.py.snap @@ -0,0 +1,125 @@ +--- +source: typechecker/src/build.rs +description: "# Show me some examples of type aliasing in Python try to give examples for all\n\ntype Alias1 = int\ntype Alias2 = str\ntype Alias3 = float\n\ntype AliasToAnotherAlias = Alias1\n" +expression: result +input_file: typechecker/test_data/inputs/symbol_table/type_alias.py +--- +------------------- +global scope: +Symbols: +Alias1 +- Declarations: +--: TypeAlias { + declaration_path: DeclarationPath { + module_name: [REDACTED]", + node: Node { + start: 81, + end: 98, + }, + }, + type_alias_node: TypeAlias { + node: Node { + start: 81, + end: 98, + }, + name: "Alias1", + type_params: [], + value: Name( + Name { + node: Node { + start: 95, + end: 98, + }, + id: "int", + }, + ), + }, +} +Alias2 +- Declarations: +--: TypeAlias { + declaration_path: DeclarationPath { + module_name: [REDACTED]", + node: Node { + start: 99, + end: 116, + }, + }, + type_alias_node: TypeAlias { + node: Node { + start: 99, + end: 116, + }, + name: "Alias2", + type_params: [], + value: Name( + Name { + node: Node { + start: 113, + end: 116, + }, + id: "str", + }, + ), + }, +} +Alias3 +- Declarations: +--: TypeAlias { + declaration_path: DeclarationPath { + module_name: [REDACTED]", + node: Node { + start: 117, + end: 136, + }, + }, + type_alias_node: TypeAlias { + node: Node { + start: 117, + end: 136, + }, + name: "Alias3", + type_params: [], + value: Name( + Name { + node: Node { + start: 131, + end: 136, + }, + id: "float", + }, + ), + }, +} +AliasToAnotherAlias +- Declarations: +--: TypeAlias { + declaration_path: DeclarationPath { + module_name: [REDACTED]", + node: Node { + start: 138, + end: 171, + }, + }, + type_alias_node: TypeAlias { + node: Node { + start: 138, + end: 171, + }, + name: "AliasToAnotherAlias", + type_params: [], + value: Name( + Name { + node: Node { + start: 165, + end: 171, + }, + id: "Alias1", + }, + ), + }, +} + +all scopes: +------------------- +